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
;
116 wxLog
*m_pLog
, *m_pLogPrev
;
122 // ----------------------------------------------------------------------------
123 // A shape is an example of application-specific data which may be transported
124 // via drag-and-drop or clipboard: in our case, we have different geometric
125 // shapes, each one with its own colour and position
126 // ----------------------------------------------------------------------------
139 DnDShape(const wxPoint
& pos
,
142 : m_pos(pos
), m_size(size
), m_col(col
)
146 // this is for debugging - lets us see when exactly an object is freed
147 // (this may be later than you think if it's on the clipboard, for example)
148 virtual ~DnDShape() { }
150 // the functions used for drag-and-drop: they dump and restore a shape into
151 // some bitwise-copiable data (might use streams too...)
152 // ------------------------------------------------------------------------
154 // restore from buffer
155 static DnDShape
*New(const void *buf
);
157 virtual size_t GetDataSize() const
159 return sizeof(ShapeDump
);
162 virtual void GetDataHere(void *buf
) const
164 ShapeDump
& dump
= *(ShapeDump
*)buf
;
169 dump
.r
= m_col
.Red();
170 dump
.g
= m_col
.Green();
171 dump
.b
= m_col
.Blue();
176 const wxPoint
& GetPosition() const { return m_pos
; }
177 const wxColour
& GetColour() const { return m_col
; }
178 const wxSize
& GetSize() const { return m_size
; }
180 void Move(const wxPoint
& pos
) { m_pos
= pos
; }
182 // to implement in derived classes
183 virtual Kind
GetKind() const = 0;
185 virtual void Draw(wxDC
& dc
)
187 dc
.SetPen(wxPen(m_col
, 1, wxSOLID
));
191 wxPoint
GetCentre() const
192 { return wxPoint(m_pos
.x
+ m_size
.x
/ 2, m_pos
.y
+ m_size
.y
/ 2); }
196 int x
, y
, // position
207 class DnDTriangularShape
: public DnDShape
210 DnDTriangularShape(const wxPoint
& pos
,
213 : DnDShape(pos
, size
, col
)
217 virtual ~DnDTriangularShape()
219 wxLogMessage("DnDTriangularShape is being deleted");
222 virtual Kind
GetKind() const { return Triangle
; }
223 virtual void Draw(wxDC
& dc
)
227 // well, it's a bit difficult to describe a triangle by position and
228 // size, but we're not doing geometry here, do we? ;-)
230 wxPoint
p2(m_pos
.x
+ m_size
.x
, m_pos
.y
);
231 wxPoint
p3(m_pos
.x
, m_pos
.y
+ m_size
.y
);
238 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
243 class DnDRectangularShape
: public DnDShape
246 DnDRectangularShape(const wxPoint
& pos
,
249 : DnDShape(pos
, size
, col
)
253 virtual ~DnDRectangularShape()
255 wxLogMessage("DnDRectangularShape is being deleted");
258 virtual Kind
GetKind() const { return Rectangle
; }
259 virtual void Draw(wxDC
& dc
)
264 wxPoint
p2(p1
.x
+ m_size
.x
, p1
.y
);
265 wxPoint
p3(p2
.x
, p2
.y
+ m_size
.y
);
266 wxPoint
p4(p1
.x
, p3
.y
);
274 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
279 class DnDEllipticShape
: public DnDShape
282 DnDEllipticShape(const wxPoint
& pos
,
285 : DnDShape(pos
, size
, col
)
289 virtual ~DnDEllipticShape()
291 wxLogMessage("DnDEllipticShape is being deleted");
294 virtual Kind
GetKind() const { return Ellipse
; }
295 virtual void Draw(wxDC
& dc
)
299 dc
.DrawEllipse(m_pos
, m_size
);
302 dc
.FloodFill(GetCentre(), m_col
, wxFLOOD_BORDER
);
307 // ----------------------------------------------------------------------------
308 // A wxDataObject specialisation for the application-specific data
309 // ----------------------------------------------------------------------------
311 static const char *shapeFormatId
= "wxShape";
313 class DnDShapeDataObject
: public wxDataObject
316 // ctor doesn't copy the pointer, so it shouldn't go away while this object
318 DnDShapeDataObject(DnDShape
*shape
= (DnDShape
*)NULL
)
322 // we need to copy the shape because the one we're handled may be
323 // deleted while it's still on the clipboard (for example) - and we
324 // reuse the serialisation methods here to copy it
325 void *buf
= malloc(shape
->DnDShape
::GetDataSize());
326 shape
->GetDataHere(buf
);
327 m_shape
= DnDShape
::New(buf
);
337 // this string should uniquely identify our format, but is otherwise
339 m_formatShape
.SetId(shapeFormatId
);
341 // we don't draw the shape to a bitmap until it's really needed (i.e.
342 // we're asked to do so)
346 virtual ~DnDShapeDataObject() { delete m_shape
; }
349 DnDShape
*GetShape() const { return m_shape
; }
351 // implement base class pure virtuals
352 // ----------------------------------
354 virtual wxDataFormat
GetPreferredFormat(Direction
WXUNUSED(dir
)) const
356 return m_formatShape
;
359 virtual size_t GetFormatCount(Direction dir
) const
361 // our custom format is supported by both GetData() and SetData()
365 // but the bitmap format(s) are only supported for output
366 nFormats
+= m_dataobj
.GetFormatCount(dir
);
372 virtual void GetAllFormats(wxDataFormat
*formats
, Direction dir
) const
374 formats
[0] = m_formatShape
;
377 m_dataobj
.GetAllFormats(&formats
[1], dir
);
381 virtual size_t GetDataSize(const wxDataFormat
& format
) const
383 if ( format
== m_formatShape
)
385 return m_shape
->GetDataSize();
392 return m_dataobj
.GetDataSize();
396 virtual bool GetDataHere(const wxDataFormat
& format
, void *pBuf
) const
398 if ( format
== m_formatShape
)
400 m_shape
->GetDataHere(pBuf
);
406 wxASSERT_MSG( format
== wxDF_BITMAP
, "unsupported format" );
411 return m_dataobj
.GetDataHere(pBuf
);
415 virtual bool SetData(const wxDataFormat
& format
,
416 size_t len
, const void *buf
)
418 wxCHECK_MSG( format
== m_formatShape
, FALSE
, "unsupported format" );
421 m_shape
= DnDShape
::New(buf
);
423 // the shape has changed
430 // creates a bitmap and assigns it to m_dataobj (also sets m_hasBitmap)
431 void CreateBitmap() const;
433 wxDataFormat m_formatShape
; // our custom format
435 wxBitmapDataObject m_dataobj
; // it handles bitmaps
436 bool m_hasBitmap
; // true if m_dataobj has valid bitmap
438 DnDShape
*m_shape
; // our data
441 // ----------------------------------------------------------------------------
442 // A dialog to edit shape properties
443 // ----------------------------------------------------------------------------
445 class DnDShapeDialog
: public wxDialog
448 DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
);
450 DnDShape
*GetShape() const;
452 virtual bool TransferDataToWindow();
453 virtual bool TransferDataFromWindow();
455 void OnColour(wxCommandEvent
& event
);
462 DnDShape
::Kind m_shapeKind
;
474 DECLARE_EVENT_TABLE()
477 // ----------------------------------------------------------------------------
478 // A frame for the shapes which can be drag-and-dropped between frames
479 // ----------------------------------------------------------------------------
481 class DnDShapeFrame
: public wxFrame
484 DnDShapeFrame(wxFrame
*parent
);
487 void SetShape(DnDShape
*shape
);
490 void OnNewShape(wxCommandEvent
& event
);
491 void OnEditShape(wxCommandEvent
& event
);
492 void OnClearShape(wxCommandEvent
& event
);
494 void OnCopyShape(wxCommandEvent
& event
);
495 void OnPasteShape(wxCommandEvent
& event
);
497 void OnUpdateUICopy(wxUpdateUIEvent
& event
);
498 void OnUpdateUIPaste(wxUpdateUIEvent
& event
);
500 void OnDrag(wxMouseEvent
& event
);
501 void OnPaint(wxPaintEvent
& event
);
502 void OnDrop(long x
, long y
, DnDShape
*shape
);
507 static DnDShapeFrame
*ms_lastDropTarget
;
509 DECLARE_EVENT_TABLE()
512 // ----------------------------------------------------------------------------
513 // wxDropTarget derivation for DnDShapes
514 // ----------------------------------------------------------------------------
516 class DnDShapeDropTarget
: public wxDropTarget
519 DnDShapeDropTarget(DnDShapeFrame
*frame
)
520 : wxDropTarget(new DnDShapeDataObject
)
525 // override base class (pure) virtuals
526 virtual void OnEnter()
527 { m_frame
->SetStatusText("Mouse entered the frame"); }
528 virtual void OnLeave()
529 { m_frame
->SetStatusText("Mouse left the frame"); }
530 virtual bool OnData(wxCoord x
, wxCoord y
)
534 wxLogError("Failed to get drag and drop data");
539 m_frame
->OnDrop(x
, y
,
540 ((DnDShapeDataObject
*)GetDataObject())->GetShape());
546 DnDShapeFrame
*m_frame
;
549 // ----------------------------------------------------------------------------
550 // IDs for the menu commands
551 // ----------------------------------------------------------------------------
565 Menu_ToBeGreyed
, /* for testing */
566 Menu_ToBeDeleted
, /* for testing */
567 Menu_Shape_New
= 500,
570 Menu_ShapeClipboard_Copy
,
571 Menu_ShapeClipboard_Paste
,
575 BEGIN_EVENT_TABLE(DnDFrame
, wxFrame
)
576 EVT_MENU(Menu_Quit
, DnDFrame
::OnQuit
)
577 EVT_MENU(Menu_About
, DnDFrame
::OnAbout
)
578 EVT_MENU(Menu_Drag
, DnDFrame
::OnDrag
)
579 EVT_MENU(Menu_NewFrame
, DnDFrame
::OnNewFrame
)
580 EVT_MENU(Menu_Help
, DnDFrame
::OnHelp
)
581 EVT_MENU(Menu_Clear
, DnDFrame
::OnLogClear
)
582 EVT_MENU(Menu_Copy
, DnDFrame
::OnCopy
)
583 EVT_MENU(Menu_Paste
, DnDFrame
::OnPaste
)
584 EVT_MENU(Menu_CopyBitmap
, DnDFrame
::OnCopyBitmap
)
585 EVT_MENU(Menu_PasteBitmap
,DnDFrame
::OnPasteBitmap
)
587 EVT_UPDATE_UI(Menu_Paste
, DnDFrame
::OnUpdateUIPasteText
)
588 EVT_UPDATE_UI(Menu_PasteBitmap
, DnDFrame
::OnUpdateUIPasteBitmap
)
590 EVT_LEFT_DOWN( DnDFrame
::OnLeftDown
)
591 EVT_RIGHT_DOWN( DnDFrame
::OnRightDown
)
592 EVT_PAINT( DnDFrame
::OnPaint
)
595 BEGIN_EVENT_TABLE(DnDShapeFrame
, wxFrame
)
596 EVT_MENU(Menu_Shape_New
, DnDShapeFrame
::OnNewShape
)
597 EVT_MENU(Menu_Shape_Edit
, DnDShapeFrame
::OnEditShape
)
598 EVT_MENU(Menu_Shape_Clear
, DnDShapeFrame
::OnClearShape
)
600 EVT_MENU(Menu_ShapeClipboard_Copy
, DnDShapeFrame
::OnCopyShape
)
601 EVT_MENU(Menu_ShapeClipboard_Paste
, DnDShapeFrame
::OnPasteShape
)
603 EVT_UPDATE_UI(Menu_ShapeClipboard_Copy
, DnDShapeFrame
::OnUpdateUICopy
)
604 EVT_UPDATE_UI(Menu_ShapeClipboard_Paste
, DnDShapeFrame
::OnUpdateUIPaste
)
606 EVT_LEFT_DOWN(DnDShapeFrame
::OnDrag
)
608 EVT_PAINT(DnDShapeFrame
::OnPaint
)
611 BEGIN_EVENT_TABLE(DnDShapeDialog
, wxDialog
)
612 EVT_BUTTON(Button_Colour
, OnColour
)
615 // ============================================================================
617 // ============================================================================
619 // `Main program' equivalent, creating windows and returning main app frame
620 bool DnDApp
::OnInit()
622 // load our ressources
626 pathList
.Add("./Debug");
627 pathList
.Add("./Release");
630 wxString path
= pathList
.FindValidPath("dnd.wxr");
633 wxLogError("Can't find the resource file dnd.wxr in the current "
634 "directory, aborting.");
639 wxDefaultResourceTable
->ParseResourceFile(path
);
642 wxImage
::AddHandler( new wxPNGHandler
);
645 // create the main frame window
646 DnDFrame
*frame
= new DnDFrame((wxFrame
*) NULL
,
647 "Drag-and-Drop/Clipboard wxWindows Sample",
658 DnDFrame
::DnDFrame(wxFrame
*frame
, char *title
, int x
, int y
, int w
, int h
)
659 : wxFrame(frame
, -1, title
, wxPoint(x
, y
), wxSize(w
, h
)),
660 m_strText("wxWindows drag & drop works :-)")
663 // frame icon and status bar
664 SetIcon(wxICON(mondrian
));
669 wxMenu
*file_menu
= new wxMenu
;
670 file_menu
->Append(Menu_Drag
, "&Test drag...");
671 file_menu
->AppendSeparator();
672 file_menu
->Append(Menu_NewFrame
, "&New frame\tCtrl-N");
673 file_menu
->AppendSeparator();
674 file_menu
->Append(Menu_Quit
, "E&xit");
676 wxMenu
*log_menu
= new wxMenu
;
677 log_menu
->Append(Menu_Clear
, "Clear\tDel");
679 wxMenu
*help_menu
= new wxMenu
;
680 help_menu
->Append(Menu_Help
, "&Help...");
681 help_menu
->AppendSeparator();
682 help_menu
->Append(Menu_About
, "&About");
684 wxMenu
*clip_menu
= new wxMenu
;
685 clip_menu
->Append(Menu_Copy
, "&Copy text\tCtrl+C");
686 clip_menu
->Append(Menu_Paste
, "&Paste text\tCtrl+V");
687 clip_menu
->AppendSeparator();
688 clip_menu
->Append(Menu_CopyBitmap
, "&Copy bitmap\tAlt+C");
689 clip_menu
->Append(Menu_PasteBitmap
, "&Paste bitmap\tAlt+V");
691 wxMenuBar
*menu_bar
= new wxMenuBar
;
692 menu_bar
->Append(file_menu
, "&File");
693 menu_bar
->Append(log_menu
, "&Log");
694 menu_bar
->Append(clip_menu
, "&Clipboard");
695 menu_bar
->Append(help_menu
, "&Help");
697 SetMenuBar(menu_bar
);
699 // make a panel with 3 subwindows
701 wxSize
size(400, 200);
703 wxString
strFile("Drop files here!"), strText("Drop text on me");
705 m_ctrlFile
= new wxListBox(this, -1, pos
, size
, 1, &strFile
,
706 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
707 m_ctrlText
= new wxListBox(this, -1, pos
, size
, 1, &strText
,
708 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
710 m_ctrlLog
= new wxTextCtrl(this, -1, "", pos
, size
,
711 wxTE_MULTILINE
| wxTE_READONLY
|
715 // redirect log messages to the text window and switch on OLE messages
717 wxLog
::AddTraceMask(wxTRACE_OleCalls
);
719 m_pLog
= new wxLogTextCtrl(m_ctrlLog
);
720 m_pLogPrev
= wxLog
::SetActiveTarget(m_pLog
);
722 // associate drop targets with 2 text controls
723 m_ctrlFile
->SetDropTarget(new DnDFile(m_ctrlFile
));
724 m_ctrlText
->SetDropTarget(new DnDText(m_ctrlText
));
726 wxLayoutConstraints
*c
;
729 c
= new wxLayoutConstraints
;
730 c
->left
.SameAs(this, wxLeft
);
731 c
->top
.SameAs(this, wxTop
);
732 c
->right
.PercentOf(this, wxRight
, 50);
733 c
->height
.PercentOf(this, wxHeight
, 30);
734 m_ctrlFile
->SetConstraints(c
);
737 c
= new wxLayoutConstraints
;
738 c
->left
.SameAs (m_ctrlFile
, wxRight
);
739 c
->top
.SameAs (this, wxTop
);
740 c
->right
.SameAs (this, wxRight
);
741 c
->height
.PercentOf(this, wxHeight
, 30);
742 m_ctrlText
->SetConstraints(c
);
744 // Lower text control
745 c
= new wxLayoutConstraints
;
746 c
->left
.SameAs (this, wxLeft
);
747 c
->right
.SameAs (this, wxRight
);
748 c
->height
.PercentOf(this, wxHeight
, 50);
749 c
->top
.SameAs(m_ctrlText
, wxBottom
);
750 m_ctrlLog
->SetConstraints(c
);
755 void DnDFrame
::OnQuit(wxCommandEvent
& WXUNUSED(event
))
760 void DnDFrame
::OnPaint(wxPaintEvent
& WXUNUSED(event
))
764 GetClientSize( &w
, &h
);
767 dc
.SetFont( wxFont( 24, wxDECORATIVE
, wxNORMAL
, wxNORMAL
, FALSE
, "charter" ) );
768 dc
.DrawText( "Drag text from here!", 20, h
-50 );
772 // 4/5 is 80% taken by other windows, 20 is arbitrary margin
773 dc
.DrawBitmap(m_bitmap
,
774 w
- m_bitmap
.GetWidth() - 20,
779 void DnDFrame
::OnUpdateUIPasteText(wxUpdateUIEvent
& event
)
781 event
.Enable( wxTheClipboard
->IsSupported(wxDF_TEXT
) );
784 void DnDFrame
::OnUpdateUIPasteBitmap(wxUpdateUIEvent
& event
)
786 event
.Enable( wxTheClipboard
->IsSupported(wxDF_BITMAP
) );
789 void DnDFrame
::OnNewFrame(wxCommandEvent
& WXUNUSED(event
))
791 (new DnDShapeFrame(this))->Show(TRUE
);
793 wxLogStatus(this, "Double click the new frame to select a shape for it");
796 void DnDFrame
::OnDrag(wxCommandEvent
& WXUNUSED(event
))
798 wxString strText
= wxGetTextFromUser
800 "After you enter text in this dialog, press any mouse\n"
801 "button in the bottom (empty) part of the frame and \n"
802 "drag it anywhere - you will be in fact dragging the\n"
803 "text object containing this text",
804 "Please enter some text", m_strText
, this
810 void DnDFrame
::OnAbout(wxCommandEvent
& WXUNUSED(event
))
812 wxMessageBox("Drag-&-Drop Demo\n"
813 "Please see \"Help|Help...\" for details\n"
814 "Copyright (c) 1998 Vadim Zeitlin",
816 wxICON_INFORMATION
| wxOK
,
820 void DnDFrame
::OnHelp(wxCommandEvent
& /* event */)
822 wxMessageDialog
dialog(this,
823 "This small program demonstrates drag & drop support in wxWindows. The program window\n"
824 "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
825 "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
826 "and the right one accepts text.\n"
828 "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
829 "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
830 "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
831 "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
832 "work with files) and see what changes.\n"
834 "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
835 "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
836 "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
837 "change, don't release the mouse button until it does. You can change the string being\n"
838 "dragged in in \"File|Test drag...\" dialog.\n"
841 "Please send all questions/bug reports/suggestions &c to \n"
842 "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
848 void DnDFrame
::OnLogClear(wxCommandEvent
& /* event */ )
853 void DnDFrame
::OnLeftDown(wxMouseEvent
&WXUNUSED(event
) )
855 if ( !m_strText
.IsEmpty() )
857 // start drag operation
858 wxTextDataObject
textData(m_strText
);
859 wxDropSource
source(textData
, this, wxICON(mondrian
));
863 switch ( source
.DoDragDrop(TRUE
) )
865 case wxDragError
: pc
= "Error!"; break;
866 case wxDragNone
: pc
= "Nothing"; break;
867 case wxDragCopy
: pc
= "Copied"; break;
868 case wxDragMove
: pc
= "Moved"; break;
869 case wxDragCancel
: pc
= "Cancelled"; break;
870 default: pc
= "Huh?"; break;
873 SetStatusText(wxString("Drag result: ") + pc
);
877 void DnDFrame
::OnRightDown(wxMouseEvent
&event
)
879 wxMenu
*menu
= new wxMenu
;
881 menu
->Append(Menu_Drag
, "&Test drag...");
882 menu
->Append(Menu_About
, "&About");
883 menu
->Append(Menu_Quit
, "E&xit");
884 menu
->Append(Menu_ToBeDeleted
, "To be deleted");
885 menu
->Append(Menu_ToBeGreyed
, "To be greyed");
887 menu
->Delete( Menu_ToBeDeleted
);
888 menu
->Enable( Menu_ToBeGreyed
, FALSE
);
890 PopupMenu( menu
, event
.GetX(), event
.GetY() );
893 DnDFrame
::~DnDFrame()
895 if ( m_pLog
!= NULL
) {
896 if ( wxLog
::SetActiveTarget(m_pLogPrev
) == m_pLog
)
901 // ---------------------------------------------------------------------------
903 // ---------------------------------------------------------------------------
905 void DnDFrame
::OnCopyBitmap(wxCommandEvent
& WXUNUSED(event
))
907 // PNG support is not always compiled in under Windows, so use BMP there
909 wxFileDialog
dialog(this, "Open a BMP file", "", "", "BMP files (*.bmp)|*.bmp", 0);
911 wxFileDialog
dialog(this, "Open a PNG file", "", "", "PNG files (*.png)|*.png", 0);
914 if (dialog
.ShowModal() != wxID_OK
)
916 wxLogMessage( _T("Aborted file open") );
920 if (dialog
.GetPath().IsEmpty())
922 wxLogMessage( _T("Returned empty string.") );
926 if (!wxFileExists(dialog
.GetPath()))
928 wxLogMessage( _T("File doesn't exist.") );
933 image
.LoadFile( dialog
.GetPath(),
942 wxLogError( _T("Invalid image file...") );
946 wxLogStatus( _T("Decoding image file...") );
949 wxBitmap
bitmap( image
.ConvertToBitmap() );
951 if ( !wxTheClipboard
->Open() )
953 wxLogError(_T("Can't open clipboard."));
958 wxLogMessage( _T("Creating wxBitmapDataObject...") );
961 if ( !wxTheClipboard
->AddData(new wxBitmapDataObject(bitmap
)) )
963 wxLogError(_T("Can't copy image to the clipboard."));
967 wxLogMessage(_T("Image has been put on the clipboard.") );
968 wxLogMessage(_T("You can paste it now and look at it.") );
971 wxTheClipboard
->Close();
974 void DnDFrame
::OnPasteBitmap(wxCommandEvent
& WXUNUSED(event
))
976 if ( !wxTheClipboard
->Open() )
978 wxLogError(_T("Can't open clipboard."));
983 if ( !wxTheClipboard
->IsSupported(wxDF_BITMAP
) )
985 wxLogWarning(_T("No bitmap on clipboard"));
987 wxTheClipboard
->Close();
991 wxBitmapDataObject data
;
992 if ( !wxTheClipboard
->GetData(data
) )
994 wxLogError(_T("Can't paste bitmap from the clipboard"));
998 wxLogMessage(_T("Bitmap pasted from the clipboard") );
999 m_bitmap
= data
.GetBitmap();
1003 wxTheClipboard
->Close();
1006 // ---------------------------------------------------------------------------
1008 // ---------------------------------------------------------------------------
1010 void DnDFrame
::OnCopy(wxCommandEvent
& WXUNUSED(event
))
1012 if ( !wxTheClipboard
->Open() )
1014 wxLogError(_T("Can't open clipboard."));
1019 if ( !wxTheClipboard
->AddData(new wxTextDataObject(m_strText
)) )
1021 wxLogError(_T("Can't copy data to the clipboard"));
1025 wxLogMessage(_T("Text '%s' put on the clipboard"), m_strText
.c_str());
1028 wxTheClipboard
->Close();
1031 void DnDFrame
::OnPaste(wxCommandEvent
& WXUNUSED(event
))
1033 if ( !wxTheClipboard
->Open() )
1035 wxLogError(_T("Can't open clipboard."));
1040 if ( !wxTheClipboard
->IsSupported(wxDF_TEXT
) )
1042 wxLogWarning(_T("No text data on clipboard"));
1044 wxTheClipboard
->Close();
1048 wxTextDataObject text
;
1049 if ( !wxTheClipboard
->GetData(text
) )
1051 wxLogError(_T("Can't paste data from the clipboard"));
1055 wxLogMessage(_T("Text '%s' pasted from the clipboard"),
1056 text
.GetText().c_str());
1059 wxTheClipboard
->Close();
1062 // ----------------------------------------------------------------------------
1063 // Notifications called by the base class
1064 // ----------------------------------------------------------------------------
1066 bool DnDText
::OnDropText(wxCoord
, wxCoord
, const wxString
& text
)
1068 m_pOwner
->Append(text
);
1073 bool DnDFile
::OnDropFiles(wxCoord
, wxCoord
, const wxArrayString
& filenames
)
1075 size_t nFiles
= filenames
.GetCount();
1077 str
.Printf( _T("%d files dropped"), nFiles
);
1078 m_pOwner
->Append(str
);
1079 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
1080 m_pOwner
->Append(filenames
[n
]);
1086 // ----------------------------------------------------------------------------
1088 // ----------------------------------------------------------------------------
1090 DnDShapeDialog
::DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
)
1094 LoadFromResource(parent
, "dialogShape");
1096 m_textX
= (wxTextCtrl
*)wxFindWindowByName("textX", this);
1097 m_textY
= (wxTextCtrl
*)wxFindWindowByName("textY", this);
1098 m_textW
= (wxTextCtrl
*)wxFindWindowByName("textW", this);
1099 m_textH
= (wxTextCtrl
*)wxFindWindowByName("textH", this);
1101 m_radio
= (wxRadioBox
*)wxFindWindowByName("radio", this);
1104 DnDShape
*DnDShapeDialog
::GetShape() const
1106 switch ( m_shapeKind
)
1109 case DnDShape
::None
: return NULL
;
1110 case DnDShape
::Triangle
: return new DnDTriangularShape(m_pos
, m_size
, m_col
);
1111 case DnDShape
::Rectangle
: return new DnDRectangularShape(m_pos
, m_size
, m_col
);
1112 case DnDShape
::Ellipse
: return new DnDEllipticShape(m_pos
, m_size
, m_col
);
1116 bool DnDShapeDialog
::TransferDataToWindow()
1121 m_radio
->SetSelection(m_shape
->GetKind());
1122 m_pos
= m_shape
->GetPosition();
1123 m_size
= m_shape
->GetSize();
1124 m_col
= m_shape
->GetColour();
1128 m_radio
->SetSelection(DnDShape
::None
);
1129 m_pos
= wxPoint(1, 1);
1130 m_size
= wxSize(100, 100);
1133 m_textX
->SetValue(wxString() << m_pos
.x
);
1134 m_textY
->SetValue(wxString() << m_pos
.y
);
1135 m_textW
->SetValue(wxString() << m_size
.x
);
1136 m_textH
->SetValue(wxString() << m_size
.y
);
1141 bool DnDShapeDialog
::TransferDataFromWindow()
1143 m_shapeKind
= (DnDShape
::Kind
)m_radio
->GetSelection();
1145 m_pos
.x
= atoi(m_textX
->GetValue());
1146 m_pos
.y
= atoi(m_textY
->GetValue());
1147 m_size
.x
= atoi(m_textW
->GetValue());
1148 m_size
.y
= atoi(m_textH
->GetValue());
1150 if ( !m_pos
.x
|| !m_pos
.y
|| !m_size
.x
|| !m_size
.y
)
1152 wxMessageBox("All sizes and positions should be non null!",
1153 "Invalid shape", wxICON_HAND
| wxOK
, this);
1161 void DnDShapeDialog
::OnColour(wxCommandEvent
& WXUNUSED(event
))
1164 data
.SetChooseFull(TRUE
);
1165 for (int i
= 0; i
< 16; i
++)
1167 wxColour
colour(i
*16, i
*16, i
*16);
1168 data
.SetCustomColour(i
, colour
);
1171 wxColourDialog
dialog(this, &data
);
1172 if ( dialog
.ShowModal() == wxID_OK
)
1174 m_col
= dialog
.GetColourData().GetColour();
1178 // ----------------------------------------------------------------------------
1180 // ----------------------------------------------------------------------------
1182 DnDShapeFrame
*DnDShapeFrame
::ms_lastDropTarget
= NULL
;
1184 DnDShapeFrame
::DnDShapeFrame(wxFrame
*parent
)
1185 : wxFrame(parent
, -1, "Shape Frame",
1186 wxDefaultPosition
, wxSize(250, 150))
1188 SetBackgroundColour(*wxWHITE
);
1192 wxMenu
*menuShape
= new wxMenu
;
1193 menuShape
->Append(Menu_Shape_New
, "&New default shape\tCtrl-S");
1194 menuShape
->Append(Menu_Shape_Edit
, "&Edit shape\tCtrl-E");
1195 menuShape
->AppendSeparator();
1196 menuShape
->Append(Menu_Shape_Clear
, "&Clear shape\tDel");
1198 wxMenu
*menuClipboard
= new wxMenu
;
1199 menuClipboard
->Append(Menu_ShapeClipboard_Copy
, "&Copy\tCtrl-C");
1200 menuClipboard
->Append(Menu_ShapeClipboard_Paste
, "&Paste\tCtrl-V");
1202 wxMenuBar
*menubar
= new wxMenuBar
;
1203 menubar
->Append(menuShape
, "&Shape");
1204 menubar
->Append(menuClipboard
, "&Clipboard");
1206 SetMenuBar(menubar
);
1208 SetStatusText("Press Ctrl-S to create a new shape");
1210 SetDropTarget(new DnDShapeDropTarget(this));
1215 DnDShapeFrame
::~DnDShapeFrame()
1220 void DnDShapeFrame
::SetShape(DnDShape
*shape
)
1228 void DnDShapeFrame
::OnDrag(wxMouseEvent
& event
)
1237 // start drag operation
1238 DnDShapeDataObject
shapeData(m_shape
);
1239 wxDropSource
source(shapeData
, this, wxICON(mondrian
));
1241 const char *pc
= NULL
;
1242 switch ( source
.DoDragDrop(TRUE
) )
1246 wxLogError("An error occured during drag and drop operation");
1250 SetStatusText("Nothing happened");
1259 if ( ms_lastDropTarget
!= this )
1261 // don't delete the shape if we dropped it on ourselves!
1267 SetStatusText("Drag and drop operation cancelled");
1273 SetStatusText(wxString("Shape successfully ") + pc
);
1275 //else: status text already set
1278 void DnDShapeFrame
::OnDrop(long x
, long y
, DnDShape
*shape
)
1280 ms_lastDropTarget
= this;
1283 s
.Printf("Shape dropped at (%ld, %ld)", x
, y
);
1286 shape
->Move(ScreenToClient(wxPoint(x
, y
)));
1290 void DnDShapeFrame
::OnEditShape(wxCommandEvent
& event
)
1292 DnDShapeDialog
dlg(this, m_shape
);
1293 if ( dlg
.ShowModal() == wxID_OK
)
1295 SetShape(dlg
.GetShape());
1299 SetStatusText("You can now drag the shape to another frame");
1304 void DnDShapeFrame
::OnNewShape(wxCommandEvent
& event
)
1306 SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED
));
1308 SetStatusText("You can now drag the shape to another frame");
1311 void DnDShapeFrame
::OnClearShape(wxCommandEvent
& event
)
1316 void DnDShapeFrame
::OnCopyShape(wxCommandEvent
& event
)
1320 wxClipboardLocker clipLocker
;
1323 wxLogError("Can't open the clipboard");
1328 wxTheClipboard
->AddData(new DnDShapeDataObject(m_shape
));
1332 void DnDShapeFrame
::OnPasteShape(wxCommandEvent
& event
)
1334 wxClipboardLocker clipLocker
;
1337 wxLogError("Can't open the clipboard");
1342 DnDShapeDataObject
shapeDataObject(NULL
);
1343 if ( wxTheClipboard
->GetData(shapeDataObject
) )
1345 SetShape(shapeDataObject
.GetShape());
1349 wxLogStatus("No shape on the clipboard");
1353 void DnDShapeFrame
::OnUpdateUICopy(wxUpdateUIEvent
& event
)
1355 event
.Enable( m_shape
!= NULL
);
1358 void DnDShapeFrame
::OnUpdateUIPaste(wxUpdateUIEvent
& event
)
1360 event
.Enable( wxTheClipboard
->IsSupported(wxDataFormat(shapeFormatId
)) );
1363 void DnDShapeFrame
::OnPaint(wxPaintEvent
& event
)
1377 // ----------------------------------------------------------------------------
1379 // ----------------------------------------------------------------------------
1381 DnDShape
*DnDShape
::New(const void *buf
)
1383 const ShapeDump
& dump
= *(const ShapeDump
*)buf
;
1387 return new DnDTriangularShape(wxPoint(dump
.x
, dump
.y
),
1388 wxSize(dump
.w
, dump
.h
),
1389 wxColour(dump
.r
, dump
.g
, dump
.b
));
1392 return new DnDRectangularShape(wxPoint(dump
.x
, dump
.y
),
1393 wxSize(dump
.w
, dump
.h
),
1394 wxColour(dump
.r
, dump
.g
, dump
.b
));
1397 return new DnDEllipticShape(wxPoint(dump
.x
, dump
.y
),
1398 wxSize(dump
.w
, dump
.h
),
1399 wxColour(dump
.r
, dump
.g
, dump
.b
));
1402 wxFAIL_MSG("invalid shape!");
1407 // ----------------------------------------------------------------------------
1408 // DnDShapeDataObject
1409 // ----------------------------------------------------------------------------
1411 void DnDShapeDataObject
::CreateBitmap() const
1413 wxPoint pos
= m_shape
->GetPosition();
1414 wxSize size
= m_shape
->GetSize();
1415 int x
= pos
.x
+ size
.x
,
1417 wxBitmap
bitmap(x
, y
);
1419 dc
.SelectObject(bitmap
);
1420 dc
.SetBrush(wxBrush("white", wxSOLID
));
1423 dc
.SelectObject(wxNullBitmap
);
1425 DnDShapeDataObject
*self
= (DnDShapeDataObject
*)this; // const_cast
1426 self
->m_dataobj
.SetBitmap(bitmap
);
1427 self
->m_hasBitmap
= TRUE
;