+// DnDShapeFrame
+// ----------------------------------------------------------------------------
+
+DnDShapeFrame *DnDShapeFrame::ms_lastDropTarget = NULL;
+
+DnDShapeFrame::DnDShapeFrame(wxFrame *parent)
+ : wxFrame(parent, -1, "Shape Frame",
+ wxDefaultPosition, wxSize(250, 150))
+{
+ CreateStatusBar();
+
+ wxMenu *menuShape = new wxMenu;
+ menuShape->Append(Menu_Shape_New, "&New default shape\tCtrl-S");
+ menuShape->Append(Menu_Shape_Edit, "&Edit shape\tCtrl-E");
+ menuShape->AppendSeparator();
+ menuShape->Append(Menu_Shape_Clear, "&Clear shape\tCtrl-L");
+
+ wxMenu *menuClipboard = new wxMenu;
+ menuClipboard->Append(Menu_ShapeClipboard_Copy, "&Copy\tCtrl-C");
+ menuClipboard->Append(Menu_ShapeClipboard_Paste, "&Paste\tCtrl-V");
+
+ wxMenuBar *menubar = new wxMenuBar;
+ menubar->Append(menuShape, "&Shape");
+ menubar->Append(menuClipboard, "&Clipboard");
+
+ SetMenuBar(menubar);
+
+ SetStatusText("Press Ctrl-S to create a new shape");
+
+ SetDropTarget(new DnDShapeDropTarget(this));
+
+ m_shape = NULL;
+
+ SetBackgroundColour(*wxWHITE);
+}
+
+DnDShapeFrame::~DnDShapeFrame()
+{
+ if (m_shape)
+ delete m_shape;
+}
+
+void DnDShapeFrame::SetShape(DnDShape *shape)
+{
+ if (m_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);
+
+ const char *pc = NULL;
+ switch ( source.DoDragDrop(TRUE) )
+ {
+ default:
+ case wxDragError:
+ wxLogError(wxT("An error occured during drag and drop operation"));
+ break;
+
+ case wxDragNone:
+ SetStatusText("Nothing happened");
+ break;
+
+ case wxDragCopy:
+ pc = "copied";
+ break;
+
+ case wxDragMove:
+ pc = "moved";
+ if ( ms_lastDropTarget != this )
+ {
+ // don't delete the shape if we dropped it on ourselves!
+ 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::OnDrop(wxCoord x, wxCoord y, DnDShape *shape)
+{
+ ms_lastDropTarget = this;
+
+ wxPoint pt(x, y);
+
+ wxString s;
+ s.Printf(wxT("Shape dropped at (%ld, %ld)"), pt.x, pt.y);
+ SetStatusText(s);
+
+ shape->Move(pt);
+ SetShape(shape);
+}
+
+void DnDShapeFrame::OnEditShape(wxCommandEvent& event)
+{
+ DnDShapeDialog dlg(this, m_shape);
+ if ( dlg.ShowModal() == wxID_OK )
+ {
+ SetShape(dlg.GetShape());
+
+ if ( m_shape )
+ {
+ SetStatusText("You can now drag the shape to another frame");
+ }
+ }
+}
+
+void DnDShapeFrame::OnNewShape(wxCommandEvent& event)
+{
+ SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED));
+
+ SetStatusText("You can now drag the shape to another frame");
+}
+
+void DnDShapeFrame::OnClearShape(wxCommandEvent& event)
+{
+ SetShape(NULL);
+}
+
+void DnDShapeFrame::OnCopyShape(wxCommandEvent& event)
+{
+ if ( m_shape )
+ {
+ wxClipboardLocker clipLocker;
+ if ( !clipLocker )
+ {
+ wxLogError(wxT("Can't open the clipboard"));
+
+ return;
+ }
+
+ wxTheClipboard->AddData(new DnDShapeDataObject(m_shape));
+ }
+}
+
+void DnDShapeFrame::OnPasteShape(wxCommandEvent& event)
+{
+ wxClipboardLocker clipLocker;
+ if ( !clipLocker )
+ {
+ wxLogError(wxT("Can't open the clipboard"));
+
+ return;
+ }
+
+ DnDShapeDataObject shapeDataObject(NULL);
+ if ( wxTheClipboard->GetData(shapeDataObject) )
+ {
+ SetShape(shapeDataObject.GetShape());
+ }
+ else
+ {
+ wxLogStatus(wxT("No shape on the clipboard"));
+ }
+}
+
+void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent& event)
+{
+ event.Enable( m_shape != NULL );
+}
+
+void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent& event)
+{
+ event.Enable( wxTheClipboard->IsSupported(wxDataFormat(shapeFormatId)) );
+}
+
+void DnDShapeFrame::OnPaint(wxPaintEvent& event)
+{
+ if ( m_shape )
+ {
+ wxPaintDC dc(this);
+
+ m_shape->Draw(dc);
+ }
+ else
+ {
+ event.Skip();
+ }
+}
+
+// ----------------------------------------------------------------------------
+// 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(wxT("invalid shape!"));
+ return NULL;
+ }
+}
+
+// ----------------------------------------------------------------------------
+// DnDShapeDataObject
+// ----------------------------------------------------------------------------
+
+#ifdef USE_METAFILES
+
+void DnDShapeDataObject::CreateMetaFile() const
+{
+ wxPoint pos = m_shape->GetPosition();
+ wxSize size = m_shape->GetSize();
+
+ wxMetaFileDC dcMF(wxEmptyString, pos.x + size.x, pos.y + size.y);
+
+ m_shape->Draw(dcMF);
+
+ wxMetafile *mf = dcMF.Close();
+
+ DnDShapeDataObject *self = (DnDShapeDataObject *)this; // const_cast
+ self->m_dobjMetaFile.SetMetafile(*mf);
+ self->m_hasMetaFile = TRUE;
+
+ delete mf;
+}
+
+#endif // Windows
+
+void DnDShapeDataObject::CreateBitmap() const
+{
+ wxPoint pos = m_shape->GetPosition();
+ wxSize size = m_shape->GetSize();
+ int x = pos.x + size.x,
+ y = pos.y + size.y;
+ wxBitmap bitmap(x, y);
+ wxMemoryDC dc;
+ dc.SelectObject(bitmap);
+ dc.SetBrush(wxBrush("white", wxSOLID));
+ dc.Clear();
+ m_shape->Draw(dc);
+ dc.SelectObject(wxNullBitmap);
+
+ DnDShapeDataObject *self = (DnDShapeDataObject *)this; // const_cast
+ self->m_dobjBitmap.SetBitmap(bitmap);
+ self->m_hasBitmap = TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// global functions