1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Drag and drop sample
4 // Author: Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
22 #if !wxUSE_DRAG_AND_DROP
23 #error This sample requires drag and drop support in the library
26 // under Windows we also support data transfer of metafiles as an extra bonus,
27 // but they're not available under other platforms
32 #define USE_RESOURCES 0
35 #define USE_RESOURCES 0
42 #include "wx/dirdlg.h"
43 #include "wx/filedlg.h"
45 #include "wx/clipbrd.h"
46 #include "wx/colordlg.h"
48 #include "wx/resource.h"
54 #include "wx/metafile.h"
57 #if defined(__WXGTK__) || defined(__WXX11__) || defined(__WXMOTIF__) || defined(__WXMAC__)
58 #include "mondrian.xpm"
60 #include "dnd_copy.xpm"
61 #include "dnd_move.xpm"
62 #include "dnd_none.xpm"
65 // ----------------------------------------------------------------------------
66 // Derive two simple classes which just put in the listbox the strings (text or
67 // file names) we drop on them
68 // ----------------------------------------------------------------------------
70 class DnDText
: public wxTextDropTarget
73 DnDText(wxListBox
*pOwner
) { m_pOwner
= pOwner
; }
75 virtual bool OnDropText(wxCoord x
, wxCoord y
, const wxString
& text
);
81 class DnDFile
: public wxFileDropTarget
84 DnDFile(wxListBox
*pOwner
) { m_pOwner
= pOwner
; }
86 virtual bool OnDropFiles(wxCoord x
, wxCoord y
,
87 const wxArrayString
& filenames
);
93 // ----------------------------------------------------------------------------
94 // Define a custom dtop target accepting URLs
95 // ----------------------------------------------------------------------------
97 class URLDropTarget
: public wxDropTarget
100 URLDropTarget() { SetDataObject(new wxURLDataObject
); }
102 void OnDropURL(wxCoord x
, wxCoord y
, const wxString
& text
)
104 // of course, a real program would do something more useful here...
105 wxMessageBox(text
, _T("wxDnD sample: got URL"),
106 wxICON_INFORMATION
| wxOK
);
109 // URLs can't be moved, only copied
110 virtual wxDragResult
OnDragOver(wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
113 return wxDragLink
; // At least IE 5.x needs wxDragLink, the
114 // other browsers on MSW seem okay with it too.
117 // translate this to calls to OnDropURL() just for convenience
118 virtual wxDragResult
OnData(wxCoord x
, wxCoord y
, wxDragResult def
)
123 OnDropURL(x
, y
, ((wxURLDataObject
*)m_dataObject
)->GetURL());
129 // ----------------------------------------------------------------------------
130 // Define a new application type
131 // ----------------------------------------------------------------------------
133 class DnDApp
: public wxApp
136 virtual bool OnInit();
139 IMPLEMENT_APP(DnDApp
);
141 // ----------------------------------------------------------------------------
142 // Define canvas class to show a bitmap
143 // ----------------------------------------------------------------------------
145 class DnDCanvasBitmap
: public wxScrolledWindow
148 DnDCanvasBitmap(wxWindow
*parent
) : wxScrolledWindow(parent
) { }
150 void SetBitmap(const wxBitmap
& bitmap
)
154 SetScrollbars(10, 10,
155 m_bitmap
.GetWidth() / 10, m_bitmap
.GetHeight() / 10);
160 void OnPaint(wxPaintEvent
& event
)
168 dc
.DrawBitmap(m_bitmap
, 0, 0);
175 DECLARE_EVENT_TABLE()
180 // and the same thing fo metafiles
181 class DnDCanvasMetafile
: public wxScrolledWindow
184 DnDCanvasMetafile(wxWindow
*parent
) : wxScrolledWindow(parent
) { }
186 void SetMetafile(const wxMetafile
& metafile
)
188 m_metafile
= metafile
;
190 SetScrollbars(10, 10,
191 m_metafile
.GetWidth() / 10, m_metafile
.GetHeight() / 10);
196 void OnPaint(wxPaintEvent
& event
)
200 if ( m_metafile
.Ok() )
204 m_metafile
.Play(&dc
);
209 wxMetafile m_metafile
;
211 DECLARE_EVENT_TABLE()
214 #endif // USE_METAFILES
216 // ----------------------------------------------------------------------------
217 // Define a new frame type for the main frame
218 // ----------------------------------------------------------------------------
220 class DnDFrame
: public wxFrame
223 DnDFrame(wxFrame
*frame
, char *title
, int x
, int y
, int w
, int h
);
226 void OnPaint(wxPaintEvent
& event
);
227 void OnSize(wxSizeEvent
& event
);
228 void OnQuit(wxCommandEvent
& event
);
229 void OnAbout(wxCommandEvent
& event
);
230 void OnDrag(wxCommandEvent
& event
);
231 void OnDragMoveByDefault(wxCommandEvent
& event
);
232 void OnDragMoveAllow(wxCommandEvent
& event
);
233 void OnNewFrame(wxCommandEvent
& event
);
234 void OnHelp (wxCommandEvent
& event
);
235 void OnLogClear(wxCommandEvent
& event
);
237 void OnCopy(wxCommandEvent
& event
);
238 void OnPaste(wxCommandEvent
& event
);
240 void OnCopyBitmap(wxCommandEvent
& event
);
241 void OnPasteBitmap(wxCommandEvent
& event
);
244 void OnPasteMetafile(wxCommandEvent
& event
);
245 #endif // USE_METAFILES
247 void OnCopyFiles(wxCommandEvent
& event
);
249 void OnLeftDown(wxMouseEvent
& event
);
250 void OnRightDown(wxMouseEvent
& event
);
252 void OnUpdateUIMoveByDefault(wxUpdateUIEvent
& event
);
254 void OnUpdateUIPasteText(wxUpdateUIEvent
& event
);
255 void OnUpdateUIPasteBitmap(wxUpdateUIEvent
& event
);
257 DECLARE_EVENT_TABLE()
261 wxListBox
*m_ctrlFile
,
263 wxTextCtrl
*m_ctrlLog
;
268 // move the text by default (or copy)?
269 bool m_moveByDefault
;
271 // allow moving the text at all?
278 // ----------------------------------------------------------------------------
279 // A shape is an example of application-specific data which may be transported
280 // via drag-and-drop or clipboard: in our case, we have different geometric
281 // shapes, each one with its own colour and position
282 // ----------------------------------------------------------------------------
295 DnDShape(const wxPoint
& pos
,
298 : m_pos(pos
), m_size(size
), m_col(col
)
302 // this is for debugging - lets us see when exactly an object is freed
303 // (this may be later than you think if it's on the clipboard, for example)
304 virtual ~DnDShape() { }
306 // the functions used for drag-and-drop: they dump and restore a shape into
307 // some bitwise-copiable data (might use streams too...)
308 // ------------------------------------------------------------------------
310 // restore from buffer
311 static DnDShape
*New(const void *buf
);
313 virtual size_t GetDataSize() const
315 return sizeof(ShapeDump
);
318 virtual void GetDataHere(void *buf
) const
320 ShapeDump
& dump
= *(ShapeDump
*)buf
;
325 dump
.r
= m_col
.Red();
326 dump
.g
= m_col
.Green();
327 dump
.b
= m_col
.Blue();
332 const wxPoint
& GetPosition() const { return m_pos
; }
333 const wxColour
& GetColour() const { return m_col
; }
334 const wxSize
& GetSize() const { return m_size
; }
336 void Move(const wxPoint
& pos
) { m_pos
= pos
; }
338 // to implement in derived classes
339 virtual Kind
GetKind() const = 0;
341 virtual void Draw(wxDC
& dc
)
343 dc
.SetPen(wxPen(m_col
, 1, wxSOLID
));
347 //get a point 1 up and 1 left, otherwise the mid-point of a triangle is on the line
348 wxPoint
GetCentre() const
349 { return wxPoint(m_pos
.x
+ m_size
.x
/ 2 - 1, m_pos
.y
+ m_size
.y
/ 2 - 1); }
353 int x
, y
, // position
364 class DnDTriangularShape
: public DnDShape
367 DnDTriangularShape(const wxPoint
& pos
,
370 : DnDShape(pos
, size
, col
)
372 wxLogMessage(wxT("DnDTriangularShape is being created"));
375 virtual ~DnDTriangularShape()
377 wxLogMessage(wxT("DnDTriangularShape is being deleted"));
380 virtual Kind
GetKind() const { return Triangle
; }
381 virtual void Draw(wxDC
& dc
)
385 // well, it's a bit difficult to describe a triangle by position and
386 // size, but we're not doing geometry here, do we? ;-)
388 wxPoint
p2(m_pos
.x
+ m_size
.x
, m_pos
.y
);
389 wxPoint
p3(m_pos
.x
, m_pos
.y
+ m_size
.y
);
395 //works in multicolor modes; on GTK (at least) will fail in 16-bit color
396 dc
.SetBrush(wxBrush(m_col
, wxSOLID
));
397 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
401 class DnDRectangularShape
: public DnDShape
404 DnDRectangularShape(const wxPoint
& pos
,
407 : DnDShape(pos
, size
, col
)
409 wxLogMessage(wxT("DnDRectangularShape is being created"));
412 virtual ~DnDRectangularShape()
414 wxLogMessage(wxT("DnDRectangularShape is being deleted"));
417 virtual Kind
GetKind() const { return Rectangle
; }
418 virtual void Draw(wxDC
& dc
)
423 wxPoint
p2(p1
.x
+ m_size
.x
, p1
.y
);
424 wxPoint
p3(p2
.x
, p2
.y
+ m_size
.y
);
425 wxPoint
p4(p1
.x
, p3
.y
);
432 dc
.SetBrush(wxBrush(m_col
, wxSOLID
));
433 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
437 class DnDEllipticShape
: public DnDShape
440 DnDEllipticShape(const wxPoint
& pos
,
443 : DnDShape(pos
, size
, col
)
445 wxLogMessage(wxT("DnDEllipticShape is being created"));
448 virtual ~DnDEllipticShape()
450 wxLogMessage(wxT("DnDEllipticShape is being deleted"));
453 virtual Kind
GetKind() const { return Ellipse
; }
454 virtual void Draw(wxDC
& dc
)
458 dc
.DrawEllipse(m_pos
, m_size
);
460 dc
.SetBrush(wxBrush(m_col
, wxSOLID
));
461 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
465 // ----------------------------------------------------------------------------
466 // A wxDataObject specialisation for the application-specific data
467 // ----------------------------------------------------------------------------
469 static const wxChar
*shapeFormatId
= wxT("wxShape");
471 class DnDShapeDataObject
: public wxDataObject
474 // ctor doesn't copy the pointer, so it shouldn't go away while this object
476 DnDShapeDataObject(DnDShape
*shape
= (DnDShape
*)NULL
)
480 // we need to copy the shape because the one we're handled may be
481 // deleted while it's still on the clipboard (for example) - and we
482 // reuse the serialisation methods here to copy it
483 void *buf
= malloc(shape
->DnDShape::GetDataSize());
484 shape
->GetDataHere(buf
);
485 m_shape
= DnDShape::New(buf
);
495 // this string should uniquely identify our format, but is otherwise
497 m_formatShape
.SetId(shapeFormatId
);
499 // we don't draw the shape to a bitmap until it's really needed (i.e.
500 // we're asked to do so)
503 m_hasMetaFile
= FALSE
;
507 virtual ~DnDShapeDataObject() { delete m_shape
; }
509 // after a call to this function, the shape is owned by the caller and it
510 // is responsible for deleting it!
512 // NB: a better solution would be to make DnDShapes ref counted and this
513 // is what should probably be done in a real life program, otherwise
514 // the ownership problems become too complicated really fast
517 DnDShape
*shape
= m_shape
;
519 m_shape
= (DnDShape
*)NULL
;
522 m_hasMetaFile
= FALSE
;
528 // implement base class pure virtuals
529 // ----------------------------------
531 virtual wxDataFormat
GetPreferredFormat(Direction
WXUNUSED(dir
)) const
533 return m_formatShape
;
536 virtual size_t GetFormatCount(Direction dir
) const
538 // our custom format is supported by both GetData() and SetData()
542 // but the bitmap format(s) are only supported for output
543 nFormats
+= m_dobjBitmap
.GetFormatCount(dir
);
546 nFormats
+= m_dobjMetaFile
.GetFormatCount(dir
);
553 virtual void GetAllFormats(wxDataFormat
*formats
, Direction dir
) const
555 formats
[0] = m_formatShape
;
558 // in Get direction we additionally support bitmaps and metafiles
560 m_dobjBitmap
.GetAllFormats(&formats
[1], dir
);
563 // don't assume that m_dobjBitmap has only 1 format
564 m_dobjMetaFile
.GetAllFormats(&formats
[1 +
565 m_dobjBitmap
.GetFormatCount(dir
)], dir
);
570 virtual size_t GetDataSize(const wxDataFormat
& format
) const
572 if ( format
== m_formatShape
)
574 return m_shape
->GetDataSize();
577 else if ( m_dobjMetaFile
.IsSupported(format
) )
579 if ( !m_hasMetaFile
)
582 return m_dobjMetaFile
.GetDataSize(format
);
587 wxASSERT_MSG( m_dobjBitmap
.IsSupported(format
),
588 wxT("unexpected format") );
593 return m_dobjBitmap
.GetDataSize();
597 virtual bool GetDataHere(const wxDataFormat
& format
, void *pBuf
) const
599 if ( format
== m_formatShape
)
601 m_shape
->GetDataHere(pBuf
);
606 else if ( m_dobjMetaFile
.IsSupported(format
) )
608 if ( !m_hasMetaFile
)
611 return m_dobjMetaFile
.GetDataHere(format
, pBuf
);
616 wxASSERT_MSG( m_dobjBitmap
.IsSupported(format
),
617 wxT("unexpected format") );
622 return m_dobjBitmap
.GetDataHere(pBuf
);
626 virtual bool SetData(const wxDataFormat
& format
,
627 size_t len
, const void *buf
)
629 wxCHECK_MSG( format
== m_formatShape
, FALSE
,
630 wxT( "unsupported format") );
633 m_shape
= DnDShape::New(buf
);
635 // the shape has changed
639 m_hasMetaFile
= FALSE
;
646 // creates a bitmap and assigns it to m_dobjBitmap (also sets m_hasBitmap)
647 void CreateBitmap() const;
649 void CreateMetaFile() const;
652 wxDataFormat m_formatShape
; // our custom format
654 wxBitmapDataObject m_dobjBitmap
; // it handles bitmaps
655 bool m_hasBitmap
; // true if m_dobjBitmap has valid bitmap
658 wxMetaFileDataObject m_dobjMetaFile
;// handles metafiles
659 bool m_hasMetaFile
; // true if we have valid metafile
662 DnDShape
*m_shape
; // our data
665 // ----------------------------------------------------------------------------
666 // A dialog to edit shape properties
667 // ----------------------------------------------------------------------------
669 class DnDShapeDialog
: public wxDialog
672 DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
);
674 DnDShape
*GetShape() const;
676 virtual bool TransferDataToWindow();
677 virtual bool TransferDataFromWindow();
679 void OnColour(wxCommandEvent
& event
);
686 DnDShape::Kind m_shapeKind
;
698 DECLARE_EVENT_TABLE()
701 // ----------------------------------------------------------------------------
702 // A frame for the shapes which can be drag-and-dropped between frames
703 // ----------------------------------------------------------------------------
705 class DnDShapeFrame
: public wxFrame
708 DnDShapeFrame(wxFrame
*parent
);
711 void SetShape(DnDShape
*shape
);
714 void OnNewShape(wxCommandEvent
& event
);
715 void OnEditShape(wxCommandEvent
& event
);
716 void OnClearShape(wxCommandEvent
& event
);
718 void OnCopyShape(wxCommandEvent
& event
);
719 void OnPasteShape(wxCommandEvent
& event
);
721 void OnUpdateUICopy(wxUpdateUIEvent
& event
);
722 void OnUpdateUIPaste(wxUpdateUIEvent
& event
);
724 void OnDrag(wxMouseEvent
& event
);
725 void OnPaint(wxPaintEvent
& event
);
726 void OnDrop(wxCoord x
, wxCoord y
, DnDShape
*shape
);
731 static DnDShapeFrame
*ms_lastDropTarget
;
733 DECLARE_EVENT_TABLE()
736 // ----------------------------------------------------------------------------
737 // wxDropTarget derivation for DnDShapes
738 // ----------------------------------------------------------------------------
740 class DnDShapeDropTarget
: public wxDropTarget
743 DnDShapeDropTarget(DnDShapeFrame
*frame
)
744 : wxDropTarget(new DnDShapeDataObject
)
749 // override base class (pure) virtuals
750 virtual wxDragResult
OnEnter(wxCoord x
, wxCoord y
, wxDragResult def
)
751 { m_frame
->SetStatusText("Mouse entered the frame"); return OnDragOver(x
, y
, def
); }
752 virtual void OnLeave()
753 { m_frame
->SetStatusText("Mouse left the frame"); }
754 virtual wxDragResult
OnData(wxCoord x
, wxCoord y
, wxDragResult def
)
758 wxLogError(wxT("Failed to get drag and drop data"));
763 m_frame
->OnDrop(x
, y
,
764 ((DnDShapeDataObject
*)GetDataObject())->GetShape());
770 DnDShapeFrame
*m_frame
;
773 // ----------------------------------------------------------------------------
774 // functions prototypes
775 // ----------------------------------------------------------------------------
777 static void ShowBitmap(const wxBitmap
& bitmap
);
780 static void ShowMetaFile(const wxMetaFile
& metafile
);
781 #endif // USE_METAFILES
783 // ----------------------------------------------------------------------------
784 // IDs for the menu commands
785 // ----------------------------------------------------------------------------
803 Menu_Shape_New
= 500,
806 Menu_ShapeClipboard_Copy
,
807 Menu_ShapeClipboard_Paste
,
811 BEGIN_EVENT_TABLE(DnDFrame
, wxFrame
)
812 EVT_MENU(Menu_Quit
, DnDFrame::OnQuit
)
813 EVT_MENU(Menu_About
, DnDFrame::OnAbout
)
814 EVT_MENU(Menu_Drag
, DnDFrame::OnDrag
)
815 EVT_MENU(Menu_DragMoveDef
, DnDFrame::OnDragMoveByDefault
)
816 EVT_MENU(Menu_DragMoveAllow
,DnDFrame::OnDragMoveAllow
)
817 EVT_MENU(Menu_NewFrame
, DnDFrame::OnNewFrame
)
818 EVT_MENU(Menu_Help
, DnDFrame::OnHelp
)
819 EVT_MENU(Menu_Clear
, DnDFrame::OnLogClear
)
820 EVT_MENU(Menu_Copy
, DnDFrame::OnCopy
)
821 EVT_MENU(Menu_Paste
, DnDFrame::OnPaste
)
822 EVT_MENU(Menu_CopyBitmap
, DnDFrame::OnCopyBitmap
)
823 EVT_MENU(Menu_PasteBitmap
,DnDFrame::OnPasteBitmap
)
825 EVT_MENU(Menu_PasteMFile
, DnDFrame::OnPasteMetafile
)
826 #endif // USE_METAFILES
827 EVT_MENU(Menu_CopyFiles
, DnDFrame::OnCopyFiles
)
829 EVT_UPDATE_UI(Menu_DragMoveDef
, DnDFrame::OnUpdateUIMoveByDefault
)
831 EVT_UPDATE_UI(Menu_Paste
, DnDFrame::OnUpdateUIPasteText
)
832 EVT_UPDATE_UI(Menu_PasteBitmap
, DnDFrame::OnUpdateUIPasteBitmap
)
834 EVT_LEFT_DOWN( DnDFrame::OnLeftDown
)
835 EVT_RIGHT_DOWN( DnDFrame::OnRightDown
)
836 EVT_PAINT( DnDFrame::OnPaint
)
837 EVT_SIZE( DnDFrame::OnSize
)
840 BEGIN_EVENT_TABLE(DnDShapeFrame
, wxFrame
)
841 EVT_MENU(Menu_Shape_New
, DnDShapeFrame::OnNewShape
)
842 EVT_MENU(Menu_Shape_Edit
, DnDShapeFrame::OnEditShape
)
843 EVT_MENU(Menu_Shape_Clear
, DnDShapeFrame::OnClearShape
)
845 EVT_MENU(Menu_ShapeClipboard_Copy
, DnDShapeFrame::OnCopyShape
)
846 EVT_MENU(Menu_ShapeClipboard_Paste
, DnDShapeFrame::OnPasteShape
)
848 EVT_UPDATE_UI(Menu_ShapeClipboard_Copy
, DnDShapeFrame::OnUpdateUICopy
)
849 EVT_UPDATE_UI(Menu_ShapeClipboard_Paste
, DnDShapeFrame::OnUpdateUIPaste
)
851 EVT_LEFT_DOWN(DnDShapeFrame::OnDrag
)
853 EVT_PAINT(DnDShapeFrame::OnPaint
)
856 BEGIN_EVENT_TABLE(DnDShapeDialog
, wxDialog
)
857 EVT_BUTTON(Button_Colour
, DnDShapeDialog::OnColour
)
860 BEGIN_EVENT_TABLE(DnDCanvasBitmap
, wxScrolledWindow
)
861 EVT_PAINT(DnDCanvasBitmap::OnPaint
)
865 BEGIN_EVENT_TABLE(DnDCanvasMetafile
, wxScrolledWindow
)
866 EVT_PAINT(DnDCanvasMetafile::OnPaint
)
868 #endif // USE_METAFILES
870 // ============================================================================
872 // ============================================================================
874 // `Main program' equivalent, creating windows and returning main app frame
875 bool DnDApp::OnInit()
878 // load our ressources
882 pathList
.Add("./Debug");
883 pathList
.Add("./Release");
886 wxString path
= pathList
.FindValidPath("dnd.wxr");
889 wxLogError(wxT("Can't find the resource file dnd.wxr in the current ")
890 wxT("directory, aborting."));
895 wxDefaultResourceTable
->ParseResourceFile(path
);
898 // switch on trace messages
899 #if defined(__WXGTK__)
900 wxLog::AddTraceMask(_T("clipboard"));
901 #elif defined(__WXMSW__)
902 wxLog::AddTraceMask(wxTRACE_OleCalls
);
906 wxImage::AddHandler( new wxPNGHandler
);
909 // under X we usually want to use the primary selection by default (which
910 // is shared with other apps)
911 wxTheClipboard
->UsePrimarySelection();
913 // create the main frame window
914 DnDFrame
*frame
= new DnDFrame((wxFrame
*) NULL
,
915 "Drag-and-Drop/Clipboard wxWindows Sample",
926 DnDFrame::DnDFrame(wxFrame
*frame
, char *title
, int x
, int y
, int w
, int h
)
927 : wxFrame(frame
, -1, title
, wxPoint(x
, y
), wxSize(w
, h
)),
928 m_strText("wxWindows drag & drop works :-)")
931 // frame icon and status bar
932 SetIcon(wxICON(mondrian
));
937 wxMenu
*file_menu
= new wxMenu
;
938 file_menu
->Append(Menu_Drag
, "&Test drag...");
939 file_menu
->AppendCheckItem(Menu_DragMoveDef
, "&Move by default");
940 file_menu
->AppendCheckItem(Menu_DragMoveAllow
, "&Allow moving");
941 file_menu
->AppendSeparator();
942 file_menu
->Append(Menu_NewFrame
, "&New frame\tCtrl-N");
943 file_menu
->AppendSeparator();
944 file_menu
->Append(Menu_Quit
, "E&xit\tCtrl-Q");
946 wxMenu
*log_menu
= new wxMenu
;
947 log_menu
->Append(Menu_Clear
, "Clear\tCtrl-L");
949 wxMenu
*help_menu
= new wxMenu
;
950 help_menu
->Append(Menu_Help
, "&Help...");
951 help_menu
->AppendSeparator();
952 help_menu
->Append(Menu_About
, "&About");
954 wxMenu
*clip_menu
= new wxMenu
;
955 clip_menu
->Append(Menu_Copy
, "&Copy text\tCtrl-C");
956 clip_menu
->Append(Menu_Paste
, "&Paste text\tCtrl-V");
957 clip_menu
->AppendSeparator();
958 clip_menu
->Append(Menu_CopyBitmap
, "Copy &bitmap\tCtrl-Shift-C");
959 clip_menu
->Append(Menu_PasteBitmap
, "Paste b&itmap\tCtrl-Shift-V");
961 clip_menu
->AppendSeparator();
962 clip_menu
->Append(Menu_PasteMFile
, "Paste &metafile\tCtrl-M");
963 #endif // USE_METAFILES
964 clip_menu
->AppendSeparator();
965 clip_menu
->Append(Menu_CopyFiles
, "Copy &files\tCtrl-F");
967 wxMenuBar
*menu_bar
= new wxMenuBar
;
968 menu_bar
->Append(file_menu
, "&File");
969 menu_bar
->Append(log_menu
, "&Log");
970 menu_bar
->Append(clip_menu
, "&Clipboard");
971 menu_bar
->Append(help_menu
, "&Help");
973 SetMenuBar(menu_bar
);
975 // make a panel with 3 subwindows
977 wxSize
size(400, 200);
979 wxString
strFile("Drop files here!"), strText("Drop text on me");
981 m_ctrlFile
= new wxListBox(this, -1, pos
, size
, 1, &strFile
,
982 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
983 m_ctrlText
= new wxListBox(this, -1, pos
, size
, 1, &strText
,
984 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
986 m_ctrlLog
= new wxTextCtrl(this, -1, "", pos
, size
,
987 wxTE_MULTILINE
| wxTE_READONLY
|
990 // redirect log messages to the text window
991 m_pLog
= new wxLogTextCtrl(m_ctrlLog
);
992 m_pLogPrev
= wxLog::SetActiveTarget(m_pLog
);
994 // associate drop targets with the controls
995 m_ctrlFile
->SetDropTarget(new DnDFile(m_ctrlFile
));
996 m_ctrlText
->SetDropTarget(new DnDText(m_ctrlText
));
997 m_ctrlLog
->SetDropTarget(new URLDropTarget
);
999 wxLayoutConstraints
*c
;
1002 c
= new wxLayoutConstraints
;
1003 c
->left
.SameAs(this, wxLeft
);
1004 c
->top
.SameAs(this, wxTop
);
1005 c
->right
.PercentOf(this, wxRight
, 50);
1006 c
->height
.PercentOf(this, wxHeight
, 30);
1007 m_ctrlFile
->SetConstraints(c
);
1009 // Top-right listbox
1010 c
= new wxLayoutConstraints
;
1011 c
->left
.SameAs (m_ctrlFile
, wxRight
);
1012 c
->top
.SameAs (this, wxTop
);
1013 c
->right
.SameAs (this, wxRight
);
1014 c
->height
.PercentOf(this, wxHeight
, 30);
1015 m_ctrlText
->SetConstraints(c
);
1017 // Lower text control
1018 c
= new wxLayoutConstraints
;
1019 c
->left
.SameAs (this, wxLeft
);
1020 c
->right
.SameAs (this, wxRight
);
1021 c
->height
.PercentOf(this, wxHeight
, 50);
1022 c
->top
.SameAs(m_ctrlText
, wxBottom
);
1023 m_ctrlLog
->SetConstraints(c
);
1025 SetAutoLayout(TRUE
);
1027 // copy data by default but allow moving it as well
1028 m_moveByDefault
= FALSE
;
1030 menu_bar
->Check(Menu_DragMoveAllow
, TRUE
);
1033 void DnDFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
))
1038 void DnDFrame::OnSize(wxSizeEvent
& event
)
1045 void DnDFrame::OnPaint(wxPaintEvent
& WXUNUSED(event
))
1049 GetClientSize( &w
, &h
);
1052 // dc.Clear(); -- this kills wxGTK
1053 dc
.SetFont( wxFont( 24, wxDECORATIVE
, wxNORMAL
, wxNORMAL
, FALSE
, "charter" ) );
1054 dc
.DrawText( "Drag text from here!", 100, h
-50 );
1057 void DnDFrame::OnUpdateUIMoveByDefault(wxUpdateUIEvent
& event
)
1059 // only can move by default if moving is allowed at all
1060 event
.Enable(m_moveAllow
);
1063 void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent
& event
)
1066 // too many trace messages if we don't do it - this function is called
1071 event
.Enable( wxTheClipboard
->IsSupported(wxDF_TEXT
) );
1074 void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent
& event
)
1077 // too many trace messages if we don't do it - this function is called
1082 event
.Enable( wxTheClipboard
->IsSupported(wxDF_BITMAP
) );
1085 void DnDFrame::OnNewFrame(wxCommandEvent
& WXUNUSED(event
))
1087 (new DnDShapeFrame(this))->Show(TRUE
);
1089 wxLogStatus(this, wxT("Double click the new frame to select a shape for it"));
1092 void DnDFrame::OnDrag(wxCommandEvent
& WXUNUSED(event
))
1094 wxString strText
= wxGetTextFromUser
1096 "After you enter text in this dialog, press any mouse\n"
1097 "button in the bottom (empty) part of the frame and \n"
1098 "drag it anywhere - you will be in fact dragging the\n"
1099 "text object containing this text",
1100 "Please enter some text", m_strText
, this
1103 m_strText
= strText
;
1106 void DnDFrame::OnDragMoveByDefault(wxCommandEvent
& event
)
1108 m_moveByDefault
= event
.IsChecked();
1111 void DnDFrame::OnDragMoveAllow(wxCommandEvent
& event
)
1113 m_moveAllow
= event
.IsChecked();
1116 void DnDFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
1118 wxMessageBox("Drag-&-Drop Demo\n"
1119 "Please see \"Help|Help...\" for details\n"
1120 "Copyright (c) 1998 Vadim Zeitlin",
1122 wxICON_INFORMATION
| wxOK
,
1126 void DnDFrame::OnHelp(wxCommandEvent
& /* event */)
1128 wxMessageDialog
dialog(this,
1129 "This small program demonstrates drag & drop support in wxWindows. The program window\n"
1130 "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
1131 "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
1132 "and the right one accepts text.\n"
1134 "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
1135 "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
1136 "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
1137 "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
1138 "work with files) and see what changes.\n"
1140 "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
1141 "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
1142 "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
1143 "change, don't release the mouse button until it does. You can change the string being\n"
1144 "dragged in in \"File|Test drag...\" dialog.\n"
1147 "Please send all questions/bug reports/suggestions &c to \n"
1148 "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
1154 void DnDFrame::OnLogClear(wxCommandEvent
& /* event */ )
1157 m_ctrlText
->Clear();
1158 m_ctrlFile
->Clear();
1161 void DnDFrame::OnLeftDown(wxMouseEvent
&WXUNUSED(event
) )
1163 if ( !m_strText
.IsEmpty() )
1165 // start drag operation
1166 wxTextDataObject
textData(m_strText
);
1168 wxFileDataObject textData;
1169 textData.AddFile( "/file1.txt" );
1170 textData.AddFile( "/file2.txt" );
1172 wxDropSource
source(textData
, this,
1173 wxDROP_ICON(dnd_copy
),
1174 wxDROP_ICON(dnd_move
),
1175 wxDROP_ICON(dnd_none
));
1178 if ( m_moveByDefault
)
1179 flags
|= wxDrag_DefaultMove
;
1180 else if ( m_moveAllow
)
1181 flags
|= wxDrag_AllowMove
;
1184 switch ( source
.DoDragDrop(flags
) )
1186 case wxDragError
: pc
= "Error!"; break;
1187 case wxDragNone
: pc
= "Nothing"; break;
1188 case wxDragCopy
: pc
= "Copied"; break;
1189 case wxDragMove
: pc
= "Moved"; break;
1190 case wxDragCancel
: pc
= "Cancelled"; break;
1191 default: pc
= "Huh?"; break;
1194 SetStatusText(wxString("Drag result: ") + pc
);
1198 void DnDFrame::OnRightDown(wxMouseEvent
&event
)
1200 wxMenu
menu("Dnd sample menu");
1202 menu
.Append(Menu_Drag
, "&Test drag...");
1203 menu
.AppendSeparator();
1204 menu
.Append(Menu_About
, "&About");
1206 PopupMenu( &menu
, event
.GetX(), event
.GetY() );
1209 DnDFrame::~DnDFrame()
1211 if ( m_pLog
!= NULL
) {
1212 if ( wxLog::SetActiveTarget(m_pLogPrev
) == m_pLog
)
1217 // ---------------------------------------------------------------------------
1219 // ---------------------------------------------------------------------------
1221 void DnDFrame::OnCopyBitmap(wxCommandEvent
& WXUNUSED(event
))
1223 // PNG support is not always compiled in under Windows, so use BMP there
1225 wxFileDialog
dialog(this, "Open a BMP file", "", "", "BMP files (*.bmp)|*.bmp", 0);
1227 wxFileDialog
dialog(this, "Open a PNG file", "", "", "PNG files (*.png)|*.png", 0);
1230 if (dialog
.ShowModal() != wxID_OK
)
1232 wxLogMessage( _T("Aborted file open") );
1236 if (dialog
.GetPath().IsEmpty())
1238 wxLogMessage( _T("Returned empty string.") );
1242 if (!wxFileExists(dialog
.GetPath()))
1244 wxLogMessage( _T("File doesn't exist.") );
1249 image
.LoadFile( dialog
.GetPath(),
1258 wxLogError( _T("Invalid image file...") );
1262 wxLogStatus( _T("Decoding image file...") );
1265 wxBitmap
bitmap( image
);
1267 if ( !wxTheClipboard
->Open() )
1269 wxLogError(_T("Can't open clipboard."));
1274 wxLogMessage( _T("Creating wxBitmapDataObject...") );
1277 if ( !wxTheClipboard
->AddData(new wxBitmapDataObject(bitmap
)) )
1279 wxLogError(_T("Can't copy image to the clipboard."));
1283 wxLogMessage(_T("Image has been put on the clipboard.") );
1284 wxLogMessage(_T("You can paste it now and look at it.") );
1287 wxTheClipboard
->Close();
1290 void DnDFrame::OnPasteBitmap(wxCommandEvent
& WXUNUSED(event
))
1292 if ( !wxTheClipboard
->Open() )
1294 wxLogError(_T("Can't open clipboard."));
1299 if ( !wxTheClipboard
->IsSupported(wxDF_BITMAP
) )
1301 wxLogWarning(_T("No bitmap on clipboard"));
1303 wxTheClipboard
->Close();
1307 wxBitmapDataObject data
;
1308 if ( !wxTheClipboard
->GetData(data
) )
1310 wxLogError(_T("Can't paste bitmap from the clipboard"));
1314 const wxBitmap
& bmp
= data
.GetBitmap();
1316 wxLogMessage(_T("Bitmap %dx%d pasted from the clipboard"),
1317 bmp
.GetWidth(), bmp
.GetHeight());
1321 wxTheClipboard
->Close();
1324 #ifdef USE_METAFILES
1326 void DnDFrame::OnPasteMetafile(wxCommandEvent
& WXUNUSED(event
))
1328 if ( !wxTheClipboard
->Open() )
1330 wxLogError(_T("Can't open clipboard."));
1335 if ( !wxTheClipboard
->IsSupported(wxDF_METAFILE
) )
1337 wxLogWarning(_T("No metafile on clipboard"));
1341 wxMetaFileDataObject data
;
1342 if ( !wxTheClipboard
->GetData(data
) )
1344 wxLogError(_T("Can't paste metafile from the clipboard"));
1348 const wxMetaFile
& mf
= data
.GetMetafile();
1350 wxLogMessage(_T("Metafile %dx%d pasted from the clipboard"),
1351 mf
.GetWidth(), mf
.GetHeight());
1357 wxTheClipboard
->Close();
1360 #endif // USE_METAFILES
1362 // ----------------------------------------------------------------------------
1364 // ----------------------------------------------------------------------------
1366 void DnDFrame::OnCopyFiles(wxCommandEvent
& WXUNUSED(event
))
1369 wxFileDialog
dialog(this, "Select a file to copy", "", "",
1370 "All files (*.*)|*.*", 0);
1372 wxArrayString filenames
;
1373 while ( dialog
.ShowModal() == wxID_OK
)
1375 filenames
.Add(dialog
.GetPath());
1378 if ( !filenames
.IsEmpty() )
1380 wxFileDataObject
*dobj
= new wxFileDataObject
;
1381 size_t count
= filenames
.GetCount();
1382 for ( size_t n
= 0; n
< count
; n
++ )
1384 dobj
->AddFile(filenames
[n
]);
1387 wxClipboardLocker locker
;
1390 wxLogError(wxT("Can't open clipboard"));
1394 if ( !wxTheClipboard
->AddData(dobj
) )
1396 wxLogError(wxT("Can't copy file(s) to the clipboard"));
1400 wxLogStatus(this, wxT("%d file%s copied to the clipboard"),
1401 count
, count
== 1 ? wxT("") : wxT("s"));
1407 wxLogStatus(this, wxT("Aborted"));
1410 wxLogError(wxT("Sorry, not implemented"));
1414 // ---------------------------------------------------------------------------
1416 // ---------------------------------------------------------------------------
1418 void DnDFrame::OnCopy(wxCommandEvent
& WXUNUSED(event
))
1420 if ( !wxTheClipboard
->Open() )
1422 wxLogError(_T("Can't open clipboard."));
1427 if ( !wxTheClipboard
->AddData(new wxTextDataObject(m_strText
)) )
1429 wxLogError(_T("Can't copy data to the clipboard"));
1433 wxLogMessage(_T("Text '%s' put on the clipboard"), m_strText
.c_str());
1436 wxTheClipboard
->Close();
1439 void DnDFrame::OnPaste(wxCommandEvent
& WXUNUSED(event
))
1441 if ( !wxTheClipboard
->Open() )
1443 wxLogError(_T("Can't open clipboard."));
1448 if ( !wxTheClipboard
->IsSupported(wxDF_TEXT
) )
1450 wxLogWarning(_T("No text data on clipboard"));
1452 wxTheClipboard
->Close();
1456 wxTextDataObject text
;
1457 if ( !wxTheClipboard
->GetData(text
) )
1459 wxLogError(_T("Can't paste data from the clipboard"));
1463 wxLogMessage(_T("Text '%s' pasted from the clipboard"),
1464 text
.GetText().c_str());
1467 wxTheClipboard
->Close();
1470 // ----------------------------------------------------------------------------
1471 // Notifications called by the base class
1472 // ----------------------------------------------------------------------------
1474 bool DnDText::OnDropText(wxCoord
, wxCoord
, const wxString
& text
)
1476 m_pOwner
->Append(text
);
1481 bool DnDFile::OnDropFiles(wxCoord
, wxCoord
, const wxArrayString
& filenames
)
1483 size_t nFiles
= filenames
.GetCount();
1485 str
.Printf( _T("%d files dropped"), nFiles
);
1486 m_pOwner
->Append(str
);
1487 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
1488 m_pOwner
->Append(filenames
[n
]);
1494 // ----------------------------------------------------------------------------
1496 // ----------------------------------------------------------------------------
1498 DnDShapeDialog::DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
)
1500 :wxDialog( parent
, 6001, wxT("Choose Shape"), wxPoint( 10, 10 ),
1502 wxRAISED_BORDER
|wxCAPTION
|wxTHICK_FRAME
|wxSYSTEM_MENU
)
1507 LoadFromResource(parent
, "dialogShape");
1509 m_textX
= (wxTextCtrl
*)wxFindWindowByName("textX", this);
1510 m_textY
= (wxTextCtrl
*)wxFindWindowByName("textY", this);
1511 m_textW
= (wxTextCtrl
*)wxFindWindowByName("textW", this);
1512 m_textH
= (wxTextCtrl
*)wxFindWindowByName("textH", this);
1514 m_radio
= (wxRadioBox
*)wxFindWindowByName("radio", this);
1516 wxBoxSizer
* topSizer
= new wxBoxSizer( wxVERTICAL
);
1519 wxBoxSizer
* shapesSizer
= new wxBoxSizer( wxHORIZONTAL
);
1520 const wxString choices
[] = { wxT("None"), wxT("Triangle"),
1521 wxT("Rectangle"), wxT("Ellipse") };
1523 m_radio
= new wxRadioBox( this, -1, wxT("&Shape"),
1524 wxDefaultPosition
, wxDefaultSize
, 4, choices
, 4,
1525 wxRA_SPECIFY_COLS
);
1526 shapesSizer
->Add( m_radio
, 0, wxGROW
|wxALL
, 5 );
1527 topSizer
->Add( shapesSizer
, 0, wxALL
, 2 );
1530 wxStaticBox
* box
= new wxStaticBox( this, -1, wxT("&Attributes") );
1531 wxStaticBoxSizer
* attrSizer
= new wxStaticBoxSizer( box
, wxHORIZONTAL
);
1532 wxFlexGridSizer
* xywhSizer
= new wxFlexGridSizer( 4, 2 );
1536 st
= new wxStaticText( this, -1, wxT("Position &X:") );
1537 m_textX
= new wxTextCtrl( this, -1, wxEmptyString
, wxDefaultPosition
,
1539 xywhSizer
->Add( st
, 1, wxGROW
|wxALL
, 2 );
1540 xywhSizer
->Add( m_textX
, 1, wxGROW
|wxALL
, 2 );
1542 st
= new wxStaticText( this, -1, wxT("Size &width:") );
1543 m_textW
= new wxTextCtrl( this, -1, wxEmptyString
, wxDefaultPosition
,
1545 xywhSizer
->Add( st
, 1, wxGROW
|wxALL
, 2 );
1546 xywhSizer
->Add( m_textW
, 1, wxGROW
|wxALL
, 2 );
1548 st
= new wxStaticText( this, -1, wxT("&Y:") );
1549 m_textY
= new wxTextCtrl( this, -1, wxEmptyString
, wxDefaultPosition
,
1551 xywhSizer
->Add( st
, 1, wxALL
|wxALIGN_RIGHT
, 2 );
1552 xywhSizer
->Add( m_textY
, 1, wxGROW
|wxALL
, 2 );
1554 st
= new wxStaticText( this, -1, wxT("&height:") );
1555 m_textH
= new wxTextCtrl( this, -1, wxEmptyString
, wxDefaultPosition
,
1557 xywhSizer
->Add( st
, 1, wxALL
|wxALIGN_RIGHT
, 2 );
1558 xywhSizer
->Add( m_textH
, 1, wxGROW
|wxALL
, 2 );
1560 wxButton
* col
= new wxButton( this, Button_Colour
, wxT("&Colour...") );
1561 attrSizer
->Add( xywhSizer
, 1, wxGROW
);
1562 attrSizer
->Add( col
, 0, wxALL
|wxALIGN_CENTRE_VERTICAL
, 2 );
1563 topSizer
->Add( attrSizer
, 0, wxGROW
|wxALL
, 5 );
1566 wxBoxSizer
* buttonSizer
= new wxBoxSizer( wxHORIZONTAL
);
1568 bt
= new wxButton( this, wxID_OK
, wxT("Ok") );
1569 buttonSizer
->Add( bt
, 0, wxALL
, 2 );
1570 bt
= new wxButton( this, wxID_CANCEL
, wxT("Cancel") );
1571 buttonSizer
->Add( bt
, 0, wxALL
, 2 );
1572 topSizer
->Add( buttonSizer
, 0, wxALL
|wxALIGN_RIGHT
, 2 );
1574 SetAutoLayout( TRUE
);
1575 SetSizer( topSizer
);
1576 topSizer
->Fit( this );
1580 DnDShape
*DnDShapeDialog::GetShape() const
1582 switch ( m_shapeKind
)
1585 case DnDShape::None
: return NULL
;
1586 case DnDShape::Triangle
: return new DnDTriangularShape(m_pos
, m_size
, m_col
);
1587 case DnDShape::Rectangle
: return new DnDRectangularShape(m_pos
, m_size
, m_col
);
1588 case DnDShape::Ellipse
: return new DnDEllipticShape(m_pos
, m_size
, m_col
);
1592 bool DnDShapeDialog::TransferDataToWindow()
1597 m_radio
->SetSelection(m_shape
->GetKind());
1598 m_pos
= m_shape
->GetPosition();
1599 m_size
= m_shape
->GetSize();
1600 m_col
= m_shape
->GetColour();
1604 m_radio
->SetSelection(DnDShape::None
);
1605 m_pos
= wxPoint(1, 1);
1606 m_size
= wxSize(100, 100);
1609 m_textX
->SetValue(wxString() << m_pos
.x
);
1610 m_textY
->SetValue(wxString() << m_pos
.y
);
1611 m_textW
->SetValue(wxString() << m_size
.x
);
1612 m_textH
->SetValue(wxString() << m_size
.y
);
1617 bool DnDShapeDialog::TransferDataFromWindow()
1619 m_shapeKind
= (DnDShape::Kind
)m_radio
->GetSelection();
1621 m_pos
.x
= wxAtoi(m_textX
->GetValue());
1622 m_pos
.y
= wxAtoi(m_textY
->GetValue());
1623 m_size
.x
= wxAtoi(m_textW
->GetValue());
1624 m_size
.y
= wxAtoi(m_textH
->GetValue());
1626 if ( !m_pos
.x
|| !m_pos
.y
|| !m_size
.x
|| !m_size
.y
)
1628 wxMessageBox("All sizes and positions should be non null!",
1629 "Invalid shape", wxICON_HAND
| wxOK
, this);
1637 void DnDShapeDialog::OnColour(wxCommandEvent
& WXUNUSED(event
))
1640 data
.SetChooseFull(TRUE
);
1641 for (int i
= 0; i
< 16; i
++)
1643 wxColour
colour(i
*16, i
*16, i
*16);
1644 data
.SetCustomColour(i
, colour
);
1647 wxColourDialog
dialog(this, &data
);
1648 if ( dialog
.ShowModal() == wxID_OK
)
1650 m_col
= dialog
.GetColourData().GetColour();
1654 // ----------------------------------------------------------------------------
1656 // ----------------------------------------------------------------------------
1658 DnDShapeFrame
*DnDShapeFrame::ms_lastDropTarget
= NULL
;
1660 DnDShapeFrame::DnDShapeFrame(wxFrame
*parent
)
1661 : wxFrame(parent
, -1, "Shape Frame",
1662 wxDefaultPosition
, wxSize(250, 150))
1666 wxMenu
*menuShape
= new wxMenu
;
1667 menuShape
->Append(Menu_Shape_New
, "&New default shape\tCtrl-S");
1668 menuShape
->Append(Menu_Shape_Edit
, "&Edit shape\tCtrl-E");
1669 menuShape
->AppendSeparator();
1670 menuShape
->Append(Menu_Shape_Clear
, "&Clear shape\tCtrl-L");
1672 wxMenu
*menuClipboard
= new wxMenu
;
1673 menuClipboard
->Append(Menu_ShapeClipboard_Copy
, "&Copy\tCtrl-C");
1674 menuClipboard
->Append(Menu_ShapeClipboard_Paste
, "&Paste\tCtrl-V");
1676 wxMenuBar
*menubar
= new wxMenuBar
;
1677 menubar
->Append(menuShape
, "&Shape");
1678 menubar
->Append(menuClipboard
, "&Clipboard");
1680 SetMenuBar(menubar
);
1682 SetStatusText("Press Ctrl-S to create a new shape");
1684 SetDropTarget(new DnDShapeDropTarget(this));
1688 SetBackgroundColour(*wxWHITE
);
1691 DnDShapeFrame::~DnDShapeFrame()
1697 void DnDShapeFrame::SetShape(DnDShape
*shape
)
1706 void DnDShapeFrame::OnDrag(wxMouseEvent
& event
)
1715 // start drag operation
1716 DnDShapeDataObject
shapeData(m_shape
);
1717 wxDropSource
source(shapeData
, this);
1719 const char *pc
= NULL
;
1720 switch ( source
.DoDragDrop(TRUE
) )
1724 wxLogError(wxT("An error occured during drag and drop operation"));
1728 SetStatusText("Nothing happened");
1737 if ( ms_lastDropTarget
!= this )
1739 // don't delete the shape if we dropped it on ourselves!
1745 SetStatusText("Drag and drop operation cancelled");
1751 SetStatusText(wxString("Shape successfully ") + pc
);
1753 //else: status text already set
1756 void DnDShapeFrame::OnDrop(wxCoord x
, wxCoord y
, DnDShape
*shape
)
1758 ms_lastDropTarget
= this;
1763 s
.Printf(wxT("Shape dropped at (%d, %d)"), pt
.x
, pt
.y
);
1770 void DnDShapeFrame::OnEditShape(wxCommandEvent
& event
)
1772 DnDShapeDialog
dlg(this, m_shape
);
1773 if ( dlg
.ShowModal() == wxID_OK
)
1775 SetShape(dlg
.GetShape());
1779 SetStatusText("You can now drag the shape to another frame");
1784 void DnDShapeFrame::OnNewShape(wxCommandEvent
& event
)
1786 SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED
));
1788 SetStatusText("You can now drag the shape to another frame");
1791 void DnDShapeFrame::OnClearShape(wxCommandEvent
& event
)
1796 void DnDShapeFrame::OnCopyShape(wxCommandEvent
& event
)
1800 wxClipboardLocker clipLocker
;
1803 wxLogError(wxT("Can't open the clipboard"));
1808 wxTheClipboard
->AddData(new DnDShapeDataObject(m_shape
));
1812 void DnDShapeFrame::OnPasteShape(wxCommandEvent
& event
)
1814 wxClipboardLocker clipLocker
;
1817 wxLogError(wxT("Can't open the clipboard"));
1822 DnDShapeDataObject
shapeDataObject(NULL
);
1823 if ( wxTheClipboard
->GetData(shapeDataObject
) )
1825 SetShape(shapeDataObject
.GetShape());
1829 wxLogStatus(wxT("No shape on the clipboard"));
1833 void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent
& event
)
1835 event
.Enable( m_shape
!= NULL
);
1838 void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent
& event
)
1840 event
.Enable( wxTheClipboard
->IsSupported(wxDataFormat(shapeFormatId
)) );
1843 void DnDShapeFrame::OnPaint(wxPaintEvent
& event
)
1857 // ----------------------------------------------------------------------------
1859 // ----------------------------------------------------------------------------
1861 DnDShape
*DnDShape::New(const void *buf
)
1863 const ShapeDump
& dump
= *(const ShapeDump
*)buf
;
1867 return new DnDTriangularShape(wxPoint(dump
.x
, dump
.y
),
1868 wxSize(dump
.w
, dump
.h
),
1869 wxColour(dump
.r
, dump
.g
, dump
.b
));
1872 return new DnDRectangularShape(wxPoint(dump
.x
, dump
.y
),
1873 wxSize(dump
.w
, dump
.h
),
1874 wxColour(dump
.r
, dump
.g
, dump
.b
));
1877 return new DnDEllipticShape(wxPoint(dump
.x
, dump
.y
),
1878 wxSize(dump
.w
, dump
.h
),
1879 wxColour(dump
.r
, dump
.g
, dump
.b
));
1882 wxFAIL_MSG(wxT("invalid shape!"));
1887 // ----------------------------------------------------------------------------
1888 // DnDShapeDataObject
1889 // ----------------------------------------------------------------------------
1891 #ifdef USE_METAFILES
1893 void DnDShapeDataObject::CreateMetaFile() const
1895 wxPoint pos
= m_shape
->GetPosition();
1896 wxSize size
= m_shape
->GetSize();
1898 wxMetaFileDC
dcMF(wxEmptyString
, pos
.x
+ size
.x
, pos
.y
+ size
.y
);
1900 m_shape
->Draw(dcMF
);
1902 wxMetafile
*mf
= dcMF
.Close();
1904 DnDShapeDataObject
*self
= (DnDShapeDataObject
*)this; // const_cast
1905 self
->m_dobjMetaFile
.SetMetafile(*mf
);
1906 self
->m_hasMetaFile
= TRUE
;
1913 void DnDShapeDataObject::CreateBitmap() const
1915 wxPoint pos
= m_shape
->GetPosition();
1916 wxSize size
= m_shape
->GetSize();
1917 int x
= pos
.x
+ size
.x
,
1919 wxBitmap
bitmap(x
, y
);
1921 dc
.SelectObject(bitmap
);
1922 dc
.SetBrush(wxBrush(wxT("white"), wxSOLID
));
1925 dc
.SelectObject(wxNullBitmap
);
1927 DnDShapeDataObject
*self
= (DnDShapeDataObject
*)this; // const_cast
1928 self
->m_dobjBitmap
.SetBitmap(bitmap
);
1929 self
->m_hasBitmap
= TRUE
;
1932 // ----------------------------------------------------------------------------
1934 // ----------------------------------------------------------------------------
1936 static void ShowBitmap(const wxBitmap
& bitmap
)
1938 wxFrame
*frame
= new wxFrame(NULL
, -1, _T("Bitmap view"));
1939 frame
->CreateStatusBar();
1940 DnDCanvasBitmap
*canvas
= new DnDCanvasBitmap(frame
);
1941 canvas
->SetBitmap(bitmap
);
1943 int w
= bitmap
.GetWidth(),
1944 h
= bitmap
.GetHeight();
1945 frame
->SetStatusText(wxString::Format(_T("%dx%d"), w
, h
));
1947 frame
->SetClientSize(w
> 100 ? 100 : w
, h
> 100 ? 100 : h
);
1951 #ifdef USE_METAFILES
1953 static void ShowMetaFile(const wxMetaFile
& metafile
)
1955 wxFrame
*frame
= new wxFrame(NULL
, -1, _T("Metafile view"));
1956 frame
->CreateStatusBar();
1957 DnDCanvasMetafile
*canvas
= new DnDCanvasMetafile(frame
);
1958 canvas
->SetMetafile(metafile
);
1960 wxSize size
= metafile
.GetSize();
1961 frame
->SetStatusText(wxString::Format(_T("%dx%d"), size
.x
, size
.y
));
1963 frame
->SetClientSize(size
.x
> 100 ? 100 : size
.x
,
1964 size
.y
> 100 ? 100 : size
.y
);
1968 #endif // USE_METAFILES