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 typedef long wxDropPointCoord
;
48 class DnDText
: public wxTextDropTarget
51 DnDText(wxListBox
*pOwner
) { m_pOwner
= pOwner
; }
53 virtual bool OnDropText(wxDropPointCoord x
, wxDropPointCoord y
,
60 class DnDFile
: public wxFileDropTarget
63 DnDFile(wxListBox
*pOwner
) { m_pOwner
= pOwner
; }
65 virtual bool OnDropFiles(wxDropPointCoord x
, wxDropPointCoord y
,
66 size_t nFiles
, const wxChar
* const aszFiles
[] );
72 // ----------------------------------------------------------------------------
73 // Define a new application type
74 // ----------------------------------------------------------------------------
76 class DnDApp
: public wxApp
79 virtual bool OnInit();
82 IMPLEMENT_APP(DnDApp
);
84 // ----------------------------------------------------------------------------
85 // Define a new frame type for the main frame
86 // ----------------------------------------------------------------------------
88 class DnDFrame
: public wxFrame
91 DnDFrame(wxFrame
*frame
, char *title
, int x
, int y
, int w
, int h
);
94 void OnPaint(wxPaintEvent
& event
);
95 void OnQuit (wxCommandEvent
& event
);
96 void OnAbout(wxCommandEvent
& event
);
97 void OnDrag (wxCommandEvent
& event
);
98 void OnNewFrame(wxCommandEvent
& event
);
99 void OnHelp (wxCommandEvent
& event
);
100 void OnLogClear(wxCommandEvent
& event
);
101 void OnCopy(wxCommandEvent
& event
);
102 void OnPaste(wxCommandEvent
& event
);
103 void OnCopyBitmap(wxCommandEvent
& event
);
104 void OnPasteBitmap(wxCommandEvent
& event
);
106 void OnLeftDown(wxMouseEvent
& event
);
107 void OnRightDown(wxMouseEvent
& event
);
109 void OnUpdateUIPasteText(wxUpdateUIEvent
& event
);
110 void OnUpdateUIPasteBitmap(wxUpdateUIEvent
& event
);
112 DECLARE_EVENT_TABLE()
115 wxListBox
*m_ctrlFile
,
117 wxTextCtrl
*m_ctrlLog
;
119 wxLog
*m_pLog
, *m_pLogPrev
;
125 // ----------------------------------------------------------------------------
126 // A shape is an example of application-specific data which may be transported
127 // via drag-and-drop or clipboard: in our case, we have different geometric
128 // shapes, each one with its own colour and position
129 // ----------------------------------------------------------------------------
142 DnDShape(const wxPoint
& pos
,
145 : m_pos(pos
), m_size(size
), m_col(col
)
149 // the functions used for drag-and-drop: they dump and restore a shape into
150 // some bitwise-copiable data (might use streams too...)
151 // ------------------------------------------------------------------------
153 // restore from buffer
154 static DnDShape
*New(const void *buf
);
156 virtual size_t GetDataSize() const
158 return sizeof(ShapeDump
);
161 virtual void GetDataHere(void *buf
) const
163 ShapeDump
& dump
= *(ShapeDump
*)buf
;
168 dump
.r
= m_col
.Red();
169 dump
.g
= m_col
.Green();
170 dump
.b
= m_col
.Blue();
175 const wxPoint
& GetPosition() const { return m_pos
; }
176 const wxColour
& GetColour() const { return m_col
; }
177 const wxSize
& GetSize() const { return m_size
; }
179 void Move(const wxPoint
& pos
) { m_pos
= pos
; }
181 // to implement in derived classes
182 virtual Kind
GetKind() const = 0;
184 virtual void Draw(wxDC
& dc
)
186 dc
.SetPen(wxPen(m_col
, 1, wxSOLID
));
190 wxPoint
GetCentre() const
191 { return wxPoint(m_pos
.x
+ m_size
.x
/ 2, m_pos
.y
+ m_size
.y
/ 2); }
195 int x
, y
, // position
206 class DnDTriangularShape
: public DnDShape
209 DnDTriangularShape(const wxPoint
& pos
,
212 : DnDShape(pos
, size
, col
)
216 virtual Kind
GetKind() const { return Triangle
; }
217 virtual void Draw(wxDC
& dc
)
221 // well, it's a bit difficult to describe a triangle by position and
222 // size, but we're not doing geometry here, do we? ;-)
224 wxPoint
p2(m_pos
.x
+ m_size
.x
, m_pos
.y
);
225 wxPoint
p3(m_pos
.x
, m_pos
.y
+ m_size
.y
);
232 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
237 class DnDRectangularShape
: public DnDShape
240 DnDRectangularShape(const wxPoint
& pos
,
243 : DnDShape(pos
, size
, col
)
247 virtual Kind
GetKind() const { return Rectangle
; }
248 virtual void Draw(wxDC
& dc
)
253 wxPoint
p2(p1
.x
+ m_size
.x
, p1
.y
);
254 wxPoint
p3(p2
.x
, p2
.y
+ m_size
.y
);
255 wxPoint
p4(p1
.x
, p3
.y
);
263 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
268 class DnDEllipticShape
: public DnDShape
271 DnDEllipticShape(const wxPoint
& pos
,
274 : DnDShape(pos
, size
, col
)
278 virtual Kind
GetKind() const { return Ellipse
; }
279 virtual void Draw(wxDC
& dc
)
283 dc
.DrawEllipse(m_pos
, m_size
);
286 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
291 // ----------------------------------------------------------------------------
292 // A wxDataObject specialisation for the application-specific data
293 // ----------------------------------------------------------------------------
295 static const char *shapeFormatId
= "wxShape";
297 class DnDShapeDataObject
: public wxDataObject
300 // ctor doesn't copy the pointer, so it shouldn't go away while this object
302 DnDShapeDataObject(DnDShape
*shape
)
306 // this string should uniquely identify our format, but is otherwise
308 m_formatShape
.SetId(shapeFormatId
);
310 // we don't draw the shape to a bitmap until it's really needed (i.e.
311 // we're asked to do so)
316 DnDShape
*GetShape() const { return m_shape
; }
318 // implement base class pure virtuals
319 // ----------------------------------
321 virtual wxDataFormat
GetPreferredFormat() const
323 return m_formatShape
;
326 virtual size_t GetFormatCount(bool outputOnlyToo
) const
328 // our custom format is supported by both GetData() and SetData()
332 // but the bitmap format(s) are only supported for output
333 nFormats
+= m_dataobj
.GetFormatCount();
339 virtual void GetAllFormats(wxDataFormat
*formats
, bool outputOnlyToo
) const
341 formats
[0] = m_formatShape
;
344 m_dataobj
.GetAllFormats(&formats
[1]);
348 virtual size_t GetDataSize(const wxDataFormat
& format
) const
350 if ( format
== m_formatShape
)
352 return m_shape
->GetDataSize();
359 return m_dataobj
.GetDataSize(format
);
363 virtual bool GetDataHere(const wxDataFormat
& format
, void *pBuf
) const
365 if ( format
== m_formatShape
)
367 m_shape
->GetDataHere(pBuf
);
373 wxASSERT_MSG( format
== wxDF_BITMAP
, "unsupported format" );
378 return m_dataobj
.GetDataHere(format
, pBuf
);
382 virtual bool SetData(const wxDataFormat
& format
, const void *buf
)
384 wxCHECK_MSG( format
== m_formatShape
, FALSE
, "unsupported format" );
387 m_shape
= DnDShape::New(buf
);
389 // the shape has changed
396 // creates a bitmap and assigns it to m_dataobj (also sets m_hasBitmap)
397 void CreateBitmap() const;
399 wxDataFormat m_formatShape
; // our custom format
401 wxBitmapDataObject m_dataobj
; // it handles bitmaps
402 bool m_hasBitmap
; // true if m_dataobj has valid bitmap
404 DnDShape
*m_shape
; // our data
407 // ----------------------------------------------------------------------------
408 // A dialog to edit shape properties
409 // ----------------------------------------------------------------------------
411 class DnDShapeDialog
: public wxDialog
414 DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
);
416 DnDShape
*GetShape() const;
418 virtual bool TransferDataToWindow();
419 virtual bool TransferDataFromWindow();
421 void OnColour(wxCommandEvent
& event
);
428 DnDShape::Kind m_shapeKind
;
440 DECLARE_EVENT_TABLE()
443 // ----------------------------------------------------------------------------
444 // A frame for the shapes which can be drag-and-dropped between frames
445 // ----------------------------------------------------------------------------
447 class DnDShapeFrame
: public wxFrame
450 DnDShapeFrame(wxFrame
*parent
);
453 void SetShape(DnDShape
*shape
);
456 void OnNewShape(wxCommandEvent
& event
);
457 void OnEditShape(wxCommandEvent
& event
);
458 void OnClearShape(wxCommandEvent
& event
);
460 void OnCopyShape(wxCommandEvent
& event
);
461 void OnPasteShape(wxCommandEvent
& event
);
463 void OnUpdateUICopy(wxUpdateUIEvent
& event
);
464 void OnUpdateUIPaste(wxUpdateUIEvent
& event
);
466 void OnDrag(wxMouseEvent
& event
);
467 void OnPaint(wxPaintEvent
& event
);
468 void OnDrop(long x
, long y
, DnDShape
*shape
);
473 static DnDShapeFrame
*ms_lastDropTarget
;
475 DECLARE_EVENT_TABLE()
478 // ----------------------------------------------------------------------------
479 // wxDropTarget derivation for DnDShapes
480 // ----------------------------------------------------------------------------
482 class DnDShapeDropTarget
: public wxDropTarget
485 DnDShapeDropTarget(DnDShapeFrame
*frame
)
489 // the same as used by DnDShapeDataObject
490 m_formatShape
.SetId(shapeFormatId
);
493 // override base class (pure) virtuals
494 virtual void OnEnter()
495 { m_frame
->SetStatusText("Mouse entered the frame"); }
496 virtual void OnLeave()
497 { m_frame
->SetStatusText("Mouse left the frame"); }
498 virtual bool OnDrop(long x
, long y
, const void *pData
)
500 m_frame
->OnDrop(x
, y
, DnDShape::New(pData
));
506 virtual size_t GetFormatCount() const { return 1; }
507 virtual wxDataFormat
GetFormat(size_t WXUNUSED(n
)) const
508 { return m_formatShape
; }
511 DnDShapeFrame
*m_frame
;
512 wxDataFormat m_formatShape
;
515 // ----------------------------------------------------------------------------
516 // IDs for the menu commands
517 // ----------------------------------------------------------------------------
531 Menu_ToBeGreyed
, /* for testing */
532 Menu_ToBeDeleted
, /* for testing */
533 Menu_Shape_New
= 500,
536 Menu_ShapeClipboard_Copy
,
537 Menu_ShapeClipboard_Paste
,
541 BEGIN_EVENT_TABLE(DnDFrame
, wxFrame
)
542 EVT_MENU(Menu_Quit
, DnDFrame::OnQuit
)
543 EVT_MENU(Menu_About
, DnDFrame::OnAbout
)
544 EVT_MENU(Menu_Drag
, DnDFrame::OnDrag
)
545 EVT_MENU(Menu_NewFrame
, DnDFrame::OnNewFrame
)
546 EVT_MENU(Menu_Help
, DnDFrame::OnHelp
)
547 EVT_MENU(Menu_Clear
, DnDFrame::OnLogClear
)
548 EVT_MENU(Menu_Copy
, DnDFrame::OnCopy
)
549 EVT_MENU(Menu_Paste
, DnDFrame::OnPaste
)
550 EVT_MENU(Menu_CopyBitmap
, DnDFrame::OnCopyBitmap
)
551 EVT_MENU(Menu_PasteBitmap
,DnDFrame::OnPasteBitmap
)
553 EVT_UPDATE_UI(Menu_Paste
, DnDFrame::OnUpdateUIPasteText
)
554 EVT_UPDATE_UI(Menu_PasteBitmap
, DnDFrame::OnUpdateUIPasteBitmap
)
556 EVT_LEFT_DOWN( DnDFrame::OnLeftDown
)
557 EVT_RIGHT_DOWN( DnDFrame::OnRightDown
)
558 EVT_PAINT( DnDFrame::OnPaint
)
561 BEGIN_EVENT_TABLE(DnDShapeFrame
, wxFrame
)
562 EVT_MENU(Menu_Shape_New
, DnDShapeFrame::OnNewShape
)
563 EVT_MENU(Menu_Shape_Edit
, DnDShapeFrame::OnEditShape
)
564 EVT_MENU(Menu_Shape_Clear
, DnDShapeFrame::OnClearShape
)
566 EVT_MENU(Menu_ShapeClipboard_Copy
, DnDShapeFrame::OnCopyShape
)
567 EVT_MENU(Menu_ShapeClipboard_Paste
, DnDShapeFrame::OnPasteShape
)
569 EVT_UPDATE_UI(Menu_ShapeClipboard_Copy
, DnDShapeFrame::OnUpdateUICopy
)
570 EVT_UPDATE_UI(Menu_ShapeClipboard_Paste
, DnDShapeFrame::OnUpdateUIPaste
)
572 EVT_LEFT_DOWN(DnDShapeFrame::OnDrag
)
574 EVT_PAINT(DnDShapeFrame::OnPaint
)
577 BEGIN_EVENT_TABLE(DnDShapeDialog
, wxDialog
)
578 EVT_BUTTON(Button_Colour
, OnColour
)
581 // ============================================================================
583 // ============================================================================
585 // `Main program' equivalent, creating windows and returning main app frame
586 bool DnDApp::OnInit()
589 wxImage::AddHandler( new wxPNGHandler
);
592 // create the main frame window
593 DnDFrame
*frame
= new DnDFrame((wxFrame
*) NULL
,
594 "Drag-and-Drop/Clipboard wxWindows Sample",
602 wxDefaultResourceTable
->ParseResourceFile("dnd.wxr");
607 DnDFrame::DnDFrame(wxFrame
*frame
, char *title
, int x
, int y
, int w
, int h
)
608 : wxFrame(frame
, -1, title
, wxPoint(x
, y
), wxSize(w
, h
)),
609 m_strText("wxWindows drag & drop works :-)")
612 // frame icon and status bar
613 SetIcon(wxICON(mondrian
));
618 wxMenu
*file_menu
= new wxMenu
;
619 file_menu
->Append(Menu_Drag
, "&Test drag...");
620 file_menu
->AppendSeparator();
621 file_menu
->Append(Menu_NewFrame
, "&New frame\tCtrl-N");
622 file_menu
->AppendSeparator();
623 file_menu
->Append(Menu_Quit
, "E&xit");
625 wxMenu
*log_menu
= new wxMenu
;
626 log_menu
->Append(Menu_Clear
, "Clear\tDel");
628 wxMenu
*help_menu
= new wxMenu
;
629 help_menu
->Append(Menu_Help
, "&Help...");
630 help_menu
->AppendSeparator();
631 help_menu
->Append(Menu_About
, "&About");
633 wxMenu
*clip_menu
= new wxMenu
;
634 clip_menu
->Append(Menu_Copy
, "&Copy text\tCtrl+C");
635 clip_menu
->Append(Menu_Paste
, "&Paste text\tCtrl+V");
636 clip_menu
->AppendSeparator();
637 clip_menu
->Append(Menu_CopyBitmap
, "&Copy bitmap\tAlt+C");
638 clip_menu
->Append(Menu_PasteBitmap
, "&Paste bitmap\tAlt+V");
640 wxMenuBar
*menu_bar
= new wxMenuBar
;
641 menu_bar
->Append(file_menu
, "&File");
642 menu_bar
->Append(log_menu
, "&Log");
643 menu_bar
->Append(clip_menu
, "&Clipboard");
644 menu_bar
->Append(help_menu
, "&Help");
646 SetMenuBar(menu_bar
);
648 // make a panel with 3 subwindows
650 wxSize
size(400, 200);
652 wxString
strFile("Drop files here!"), strText("Drop text on me");
654 m_ctrlFile
= new wxListBox(this, -1, pos
, size
, 1, &strFile
,
655 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
656 m_ctrlText
= new wxListBox(this, -1, pos
, size
, 1, &strText
,
657 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
659 m_ctrlLog
= new wxTextCtrl(this, -1, "", pos
, size
,
660 wxTE_MULTILINE
| wxTE_READONLY
|
664 // redirect log messages to the text window and switch on OLE messages
666 wxLog::AddTraceMask(wxTRACE_OleCalls
);
668 m_pLog
= new wxLogTextCtrl(m_ctrlLog
);
669 m_pLogPrev
= wxLog::SetActiveTarget(m_pLog
);
671 // associate drop targets with 2 text controls
672 m_ctrlFile
->SetDropTarget(new DnDFile(m_ctrlFile
));
673 m_ctrlText
->SetDropTarget(new DnDText(m_ctrlText
));
675 wxLayoutConstraints
*c
;
678 c
= new wxLayoutConstraints
;
679 c
->left
.SameAs(this, wxLeft
);
680 c
->top
.SameAs(this, wxTop
);
681 c
->right
.PercentOf(this, wxRight
, 50);
682 c
->height
.PercentOf(this, wxHeight
, 30);
683 m_ctrlFile
->SetConstraints(c
);
686 c
= new wxLayoutConstraints
;
687 c
->left
.SameAs (m_ctrlFile
, wxRight
);
688 c
->top
.SameAs (this, wxTop
);
689 c
->right
.SameAs (this, wxRight
);
690 c
->height
.PercentOf(this, wxHeight
, 30);
691 m_ctrlText
->SetConstraints(c
);
693 // Lower text control
694 c
= new wxLayoutConstraints
;
695 c
->left
.SameAs (this, wxLeft
);
696 c
->right
.SameAs (this, wxRight
);
697 c
->height
.PercentOf(this, wxHeight
, 50);
698 c
->top
.SameAs(m_ctrlText
, wxBottom
);
699 m_ctrlLog
->SetConstraints(c
);
704 void DnDFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
))
709 void DnDFrame::OnPaint(wxPaintEvent
& WXUNUSED(event
))
713 GetClientSize( &w
, &h
);
716 dc
.SetFont( wxFont( 24, wxDECORATIVE
, wxNORMAL
, wxNORMAL
, FALSE
, "charter" ) );
717 dc
.DrawText( "Drag text from here!", 20, h
-50 );
721 // 4/5 is 80% taken by other windows, 20 is arbitrary margin
722 dc
.DrawBitmap(m_bitmap
,
723 w
- m_bitmap
.GetWidth() - 20,
728 void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent
& event
)
730 event
.Enable( wxTheClipboard
->IsSupported(wxDF_TEXT
) );
733 void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent
& event
)
735 event
.Enable( wxTheClipboard
->IsSupported(wxDF_BITMAP
) );
738 void DnDFrame::OnNewFrame(wxCommandEvent
& WXUNUSED(event
))
740 (new DnDShapeFrame(this))->Show(TRUE
);
742 wxLogStatus(this, "Double click the new frame to select a shape for it");
745 void DnDFrame::OnDrag(wxCommandEvent
& WXUNUSED(event
))
747 wxString strText
= wxGetTextFromUser
749 "After you enter text in this dialog, press any mouse\n"
750 "button in the bottom (empty) part of the frame and \n"
751 "drag it anywhere - you will be in fact dragging the\n"
752 "text object containing this text",
753 "Please enter some text", m_strText
, this
759 void DnDFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
761 wxMessageBox("Drag-&-Drop Demo\n"
762 "Please see \"Help|Help...\" for details\n"
763 "Copyright (c) 1998 Vadim Zeitlin",
765 wxICON_INFORMATION
| wxOK
,
769 void DnDFrame::OnHelp(wxCommandEvent
& /* event */)
771 wxMessageDialog
dialog(this,
772 "This small program demonstrates drag & drop support in wxWindows. The program window\n"
773 "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
774 "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
775 "and the right one accepts text.\n"
777 "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
778 "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
779 "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
780 "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
781 "work with files) and see what changes.\n"
783 "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
784 "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
785 "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
786 "change, don't release the mouse button until it does. You can change the string being\n"
787 "dragged in in \"File|Test drag...\" dialog.\n"
790 "Please send all questions/bug reports/suggestions &c to \n"
791 "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
797 void DnDFrame::OnLogClear(wxCommandEvent
& /* event */ )
802 void DnDFrame::OnLeftDown(wxMouseEvent
&WXUNUSED(event
) )
804 if ( !m_strText
.IsEmpty() )
806 // start drag operation
807 wxTextDataObject
textData(m_strText
);
808 wxDropSource
source(textData
, this, wxICON(mondrian
));
812 switch ( source
.DoDragDrop(TRUE
) )
814 case wxDragError
: pc
= "Error!"; break;
815 case wxDragNone
: pc
= "Nothing"; break;
816 case wxDragCopy
: pc
= "Copied"; break;
817 case wxDragMove
: pc
= "Moved"; break;
818 case wxDragCancel
: pc
= "Cancelled"; break;
819 default: pc
= "Huh?"; break;
822 SetStatusText(wxString("Drag result: ") + pc
);
826 void DnDFrame::OnRightDown(wxMouseEvent
&event
)
828 wxMenu
*menu
= new wxMenu
;
830 menu
->Append(Menu_Drag
, "&Test drag...");
831 menu
->Append(Menu_About
, "&About");
832 menu
->Append(Menu_Quit
, "E&xit");
833 menu
->Append(Menu_ToBeDeleted
, "To be deleted");
834 menu
->Append(Menu_ToBeGreyed
, "To be greyed");
836 menu
->Delete( Menu_ToBeDeleted
);
837 menu
->Enable( Menu_ToBeGreyed
, FALSE
);
839 PopupMenu( menu
, event
.GetX(), event
.GetY() );
842 DnDFrame::~DnDFrame()
844 if ( m_pLog
!= NULL
) {
845 if ( wxLog::SetActiveTarget(m_pLogPrev
) == m_pLog
)
850 // ---------------------------------------------------------------------------
852 // ---------------------------------------------------------------------------
854 void DnDFrame::OnCopyBitmap(wxCommandEvent
& WXUNUSED(event
))
856 // PNG support is not always compiled in under Windows, so use BMP there
858 wxFileDialog
dialog(this, "Open a BMP file", "", "", "BMP files (*.bmp)|*.bmp", 0);
860 wxFileDialog
dialog(this, "Open a PNG file", "", "", "PNG files (*.png)|*.png", 0);
863 if (dialog
.ShowModal() != wxID_OK
)
865 wxLogMessage( _T("Aborted file open") );
869 if (dialog
.GetPath().IsEmpty())
871 wxLogMessage( _T("Returned empty string.") );
875 if (!wxFileExists(dialog
.GetPath()))
877 wxLogMessage( _T("File doesn't exist.") );
882 image
.LoadFile( dialog
.GetPath(),
891 wxLogError( _T("Invalid image file...") );
895 wxLogStatus( _T("Decoding image file...") );
898 wxBitmap
bitmap( image
.ConvertToBitmap() );
900 if ( !wxTheClipboard
->Open() )
902 wxLogError(_T("Can't open clipboard."));
907 wxLogMessage( _T("Creating wxBitmapDataObject...") );
910 if ( !wxTheClipboard
->AddData(new wxBitmapDataObject(bitmap
)) )
912 wxLogError(_T("Can't copy image to the clipboard."));
916 wxLogMessage(_T("Image has been put on the clipboard.") );
917 wxLogMessage(_T("You can paste it now and look at it.") );
920 wxTheClipboard
->Close();
923 void DnDFrame::OnPasteBitmap(wxCommandEvent
& WXUNUSED(event
))
925 if ( !wxTheClipboard
->Open() )
927 wxLogError(_T("Can't open clipboard."));
932 if ( !wxTheClipboard
->IsSupported(wxDF_BITMAP
) )
934 wxLogWarning(_T("No bitmap on clipboard"));
936 wxTheClipboard
->Close();
940 wxBitmapDataObject data
;
941 if ( !wxTheClipboard
->GetData(&data
) )
943 wxLogError(_T("Can't paste bitmap from the clipboard"));
947 wxLogMessage(_T("Bitmap pasted from the clipboard") );
948 m_bitmap
= data
.GetBitmap();
952 wxTheClipboard
->Close();
955 // ---------------------------------------------------------------------------
957 // ---------------------------------------------------------------------------
959 void DnDFrame::OnCopy(wxCommandEvent
& WXUNUSED(event
))
961 if ( !wxTheClipboard
->Open() )
963 wxLogError(_T("Can't open clipboard."));
968 if ( !wxTheClipboard
->AddData(new wxTextDataObject(m_strText
)) )
970 wxLogError(_T("Can't copy data to the clipboard"));
974 wxLogMessage(_T("Text '%s' put on the clipboard"), m_strText
.c_str());
977 wxTheClipboard
->Close();
980 void DnDFrame::OnPaste(wxCommandEvent
& WXUNUSED(event
))
982 if ( !wxTheClipboard
->Open() )
984 wxLogError(_T("Can't open clipboard."));
989 if ( !wxTheClipboard
->IsSupported(wxDF_TEXT
) )
991 wxLogWarning(_T("No text data on clipboard"));
993 wxTheClipboard
->Close();
997 wxTextDataObject text
;
998 if ( !wxTheClipboard
->GetData(&text
) )
1000 wxLogError(_T("Can't paste data from the clipboard"));
1004 wxLogMessage(_T("Text '%s' pasted from the clipboard"),
1005 text
.GetText().c_str());
1008 wxTheClipboard
->Close();
1011 // ----------------------------------------------------------------------------
1012 // Notifications called by the base class
1013 // ----------------------------------------------------------------------------
1015 bool DnDText::OnDropText( wxDropPointCoord
, wxDropPointCoord
, const wxChar
*psz
)
1017 m_pOwner
->Append(psz
);
1022 bool DnDFile::OnDropFiles( wxDropPointCoord
, wxDropPointCoord
, size_t nFiles
,
1023 const wxChar
* const aszFiles
[])
1026 str
.Printf( _T("%d files dropped"), nFiles
);
1027 m_pOwner
->Append(str
);
1028 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
1029 m_pOwner
->Append(aszFiles
[n
]);
1035 // ----------------------------------------------------------------------------
1037 // ----------------------------------------------------------------------------
1039 DnDShapeDialog::DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
)
1043 LoadFromResource(parent
, "dialogShape");
1045 m_textX
= (wxTextCtrl
*)wxFindWindowByName("textX", this);
1046 m_textY
= (wxTextCtrl
*)wxFindWindowByName("textY", this);
1047 m_textW
= (wxTextCtrl
*)wxFindWindowByName("textW", this);
1048 m_textH
= (wxTextCtrl
*)wxFindWindowByName("textH", this);
1050 m_radio
= (wxRadioBox
*)wxFindWindowByName("radio", this);
1053 DnDShape
*DnDShapeDialog::GetShape() const
1055 switch ( m_shapeKind
)
1058 case DnDShape::None
: return NULL
;
1059 case DnDShape::Triangle
: return new DnDTriangularShape(m_pos
, m_size
, m_col
);
1060 case DnDShape::Rectangle
: return new DnDRectangularShape(m_pos
, m_size
, m_col
);
1061 case DnDShape::Ellipse
: return new DnDEllipticShape(m_pos
, m_size
, m_col
);
1065 bool DnDShapeDialog::TransferDataToWindow()
1070 m_radio
->SetSelection(m_shape
->GetKind());
1071 m_pos
= m_shape
->GetPosition();
1072 m_size
= m_shape
->GetSize();
1073 m_col
= m_shape
->GetColour();
1077 m_radio
->SetSelection(DnDShape::None
);
1078 m_pos
= wxPoint(1, 1);
1079 m_size
= wxSize(100, 100);
1082 m_textX
->SetValue(wxString() << m_pos
.x
);
1083 m_textY
->SetValue(wxString() << m_pos
.y
);
1084 m_textW
->SetValue(wxString() << m_size
.x
);
1085 m_textH
->SetValue(wxString() << m_size
.y
);
1090 bool DnDShapeDialog::TransferDataFromWindow()
1092 m_shapeKind
= (DnDShape::Kind
)m_radio
->GetSelection();
1094 m_pos
.x
= atoi(m_textX
->GetValue());
1095 m_pos
.y
= atoi(m_textY
->GetValue());
1096 m_size
.x
= atoi(m_textW
->GetValue());
1097 m_size
.y
= atoi(m_textH
->GetValue());
1099 if ( !m_pos
.x
|| !m_pos
.y
|| !m_size
.x
|| !m_size
.y
)
1101 wxMessageBox("All sizes and positions should be non null!",
1102 "Invalid shape", wxICON_HAND
| wxOK
, this);
1110 void DnDShapeDialog::OnColour(wxCommandEvent
& WXUNUSED(event
))
1113 data
.SetChooseFull(TRUE
);
1114 for (int i
= 0; i
< 16; i
++)
1116 wxColour
colour(i
*16, i
*16, i
*16);
1117 data
.SetCustomColour(i
, colour
);
1120 wxColourDialog
dialog(this, &data
);
1121 if ( dialog
.ShowModal() == wxID_OK
)
1123 m_col
= dialog
.GetColourData().GetColour();
1127 // ----------------------------------------------------------------------------
1129 // ----------------------------------------------------------------------------
1131 DnDShapeFrame
*DnDShapeFrame::ms_lastDropTarget
= NULL
;
1133 DnDShapeFrame::DnDShapeFrame(wxFrame
*parent
)
1134 : wxFrame(parent
, -1, "Shape Frame",
1135 wxDefaultPosition
, wxSize(250, 150))
1137 SetBackgroundColour(*wxWHITE
);
1141 wxMenu
*menuShape
= new wxMenu
;
1142 menuShape
->Append(Menu_Shape_New
, "&New default shape\tCtrl-S");
1143 menuShape
->Append(Menu_Shape_Edit
, "&Edit shape\tCtrl-E");
1144 menuShape
->AppendSeparator();
1145 menuShape
->Append(Menu_Shape_Clear
, "&Clear shape\tDel");
1147 wxMenu
*menuClipboard
= new wxMenu
;
1148 menuClipboard
->Append(Menu_ShapeClipboard_Copy
, "&Copy\tCtrl-C");
1149 menuClipboard
->Append(Menu_ShapeClipboard_Paste
, "&Paste\tCtrl-V");
1151 wxMenuBar
*menubar
= new wxMenuBar
;
1152 menubar
->Append(menuShape
, "&Shape");
1153 menubar
->Append(menuClipboard
, "&Clipboard");
1155 SetMenuBar(menubar
);
1157 SetStatusText("Press Ctrl-S to create a new shape");
1159 SetDropTarget(new DnDShapeDropTarget(this));
1164 DnDShapeFrame::~DnDShapeFrame()
1169 void DnDShapeFrame::SetShape(DnDShape
*shape
)
1177 void DnDShapeFrame::OnDrag(wxMouseEvent
& event
)
1186 // start drag operation
1187 DnDShapeDataObject
shapeData(m_shape
);
1188 wxDropSource
source(shapeData
, this, wxICON(mondrian
));
1190 const char *pc
= NULL
;
1191 switch ( source
.DoDragDrop(TRUE
) )
1195 wxLogError("An error occured during drag and drop operation");
1199 SetStatusText("Nothing happened");
1208 if ( ms_lastDropTarget
!= this )
1210 // don't delete the shape if we dropped it on ourselves!
1216 SetStatusText("Drag and drop operation cancelled");
1222 SetStatusText(wxString("Shape successfully ") + pc
);
1224 //else: status text already set
1227 void DnDShapeFrame::OnEditShape(wxCommandEvent
& event
)
1229 DnDShapeDialog
dlg(this, m_shape
);
1230 if ( dlg
.ShowModal() == wxID_OK
)
1232 SetShape(dlg
.GetShape());
1236 SetStatusText("You can now drag the shape to another frame");
1241 void DnDShapeFrame::OnNewShape(wxCommandEvent
& event
)
1243 SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED
));
1245 SetStatusText("You can now drag the shape to another frame");
1248 void DnDShapeFrame::OnClearShape(wxCommandEvent
& event
)
1253 void DnDShapeFrame::OnCopyShape(wxCommandEvent
& event
)
1256 wxTheClipboard
->AddData(new DnDShapeDataObject(m_shape
));
1259 void DnDShapeFrame::OnPasteShape(wxCommandEvent
& event
)
1261 DnDShapeDataObject
shapeDataObject(NULL
);
1262 if ( wxTheClipboard
->GetData(&shapeDataObject
) )
1264 SetShape(shapeDataObject
.GetShape());
1268 wxLogStatus("No shape on the clipboard");
1272 void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent
& event
)
1274 event
.Enable( m_shape
!= NULL
);
1277 void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent
& event
)
1279 event
.Enable( wxTheClipboard
->IsSupported(wxDataFormat(shapeFormatId
)) );
1282 void DnDShapeFrame::OnPaint(wxPaintEvent
& event
)
1285 m_shape
->Draw(wxPaintDC(this));
1290 void DnDShapeFrame::OnDrop(long x
, long y
, DnDShape
*shape
)
1292 ms_lastDropTarget
= this;
1295 s
.Printf("Shape dropped at (%ld, %ld)", x
, y
);
1298 shape
->Move(ScreenToClient(wxPoint(x
, y
)));
1302 // ----------------------------------------------------------------------------
1304 // ----------------------------------------------------------------------------
1306 DnDShape
*DnDShape::New(const void *buf
)
1308 const ShapeDump
& dump
= *(const ShapeDump
*)buf
;
1312 return new DnDTriangularShape(wxPoint(dump
.x
, dump
.y
),
1313 wxSize(dump
.w
, dump
.h
),
1314 wxColour(dump
.r
, dump
.g
, dump
.b
));
1317 return new DnDRectangularShape(wxPoint(dump
.x
, dump
.y
),
1318 wxSize(dump
.w
, dump
.h
),
1319 wxColour(dump
.r
, dump
.g
, dump
.b
));
1322 return new DnDEllipticShape(wxPoint(dump
.x
, dump
.y
),
1323 wxSize(dump
.w
, dump
.h
),
1324 wxColour(dump
.r
, dump
.g
, dump
.b
));
1327 wxFAIL_MSG("invalid shape!");
1332 // ----------------------------------------------------------------------------
1333 // DnDShapeDataObject
1334 // ----------------------------------------------------------------------------
1336 void DnDShapeDataObject::CreateBitmap() const
1338 wxPoint pos
= m_shape
->GetPosition();
1339 wxSize size
= m_shape
->GetSize();
1340 int x
= pos
.x
+ size
.x
,
1342 wxBitmap
bitmap(x
, y
);
1344 dc
.SelectObject(bitmap
);
1345 dc
.SetBrush(wxBrush("white", wxSOLID
));
1348 dc
.SelectObject(wxNullBitmap
);
1350 DnDShapeDataObject
*self
= (DnDShapeDataObject
*)this; // const_cast
1351 self
->m_dataobj
.SetBitmap(bitmap
);
1352 self
->m_hasBitmap
= TRUE
;