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 wxDragResult
OnEnter(wxCoord x
, wxCoord y
, wxDragResult def
)
546 { m_frame
->SetStatusText("Mouse entered the frame");
547 return OnDragOver(x
, y
, def
); }
548 virtual void OnLeave()
549 { m_frame
->SetStatusText("Mouse left the frame"); }
550 virtual wxDragResult
OnData(wxCoord x
, wxCoord y
, wxDragResult def
)
554 wxLogError("Failed to get drag and drop data");
559 m_frame
->OnDrop(x
, y
,
560 ((DnDShapeDataObject
*)GetDataObject())->GetShape());
566 DnDShapeFrame
*m_frame
;
569 // ----------------------------------------------------------------------------
570 // IDs for the menu commands
571 // ----------------------------------------------------------------------------
586 Menu_Shape_New
= 500,
589 Menu_ShapeClipboard_Copy
,
590 Menu_ShapeClipboard_Paste
,
594 BEGIN_EVENT_TABLE(DnDFrame
, wxFrame
)
595 EVT_MENU(Menu_Quit
, DnDFrame::OnQuit
)
596 EVT_MENU(Menu_About
, DnDFrame::OnAbout
)
597 EVT_MENU(Menu_Drag
, DnDFrame::OnDrag
)
598 EVT_MENU(Menu_NewFrame
, DnDFrame::OnNewFrame
)
599 EVT_MENU(Menu_Help
, DnDFrame::OnHelp
)
600 EVT_MENU(Menu_Clear
, DnDFrame::OnLogClear
)
601 EVT_MENU(Menu_Copy
, DnDFrame::OnCopy
)
602 EVT_MENU(Menu_Paste
, DnDFrame::OnPaste
)
603 EVT_MENU(Menu_CopyBitmap
, DnDFrame::OnCopyBitmap
)
604 EVT_MENU(Menu_PasteBitmap
,DnDFrame::OnPasteBitmap
)
605 EVT_MENU(Menu_CopyFiles
, DnDFrame::OnCopyFiles
)
607 EVT_UPDATE_UI(Menu_Paste
, DnDFrame::OnUpdateUIPasteText
)
608 EVT_UPDATE_UI(Menu_PasteBitmap
, DnDFrame::OnUpdateUIPasteBitmap
)
610 EVT_LEFT_DOWN( DnDFrame::OnLeftDown
)
611 EVT_RIGHT_DOWN( DnDFrame::OnRightDown
)
612 EVT_PAINT( DnDFrame::OnPaint
)
615 BEGIN_EVENT_TABLE(DnDShapeFrame
, wxFrame
)
616 EVT_MENU(Menu_Shape_New
, DnDShapeFrame::OnNewShape
)
617 EVT_MENU(Menu_Shape_Edit
, DnDShapeFrame::OnEditShape
)
618 EVT_MENU(Menu_Shape_Clear
, DnDShapeFrame::OnClearShape
)
620 EVT_MENU(Menu_ShapeClipboard_Copy
, DnDShapeFrame::OnCopyShape
)
621 EVT_MENU(Menu_ShapeClipboard_Paste
, DnDShapeFrame::OnPasteShape
)
623 EVT_UPDATE_UI(Menu_ShapeClipboard_Copy
, DnDShapeFrame::OnUpdateUICopy
)
624 EVT_UPDATE_UI(Menu_ShapeClipboard_Paste
, DnDShapeFrame::OnUpdateUIPaste
)
626 EVT_LEFT_DOWN(DnDShapeFrame::OnDrag
)
628 EVT_PAINT(DnDShapeFrame::OnPaint
)
631 BEGIN_EVENT_TABLE(DnDShapeDialog
, wxDialog
)
632 EVT_BUTTON(Button_Colour
, DnDShapeDialog::OnColour
)
635 // ============================================================================
637 // ============================================================================
639 // `Main program' equivalent, creating windows and returning main app frame
640 bool DnDApp::OnInit()
642 // load our ressources
646 pathList
.Add("./Debug");
647 pathList
.Add("./Release");
650 wxString path
= pathList
.FindValidPath("dnd.wxr");
653 wxLogError("Can't find the resource file dnd.wxr in the current "
654 "directory, aborting.");
659 wxDefaultResourceTable
->ParseResourceFile(path
);
661 // switch on trace messages
662 #if defined(__WXGTK__)
663 wxLog::AddTraceMask(_T("clipboard"));
664 #elif defined(__WXMSW__)
665 wxLog::AddTraceMask(wxTRACE_OleCalls
);
669 wxImage::AddHandler( new wxPNGHandler
);
672 // under X we usually want to use the primary selection by default (which
673 // is shared with other apps)
674 wxTheClipboard
->UsePrimarySelection();
676 // create the main frame window
677 DnDFrame
*frame
= new DnDFrame((wxFrame
*) NULL
,
678 "Drag-and-Drop/Clipboard wxWindows Sample",
689 DnDFrame::DnDFrame(wxFrame
*frame
, char *title
, int x
, int y
, int w
, int h
)
690 : wxFrame(frame
, -1, title
, wxPoint(x
, y
), wxSize(w
, h
)),
691 m_strText("wxWindows drag & drop works :-)")
694 // frame icon and status bar
695 SetIcon(wxICON(mondrian
));
700 wxMenu
*file_menu
= new wxMenu
;
701 file_menu
->Append(Menu_Drag
, "&Test drag...");
702 file_menu
->AppendSeparator();
703 file_menu
->Append(Menu_NewFrame
, "&New frame\tCtrl-N");
704 file_menu
->AppendSeparator();
705 file_menu
->Append(Menu_Quit
, "E&xit");
707 wxMenu
*log_menu
= new wxMenu
;
708 log_menu
->Append(Menu_Clear
, "Clear\tCtrl-L");
710 wxMenu
*help_menu
= new wxMenu
;
711 help_menu
->Append(Menu_Help
, "&Help...");
712 help_menu
->AppendSeparator();
713 help_menu
->Append(Menu_About
, "&About");
715 wxMenu
*clip_menu
= new wxMenu
;
716 clip_menu
->Append(Menu_Copy
, "&Copy text\tCtrl+C");
717 clip_menu
->Append(Menu_Paste
, "&Paste text\tCtrl+V");
718 clip_menu
->AppendSeparator();
719 clip_menu
->Append(Menu_CopyBitmap
, "&Copy bitmap\tAlt+C");
720 clip_menu
->Append(Menu_PasteBitmap
, "&Paste bitmap\tAlt+V");
721 clip_menu
->AppendSeparator();
722 clip_menu
->Append(Menu_CopyFiles
, "&Copy files\tCtrl+F");
724 wxMenuBar
*menu_bar
= new wxMenuBar
;
725 menu_bar
->Append(file_menu
, "&File");
726 menu_bar
->Append(log_menu
, "&Log");
727 menu_bar
->Append(clip_menu
, "&Clipboard");
728 menu_bar
->Append(help_menu
, "&Help");
730 SetMenuBar(menu_bar
);
732 // make a panel with 3 subwindows
734 wxSize
size(400, 200);
736 wxString
strFile("Drop files here!"), strText("Drop text on me");
738 m_ctrlFile
= new wxListBox(this, -1, pos
, size
, 1, &strFile
,
739 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
740 m_ctrlText
= new wxListBox(this, -1, pos
, size
, 1, &strText
,
741 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
743 m_ctrlLog
= new wxTextCtrl(this, -1, "", pos
, size
,
744 wxTE_MULTILINE
| wxTE_READONLY
|
747 // redirect log messages to the text window
748 m_pLog
= new wxLogTextCtrl(m_ctrlLog
);
749 m_pLogPrev
= wxLog::SetActiveTarget(m_pLog
);
751 // associate drop targets with 2 text controls
752 m_ctrlFile
->SetDropTarget(new DnDFile(m_ctrlFile
));
753 m_ctrlText
->SetDropTarget(new DnDText(m_ctrlText
));
755 wxLayoutConstraints
*c
;
758 c
= new wxLayoutConstraints
;
759 c
->left
.SameAs(this, wxLeft
);
760 c
->top
.SameAs(this, wxTop
);
761 c
->right
.PercentOf(this, wxRight
, 50);
762 c
->height
.PercentOf(this, wxHeight
, 30);
763 m_ctrlFile
->SetConstraints(c
);
766 c
= new wxLayoutConstraints
;
767 c
->left
.SameAs (m_ctrlFile
, wxRight
);
768 c
->top
.SameAs (this, wxTop
);
769 c
->right
.SameAs (this, wxRight
);
770 c
->height
.PercentOf(this, wxHeight
, 30);
771 m_ctrlText
->SetConstraints(c
);
773 // Lower text control
774 c
= new wxLayoutConstraints
;
775 c
->left
.SameAs (this, wxLeft
);
776 c
->right
.SameAs (this, wxRight
);
777 c
->height
.PercentOf(this, wxHeight
, 50);
778 c
->top
.SameAs(m_ctrlText
, wxBottom
);
779 m_ctrlLog
->SetConstraints(c
);
784 void DnDFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
))
789 void DnDFrame::OnPaint(wxPaintEvent
& WXUNUSED(event
))
793 GetClientSize( &w
, &h
);
796 dc
.SetFont( wxFont( 24, wxDECORATIVE
, wxNORMAL
, wxNORMAL
, FALSE
, "charter" ) );
797 dc
.DrawText( "Drag text from here!", 20, h
-50 );
801 // 4/5 is 80% taken by other windows, 20 is arbitrary margin
802 dc
.DrawBitmap(m_bitmap
,
803 w
- m_bitmap
.GetWidth() - 20,
808 void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent
& event
)
811 // too many trace messages if we don't do it - this function is called
816 event
.Enable( wxTheClipboard
->IsSupported(wxDF_TEXT
) );
819 void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent
& event
)
822 // too many trace messages if we don't do it - this function is called
827 event
.Enable( wxTheClipboard
->IsSupported(wxDF_BITMAP
) );
830 void DnDFrame::OnNewFrame(wxCommandEvent
& WXUNUSED(event
))
832 (new DnDShapeFrame(this))->Show(TRUE
);
834 wxLogStatus(this, "Double click the new frame to select a shape for it");
837 void DnDFrame::OnDrag(wxCommandEvent
& WXUNUSED(event
))
839 wxString strText
= wxGetTextFromUser
841 "After you enter text in this dialog, press any mouse\n"
842 "button in the bottom (empty) part of the frame and \n"
843 "drag it anywhere - you will be in fact dragging the\n"
844 "text object containing this text",
845 "Please enter some text", m_strText
, this
851 void DnDFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
853 wxMessageBox("Drag-&-Drop Demo\n"
854 "Please see \"Help|Help...\" for details\n"
855 "Copyright (c) 1998 Vadim Zeitlin",
857 wxICON_INFORMATION
| wxOK
,
861 void DnDFrame::OnHelp(wxCommandEvent
& /* event */)
863 wxMessageDialog
dialog(this,
864 "This small program demonstrates drag & drop support in wxWindows. The program window\n"
865 "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
866 "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
867 "and the right one accepts text.\n"
869 "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
870 "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
871 "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
872 "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
873 "work with files) and see what changes.\n"
875 "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
876 "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
877 "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
878 "change, don't release the mouse button until it does. You can change the string being\n"
879 "dragged in in \"File|Test drag...\" dialog.\n"
882 "Please send all questions/bug reports/suggestions &c to \n"
883 "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
889 void DnDFrame::OnLogClear(wxCommandEvent
& /* event */ )
896 void DnDFrame::OnLeftDown(wxMouseEvent
&WXUNUSED(event
) )
898 if ( !m_strText
.IsEmpty() )
900 // start drag operation
901 wxTextDataObject
textData(m_strText
);
903 wxFileDataObject textData;
904 textData.AddFile( "/file1.txt" );
905 textData.AddFile( "/file2.txt" );
907 wxDropSource
source(textData
, this
910 ,wxCURSOR_PENCIL
, // for copy
911 wxCURSOR_SPRAYCAN
, // for move
912 wxCURSOR_QUESTION_ARROW
// for nothing
918 switch ( source
.DoDragDrop(TRUE
) )
920 case wxDragError
: pc
= "Error!"; break;
921 case wxDragNone
: pc
= "Nothing"; break;
922 case wxDragCopy
: pc
= "Copied"; break;
923 case wxDragMove
: pc
= "Moved"; break;
924 case wxDragCancel
: pc
= "Cancelled"; break;
925 default: pc
= "Huh?"; break;
928 SetStatusText(wxString("Drag result: ") + pc
);
932 void DnDFrame::OnRightDown(wxMouseEvent
&event
)
934 wxMenu
menu("Dnd sample menu");
936 menu
.Append(Menu_Drag
, "&Test drag...");
937 menu
.AppendSeparator();
938 menu
.Append(Menu_About
, "&About");
940 PopupMenu( &menu
, event
.GetX(), event
.GetY() );
943 DnDFrame::~DnDFrame()
945 if ( m_pLog
!= NULL
) {
946 if ( wxLog::SetActiveTarget(m_pLogPrev
) == m_pLog
)
951 // ---------------------------------------------------------------------------
953 // ---------------------------------------------------------------------------
955 void DnDFrame::OnCopyBitmap(wxCommandEvent
& WXUNUSED(event
))
957 // PNG support is not always compiled in under Windows, so use BMP there
959 wxFileDialog
dialog(this, "Open a BMP file", "", "", "BMP files (*.bmp)|*.bmp", 0);
961 wxFileDialog
dialog(this, "Open a PNG file", "", "", "PNG files (*.png)|*.png", 0);
964 if (dialog
.ShowModal() != wxID_OK
)
966 wxLogMessage( _T("Aborted file open") );
970 if (dialog
.GetPath().IsEmpty())
972 wxLogMessage( _T("Returned empty string.") );
976 if (!wxFileExists(dialog
.GetPath()))
978 wxLogMessage( _T("File doesn't exist.") );
983 image
.LoadFile( dialog
.GetPath(),
992 wxLogError( _T("Invalid image file...") );
996 wxLogStatus( _T("Decoding image file...") );
999 wxBitmap
bitmap( image
.ConvertToBitmap() );
1001 if ( !wxTheClipboard
->Open() )
1003 wxLogError(_T("Can't open clipboard."));
1008 wxLogMessage( _T("Creating wxBitmapDataObject...") );
1011 if ( !wxTheClipboard
->AddData(new wxBitmapDataObject(bitmap
)) )
1013 wxLogError(_T("Can't copy image to the clipboard."));
1017 wxLogMessage(_T("Image has been put on the clipboard.") );
1018 wxLogMessage(_T("You can paste it now and look at it.") );
1021 wxTheClipboard
->Close();
1024 void DnDFrame::OnPasteBitmap(wxCommandEvent
& WXUNUSED(event
))
1026 if ( !wxTheClipboard
->Open() )
1028 wxLogError(_T("Can't open clipboard."));
1033 if ( !wxTheClipboard
->IsSupported(wxDF_BITMAP
) )
1035 wxLogWarning(_T("No bitmap on clipboard"));
1037 wxTheClipboard
->Close();
1041 wxBitmapDataObject data
;
1042 if ( !wxTheClipboard
->GetData(data
) )
1044 wxLogError(_T("Can't paste bitmap from the clipboard"));
1048 wxLogMessage(_T("Bitmap pasted from the clipboard") );
1049 m_bitmap
= data
.GetBitmap();
1053 wxTheClipboard
->Close();
1056 // ----------------------------------------------------------------------------
1058 // ----------------------------------------------------------------------------
1060 void DnDFrame::OnCopyFiles(wxCommandEvent
& WXUNUSED(event
))
1063 wxFileDialog
dialog(this, "Select a file to copy", "", "",
1064 "All files (*.*)|*.*", 0);
1066 wxArrayString filenames
;
1067 while ( dialog
.ShowModal() == wxID_OK
)
1069 filenames
.Add(dialog
.GetPath());
1072 if ( !filenames
.IsEmpty() )
1074 wxFileDataObject
*dobj
= new wxFileDataObject
;
1075 size_t count
= filenames
.GetCount();
1076 for ( size_t n
= 0; n
< count
; n
++ )
1078 dobj
->AddFile(filenames
[n
]);
1081 wxClipboardLocker locker
;
1084 wxLogError("Can't open clipboard");
1088 if ( !wxTheClipboard
->AddData(dobj
) )
1090 wxLogError("Can't copy file(s) to the clipboard");
1094 wxLogStatus(this, "%d file%s copied to the clipboard",
1095 count
, count
== 1 ? "" : "s");
1101 wxLogStatus(this, "Aborted");
1104 wxLogError("Sorry, not implemented");
1108 // ---------------------------------------------------------------------------
1110 // ---------------------------------------------------------------------------
1112 void DnDFrame::OnCopy(wxCommandEvent
& WXUNUSED(event
))
1114 if ( !wxTheClipboard
->Open() )
1116 wxLogError(_T("Can't open clipboard."));
1121 if ( !wxTheClipboard
->AddData(new wxTextDataObject(m_strText
)) )
1123 wxLogError(_T("Can't copy data to the clipboard"));
1127 wxLogMessage(_T("Text '%s' put on the clipboard"), m_strText
.c_str());
1130 wxTheClipboard
->Close();
1133 void DnDFrame::OnPaste(wxCommandEvent
& WXUNUSED(event
))
1135 if ( !wxTheClipboard
->Open() )
1137 wxLogError(_T("Can't open clipboard."));
1142 if ( !wxTheClipboard
->IsSupported(wxDF_TEXT
) )
1144 wxLogWarning(_T("No text data on clipboard"));
1146 wxTheClipboard
->Close();
1150 wxTextDataObject text
;
1151 if ( !wxTheClipboard
->GetData(text
) )
1153 wxLogError(_T("Can't paste data from the clipboard"));
1157 wxLogMessage(_T("Text '%s' pasted from the clipboard"),
1158 text
.GetText().c_str());
1161 wxTheClipboard
->Close();
1164 // ----------------------------------------------------------------------------
1165 // Notifications called by the base class
1166 // ----------------------------------------------------------------------------
1168 bool DnDText::OnDropText(wxCoord
, wxCoord
, const wxString
& text
)
1170 m_pOwner
->Append(text
);
1175 bool DnDFile::OnDropFiles(wxCoord
, wxCoord
, const wxArrayString
& filenames
)
1177 size_t nFiles
= filenames
.GetCount();
1179 str
.Printf( _T("%d files dropped"), nFiles
);
1180 m_pOwner
->Append(str
);
1181 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
1182 m_pOwner
->Append(filenames
[n
]);
1188 // ----------------------------------------------------------------------------
1190 // ----------------------------------------------------------------------------
1192 DnDShapeDialog::DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
)
1196 LoadFromResource(parent
, "dialogShape");
1198 m_textX
= (wxTextCtrl
*)wxFindWindowByName("textX", this);
1199 m_textY
= (wxTextCtrl
*)wxFindWindowByName("textY", this);
1200 m_textW
= (wxTextCtrl
*)wxFindWindowByName("textW", this);
1201 m_textH
= (wxTextCtrl
*)wxFindWindowByName("textH", this);
1203 m_radio
= (wxRadioBox
*)wxFindWindowByName("radio", this);
1206 DnDShape
*DnDShapeDialog::GetShape() const
1208 switch ( m_shapeKind
)
1211 case DnDShape::None
: return NULL
;
1212 case DnDShape::Triangle
: return new DnDTriangularShape(m_pos
, m_size
, m_col
);
1213 case DnDShape::Rectangle
: return new DnDRectangularShape(m_pos
, m_size
, m_col
);
1214 case DnDShape::Ellipse
: return new DnDEllipticShape(m_pos
, m_size
, m_col
);
1218 bool DnDShapeDialog::TransferDataToWindow()
1223 m_radio
->SetSelection(m_shape
->GetKind());
1224 m_pos
= m_shape
->GetPosition();
1225 m_size
= m_shape
->GetSize();
1226 m_col
= m_shape
->GetColour();
1230 m_radio
->SetSelection(DnDShape::None
);
1231 m_pos
= wxPoint(1, 1);
1232 m_size
= wxSize(100, 100);
1235 m_textX
->SetValue(wxString() << m_pos
.x
);
1236 m_textY
->SetValue(wxString() << m_pos
.y
);
1237 m_textW
->SetValue(wxString() << m_size
.x
);
1238 m_textH
->SetValue(wxString() << m_size
.y
);
1243 bool DnDShapeDialog::TransferDataFromWindow()
1245 m_shapeKind
= (DnDShape::Kind
)m_radio
->GetSelection();
1247 m_pos
.x
= atoi(m_textX
->GetValue());
1248 m_pos
.y
= atoi(m_textY
->GetValue());
1249 m_size
.x
= atoi(m_textW
->GetValue());
1250 m_size
.y
= atoi(m_textH
->GetValue());
1252 if ( !m_pos
.x
|| !m_pos
.y
|| !m_size
.x
|| !m_size
.y
)
1254 wxMessageBox("All sizes and positions should be non null!",
1255 "Invalid shape", wxICON_HAND
| wxOK
, this);
1263 void DnDShapeDialog::OnColour(wxCommandEvent
& WXUNUSED(event
))
1266 data
.SetChooseFull(TRUE
);
1267 for (int i
= 0; i
< 16; i
++)
1269 wxColour
colour(i
*16, i
*16, i
*16);
1270 data
.SetCustomColour(i
, colour
);
1273 wxColourDialog
dialog(this, &data
);
1274 if ( dialog
.ShowModal() == wxID_OK
)
1276 m_col
= dialog
.GetColourData().GetColour();
1280 // ----------------------------------------------------------------------------
1282 // ----------------------------------------------------------------------------
1284 DnDShapeFrame
*DnDShapeFrame::ms_lastDropTarget
= NULL
;
1286 DnDShapeFrame::DnDShapeFrame(wxFrame
*parent
)
1287 : wxFrame(parent
, -1, "Shape Frame",
1288 wxDefaultPosition
, wxSize(250, 150))
1292 wxMenu
*menuShape
= new wxMenu
;
1293 menuShape
->Append(Menu_Shape_New
, "&New default shape\tCtrl-S");
1294 menuShape
->Append(Menu_Shape_Edit
, "&Edit shape\tCtrl-E");
1295 menuShape
->AppendSeparator();
1296 menuShape
->Append(Menu_Shape_Clear
, "&Clear shape\tDel");
1298 wxMenu
*menuClipboard
= new wxMenu
;
1299 menuClipboard
->Append(Menu_ShapeClipboard_Copy
, "&Copy\tCtrl-C");
1300 menuClipboard
->Append(Menu_ShapeClipboard_Paste
, "&Paste\tCtrl-V");
1302 wxMenuBar
*menubar
= new wxMenuBar
;
1303 menubar
->Append(menuShape
, "&Shape");
1304 menubar
->Append(menuClipboard
, "&Clipboard");
1306 SetMenuBar(menubar
);
1308 SetStatusText("Press Ctrl-S to create a new shape");
1310 SetDropTarget(new DnDShapeDropTarget(this));
1314 SetBackgroundColour(*wxWHITE
);
1317 DnDShapeFrame::~DnDShapeFrame()
1323 void DnDShapeFrame::SetShape(DnDShape
*shape
)
1332 void DnDShapeFrame::OnDrag(wxMouseEvent
& event
)
1341 // start drag operation
1342 DnDShapeDataObject
shapeData(m_shape
);
1343 wxDropSource
source(shapeData
, this);
1345 const char *pc
= NULL
;
1346 switch ( source
.DoDragDrop(TRUE
) )
1350 wxLogError("An error occured during drag and drop operation");
1354 SetStatusText("Nothing happened");
1363 if ( ms_lastDropTarget
!= this )
1365 // don't delete the shape if we dropped it on ourselves!
1371 SetStatusText("Drag and drop operation cancelled");
1377 SetStatusText(wxString("Shape successfully ") + pc
);
1379 //else: status text already set
1382 void DnDShapeFrame::OnDrop(wxCoord x
, wxCoord y
, DnDShape
*shape
)
1384 ms_lastDropTarget
= this;
1389 s
.Printf("Shape dropped at (%ld, %ld)", pt
.x
, pt
.y
);
1396 void DnDShapeFrame::OnEditShape(wxCommandEvent
& event
)
1398 DnDShapeDialog
dlg(this, m_shape
);
1399 if ( dlg
.ShowModal() == wxID_OK
)
1401 SetShape(dlg
.GetShape());
1405 SetStatusText("You can now drag the shape to another frame");
1410 void DnDShapeFrame::OnNewShape(wxCommandEvent
& event
)
1412 SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED
));
1414 SetStatusText("You can now drag the shape to another frame");
1417 void DnDShapeFrame::OnClearShape(wxCommandEvent
& event
)
1422 void DnDShapeFrame::OnCopyShape(wxCommandEvent
& event
)
1426 wxClipboardLocker clipLocker
;
1429 wxLogError("Can't open the clipboard");
1434 wxTheClipboard
->AddData(new DnDShapeDataObject(m_shape
));
1438 void DnDShapeFrame::OnPasteShape(wxCommandEvent
& event
)
1440 wxClipboardLocker clipLocker
;
1443 wxLogError("Can't open the clipboard");
1448 DnDShapeDataObject
shapeDataObject(NULL
);
1449 if ( wxTheClipboard
->GetData(shapeDataObject
) )
1451 SetShape(shapeDataObject
.GetShape());
1455 wxLogStatus("No shape on the clipboard");
1459 void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent
& event
)
1461 event
.Enable( m_shape
!= NULL
);
1464 void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent
& event
)
1466 event
.Enable( wxTheClipboard
->IsSupported(wxDataFormat(shapeFormatId
)) );
1469 void DnDShapeFrame::OnPaint(wxPaintEvent
& event
)
1483 // ----------------------------------------------------------------------------
1485 // ----------------------------------------------------------------------------
1487 DnDShape
*DnDShape::New(const void *buf
)
1489 const ShapeDump
& dump
= *(const ShapeDump
*)buf
;
1493 return new DnDTriangularShape(wxPoint(dump
.x
, dump
.y
),
1494 wxSize(dump
.w
, dump
.h
),
1495 wxColour(dump
.r
, dump
.g
, dump
.b
));
1498 return new DnDRectangularShape(wxPoint(dump
.x
, dump
.y
),
1499 wxSize(dump
.w
, dump
.h
),
1500 wxColour(dump
.r
, dump
.g
, dump
.b
));
1503 return new DnDEllipticShape(wxPoint(dump
.x
, dump
.y
),
1504 wxSize(dump
.w
, dump
.h
),
1505 wxColour(dump
.r
, dump
.g
, dump
.b
));
1508 wxFAIL_MSG("invalid shape!");
1513 // ----------------------------------------------------------------------------
1514 // DnDShapeDataObject
1515 // ----------------------------------------------------------------------------
1517 void DnDShapeDataObject::CreateBitmap() const
1519 wxPoint pos
= m_shape
->GetPosition();
1520 wxSize size
= m_shape
->GetSize();
1521 int x
= pos
.x
+ size
.x
,
1523 wxBitmap
bitmap(x
, y
);
1525 dc
.SelectObject(bitmap
);
1526 dc
.SetBrush(wxBrush("white", wxSOLID
));
1529 dc
.SelectObject(wxNullBitmap
);
1531 DnDShapeDataObject
*self
= (DnDShapeDataObject
*)this; // const_cast
1532 self
->m_dataobj
.SetBitmap(bitmap
);
1533 self
->m_hasBitmap
= TRUE
;