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
);
98 void OnCopy(wxCommandEvent
& event
);
99 void OnPaste(wxCommandEvent
& event
);
100 void OnCopyBitmap(wxCommandEvent
& event
);
101 void OnPasteBitmap(wxCommandEvent
& event
);
103 void OnLeftDown(wxMouseEvent
& event
);
104 void OnRightDown(wxMouseEvent
& event
);
106 void OnUpdateUIPasteText(wxUpdateUIEvent
& event
);
107 void OnUpdateUIPasteBitmap(wxUpdateUIEvent
& event
);
109 DECLARE_EVENT_TABLE()
112 wxListBox
*m_ctrlFile
,
114 wxTextCtrl
*m_ctrlLog
;
123 // ----------------------------------------------------------------------------
124 // A shape is an example of application-specific data which may be transported
125 // via drag-and-drop or clipboard: in our case, we have different geometric
126 // shapes, each one with its own colour and position
127 // ----------------------------------------------------------------------------
140 DnDShape(const wxPoint
& pos
,
143 : m_pos(pos
), m_size(size
), m_col(col
)
147 // this is for debugging - lets us see when exactly an object is freed
148 // (this may be later than you think if it's on the clipboard, for example)
149 virtual ~DnDShape() { }
151 // the functions used for drag-and-drop: they dump and restore a shape into
152 // some bitwise-copiable data (might use streams too...)
153 // ------------------------------------------------------------------------
155 // restore from buffer
156 static DnDShape
*New(const void *buf
);
158 virtual size_t GetDataSize() const
160 return sizeof(ShapeDump
);
163 virtual void GetDataHere(void *buf
) const
165 ShapeDump
& dump
= *(ShapeDump
*)buf
;
170 dump
.r
= m_col
.Red();
171 dump
.g
= m_col
.Green();
172 dump
.b
= m_col
.Blue();
177 const wxPoint
& GetPosition() const { return m_pos
; }
178 const wxColour
& GetColour() const { return m_col
; }
179 const wxSize
& GetSize() const { return m_size
; }
181 void Move(const wxPoint
& pos
) { m_pos
= pos
; }
183 // to implement in derived classes
184 virtual Kind
GetKind() const = 0;
186 virtual void Draw(wxDC
& dc
)
188 dc
.SetPen(wxPen(m_col
, 1, wxSOLID
));
192 wxPoint
GetCentre() const
193 { return wxPoint(m_pos
.x
+ m_size
.x
/ 2, m_pos
.y
+ m_size
.y
/ 2); }
197 int x
, y
, // position
208 class DnDTriangularShape
: public DnDShape
211 DnDTriangularShape(const wxPoint
& pos
,
214 : DnDShape(pos
, size
, col
)
216 wxLogMessage("DnDTriangularShape is being created");
219 virtual ~DnDTriangularShape()
221 wxLogMessage("DnDTriangularShape is being deleted");
224 virtual Kind
GetKind() const { return Triangle
; }
225 virtual void Draw(wxDC
& dc
)
229 // well, it's a bit difficult to describe a triangle by position and
230 // size, but we're not doing geometry here, do we? ;-)
232 wxPoint
p2(m_pos
.x
+ m_size
.x
, m_pos
.y
);
233 wxPoint
p3(m_pos
.x
, m_pos
.y
+ m_size
.y
);
240 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
245 class DnDRectangularShape
: public DnDShape
248 DnDRectangularShape(const wxPoint
& pos
,
251 : DnDShape(pos
, size
, col
)
253 wxLogMessage("DnDRectangularShape is being created");
256 virtual ~DnDRectangularShape()
258 wxLogMessage("DnDRectangularShape is being deleted");
261 virtual Kind
GetKind() const { return Rectangle
; }
262 virtual void Draw(wxDC
& dc
)
267 wxPoint
p2(p1
.x
+ m_size
.x
, p1
.y
);
268 wxPoint
p3(p2
.x
, p2
.y
+ m_size
.y
);
269 wxPoint
p4(p1
.x
, p3
.y
);
277 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
282 class DnDEllipticShape
: public DnDShape
285 DnDEllipticShape(const wxPoint
& pos
,
288 : DnDShape(pos
, size
, col
)
290 wxLogMessage("DnDEllipticShape is being created");
293 virtual ~DnDEllipticShape()
295 wxLogMessage("DnDEllipticShape is being deleted");
298 virtual Kind
GetKind() const { return Ellipse
; }
299 virtual void Draw(wxDC
& dc
)
303 dc
.DrawEllipse(m_pos
, m_size
);
306 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
311 // ----------------------------------------------------------------------------
312 // A wxDataObject specialisation for the application-specific data
313 // ----------------------------------------------------------------------------
315 static const char *shapeFormatId
= "wxShape";
317 class DnDShapeDataObject
: public wxDataObject
320 // ctor doesn't copy the pointer, so it shouldn't go away while this object
322 DnDShapeDataObject(DnDShape
*shape
= (DnDShape
*)NULL
)
326 // we need to copy the shape because the one we're handled may be
327 // deleted while it's still on the clipboard (for example) - and we
328 // reuse the serialisation methods here to copy it
329 void *buf
= malloc(shape
->DnDShape
::GetDataSize());
330 shape
->GetDataHere(buf
);
331 m_shape
= DnDShape
::New(buf
);
341 // this string should uniquely identify our format, but is otherwise
343 m_formatShape
.SetId(shapeFormatId
);
345 // we don't draw the shape to a bitmap until it's really needed (i.e.
346 // we're asked to do so)
350 virtual ~DnDShapeDataObject() { delete m_shape
; }
352 // after a call to this function, the shape is owned by the caller and it
353 // is responsible for deleting it!
355 // NB: a better solution would be to make DnDShapes ref counted and this
356 // is what should probably be done in a real life program, otherwise
357 // the ownership problems become too complicated really fast
360 DnDShape
*shape
= m_shape
;
362 m_shape
= (DnDShape
*)NULL
;
368 // implement base class pure virtuals
369 // ----------------------------------
371 virtual wxDataFormat
GetPreferredFormat(Direction
WXUNUSED(dir
)) const
373 return m_formatShape
;
376 virtual size_t GetFormatCount(Direction dir
) const
378 // our custom format is supported by both GetData() and SetData()
382 // but the bitmap format(s) are only supported for output
383 nFormats
+= m_dataobj
.GetFormatCount(dir
);
389 virtual void GetAllFormats(wxDataFormat
*formats
, Direction dir
) const
391 formats
[0] = m_formatShape
;
394 m_dataobj
.GetAllFormats(&formats
[1], dir
);
398 virtual size_t GetDataSize(const wxDataFormat
& format
) const
400 if ( format
== m_formatShape
)
402 return m_shape
->GetDataSize();
409 return m_dataobj
.GetDataSize();
413 virtual bool GetDataHere(const wxDataFormat
& format
, void *pBuf
) const
415 if ( format
== m_formatShape
)
417 m_shape
->GetDataHere(pBuf
);
426 return m_dataobj
.GetDataHere(pBuf
);
430 virtual bool SetData(const wxDataFormat
& format
,
431 size_t len
, const void *buf
)
433 wxCHECK_MSG( format
== m_formatShape
, FALSE
, "unsupported format" );
436 m_shape
= DnDShape
::New(buf
);
438 // the shape has changed
445 // creates a bitmap and assigns it to m_dataobj (also sets m_hasBitmap)
446 void CreateBitmap() const;
448 wxDataFormat m_formatShape
; // our custom format
450 wxBitmapDataObject m_dataobj
; // it handles bitmaps
451 bool m_hasBitmap
; // true if m_dataobj has valid bitmap
453 DnDShape
*m_shape
; // our data
456 // ----------------------------------------------------------------------------
457 // A dialog to edit shape properties
458 // ----------------------------------------------------------------------------
460 class DnDShapeDialog
: public wxDialog
463 DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
);
465 DnDShape
*GetShape() const;
467 virtual bool TransferDataToWindow();
468 virtual bool TransferDataFromWindow();
470 void OnColour(wxCommandEvent
& event
);
477 DnDShape
::Kind m_shapeKind
;
489 DECLARE_EVENT_TABLE()
492 // ----------------------------------------------------------------------------
493 // A frame for the shapes which can be drag-and-dropped between frames
494 // ----------------------------------------------------------------------------
496 class DnDShapeFrame
: public wxFrame
499 DnDShapeFrame(wxFrame
*parent
);
502 void SetShape(DnDShape
*shape
);
505 void OnNewShape(wxCommandEvent
& event
);
506 void OnEditShape(wxCommandEvent
& event
);
507 void OnClearShape(wxCommandEvent
& event
);
509 void OnCopyShape(wxCommandEvent
& event
);
510 void OnPasteShape(wxCommandEvent
& event
);
512 void OnUpdateUICopy(wxUpdateUIEvent
& event
);
513 void OnUpdateUIPaste(wxUpdateUIEvent
& event
);
515 void OnDrag(wxMouseEvent
& event
);
516 void OnPaint(wxPaintEvent
& event
);
517 void OnDrop(wxCoord x
, wxCoord y
, DnDShape
*shape
);
522 static DnDShapeFrame
*ms_lastDropTarget
;
524 DECLARE_EVENT_TABLE()
527 // ----------------------------------------------------------------------------
528 // wxDropTarget derivation for DnDShapes
529 // ----------------------------------------------------------------------------
531 class DnDShapeDropTarget
: public wxDropTarget
534 DnDShapeDropTarget(DnDShapeFrame
*frame
)
535 : wxDropTarget(new DnDShapeDataObject
)
540 // override base class (pure) virtuals
541 virtual void OnEnter()
542 { m_frame
->SetStatusText("Mouse entered the frame"); }
543 virtual void OnLeave()
544 { m_frame
->SetStatusText("Mouse left the frame"); }
545 virtual wxDragResult
OnData(wxCoord x
, wxCoord y
, wxDragResult def
)
549 wxLogError("Failed to get drag and drop data");
554 m_frame
->OnDrop(x
, y
,
555 ((DnDShapeDataObject
*)GetDataObject())->GetShape());
561 DnDShapeFrame
*m_frame
;
564 // ----------------------------------------------------------------------------
565 // IDs for the menu commands
566 // ----------------------------------------------------------------------------
580 Menu_ToBeGreyed
, /* for testing */
581 Menu_ToBeDeleted
, /* for testing */
582 Menu_Shape_New
= 500,
585 Menu_ShapeClipboard_Copy
,
586 Menu_ShapeClipboard_Paste
,
590 BEGIN_EVENT_TABLE(DnDFrame
, wxFrame
)
591 EVT_MENU(Menu_Quit
, DnDFrame
::OnQuit
)
592 EVT_MENU(Menu_About
, DnDFrame
::OnAbout
)
593 EVT_MENU(Menu_Drag
, DnDFrame
::OnDrag
)
594 EVT_MENU(Menu_NewFrame
, DnDFrame
::OnNewFrame
)
595 EVT_MENU(Menu_Help
, DnDFrame
::OnHelp
)
596 EVT_MENU(Menu_Clear
, DnDFrame
::OnLogClear
)
597 EVT_MENU(Menu_Copy
, DnDFrame
::OnCopy
)
598 EVT_MENU(Menu_Paste
, DnDFrame
::OnPaste
)
599 EVT_MENU(Menu_CopyBitmap
, DnDFrame
::OnCopyBitmap
)
600 EVT_MENU(Menu_PasteBitmap
,DnDFrame
::OnPasteBitmap
)
602 EVT_UPDATE_UI(Menu_Paste
, DnDFrame
::OnUpdateUIPasteText
)
603 EVT_UPDATE_UI(Menu_PasteBitmap
, DnDFrame
::OnUpdateUIPasteBitmap
)
605 EVT_LEFT_DOWN( DnDFrame
::OnLeftDown
)
606 EVT_RIGHT_DOWN( DnDFrame
::OnRightDown
)
607 EVT_PAINT( DnDFrame
::OnPaint
)
610 BEGIN_EVENT_TABLE(DnDShapeFrame
, wxFrame
)
611 EVT_MENU(Menu_Shape_New
, DnDShapeFrame
::OnNewShape
)
612 EVT_MENU(Menu_Shape_Edit
, DnDShapeFrame
::OnEditShape
)
613 EVT_MENU(Menu_Shape_Clear
, DnDShapeFrame
::OnClearShape
)
615 EVT_MENU(Menu_ShapeClipboard_Copy
, DnDShapeFrame
::OnCopyShape
)
616 EVT_MENU(Menu_ShapeClipboard_Paste
, DnDShapeFrame
::OnPasteShape
)
618 EVT_UPDATE_UI(Menu_ShapeClipboard_Copy
, DnDShapeFrame
::OnUpdateUICopy
)
619 EVT_UPDATE_UI(Menu_ShapeClipboard_Paste
, DnDShapeFrame
::OnUpdateUIPaste
)
621 EVT_LEFT_DOWN(DnDShapeFrame
::OnDrag
)
623 EVT_PAINT(DnDShapeFrame
::OnPaint
)
626 BEGIN_EVENT_TABLE(DnDShapeDialog
, wxDialog
)
627 EVT_BUTTON(Button_Colour
, DnDShapeDialog
::OnColour
)
630 // ============================================================================
632 // ============================================================================
634 // `Main program' equivalent, creating windows and returning main app frame
635 bool DnDApp
::OnInit()
637 // load our ressources
641 pathList
.Add("./Debug");
642 pathList
.Add("./Release");
645 wxString path
= pathList
.FindValidPath("dnd.wxr");
648 wxLogError("Can't find the resource file dnd.wxr in the current "
649 "directory, aborting.");
654 wxDefaultResourceTable
->ParseResourceFile(path
);
657 wxImage
::AddHandler( new wxPNGHandler
);
660 // create the main frame window
661 DnDFrame
*frame
= new DnDFrame((wxFrame
*) NULL
,
662 "Drag-and-Drop/Clipboard wxWindows Sample",
673 DnDFrame
::DnDFrame(wxFrame
*frame
, char *title
, int x
, int y
, int w
, int h
)
674 : wxFrame(frame
, -1, title
, wxPoint(x
, y
), wxSize(w
, h
)),
675 m_strText("wxWindows drag & drop works :-)")
678 // frame icon and status bar
679 SetIcon(wxICON(mondrian
));
684 wxMenu
*file_menu
= new wxMenu
;
685 file_menu
->Append(Menu_Drag
, "&Test drag...");
686 file_menu
->AppendSeparator();
687 file_menu
->Append(Menu_NewFrame
, "&New frame\tCtrl-N");
688 file_menu
->AppendSeparator();
689 file_menu
->Append(Menu_Quit
, "E&xit");
691 wxMenu
*log_menu
= new wxMenu
;
692 log_menu
->Append(Menu_Clear
, "Clear\tDel");
694 wxMenu
*help_menu
= new wxMenu
;
695 help_menu
->Append(Menu_Help
, "&Help...");
696 help_menu
->AppendSeparator();
697 help_menu
->Append(Menu_About
, "&About");
699 wxMenu
*clip_menu
= new wxMenu
;
700 clip_menu
->Append(Menu_Copy
, "&Copy text\tCtrl+C");
701 clip_menu
->Append(Menu_Paste
, "&Paste text\tCtrl+V");
702 clip_menu
->AppendSeparator();
703 clip_menu
->Append(Menu_CopyBitmap
, "&Copy bitmap\tAlt+C");
704 clip_menu
->Append(Menu_PasteBitmap
, "&Paste bitmap\tAlt+V");
706 wxMenuBar
*menu_bar
= new wxMenuBar
;
707 menu_bar
->Append(file_menu
, "&File");
708 menu_bar
->Append(log_menu
, "&Log");
709 menu_bar
->Append(clip_menu
, "&Clipboard");
710 menu_bar
->Append(help_menu
, "&Help");
712 SetMenuBar(menu_bar
);
714 // make a panel with 3 subwindows
716 wxSize
size(400, 200);
718 wxString
strFile("Drop files here!"), strText("Drop text on me");
720 m_ctrlFile
= new wxListBox(this, -1, pos
, size
, 1, &strFile
,
721 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
722 m_ctrlText
= new wxListBox(this, -1, pos
, size
, 1, &strText
,
723 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
725 m_ctrlLog
= new wxTextCtrl(this, -1, "", pos
, size
,
726 wxTE_MULTILINE
| wxTE_READONLY
|
730 // redirect log messages to the text window and switch on OLE messages
732 wxLog
::AddTraceMask(wxTRACE_OleCalls
);
734 m_pLog
= new wxLogTextCtrl(m_ctrlLog
);
735 m_pLogPrev
= wxLog
::SetActiveTarget(m_pLog
);
737 // associate drop targets with 2 text controls
738 m_ctrlFile
->SetDropTarget(new DnDFile(m_ctrlFile
));
739 m_ctrlText
->SetDropTarget(new DnDText(m_ctrlText
));
741 wxLayoutConstraints
*c
;
744 c
= new wxLayoutConstraints
;
745 c
->left
.SameAs(this, wxLeft
);
746 c
->top
.SameAs(this, wxTop
);
747 c
->right
.PercentOf(this, wxRight
, 50);
748 c
->height
.PercentOf(this, wxHeight
, 30);
749 m_ctrlFile
->SetConstraints(c
);
752 c
= new wxLayoutConstraints
;
753 c
->left
.SameAs (m_ctrlFile
, wxRight
);
754 c
->top
.SameAs (this, wxTop
);
755 c
->right
.SameAs (this, wxRight
);
756 c
->height
.PercentOf(this, wxHeight
, 30);
757 m_ctrlText
->SetConstraints(c
);
759 // Lower text control
760 c
= new wxLayoutConstraints
;
761 c
->left
.SameAs (this, wxLeft
);
762 c
->right
.SameAs (this, wxRight
);
763 c
->height
.PercentOf(this, wxHeight
, 50);
764 c
->top
.SameAs(m_ctrlText
, wxBottom
);
765 m_ctrlLog
->SetConstraints(c
);
770 void DnDFrame
::OnQuit(wxCommandEvent
& WXUNUSED(event
))
775 void DnDFrame
::OnPaint(wxPaintEvent
& WXUNUSED(event
))
779 GetClientSize( &w
, &h
);
782 dc
.SetFont( wxFont( 24, wxDECORATIVE
, wxNORMAL
, wxNORMAL
, FALSE
, "charter" ) );
783 dc
.DrawText( "Drag text from here!", 20, h
-50 );
787 // 4/5 is 80% taken by other windows, 20 is arbitrary margin
788 dc
.DrawBitmap(m_bitmap
,
789 w
- m_bitmap
.GetWidth() - 20,
794 void DnDFrame
::OnUpdateUIPasteText(wxUpdateUIEvent
& event
)
796 event
.Enable( wxTheClipboard
->IsSupported(wxDF_TEXT
) );
799 void DnDFrame
::OnUpdateUIPasteBitmap(wxUpdateUIEvent
& event
)
801 event
.Enable( wxTheClipboard
->IsSupported(wxDF_BITMAP
) );
804 void DnDFrame
::OnNewFrame(wxCommandEvent
& WXUNUSED(event
))
806 (new DnDShapeFrame(this))->Show(TRUE
);
808 wxLogStatus(this, "Double click the new frame to select a shape for it");
811 void DnDFrame
::OnDrag(wxCommandEvent
& WXUNUSED(event
))
813 wxString strText
= wxGetTextFromUser
815 "After you enter text in this dialog, press any mouse\n"
816 "button in the bottom (empty) part of the frame and \n"
817 "drag it anywhere - you will be in fact dragging the\n"
818 "text object containing this text",
819 "Please enter some text", m_strText
, this
825 void DnDFrame
::OnAbout(wxCommandEvent
& WXUNUSED(event
))
827 wxMessageBox("Drag-&-Drop Demo\n"
828 "Please see \"Help|Help...\" for details\n"
829 "Copyright (c) 1998 Vadim Zeitlin",
831 wxICON_INFORMATION
| wxOK
,
835 void DnDFrame
::OnHelp(wxCommandEvent
& /* event */)
837 wxMessageDialog
dialog(this,
838 "This small program demonstrates drag & drop support in wxWindows. The program window\n"
839 "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
840 "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
841 "and the right one accepts text.\n"
843 "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
844 "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
845 "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
846 "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
847 "work with files) and see what changes.\n"
849 "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
850 "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
851 "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
852 "change, don't release the mouse button until it does. You can change the string being\n"
853 "dragged in in \"File|Test drag...\" dialog.\n"
856 "Please send all questions/bug reports/suggestions &c to \n"
857 "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
863 void DnDFrame
::OnLogClear(wxCommandEvent
& /* event */ )
868 void DnDFrame
::OnLeftDown(wxMouseEvent
&WXUNUSED(event
) )
870 if ( !m_strText
.IsEmpty() )
872 // start drag operation
873 wxTextDataObject
textData(m_strText
);
874 wxDropSource
source(textData
, this, wxICON(mondrian
));
878 switch ( source
.DoDragDrop(TRUE
) )
880 case wxDragError
: pc
= "Error!"; break;
881 case wxDragNone
: pc
= "Nothing"; break;
882 case wxDragCopy
: pc
= "Copied"; break;
883 case wxDragMove
: pc
= "Moved"; break;
884 case wxDragCancel
: pc
= "Cancelled"; break;
885 default: pc
= "Huh?"; break;
888 SetStatusText(wxString("Drag result: ") + pc
);
892 void DnDFrame
::OnRightDown(wxMouseEvent
&event
)
894 wxMenu
*menu
= new wxMenu
;
896 menu
->Append(Menu_Drag
, "&Test drag...");
897 menu
->Append(Menu_About
, "&About");
898 menu
->Append(Menu_Quit
, "E&xit");
899 menu
->Append(Menu_ToBeDeleted
, "To be deleted");
900 menu
->Append(Menu_ToBeGreyed
, "To be greyed");
902 menu
->Delete( Menu_ToBeDeleted
);
903 menu
->Enable( Menu_ToBeGreyed
, FALSE
);
905 PopupMenu( menu
, event
.GetX(), event
.GetY() );
908 DnDFrame
::~DnDFrame()
910 if ( m_pLog
!= NULL
) {
911 if ( wxLog
::SetActiveTarget(m_pLogPrev
) == m_pLog
)
916 // ---------------------------------------------------------------------------
918 // ---------------------------------------------------------------------------
920 void DnDFrame
::OnCopyBitmap(wxCommandEvent
& WXUNUSED(event
))
922 // PNG support is not always compiled in under Windows, so use BMP there
924 wxFileDialog
dialog(this, "Open a BMP file", "", "", "BMP files (*.bmp)|*.bmp", 0);
926 wxFileDialog
dialog(this, "Open a PNG file", "", "", "PNG files (*.png)|*.png", 0);
929 if (dialog
.ShowModal() != wxID_OK
)
931 wxLogMessage( _T("Aborted file open") );
935 if (dialog
.GetPath().IsEmpty())
937 wxLogMessage( _T("Returned empty string.") );
941 if (!wxFileExists(dialog
.GetPath()))
943 wxLogMessage( _T("File doesn't exist.") );
948 image
.LoadFile( dialog
.GetPath(),
957 wxLogError( _T("Invalid image file...") );
961 wxLogStatus( _T("Decoding image file...") );
964 wxBitmap
bitmap( image
.ConvertToBitmap() );
966 if ( !wxTheClipboard
->Open() )
968 wxLogError(_T("Can't open clipboard."));
973 wxLogMessage( _T("Creating wxBitmapDataObject...") );
976 if ( !wxTheClipboard
->AddData(new wxBitmapDataObject(bitmap
)) )
978 wxLogError(_T("Can't copy image to the clipboard."));
982 wxLogMessage(_T("Image has been put on the clipboard.") );
983 wxLogMessage(_T("You can paste it now and look at it.") );
986 wxTheClipboard
->Close();
989 void DnDFrame
::OnPasteBitmap(wxCommandEvent
& WXUNUSED(event
))
991 if ( !wxTheClipboard
->Open() )
993 wxLogError(_T("Can't open clipboard."));
998 if ( !wxTheClipboard
->IsSupported(wxDF_BITMAP
) )
1000 wxLogWarning(_T("No bitmap on clipboard"));
1002 wxTheClipboard
->Close();
1006 wxBitmapDataObject data
;
1007 if ( !wxTheClipboard
->GetData(data
) )
1009 wxLogError(_T("Can't paste bitmap from the clipboard"));
1013 wxLogMessage(_T("Bitmap pasted from the clipboard") );
1014 m_bitmap
= data
.GetBitmap();
1018 wxTheClipboard
->Close();
1021 // ---------------------------------------------------------------------------
1023 // ---------------------------------------------------------------------------
1025 void DnDFrame
::OnCopy(wxCommandEvent
& WXUNUSED(event
))
1027 if ( !wxTheClipboard
->Open() )
1029 wxLogError(_T("Can't open clipboard."));
1034 if ( !wxTheClipboard
->AddData(new wxTextDataObject(m_strText
)) )
1036 wxLogError(_T("Can't copy data to the clipboard"));
1040 wxLogMessage(_T("Text '%s' put on the clipboard"), m_strText
.c_str());
1043 wxTheClipboard
->Close();
1046 void DnDFrame
::OnPaste(wxCommandEvent
& WXUNUSED(event
))
1048 if ( !wxTheClipboard
->Open() )
1050 wxLogError(_T("Can't open clipboard."));
1055 if ( !wxTheClipboard
->IsSupported(wxDF_TEXT
) )
1057 wxLogWarning(_T("No text data on clipboard"));
1059 wxTheClipboard
->Close();
1063 wxTextDataObject text
;
1064 if ( !wxTheClipboard
->GetData(text
) )
1066 wxLogError(_T("Can't paste data from the clipboard"));
1070 wxLogMessage(_T("Text '%s' pasted from the clipboard"),
1071 text
.GetText().c_str());
1074 wxTheClipboard
->Close();
1077 // ----------------------------------------------------------------------------
1078 // Notifications called by the base class
1079 // ----------------------------------------------------------------------------
1081 bool DnDText
::OnDropText(wxCoord
, wxCoord
, const wxString
& text
)
1083 m_pOwner
->Append(text
);
1088 bool DnDFile
::OnDropFiles(wxCoord
, wxCoord
, const wxArrayString
& filenames
)
1090 size_t nFiles
= filenames
.GetCount();
1092 str
.Printf( _T("%d files dropped"), nFiles
);
1093 m_pOwner
->Append(str
);
1094 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
1095 m_pOwner
->Append(filenames
[n
]);
1101 // ----------------------------------------------------------------------------
1103 // ----------------------------------------------------------------------------
1105 DnDShapeDialog
::DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
)
1109 LoadFromResource(parent
, "dialogShape");
1111 m_textX
= (wxTextCtrl
*)wxFindWindowByName("textX", this);
1112 m_textY
= (wxTextCtrl
*)wxFindWindowByName("textY", this);
1113 m_textW
= (wxTextCtrl
*)wxFindWindowByName("textW", this);
1114 m_textH
= (wxTextCtrl
*)wxFindWindowByName("textH", this);
1116 m_radio
= (wxRadioBox
*)wxFindWindowByName("radio", this);
1119 DnDShape
*DnDShapeDialog
::GetShape() const
1121 switch ( m_shapeKind
)
1124 case DnDShape
::None
: return NULL
;
1125 case DnDShape
::Triangle
: return new DnDTriangularShape(m_pos
, m_size
, m_col
);
1126 case DnDShape
::Rectangle
: return new DnDRectangularShape(m_pos
, m_size
, m_col
);
1127 case DnDShape
::Ellipse
: return new DnDEllipticShape(m_pos
, m_size
, m_col
);
1131 bool DnDShapeDialog
::TransferDataToWindow()
1136 m_radio
->SetSelection(m_shape
->GetKind());
1137 m_pos
= m_shape
->GetPosition();
1138 m_size
= m_shape
->GetSize();
1139 m_col
= m_shape
->GetColour();
1143 m_radio
->SetSelection(DnDShape
::None
);
1144 m_pos
= wxPoint(1, 1);
1145 m_size
= wxSize(100, 100);
1148 m_textX
->SetValue(wxString() << m_pos
.x
);
1149 m_textY
->SetValue(wxString() << m_pos
.y
);
1150 m_textW
->SetValue(wxString() << m_size
.x
);
1151 m_textH
->SetValue(wxString() << m_size
.y
);
1156 bool DnDShapeDialog
::TransferDataFromWindow()
1158 m_shapeKind
= (DnDShape
::Kind
)m_radio
->GetSelection();
1160 m_pos
.x
= atoi(m_textX
->GetValue());
1161 m_pos
.y
= atoi(m_textY
->GetValue());
1162 m_size
.x
= atoi(m_textW
->GetValue());
1163 m_size
.y
= atoi(m_textH
->GetValue());
1165 if ( !m_pos
.x
|| !m_pos
.y
|| !m_size
.x
|| !m_size
.y
)
1167 wxMessageBox("All sizes and positions should be non null!",
1168 "Invalid shape", wxICON_HAND
| wxOK
, this);
1176 void DnDShapeDialog
::OnColour(wxCommandEvent
& WXUNUSED(event
))
1179 data
.SetChooseFull(TRUE
);
1180 for (int i
= 0; i
< 16; i
++)
1182 wxColour
colour(i
*16, i
*16, i
*16);
1183 data
.SetCustomColour(i
, colour
);
1186 wxColourDialog
dialog(this, &data
);
1187 if ( dialog
.ShowModal() == wxID_OK
)
1189 m_col
= dialog
.GetColourData().GetColour();
1193 // ----------------------------------------------------------------------------
1195 // ----------------------------------------------------------------------------
1197 DnDShapeFrame
*DnDShapeFrame
::ms_lastDropTarget
= NULL
;
1199 DnDShapeFrame
::DnDShapeFrame(wxFrame
*parent
)
1200 : wxFrame(parent
, -1, "Shape Frame",
1201 wxDefaultPosition
, wxSize(250, 150))
1205 wxMenu
*menuShape
= new wxMenu
;
1206 menuShape
->Append(Menu_Shape_New
, "&New default shape\tCtrl-S");
1207 menuShape
->Append(Menu_Shape_Edit
, "&Edit shape\tCtrl-E");
1208 menuShape
->AppendSeparator();
1209 menuShape
->Append(Menu_Shape_Clear
, "&Clear shape\tDel");
1211 wxMenu
*menuClipboard
= new wxMenu
;
1212 menuClipboard
->Append(Menu_ShapeClipboard_Copy
, "&Copy\tCtrl-C");
1213 menuClipboard
->Append(Menu_ShapeClipboard_Paste
, "&Paste\tCtrl-V");
1215 wxMenuBar
*menubar
= new wxMenuBar
;
1216 menubar
->Append(menuShape
, "&Shape");
1217 menubar
->Append(menuClipboard
, "&Clipboard");
1219 SetMenuBar(menubar
);
1221 SetStatusText("Press Ctrl-S to create a new shape");
1223 SetDropTarget(new DnDShapeDropTarget(this));
1227 SetBackgroundColour(*wxWHITE
);
1230 DnDShapeFrame
::~DnDShapeFrame()
1236 void DnDShapeFrame
::SetShape(DnDShape
*shape
)
1245 void DnDShapeFrame
::OnDrag(wxMouseEvent
& event
)
1254 // start drag operation
1255 DnDShapeDataObject
shapeData(m_shape
);
1256 wxDropSource
source(shapeData
, this, wxICON(mondrian
));
1258 const char *pc
= NULL
;
1259 switch ( source
.DoDragDrop(TRUE
) )
1263 wxLogError("An error occured during drag and drop operation");
1267 SetStatusText("Nothing happened");
1276 if ( ms_lastDropTarget
!= this )
1278 // don't delete the shape if we dropped it on ourselves!
1284 SetStatusText("Drag and drop operation cancelled");
1290 SetStatusText(wxString("Shape successfully ") + pc
);
1292 //else: status text already set
1295 void DnDShapeFrame
::OnDrop(wxCoord x
, wxCoord y
, DnDShape
*shape
)
1297 ms_lastDropTarget
= this;
1302 s
.Printf("Shape dropped at (%ld, %ld)", pt
.x
, pt
.y
);
1309 void DnDShapeFrame
::OnEditShape(wxCommandEvent
& event
)
1311 DnDShapeDialog
dlg(this, m_shape
);
1312 if ( dlg
.ShowModal() == wxID_OK
)
1314 SetShape(dlg
.GetShape());
1318 SetStatusText("You can now drag the shape to another frame");
1323 void DnDShapeFrame
::OnNewShape(wxCommandEvent
& event
)
1325 SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED
));
1327 SetStatusText("You can now drag the shape to another frame");
1330 void DnDShapeFrame
::OnClearShape(wxCommandEvent
& event
)
1335 void DnDShapeFrame
::OnCopyShape(wxCommandEvent
& event
)
1339 wxClipboardLocker clipLocker
;
1342 wxLogError("Can't open the clipboard");
1347 wxTheClipboard
->AddData(new DnDShapeDataObject(m_shape
));
1351 void DnDShapeFrame
::OnPasteShape(wxCommandEvent
& event
)
1353 wxClipboardLocker clipLocker
;
1356 wxLogError("Can't open the clipboard");
1361 DnDShapeDataObject
shapeDataObject(NULL
);
1362 if ( wxTheClipboard
->GetData(shapeDataObject
) )
1364 SetShape(shapeDataObject
.GetShape());
1368 wxLogStatus("No shape on the clipboard");
1372 void DnDShapeFrame
::OnUpdateUICopy(wxUpdateUIEvent
& event
)
1374 event
.Enable( m_shape
!= NULL
);
1377 void DnDShapeFrame
::OnUpdateUIPaste(wxUpdateUIEvent
& event
)
1379 event
.Enable( wxTheClipboard
->IsSupported(wxDataFormat(shapeFormatId
)) );
1382 void DnDShapeFrame
::OnPaint(wxPaintEvent
& event
)
1396 // ----------------------------------------------------------------------------
1398 // ----------------------------------------------------------------------------
1400 DnDShape
*DnDShape
::New(const void *buf
)
1402 const ShapeDump
& dump
= *(const ShapeDump
*)buf
;
1406 return new DnDTriangularShape(wxPoint(dump
.x
, dump
.y
),
1407 wxSize(dump
.w
, dump
.h
),
1408 wxColour(dump
.r
, dump
.g
, dump
.b
));
1411 return new DnDRectangularShape(wxPoint(dump
.x
, dump
.y
),
1412 wxSize(dump
.w
, dump
.h
),
1413 wxColour(dump
.r
, dump
.g
, dump
.b
));
1416 return new DnDEllipticShape(wxPoint(dump
.x
, dump
.y
),
1417 wxSize(dump
.w
, dump
.h
),
1418 wxColour(dump
.r
, dump
.g
, dump
.b
));
1421 wxFAIL_MSG("invalid shape!");
1426 // ----------------------------------------------------------------------------
1427 // DnDShapeDataObject
1428 // ----------------------------------------------------------------------------
1430 void DnDShapeDataObject
::CreateBitmap() const
1432 wxPoint pos
= m_shape
->GetPosition();
1433 wxSize size
= m_shape
->GetSize();
1434 int x
= pos
.x
+ size
.x
,
1436 wxBitmap
bitmap(x
, y
);
1438 dc
.SelectObject(bitmap
);
1439 dc
.SetBrush(wxBrush("white", wxSOLID
));
1442 dc
.SelectObject(wxNullBitmap
);
1444 DnDShapeDataObject
*self
= (DnDShapeDataObject
*)this; // const_cast
1445 self
->m_dataobj
.SetBitmap(bitmap
);
1446 self
->m_hasBitmap
= TRUE
;