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
30 #include "wx/dirdlg.h"
31 #include "wx/filedlg.h"
33 #include "wx/clipbrd.h"
34 #include "wx/colordlg.h"
35 #include "wx/resource.h"
37 #if defined(__WXGTK__) || defined(__WXMOTIF__)
38 #include "mondrian.xpm"
41 // ----------------------------------------------------------------------------
42 // Derive two simple classes which just put in the listbox the strings (text or
43 // file names) we drop on them
44 // ----------------------------------------------------------------------------
46 class DnDText
: public wxTextDropTarget
49 DnDText(wxListBox
*pOwner
) { m_pOwner
= pOwner
; }
51 virtual bool OnDropText(wxCoord x
, wxCoord y
, const wxString
& text
);
57 class DnDFile
: public wxFileDropTarget
60 DnDFile(wxListBox
*pOwner
) { m_pOwner
= pOwner
; }
62 virtual bool OnDropFiles(wxCoord x
, wxCoord y
,
63 const wxArrayString
& filenames
);
69 // ----------------------------------------------------------------------------
70 // Define a new application type
71 // ----------------------------------------------------------------------------
73 class DnDApp
: public wxApp
76 virtual bool OnInit();
79 IMPLEMENT_APP(DnDApp
);
81 // ----------------------------------------------------------------------------
82 // Define a new frame type for the main frame
83 // ----------------------------------------------------------------------------
85 class DnDFrame
: public wxFrame
88 DnDFrame(wxFrame
*frame
, char *title
, int x
, int y
, int w
, int h
);
91 void OnPaint(wxPaintEvent
& event
);
92 void OnQuit (wxCommandEvent
& event
);
93 void OnAbout(wxCommandEvent
& event
);
94 void OnDrag (wxCommandEvent
& event
);
95 void OnNewFrame(wxCommandEvent
& event
);
96 void OnHelp (wxCommandEvent
& event
);
97 void OnLogClear(wxCommandEvent
& event
);
99 void OnCopy(wxCommandEvent
& event
);
100 void OnPaste(wxCommandEvent
& event
);
102 void OnCopyBitmap(wxCommandEvent
& event
);
103 void OnPasteBitmap(wxCommandEvent
& event
);
105 void OnCopyFiles(wxCommandEvent
& event
);
107 void OnLeftDown(wxMouseEvent
& event
);
108 void OnRightDown(wxMouseEvent
& event
);
110 void OnUpdateUIPasteText(wxUpdateUIEvent
& event
);
111 void OnUpdateUIPasteBitmap(wxUpdateUIEvent
& event
);
113 DECLARE_EVENT_TABLE()
116 wxListBox
*m_ctrlFile
,
118 wxTextCtrl
*m_ctrlLog
;
127 // ----------------------------------------------------------------------------
128 // A shape is an example of application-specific data which may be transported
129 // via drag-and-drop or clipboard: in our case, we have different geometric
130 // shapes, each one with its own colour and position
131 // ----------------------------------------------------------------------------
144 DnDShape(const wxPoint
& pos
,
147 : m_pos(pos
), m_size(size
), m_col(col
)
151 // this is for debugging - lets us see when exactly an object is freed
152 // (this may be later than you think if it's on the clipboard, for example)
153 virtual ~DnDShape() { }
155 // the functions used for drag-and-drop: they dump and restore a shape into
156 // some bitwise-copiable data (might use streams too...)
157 // ------------------------------------------------------------------------
159 // restore from buffer
160 static DnDShape
*New(const void *buf
);
162 virtual size_t GetDataSize() const
164 return sizeof(ShapeDump
);
167 virtual void GetDataHere(void *buf
) const
169 ShapeDump
& dump
= *(ShapeDump
*)buf
;
174 dump
.r
= m_col
.Red();
175 dump
.g
= m_col
.Green();
176 dump
.b
= m_col
.Blue();
181 const wxPoint
& GetPosition() const { return m_pos
; }
182 const wxColour
& GetColour() const { return m_col
; }
183 const wxSize
& GetSize() const { return m_size
; }
185 void Move(const wxPoint
& pos
) { m_pos
= pos
; }
187 // to implement in derived classes
188 virtual Kind
GetKind() const = 0;
190 virtual void Draw(wxDC
& dc
)
192 dc
.SetPen(wxPen(m_col
, 1, wxSOLID
));
196 wxPoint
GetCentre() const
197 { return wxPoint(m_pos
.x
+ m_size
.x
/ 2, m_pos
.y
+ m_size
.y
/ 2); }
201 int x
, y
, // position
212 class DnDTriangularShape
: public DnDShape
215 DnDTriangularShape(const wxPoint
& pos
,
218 : DnDShape(pos
, size
, col
)
220 wxLogMessage("DnDTriangularShape is being created");
223 virtual ~DnDTriangularShape()
225 wxLogMessage("DnDTriangularShape is being deleted");
228 virtual Kind
GetKind() const { return Triangle
; }
229 virtual void Draw(wxDC
& dc
)
233 // well, it's a bit difficult to describe a triangle by position and
234 // size, but we're not doing geometry here, do we? ;-)
236 wxPoint
p2(m_pos
.x
+ m_size
.x
, m_pos
.y
);
237 wxPoint
p3(m_pos
.x
, m_pos
.y
+ m_size
.y
);
244 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
249 class DnDRectangularShape
: public DnDShape
252 DnDRectangularShape(const wxPoint
& pos
,
255 : DnDShape(pos
, size
, col
)
257 wxLogMessage("DnDRectangularShape is being created");
260 virtual ~DnDRectangularShape()
262 wxLogMessage("DnDRectangularShape is being deleted");
265 virtual Kind
GetKind() const { return Rectangle
; }
266 virtual void Draw(wxDC
& dc
)
271 wxPoint
p2(p1
.x
+ m_size
.x
, p1
.y
);
272 wxPoint
p3(p2
.x
, p2
.y
+ m_size
.y
);
273 wxPoint
p4(p1
.x
, p3
.y
);
281 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
286 class DnDEllipticShape
: public DnDShape
289 DnDEllipticShape(const wxPoint
& pos
,
292 : DnDShape(pos
, size
, col
)
294 wxLogMessage("DnDEllipticShape is being created");
297 virtual ~DnDEllipticShape()
299 wxLogMessage("DnDEllipticShape is being deleted");
302 virtual Kind
GetKind() const { return Ellipse
; }
303 virtual void Draw(wxDC
& dc
)
307 dc
.DrawEllipse(m_pos
, m_size
);
310 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
315 // ----------------------------------------------------------------------------
316 // A wxDataObject specialisation for the application-specific data
317 // ----------------------------------------------------------------------------
319 static const char *shapeFormatId
= "wxShape";
321 class DnDShapeDataObject
: public wxDataObject
324 // ctor doesn't copy the pointer, so it shouldn't go away while this object
326 DnDShapeDataObject(DnDShape
*shape
= (DnDShape
*)NULL
)
330 // we need to copy the shape because the one we're handled may be
331 // deleted while it's still on the clipboard (for example) - and we
332 // reuse the serialisation methods here to copy it
333 void *buf
= malloc(shape
->DnDShape
::GetDataSize());
334 shape
->GetDataHere(buf
);
335 m_shape
= DnDShape
::New(buf
);
345 // this string should uniquely identify our format, but is otherwise
347 m_formatShape
.SetId(shapeFormatId
);
349 // we don't draw the shape to a bitmap until it's really needed (i.e.
350 // we're asked to do so)
354 virtual ~DnDShapeDataObject() { delete m_shape
; }
356 // after a call to this function, the shape is owned by the caller and it
357 // is responsible for deleting it!
359 // NB: a better solution would be to make DnDShapes ref counted and this
360 // is what should probably be done in a real life program, otherwise
361 // the ownership problems become too complicated really fast
364 DnDShape
*shape
= m_shape
;
366 m_shape
= (DnDShape
*)NULL
;
372 // implement base class pure virtuals
373 // ----------------------------------
375 virtual wxDataFormat
GetPreferredFormat(Direction
WXUNUSED(dir
)) const
377 return m_formatShape
;
380 virtual size_t GetFormatCount(Direction dir
) const
382 // our custom format is supported by both GetData() and SetData()
386 // but the bitmap format(s) are only supported for output
387 nFormats
+= m_dataobj
.GetFormatCount(dir
);
393 virtual void GetAllFormats(wxDataFormat
*formats
, Direction dir
) const
395 formats
[0] = m_formatShape
;
398 m_dataobj
.GetAllFormats(&formats
[1], dir
);
402 virtual size_t GetDataSize(const wxDataFormat
& format
) const
404 if ( format
== m_formatShape
)
406 return m_shape
->GetDataSize();
413 return m_dataobj
.GetDataSize();
417 virtual bool GetDataHere(const wxDataFormat
& format
, void *pBuf
) const
419 if ( format
== m_formatShape
)
421 m_shape
->GetDataHere(pBuf
);
430 return m_dataobj
.GetDataHere(pBuf
);
434 virtual bool SetData(const wxDataFormat
& format
,
435 size_t len
, const void *buf
)
437 wxCHECK_MSG( format
== m_formatShape
, FALSE
, "unsupported format" );
440 m_shape
= DnDShape
::New(buf
);
442 // the shape has changed
449 // creates a bitmap and assigns it to m_dataobj (also sets m_hasBitmap)
450 void CreateBitmap() const;
452 wxDataFormat m_formatShape
; // our custom format
454 wxBitmapDataObject m_dataobj
; // it handles bitmaps
455 bool m_hasBitmap
; // true if m_dataobj has valid bitmap
457 DnDShape
*m_shape
; // our data
460 // ----------------------------------------------------------------------------
461 // A dialog to edit shape properties
462 // ----------------------------------------------------------------------------
464 class DnDShapeDialog
: public wxDialog
467 DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
);
469 DnDShape
*GetShape() const;
471 virtual bool TransferDataToWindow();
472 virtual bool TransferDataFromWindow();
474 void OnColour(wxCommandEvent
& event
);
481 DnDShape
::Kind m_shapeKind
;
493 DECLARE_EVENT_TABLE()
496 // ----------------------------------------------------------------------------
497 // A frame for the shapes which can be drag-and-dropped between frames
498 // ----------------------------------------------------------------------------
500 class DnDShapeFrame
: public wxFrame
503 DnDShapeFrame(wxFrame
*parent
);
506 void SetShape(DnDShape
*shape
);
509 void OnNewShape(wxCommandEvent
& event
);
510 void OnEditShape(wxCommandEvent
& event
);
511 void OnClearShape(wxCommandEvent
& event
);
513 void OnCopyShape(wxCommandEvent
& event
);
514 void OnPasteShape(wxCommandEvent
& event
);
516 void OnUpdateUICopy(wxUpdateUIEvent
& event
);
517 void OnUpdateUIPaste(wxUpdateUIEvent
& event
);
519 void OnDrag(wxMouseEvent
& event
);
520 void OnPaint(wxPaintEvent
& event
);
521 void OnDrop(wxCoord x
, wxCoord y
, DnDShape
*shape
);
526 static DnDShapeFrame
*ms_lastDropTarget
;
528 DECLARE_EVENT_TABLE()
531 // ----------------------------------------------------------------------------
532 // wxDropTarget derivation for DnDShapes
533 // ----------------------------------------------------------------------------
535 class DnDShapeDropTarget
: public wxDropTarget
538 DnDShapeDropTarget(DnDShapeFrame
*frame
)
539 : wxDropTarget(new DnDShapeDataObject
)
544 // override base class (pure) virtuals
545 virtual void OnEnter()
546 { m_frame
->SetStatusText("Mouse entered the frame"); }
547 virtual void OnLeave()
548 { m_frame
->SetStatusText("Mouse left the frame"); }
549 virtual wxDragResult
OnData(wxCoord x
, wxCoord y
, wxDragResult def
)
553 wxLogError("Failed to get drag and drop data");
558 m_frame
->OnDrop(x
, y
,
559 ((DnDShapeDataObject
*)GetDataObject())->GetShape());
565 DnDShapeFrame
*m_frame
;
568 // ----------------------------------------------------------------------------
569 // IDs for the menu commands
570 // ----------------------------------------------------------------------------
585 Menu_Shape_New
= 500,
588 Menu_ShapeClipboard_Copy
,
589 Menu_ShapeClipboard_Paste
,
593 BEGIN_EVENT_TABLE(DnDFrame
, wxFrame
)
594 EVT_MENU(Menu_Quit
, DnDFrame
::OnQuit
)
595 EVT_MENU(Menu_About
, DnDFrame
::OnAbout
)
596 EVT_MENU(Menu_Drag
, DnDFrame
::OnDrag
)
597 EVT_MENU(Menu_NewFrame
, DnDFrame
::OnNewFrame
)
598 EVT_MENU(Menu_Help
, DnDFrame
::OnHelp
)
599 EVT_MENU(Menu_Clear
, DnDFrame
::OnLogClear
)
600 EVT_MENU(Menu_Copy
, DnDFrame
::OnCopy
)
601 EVT_MENU(Menu_Paste
, DnDFrame
::OnPaste
)
602 EVT_MENU(Menu_CopyBitmap
, DnDFrame
::OnCopyBitmap
)
603 EVT_MENU(Menu_PasteBitmap
,DnDFrame
::OnPasteBitmap
)
604 EVT_MENU(Menu_CopyFiles
, DnDFrame
::OnCopyFiles
)
606 EVT_UPDATE_UI(Menu_Paste
, DnDFrame
::OnUpdateUIPasteText
)
607 EVT_UPDATE_UI(Menu_PasteBitmap
, DnDFrame
::OnUpdateUIPasteBitmap
)
609 EVT_LEFT_DOWN( DnDFrame
::OnLeftDown
)
610 EVT_RIGHT_DOWN( DnDFrame
::OnRightDown
)
611 EVT_PAINT( DnDFrame
::OnPaint
)
614 BEGIN_EVENT_TABLE(DnDShapeFrame
, wxFrame
)
615 EVT_MENU(Menu_Shape_New
, DnDShapeFrame
::OnNewShape
)
616 EVT_MENU(Menu_Shape_Edit
, DnDShapeFrame
::OnEditShape
)
617 EVT_MENU(Menu_Shape_Clear
, DnDShapeFrame
::OnClearShape
)
619 EVT_MENU(Menu_ShapeClipboard_Copy
, DnDShapeFrame
::OnCopyShape
)
620 EVT_MENU(Menu_ShapeClipboard_Paste
, DnDShapeFrame
::OnPasteShape
)
622 EVT_UPDATE_UI(Menu_ShapeClipboard_Copy
, DnDShapeFrame
::OnUpdateUICopy
)
623 EVT_UPDATE_UI(Menu_ShapeClipboard_Paste
, DnDShapeFrame
::OnUpdateUIPaste
)
625 EVT_LEFT_DOWN(DnDShapeFrame
::OnDrag
)
627 EVT_PAINT(DnDShapeFrame
::OnPaint
)
630 BEGIN_EVENT_TABLE(DnDShapeDialog
, wxDialog
)
631 EVT_BUTTON(Button_Colour
, DnDShapeDialog
::OnColour
)
634 // ============================================================================
636 // ============================================================================
638 // `Main program' equivalent, creating windows and returning main app frame
639 bool DnDApp
::OnInit()
641 // load our ressources
645 pathList
.Add("./Debug");
646 pathList
.Add("./Release");
649 wxString path
= pathList
.FindValidPath("dnd.wxr");
652 wxLogError("Can't find the resource file dnd.wxr in the current "
653 "directory, aborting.");
658 wxDefaultResourceTable
->ParseResourceFile(path
);
660 // switch on trace messages
661 #if defined(__WXGTK__)
662 wxLog
::AddTraceMask(_T("clipboard"));
663 #elif defined(__WXMSW__)
664 wxLog
::AddTraceMask(wxTRACE_OleCalls
);
668 wxImage
::AddHandler( new wxPNGHandler
);
671 // under X we usually want to use the primary selection by default (which
672 // is shared with other apps)
673 wxTheClipboard
->UsePrimarySelection();
675 // create the main frame window
676 DnDFrame
*frame
= new DnDFrame((wxFrame
*) NULL
,
677 "Drag-and-Drop/Clipboard wxWindows Sample",
688 DnDFrame
::DnDFrame(wxFrame
*frame
, char *title
, int x
, int y
, int w
, int h
)
689 : wxFrame(frame
, -1, title
, wxPoint(x
, y
), wxSize(w
, h
)),
690 m_strText("wxWindows drag & drop works :-)")
693 // frame icon and status bar
694 SetIcon(wxICON(mondrian
));
699 wxMenu
*file_menu
= new wxMenu
;
700 file_menu
->Append(Menu_Drag
, "&Test drag...");
701 file_menu
->AppendSeparator();
702 file_menu
->Append(Menu_NewFrame
, "&New frame\tCtrl-N");
703 file_menu
->AppendSeparator();
704 file_menu
->Append(Menu_Quit
, "E&xit");
706 wxMenu
*log_menu
= new wxMenu
;
707 log_menu
->Append(Menu_Clear
, "Clear\tCtrl-L");
709 wxMenu
*help_menu
= new wxMenu
;
710 help_menu
->Append(Menu_Help
, "&Help...");
711 help_menu
->AppendSeparator();
712 help_menu
->Append(Menu_About
, "&About");
714 wxMenu
*clip_menu
= new wxMenu
;
715 clip_menu
->Append(Menu_Copy
, "&Copy text\tCtrl+C");
716 clip_menu
->Append(Menu_Paste
, "&Paste text\tCtrl+V");
717 clip_menu
->AppendSeparator();
718 clip_menu
->Append(Menu_CopyBitmap
, "&Copy bitmap\tAlt+C");
719 clip_menu
->Append(Menu_PasteBitmap
, "&Paste bitmap\tAlt+V");
720 clip_menu
->AppendSeparator();
721 clip_menu
->Append(Menu_CopyFiles
, "&Copy files\tCtrl+F");
723 wxMenuBar
*menu_bar
= new wxMenuBar
;
724 menu_bar
->Append(file_menu
, "&File");
725 menu_bar
->Append(log_menu
, "&Log");
726 menu_bar
->Append(clip_menu
, "&Clipboard");
727 menu_bar
->Append(help_menu
, "&Help");
729 SetMenuBar(menu_bar
);
731 // make a panel with 3 subwindows
733 wxSize
size(400, 200);
735 wxString
strFile("Drop files here!"), strText("Drop text on me");
737 m_ctrlFile
= new wxListBox(this, -1, pos
, size
, 1, &strFile
,
738 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
739 m_ctrlText
= new wxListBox(this, -1, pos
, size
, 1, &strText
,
740 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
742 m_ctrlLog
= new wxTextCtrl(this, -1, "", pos
, size
,
743 wxTE_MULTILINE
| wxTE_READONLY
|
746 // redirect log messages to the text window
747 m_pLog
= new wxLogTextCtrl(m_ctrlLog
);
748 m_pLogPrev
= wxLog
::SetActiveTarget(m_pLog
);
750 // associate drop targets with 2 text controls
751 m_ctrlFile
->SetDropTarget(new DnDFile(m_ctrlFile
));
752 m_ctrlText
->SetDropTarget(new DnDText(m_ctrlText
));
754 wxLayoutConstraints
*c
;
757 c
= new wxLayoutConstraints
;
758 c
->left
.SameAs(this, wxLeft
);
759 c
->top
.SameAs(this, wxTop
);
760 c
->right
.PercentOf(this, wxRight
, 50);
761 c
->height
.PercentOf(this, wxHeight
, 30);
762 m_ctrlFile
->SetConstraints(c
);
765 c
= new wxLayoutConstraints
;
766 c
->left
.SameAs (m_ctrlFile
, wxRight
);
767 c
->top
.SameAs (this, wxTop
);
768 c
->right
.SameAs (this, wxRight
);
769 c
->height
.PercentOf(this, wxHeight
, 30);
770 m_ctrlText
->SetConstraints(c
);
772 // Lower text control
773 c
= new wxLayoutConstraints
;
774 c
->left
.SameAs (this, wxLeft
);
775 c
->right
.SameAs (this, wxRight
);
776 c
->height
.PercentOf(this, wxHeight
, 50);
777 c
->top
.SameAs(m_ctrlText
, wxBottom
);
778 m_ctrlLog
->SetConstraints(c
);
783 void DnDFrame
::OnQuit(wxCommandEvent
& WXUNUSED(event
))
788 void DnDFrame
::OnPaint(wxPaintEvent
& WXUNUSED(event
))
792 GetClientSize( &w
, &h
);
795 dc
.SetFont( wxFont( 24, wxDECORATIVE
, wxNORMAL
, wxNORMAL
, FALSE
, "charter" ) );
796 dc
.DrawText( "Drag text from here!", 20, h
-50 );
800 // 4/5 is 80% taken by other windows, 20 is arbitrary margin
801 dc
.DrawBitmap(m_bitmap
,
802 w
- m_bitmap
.GetWidth() - 20,
807 void DnDFrame
::OnUpdateUIPasteText(wxUpdateUIEvent
& event
)
810 // too many trace messages if we don't do it - this function is called
815 event
.Enable( wxTheClipboard
->IsSupported(wxDF_TEXT
) );
818 void DnDFrame
::OnUpdateUIPasteBitmap(wxUpdateUIEvent
& event
)
821 // too many trace messages if we don't do it - this function is called
826 event
.Enable( wxTheClipboard
->IsSupported(wxDF_BITMAP
) );
829 void DnDFrame
::OnNewFrame(wxCommandEvent
& WXUNUSED(event
))
831 (new DnDShapeFrame(this))->Show(TRUE
);
833 wxLogStatus(this, "Double click the new frame to select a shape for it");
836 void DnDFrame
::OnDrag(wxCommandEvent
& WXUNUSED(event
))
838 wxString strText
= wxGetTextFromUser
840 "After you enter text in this dialog, press any mouse\n"
841 "button in the bottom (empty) part of the frame and \n"
842 "drag it anywhere - you will be in fact dragging the\n"
843 "text object containing this text",
844 "Please enter some text", m_strText
, this
850 void DnDFrame
::OnAbout(wxCommandEvent
& WXUNUSED(event
))
852 wxMessageBox("Drag-&-Drop Demo\n"
853 "Please see \"Help|Help...\" for details\n"
854 "Copyright (c) 1998 Vadim Zeitlin",
856 wxICON_INFORMATION
| wxOK
,
860 void DnDFrame
::OnHelp(wxCommandEvent
& /* event */)
862 wxMessageDialog
dialog(this,
863 "This small program demonstrates drag & drop support in wxWindows. The program window\n"
864 "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
865 "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
866 "and the right one accepts text.\n"
868 "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
869 "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
870 "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
871 "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
872 "work with files) and see what changes.\n"
874 "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
875 "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
876 "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
877 "change, don't release the mouse button until it does. You can change the string being\n"
878 "dragged in in \"File|Test drag...\" dialog.\n"
881 "Please send all questions/bug reports/suggestions &c to \n"
882 "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
888 void DnDFrame
::OnLogClear(wxCommandEvent
& /* event */ )
895 void DnDFrame
::OnLeftDown(wxMouseEvent
&WXUNUSED(event
) )
897 if ( !m_strText
.IsEmpty() )
899 // start drag operation
900 wxTextDataObject
textData(m_strText
);
902 wxFileDataObject textData;
903 textData.AddFile( "/file1.txt" );
904 textData.AddFile( "/file2.txt" );
906 wxDropSource
source(textData
, this
909 ,wxCURSOR_PENCIL
, // for copy
910 wxCURSOR_SPRAYCAN
, // for move
911 wxCURSOR_QUESTION_ARROW
// for nothing
917 switch ( source
.DoDragDrop(TRUE
) )
919 case wxDragError
: pc
= "Error!"; break;
920 case wxDragNone
: pc
= "Nothing"; break;
921 case wxDragCopy
: pc
= "Copied"; break;
922 case wxDragMove
: pc
= "Moved"; break;
923 case wxDragCancel
: pc
= "Cancelled"; break;
924 default: pc
= "Huh?"; break;
927 SetStatusText(wxString("Drag result: ") + pc
);
931 void DnDFrame
::OnRightDown(wxMouseEvent
&event
)
933 wxMenu
menu("Dnd sample menu");
935 menu
.Append(Menu_Drag
, "&Test drag...");
936 menu
.AppendSeparator();
937 menu
.Append(Menu_About
, "&About");
939 PopupMenu( &menu
, event
.GetX(), event
.GetY() );
942 DnDFrame
::~DnDFrame()
944 if ( m_pLog
!= NULL
) {
945 if ( wxLog
::SetActiveTarget(m_pLogPrev
) == m_pLog
)
950 // ---------------------------------------------------------------------------
952 // ---------------------------------------------------------------------------
954 void DnDFrame
::OnCopyBitmap(wxCommandEvent
& WXUNUSED(event
))
956 // PNG support is not always compiled in under Windows, so use BMP there
958 wxFileDialog
dialog(this, "Open a BMP file", "", "", "BMP files (*.bmp)|*.bmp", 0);
960 wxFileDialog
dialog(this, "Open a PNG file", "", "", "PNG files (*.png)|*.png", 0);
963 if (dialog
.ShowModal() != wxID_OK
)
965 wxLogMessage( _T("Aborted file open") );
969 if (dialog
.GetPath().IsEmpty())
971 wxLogMessage( _T("Returned empty string.") );
975 if (!wxFileExists(dialog
.GetPath()))
977 wxLogMessage( _T("File doesn't exist.") );
982 image
.LoadFile( dialog
.GetPath(),
991 wxLogError( _T("Invalid image file...") );
995 wxLogStatus( _T("Decoding image file...") );
998 wxBitmap
bitmap( image
.ConvertToBitmap() );
1000 if ( !wxTheClipboard
->Open() )
1002 wxLogError(_T("Can't open clipboard."));
1007 wxLogMessage( _T("Creating wxBitmapDataObject...") );
1010 if ( !wxTheClipboard
->AddData(new wxBitmapDataObject(bitmap
)) )
1012 wxLogError(_T("Can't copy image to the clipboard."));
1016 wxLogMessage(_T("Image has been put on the clipboard.") );
1017 wxLogMessage(_T("You can paste it now and look at it.") );
1020 wxTheClipboard
->Close();
1023 void DnDFrame
::OnPasteBitmap(wxCommandEvent
& WXUNUSED(event
))
1025 if ( !wxTheClipboard
->Open() )
1027 wxLogError(_T("Can't open clipboard."));
1032 if ( !wxTheClipboard
->IsSupported(wxDF_BITMAP
) )
1034 wxLogWarning(_T("No bitmap on clipboard"));
1036 wxTheClipboard
->Close();
1040 wxBitmapDataObject data
;
1041 if ( !wxTheClipboard
->GetData(data
) )
1043 wxLogError(_T("Can't paste bitmap from the clipboard"));
1047 wxLogMessage(_T("Bitmap pasted from the clipboard") );
1048 m_bitmap
= data
.GetBitmap();
1052 wxTheClipboard
->Close();
1055 // ----------------------------------------------------------------------------
1057 // ----------------------------------------------------------------------------
1059 void DnDFrame
::OnCopyFiles(wxCommandEvent
& WXUNUSED(event
))
1062 wxFileDialog
dialog(this, "Select a file to copy", "", "",
1063 "All files (*.*)|*.*", 0);
1065 wxArrayString filenames
;
1066 while ( dialog
.ShowModal() == wxID_OK
)
1068 filenames
.Add(dialog
.GetPath());
1071 if ( !filenames
.IsEmpty() )
1073 wxFileDataObject
*dobj
= new wxFileDataObject
;
1074 size_t count
= filenames
.GetCount();
1075 for ( size_t n
= 0; n
< count
; n
++ )
1077 dobj
->AddFile(filenames
[n
]);
1080 wxClipboardLocker locker
;
1083 wxLogError("Can't open clipboard");
1087 if ( !wxTheClipboard
->AddData(dobj
) )
1089 wxLogError("Can't copy file(s) to the clipboard");
1093 wxLogStatus(this, "%d file%s copied to the clipboard",
1094 count
, count
== 1 ?
"" : "s");
1100 wxLogStatus(this, "Aborted");
1103 wxLogError("Sorry, not implemented");
1107 // ---------------------------------------------------------------------------
1109 // ---------------------------------------------------------------------------
1111 void DnDFrame
::OnCopy(wxCommandEvent
& WXUNUSED(event
))
1113 if ( !wxTheClipboard
->Open() )
1115 wxLogError(_T("Can't open clipboard."));
1120 if ( !wxTheClipboard
->AddData(new wxTextDataObject(m_strText
)) )
1122 wxLogError(_T("Can't copy data to the clipboard"));
1126 wxLogMessage(_T("Text '%s' put on the clipboard"), m_strText
.c_str());
1129 wxTheClipboard
->Close();
1132 void DnDFrame
::OnPaste(wxCommandEvent
& WXUNUSED(event
))
1134 if ( !wxTheClipboard
->Open() )
1136 wxLogError(_T("Can't open clipboard."));
1141 if ( !wxTheClipboard
->IsSupported(wxDF_TEXT
) )
1143 wxLogWarning(_T("No text data on clipboard"));
1145 wxTheClipboard
->Close();
1149 wxTextDataObject text
;
1150 if ( !wxTheClipboard
->GetData(text
) )
1152 wxLogError(_T("Can't paste data from the clipboard"));
1156 wxLogMessage(_T("Text '%s' pasted from the clipboard"),
1157 text
.GetText().c_str());
1160 wxTheClipboard
->Close();
1163 // ----------------------------------------------------------------------------
1164 // Notifications called by the base class
1165 // ----------------------------------------------------------------------------
1167 bool DnDText
::OnDropText(wxCoord
, wxCoord
, const wxString
& text
)
1169 m_pOwner
->Append(text
);
1174 bool DnDFile
::OnDropFiles(wxCoord
, wxCoord
, const wxArrayString
& filenames
)
1176 size_t nFiles
= filenames
.GetCount();
1178 str
.Printf( _T("%d files dropped"), nFiles
);
1179 m_pOwner
->Append(str
);
1180 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
1181 m_pOwner
->Append(filenames
[n
]);
1187 // ----------------------------------------------------------------------------
1189 // ----------------------------------------------------------------------------
1191 DnDShapeDialog
::DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
)
1195 LoadFromResource(parent
, "dialogShape");
1197 m_textX
= (wxTextCtrl
*)wxFindWindowByName("textX", this);
1198 m_textY
= (wxTextCtrl
*)wxFindWindowByName("textY", this);
1199 m_textW
= (wxTextCtrl
*)wxFindWindowByName("textW", this);
1200 m_textH
= (wxTextCtrl
*)wxFindWindowByName("textH", this);
1202 m_radio
= (wxRadioBox
*)wxFindWindowByName("radio", this);
1205 DnDShape
*DnDShapeDialog
::GetShape() const
1207 switch ( m_shapeKind
)
1210 case DnDShape
::None
: return NULL
;
1211 case DnDShape
::Triangle
: return new DnDTriangularShape(m_pos
, m_size
, m_col
);
1212 case DnDShape
::Rectangle
: return new DnDRectangularShape(m_pos
, m_size
, m_col
);
1213 case DnDShape
::Ellipse
: return new DnDEllipticShape(m_pos
, m_size
, m_col
);
1217 bool DnDShapeDialog
::TransferDataToWindow()
1222 m_radio
->SetSelection(m_shape
->GetKind());
1223 m_pos
= m_shape
->GetPosition();
1224 m_size
= m_shape
->GetSize();
1225 m_col
= m_shape
->GetColour();
1229 m_radio
->SetSelection(DnDShape
::None
);
1230 m_pos
= wxPoint(1, 1);
1231 m_size
= wxSize(100, 100);
1234 m_textX
->SetValue(wxString() << m_pos
.x
);
1235 m_textY
->SetValue(wxString() << m_pos
.y
);
1236 m_textW
->SetValue(wxString() << m_size
.x
);
1237 m_textH
->SetValue(wxString() << m_size
.y
);
1242 bool DnDShapeDialog
::TransferDataFromWindow()
1244 m_shapeKind
= (DnDShape
::Kind
)m_radio
->GetSelection();
1246 m_pos
.x
= atoi(m_textX
->GetValue());
1247 m_pos
.y
= atoi(m_textY
->GetValue());
1248 m_size
.x
= atoi(m_textW
->GetValue());
1249 m_size
.y
= atoi(m_textH
->GetValue());
1251 if ( !m_pos
.x
|| !m_pos
.y
|| !m_size
.x
|| !m_size
.y
)
1253 wxMessageBox("All sizes and positions should be non null!",
1254 "Invalid shape", wxICON_HAND
| wxOK
, this);
1262 void DnDShapeDialog
::OnColour(wxCommandEvent
& WXUNUSED(event
))
1265 data
.SetChooseFull(TRUE
);
1266 for (int i
= 0; i
< 16; i
++)
1268 wxColour
colour(i
*16, i
*16, i
*16);
1269 data
.SetCustomColour(i
, colour
);
1272 wxColourDialog
dialog(this, &data
);
1273 if ( dialog
.ShowModal() == wxID_OK
)
1275 m_col
= dialog
.GetColourData().GetColour();
1279 // ----------------------------------------------------------------------------
1281 // ----------------------------------------------------------------------------
1283 DnDShapeFrame
*DnDShapeFrame
::ms_lastDropTarget
= NULL
;
1285 DnDShapeFrame
::DnDShapeFrame(wxFrame
*parent
)
1286 : wxFrame(parent
, -1, "Shape Frame",
1287 wxDefaultPosition
, wxSize(250, 150))
1291 wxMenu
*menuShape
= new wxMenu
;
1292 menuShape
->Append(Menu_Shape_New
, "&New default shape\tCtrl-S");
1293 menuShape
->Append(Menu_Shape_Edit
, "&Edit shape\tCtrl-E");
1294 menuShape
->AppendSeparator();
1295 menuShape
->Append(Menu_Shape_Clear
, "&Clear shape\tDel");
1297 wxMenu
*menuClipboard
= new wxMenu
;
1298 menuClipboard
->Append(Menu_ShapeClipboard_Copy
, "&Copy\tCtrl-C");
1299 menuClipboard
->Append(Menu_ShapeClipboard_Paste
, "&Paste\tCtrl-V");
1301 wxMenuBar
*menubar
= new wxMenuBar
;
1302 menubar
->Append(menuShape
, "&Shape");
1303 menubar
->Append(menuClipboard
, "&Clipboard");
1305 SetMenuBar(menubar
);
1307 SetStatusText("Press Ctrl-S to create a new shape");
1309 SetDropTarget(new DnDShapeDropTarget(this));
1313 SetBackgroundColour(*wxWHITE
);
1316 DnDShapeFrame
::~DnDShapeFrame()
1322 void DnDShapeFrame
::SetShape(DnDShape
*shape
)
1331 void DnDShapeFrame
::OnDrag(wxMouseEvent
& event
)
1340 // start drag operation
1341 DnDShapeDataObject
shapeData(m_shape
);
1342 wxDropSource
source(shapeData
, this);
1344 const char *pc
= NULL
;
1345 switch ( source
.DoDragDrop(TRUE
) )
1349 wxLogError("An error occured during drag and drop operation");
1353 SetStatusText("Nothing happened");
1362 if ( ms_lastDropTarget
!= this )
1364 // don't delete the shape if we dropped it on ourselves!
1370 SetStatusText("Drag and drop operation cancelled");
1376 SetStatusText(wxString("Shape successfully ") + pc
);
1378 //else: status text already set
1381 void DnDShapeFrame
::OnDrop(wxCoord x
, wxCoord y
, DnDShape
*shape
)
1383 ms_lastDropTarget
= this;
1388 s
.Printf("Shape dropped at (%ld, %ld)", pt
.x
, pt
.y
);
1395 void DnDShapeFrame
::OnEditShape(wxCommandEvent
& event
)
1397 DnDShapeDialog
dlg(this, m_shape
);
1398 if ( dlg
.ShowModal() == wxID_OK
)
1400 SetShape(dlg
.GetShape());
1404 SetStatusText("You can now drag the shape to another frame");
1409 void DnDShapeFrame
::OnNewShape(wxCommandEvent
& event
)
1411 SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED
));
1413 SetStatusText("You can now drag the shape to another frame");
1416 void DnDShapeFrame
::OnClearShape(wxCommandEvent
& event
)
1421 void DnDShapeFrame
::OnCopyShape(wxCommandEvent
& event
)
1425 wxClipboardLocker clipLocker
;
1428 wxLogError("Can't open the clipboard");
1433 wxTheClipboard
->AddData(new DnDShapeDataObject(m_shape
));
1437 void DnDShapeFrame
::OnPasteShape(wxCommandEvent
& event
)
1439 wxClipboardLocker clipLocker
;
1442 wxLogError("Can't open the clipboard");
1447 DnDShapeDataObject
shapeDataObject(NULL
);
1448 if ( wxTheClipboard
->GetData(shapeDataObject
) )
1450 SetShape(shapeDataObject
.GetShape());
1454 wxLogStatus("No shape on the clipboard");
1458 void DnDShapeFrame
::OnUpdateUICopy(wxUpdateUIEvent
& event
)
1460 event
.Enable( m_shape
!= NULL
);
1463 void DnDShapeFrame
::OnUpdateUIPaste(wxUpdateUIEvent
& event
)
1465 event
.Enable( wxTheClipboard
->IsSupported(wxDataFormat(shapeFormatId
)) );
1468 void DnDShapeFrame
::OnPaint(wxPaintEvent
& event
)
1482 // ----------------------------------------------------------------------------
1484 // ----------------------------------------------------------------------------
1486 DnDShape
*DnDShape
::New(const void *buf
)
1488 const ShapeDump
& dump
= *(const ShapeDump
*)buf
;
1492 return new DnDTriangularShape(wxPoint(dump
.x
, dump
.y
),
1493 wxSize(dump
.w
, dump
.h
),
1494 wxColour(dump
.r
, dump
.g
, dump
.b
));
1497 return new DnDRectangularShape(wxPoint(dump
.x
, dump
.y
),
1498 wxSize(dump
.w
, dump
.h
),
1499 wxColour(dump
.r
, dump
.g
, dump
.b
));
1502 return new DnDEllipticShape(wxPoint(dump
.x
, dump
.y
),
1503 wxSize(dump
.w
, dump
.h
),
1504 wxColour(dump
.r
, dump
.g
, dump
.b
));
1507 wxFAIL_MSG("invalid shape!");
1512 // ----------------------------------------------------------------------------
1513 // DnDShapeDataObject
1514 // ----------------------------------------------------------------------------
1516 void DnDShapeDataObject
::CreateBitmap() const
1518 wxPoint pos
= m_shape
->GetPosition();
1519 wxSize size
= m_shape
->GetSize();
1520 int x
= pos
.x
+ size
.x
,
1522 wxBitmap
bitmap(x
, y
);
1524 dc
.SelectObject(bitmap
);
1525 dc
.SetBrush(wxBrush("white", wxSOLID
));
1528 dc
.SelectObject(wxNullBitmap
);
1530 DnDShapeDataObject
*self
= (DnDShapeDataObject
*)this; // const_cast
1531 self
->m_dataobj
.SetBitmap(bitmap
);
1532 self
->m_hasBitmap
= TRUE
;