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
36 #include "wx/dirdlg.h"
37 #include "wx/filedlg.h"
39 #include "wx/clipbrd.h"
40 #include "wx/colordlg.h"
41 #include "wx/resource.h"
44 #include "wx/metafile.h"
47 #if defined(__WXGTK__) || defined(__WXMOTIF__)
48 #include "mondrian.xpm"
50 #include "dnd_copy.xpm"
51 #include "dnd_move.xpm"
52 #include "dnd_none.xpm"
55 // ----------------------------------------------------------------------------
56 // Derive two simple classes which just put in the listbox the strings (text or
57 // file names) we drop on them
58 // ----------------------------------------------------------------------------
60 class DnDText
: public wxTextDropTarget
63 DnDText(wxListBox
*pOwner
) { m_pOwner
= pOwner
; }
65 virtual bool OnDropText(wxCoord x
, wxCoord y
, const wxString
& text
);
71 class DnDFile
: public wxFileDropTarget
74 DnDFile(wxListBox
*pOwner
) { m_pOwner
= pOwner
; }
76 virtual bool OnDropFiles(wxCoord x
, wxCoord y
,
77 const wxArrayString
& filenames
);
83 // ----------------------------------------------------------------------------
84 // Define a custom dtop target accepting URLs
85 // ----------------------------------------------------------------------------
87 class WXDLLEXPORT URLDropTarget
: public wxDropTarget
90 URLDropTarget() { SetDataObject(new wxURLDataObject
); }
92 void OnDropURL(wxCoord x
, wxCoord y
, const wxString
& text
)
94 // of course, a real program would do something more useful here...
95 wxMessageBox(text
, _T("wxDnD sample: got URL"),
96 wxICON_INFORMATION
| wxOK
);
99 // URLs can't be moved, only copied
100 virtual wxDragResult
OnDragOver(wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
102 { return def
== wxDragMove
? wxDragCopy
: def
; }
104 // translate this to calls to OnDropURL() just for convenience
105 virtual wxDragResult
OnData(wxCoord x
, wxCoord y
, wxDragResult def
)
110 OnDropURL(x
, y
, ((wxURLDataObject
*)m_dataObject
)->GetURL());
116 // ----------------------------------------------------------------------------
117 // Define a new application type
118 // ----------------------------------------------------------------------------
120 class DnDApp
: public wxApp
123 virtual bool OnInit();
126 IMPLEMENT_APP(DnDApp
);
128 // ----------------------------------------------------------------------------
129 // Define canvas class to show a bitmap
130 // ----------------------------------------------------------------------------
132 class DnDCanvasBitmap
: public wxScrolledWindow
135 DnDCanvasBitmap(wxWindow
*parent
) : wxScrolledWindow(parent
) { }
137 void SetBitmap(const wxBitmap
& bitmap
)
141 SetScrollbars(10, 10,
142 m_bitmap
.GetWidth() / 10, m_bitmap
.GetHeight() / 10);
147 void OnPaint(wxPaintEvent
& event
)
155 dc
.DrawBitmap(m_bitmap
, 0, 0);
162 DECLARE_EVENT_TABLE()
167 // and the same thing fo metafiles
168 class DnDCanvasMetafile
: public wxScrolledWindow
171 DnDCanvasMetafile(wxWindow
*parent
) : wxScrolledWindow(parent
) { }
173 void SetMetafile(const wxMetafile
& metafile
)
175 m_metafile
= metafile
;
177 SetScrollbars(10, 10,
178 m_metafile
.GetWidth() / 10, m_metafile
.GetHeight() / 10);
183 void OnPaint(wxPaintEvent
& event
)
187 if ( m_metafile
.Ok() )
191 m_metafile
.Play(&dc
);
196 wxMetafile m_metafile
;
198 DECLARE_EVENT_TABLE()
201 #endif // USE_METAFILES
203 // ----------------------------------------------------------------------------
204 // Define a new frame type for the main frame
205 // ----------------------------------------------------------------------------
207 class DnDFrame
: public wxFrame
210 DnDFrame(wxFrame
*frame
, char *title
, int x
, int y
, int w
, int h
);
213 void OnPaint(wxPaintEvent
& event
);
214 void OnQuit (wxCommandEvent
& event
);
215 void OnAbout(wxCommandEvent
& event
);
216 void OnDrag (wxCommandEvent
& event
);
217 void OnNewFrame(wxCommandEvent
& event
);
218 void OnHelp (wxCommandEvent
& event
);
219 void OnLogClear(wxCommandEvent
& event
);
221 void OnCopy(wxCommandEvent
& event
);
222 void OnPaste(wxCommandEvent
& event
);
224 void OnCopyBitmap(wxCommandEvent
& event
);
225 void OnPasteBitmap(wxCommandEvent
& event
);
228 void OnPasteMetafile(wxCommandEvent
& event
);
229 #endif // USE_METAFILES
231 void OnCopyFiles(wxCommandEvent
& event
);
233 void OnLeftDown(wxMouseEvent
& event
);
234 void OnRightDown(wxMouseEvent
& event
);
236 void OnUpdateUIPasteText(wxUpdateUIEvent
& event
);
237 void OnUpdateUIPasteBitmap(wxUpdateUIEvent
& event
);
239 DECLARE_EVENT_TABLE()
242 wxListBox
*m_ctrlFile
,
244 wxTextCtrl
*m_ctrlLog
;
252 // ----------------------------------------------------------------------------
253 // A shape is an example of application-specific data which may be transported
254 // via drag-and-drop or clipboard: in our case, we have different geometric
255 // shapes, each one with its own colour and position
256 // ----------------------------------------------------------------------------
269 DnDShape(const wxPoint
& pos
,
272 : m_pos(pos
), m_size(size
), m_col(col
)
276 // this is for debugging - lets us see when exactly an object is freed
277 // (this may be later than you think if it's on the clipboard, for example)
278 virtual ~DnDShape() { }
280 // the functions used for drag-and-drop: they dump and restore a shape into
281 // some bitwise-copiable data (might use streams too...)
282 // ------------------------------------------------------------------------
284 // restore from buffer
285 static DnDShape
*New(const void *buf
);
287 virtual size_t GetDataSize() const
289 return sizeof(ShapeDump
);
292 virtual void GetDataHere(void *buf
) const
294 ShapeDump
& dump
= *(ShapeDump
*)buf
;
299 dump
.r
= m_col
.Red();
300 dump
.g
= m_col
.Green();
301 dump
.b
= m_col
.Blue();
306 const wxPoint
& GetPosition() const { return m_pos
; }
307 const wxColour
& GetColour() const { return m_col
; }
308 const wxSize
& GetSize() const { return m_size
; }
310 void Move(const wxPoint
& pos
) { m_pos
= pos
; }
312 // to implement in derived classes
313 virtual Kind
GetKind() const = 0;
315 virtual void Draw(wxDC
& dc
)
317 dc
.SetPen(wxPen(m_col
, 1, wxSOLID
));
321 wxPoint
GetCentre() const
322 { return wxPoint(m_pos
.x
+ m_size
.x
/ 2, m_pos
.y
+ m_size
.y
/ 2); }
326 int x
, y
, // position
337 class DnDTriangularShape
: public DnDShape
340 DnDTriangularShape(const wxPoint
& pos
,
343 : DnDShape(pos
, size
, col
)
345 wxLogMessage("DnDTriangularShape is being created");
348 virtual ~DnDTriangularShape()
350 wxLogMessage("DnDTriangularShape is being deleted");
353 virtual Kind
GetKind() const { return Triangle
; }
354 virtual void Draw(wxDC
& dc
)
358 // well, it's a bit difficult to describe a triangle by position and
359 // size, but we're not doing geometry here, do we? ;-)
361 wxPoint
p2(m_pos
.x
+ m_size
.x
, m_pos
.y
);
362 wxPoint
p3(m_pos
.x
, m_pos
.y
+ m_size
.y
);
369 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
374 class DnDRectangularShape
: public DnDShape
377 DnDRectangularShape(const wxPoint
& pos
,
380 : DnDShape(pos
, size
, col
)
382 wxLogMessage("DnDRectangularShape is being created");
385 virtual ~DnDRectangularShape()
387 wxLogMessage("DnDRectangularShape is being deleted");
390 virtual Kind
GetKind() const { return Rectangle
; }
391 virtual void Draw(wxDC
& dc
)
396 wxPoint
p2(p1
.x
+ m_size
.x
, p1
.y
);
397 wxPoint
p3(p2
.x
, p2
.y
+ m_size
.y
);
398 wxPoint
p4(p1
.x
, p3
.y
);
406 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
411 class DnDEllipticShape
: public DnDShape
414 DnDEllipticShape(const wxPoint
& pos
,
417 : DnDShape(pos
, size
, col
)
419 wxLogMessage("DnDEllipticShape is being created");
422 virtual ~DnDEllipticShape()
424 wxLogMessage("DnDEllipticShape is being deleted");
427 virtual Kind
GetKind() const { return Ellipse
; }
428 virtual void Draw(wxDC
& dc
)
432 dc
.DrawEllipse(m_pos
, m_size
);
435 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
440 // ----------------------------------------------------------------------------
441 // A wxDataObject specialisation for the application-specific data
442 // ----------------------------------------------------------------------------
444 static const char *shapeFormatId
= "wxShape";
446 class DnDShapeDataObject
: public wxDataObject
449 // ctor doesn't copy the pointer, so it shouldn't go away while this object
451 DnDShapeDataObject(DnDShape
*shape
= (DnDShape
*)NULL
)
455 // we need to copy the shape because the one we're handled may be
456 // deleted while it's still on the clipboard (for example) - and we
457 // reuse the serialisation methods here to copy it
458 void *buf
= malloc(shape
->DnDShape::GetDataSize());
459 shape
->GetDataHere(buf
);
460 m_shape
= DnDShape::New(buf
);
470 // this string should uniquely identify our format, but is otherwise
472 m_formatShape
.SetId(shapeFormatId
);
474 // we don't draw the shape to a bitmap until it's really needed (i.e.
475 // we're asked to do so)
478 m_hasMetaFile
= FALSE
;
482 virtual ~DnDShapeDataObject() { delete m_shape
; }
484 // after a call to this function, the shape is owned by the caller and it
485 // is responsible for deleting it!
487 // NB: a better solution would be to make DnDShapes ref counted and this
488 // is what should probably be done in a real life program, otherwise
489 // the ownership problems become too complicated really fast
492 DnDShape
*shape
= m_shape
;
494 m_shape
= (DnDShape
*)NULL
;
497 m_hasMetaFile
= FALSE
;
503 // implement base class pure virtuals
504 // ----------------------------------
506 virtual wxDataFormat
GetPreferredFormat(Direction
WXUNUSED(dir
)) const
508 return m_formatShape
;
511 virtual size_t GetFormatCount(Direction dir
) const
513 // our custom format is supported by both GetData() and SetData()
517 // but the bitmap format(s) are only supported for output
518 nFormats
+= m_dobjBitmap
.GetFormatCount(dir
);
521 nFormats
+= m_dobjMetaFile
.GetFormatCount(dir
);
528 virtual void GetAllFormats(wxDataFormat
*formats
, Direction dir
) const
530 formats
[0] = m_formatShape
;
533 // in Get direction we additionally support bitmaps and metafiles
535 m_dobjBitmap
.GetAllFormats(&formats
[1], dir
);
538 // don't assume that m_dobjBitmap has only 1 format
539 m_dobjMetaFile
.GetAllFormats(&formats
[1 +
540 m_dobjBitmap
.GetFormatCount(dir
)], dir
);
545 virtual size_t GetDataSize(const wxDataFormat
& format
) const
547 if ( format
== m_formatShape
)
549 return m_shape
->GetDataSize();
552 else if ( m_dobjMetaFile
.IsSupported(format
) )
554 if ( !m_hasMetaFile
)
557 return m_dobjMetaFile
.GetDataSize(format
);
562 wxASSERT_MSG( m_dobjBitmap
.IsSupported(format
),
563 "unexpected format" );
568 return m_dobjBitmap
.GetDataSize();
572 virtual bool GetDataHere(const wxDataFormat
& format
, void *pBuf
) const
574 if ( format
== m_formatShape
)
576 m_shape
->GetDataHere(pBuf
);
581 else if ( m_dobjMetaFile
.IsSupported(format
) )
583 if ( !m_hasMetaFile
)
586 return m_dobjMetaFile
.GetDataHere(format
, pBuf
);
591 wxASSERT_MSG( m_dobjBitmap
.IsSupported(format
),
592 "unexpected format" );
597 return m_dobjBitmap
.GetDataHere(pBuf
);
601 virtual bool SetData(const wxDataFormat
& format
,
602 size_t len
, const void *buf
)
604 wxCHECK_MSG( format
== m_formatShape
, FALSE
, "unsupported format" );
607 m_shape
= DnDShape::New(buf
);
609 // the shape has changed
613 m_hasMetaFile
= FALSE
;
620 // creates a bitmap and assigns it to m_dobjBitmap (also sets m_hasBitmap)
621 void CreateBitmap() const;
623 void CreateMetaFile() const;
626 wxDataFormat m_formatShape
; // our custom format
628 wxBitmapDataObject m_dobjBitmap
; // it handles bitmaps
629 bool m_hasBitmap
; // true if m_dobjBitmap has valid bitmap
632 wxMetaFileDataObject m_dobjMetaFile
;// handles metafiles
633 bool m_hasMetaFile
; // true if we have valid metafile
636 DnDShape
*m_shape
; // our data
639 // ----------------------------------------------------------------------------
640 // A dialog to edit shape properties
641 // ----------------------------------------------------------------------------
643 class DnDShapeDialog
: public wxDialog
646 DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
);
648 DnDShape
*GetShape() const;
650 virtual bool TransferDataToWindow();
651 virtual bool TransferDataFromWindow();
653 void OnColour(wxCommandEvent
& event
);
660 DnDShape::Kind m_shapeKind
;
672 DECLARE_EVENT_TABLE()
675 // ----------------------------------------------------------------------------
676 // A frame for the shapes which can be drag-and-dropped between frames
677 // ----------------------------------------------------------------------------
679 class DnDShapeFrame
: public wxFrame
682 DnDShapeFrame(wxFrame
*parent
);
685 void SetShape(DnDShape
*shape
);
688 void OnNewShape(wxCommandEvent
& event
);
689 void OnEditShape(wxCommandEvent
& event
);
690 void OnClearShape(wxCommandEvent
& event
);
692 void OnCopyShape(wxCommandEvent
& event
);
693 void OnPasteShape(wxCommandEvent
& event
);
695 void OnUpdateUICopy(wxUpdateUIEvent
& event
);
696 void OnUpdateUIPaste(wxUpdateUIEvent
& event
);
698 void OnDrag(wxMouseEvent
& event
);
699 void OnPaint(wxPaintEvent
& event
);
700 void OnDrop(wxCoord x
, wxCoord y
, DnDShape
*shape
);
705 static DnDShapeFrame
*ms_lastDropTarget
;
707 DECLARE_EVENT_TABLE()
710 // ----------------------------------------------------------------------------
711 // wxDropTarget derivation for DnDShapes
712 // ----------------------------------------------------------------------------
714 class DnDShapeDropTarget
: public wxDropTarget
717 DnDShapeDropTarget(DnDShapeFrame
*frame
)
718 : wxDropTarget(new DnDShapeDataObject
)
723 // override base class (pure) virtuals
724 virtual wxDragResult
OnEnter(wxCoord x
, wxCoord y
, wxDragResult def
)
725 { m_frame
->SetStatusText("Mouse entered the frame"); return OnDragOver(x
, y
, def
); }
726 virtual void OnLeave()
727 { m_frame
->SetStatusText("Mouse left the frame"); }
728 virtual wxDragResult
OnData(wxCoord x
, wxCoord y
, wxDragResult def
)
732 wxLogError("Failed to get drag and drop data");
737 m_frame
->OnDrop(x
, y
,
738 ((DnDShapeDataObject
*)GetDataObject())->GetShape());
744 DnDShapeFrame
*m_frame
;
747 // ----------------------------------------------------------------------------
748 // functions prototypes
749 // ----------------------------------------------------------------------------
751 static void ShowBitmap(const wxBitmap
& bitmap
);
754 static void ShowMetaFile(const wxMetaFile
& metafile
);
755 #endif // USE_METAFILES
757 // ----------------------------------------------------------------------------
758 // IDs for the menu commands
759 // ----------------------------------------------------------------------------
775 Menu_Shape_New
= 500,
778 Menu_ShapeClipboard_Copy
,
779 Menu_ShapeClipboard_Paste
,
783 BEGIN_EVENT_TABLE(DnDFrame
, wxFrame
)
784 EVT_MENU(Menu_Quit
, DnDFrame::OnQuit
)
785 EVT_MENU(Menu_About
, DnDFrame::OnAbout
)
786 EVT_MENU(Menu_Drag
, DnDFrame::OnDrag
)
787 EVT_MENU(Menu_NewFrame
, DnDFrame::OnNewFrame
)
788 EVT_MENU(Menu_Help
, DnDFrame::OnHelp
)
789 EVT_MENU(Menu_Clear
, DnDFrame::OnLogClear
)
790 EVT_MENU(Menu_Copy
, DnDFrame::OnCopy
)
791 EVT_MENU(Menu_Paste
, DnDFrame::OnPaste
)
792 EVT_MENU(Menu_CopyBitmap
, DnDFrame::OnCopyBitmap
)
793 EVT_MENU(Menu_PasteBitmap
,DnDFrame::OnPasteBitmap
)
795 EVT_MENU(Menu_PasteMFile
, DnDFrame::OnPasteMetafile
)
796 #endif // USE_METAFILES
797 EVT_MENU(Menu_CopyFiles
, DnDFrame::OnCopyFiles
)
799 EVT_UPDATE_UI(Menu_Paste
, DnDFrame::OnUpdateUIPasteText
)
800 EVT_UPDATE_UI(Menu_PasteBitmap
, DnDFrame::OnUpdateUIPasteBitmap
)
802 EVT_LEFT_DOWN( DnDFrame::OnLeftDown
)
803 EVT_RIGHT_DOWN( DnDFrame::OnRightDown
)
804 EVT_PAINT( DnDFrame::OnPaint
)
807 BEGIN_EVENT_TABLE(DnDShapeFrame
, wxFrame
)
808 EVT_MENU(Menu_Shape_New
, DnDShapeFrame::OnNewShape
)
809 EVT_MENU(Menu_Shape_Edit
, DnDShapeFrame::OnEditShape
)
810 EVT_MENU(Menu_Shape_Clear
, DnDShapeFrame::OnClearShape
)
812 EVT_MENU(Menu_ShapeClipboard_Copy
, DnDShapeFrame::OnCopyShape
)
813 EVT_MENU(Menu_ShapeClipboard_Paste
, DnDShapeFrame::OnPasteShape
)
815 EVT_UPDATE_UI(Menu_ShapeClipboard_Copy
, DnDShapeFrame::OnUpdateUICopy
)
816 EVT_UPDATE_UI(Menu_ShapeClipboard_Paste
, DnDShapeFrame::OnUpdateUIPaste
)
818 EVT_LEFT_DOWN(DnDShapeFrame::OnDrag
)
820 EVT_PAINT(DnDShapeFrame::OnPaint
)
823 BEGIN_EVENT_TABLE(DnDShapeDialog
, wxDialog
)
824 EVT_BUTTON(Button_Colour
, DnDShapeDialog::OnColour
)
827 BEGIN_EVENT_TABLE(DnDCanvasBitmap
, wxScrolledWindow
)
828 EVT_PAINT(DnDCanvasBitmap::OnPaint
)
832 BEGIN_EVENT_TABLE(DnDCanvasMetafile
, wxScrolledWindow
)
833 EVT_PAINT(DnDCanvasMetafile::OnPaint
)
835 #endif // USE_METAFILES
837 // ============================================================================
839 // ============================================================================
841 // `Main program' equivalent, creating windows and returning main app frame
842 bool DnDApp::OnInit()
844 // load our ressources
848 pathList
.Add("./Debug");
849 pathList
.Add("./Release");
852 wxString path
= pathList
.FindValidPath("dnd.wxr");
855 wxLogError("Can't find the resource file dnd.wxr in the current "
856 "directory, aborting.");
861 wxDefaultResourceTable
->ParseResourceFile(path
);
863 // switch on trace messages
864 #if defined(__WXGTK__)
865 wxLog::AddTraceMask(_T("clipboard"));
866 #elif defined(__WXMSW__)
867 wxLog::AddTraceMask(wxTRACE_OleCalls
);
871 wxImage::AddHandler( new wxPNGHandler
);
874 // under X we usually want to use the primary selection by default (which
875 // is shared with other apps)
876 wxTheClipboard
->UsePrimarySelection();
878 // create the main frame window
879 DnDFrame
*frame
= new DnDFrame((wxFrame
*) NULL
,
880 "Drag-and-Drop/Clipboard wxWindows Sample",
891 DnDFrame::DnDFrame(wxFrame
*frame
, char *title
, int x
, int y
, int w
, int h
)
892 : wxFrame(frame
, -1, title
, wxPoint(x
, y
), wxSize(w
, h
)),
893 m_strText("wxWindows drag & drop works :-)")
896 // frame icon and status bar
897 SetIcon(wxICON(mondrian
));
902 wxMenu
*file_menu
= new wxMenu
;
903 file_menu
->Append(Menu_Drag
, "&Test drag...");
904 file_menu
->AppendSeparator();
905 file_menu
->Append(Menu_NewFrame
, "&New frame\tCtrl-N");
906 file_menu
->AppendSeparator();
907 file_menu
->Append(Menu_Quit
, "E&xit");
909 wxMenu
*log_menu
= new wxMenu
;
910 log_menu
->Append(Menu_Clear
, "Clear\tCtrl-L");
912 wxMenu
*help_menu
= new wxMenu
;
913 help_menu
->Append(Menu_Help
, "&Help...");
914 help_menu
->AppendSeparator();
915 help_menu
->Append(Menu_About
, "&About");
917 wxMenu
*clip_menu
= new wxMenu
;
918 clip_menu
->Append(Menu_Copy
, "&Copy text\tCtrl+C");
919 clip_menu
->Append(Menu_Paste
, "&Paste text\tCtrl+V");
920 clip_menu
->AppendSeparator();
921 clip_menu
->Append(Menu_CopyBitmap
, "Copy &bitmap\tAlt+C");
922 clip_menu
->Append(Menu_PasteBitmap
, "Paste b&itmap\tAlt+V");
924 clip_menu
->AppendSeparator();
925 clip_menu
->Append(Menu_PasteMFile
, "Paste &metafile\tCtrl-M");
926 #endif // USE_METAFILES
927 clip_menu
->AppendSeparator();
928 clip_menu
->Append(Menu_CopyFiles
, "Copy &files\tCtrl+F");
930 wxMenuBar
*menu_bar
= new wxMenuBar
;
931 menu_bar
->Append(file_menu
, "&File");
932 menu_bar
->Append(log_menu
, "&Log");
933 menu_bar
->Append(clip_menu
, "&Clipboard");
934 menu_bar
->Append(help_menu
, "&Help");
936 SetMenuBar(menu_bar
);
938 // make a panel with 3 subwindows
940 wxSize
size(400, 200);
942 wxString
strFile("Drop files here!"), strText("Drop text on me");
944 m_ctrlFile
= new wxListBox(this, -1, pos
, size
, 1, &strFile
,
945 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
946 m_ctrlText
= new wxListBox(this, -1, pos
, size
, 1, &strText
,
947 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
949 m_ctrlLog
= new wxTextCtrl(this, -1, "", pos
, size
,
950 wxTE_MULTILINE
| wxTE_READONLY
|
953 // redirect log messages to the text window
954 m_pLog
= new wxLogTextCtrl(m_ctrlLog
);
955 m_pLogPrev
= wxLog::SetActiveTarget(m_pLog
);
957 // associate drop targets with the controls
958 m_ctrlFile
->SetDropTarget(new DnDFile(m_ctrlFile
));
959 m_ctrlText
->SetDropTarget(new DnDText(m_ctrlText
));
960 m_ctrlLog
->SetDropTarget(new URLDropTarget
);
962 wxLayoutConstraints
*c
;
965 c
= new wxLayoutConstraints
;
966 c
->left
.SameAs(this, wxLeft
);
967 c
->top
.SameAs(this, wxTop
);
968 c
->right
.PercentOf(this, wxRight
, 50);
969 c
->height
.PercentOf(this, wxHeight
, 30);
970 m_ctrlFile
->SetConstraints(c
);
973 c
= new wxLayoutConstraints
;
974 c
->left
.SameAs (m_ctrlFile
, wxRight
);
975 c
->top
.SameAs (this, wxTop
);
976 c
->right
.SameAs (this, wxRight
);
977 c
->height
.PercentOf(this, wxHeight
, 30);
978 m_ctrlText
->SetConstraints(c
);
980 // Lower text control
981 c
= new wxLayoutConstraints
;
982 c
->left
.SameAs (this, wxLeft
);
983 c
->right
.SameAs (this, wxRight
);
984 c
->height
.PercentOf(this, wxHeight
, 50);
985 c
->top
.SameAs(m_ctrlText
, wxBottom
);
986 m_ctrlLog
->SetConstraints(c
);
991 void DnDFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
))
996 void DnDFrame::OnPaint(wxPaintEvent
& WXUNUSED(event
))
1000 GetClientSize( &w
, &h
);
1003 dc
.SetFont( wxFont( 24, wxDECORATIVE
, wxNORMAL
, wxNORMAL
, FALSE
, "charter" ) );
1004 dc
.DrawText( "Drag text from here!", 100, h
-50 );
1007 void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent
& event
)
1010 // too many trace messages if we don't do it - this function is called
1015 event
.Enable( wxTheClipboard
->IsSupported(wxDF_TEXT
) );
1018 void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent
& event
)
1021 // too many trace messages if we don't do it - this function is called
1026 event
.Enable( wxTheClipboard
->IsSupported(wxDF_BITMAP
) );
1029 void DnDFrame::OnNewFrame(wxCommandEvent
& WXUNUSED(event
))
1031 (new DnDShapeFrame(this))->Show(TRUE
);
1033 wxLogStatus(this, "Double click the new frame to select a shape for it");
1036 void DnDFrame::OnDrag(wxCommandEvent
& WXUNUSED(event
))
1038 wxString strText
= wxGetTextFromUser
1040 "After you enter text in this dialog, press any mouse\n"
1041 "button in the bottom (empty) part of the frame and \n"
1042 "drag it anywhere - you will be in fact dragging the\n"
1043 "text object containing this text",
1044 "Please enter some text", m_strText
, this
1047 m_strText
= strText
;
1050 void DnDFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
1052 wxMessageBox("Drag-&-Drop Demo\n"
1053 "Please see \"Help|Help...\" for details\n"
1054 "Copyright (c) 1998 Vadim Zeitlin",
1056 wxICON_INFORMATION
| wxOK
,
1060 void DnDFrame::OnHelp(wxCommandEvent
& /* event */)
1062 wxMessageDialog
dialog(this,
1063 "This small program demonstrates drag & drop support in wxWindows. The program window\n"
1064 "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
1065 "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
1066 "and the right one accepts text.\n"
1068 "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
1069 "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
1070 "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
1071 "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
1072 "work with files) and see what changes.\n"
1074 "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
1075 "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
1076 "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
1077 "change, don't release the mouse button until it does. You can change the string being\n"
1078 "dragged in in \"File|Test drag...\" dialog.\n"
1081 "Please send all questions/bug reports/suggestions &c to \n"
1082 "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
1088 void DnDFrame::OnLogClear(wxCommandEvent
& /* event */ )
1091 m_ctrlText
->Clear();
1092 m_ctrlFile
->Clear();
1095 void DnDFrame::OnLeftDown(wxMouseEvent
&WXUNUSED(event
) )
1097 if ( !m_strText
.IsEmpty() )
1099 // start drag operation
1100 wxTextDataObject
textData(m_strText
);
1102 wxFileDataObject textData;
1103 textData.AddFile( "/file1.txt" );
1104 textData.AddFile( "/file2.txt" );
1106 wxDropSource
source(textData
, this,
1107 wxDROP_ICON(dnd_copy
),
1108 wxDROP_ICON(dnd_move
),
1109 wxDROP_ICON(dnd_none
));
1113 switch ( source
.DoDragDrop(TRUE
) )
1115 case wxDragError
: pc
= "Error!"; break;
1116 case wxDragNone
: pc
= "Nothing"; break;
1117 case wxDragCopy
: pc
= "Copied"; break;
1118 case wxDragMove
: pc
= "Moved"; break;
1119 case wxDragCancel
: pc
= "Cancelled"; break;
1120 default: pc
= "Huh?"; break;
1123 SetStatusText(wxString("Drag result: ") + pc
);
1127 void DnDFrame::OnRightDown(wxMouseEvent
&event
)
1129 wxMenu
menu("Dnd sample menu");
1131 menu
.Append(Menu_Drag
, "&Test drag...");
1132 menu
.AppendSeparator();
1133 menu
.Append(Menu_About
, "&About");
1135 PopupMenu( &menu
, event
.GetX(), event
.GetY() );
1138 DnDFrame::~DnDFrame()
1140 if ( m_pLog
!= NULL
) {
1141 if ( wxLog::SetActiveTarget(m_pLogPrev
) == m_pLog
)
1146 // ---------------------------------------------------------------------------
1148 // ---------------------------------------------------------------------------
1150 void DnDFrame::OnCopyBitmap(wxCommandEvent
& WXUNUSED(event
))
1152 // PNG support is not always compiled in under Windows, so use BMP there
1154 wxFileDialog
dialog(this, "Open a BMP file", "", "", "BMP files (*.bmp)|*.bmp", 0);
1156 wxFileDialog
dialog(this, "Open a PNG file", "", "", "PNG files (*.png)|*.png", 0);
1159 if (dialog
.ShowModal() != wxID_OK
)
1161 wxLogMessage( _T("Aborted file open") );
1165 if (dialog
.GetPath().IsEmpty())
1167 wxLogMessage( _T("Returned empty string.") );
1171 if (!wxFileExists(dialog
.GetPath()))
1173 wxLogMessage( _T("File doesn't exist.") );
1178 image
.LoadFile( dialog
.GetPath(),
1187 wxLogError( _T("Invalid image file...") );
1191 wxLogStatus( _T("Decoding image file...") );
1194 wxBitmap
bitmap( image
.ConvertToBitmap() );
1196 if ( !wxTheClipboard
->Open() )
1198 wxLogError(_T("Can't open clipboard."));
1203 wxLogMessage( _T("Creating wxBitmapDataObject...") );
1206 if ( !wxTheClipboard
->AddData(new wxBitmapDataObject(bitmap
)) )
1208 wxLogError(_T("Can't copy image to the clipboard."));
1212 wxLogMessage(_T("Image has been put on the clipboard.") );
1213 wxLogMessage(_T("You can paste it now and look at it.") );
1216 wxTheClipboard
->Close();
1219 void DnDFrame::OnPasteBitmap(wxCommandEvent
& WXUNUSED(event
))
1221 if ( !wxTheClipboard
->Open() )
1223 wxLogError(_T("Can't open clipboard."));
1228 if ( !wxTheClipboard
->IsSupported(wxDF_BITMAP
) )
1230 wxLogWarning(_T("No bitmap on clipboard"));
1232 wxTheClipboard
->Close();
1236 wxBitmapDataObject data
;
1237 if ( !wxTheClipboard
->GetData(data
) )
1239 wxLogError(_T("Can't paste bitmap from the clipboard"));
1243 const wxBitmap
& bmp
= data
.GetBitmap();
1245 wxLogMessage(_T("Bitmap %dx%d pasted from the clipboard"),
1246 bmp
.GetWidth(), bmp
.GetHeight());
1250 wxTheClipboard
->Close();
1253 #ifdef USE_METAFILES
1255 void DnDFrame::OnPasteMetafile(wxCommandEvent
& WXUNUSED(event
))
1257 if ( !wxTheClipboard
->Open() )
1259 wxLogError(_T("Can't open clipboard."));
1264 if ( !wxTheClipboard
->IsSupported(wxDF_METAFILE
) )
1266 wxLogWarning(_T("No metafile on clipboard"));
1270 wxMetaFileDataObject data
;
1271 if ( !wxTheClipboard
->GetData(data
) )
1273 wxLogError(_T("Can't paste metafile from the clipboard"));
1277 const wxMetaFile
& mf
= data
.GetMetafile();
1279 wxLogMessage(_T("Metafile %dx%d pasted from the clipboard"),
1280 mf
.GetWidth(), mf
.GetHeight());
1286 wxTheClipboard
->Close();
1289 #endif // USE_METAFILES
1291 // ----------------------------------------------------------------------------
1293 // ----------------------------------------------------------------------------
1295 void DnDFrame::OnCopyFiles(wxCommandEvent
& WXUNUSED(event
))
1298 wxFileDialog
dialog(this, "Select a file to copy", "", "",
1299 "All files (*.*)|*.*", 0);
1301 wxArrayString filenames
;
1302 while ( dialog
.ShowModal() == wxID_OK
)
1304 filenames
.Add(dialog
.GetPath());
1307 if ( !filenames
.IsEmpty() )
1309 wxFileDataObject
*dobj
= new wxFileDataObject
;
1310 size_t count
= filenames
.GetCount();
1311 for ( size_t n
= 0; n
< count
; n
++ )
1313 dobj
->AddFile(filenames
[n
]);
1316 wxClipboardLocker locker
;
1319 wxLogError("Can't open clipboard");
1323 if ( !wxTheClipboard
->AddData(dobj
) )
1325 wxLogError("Can't copy file(s) to the clipboard");
1329 wxLogStatus(this, "%d file%s copied to the clipboard",
1330 count
, count
== 1 ? "" : "s");
1336 wxLogStatus(this, "Aborted");
1339 wxLogError("Sorry, not implemented");
1343 // ---------------------------------------------------------------------------
1345 // ---------------------------------------------------------------------------
1347 void DnDFrame::OnCopy(wxCommandEvent
& WXUNUSED(event
))
1349 if ( !wxTheClipboard
->Open() )
1351 wxLogError(_T("Can't open clipboard."));
1356 if ( !wxTheClipboard
->AddData(new wxTextDataObject(m_strText
)) )
1358 wxLogError(_T("Can't copy data to the clipboard"));
1362 wxLogMessage(_T("Text '%s' put on the clipboard"), m_strText
.c_str());
1365 wxTheClipboard
->Close();
1368 void DnDFrame::OnPaste(wxCommandEvent
& WXUNUSED(event
))
1370 if ( !wxTheClipboard
->Open() )
1372 wxLogError(_T("Can't open clipboard."));
1377 if ( !wxTheClipboard
->IsSupported(wxDF_TEXT
) )
1379 wxLogWarning(_T("No text data on clipboard"));
1381 wxTheClipboard
->Close();
1385 wxTextDataObject text
;
1386 if ( !wxTheClipboard
->GetData(text
) )
1388 wxLogError(_T("Can't paste data from the clipboard"));
1392 wxLogMessage(_T("Text '%s' pasted from the clipboard"),
1393 text
.GetText().c_str());
1396 wxTheClipboard
->Close();
1399 // ----------------------------------------------------------------------------
1400 // Notifications called by the base class
1401 // ----------------------------------------------------------------------------
1403 bool DnDText::OnDropText(wxCoord
, wxCoord
, const wxString
& text
)
1405 m_pOwner
->Append(text
);
1410 bool DnDFile::OnDropFiles(wxCoord
, wxCoord
, const wxArrayString
& filenames
)
1412 size_t nFiles
= filenames
.GetCount();
1414 str
.Printf( _T("%d files dropped"), nFiles
);
1415 m_pOwner
->Append(str
);
1416 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
1417 m_pOwner
->Append(filenames
[n
]);
1423 // ----------------------------------------------------------------------------
1425 // ----------------------------------------------------------------------------
1427 DnDShapeDialog::DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
)
1431 LoadFromResource(parent
, "dialogShape");
1433 m_textX
= (wxTextCtrl
*)wxFindWindowByName("textX", this);
1434 m_textY
= (wxTextCtrl
*)wxFindWindowByName("textY", this);
1435 m_textW
= (wxTextCtrl
*)wxFindWindowByName("textW", this);
1436 m_textH
= (wxTextCtrl
*)wxFindWindowByName("textH", this);
1438 m_radio
= (wxRadioBox
*)wxFindWindowByName("radio", this);
1441 DnDShape
*DnDShapeDialog::GetShape() const
1443 switch ( m_shapeKind
)
1446 case DnDShape::None
: return NULL
;
1447 case DnDShape::Triangle
: return new DnDTriangularShape(m_pos
, m_size
, m_col
);
1448 case DnDShape::Rectangle
: return new DnDRectangularShape(m_pos
, m_size
, m_col
);
1449 case DnDShape::Ellipse
: return new DnDEllipticShape(m_pos
, m_size
, m_col
);
1453 bool DnDShapeDialog::TransferDataToWindow()
1458 m_radio
->SetSelection(m_shape
->GetKind());
1459 m_pos
= m_shape
->GetPosition();
1460 m_size
= m_shape
->GetSize();
1461 m_col
= m_shape
->GetColour();
1465 m_radio
->SetSelection(DnDShape::None
);
1466 m_pos
= wxPoint(1, 1);
1467 m_size
= wxSize(100, 100);
1470 m_textX
->SetValue(wxString() << m_pos
.x
);
1471 m_textY
->SetValue(wxString() << m_pos
.y
);
1472 m_textW
->SetValue(wxString() << m_size
.x
);
1473 m_textH
->SetValue(wxString() << m_size
.y
);
1478 bool DnDShapeDialog::TransferDataFromWindow()
1480 m_shapeKind
= (DnDShape::Kind
)m_radio
->GetSelection();
1482 m_pos
.x
= atoi(m_textX
->GetValue());
1483 m_pos
.y
= atoi(m_textY
->GetValue());
1484 m_size
.x
= atoi(m_textW
->GetValue());
1485 m_size
.y
= atoi(m_textH
->GetValue());
1487 if ( !m_pos
.x
|| !m_pos
.y
|| !m_size
.x
|| !m_size
.y
)
1489 wxMessageBox("All sizes and positions should be non null!",
1490 "Invalid shape", wxICON_HAND
| wxOK
, this);
1498 void DnDShapeDialog::OnColour(wxCommandEvent
& WXUNUSED(event
))
1501 data
.SetChooseFull(TRUE
);
1502 for (int i
= 0; i
< 16; i
++)
1504 wxColour
colour(i
*16, i
*16, i
*16);
1505 data
.SetCustomColour(i
, colour
);
1508 wxColourDialog
dialog(this, &data
);
1509 if ( dialog
.ShowModal() == wxID_OK
)
1511 m_col
= dialog
.GetColourData().GetColour();
1515 // ----------------------------------------------------------------------------
1517 // ----------------------------------------------------------------------------
1519 DnDShapeFrame
*DnDShapeFrame::ms_lastDropTarget
= NULL
;
1521 DnDShapeFrame::DnDShapeFrame(wxFrame
*parent
)
1522 : wxFrame(parent
, -1, "Shape Frame",
1523 wxDefaultPosition
, wxSize(250, 150))
1527 wxMenu
*menuShape
= new wxMenu
;
1528 menuShape
->Append(Menu_Shape_New
, "&New default shape\tCtrl-S");
1529 menuShape
->Append(Menu_Shape_Edit
, "&Edit shape\tCtrl-E");
1530 menuShape
->AppendSeparator();
1531 menuShape
->Append(Menu_Shape_Clear
, "&Clear shape\tCtrl-L");
1533 wxMenu
*menuClipboard
= new wxMenu
;
1534 menuClipboard
->Append(Menu_ShapeClipboard_Copy
, "&Copy\tCtrl-C");
1535 menuClipboard
->Append(Menu_ShapeClipboard_Paste
, "&Paste\tCtrl-V");
1537 wxMenuBar
*menubar
= new wxMenuBar
;
1538 menubar
->Append(menuShape
, "&Shape");
1539 menubar
->Append(menuClipboard
, "&Clipboard");
1541 SetMenuBar(menubar
);
1543 SetStatusText("Press Ctrl-S to create a new shape");
1545 SetDropTarget(new DnDShapeDropTarget(this));
1549 SetBackgroundColour(*wxWHITE
);
1552 DnDShapeFrame::~DnDShapeFrame()
1558 void DnDShapeFrame::SetShape(DnDShape
*shape
)
1567 void DnDShapeFrame::OnDrag(wxMouseEvent
& event
)
1576 // start drag operation
1577 DnDShapeDataObject
shapeData(m_shape
);
1578 wxDropSource
source(shapeData
, this);
1580 const char *pc
= NULL
;
1581 switch ( source
.DoDragDrop(TRUE
) )
1585 wxLogError("An error occured during drag and drop operation");
1589 SetStatusText("Nothing happened");
1598 if ( ms_lastDropTarget
!= this )
1600 // don't delete the shape if we dropped it on ourselves!
1606 SetStatusText("Drag and drop operation cancelled");
1612 SetStatusText(wxString("Shape successfully ") + pc
);
1614 //else: status text already set
1617 void DnDShapeFrame::OnDrop(wxCoord x
, wxCoord y
, DnDShape
*shape
)
1619 ms_lastDropTarget
= this;
1624 s
.Printf("Shape dropped at (%ld, %ld)", pt
.x
, pt
.y
);
1631 void DnDShapeFrame::OnEditShape(wxCommandEvent
& event
)
1633 DnDShapeDialog
dlg(this, m_shape
);
1634 if ( dlg
.ShowModal() == wxID_OK
)
1636 SetShape(dlg
.GetShape());
1640 SetStatusText("You can now drag the shape to another frame");
1645 void DnDShapeFrame::OnNewShape(wxCommandEvent
& event
)
1647 SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED
));
1649 SetStatusText("You can now drag the shape to another frame");
1652 void DnDShapeFrame::OnClearShape(wxCommandEvent
& event
)
1657 void DnDShapeFrame::OnCopyShape(wxCommandEvent
& event
)
1661 wxClipboardLocker clipLocker
;
1664 wxLogError("Can't open the clipboard");
1669 wxTheClipboard
->AddData(new DnDShapeDataObject(m_shape
));
1673 void DnDShapeFrame::OnPasteShape(wxCommandEvent
& event
)
1675 wxClipboardLocker clipLocker
;
1678 wxLogError("Can't open the clipboard");
1683 DnDShapeDataObject
shapeDataObject(NULL
);
1684 if ( wxTheClipboard
->GetData(shapeDataObject
) )
1686 SetShape(shapeDataObject
.GetShape());
1690 wxLogStatus("No shape on the clipboard");
1694 void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent
& event
)
1696 event
.Enable( m_shape
!= NULL
);
1699 void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent
& event
)
1701 event
.Enable( wxTheClipboard
->IsSupported(wxDataFormat(shapeFormatId
)) );
1704 void DnDShapeFrame::OnPaint(wxPaintEvent
& event
)
1718 // ----------------------------------------------------------------------------
1720 // ----------------------------------------------------------------------------
1722 DnDShape
*DnDShape::New(const void *buf
)
1724 const ShapeDump
& dump
= *(const ShapeDump
*)buf
;
1728 return new DnDTriangularShape(wxPoint(dump
.x
, dump
.y
),
1729 wxSize(dump
.w
, dump
.h
),
1730 wxColour(dump
.r
, dump
.g
, dump
.b
));
1733 return new DnDRectangularShape(wxPoint(dump
.x
, dump
.y
),
1734 wxSize(dump
.w
, dump
.h
),
1735 wxColour(dump
.r
, dump
.g
, dump
.b
));
1738 return new DnDEllipticShape(wxPoint(dump
.x
, dump
.y
),
1739 wxSize(dump
.w
, dump
.h
),
1740 wxColour(dump
.r
, dump
.g
, dump
.b
));
1743 wxFAIL_MSG("invalid shape!");
1748 // ----------------------------------------------------------------------------
1749 // DnDShapeDataObject
1750 // ----------------------------------------------------------------------------
1752 #ifdef USE_METAFILES
1754 void DnDShapeDataObject::CreateMetaFile() const
1756 wxPoint pos
= m_shape
->GetPosition();
1757 wxSize size
= m_shape
->GetSize();
1759 wxMetaFileDC
dcMF(wxEmptyString
, pos
.x
+ size
.x
, pos
.y
+ size
.y
);
1761 m_shape
->Draw(dcMF
);
1763 wxMetafile
*mf
= dcMF
.Close();
1765 DnDShapeDataObject
*self
= (DnDShapeDataObject
*)this; // const_cast
1766 self
->m_dobjMetaFile
.SetMetafile(*mf
);
1767 self
->m_hasMetaFile
= TRUE
;
1774 void DnDShapeDataObject::CreateBitmap() const
1776 wxPoint pos
= m_shape
->GetPosition();
1777 wxSize size
= m_shape
->GetSize();
1778 int x
= pos
.x
+ size
.x
,
1780 wxBitmap
bitmap(x
, y
);
1782 dc
.SelectObject(bitmap
);
1783 dc
.SetBrush(wxBrush("white", wxSOLID
));
1786 dc
.SelectObject(wxNullBitmap
);
1788 DnDShapeDataObject
*self
= (DnDShapeDataObject
*)this; // const_cast
1789 self
->m_dobjBitmap
.SetBitmap(bitmap
);
1790 self
->m_hasBitmap
= TRUE
;
1793 // ----------------------------------------------------------------------------
1795 // ----------------------------------------------------------------------------
1797 static void ShowBitmap(const wxBitmap
& bitmap
)
1799 wxFrame
*frame
= new wxFrame(NULL
, -1, _T("Bitmap view"));
1800 frame
->CreateStatusBar();
1801 DnDCanvasBitmap
*canvas
= new DnDCanvasBitmap(frame
);
1802 canvas
->SetBitmap(bitmap
);
1804 int w
= bitmap
.GetWidth(),
1805 h
= bitmap
.GetHeight();
1806 frame
->SetStatusText(wxString::Format(_T("%dx%d"), w
, h
));
1808 frame
->SetClientSize(w
> 100 ? 100 : w
, h
> 100 ? 100 : h
);
1812 #ifdef USE_METAFILES
1814 static void ShowMetaFile(const wxMetaFile
& metafile
)
1816 wxFrame
*frame
= new wxFrame(NULL
, -1, _T("Metafile view"));
1817 frame
->CreateStatusBar();
1818 DnDCanvasMetafile
*canvas
= new DnDCanvasMetafile(frame
);
1819 canvas
->SetMetafile(metafile
);
1821 wxSize size
= metafile
.GetSize();
1822 frame
->SetStatusText(wxString::Format(_T("%dx%d"), size
.x
, size
.y
));
1824 frame
->SetClientSize(size
.x
> 100 ? 100 : size
.x
,
1825 size
.y
> 100 ? 100 : size
.y
);
1829 #endif // USE_METAFILES