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 new application type
85 // ----------------------------------------------------------------------------
87 class DnDApp
: public wxApp
90 virtual bool OnInit();
93 IMPLEMENT_APP(DnDApp
);
95 // ----------------------------------------------------------------------------
96 // Define canvas class to show a bitmap
97 // ----------------------------------------------------------------------------
99 class DnDCanvasBitmap
: public wxScrolledWindow
102 DnDCanvasBitmap(wxWindow
*parent
) : wxScrolledWindow(parent
) { }
104 void SetBitmap(const wxBitmap
& bitmap
)
108 SetScrollbars(10, 10,
109 m_bitmap
.GetWidth() / 10, m_bitmap
.GetHeight() / 10);
114 void OnPaint(wxPaintEvent
& event
)
122 dc
.DrawBitmap(m_bitmap
, 0, 0);
129 DECLARE_EVENT_TABLE()
134 // and the same thing fo metafiles
135 class DnDCanvasMetafile
: public wxScrolledWindow
138 DnDCanvasMetafile(wxWindow
*parent
) : wxScrolledWindow(parent
) { }
140 void SetMetafile(const wxMetafile
& metafile
)
142 m_metafile
= metafile
;
144 SetScrollbars(10, 10,
145 m_metafile
.GetWidth() / 10, m_metafile
.GetHeight() / 10);
150 void OnPaint(wxPaintEvent
& event
)
154 if ( m_metafile
.Ok() )
158 m_metafile
.Play(&dc
);
163 wxMetafile m_metafile
;
165 DECLARE_EVENT_TABLE()
168 #endif // USE_METAFILES
170 // ----------------------------------------------------------------------------
171 // Define a new frame type for the main frame
172 // ----------------------------------------------------------------------------
174 class DnDFrame
: public wxFrame
177 DnDFrame(wxFrame
*frame
, char *title
, int x
, int y
, int w
, int h
);
180 void OnPaint(wxPaintEvent
& event
);
181 void OnQuit (wxCommandEvent
& event
);
182 void OnAbout(wxCommandEvent
& event
);
183 void OnDrag (wxCommandEvent
& event
);
184 void OnNewFrame(wxCommandEvent
& event
);
185 void OnHelp (wxCommandEvent
& event
);
186 void OnLogClear(wxCommandEvent
& event
);
188 void OnCopy(wxCommandEvent
& event
);
189 void OnPaste(wxCommandEvent
& event
);
191 void OnCopyBitmap(wxCommandEvent
& event
);
192 void OnPasteBitmap(wxCommandEvent
& event
);
195 void OnPasteMetafile(wxCommandEvent
& event
);
196 #endif // USE_METAFILES
198 void OnCopyFiles(wxCommandEvent
& event
);
200 void OnLeftDown(wxMouseEvent
& event
);
201 void OnRightDown(wxMouseEvent
& event
);
203 void OnUpdateUIPasteText(wxUpdateUIEvent
& event
);
204 void OnUpdateUIPasteBitmap(wxUpdateUIEvent
& event
);
206 DECLARE_EVENT_TABLE()
209 wxListBox
*m_ctrlFile
,
211 wxTextCtrl
*m_ctrlLog
;
219 // ----------------------------------------------------------------------------
220 // A shape is an example of application-specific data which may be transported
221 // via drag-and-drop or clipboard: in our case, we have different geometric
222 // shapes, each one with its own colour and position
223 // ----------------------------------------------------------------------------
236 DnDShape(const wxPoint
& pos
,
239 : m_pos(pos
), m_size(size
), m_col(col
)
243 // this is for debugging - lets us see when exactly an object is freed
244 // (this may be later than you think if it's on the clipboard, for example)
245 virtual ~DnDShape() { }
247 // the functions used for drag-and-drop: they dump and restore a shape into
248 // some bitwise-copiable data (might use streams too...)
249 // ------------------------------------------------------------------------
251 // restore from buffer
252 static DnDShape
*New(const void *buf
);
254 virtual size_t GetDataSize() const
256 return sizeof(ShapeDump
);
259 virtual void GetDataHere(void *buf
) const
261 ShapeDump
& dump
= *(ShapeDump
*)buf
;
266 dump
.r
= m_col
.Red();
267 dump
.g
= m_col
.Green();
268 dump
.b
= m_col
.Blue();
273 const wxPoint
& GetPosition() const { return m_pos
; }
274 const wxColour
& GetColour() const { return m_col
; }
275 const wxSize
& GetSize() const { return m_size
; }
277 void Move(const wxPoint
& pos
) { m_pos
= pos
; }
279 // to implement in derived classes
280 virtual Kind
GetKind() const = 0;
282 virtual void Draw(wxDC
& dc
)
284 dc
.SetPen(wxPen(m_col
, 1, wxSOLID
));
288 wxPoint
GetCentre() const
289 { return wxPoint(m_pos
.x
+ m_size
.x
/ 2, m_pos
.y
+ m_size
.y
/ 2); }
293 int x
, y
, // position
304 class DnDTriangularShape
: public DnDShape
307 DnDTriangularShape(const wxPoint
& pos
,
310 : DnDShape(pos
, size
, col
)
312 wxLogMessage("DnDTriangularShape is being created");
315 virtual ~DnDTriangularShape()
317 wxLogMessage("DnDTriangularShape is being deleted");
320 virtual Kind
GetKind() const { return Triangle
; }
321 virtual void Draw(wxDC
& dc
)
325 // well, it's a bit difficult to describe a triangle by position and
326 // size, but we're not doing geometry here, do we? ;-)
328 wxPoint
p2(m_pos
.x
+ m_size
.x
, m_pos
.y
);
329 wxPoint
p3(m_pos
.x
, m_pos
.y
+ m_size
.y
);
336 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
341 class DnDRectangularShape
: public DnDShape
344 DnDRectangularShape(const wxPoint
& pos
,
347 : DnDShape(pos
, size
, col
)
349 wxLogMessage("DnDRectangularShape is being created");
352 virtual ~DnDRectangularShape()
354 wxLogMessage("DnDRectangularShape is being deleted");
357 virtual Kind
GetKind() const { return Rectangle
; }
358 virtual void Draw(wxDC
& dc
)
363 wxPoint
p2(p1
.x
+ m_size
.x
, p1
.y
);
364 wxPoint
p3(p2
.x
, p2
.y
+ m_size
.y
);
365 wxPoint
p4(p1
.x
, p3
.y
);
373 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
378 class DnDEllipticShape
: public DnDShape
381 DnDEllipticShape(const wxPoint
& pos
,
384 : DnDShape(pos
, size
, col
)
386 wxLogMessage("DnDEllipticShape is being created");
389 virtual ~DnDEllipticShape()
391 wxLogMessage("DnDEllipticShape is being deleted");
394 virtual Kind
GetKind() const { return Ellipse
; }
395 virtual void Draw(wxDC
& dc
)
399 dc
.DrawEllipse(m_pos
, m_size
);
402 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
407 // ----------------------------------------------------------------------------
408 // A wxDataObject specialisation for the application-specific data
409 // ----------------------------------------------------------------------------
411 static const char *shapeFormatId
= "wxShape";
413 class DnDShapeDataObject
: public wxDataObject
416 // ctor doesn't copy the pointer, so it shouldn't go away while this object
418 DnDShapeDataObject(DnDShape
*shape
= (DnDShape
*)NULL
)
422 // we need to copy the shape because the one we're handled may be
423 // deleted while it's still on the clipboard (for example) - and we
424 // reuse the serialisation methods here to copy it
425 void *buf
= malloc(shape
->DnDShape::GetDataSize());
426 shape
->GetDataHere(buf
);
427 m_shape
= DnDShape::New(buf
);
437 // this string should uniquely identify our format, but is otherwise
439 m_formatShape
.SetId(shapeFormatId
);
441 // we don't draw the shape to a bitmap until it's really needed (i.e.
442 // we're asked to do so)
445 m_hasMetaFile
= FALSE
;
449 virtual ~DnDShapeDataObject() { delete m_shape
; }
451 // after a call to this function, the shape is owned by the caller and it
452 // is responsible for deleting it!
454 // NB: a better solution would be to make DnDShapes ref counted and this
455 // is what should probably be done in a real life program, otherwise
456 // the ownership problems become too complicated really fast
459 DnDShape
*shape
= m_shape
;
461 m_shape
= (DnDShape
*)NULL
;
464 m_hasMetaFile
= FALSE
;
470 // implement base class pure virtuals
471 // ----------------------------------
473 virtual wxDataFormat
GetPreferredFormat(Direction
WXUNUSED(dir
)) const
475 return m_formatShape
;
478 virtual size_t GetFormatCount(Direction dir
) const
480 // our custom format is supported by both GetData() and SetData()
484 // but the bitmap format(s) are only supported for output
485 nFormats
+= m_dobjBitmap
.GetFormatCount(dir
);
488 nFormats
+= m_dobjMetaFile
.GetFormatCount(dir
);
495 virtual void GetAllFormats(wxDataFormat
*formats
, Direction dir
) const
497 formats
[0] = m_formatShape
;
500 // in Get direction we additionally support bitmaps and metafiles
502 m_dobjBitmap
.GetAllFormats(&formats
[1], dir
);
505 // don't assume that m_dobjBitmap has only 1 format
506 m_dobjMetaFile
.GetAllFormats(&formats
[1 +
507 m_dobjBitmap
.GetFormatCount(dir
)], dir
);
512 virtual size_t GetDataSize(const wxDataFormat
& format
) const
514 if ( format
== m_formatShape
)
516 return m_shape
->GetDataSize();
519 else if ( m_dobjMetaFile
.IsSupported(format
) )
521 if ( !m_hasMetaFile
)
524 return m_dobjMetaFile
.GetDataSize(format
);
529 wxASSERT_MSG( m_dobjBitmap
.IsSupported(format
),
530 "unexpected format" );
535 return m_dobjBitmap
.GetDataSize();
539 virtual bool GetDataHere(const wxDataFormat
& format
, void *pBuf
) const
541 if ( format
== m_formatShape
)
543 m_shape
->GetDataHere(pBuf
);
548 else if ( m_dobjMetaFile
.IsSupported(format
) )
550 if ( !m_hasMetaFile
)
553 return m_dobjMetaFile
.GetDataHere(format
, pBuf
);
558 wxASSERT_MSG( m_dobjBitmap
.IsSupported(format
),
559 "unexpected format" );
564 return m_dobjBitmap
.GetDataHere(pBuf
);
568 virtual bool SetData(const wxDataFormat
& format
,
569 size_t len
, const void *buf
)
571 wxCHECK_MSG( format
== m_formatShape
, FALSE
, "unsupported format" );
574 m_shape
= DnDShape::New(buf
);
576 // the shape has changed
580 m_hasMetaFile
= FALSE
;
587 // creates a bitmap and assigns it to m_dobjBitmap (also sets m_hasBitmap)
588 void CreateBitmap() const;
590 void CreateMetaFile() const;
593 wxDataFormat m_formatShape
; // our custom format
595 wxBitmapDataObject m_dobjBitmap
; // it handles bitmaps
596 bool m_hasBitmap
; // true if m_dobjBitmap has valid bitmap
599 wxMetaFileDataObject m_dobjMetaFile
;// handles metafiles
600 bool m_hasMetaFile
; // true if we have valid metafile
603 DnDShape
*m_shape
; // our data
606 // ----------------------------------------------------------------------------
607 // A dialog to edit shape properties
608 // ----------------------------------------------------------------------------
610 class DnDShapeDialog
: public wxDialog
613 DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
);
615 DnDShape
*GetShape() const;
617 virtual bool TransferDataToWindow();
618 virtual bool TransferDataFromWindow();
620 void OnColour(wxCommandEvent
& event
);
627 DnDShape::Kind m_shapeKind
;
639 DECLARE_EVENT_TABLE()
642 // ----------------------------------------------------------------------------
643 // A frame for the shapes which can be drag-and-dropped between frames
644 // ----------------------------------------------------------------------------
646 class DnDShapeFrame
: public wxFrame
649 DnDShapeFrame(wxFrame
*parent
);
652 void SetShape(DnDShape
*shape
);
655 void OnNewShape(wxCommandEvent
& event
);
656 void OnEditShape(wxCommandEvent
& event
);
657 void OnClearShape(wxCommandEvent
& event
);
659 void OnCopyShape(wxCommandEvent
& event
);
660 void OnPasteShape(wxCommandEvent
& event
);
662 void OnUpdateUICopy(wxUpdateUIEvent
& event
);
663 void OnUpdateUIPaste(wxUpdateUIEvent
& event
);
665 void OnDrag(wxMouseEvent
& event
);
666 void OnPaint(wxPaintEvent
& event
);
667 void OnDrop(wxCoord x
, wxCoord y
, DnDShape
*shape
);
672 static DnDShapeFrame
*ms_lastDropTarget
;
674 DECLARE_EVENT_TABLE()
677 // ----------------------------------------------------------------------------
678 // wxDropTarget derivation for DnDShapes
679 // ----------------------------------------------------------------------------
681 class DnDShapeDropTarget
: public wxDropTarget
684 DnDShapeDropTarget(DnDShapeFrame
*frame
)
685 : wxDropTarget(new DnDShapeDataObject
)
690 // override base class (pure) virtuals
691 virtual wxDragResult
OnEnter(wxCoord x
, wxCoord y
, wxDragResult def
)
692 { m_frame
->SetStatusText("Mouse entered the frame"); return OnDragOver(x
, y
, def
); }
693 virtual void OnLeave()
694 { m_frame
->SetStatusText("Mouse left the frame"); }
695 virtual wxDragResult
OnData(wxCoord x
, wxCoord y
, wxDragResult def
)
699 wxLogError("Failed to get drag and drop data");
704 m_frame
->OnDrop(x
, y
,
705 ((DnDShapeDataObject
*)GetDataObject())->GetShape());
711 DnDShapeFrame
*m_frame
;
714 // ----------------------------------------------------------------------------
715 // functions prototypes
716 // ----------------------------------------------------------------------------
718 static void ShowBitmap(const wxBitmap
& bitmap
);
721 static void ShowMetaFile(const wxMetaFile
& metafile
);
722 #endif // USE_METAFILES
724 // ----------------------------------------------------------------------------
725 // IDs for the menu commands
726 // ----------------------------------------------------------------------------
742 Menu_Shape_New
= 500,
745 Menu_ShapeClipboard_Copy
,
746 Menu_ShapeClipboard_Paste
,
750 BEGIN_EVENT_TABLE(DnDFrame
, wxFrame
)
751 EVT_MENU(Menu_Quit
, DnDFrame::OnQuit
)
752 EVT_MENU(Menu_About
, DnDFrame::OnAbout
)
753 EVT_MENU(Menu_Drag
, DnDFrame::OnDrag
)
754 EVT_MENU(Menu_NewFrame
, DnDFrame::OnNewFrame
)
755 EVT_MENU(Menu_Help
, DnDFrame::OnHelp
)
756 EVT_MENU(Menu_Clear
, DnDFrame::OnLogClear
)
757 EVT_MENU(Menu_Copy
, DnDFrame::OnCopy
)
758 EVT_MENU(Menu_Paste
, DnDFrame::OnPaste
)
759 EVT_MENU(Menu_CopyBitmap
, DnDFrame::OnCopyBitmap
)
760 EVT_MENU(Menu_PasteBitmap
,DnDFrame::OnPasteBitmap
)
762 EVT_MENU(Menu_PasteMFile
, DnDFrame::OnPasteMetafile
)
763 #endif // USE_METAFILES
764 EVT_MENU(Menu_CopyFiles
, DnDFrame::OnCopyFiles
)
766 EVT_UPDATE_UI(Menu_Paste
, DnDFrame::OnUpdateUIPasteText
)
767 EVT_UPDATE_UI(Menu_PasteBitmap
, DnDFrame::OnUpdateUIPasteBitmap
)
769 EVT_LEFT_DOWN( DnDFrame::OnLeftDown
)
770 EVT_RIGHT_DOWN( DnDFrame::OnRightDown
)
771 EVT_PAINT( DnDFrame::OnPaint
)
774 BEGIN_EVENT_TABLE(DnDShapeFrame
, wxFrame
)
775 EVT_MENU(Menu_Shape_New
, DnDShapeFrame::OnNewShape
)
776 EVT_MENU(Menu_Shape_Edit
, DnDShapeFrame::OnEditShape
)
777 EVT_MENU(Menu_Shape_Clear
, DnDShapeFrame::OnClearShape
)
779 EVT_MENU(Menu_ShapeClipboard_Copy
, DnDShapeFrame::OnCopyShape
)
780 EVT_MENU(Menu_ShapeClipboard_Paste
, DnDShapeFrame::OnPasteShape
)
782 EVT_UPDATE_UI(Menu_ShapeClipboard_Copy
, DnDShapeFrame::OnUpdateUICopy
)
783 EVT_UPDATE_UI(Menu_ShapeClipboard_Paste
, DnDShapeFrame::OnUpdateUIPaste
)
785 EVT_LEFT_DOWN(DnDShapeFrame::OnDrag
)
787 EVT_PAINT(DnDShapeFrame::OnPaint
)
790 BEGIN_EVENT_TABLE(DnDShapeDialog
, wxDialog
)
791 EVT_BUTTON(Button_Colour
, DnDShapeDialog::OnColour
)
794 BEGIN_EVENT_TABLE(DnDCanvasBitmap
, wxScrolledWindow
)
795 EVT_PAINT(DnDCanvasBitmap::OnPaint
)
799 BEGIN_EVENT_TABLE(DnDCanvasMetafile
, wxScrolledWindow
)
800 EVT_PAINT(DnDCanvasMetafile::OnPaint
)
802 #endif // USE_METAFILES
804 // ============================================================================
806 // ============================================================================
808 // `Main program' equivalent, creating windows and returning main app frame
809 bool DnDApp::OnInit()
811 // load our ressources
815 pathList
.Add("./Debug");
816 pathList
.Add("./Release");
819 wxString path
= pathList
.FindValidPath("dnd.wxr");
822 wxLogError("Can't find the resource file dnd.wxr in the current "
823 "directory, aborting.");
828 wxDefaultResourceTable
->ParseResourceFile(path
);
830 // switch on trace messages
831 #if defined(__WXGTK__)
832 wxLog::AddTraceMask(_T("clipboard"));
833 #elif defined(__WXMSW__)
834 wxLog::AddTraceMask(wxTRACE_OleCalls
);
838 wxImage::AddHandler( new wxPNGHandler
);
841 // under X we usually want to use the primary selection by default (which
842 // is shared with other apps)
843 wxTheClipboard
->UsePrimarySelection();
845 // create the main frame window
846 DnDFrame
*frame
= new DnDFrame((wxFrame
*) NULL
,
847 "Drag-and-Drop/Clipboard wxWindows Sample",
858 DnDFrame::DnDFrame(wxFrame
*frame
, char *title
, int x
, int y
, int w
, int h
)
859 : wxFrame(frame
, -1, title
, wxPoint(x
, y
), wxSize(w
, h
)),
860 m_strText("wxWindows drag & drop works :-)")
863 // frame icon and status bar
864 SetIcon(wxICON(mondrian
));
869 wxMenu
*file_menu
= new wxMenu
;
870 file_menu
->Append(Menu_Drag
, "&Test drag...");
871 file_menu
->AppendSeparator();
872 file_menu
->Append(Menu_NewFrame
, "&New frame\tCtrl-N");
873 file_menu
->AppendSeparator();
874 file_menu
->Append(Menu_Quit
, "E&xit");
876 wxMenu
*log_menu
= new wxMenu
;
877 log_menu
->Append(Menu_Clear
, "Clear\tCtrl-L");
879 wxMenu
*help_menu
= new wxMenu
;
880 help_menu
->Append(Menu_Help
, "&Help...");
881 help_menu
->AppendSeparator();
882 help_menu
->Append(Menu_About
, "&About");
884 wxMenu
*clip_menu
= new wxMenu
;
885 clip_menu
->Append(Menu_Copy
, "&Copy text\tCtrl+C");
886 clip_menu
->Append(Menu_Paste
, "&Paste text\tCtrl+V");
887 clip_menu
->AppendSeparator();
888 clip_menu
->Append(Menu_CopyBitmap
, "Copy &bitmap\tAlt+C");
889 clip_menu
->Append(Menu_PasteBitmap
, "Paste b&itmap\tAlt+V");
891 clip_menu
->AppendSeparator();
892 clip_menu
->Append(Menu_PasteMFile
, "Paste &metafile\tCtrl-M");
893 #endif // USE_METAFILES
894 clip_menu
->AppendSeparator();
895 clip_menu
->Append(Menu_CopyFiles
, "Copy &files\tCtrl+F");
897 wxMenuBar
*menu_bar
= new wxMenuBar
;
898 menu_bar
->Append(file_menu
, "&File");
899 menu_bar
->Append(log_menu
, "&Log");
900 menu_bar
->Append(clip_menu
, "&Clipboard");
901 menu_bar
->Append(help_menu
, "&Help");
903 SetMenuBar(menu_bar
);
905 // make a panel with 3 subwindows
907 wxSize
size(400, 200);
909 wxString
strFile("Drop files here!"), strText("Drop text on me");
911 m_ctrlFile
= new wxListBox(this, -1, pos
, size
, 1, &strFile
,
912 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
913 m_ctrlText
= new wxListBox(this, -1, pos
, size
, 1, &strText
,
914 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
916 m_ctrlLog
= new wxTextCtrl(this, -1, "", pos
, size
,
917 wxTE_MULTILINE
| wxTE_READONLY
|
920 // redirect log messages to the text window
921 m_pLog
= new wxLogTextCtrl(m_ctrlLog
);
922 m_pLogPrev
= wxLog::SetActiveTarget(m_pLog
);
924 // associate drop targets with 2 text controls
925 m_ctrlFile
->SetDropTarget(new DnDFile(m_ctrlFile
));
926 m_ctrlText
->SetDropTarget(new DnDText(m_ctrlText
));
928 wxLayoutConstraints
*c
;
931 c
= new wxLayoutConstraints
;
932 c
->left
.SameAs(this, wxLeft
);
933 c
->top
.SameAs(this, wxTop
);
934 c
->right
.PercentOf(this, wxRight
, 50);
935 c
->height
.PercentOf(this, wxHeight
, 30);
936 m_ctrlFile
->SetConstraints(c
);
939 c
= new wxLayoutConstraints
;
940 c
->left
.SameAs (m_ctrlFile
, wxRight
);
941 c
->top
.SameAs (this, wxTop
);
942 c
->right
.SameAs (this, wxRight
);
943 c
->height
.PercentOf(this, wxHeight
, 30);
944 m_ctrlText
->SetConstraints(c
);
946 // Lower text control
947 c
= new wxLayoutConstraints
;
948 c
->left
.SameAs (this, wxLeft
);
949 c
->right
.SameAs (this, wxRight
);
950 c
->height
.PercentOf(this, wxHeight
, 50);
951 c
->top
.SameAs(m_ctrlText
, wxBottom
);
952 m_ctrlLog
->SetConstraints(c
);
957 void DnDFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
))
962 void DnDFrame::OnPaint(wxPaintEvent
& WXUNUSED(event
))
966 GetClientSize( &w
, &h
);
969 dc
.SetFont( wxFont( 24, wxDECORATIVE
, wxNORMAL
, wxNORMAL
, FALSE
, "charter" ) );
970 dc
.DrawText( "Drag text from here!", 100, h
-50 );
973 void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent
& event
)
976 // too many trace messages if we don't do it - this function is called
981 event
.Enable( wxTheClipboard
->IsSupported(wxDF_TEXT
) );
984 void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent
& event
)
987 // too many trace messages if we don't do it - this function is called
992 event
.Enable( wxTheClipboard
->IsSupported(wxDF_BITMAP
) );
995 void DnDFrame::OnNewFrame(wxCommandEvent
& WXUNUSED(event
))
997 (new DnDShapeFrame(this))->Show(TRUE
);
999 wxLogStatus(this, "Double click the new frame to select a shape for it");
1002 void DnDFrame::OnDrag(wxCommandEvent
& WXUNUSED(event
))
1004 wxString strText
= wxGetTextFromUser
1006 "After you enter text in this dialog, press any mouse\n"
1007 "button in the bottom (empty) part of the frame and \n"
1008 "drag it anywhere - you will be in fact dragging the\n"
1009 "text object containing this text",
1010 "Please enter some text", m_strText
, this
1013 m_strText
= strText
;
1016 void DnDFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
1018 wxMessageBox("Drag-&-Drop Demo\n"
1019 "Please see \"Help|Help...\" for details\n"
1020 "Copyright (c) 1998 Vadim Zeitlin",
1022 wxICON_INFORMATION
| wxOK
,
1026 void DnDFrame::OnHelp(wxCommandEvent
& /* event */)
1028 wxMessageDialog
dialog(this,
1029 "This small program demonstrates drag & drop support in wxWindows. The program window\n"
1030 "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
1031 "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
1032 "and the right one accepts text.\n"
1034 "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
1035 "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
1036 "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
1037 "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
1038 "work with files) and see what changes.\n"
1040 "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
1041 "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
1042 "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
1043 "change, don't release the mouse button until it does. You can change the string being\n"
1044 "dragged in in \"File|Test drag...\" dialog.\n"
1047 "Please send all questions/bug reports/suggestions &c to \n"
1048 "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
1054 void DnDFrame::OnLogClear(wxCommandEvent
& /* event */ )
1057 m_ctrlText
->Clear();
1058 m_ctrlFile
->Clear();
1061 void DnDFrame::OnLeftDown(wxMouseEvent
&WXUNUSED(event
) )
1063 if ( !m_strText
.IsEmpty() )
1065 // start drag operation
1066 wxTextDataObject
textData(m_strText
);
1068 wxFileDataObject textData;
1069 textData.AddFile( "/file1.txt" );
1070 textData.AddFile( "/file2.txt" );
1072 wxDropSource
source(textData
, this,
1073 wxDROP_ICON(dnd_copy
),
1074 wxDROP_ICON(dnd_move
),
1075 wxDROP_ICON(dnd_none
));
1079 switch ( source
.DoDragDrop(TRUE
) )
1081 case wxDragError
: pc
= "Error!"; break;
1082 case wxDragNone
: pc
= "Nothing"; break;
1083 case wxDragCopy
: pc
= "Copied"; break;
1084 case wxDragMove
: pc
= "Moved"; break;
1085 case wxDragCancel
: pc
= "Cancelled"; break;
1086 default: pc
= "Huh?"; break;
1089 SetStatusText(wxString("Drag result: ") + pc
);
1093 void DnDFrame::OnRightDown(wxMouseEvent
&event
)
1095 wxMenu
menu("Dnd sample menu");
1097 menu
.Append(Menu_Drag
, "&Test drag...");
1098 menu
.AppendSeparator();
1099 menu
.Append(Menu_About
, "&About");
1101 PopupMenu( &menu
, event
.GetX(), event
.GetY() );
1104 DnDFrame::~DnDFrame()
1106 if ( m_pLog
!= NULL
) {
1107 if ( wxLog::SetActiveTarget(m_pLogPrev
) == m_pLog
)
1112 // ---------------------------------------------------------------------------
1114 // ---------------------------------------------------------------------------
1116 void DnDFrame::OnCopyBitmap(wxCommandEvent
& WXUNUSED(event
))
1118 // PNG support is not always compiled in under Windows, so use BMP there
1120 wxFileDialog
dialog(this, "Open a BMP file", "", "", "BMP files (*.bmp)|*.bmp", 0);
1122 wxFileDialog
dialog(this, "Open a PNG file", "", "", "PNG files (*.png)|*.png", 0);
1125 if (dialog
.ShowModal() != wxID_OK
)
1127 wxLogMessage( _T("Aborted file open") );
1131 if (dialog
.GetPath().IsEmpty())
1133 wxLogMessage( _T("Returned empty string.") );
1137 if (!wxFileExists(dialog
.GetPath()))
1139 wxLogMessage( _T("File doesn't exist.") );
1144 image
.LoadFile( dialog
.GetPath(),
1153 wxLogError( _T("Invalid image file...") );
1157 wxLogStatus( _T("Decoding image file...") );
1160 wxBitmap
bitmap( image
.ConvertToBitmap() );
1162 if ( !wxTheClipboard
->Open() )
1164 wxLogError(_T("Can't open clipboard."));
1169 wxLogMessage( _T("Creating wxBitmapDataObject...") );
1172 if ( !wxTheClipboard
->AddData(new wxBitmapDataObject(bitmap
)) )
1174 wxLogError(_T("Can't copy image to the clipboard."));
1178 wxLogMessage(_T("Image has been put on the clipboard.") );
1179 wxLogMessage(_T("You can paste it now and look at it.") );
1182 wxTheClipboard
->Close();
1185 void DnDFrame::OnPasteBitmap(wxCommandEvent
& WXUNUSED(event
))
1187 if ( !wxTheClipboard
->Open() )
1189 wxLogError(_T("Can't open clipboard."));
1194 if ( !wxTheClipboard
->IsSupported(wxDF_BITMAP
) )
1196 wxLogWarning(_T("No bitmap on clipboard"));
1198 wxTheClipboard
->Close();
1202 wxBitmapDataObject data
;
1203 if ( !wxTheClipboard
->GetData(data
) )
1205 wxLogError(_T("Can't paste bitmap from the clipboard"));
1209 const wxBitmap
& bmp
= data
.GetBitmap();
1211 wxLogMessage(_T("Bitmap %dx%d pasted from the clipboard"),
1212 bmp
.GetWidth(), bmp
.GetHeight());
1216 wxTheClipboard
->Close();
1219 #ifdef USE_METAFILES
1221 void DnDFrame::OnPasteMetafile(wxCommandEvent
& WXUNUSED(event
))
1223 if ( !wxTheClipboard
->Open() )
1225 wxLogError(_T("Can't open clipboard."));
1230 if ( !wxTheClipboard
->IsSupported(wxDF_METAFILE
) )
1232 wxLogWarning(_T("No metafile on clipboard"));
1236 wxMetaFileDataObject data
;
1237 if ( !wxTheClipboard
->GetData(data
) )
1239 wxLogError(_T("Can't paste metafile from the clipboard"));
1243 const wxMetaFile
& mf
= data
.GetMetafile();
1245 wxLogMessage(_T("Metafile %dx%d pasted from the clipboard"),
1246 mf
.GetWidth(), mf
.GetHeight());
1252 wxTheClipboard
->Close();
1255 #endif // USE_METAFILES
1257 // ----------------------------------------------------------------------------
1259 // ----------------------------------------------------------------------------
1261 void DnDFrame::OnCopyFiles(wxCommandEvent
& WXUNUSED(event
))
1264 wxFileDialog
dialog(this, "Select a file to copy", "", "",
1265 "All files (*.*)|*.*", 0);
1267 wxArrayString filenames
;
1268 while ( dialog
.ShowModal() == wxID_OK
)
1270 filenames
.Add(dialog
.GetPath());
1273 if ( !filenames
.IsEmpty() )
1275 wxFileDataObject
*dobj
= new wxFileDataObject
;
1276 size_t count
= filenames
.GetCount();
1277 for ( size_t n
= 0; n
< count
; n
++ )
1279 dobj
->AddFile(filenames
[n
]);
1282 wxClipboardLocker locker
;
1285 wxLogError("Can't open clipboard");
1289 if ( !wxTheClipboard
->AddData(dobj
) )
1291 wxLogError("Can't copy file(s) to the clipboard");
1295 wxLogStatus(this, "%d file%s copied to the clipboard",
1296 count
, count
== 1 ? "" : "s");
1302 wxLogStatus(this, "Aborted");
1305 wxLogError("Sorry, not implemented");
1309 // ---------------------------------------------------------------------------
1311 // ---------------------------------------------------------------------------
1313 void DnDFrame::OnCopy(wxCommandEvent
& WXUNUSED(event
))
1315 if ( !wxTheClipboard
->Open() )
1317 wxLogError(_T("Can't open clipboard."));
1322 if ( !wxTheClipboard
->AddData(new wxTextDataObject(m_strText
)) )
1324 wxLogError(_T("Can't copy data to the clipboard"));
1328 wxLogMessage(_T("Text '%s' put on the clipboard"), m_strText
.c_str());
1331 wxTheClipboard
->Close();
1334 void DnDFrame::OnPaste(wxCommandEvent
& WXUNUSED(event
))
1336 if ( !wxTheClipboard
->Open() )
1338 wxLogError(_T("Can't open clipboard."));
1343 if ( !wxTheClipboard
->IsSupported(wxDF_TEXT
) )
1345 wxLogWarning(_T("No text data on clipboard"));
1347 wxTheClipboard
->Close();
1351 wxTextDataObject text
;
1352 if ( !wxTheClipboard
->GetData(text
) )
1354 wxLogError(_T("Can't paste data from the clipboard"));
1358 wxLogMessage(_T("Text '%s' pasted from the clipboard"),
1359 text
.GetText().c_str());
1362 wxTheClipboard
->Close();
1365 // ----------------------------------------------------------------------------
1366 // Notifications called by the base class
1367 // ----------------------------------------------------------------------------
1369 bool DnDText::OnDropText(wxCoord
, wxCoord
, const wxString
& text
)
1371 m_pOwner
->Append(text
);
1376 bool DnDFile::OnDropFiles(wxCoord
, wxCoord
, const wxArrayString
& filenames
)
1378 size_t nFiles
= filenames
.GetCount();
1380 str
.Printf( _T("%d files dropped"), nFiles
);
1381 m_pOwner
->Append(str
);
1382 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
1383 m_pOwner
->Append(filenames
[n
]);
1389 // ----------------------------------------------------------------------------
1391 // ----------------------------------------------------------------------------
1393 DnDShapeDialog::DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
)
1397 LoadFromResource(parent
, "dialogShape");
1399 m_textX
= (wxTextCtrl
*)wxFindWindowByName("textX", this);
1400 m_textY
= (wxTextCtrl
*)wxFindWindowByName("textY", this);
1401 m_textW
= (wxTextCtrl
*)wxFindWindowByName("textW", this);
1402 m_textH
= (wxTextCtrl
*)wxFindWindowByName("textH", this);
1404 m_radio
= (wxRadioBox
*)wxFindWindowByName("radio", this);
1407 DnDShape
*DnDShapeDialog::GetShape() const
1409 switch ( m_shapeKind
)
1412 case DnDShape::None
: return NULL
;
1413 case DnDShape::Triangle
: return new DnDTriangularShape(m_pos
, m_size
, m_col
);
1414 case DnDShape::Rectangle
: return new DnDRectangularShape(m_pos
, m_size
, m_col
);
1415 case DnDShape::Ellipse
: return new DnDEllipticShape(m_pos
, m_size
, m_col
);
1419 bool DnDShapeDialog::TransferDataToWindow()
1424 m_radio
->SetSelection(m_shape
->GetKind());
1425 m_pos
= m_shape
->GetPosition();
1426 m_size
= m_shape
->GetSize();
1427 m_col
= m_shape
->GetColour();
1431 m_radio
->SetSelection(DnDShape::None
);
1432 m_pos
= wxPoint(1, 1);
1433 m_size
= wxSize(100, 100);
1436 m_textX
->SetValue(wxString() << m_pos
.x
);
1437 m_textY
->SetValue(wxString() << m_pos
.y
);
1438 m_textW
->SetValue(wxString() << m_size
.x
);
1439 m_textH
->SetValue(wxString() << m_size
.y
);
1444 bool DnDShapeDialog::TransferDataFromWindow()
1446 m_shapeKind
= (DnDShape::Kind
)m_radio
->GetSelection();
1448 m_pos
.x
= atoi(m_textX
->GetValue());
1449 m_pos
.y
= atoi(m_textY
->GetValue());
1450 m_size
.x
= atoi(m_textW
->GetValue());
1451 m_size
.y
= atoi(m_textH
->GetValue());
1453 if ( !m_pos
.x
|| !m_pos
.y
|| !m_size
.x
|| !m_size
.y
)
1455 wxMessageBox("All sizes and positions should be non null!",
1456 "Invalid shape", wxICON_HAND
| wxOK
, this);
1464 void DnDShapeDialog::OnColour(wxCommandEvent
& WXUNUSED(event
))
1467 data
.SetChooseFull(TRUE
);
1468 for (int i
= 0; i
< 16; i
++)
1470 wxColour
colour(i
*16, i
*16, i
*16);
1471 data
.SetCustomColour(i
, colour
);
1474 wxColourDialog
dialog(this, &data
);
1475 if ( dialog
.ShowModal() == wxID_OK
)
1477 m_col
= dialog
.GetColourData().GetColour();
1481 // ----------------------------------------------------------------------------
1483 // ----------------------------------------------------------------------------
1485 DnDShapeFrame
*DnDShapeFrame::ms_lastDropTarget
= NULL
;
1487 DnDShapeFrame::DnDShapeFrame(wxFrame
*parent
)
1488 : wxFrame(parent
, -1, "Shape Frame",
1489 wxDefaultPosition
, wxSize(250, 150))
1493 wxMenu
*menuShape
= new wxMenu
;
1494 menuShape
->Append(Menu_Shape_New
, "&New default shape\tCtrl-S");
1495 menuShape
->Append(Menu_Shape_Edit
, "&Edit shape\tCtrl-E");
1496 menuShape
->AppendSeparator();
1497 menuShape
->Append(Menu_Shape_Clear
, "&Clear shape\tCtrl-L");
1499 wxMenu
*menuClipboard
= new wxMenu
;
1500 menuClipboard
->Append(Menu_ShapeClipboard_Copy
, "&Copy\tCtrl-C");
1501 menuClipboard
->Append(Menu_ShapeClipboard_Paste
, "&Paste\tCtrl-V");
1503 wxMenuBar
*menubar
= new wxMenuBar
;
1504 menubar
->Append(menuShape
, "&Shape");
1505 menubar
->Append(menuClipboard
, "&Clipboard");
1507 SetMenuBar(menubar
);
1509 SetStatusText("Press Ctrl-S to create a new shape");
1511 SetDropTarget(new DnDShapeDropTarget(this));
1515 SetBackgroundColour(*wxWHITE
);
1518 DnDShapeFrame::~DnDShapeFrame()
1524 void DnDShapeFrame::SetShape(DnDShape
*shape
)
1533 void DnDShapeFrame::OnDrag(wxMouseEvent
& event
)
1542 // start drag operation
1543 DnDShapeDataObject
shapeData(m_shape
);
1544 wxDropSource
source(shapeData
, this);
1546 const char *pc
= NULL
;
1547 switch ( source
.DoDragDrop(TRUE
) )
1551 wxLogError("An error occured during drag and drop operation");
1555 SetStatusText("Nothing happened");
1564 if ( ms_lastDropTarget
!= this )
1566 // don't delete the shape if we dropped it on ourselves!
1572 SetStatusText("Drag and drop operation cancelled");
1578 SetStatusText(wxString("Shape successfully ") + pc
);
1580 //else: status text already set
1583 void DnDShapeFrame::OnDrop(wxCoord x
, wxCoord y
, DnDShape
*shape
)
1585 ms_lastDropTarget
= this;
1590 s
.Printf("Shape dropped at (%ld, %ld)", pt
.x
, pt
.y
);
1597 void DnDShapeFrame::OnEditShape(wxCommandEvent
& event
)
1599 DnDShapeDialog
dlg(this, m_shape
);
1600 if ( dlg
.ShowModal() == wxID_OK
)
1602 SetShape(dlg
.GetShape());
1606 SetStatusText("You can now drag the shape to another frame");
1611 void DnDShapeFrame::OnNewShape(wxCommandEvent
& event
)
1613 SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED
));
1615 SetStatusText("You can now drag the shape to another frame");
1618 void DnDShapeFrame::OnClearShape(wxCommandEvent
& event
)
1623 void DnDShapeFrame::OnCopyShape(wxCommandEvent
& event
)
1627 wxClipboardLocker clipLocker
;
1630 wxLogError("Can't open the clipboard");
1635 wxTheClipboard
->AddData(new DnDShapeDataObject(m_shape
));
1639 void DnDShapeFrame::OnPasteShape(wxCommandEvent
& event
)
1641 wxClipboardLocker clipLocker
;
1644 wxLogError("Can't open the clipboard");
1649 DnDShapeDataObject
shapeDataObject(NULL
);
1650 if ( wxTheClipboard
->GetData(shapeDataObject
) )
1652 SetShape(shapeDataObject
.GetShape());
1656 wxLogStatus("No shape on the clipboard");
1660 void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent
& event
)
1662 event
.Enable( m_shape
!= NULL
);
1665 void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent
& event
)
1667 event
.Enable( wxTheClipboard
->IsSupported(wxDataFormat(shapeFormatId
)) );
1670 void DnDShapeFrame::OnPaint(wxPaintEvent
& event
)
1684 // ----------------------------------------------------------------------------
1686 // ----------------------------------------------------------------------------
1688 DnDShape
*DnDShape::New(const void *buf
)
1690 const ShapeDump
& dump
= *(const ShapeDump
*)buf
;
1694 return new DnDTriangularShape(wxPoint(dump
.x
, dump
.y
),
1695 wxSize(dump
.w
, dump
.h
),
1696 wxColour(dump
.r
, dump
.g
, dump
.b
));
1699 return new DnDRectangularShape(wxPoint(dump
.x
, dump
.y
),
1700 wxSize(dump
.w
, dump
.h
),
1701 wxColour(dump
.r
, dump
.g
, dump
.b
));
1704 return new DnDEllipticShape(wxPoint(dump
.x
, dump
.y
),
1705 wxSize(dump
.w
, dump
.h
),
1706 wxColour(dump
.r
, dump
.g
, dump
.b
));
1709 wxFAIL_MSG("invalid shape!");
1714 // ----------------------------------------------------------------------------
1715 // DnDShapeDataObject
1716 // ----------------------------------------------------------------------------
1718 #ifdef USE_METAFILES
1720 void DnDShapeDataObject::CreateMetaFile() const
1722 wxPoint pos
= m_shape
->GetPosition();
1723 wxSize size
= m_shape
->GetSize();
1725 wxMetaFileDC
dcMF(wxEmptyString
, pos
.x
+ size
.x
, pos
.y
+ size
.y
);
1727 m_shape
->Draw(dcMF
);
1729 wxMetafile
*mf
= dcMF
.Close();
1731 DnDShapeDataObject
*self
= (DnDShapeDataObject
*)this; // const_cast
1732 self
->m_dobjMetaFile
.SetMetafile(*mf
);
1733 self
->m_hasMetaFile
= TRUE
;
1740 void DnDShapeDataObject::CreateBitmap() const
1742 wxPoint pos
= m_shape
->GetPosition();
1743 wxSize size
= m_shape
->GetSize();
1744 int x
= pos
.x
+ size
.x
,
1746 wxBitmap
bitmap(x
, y
);
1748 dc
.SelectObject(bitmap
);
1749 dc
.SetBrush(wxBrush("white", wxSOLID
));
1752 dc
.SelectObject(wxNullBitmap
);
1754 DnDShapeDataObject
*self
= (DnDShapeDataObject
*)this; // const_cast
1755 self
->m_dobjBitmap
.SetBitmap(bitmap
);
1756 self
->m_hasBitmap
= TRUE
;
1759 // ----------------------------------------------------------------------------
1761 // ----------------------------------------------------------------------------
1763 static void ShowBitmap(const wxBitmap
& bitmap
)
1765 wxFrame
*frame
= new wxFrame(NULL
, -1, _T("Bitmap view"));
1766 frame
->CreateStatusBar();
1767 DnDCanvasBitmap
*canvas
= new DnDCanvasBitmap(frame
);
1768 canvas
->SetBitmap(bitmap
);
1770 int w
= bitmap
.GetWidth(),
1771 h
= bitmap
.GetHeight();
1772 frame
->SetStatusText(wxString::Format(_T("%dx%d"), w
, h
));
1774 frame
->SetClientSize(w
> 100 ? 100 : w
, h
> 100 ? 100 : h
);
1778 #ifdef USE_METAFILES
1780 static void ShowMetaFile(const wxMetaFile
& metafile
)
1782 wxFrame
*frame
= new wxFrame(NULL
, -1, _T("Metafile view"));
1783 frame
->CreateStatusBar();
1784 DnDCanvasMetafile
*canvas
= new DnDCanvasMetafile(frame
);
1785 canvas
->SetMetafile(metafile
);
1787 wxSize size
= metafile
.GetSize();
1788 frame
->SetStatusText(wxString::Format(_T("%dx%d"), size
.x
, size
.y
));
1790 frame
->SetClientSize(size
.x
> 100 ? 100 : size
.x
,
1791 size
.y
> 100 ? 100 : size
.y
);
1795 #endif // USE_METAFILES