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
) = 0
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
);
231 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
235 class DnDRectangularShape
: public DnDShape
238 DnDRectangularShape(const wxPoint
& pos
,
241 : DnDShape(pos
, size
, col
)
245 virtual Kind
GetKind() const { return Rectangle
; }
246 virtual void Draw(wxDC
& dc
)
251 wxPoint
p2(p1
.x
+ m_size
.x
, p1
.y
);
252 wxPoint
p3(p2
.x
, p2
.y
+ m_size
.y
);
253 wxPoint
p4(p1
.x
, p3
.y
);
260 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
264 class DnDEllipticShape
: public DnDShape
267 DnDEllipticShape(const wxPoint
& pos
,
270 : DnDShape(pos
, size
, col
)
274 virtual Kind
GetKind() const { return Ellipse
; }
275 virtual void Draw(wxDC
& dc
)
279 dc
.DrawEllipse(m_pos
, m_size
);
281 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
285 // ----------------------------------------------------------------------------
286 // A wxDataObject specialisation for the application-specific data
287 // ----------------------------------------------------------------------------
289 static const char *shapeFormatId
= "wxShape";
291 class DnDShapeDataObject
: public wxDataObject
294 // ctor doesn't copy the pointer, so it shouldn't go away while this object
296 DnDShapeDataObject(DnDShape
*shape
)
300 // this string should uniquely identify our format, but is otherwise
302 m_formatShape
.SetId(shapeFormatId
);
304 // we don't draw the shape to a bitmap until it's really needed (i.e.
305 // we're asked to do so)
310 DnDShape
*GetShape() const { return m_shape
; }
312 // implement base class pure virtuals
313 // ----------------------------------
315 virtual wxDataFormat
GetPreferredFormat() const
317 return m_formatShape
;
320 virtual size_t GetFormatCount(bool outputOnlyToo
) const
322 // our custom format is supported by both GetData() and SetData()
326 // but the bitmap format(s) are only supported for output
327 nFormats
+= m_dataobj
.GetFormatCount();
333 virtual void GetAllFormats(wxDataFormat
*formats
, bool outputOnlyToo
) const
335 formats
[0] = m_formatShape
;
338 m_dataobj
.GetAllFormats(&formats
[1]);
342 virtual size_t GetDataSize(const wxDataFormat
& format
) const
344 if ( format
== m_formatShape
)
346 return m_shape
->GetDataSize();
353 return m_dataobj
.GetDataSize(format
);
357 virtual bool GetDataHere(const wxDataFormat
& format
, void *pBuf
) const
359 if ( format
== m_formatShape
)
361 m_shape
->GetDataHere(pBuf
);
367 wxASSERT_MSG( format
== wxDF_BITMAP
, "unsupported format" );
372 return m_dataobj
.GetDataHere(format
, pBuf
);
376 virtual bool SetData(const wxDataFormat
& format
, const void *buf
)
378 wxCHECK_MSG( format
== m_formatShape
, FALSE
, "unsupported format" );
381 m_shape
= DnDShape::New(buf
);
383 // the shape has changed
390 // creates a bitmap and assigns it to m_dataobj (also sets m_hasBitmap)
391 void CreateBitmap() const;
393 wxDataFormat m_formatShape
; // our custom format
395 wxBitmapDataObject m_dataobj
; // it handles bitmaps
396 bool m_hasBitmap
; // true if m_dataobj has valid bitmap
398 DnDShape
*m_shape
; // our data
401 // ----------------------------------------------------------------------------
402 // A dialog to edit shape properties
403 // ----------------------------------------------------------------------------
405 class DnDShapeDialog
: public wxDialog
408 DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
);
410 DnDShape
*GetShape() const;
412 virtual bool TransferDataToWindow();
413 virtual bool TransferDataFromWindow();
415 void OnColour(wxCommandEvent
& event
);
422 DnDShape::Kind m_shapeKind
;
434 DECLARE_EVENT_TABLE()
437 // ----------------------------------------------------------------------------
438 // A frame for the shapes which can be drag-and-dropped between frames
439 // ----------------------------------------------------------------------------
441 class DnDShapeFrame
: public wxFrame
444 DnDShapeFrame(wxFrame
*parent
);
447 void SetShape(DnDShape
*shape
);
450 void OnNewShape(wxCommandEvent
& event
);
451 void OnEditShape(wxCommandEvent
& event
);
452 void OnClearShape(wxCommandEvent
& event
);
454 void OnCopyShape(wxCommandEvent
& event
);
455 void OnPasteShape(wxCommandEvent
& event
);
457 void OnUpdateUICopy(wxUpdateUIEvent
& event
);
458 void OnUpdateUIPaste(wxUpdateUIEvent
& event
);
460 void OnDrag(wxMouseEvent
& event
);
461 void OnPaint(wxPaintEvent
& event
);
462 void OnDrop(long x
, long y
, DnDShape
*shape
);
467 static DnDShapeFrame
*ms_lastDropTarget
;
469 DECLARE_EVENT_TABLE()
472 // ----------------------------------------------------------------------------
473 // wxDropTarget derivation for DnDShapes
474 // ----------------------------------------------------------------------------
476 class DnDShapeDropTarget
: public wxDropTarget
479 DnDShapeDropTarget(DnDShapeFrame
*frame
)
483 // the same as used by DnDShapeDataObject
484 m_formatShape
.SetId(shapeFormatId
);
487 // override base class (pure) virtuals
488 virtual void OnEnter()
489 { m_frame
->SetStatusText("Mouse entered the frame"); }
490 virtual void OnLeave()
491 { m_frame
->SetStatusText("Mouse left the frame"); }
492 virtual bool OnDrop(long x
, long y
, const void *pData
)
494 m_frame
->OnDrop(x
, y
, DnDShape::New(pData
));
500 virtual size_t GetFormatCount() const { return 1; }
501 virtual wxDataFormat
GetFormat(size_t WXUNUSED(n
)) const
502 { return m_formatShape
; }
505 DnDShapeFrame
*m_frame
;
506 wxDataFormat m_formatShape
;
509 // ----------------------------------------------------------------------------
510 // IDs for the menu commands
511 // ----------------------------------------------------------------------------
525 Menu_ToBeGreyed
, /* for testing */
526 Menu_ToBeDeleted
, /* for testing */
527 Menu_Shape_New
= 500,
530 Menu_ShapeClipboard_Copy
,
531 Menu_ShapeClipboard_Paste
,
535 BEGIN_EVENT_TABLE(DnDFrame
, wxFrame
)
536 EVT_MENU(Menu_Quit
, DnDFrame::OnQuit
)
537 EVT_MENU(Menu_About
, DnDFrame::OnAbout
)
538 EVT_MENU(Menu_Drag
, DnDFrame::OnDrag
)
539 EVT_MENU(Menu_NewFrame
, DnDFrame::OnNewFrame
)
540 EVT_MENU(Menu_Help
, DnDFrame::OnHelp
)
541 EVT_MENU(Menu_Clear
, DnDFrame::OnLogClear
)
542 EVT_MENU(Menu_Copy
, DnDFrame::OnCopy
)
543 EVT_MENU(Menu_Paste
, DnDFrame::OnPaste
)
544 EVT_MENU(Menu_CopyBitmap
, DnDFrame::OnCopyBitmap
)
545 EVT_MENU(Menu_PasteBitmap
,DnDFrame::OnPasteBitmap
)
547 EVT_UPDATE_UI(Menu_Paste
, DnDFrame::OnUpdateUIPasteText
)
548 EVT_UPDATE_UI(Menu_PasteBitmap
, DnDFrame::OnUpdateUIPasteBitmap
)
550 EVT_LEFT_DOWN( DnDFrame::OnLeftDown
)
551 EVT_RIGHT_DOWN( DnDFrame::OnRightDown
)
552 EVT_PAINT( DnDFrame::OnPaint
)
555 BEGIN_EVENT_TABLE(DnDShapeFrame
, wxFrame
)
556 EVT_MENU(Menu_Shape_New
, DnDShapeFrame::OnNewShape
)
557 EVT_MENU(Menu_Shape_Edit
, DnDShapeFrame::OnEditShape
)
558 EVT_MENU(Menu_Shape_Clear
, DnDShapeFrame::OnClearShape
)
560 EVT_MENU(Menu_ShapeClipboard_Copy
, DnDShapeFrame::OnCopyShape
)
561 EVT_MENU(Menu_ShapeClipboard_Paste
, DnDShapeFrame::OnPasteShape
)
563 EVT_UPDATE_UI(Menu_ShapeClipboard_Copy
, DnDShapeFrame::OnUpdateUICopy
)
564 EVT_UPDATE_UI(Menu_ShapeClipboard_Paste
, DnDShapeFrame::OnUpdateUIPaste
)
566 EVT_LEFT_DOWN(DnDShapeFrame::OnDrag
)
568 EVT_PAINT(DnDShapeFrame::OnPaint
)
571 BEGIN_EVENT_TABLE(DnDShapeDialog
, wxDialog
)
572 EVT_BUTTON(Button_Colour
, OnColour
)
575 // ============================================================================
577 // ============================================================================
579 // `Main program' equivalent, creating windows and returning main app frame
580 bool DnDApp::OnInit()
583 wxImage::AddHandler( new wxPNGHandler
);
586 // create the main frame window
587 DnDFrame
*frame
= new DnDFrame((wxFrame
*) NULL
,
588 "Drag-and-Drop/Clipboard wxWindows Sample",
596 wxDefaultResourceTable
->ParseResourceFile("dnd.wxr");
601 DnDFrame::DnDFrame(wxFrame
*frame
, char *title
, int x
, int y
, int w
, int h
)
602 : wxFrame(frame
, -1, title
, wxPoint(x
, y
), wxSize(w
, h
)),
603 m_strText("wxWindows drag & drop works :-)")
606 // frame icon and status bar
607 SetIcon(wxICON(mondrian
));
612 wxMenu
*file_menu
= new wxMenu
;
613 file_menu
->Append(Menu_Drag
, "&Test drag...");
614 file_menu
->AppendSeparator();
615 file_menu
->Append(Menu_NewFrame
, "&New frame\tCtrl-N");
616 file_menu
->AppendSeparator();
617 file_menu
->Append(Menu_Quit
, "E&xit");
619 wxMenu
*log_menu
= new wxMenu
;
620 log_menu
->Append(Menu_Clear
, "Clear\tDel");
622 wxMenu
*help_menu
= new wxMenu
;
623 help_menu
->Append(Menu_Help
, "&Help...");
624 help_menu
->AppendSeparator();
625 help_menu
->Append(Menu_About
, "&About");
627 wxMenu
*clip_menu
= new wxMenu
;
628 clip_menu
->Append(Menu_Copy
, "&Copy text\tCtrl+C");
629 clip_menu
->Append(Menu_Paste
, "&Paste text\tCtrl+V");
630 clip_menu
->AppendSeparator();
631 clip_menu
->Append(Menu_CopyBitmap
, "&Copy bitmap\tAlt+C");
632 clip_menu
->Append(Menu_PasteBitmap
, "&Paste bitmap\tAlt+V");
634 wxMenuBar
*menu_bar
= new wxMenuBar
;
635 menu_bar
->Append(file_menu
, "&File");
636 menu_bar
->Append(log_menu
, "&Log");
637 menu_bar
->Append(clip_menu
, "&Clipboard");
638 menu_bar
->Append(help_menu
, "&Help");
640 SetMenuBar(menu_bar
);
642 // make a panel with 3 subwindows
644 wxSize
size(400, 200);
646 wxString
strFile("Drop files here!"), strText("Drop text on me");
648 m_ctrlFile
= new wxListBox(this, -1, pos
, size
, 1, &strFile
,
649 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
650 m_ctrlText
= new wxListBox(this, -1, pos
, size
, 1, &strText
,
651 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
653 m_ctrlLog
= new wxTextCtrl(this, -1, "", pos
, size
,
654 wxTE_MULTILINE
| wxTE_READONLY
|
657 // redirect log messages to the text window and switch on OLE messages
659 wxLog::AddTraceMask(wxTRACE_OleCalls
);
660 m_pLog
= new wxLogTextCtrl(m_ctrlLog
);
661 m_pLogPrev
= wxLog::SetActiveTarget(m_pLog
);
663 // associate drop targets with 2 text controls
664 m_ctrlFile
->SetDropTarget(new DnDFile(m_ctrlFile
));
665 m_ctrlText
->SetDropTarget(new DnDText(m_ctrlText
));
667 wxLayoutConstraints
*c
;
670 c
= new wxLayoutConstraints
;
671 c
->left
.SameAs(this, wxLeft
);
672 c
->top
.SameAs(this, wxTop
);
673 c
->right
.PercentOf(this, wxRight
, 50);
674 c
->height
.PercentOf(this, wxHeight
, 30);
675 m_ctrlFile
->SetConstraints(c
);
678 c
= new wxLayoutConstraints
;
679 c
->left
.SameAs (m_ctrlFile
, wxRight
);
680 c
->top
.SameAs (this, wxTop
);
681 c
->right
.SameAs (this, wxRight
);
682 c
->height
.PercentOf(this, wxHeight
, 30);
683 m_ctrlText
->SetConstraints(c
);
685 // Lower text control
686 c
= new wxLayoutConstraints
;
687 c
->left
.SameAs (this, wxLeft
);
688 c
->right
.SameAs (this, wxRight
);
689 c
->height
.PercentOf(this, wxHeight
, 50);
690 c
->top
.SameAs(m_ctrlText
, wxBottom
);
691 m_ctrlLog
->SetConstraints(c
);
696 void DnDFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
))
701 void DnDFrame::OnPaint(wxPaintEvent
& WXUNUSED(event
))
705 GetClientSize( &w
, &h
);
708 dc
.SetFont( wxFont( 24, wxDECORATIVE
, wxNORMAL
, wxNORMAL
, FALSE
, "charter" ) );
709 dc
.DrawText( "Drag text from here!", 20, h
-50 );
713 // 4/5 is 80% taken by other windows, 20 is arbitrary margin
714 dc
.DrawBitmap(m_bitmap
,
715 w
- m_bitmap
.GetWidth() - 20,
720 void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent
& event
)
722 event
.Enable( wxTheClipboard
->IsSupported(wxDF_TEXT
) );
725 void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent
& event
)
727 event
.Enable( wxTheClipboard
->IsSupported(wxDF_BITMAP
) );
730 void DnDFrame::OnNewFrame(wxCommandEvent
& WXUNUSED(event
))
732 (new DnDShapeFrame(this))->Show(TRUE
);
734 wxLogStatus(this, "Double click the new frame to select a shape for it");
737 void DnDFrame::OnDrag(wxCommandEvent
& WXUNUSED(event
))
739 wxString strText
= wxGetTextFromUser
741 "After you enter text in this dialog, press any mouse\n"
742 "button in the bottom (empty) part of the frame and \n"
743 "drag it anywhere - you will be in fact dragging the\n"
744 "text object containing this text",
745 "Please enter some text", m_strText
, this
751 void DnDFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
753 wxMessageBox("Drag-&-Drop Demo\n"
754 "Please see \"Help|Help...\" for details\n"
755 "Copyright (c) 1998 Vadim Zeitlin",
757 wxICON_INFORMATION
| wxOK
,
761 void DnDFrame::OnHelp(wxCommandEvent
& /* event */)
763 wxMessageDialog
dialog(this,
764 "This small program demonstrates drag & drop support in wxWindows. The program window\n"
765 "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
766 "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
767 "and the right one accepts text.\n"
769 "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
770 "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
771 "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
772 "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
773 "work with files) and see what changes.\n"
775 "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
776 "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
777 "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
778 "change, don't release the mouse button until it does. You can change the string being\n"
779 "dragged in in \"File|Test drag...\" dialog.\n"
782 "Please send all questions/bug reports/suggestions &c to \n"
783 "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
789 void DnDFrame::OnLogClear(wxCommandEvent
& /* event */ )
794 void DnDFrame::OnLeftDown(wxMouseEvent
&WXUNUSED(event
) )
796 if ( !m_strText
.IsEmpty() )
798 // start drag operation
799 wxTextDataObject
textData(m_strText
);
800 wxDropSource
source(textData
, this, wxICON(mondrian
));
804 switch ( source
.DoDragDrop(TRUE
) )
806 case wxDragError
: pc
= "Error!"; break;
807 case wxDragNone
: pc
= "Nothing"; break;
808 case wxDragCopy
: pc
= "Copied"; break;
809 case wxDragMove
: pc
= "Moved"; break;
810 case wxDragCancel
: pc
= "Cancelled"; break;
811 default: pc
= "Huh?"; break;
814 SetStatusText(wxString("Drag result: ") + pc
);
818 void DnDFrame::OnRightDown(wxMouseEvent
&event
)
820 wxMenu
*menu
= new wxMenu
;
822 menu
->Append(Menu_Drag
, "&Test drag...");
823 menu
->Append(Menu_About
, "&About");
824 menu
->Append(Menu_Quit
, "E&xit");
825 menu
->Append(Menu_ToBeDeleted
, "To be deleted");
826 menu
->Append(Menu_ToBeGreyed
, "To be greyed");
828 menu
->Delete( Menu_ToBeDeleted
);
829 menu
->Enable( Menu_ToBeGreyed
, FALSE
);
831 PopupMenu( menu
, event
.GetX(), event
.GetY() );
834 DnDFrame::~DnDFrame()
836 if ( m_pLog
!= NULL
) {
837 if ( wxLog::SetActiveTarget(m_pLogPrev
) == m_pLog
)
842 // ---------------------------------------------------------------------------
844 // ---------------------------------------------------------------------------
846 void DnDFrame::OnCopyBitmap(wxCommandEvent
& WXUNUSED(event
))
848 // PNG support is not always compiled in under Windows, so use BMP there
850 wxFileDialog
dialog(this, "Open a BMP file", "", "", "BMP files (*.bmp)|*.bmp", 0);
852 wxFileDialog
dialog(this, "Open a PNG file", "", "", "PNG files (*.png)|*.png", 0);
855 if (dialog
.ShowModal() != wxID_OK
)
857 wxLogMessage( _T("Aborted file open") );
861 if (dialog
.GetPath().IsEmpty())
863 wxLogMessage( _T("Returned empty string.") );
867 if (!wxFileExists(dialog
.GetPath()))
869 wxLogMessage( _T("File doesn't exist.") );
874 image
.LoadFile( dialog
.GetPath(),
883 wxLogError( _T("Invalid image file...") );
887 wxLogStatus( _T("Decoding image file...") );
890 wxBitmap
bitmap( image
.ConvertToBitmap() );
892 if ( !wxTheClipboard
->Open() )
894 wxLogError(_T("Can't open clipboard."));
899 wxLogMessage( _T("Creating wxBitmapDataObject...") );
902 if ( !wxTheClipboard
->AddData(new wxBitmapDataObject(bitmap
)) )
904 wxLogError(_T("Can't copy image to the clipboard."));
908 wxLogMessage(_T("Image has been put on the clipboard.") );
909 wxLogMessage(_T("You can paste it now and look at it.") );
912 wxTheClipboard
->Close();
915 void DnDFrame::OnPasteBitmap(wxCommandEvent
& WXUNUSED(event
))
917 if ( !wxTheClipboard
->Open() )
919 wxLogError(_T("Can't open clipboard."));
924 if ( !wxTheClipboard
->IsSupported(wxDF_BITMAP
) )
926 wxLogWarning(_T("No bitmap on clipboard"));
928 wxTheClipboard
->Close();
932 wxBitmapDataObject data
;
933 if ( !wxTheClipboard
->GetData(&data
) )
935 wxLogError(_T("Can't paste bitmap from the clipboard"));
939 wxLogMessage(_T("Bitmap pasted from the clipboard") );
940 m_bitmap
= data
.GetBitmap();
944 wxTheClipboard
->Close();
947 // ---------------------------------------------------------------------------
949 // ---------------------------------------------------------------------------
951 void DnDFrame::OnCopy(wxCommandEvent
& WXUNUSED(event
))
953 if ( !wxTheClipboard
->Open() )
955 wxLogError(_T("Can't open clipboard."));
960 if ( !wxTheClipboard
->AddData(new wxTextDataObject(m_strText
)) )
962 wxLogError(_T("Can't copy data to the clipboard"));
966 wxLogMessage(_T("Text '%s' put on the clipboard"), m_strText
.c_str());
969 wxTheClipboard
->Close();
972 void DnDFrame::OnPaste(wxCommandEvent
& WXUNUSED(event
))
974 if ( !wxTheClipboard
->Open() )
976 wxLogError(_T("Can't open clipboard."));
981 if ( !wxTheClipboard
->IsSupported(wxDF_TEXT
) )
983 wxLogWarning(_T("No text data on clipboard"));
985 wxTheClipboard
->Close();
989 wxTextDataObject text
;
990 if ( !wxTheClipboard
->GetData(&text
) )
992 wxLogError(_T("Can't paste data from the clipboard"));
996 wxLogMessage(_T("Text '%s' pasted from the clipboard"),
997 text
.GetText().c_str());
1000 wxTheClipboard
->Close();
1003 // ----------------------------------------------------------------------------
1004 // Notifications called by the base class
1005 // ----------------------------------------------------------------------------
1007 bool DnDText::OnDropText( wxDropPointCoord
, wxDropPointCoord
, const wxChar
*psz
)
1009 m_pOwner
->Append(psz
);
1014 bool DnDFile::OnDropFiles( wxDropPointCoord
, wxDropPointCoord
, size_t nFiles
,
1015 const wxChar
* const aszFiles
[])
1018 str
.Printf( _T("%d files dropped"), nFiles
);
1019 m_pOwner
->Append(str
);
1020 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
1021 m_pOwner
->Append(aszFiles
[n
]);
1027 // ----------------------------------------------------------------------------
1029 // ----------------------------------------------------------------------------
1031 DnDShapeDialog::DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
)
1035 LoadFromResource(parent
, "dialogShape");
1037 m_textX
= (wxTextCtrl
*)wxFindWindowByName("textX", this);
1038 m_textY
= (wxTextCtrl
*)wxFindWindowByName("textY", this);
1039 m_textW
= (wxTextCtrl
*)wxFindWindowByName("textW", this);
1040 m_textH
= (wxTextCtrl
*)wxFindWindowByName("textH", this);
1042 m_radio
= (wxRadioBox
*)wxFindWindowByName("radio", this);
1045 DnDShape
*DnDShapeDialog::GetShape() const
1047 switch ( m_shapeKind
)
1050 case DnDShape::None
: return NULL
;
1051 case DnDShape::Triangle
: return new DnDTriangularShape(m_pos
, m_size
, m_col
);
1052 case DnDShape::Rectangle
: return new DnDRectangularShape(m_pos
, m_size
, m_col
);
1053 case DnDShape::Ellipse
: return new DnDEllipticShape(m_pos
, m_size
, m_col
);
1057 bool DnDShapeDialog::TransferDataToWindow()
1061 m_radio
->SetSelection(m_shape
->GetKind());
1062 m_pos
= m_shape
->GetPosition();
1063 m_size
= m_shape
->GetSize();
1064 m_col
= m_shape
->GetColour();
1068 m_radio
->SetSelection(DnDShape::None
);
1069 m_pos
= wxPoint(1, 1);
1070 m_size
= wxSize(100, 100);
1073 m_textX
->SetValue(wxString() << m_pos
.x
);
1074 m_textY
->SetValue(wxString() << m_pos
.y
);
1075 m_textW
->SetValue(wxString() << m_size
.x
);
1076 m_textH
->SetValue(wxString() << m_size
.y
);
1081 bool DnDShapeDialog::TransferDataFromWindow()
1083 m_shapeKind
= (DnDShape::Kind
)m_radio
->GetSelection();
1085 m_pos
.x
= atoi(m_textX
->GetValue());
1086 m_pos
.y
= atoi(m_textY
->GetValue());
1087 m_size
.x
= atoi(m_textW
->GetValue());
1088 m_size
.y
= atoi(m_textH
->GetValue());
1090 if ( !m_pos
.x
|| !m_pos
.y
|| !m_size
.x
|| !m_size
.y
)
1092 wxMessageBox("All sizes and positions should be non null!",
1093 "Invalid shape", wxICON_HAND
| wxOK
, this);
1101 void DnDShapeDialog::OnColour(wxCommandEvent
& WXUNUSED(event
))
1104 data
.SetChooseFull(TRUE
);
1105 for (int i
= 0; i
< 16; i
++)
1107 wxColour
colour(i
*16, i
*16, i
*16);
1108 data
.SetCustomColour(i
, colour
);
1111 wxColourDialog
dialog(this, &data
);
1112 if ( dialog
.ShowModal() == wxID_OK
)
1114 m_col
= dialog
.GetColourData().GetColour();
1118 // ----------------------------------------------------------------------------
1120 // ----------------------------------------------------------------------------
1122 DnDShapeFrame
*DnDShapeFrame::ms_lastDropTarget
= NULL
;
1124 DnDShapeFrame::DnDShapeFrame(wxFrame
*parent
)
1125 : wxFrame(parent
, -1, "Shape Frame",
1126 wxDefaultPosition
, wxSize(250, 150))
1128 SetBackgroundColour(*wxWHITE
);
1132 wxMenu
*menuShape
= new wxMenu
;
1133 menuShape
->Append(Menu_Shape_New
, "&New default shape\tCtrl-S");
1134 menuShape
->Append(Menu_Shape_Edit
, "&Edit shape\tCtrl-E");
1135 menuShape
->AppendSeparator();
1136 menuShape
->Append(Menu_Shape_Clear
, "&Clear shape\tDel");
1138 wxMenu
*menuClipboard
= new wxMenu
;
1139 menuClipboard
->Append(Menu_ShapeClipboard_Copy
, "&Copy\tCtrl-C");
1140 menuClipboard
->Append(Menu_ShapeClipboard_Paste
, "&Paste\tCtrl-V");
1142 wxMenuBar
*menubar
= new wxMenuBar
;
1143 menubar
->Append(menuShape
, "&Shape");
1144 menubar
->Append(menuClipboard
, "&Clipboard");
1146 SetMenuBar(menubar
);
1148 SetStatusText("Press Ctrl-S to create a new shape");
1150 SetDropTarget(new DnDShapeDropTarget(this));
1155 DnDShapeFrame::~DnDShapeFrame()
1160 void DnDShapeFrame::SetShape(DnDShape
*shape
)
1168 void DnDShapeFrame::OnDrag(wxMouseEvent
& event
)
1177 // start drag operation
1178 DnDShapeDataObject
shapeData(m_shape
);
1179 wxDropSource
source(shapeData
, this, wxICON(mondrian
));
1181 const char *pc
= NULL
;
1182 switch ( source
.DoDragDrop(TRUE
) )
1186 wxLogError("An error occured during drag and drop operation");
1190 SetStatusText("Nothing happened");
1199 if ( ms_lastDropTarget
!= this )
1201 // don't delete the shape if we dropped it on ourselves!
1207 SetStatusText("Drag and drop operation cancelled");
1213 SetStatusText(wxString("Shape successfully ") + pc
);
1215 //else: status text already set
1218 void DnDShapeFrame::OnEditShape(wxCommandEvent
& event
)
1220 DnDShapeDialog
dlg(this, m_shape
);
1221 if ( dlg
.ShowModal() == wxID_OK
)
1223 SetShape(dlg
.GetShape());
1227 SetStatusText("You can now drag the shape to another frame");
1232 void DnDShapeFrame::OnNewShape(wxCommandEvent
& event
)
1234 SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED
));
1236 SetStatusText("You can now drag the shape to another frame");
1239 void DnDShapeFrame::OnClearShape(wxCommandEvent
& event
)
1244 void DnDShapeFrame::OnCopyShape(wxCommandEvent
& event
)
1247 wxTheClipboard
->AddData(new DnDShapeDataObject(m_shape
));
1250 void DnDShapeFrame::OnPasteShape(wxCommandEvent
& event
)
1252 DnDShapeDataObject
shapeDataObject(NULL
);
1253 if ( wxTheClipboard
->GetData(&shapeDataObject
) )
1255 SetShape(shapeDataObject
.GetShape());
1259 wxLogStatus("No shape on the clipboard");
1263 void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent
& event
)
1265 event
.Enable( m_shape
!= NULL
);
1268 void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent
& event
)
1270 event
.Enable( wxTheClipboard
->IsSupported(wxDataFormat(shapeFormatId
)) );
1273 void DnDShapeFrame::OnPaint(wxPaintEvent
& event
)
1276 m_shape
->Draw(wxPaintDC(this));
1281 void DnDShapeFrame::OnDrop(long x
, long y
, DnDShape
*shape
)
1283 ms_lastDropTarget
= this;
1286 s
.Printf("Shape dropped at (%ld, %ld)", x
, y
);
1289 shape
->Move(ScreenToClient(wxPoint(x
, y
)));
1293 // ----------------------------------------------------------------------------
1295 // ----------------------------------------------------------------------------
1297 DnDShape
*DnDShape::New(const void *buf
)
1299 const ShapeDump
& dump
= *(const ShapeDump
*)buf
;
1303 return new DnDTriangularShape(wxPoint(dump
.x
, dump
.y
),
1304 wxSize(dump
.w
, dump
.h
),
1305 wxColour(dump
.r
, dump
.g
, dump
.b
));
1308 return new DnDRectangularShape(wxPoint(dump
.x
, dump
.y
),
1309 wxSize(dump
.w
, dump
.h
),
1310 wxColour(dump
.r
, dump
.g
, dump
.b
));
1313 return new DnDEllipticShape(wxPoint(dump
.x
, dump
.y
),
1314 wxSize(dump
.w
, dump
.h
),
1315 wxColour(dump
.r
, dump
.g
, dump
.b
));
1318 wxFAIL_MSG("invalid shape!");
1323 // ----------------------------------------------------------------------------
1324 // DnDShapeDataObject
1325 // ----------------------------------------------------------------------------
1327 void DnDShapeDataObject::CreateBitmap() const
1329 wxPoint pos
= m_shape
->GetPosition();
1330 wxSize size
= m_shape
->GetSize();
1331 int x
= pos
.x
+ size
.x
,
1333 wxBitmap
bitmap(x
, y
);
1335 dc
.SelectObject(bitmap
);
1336 dc
.SetBrush(wxBrush("white", wxSOLID
));
1339 dc
.SelectObject(wxNullBitmap
);
1341 DnDShapeDataObject
*self
= (DnDShapeDataObject
*)this; // const_cast
1342 self
->m_dataobj
.SetBitmap(bitmap
);
1343 self
->m_hasBitmap
= TRUE
;