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,
875 wxCURSOR_PENCIL
, // for copy
876 wxCURSOR_SPRAYCAN
, // for move
877 wxCURSOR_QUESTION_ARROW
); // for nothing
881 switch ( source
.DoDragDrop(TRUE
) )
883 case wxDragError
: pc
= "Error!"; break;
884 case wxDragNone
: pc
= "Nothing"; break;
885 case wxDragCopy
: pc
= "Copied"; break;
886 case wxDragMove
: pc
= "Moved"; break;
887 case wxDragCancel
: pc
= "Cancelled"; break;
888 default: pc
= "Huh?"; break;
891 SetStatusText(wxString("Drag result: ") + pc
);
895 void DnDFrame::OnRightDown(wxMouseEvent
&event
)
897 wxMenu
*menu
= new wxMenu
;
899 menu
->Append(Menu_Drag
, "&Test drag...");
900 menu
->Append(Menu_About
, "&About");
901 menu
->Append(Menu_Quit
, "E&xit");
902 menu
->Append(Menu_ToBeDeleted
, "To be deleted");
903 menu
->Append(Menu_ToBeGreyed
, "To be greyed");
905 menu
->Delete( Menu_ToBeDeleted
);
906 menu
->Enable( Menu_ToBeGreyed
, FALSE
);
908 PopupMenu( menu
, event
.GetX(), event
.GetY() );
911 DnDFrame::~DnDFrame()
913 if ( m_pLog
!= NULL
) {
914 if ( wxLog::SetActiveTarget(m_pLogPrev
) == m_pLog
)
919 // ---------------------------------------------------------------------------
921 // ---------------------------------------------------------------------------
923 void DnDFrame::OnCopyBitmap(wxCommandEvent
& WXUNUSED(event
))
925 // PNG support is not always compiled in under Windows, so use BMP there
927 wxFileDialog
dialog(this, "Open a BMP file", "", "", "BMP files (*.bmp)|*.bmp", 0);
929 wxFileDialog
dialog(this, "Open a PNG file", "", "", "PNG files (*.png)|*.png", 0);
932 if (dialog
.ShowModal() != wxID_OK
)
934 wxLogMessage( _T("Aborted file open") );
938 if (dialog
.GetPath().IsEmpty())
940 wxLogMessage( _T("Returned empty string.") );
944 if (!wxFileExists(dialog
.GetPath()))
946 wxLogMessage( _T("File doesn't exist.") );
951 image
.LoadFile( dialog
.GetPath(),
960 wxLogError( _T("Invalid image file...") );
964 wxLogStatus( _T("Decoding image file...") );
967 wxBitmap
bitmap( image
.ConvertToBitmap() );
969 if ( !wxTheClipboard
->Open() )
971 wxLogError(_T("Can't open clipboard."));
976 wxLogMessage( _T("Creating wxBitmapDataObject...") );
979 if ( !wxTheClipboard
->AddData(new wxBitmapDataObject(bitmap
)) )
981 wxLogError(_T("Can't copy image to the clipboard."));
985 wxLogMessage(_T("Image has been put on the clipboard.") );
986 wxLogMessage(_T("You can paste it now and look at it.") );
989 wxTheClipboard
->Close();
992 void DnDFrame::OnPasteBitmap(wxCommandEvent
& WXUNUSED(event
))
994 if ( !wxTheClipboard
->Open() )
996 wxLogError(_T("Can't open clipboard."));
1001 if ( !wxTheClipboard
->IsSupported(wxDF_BITMAP
) )
1003 wxLogWarning(_T("No bitmap on clipboard"));
1005 wxTheClipboard
->Close();
1009 wxBitmapDataObject data
;
1010 if ( !wxTheClipboard
->GetData(data
) )
1012 wxLogError(_T("Can't paste bitmap from the clipboard"));
1016 wxLogMessage(_T("Bitmap pasted from the clipboard") );
1017 m_bitmap
= data
.GetBitmap();
1021 wxTheClipboard
->Close();
1024 // ---------------------------------------------------------------------------
1026 // ---------------------------------------------------------------------------
1028 void DnDFrame::OnCopy(wxCommandEvent
& WXUNUSED(event
))
1030 if ( !wxTheClipboard
->Open() )
1032 wxLogError(_T("Can't open clipboard."));
1037 if ( !wxTheClipboard
->AddData(new wxTextDataObject(m_strText
)) )
1039 wxLogError(_T("Can't copy data to the clipboard"));
1043 wxLogMessage(_T("Text '%s' put on the clipboard"), m_strText
.c_str());
1046 wxTheClipboard
->Close();
1049 void DnDFrame::OnPaste(wxCommandEvent
& WXUNUSED(event
))
1051 if ( !wxTheClipboard
->Open() )
1053 wxLogError(_T("Can't open clipboard."));
1058 if ( !wxTheClipboard
->IsSupported(wxDF_TEXT
) )
1060 wxLogWarning(_T("No text data on clipboard"));
1062 wxTheClipboard
->Close();
1066 wxTextDataObject text
;
1067 if ( !wxTheClipboard
->GetData(text
) )
1069 wxLogError(_T("Can't paste data from the clipboard"));
1073 wxLogMessage(_T("Text '%s' pasted from the clipboard"),
1074 text
.GetText().c_str());
1077 wxTheClipboard
->Close();
1080 // ----------------------------------------------------------------------------
1081 // Notifications called by the base class
1082 // ----------------------------------------------------------------------------
1084 bool DnDText::OnDropText(wxCoord
, wxCoord
, const wxString
& text
)
1086 m_pOwner
->Append(text
);
1091 bool DnDFile::OnDropFiles(wxCoord
, wxCoord
, const wxArrayString
& filenames
)
1093 size_t nFiles
= filenames
.GetCount();
1095 str
.Printf( _T("%d files dropped"), nFiles
);
1096 m_pOwner
->Append(str
);
1097 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
1098 m_pOwner
->Append(filenames
[n
]);
1104 // ----------------------------------------------------------------------------
1106 // ----------------------------------------------------------------------------
1108 DnDShapeDialog::DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
)
1112 LoadFromResource(parent
, "dialogShape");
1114 m_textX
= (wxTextCtrl
*)wxFindWindowByName("textX", this);
1115 m_textY
= (wxTextCtrl
*)wxFindWindowByName("textY", this);
1116 m_textW
= (wxTextCtrl
*)wxFindWindowByName("textW", this);
1117 m_textH
= (wxTextCtrl
*)wxFindWindowByName("textH", this);
1119 m_radio
= (wxRadioBox
*)wxFindWindowByName("radio", this);
1122 DnDShape
*DnDShapeDialog::GetShape() const
1124 switch ( m_shapeKind
)
1127 case DnDShape::None
: return NULL
;
1128 case DnDShape::Triangle
: return new DnDTriangularShape(m_pos
, m_size
, m_col
);
1129 case DnDShape::Rectangle
: return new DnDRectangularShape(m_pos
, m_size
, m_col
);
1130 case DnDShape::Ellipse
: return new DnDEllipticShape(m_pos
, m_size
, m_col
);
1134 bool DnDShapeDialog::TransferDataToWindow()
1139 m_radio
->SetSelection(m_shape
->GetKind());
1140 m_pos
= m_shape
->GetPosition();
1141 m_size
= m_shape
->GetSize();
1142 m_col
= m_shape
->GetColour();
1146 m_radio
->SetSelection(DnDShape::None
);
1147 m_pos
= wxPoint(1, 1);
1148 m_size
= wxSize(100, 100);
1151 m_textX
->SetValue(wxString() << m_pos
.x
);
1152 m_textY
->SetValue(wxString() << m_pos
.y
);
1153 m_textW
->SetValue(wxString() << m_size
.x
);
1154 m_textH
->SetValue(wxString() << m_size
.y
);
1159 bool DnDShapeDialog::TransferDataFromWindow()
1161 m_shapeKind
= (DnDShape::Kind
)m_radio
->GetSelection();
1163 m_pos
.x
= atoi(m_textX
->GetValue());
1164 m_pos
.y
= atoi(m_textY
->GetValue());
1165 m_size
.x
= atoi(m_textW
->GetValue());
1166 m_size
.y
= atoi(m_textH
->GetValue());
1168 if ( !m_pos
.x
|| !m_pos
.y
|| !m_size
.x
|| !m_size
.y
)
1170 wxMessageBox("All sizes and positions should be non null!",
1171 "Invalid shape", wxICON_HAND
| wxOK
, this);
1179 void DnDShapeDialog::OnColour(wxCommandEvent
& WXUNUSED(event
))
1182 data
.SetChooseFull(TRUE
);
1183 for (int i
= 0; i
< 16; i
++)
1185 wxColour
colour(i
*16, i
*16, i
*16);
1186 data
.SetCustomColour(i
, colour
);
1189 wxColourDialog
dialog(this, &data
);
1190 if ( dialog
.ShowModal() == wxID_OK
)
1192 m_col
= dialog
.GetColourData().GetColour();
1196 // ----------------------------------------------------------------------------
1198 // ----------------------------------------------------------------------------
1200 DnDShapeFrame
*DnDShapeFrame::ms_lastDropTarget
= NULL
;
1202 DnDShapeFrame::DnDShapeFrame(wxFrame
*parent
)
1203 : wxFrame(parent
, -1, "Shape Frame",
1204 wxDefaultPosition
, wxSize(250, 150))
1208 wxMenu
*menuShape
= new wxMenu
;
1209 menuShape
->Append(Menu_Shape_New
, "&New default shape\tCtrl-S");
1210 menuShape
->Append(Menu_Shape_Edit
, "&Edit shape\tCtrl-E");
1211 menuShape
->AppendSeparator();
1212 menuShape
->Append(Menu_Shape_Clear
, "&Clear shape\tDel");
1214 wxMenu
*menuClipboard
= new wxMenu
;
1215 menuClipboard
->Append(Menu_ShapeClipboard_Copy
, "&Copy\tCtrl-C");
1216 menuClipboard
->Append(Menu_ShapeClipboard_Paste
, "&Paste\tCtrl-V");
1218 wxMenuBar
*menubar
= new wxMenuBar
;
1219 menubar
->Append(menuShape
, "&Shape");
1220 menubar
->Append(menuClipboard
, "&Clipboard");
1222 SetMenuBar(menubar
);
1224 SetStatusText("Press Ctrl-S to create a new shape");
1226 SetDropTarget(new DnDShapeDropTarget(this));
1230 SetBackgroundColour(*wxWHITE
);
1233 DnDShapeFrame::~DnDShapeFrame()
1239 void DnDShapeFrame::SetShape(DnDShape
*shape
)
1248 void DnDShapeFrame::OnDrag(wxMouseEvent
& event
)
1257 // start drag operation
1258 DnDShapeDataObject
shapeData(m_shape
);
1259 wxDropSource
source(shapeData
, this);
1261 const char *pc
= NULL
;
1262 switch ( source
.DoDragDrop(TRUE
) )
1266 wxLogError("An error occured during drag and drop operation");
1270 SetStatusText("Nothing happened");
1279 if ( ms_lastDropTarget
!= this )
1281 // don't delete the shape if we dropped it on ourselves!
1287 SetStatusText("Drag and drop operation cancelled");
1293 SetStatusText(wxString("Shape successfully ") + pc
);
1295 //else: status text already set
1298 void DnDShapeFrame::OnDrop(wxCoord x
, wxCoord y
, DnDShape
*shape
)
1300 ms_lastDropTarget
= this;
1305 s
.Printf("Shape dropped at (%ld, %ld)", pt
.x
, pt
.y
);
1312 void DnDShapeFrame::OnEditShape(wxCommandEvent
& event
)
1314 DnDShapeDialog
dlg(this, m_shape
);
1315 if ( dlg
.ShowModal() == wxID_OK
)
1317 SetShape(dlg
.GetShape());
1321 SetStatusText("You can now drag the shape to another frame");
1326 void DnDShapeFrame::OnNewShape(wxCommandEvent
& event
)
1328 SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED
));
1330 SetStatusText("You can now drag the shape to another frame");
1333 void DnDShapeFrame::OnClearShape(wxCommandEvent
& event
)
1338 void DnDShapeFrame::OnCopyShape(wxCommandEvent
& event
)
1342 wxClipboardLocker clipLocker
;
1345 wxLogError("Can't open the clipboard");
1350 wxTheClipboard
->AddData(new DnDShapeDataObject(m_shape
));
1354 void DnDShapeFrame::OnPasteShape(wxCommandEvent
& event
)
1356 wxClipboardLocker clipLocker
;
1359 wxLogError("Can't open the clipboard");
1364 DnDShapeDataObject
shapeDataObject(NULL
);
1365 if ( wxTheClipboard
->GetData(shapeDataObject
) )
1367 SetShape(shapeDataObject
.GetShape());
1371 wxLogStatus("No shape on the clipboard");
1375 void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent
& event
)
1377 event
.Enable( m_shape
!= NULL
);
1380 void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent
& event
)
1382 event
.Enable( wxTheClipboard
->IsSupported(wxDataFormat(shapeFormatId
)) );
1385 void DnDShapeFrame::OnPaint(wxPaintEvent
& event
)
1399 // ----------------------------------------------------------------------------
1401 // ----------------------------------------------------------------------------
1403 DnDShape
*DnDShape::New(const void *buf
)
1405 const ShapeDump
& dump
= *(const ShapeDump
*)buf
;
1409 return new DnDTriangularShape(wxPoint(dump
.x
, dump
.y
),
1410 wxSize(dump
.w
, dump
.h
),
1411 wxColour(dump
.r
, dump
.g
, dump
.b
));
1414 return new DnDRectangularShape(wxPoint(dump
.x
, dump
.y
),
1415 wxSize(dump
.w
, dump
.h
),
1416 wxColour(dump
.r
, dump
.g
, dump
.b
));
1419 return new DnDEllipticShape(wxPoint(dump
.x
, dump
.y
),
1420 wxSize(dump
.w
, dump
.h
),
1421 wxColour(dump
.r
, dump
.g
, dump
.b
));
1424 wxFAIL_MSG("invalid shape!");
1429 // ----------------------------------------------------------------------------
1430 // DnDShapeDataObject
1431 // ----------------------------------------------------------------------------
1433 void DnDShapeDataObject::CreateBitmap() const
1435 wxPoint pos
= m_shape
->GetPosition();
1436 wxSize size
= m_shape
->GetSize();
1437 int x
= pos
.x
+ size
.x
,
1439 wxBitmap
bitmap(x
, y
);
1441 dc
.SelectObject(bitmap
);
1442 dc
.SetBrush(wxBrush("white", wxSOLID
));
1445 dc
.SelectObject(wxNullBitmap
);
1447 DnDShapeDataObject
*self
= (DnDShapeDataObject
*)this; // const_cast
1448 self
->m_dataobj
.SetBitmap(bitmap
);
1449 self
->m_hasBitmap
= TRUE
;