+ DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h);
+ ~DnDFrame();
+
+ void OnPaint(wxPaintEvent& event);
+ 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);
+ void OnPaste(wxCommandEvent& event);
+
+ void OnCopyBitmap(wxCommandEvent& event);
+ void OnPasteBitmap(wxCommandEvent& event);
+
+#ifdef USE_METAFILES
+ void OnPasteMetafile(wxCommandEvent& event);
+#endif // USE_METAFILES
+
+ void OnCopyFiles(wxCommandEvent& event);
+
+ void OnLeftDown(wxMouseEvent& event);
+ void OnRightDown(wxMouseEvent& event);
+
+ void OnUpdateUIPasteText(wxUpdateUIEvent& event);
+ void OnUpdateUIPasteBitmap(wxUpdateUIEvent& event);
+
+ DECLARE_EVENT_TABLE()
+
+private:
+ wxListBox *m_ctrlFile,
+ *m_ctrlText;
+ wxTextCtrl *m_ctrlLog;
+
+ wxLog *m_pLog,
+ *m_pLogPrev;
+
+ wxString m_strText;
+};
+
+// ----------------------------------------------------------------------------
+// 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)
+ {
+ }
+
+ // this is for debugging - lets us see when exactly an object is freed
+ // (this may be later than you think if it's on the clipboard, for example)
+ virtual ~DnDShape() { }
+
+ // the functions used for drag-and-drop: they dump and restore a shape into
+ // some bitwise-copiable data (might use streams too...)
+ // ------------------------------------------------------------------------
+
+ // 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; }
+
+ void Move(const wxPoint& pos) { m_pos = pos; }
+
+ // to implement in derived classes
+ virtual Kind GetKind() const = 0;
+
+ virtual void Draw(wxDC& dc)
+ {
+ 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)
+ {
+ wxLogMessage("DnDTriangularShape is being created");
+ }
+
+ virtual ~DnDTriangularShape()
+ {
+ wxLogMessage("DnDTriangularShape is being deleted");
+ }
+
+ 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);
+
+#ifdef __WXMSW__
+ dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
+#endif
+ }
+};
+
+class DnDRectangularShape : public DnDShape
+{
+public:
+ DnDRectangularShape(const wxPoint& pos,
+ const wxSize& size,
+ const wxColour& col)
+ : DnDShape(pos, size, col)
+ {
+ wxLogMessage("DnDRectangularShape is being created");
+ }
+
+ virtual ~DnDRectangularShape()
+ {
+ wxLogMessage("DnDRectangularShape is being deleted");
+ }
+
+ 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);
+
+#ifdef __WXMSW__
+ dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
+#endif
+ }
+};
+
+class DnDEllipticShape : public DnDShape
+{
+public:
+ DnDEllipticShape(const wxPoint& pos,
+ const wxSize& size,
+ const wxColour& col)
+ : DnDShape(pos, size, col)
+ {
+ wxLogMessage("DnDEllipticShape is being created");
+ }
+
+ virtual ~DnDEllipticShape()
+ {
+ wxLogMessage("DnDEllipticShape is being deleted");
+ }
+
+ virtual Kind GetKind() const { return Ellipse; }
+ virtual void Draw(wxDC& dc)
+ {
+ DnDShape::Draw(dc);
+
+ dc.DrawEllipse(m_pos, m_size);
+
+#ifdef __WXMSW__
+ dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
+#endif
+ }
+};
+
+// ----------------------------------------------------------------------------
+// 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 = (DnDShape *)NULL)
+ {
+ if ( shape )
+ {
+ // we need to copy the shape because the one we're handled may be
+ // deleted while it's still on the clipboard (for example) - and we
+ // reuse the serialisation methods here to copy it
+ void *buf = malloc(shape->DnDShape::GetDataSize());
+ shape->GetDataHere(buf);
+ m_shape = DnDShape::New(buf);
+
+ free(buf);
+ }
+ else
+ {
+ // nothing to copy
+ m_shape = NULL;
+ }
+
+ // 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;
+#ifdef USE_METAFILES
+ m_hasMetaFile = FALSE;
+#endif // Windows
+ }
+
+ virtual ~DnDShapeDataObject() { delete m_shape; }
+
+ // after a call to this function, the shape is owned by the caller and it
+ // is responsible for deleting it!
+ //
+ // NB: a better solution would be to make DnDShapes ref counted and this
+ // is what should probably be done in a real life program, otherwise
+ // the ownership problems become too complicated really fast
+ DnDShape *GetShape()
+ {
+ DnDShape *shape = m_shape;
+
+ m_shape = (DnDShape *)NULL;
+ m_hasBitmap = FALSE;
+#ifdef USE_METAFILES
+ m_hasMetaFile = FALSE;
+#endif // Windows
+
+ return shape;
+ }
+
+ // implement base class pure virtuals
+ // ----------------------------------