1. wxPostEvent added and documented
2. Made it possible to have wxDataObjects which support multiple formats painlessly 3. Extensively modified dnd sample to show a "real life" wxDataObject git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4028 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -19,8 +19,8 @@
|
||||
#include "wx/wx.h"
|
||||
#endif
|
||||
|
||||
#ifdef __WXMOTIF__
|
||||
#error Sorry, drag and drop is not yet implemented on wxMotif.
|
||||
#if !wxUSE_DRAG_AND_DROP
|
||||
#error This sample requires drag and drop support in the library
|
||||
#endif
|
||||
|
||||
#include "wx/intl.h"
|
||||
@@ -31,6 +31,8 @@
|
||||
#include "wx/filedlg.h"
|
||||
#include "wx/image.h"
|
||||
#include "wx/clipbrd.h"
|
||||
#include "wx/colordlg.h"
|
||||
#include "wx/resource.h"
|
||||
|
||||
#if defined(__WXGTK__) || defined(__WXMOTIF__)
|
||||
#include "mondrian.xpm"
|
||||
@@ -74,14 +76,15 @@ private:
|
||||
class DnDApp : public wxApp
|
||||
{
|
||||
public:
|
||||
bool OnInit();
|
||||
virtual bool OnInit();
|
||||
};
|
||||
|
||||
IMPLEMENT_APP(DnDApp);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Define a new frame type
|
||||
// Define a new frame type for the main frame
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class DnDFrame : public wxFrame
|
||||
{
|
||||
public:
|
||||
@@ -92,6 +95,7 @@ public:
|
||||
void OnQuit (wxCommandEvent& event);
|
||||
void OnAbout(wxCommandEvent& event);
|
||||
void OnDrag (wxCommandEvent& event);
|
||||
void OnNewFrame(wxCommandEvent& event);
|
||||
void OnHelp (wxCommandEvent& event);
|
||||
void OnLogClear(wxCommandEvent& event);
|
||||
void OnCopy(wxCommandEvent& event);
|
||||
@@ -117,6 +121,355 @@ private:
|
||||
wxBitmap m_bitmap;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// A shape is an example of application-specific data which may be transported
|
||||
// via drag-and-drop or clipboard: in our case, we have different geometric
|
||||
// shapes, each one with its own colour and position
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class DnDShape
|
||||
{
|
||||
public:
|
||||
enum Kind
|
||||
{
|
||||
None,
|
||||
Triangle,
|
||||
Rectangle,
|
||||
Ellipse
|
||||
};
|
||||
|
||||
DnDShape(const wxPoint& pos,
|
||||
const wxSize& size,
|
||||
const wxColour& col)
|
||||
: m_pos(pos), m_size(size), m_col(col)
|
||||
{
|
||||
}
|
||||
|
||||
// the functions used for drag-and-drop: they dump and restore a shape into
|
||||
// some bitwise-copiable data
|
||||
//
|
||||
// NB: here we profit from the fact that wxPoint, wxSize and wxColour are
|
||||
// POD (plain old data) and so can be copied directly - but it wouldn't
|
||||
// work for other types!
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// restore from buffer
|
||||
static DnDShape *New(const void *buf);
|
||||
|
||||
virtual size_t GetDataSize() const
|
||||
{
|
||||
return sizeof(ShapeDump);
|
||||
}
|
||||
|
||||
virtual void GetDataHere(void *buf) const
|
||||
{
|
||||
ShapeDump& dump = *(ShapeDump *)buf;
|
||||
dump.x = m_pos.x;
|
||||
dump.y = m_pos.y;
|
||||
dump.w = m_size.x;
|
||||
dump.h = m_size.y;
|
||||
dump.r = m_col.Red();
|
||||
dump.g = m_col.Green();
|
||||
dump.b = m_col.Blue();
|
||||
dump.k = GetKind();
|
||||
}
|
||||
|
||||
// accessors
|
||||
const wxPoint& GetPosition() const { return m_pos; }
|
||||
const wxColour& GetColour() const { return m_col; }
|
||||
const wxSize& GetSize() const { return m_size; }
|
||||
|
||||
// to implement in derived classes
|
||||
virtual Kind GetKind() const = 0;
|
||||
|
||||
virtual void Draw(wxDC& dc) = 0
|
||||
{
|
||||
dc.SetPen(wxPen(m_col, 1, wxSOLID));
|
||||
}
|
||||
|
||||
protected:
|
||||
wxPoint GetCentre() const
|
||||
{ return wxPoint(m_pos.x + m_size.x / 2, m_pos.y + m_size.y / 2); }
|
||||
|
||||
struct ShapeDump
|
||||
{
|
||||
int x, y, // position
|
||||
w, h, // size
|
||||
r, g, b, // colour
|
||||
k; // kind
|
||||
};
|
||||
|
||||
wxPoint m_pos;
|
||||
wxSize m_size;
|
||||
wxColour m_col;
|
||||
};
|
||||
|
||||
class DnDTriangularShape : public DnDShape
|
||||
{
|
||||
public:
|
||||
DnDTriangularShape(const wxPoint& pos,
|
||||
const wxSize& size,
|
||||
const wxColour& col)
|
||||
: DnDShape(pos, size, col)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Kind GetKind() const { return Triangle; }
|
||||
virtual void Draw(wxDC& dc)
|
||||
{
|
||||
DnDShape::Draw(dc);
|
||||
|
||||
// well, it's a bit difficult to describe a triangle by position and
|
||||
// size, but we're not doing geometry here, do we? ;-)
|
||||
wxPoint p1(m_pos);
|
||||
wxPoint p2(m_pos.x + m_size.x, m_pos.y);
|
||||
wxPoint p3(m_pos.x, m_pos.y + m_size.y);
|
||||
|
||||
dc.DrawLine(p1, p2);
|
||||
dc.DrawLine(p2, p3);
|
||||
dc.DrawLine(p3, p1);
|
||||
|
||||
dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
|
||||
}
|
||||
};
|
||||
|
||||
class DnDRectangularShape : public DnDShape
|
||||
{
|
||||
public:
|
||||
DnDRectangularShape(const wxPoint& pos,
|
||||
const wxSize& size,
|
||||
const wxColour& col)
|
||||
: DnDShape(pos, size, col)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Kind GetKind() const { return Rectangle; }
|
||||
virtual void Draw(wxDC& dc)
|
||||
{
|
||||
DnDShape::Draw(dc);
|
||||
|
||||
wxPoint p1(m_pos);
|
||||
wxPoint p2(p1.x + m_size.x, p1.y);
|
||||
wxPoint p3(p2.x, p2.y + m_size.y);
|
||||
wxPoint p4(p1.x, p3.y);
|
||||
|
||||
dc.DrawLine(p1, p2);
|
||||
dc.DrawLine(p2, p3);
|
||||
dc.DrawLine(p3, p4);
|
||||
dc.DrawLine(p4, p1);
|
||||
|
||||
dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
|
||||
}
|
||||
};
|
||||
|
||||
class DnDEllipticShape : public DnDShape
|
||||
{
|
||||
public:
|
||||
DnDEllipticShape(const wxPoint& pos,
|
||||
const wxSize& size,
|
||||
const wxColour& col)
|
||||
: DnDShape(pos, size, col)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Kind GetKind() const { return Ellipse; }
|
||||
virtual void Draw(wxDC& dc)
|
||||
{
|
||||
DnDShape::Draw(dc);
|
||||
|
||||
dc.DrawEllipse(m_pos, m_size);
|
||||
|
||||
dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
|
||||
}
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// A wxDataObject specialisation for the application-specific data
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static const char *shapeFormatId = "wxShape";
|
||||
|
||||
class DnDShapeDataObject : public wxDataObject
|
||||
{
|
||||
public:
|
||||
// ctor doesn't copy the pointer, so it shouldn't go away while this object
|
||||
// is alive
|
||||
DnDShapeDataObject(DnDShape *shape)
|
||||
{
|
||||
m_shape = shape;
|
||||
|
||||
// this string should uniquely identify our format, but is otherwise
|
||||
// arbitrary
|
||||
m_formatShape.SetId(shapeFormatId);
|
||||
|
||||
// we don't draw the shape to a bitmap until it's really needed (i.e.
|
||||
// we're asked to do so)
|
||||
m_hasBitmap = FALSE;
|
||||
}
|
||||
|
||||
// implement base class pure virtuals
|
||||
// ----------------------------------
|
||||
|
||||
virtual wxDataFormat GetPreferredFormat() const
|
||||
{
|
||||
return m_formatShape;
|
||||
}
|
||||
|
||||
virtual size_t GetFormatCount() const
|
||||
{
|
||||
// +1 for our custom format
|
||||
return m_dataobj.GetFormatCount() + 1;
|
||||
}
|
||||
|
||||
virtual void GetAllFormats(wxDataFormat *formats) const
|
||||
{
|
||||
formats[0] = m_formatShape;
|
||||
m_dataobj.GetAllFormats(&formats[1]);
|
||||
}
|
||||
|
||||
virtual size_t GetDataSize(const wxDataFormat& format) const
|
||||
{
|
||||
if ( format == m_formatShape )
|
||||
{
|
||||
return m_shape->GetDataSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
wxASSERT_MSG( format == wxDF_BITMAP, "unsupported format" );
|
||||
|
||||
if ( !m_hasBitmap )
|
||||
CreateBitmap();
|
||||
|
||||
return m_dataobj.GetDataSize(format);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void GetDataHere(const wxDataFormat& format, void *pBuf) const
|
||||
{
|
||||
if ( format == m_formatShape )
|
||||
{
|
||||
m_shape->GetDataHere(pBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
wxASSERT_MSG( format == wxDF_BITMAP, "unsupported format" );
|
||||
|
||||
if ( !m_hasBitmap )
|
||||
CreateBitmap();
|
||||
|
||||
m_dataobj.GetDataHere(format, pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// creates a bitmap and assigns it to m_dataobj (also sets m_hasBitmap)
|
||||
void CreateBitmap() const;
|
||||
|
||||
wxDataFormat m_formatShape; // our custom format
|
||||
|
||||
wxBitmapDataObject m_dataobj; // it handles bitmaps
|
||||
bool m_hasBitmap; // true if m_dataobj has valid bitmap
|
||||
|
||||
DnDShape *m_shape; // our data
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// A dialog to edit shape properties
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class DnDShapeDialog : public wxDialog
|
||||
{
|
||||
public:
|
||||
DnDShapeDialog(wxFrame *parent, DnDShape *shape);
|
||||
|
||||
DnDShape *GetShape() const;
|
||||
|
||||
virtual bool TransferDataToWindow();
|
||||
virtual bool TransferDataFromWindow();
|
||||
|
||||
void OnColour(wxCommandEvent& event);
|
||||
|
||||
private:
|
||||
// input
|
||||
DnDShape *m_shape;
|
||||
|
||||
// output
|
||||
DnDShape::Kind m_shapeKind;
|
||||
wxPoint m_pos;
|
||||
wxSize m_size;
|
||||
wxColour m_col;
|
||||
|
||||
// controls
|
||||
wxRadioBox *m_radio;
|
||||
wxTextCtrl *m_textX,
|
||||
*m_textY,
|
||||
*m_textW,
|
||||
*m_textH;
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// A frame for the shapes which can be drag-and-dropped between frames
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class DnDShapeFrame : public wxFrame
|
||||
{
|
||||
public:
|
||||
DnDShapeFrame(wxFrame *parent);
|
||||
~DnDShapeFrame();
|
||||
|
||||
void SetShape(DnDShape *shape);
|
||||
|
||||
// callbacks
|
||||
void OnDrag(wxMouseEvent& event);
|
||||
void OnEdit(wxMouseEvent& event);
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
void OnDrop(long x, long y, DnDShape *shape);
|
||||
|
||||
private:
|
||||
DnDShape *m_shape;
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxDropTarget derivation for DnDShapes
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class DnDShapeDropTarget : public wxDropTarget
|
||||
{
|
||||
public:
|
||||
DnDShapeDropTarget(DnDShapeFrame *frame)
|
||||
{
|
||||
m_frame = frame;
|
||||
|
||||
// the same as used by DnDShapeDataObject
|
||||
m_formatShape.SetId(shapeFormatId);
|
||||
}
|
||||
|
||||
// override base class (pure) virtuals
|
||||
virtual void OnEnter()
|
||||
{ m_frame->SetStatusText("Mouse entered the frame"); }
|
||||
virtual void OnLeave()
|
||||
{ m_frame->SetStatusText("Mouse left the frame"); }
|
||||
virtual bool OnDrop(long x, long y, const void *pData)
|
||||
{
|
||||
m_frame->OnDrop(x, y, DnDShape::New(pData));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual size_t GetFormatCount() const { return 1; }
|
||||
virtual wxDataFormat GetFormat(size_t WXUNUSED(n)) const
|
||||
{ return m_formatShape; }
|
||||
|
||||
private:
|
||||
DnDShapeFrame *m_frame;
|
||||
wxDataFormat m_formatShape;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// IDs for the menu commands
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -125,6 +478,7 @@ enum
|
||||
{
|
||||
Menu_Quit = 1,
|
||||
Menu_Drag,
|
||||
Menu_NewFrame,
|
||||
Menu_About = 101,
|
||||
Menu_Help,
|
||||
Menu_Clear,
|
||||
@@ -135,13 +489,15 @@ enum
|
||||
Menu_HasText,
|
||||
Menu_HasBitmap,
|
||||
Menu_ToBeGreyed, /* for testing */
|
||||
Menu_ToBeDeleted /* for testing */
|
||||
Menu_ToBeDeleted, /* for testing */
|
||||
Button_Colour = 1001
|
||||
};
|
||||
|
||||
BEGIN_EVENT_TABLE(DnDFrame, wxFrame)
|
||||
EVT_MENU(Menu_Quit, DnDFrame::OnQuit)
|
||||
EVT_MENU(Menu_About, DnDFrame::OnAbout)
|
||||
EVT_MENU(Menu_Drag, DnDFrame::OnDrag)
|
||||
EVT_MENU(Menu_NewFrame, DnDFrame::OnNewFrame)
|
||||
EVT_MENU(Menu_Help, DnDFrame::OnHelp)
|
||||
EVT_MENU(Menu_Clear, DnDFrame::OnLogClear)
|
||||
EVT_MENU(Menu_Copy, DnDFrame::OnCopy)
|
||||
@@ -156,7 +512,21 @@ BEGIN_EVENT_TABLE(DnDFrame, wxFrame)
|
||||
EVT_PAINT( DnDFrame::OnPaint)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
// `Main program' equivalent, creating windows and returning main app frame
|
||||
BEGIN_EVENT_TABLE(DnDShapeFrame, wxFrame)
|
||||
EVT_RIGHT_DOWN(DnDShapeFrame::OnDrag)
|
||||
EVT_LEFT_DCLICK(DnDShapeFrame::OnEdit)
|
||||
EVT_PAINT(DnDShapeFrame::OnPaint)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
BEGIN_EVENT_TABLE(DnDShapeDialog, wxDialog)
|
||||
EVT_BUTTON(Button_Colour, OnColour)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
// `Main program' equivalent, creating windows and returning main app frame
|
||||
bool DnDApp::OnInit()
|
||||
{
|
||||
#if wxUSE_LIBPNG
|
||||
@@ -173,6 +543,8 @@ bool DnDApp::OnInit()
|
||||
|
||||
SetTopWindow(frame);
|
||||
|
||||
wxDefaultResourceTable->ParseResourceFile("dnd.wxr");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -186,19 +558,13 @@ DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
|
||||
|
||||
CreateStatusBar();
|
||||
|
||||
// construct sub menu for testing
|
||||
wxMenu *sub_menu = new wxMenu;
|
||||
sub_menu->Append(Menu_Quit, "E&xit");
|
||||
sub_menu->Append(Menu_Quit, "E&xit");
|
||||
sub_menu->Append(Menu_Quit, "E&xit");
|
||||
|
||||
// construct menu
|
||||
wxMenu *file_menu = new wxMenu;
|
||||
file_menu->Append(Menu_Drag, "&Test drag...");
|
||||
file_menu->AppendSeparator();
|
||||
file_menu->Append(Menu_Quit, "E&xit");
|
||||
file_menu->Append(Menu_NewFrame, "&New frame\tCtrl-N");
|
||||
file_menu->AppendSeparator();
|
||||
file_menu->Append( 0, "More exit menus", sub_menu);
|
||||
file_menu->Append(Menu_Quit, "E&xit");
|
||||
|
||||
wxMenu *log_menu = new wxMenu;
|
||||
log_menu->Append(Menu_Clear, "Clear");
|
||||
@@ -217,7 +583,7 @@ DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
|
||||
clip_menu->AppendSeparator();
|
||||
clip_menu->Append(Menu_HasText, "Clipboard has &text\tCtrl+T");
|
||||
clip_menu->Append(Menu_HasBitmap, "Clipboard has a &bitmap\tCtrl+B");
|
||||
|
||||
|
||||
wxMenuBar *menu_bar = new wxMenuBar;
|
||||
menu_bar->Append(file_menu, "&File");
|
||||
menu_bar->Append(log_menu, "&Log");
|
||||
@@ -238,7 +604,10 @@ DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
|
||||
m_ctrlLog = new wxTextCtrl(this, -1, "", pos, size,
|
||||
wxTE_MULTILINE | wxTE_READONLY |
|
||||
wxSUNKEN_BORDER );
|
||||
// redirect log messages to the text window (don't forget to delete it!)
|
||||
|
||||
// redirect log messages to the text window and switch on OLE messages
|
||||
// logging
|
||||
wxLog::AddTraceMask(wxTRACE_OleCalls);
|
||||
m_pLog = new wxLogTextCtrl(m_ctrlLog);
|
||||
m_pLogPrev = wxLog::SetActiveTarget(m_pLog);
|
||||
|
||||
@@ -289,7 +658,7 @@ void DnDFrame::OnPaint(wxPaintEvent& WXUNUSED(event))
|
||||
wxPaintDC dc(this);
|
||||
dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL, FALSE, "charter" ) );
|
||||
dc.DrawText( "Drag text from here!", 20, h-50 );
|
||||
|
||||
|
||||
if (m_bitmap.Ok())
|
||||
dc.DrawBitmap( m_bitmap, 280, h-120, TRUE );
|
||||
}
|
||||
@@ -336,6 +705,13 @@ void DnDFrame::OnClipboardHasBitmap(wxCommandEvent& WXUNUSED(event))
|
||||
wxTheClipboard->Close();
|
||||
}
|
||||
|
||||
void DnDFrame::OnNewFrame(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
(new DnDShapeFrame(this))->Show(TRUE);
|
||||
|
||||
wxLogStatus(this, "Double click the new frame to select a shape for it");
|
||||
}
|
||||
|
||||
void DnDFrame::OnDrag(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
wxString strText = wxGetTextFromUser
|
||||
@@ -395,18 +771,15 @@ void DnDFrame::OnLogClear(wxCommandEvent& /* event */ )
|
||||
|
||||
void DnDFrame::OnLeftDown(wxMouseEvent &WXUNUSED(event) )
|
||||
{
|
||||
if ( !m_strText.IsEmpty() )
|
||||
if ( !m_strText.IsEmpty() )
|
||||
{
|
||||
// start drag operation
|
||||
#ifdef __WXMSW__
|
||||
wxTextDataObject textData(m_strText);
|
||||
wxDropSource dragSource( textData, this );
|
||||
#else
|
||||
wxDropSource dragSource( new wxTextDataObject (m_strText), this, wxIcon(mondrian_xpm) );
|
||||
#endif
|
||||
wxDropSource source(textData, this, wxICON(mondrian));
|
||||
|
||||
const char *pc;
|
||||
|
||||
switch ( dragSource.DoDragDrop(TRUE) )
|
||||
switch ( source.DoDragDrop(TRUE) )
|
||||
{
|
||||
case wxDragError: pc = "Error!"; break;
|
||||
case wxDragNone: pc = "Nothing"; break;
|
||||
@@ -429,7 +802,7 @@ void DnDFrame::OnRightDown(wxMouseEvent &event )
|
||||
menu->Append(Menu_Quit, "E&xit");
|
||||
menu->Append(Menu_ToBeDeleted, "To be deleted");
|
||||
menu->Append(Menu_ToBeGreyed, "To be greyed");
|
||||
|
||||
|
||||
menu->Delete( Menu_ToBeDeleted );
|
||||
menu->Enable( Menu_ToBeGreyed, FALSE );
|
||||
|
||||
@@ -458,25 +831,25 @@ void DnDFrame::OnCopyBitmap(wxCommandEvent& WXUNUSED(event))
|
||||
#endif
|
||||
|
||||
if (dialog.ShowModal() != wxID_OK)
|
||||
{
|
||||
{
|
||||
wxLogMessage( _T("Aborted file open") );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (dialog.GetPath().IsEmpty())
|
||||
{
|
||||
{
|
||||
wxLogMessage( _T("Returned empty string.") );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!wxFileExists(dialog.GetPath()))
|
||||
{
|
||||
wxLogMessage( _T("File doesn't exist.") );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
wxImage image;
|
||||
image.LoadFile( dialog.GetPath(),
|
||||
image.LoadFile( dialog.GetPath(),
|
||||
#ifdef __WXMSW__
|
||||
wxBITMAP_TYPE_BMP
|
||||
#else
|
||||
@@ -485,13 +858,13 @@ void DnDFrame::OnCopyBitmap(wxCommandEvent& WXUNUSED(event))
|
||||
);
|
||||
if (!image.Ok())
|
||||
{
|
||||
wxLogMessage( _T("Invalid image file...") );
|
||||
wxLogError( _T("Invalid image file...") );
|
||||
return;
|
||||
}
|
||||
|
||||
wxLogMessage( _T("Decoding image file...") );
|
||||
|
||||
wxLogStatus( _T("Decoding image file...") );
|
||||
wxYield();
|
||||
|
||||
|
||||
wxBitmap bitmap( image.ConvertToBitmap() );
|
||||
|
||||
if ( !wxTheClipboard->Open() )
|
||||
@@ -503,7 +876,7 @@ void DnDFrame::OnCopyBitmap(wxCommandEvent& WXUNUSED(event))
|
||||
|
||||
wxLogMessage( _T("Creating wxBitmapDataObject...") );
|
||||
wxYield();
|
||||
|
||||
|
||||
if ( !wxTheClipboard->AddData(new wxBitmapDataObject(bitmap)) )
|
||||
{
|
||||
wxLogError(_T("Can't copy image to the clipboard."));
|
||||
@@ -542,8 +915,8 @@ void DnDFrame::OnPasteBitmap(wxCommandEvent& WXUNUSED(event))
|
||||
else
|
||||
{
|
||||
wxLogMessage(_T("Bitmap pasted from the clipboard") );
|
||||
m_bitmap = data.GetBitmap();
|
||||
Refresh();
|
||||
m_bitmap = data.GetBitmap();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
wxTheClipboard->Close();
|
||||
@@ -628,3 +1001,251 @@ bool DnDFile::OnDropFiles( wxDropPointCoord, wxDropPointCoord, size_t nFiles,
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DnDShapeDialog
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DnDShapeDialog::DnDShapeDialog(wxFrame *parent, DnDShape *shape)
|
||||
{
|
||||
m_shape = shape;
|
||||
|
||||
LoadFromResource(parent, "dialogShape");
|
||||
|
||||
m_textX = (wxTextCtrl *)wxFindWindowByName("textX", this);
|
||||
m_textY = (wxTextCtrl *)wxFindWindowByName("textY", this);
|
||||
m_textW = (wxTextCtrl *)wxFindWindowByName("textW", this);
|
||||
m_textH = (wxTextCtrl *)wxFindWindowByName("textH", this);
|
||||
|
||||
m_radio = (wxRadioBox *)wxFindWindowByName("radio", this);
|
||||
}
|
||||
|
||||
DnDShape *DnDShapeDialog::GetShape() const
|
||||
{
|
||||
switch ( m_shapeKind )
|
||||
{
|
||||
default:
|
||||
case DnDShape::None: return NULL;
|
||||
case DnDShape::Triangle: return new DnDTriangularShape(m_pos, m_size, m_col);
|
||||
case DnDShape::Rectangle: return new DnDRectangularShape(m_pos, m_size, m_col);
|
||||
case DnDShape::Ellipse: return new DnDEllipticShape(m_pos, m_size, m_col);
|
||||
}
|
||||
}
|
||||
|
||||
bool DnDShapeDialog::TransferDataToWindow()
|
||||
{
|
||||
if ( m_shape )
|
||||
{
|
||||
m_radio->SetSelection(m_shape->GetKind());
|
||||
m_pos = m_shape->GetPosition();
|
||||
m_size = m_shape->GetSize();
|
||||
m_col = m_shape->GetColour();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_radio->SetSelection(DnDShape::None);
|
||||
m_pos = wxPoint(1, 1);
|
||||
m_size = wxSize(100, 100);
|
||||
}
|
||||
|
||||
m_textX->SetValue(wxString() << m_pos.x);
|
||||
m_textY->SetValue(wxString() << m_pos.y);
|
||||
m_textW->SetValue(wxString() << m_size.x);
|
||||
m_textH->SetValue(wxString() << m_size.y);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool DnDShapeDialog::TransferDataFromWindow()
|
||||
{
|
||||
m_shapeKind = (DnDShape::Kind)m_radio->GetSelection();
|
||||
|
||||
m_pos.x = atoi(m_textX->GetValue());
|
||||
m_pos.y = atoi(m_textY->GetValue());
|
||||
m_size.x = atoi(m_textW->GetValue());
|
||||
m_size.y = atoi(m_textH->GetValue());
|
||||
|
||||
if ( !m_pos.x || !m_pos.y || !m_size.x || !m_size.y )
|
||||
{
|
||||
wxMessageBox("All sizes and positions should be non null!",
|
||||
"Invalid shape", wxICON_HAND | wxOK, this);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void DnDShapeDialog::OnColour(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
wxColourData data;
|
||||
data.SetChooseFull(TRUE);
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
wxColour colour(i*16, i*16, i*16);
|
||||
data.SetCustomColour(i, colour);
|
||||
}
|
||||
|
||||
wxColourDialog dialog(this, &data);
|
||||
if ( dialog.ShowModal() == wxID_OK )
|
||||
{
|
||||
m_col = dialog.GetColourData().GetColour();
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DnDShapeFrame
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DnDShapeFrame::DnDShapeFrame(wxFrame *parent)
|
||||
: wxFrame(parent, -1, "Shape Frame",
|
||||
wxDefaultPosition, wxSize(250, 150))
|
||||
{
|
||||
SetBackgroundColour(*wxWHITE);
|
||||
|
||||
CreateStatusBar();
|
||||
|
||||
SetStatusText("Double click the frame to create a shape");
|
||||
|
||||
SetDropTarget(new DnDShapeDropTarget(this));
|
||||
|
||||
m_shape = NULL;
|
||||
}
|
||||
|
||||
DnDShapeFrame::~DnDShapeFrame()
|
||||
{
|
||||
delete m_shape;
|
||||
}
|
||||
|
||||
void DnDShapeFrame::SetShape(DnDShape *shape)
|
||||
{
|
||||
delete m_shape;
|
||||
m_shape = shape;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
// callbacks
|
||||
void DnDShapeFrame::OnDrag(wxMouseEvent& event)
|
||||
{
|
||||
if ( !m_shape )
|
||||
{
|
||||
event.Skip();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// start drag operation
|
||||
DnDShapeDataObject shapeData(m_shape);
|
||||
wxDropSource source(shapeData, this, wxICON(mondrian));
|
||||
|
||||
const char *pc = NULL;
|
||||
switch ( source.DoDragDrop(TRUE) )
|
||||
{
|
||||
default:
|
||||
case wxDragError:
|
||||
wxLogError("An error occured during drag and drop operation");
|
||||
break;
|
||||
|
||||
case wxDragNone:
|
||||
SetStatusText("Nothing happened");
|
||||
break;
|
||||
|
||||
case wxDragCopy:
|
||||
pc = "copied";
|
||||
break;
|
||||
|
||||
case wxDragMove:
|
||||
pc = "moved";
|
||||
SetShape(NULL);
|
||||
break;
|
||||
|
||||
case wxDragCancel:
|
||||
SetStatusText("Drag and drop operation cancelled");
|
||||
break;
|
||||
}
|
||||
|
||||
if ( pc )
|
||||
{
|
||||
SetStatusText(wxString("Shape successfully ") + pc);
|
||||
}
|
||||
//else: status text already set
|
||||
}
|
||||
|
||||
void DnDShapeFrame::OnEdit(wxMouseEvent& event)
|
||||
{
|
||||
DnDShapeDialog dlg(this, m_shape);
|
||||
if ( dlg.ShowModal() == wxID_OK )
|
||||
{
|
||||
SetShape(dlg.GetShape());
|
||||
|
||||
if ( m_shape )
|
||||
{
|
||||
SetStatusText("Right click now drag the shape to another frame");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DnDShapeFrame::OnPaint(wxPaintEvent& event)
|
||||
{
|
||||
if ( m_shape )
|
||||
m_shape->Draw(wxPaintDC(this));
|
||||
else
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void DnDShapeFrame::OnDrop(long x, long y, DnDShape *shape)
|
||||
{
|
||||
wxString s;
|
||||
s.Printf("Drop occured at (%ld, %ld)", x, y);
|
||||
SetStatusText(s);
|
||||
|
||||
SetShape(shape);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DnDShape
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DnDShape *DnDShape::New(const void *buf)
|
||||
{
|
||||
const ShapeDump& dump = *(const ShapeDump *)buf;
|
||||
switch ( dump.k )
|
||||
{
|
||||
case Triangle:
|
||||
return new DnDTriangularShape(wxPoint(dump.x, dump.y),
|
||||
wxSize(dump.w, dump.h),
|
||||
wxColour(dump.r, dump.g, dump.b));
|
||||
|
||||
case Rectangle:
|
||||
return new DnDRectangularShape(wxPoint(dump.x, dump.y),
|
||||
wxSize(dump.w, dump.h),
|
||||
wxColour(dump.r, dump.g, dump.b));
|
||||
|
||||
case Ellipse:
|
||||
return new DnDEllipticShape(wxPoint(dump.x, dump.y),
|
||||
wxSize(dump.w, dump.h),
|
||||
wxColour(dump.r, dump.g, dump.b));
|
||||
|
||||
default:
|
||||
wxFAIL_MSG("invalid shape!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DnDShapeDataObject
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DnDShapeDataObject::CreateBitmap() const
|
||||
{
|
||||
wxBitmap bitmap;
|
||||
wxMemoryDC dc;
|
||||
dc.SelectObject(bitmap);
|
||||
m_shape->Draw(dc);
|
||||
dc.SelectObject(wxNullBitmap);
|
||||
|
||||
DnDShapeDataObject *self = (DnDShapeDataObject *)this; // const_cast
|
||||
self->m_dataobj.SetBitmap(bitmap);
|
||||
self->m_hasBitmap = TRUE;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user