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
);
423 wxASSERT_MSG( format
== wxDF_BITMAP
, "unsupported format" );
428 return m_dataobj
.GetDataHere(pBuf
);
432 virtual bool SetData(const wxDataFormat
& format
,
433 size_t len
, const void *buf
)
435 wxCHECK_MSG( format
== m_formatShape
, FALSE
, "unsupported format" );
438 m_shape
= DnDShape::New(buf
);
440 // the shape has changed
447 // creates a bitmap and assigns it to m_dataobj (also sets m_hasBitmap)
448 void CreateBitmap() const;
450 wxDataFormat m_formatShape
; // our custom format
452 wxBitmapDataObject m_dataobj
; // it handles bitmaps
453 bool m_hasBitmap
; // true if m_dataobj has valid bitmap
455 DnDShape
*m_shape
; // our data
458 // ----------------------------------------------------------------------------
459 // A dialog to edit shape properties
460 // ----------------------------------------------------------------------------
462 class DnDShapeDialog
: public wxDialog
465 DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
);
467 DnDShape
*GetShape() const;
469 virtual bool TransferDataToWindow();
470 virtual bool TransferDataFromWindow();
472 void OnColour(wxCommandEvent
& event
);
479 DnDShape::Kind m_shapeKind
;
491 DECLARE_EVENT_TABLE()
494 // ----------------------------------------------------------------------------
495 // A frame for the shapes which can be drag-and-dropped between frames
496 // ----------------------------------------------------------------------------
498 class DnDShapeFrame
: public wxFrame
501 DnDShapeFrame(wxFrame
*parent
);
504 void SetShape(DnDShape
*shape
);
507 void OnNewShape(wxCommandEvent
& event
);
508 void OnEditShape(wxCommandEvent
& event
);
509 void OnClearShape(wxCommandEvent
& event
);
511 void OnCopyShape(wxCommandEvent
& event
);
512 void OnPasteShape(wxCommandEvent
& event
);
514 void OnUpdateUICopy(wxUpdateUIEvent
& event
);
515 void OnUpdateUIPaste(wxUpdateUIEvent
& event
);
517 void OnDrag(wxMouseEvent
& event
);
518 void OnPaint(wxPaintEvent
& event
);
519 void OnDrop(wxCoord x
, wxCoord y
, DnDShape
*shape
);
524 static DnDShapeFrame
*ms_lastDropTarget
;
526 DECLARE_EVENT_TABLE()
529 // ----------------------------------------------------------------------------
530 // wxDropTarget derivation for DnDShapes
531 // ----------------------------------------------------------------------------
533 class DnDShapeDropTarget
: public wxDropTarget
536 DnDShapeDropTarget(DnDShapeFrame
*frame
)
537 : wxDropTarget(new DnDShapeDataObject
)
542 // override base class (pure) virtuals
543 virtual void OnEnter()
544 { m_frame
->SetStatusText("Mouse entered the frame"); }
545 virtual void OnLeave()
546 { m_frame
->SetStatusText("Mouse left the frame"); }
547 virtual bool OnData(wxCoord x
, wxCoord y
)
551 wxLogError("Failed to get drag and drop data");
556 m_frame
->OnDrop(x
, y
,
557 ((DnDShapeDataObject
*)GetDataObject())->GetShape());
563 DnDShapeFrame
*m_frame
;
566 // ----------------------------------------------------------------------------
567 // IDs for the menu commands
568 // ----------------------------------------------------------------------------
582 Menu_ToBeGreyed
, /* for testing */
583 Menu_ToBeDeleted
, /* for testing */
584 Menu_Shape_New
= 500,
587 Menu_ShapeClipboard_Copy
,
588 Menu_ShapeClipboard_Paste
,
592 BEGIN_EVENT_TABLE(DnDFrame
, wxFrame
)
593 EVT_MENU(Menu_Quit
, DnDFrame::OnQuit
)
594 EVT_MENU(Menu_About
, DnDFrame::OnAbout
)
595 EVT_MENU(Menu_Drag
, DnDFrame::OnDrag
)
596 EVT_MENU(Menu_NewFrame
, DnDFrame::OnNewFrame
)
597 EVT_MENU(Menu_Help
, DnDFrame::OnHelp
)
598 EVT_MENU(Menu_Clear
, DnDFrame::OnLogClear
)
599 EVT_MENU(Menu_Copy
, DnDFrame::OnCopy
)
600 EVT_MENU(Menu_Paste
, DnDFrame::OnPaste
)
601 EVT_MENU(Menu_CopyBitmap
, DnDFrame::OnCopyBitmap
)
602 EVT_MENU(Menu_PasteBitmap
,DnDFrame::OnPasteBitmap
)
604 EVT_UPDATE_UI(Menu_Paste
, DnDFrame::OnUpdateUIPasteText
)
605 EVT_UPDATE_UI(Menu_PasteBitmap
, DnDFrame::OnUpdateUIPasteBitmap
)
607 EVT_LEFT_DOWN( DnDFrame::OnLeftDown
)
608 EVT_RIGHT_DOWN( DnDFrame::OnRightDown
)
609 EVT_PAINT( DnDFrame::OnPaint
)
612 BEGIN_EVENT_TABLE(DnDShapeFrame
, wxFrame
)
613 EVT_MENU(Menu_Shape_New
, DnDShapeFrame::OnNewShape
)
614 EVT_MENU(Menu_Shape_Edit
, DnDShapeFrame::OnEditShape
)
615 EVT_MENU(Menu_Shape_Clear
, DnDShapeFrame::OnClearShape
)
617 EVT_MENU(Menu_ShapeClipboard_Copy
, DnDShapeFrame::OnCopyShape
)
618 EVT_MENU(Menu_ShapeClipboard_Paste
, DnDShapeFrame::OnPasteShape
)
620 EVT_UPDATE_UI(Menu_ShapeClipboard_Copy
, DnDShapeFrame::OnUpdateUICopy
)
621 EVT_UPDATE_UI(Menu_ShapeClipboard_Paste
, DnDShapeFrame::OnUpdateUIPaste
)
623 EVT_LEFT_DOWN(DnDShapeFrame::OnDrag
)
625 EVT_PAINT(DnDShapeFrame::OnPaint
)
628 BEGIN_EVENT_TABLE(DnDShapeDialog
, wxDialog
)
629 EVT_BUTTON(Button_Colour
, OnColour
)
632 // ============================================================================
634 // ============================================================================
636 // `Main program' equivalent, creating windows and returning main app frame
637 bool DnDApp::OnInit()
639 // load our ressources
643 pathList
.Add("./Debug");
644 pathList
.Add("./Release");
647 wxString path
= pathList
.FindValidPath("dnd.wxr");
650 wxLogError("Can't find the resource file dnd.wxr in the current "
651 "directory, aborting.");
656 wxDefaultResourceTable
->ParseResourceFile(path
);
659 wxImage::AddHandler( new wxPNGHandler
);
662 // create the main frame window
663 DnDFrame
*frame
= new DnDFrame((wxFrame
*) NULL
,
664 "Drag-and-Drop/Clipboard wxWindows Sample",
675 DnDFrame::DnDFrame(wxFrame
*frame
, char *title
, int x
, int y
, int w
, int h
)
676 : wxFrame(frame
, -1, title
, wxPoint(x
, y
), wxSize(w
, h
)),
677 m_strText("wxWindows drag & drop works :-)")
680 // frame icon and status bar
681 SetIcon(wxICON(mondrian
));
686 wxMenu
*file_menu
= new wxMenu
;
687 file_menu
->Append(Menu_Drag
, "&Test drag...");
688 file_menu
->AppendSeparator();
689 file_menu
->Append(Menu_NewFrame
, "&New frame\tCtrl-N");
690 file_menu
->AppendSeparator();
691 file_menu
->Append(Menu_Quit
, "E&xit");
693 wxMenu
*log_menu
= new wxMenu
;
694 log_menu
->Append(Menu_Clear
, "Clear\tDel");
696 wxMenu
*help_menu
= new wxMenu
;
697 help_menu
->Append(Menu_Help
, "&Help...");
698 help_menu
->AppendSeparator();
699 help_menu
->Append(Menu_About
, "&About");
701 wxMenu
*clip_menu
= new wxMenu
;
702 clip_menu
->Append(Menu_Copy
, "&Copy text\tCtrl+C");
703 clip_menu
->Append(Menu_Paste
, "&Paste text\tCtrl+V");
704 clip_menu
->AppendSeparator();
705 clip_menu
->Append(Menu_CopyBitmap
, "&Copy bitmap\tAlt+C");
706 clip_menu
->Append(Menu_PasteBitmap
, "&Paste bitmap\tAlt+V");
708 wxMenuBar
*menu_bar
= new wxMenuBar
;
709 menu_bar
->Append(file_menu
, "&File");
710 menu_bar
->Append(log_menu
, "&Log");
711 menu_bar
->Append(clip_menu
, "&Clipboard");
712 menu_bar
->Append(help_menu
, "&Help");
714 SetMenuBar(menu_bar
);
716 // make a panel with 3 subwindows
718 wxSize
size(400, 200);
720 wxString
strFile("Drop files here!"), strText("Drop text on me");
722 m_ctrlFile
= new wxListBox(this, -1, pos
, size
, 1, &strFile
,
723 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
724 m_ctrlText
= new wxListBox(this, -1, pos
, size
, 1, &strText
,
725 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
727 m_ctrlLog
= new wxTextCtrl(this, -1, "", pos
, size
,
728 wxTE_MULTILINE
| wxTE_READONLY
|
732 // redirect log messages to the text window and switch on OLE messages
734 wxLog::AddTraceMask(wxTRACE_OleCalls
);
736 m_pLog
= new wxLogTextCtrl(m_ctrlLog
);
737 m_pLogPrev
= wxLog::SetActiveTarget(m_pLog
);
739 // associate drop targets with 2 text controls
740 m_ctrlFile
->SetDropTarget(new DnDFile(m_ctrlFile
));
741 m_ctrlText
->SetDropTarget(new DnDText(m_ctrlText
));
743 wxLayoutConstraints
*c
;
746 c
= new wxLayoutConstraints
;
747 c
->left
.SameAs(this, wxLeft
);
748 c
->top
.SameAs(this, wxTop
);
749 c
->right
.PercentOf(this, wxRight
, 50);
750 c
->height
.PercentOf(this, wxHeight
, 30);
751 m_ctrlFile
->SetConstraints(c
);
754 c
= new wxLayoutConstraints
;
755 c
->left
.SameAs (m_ctrlFile
, wxRight
);
756 c
->top
.SameAs (this, wxTop
);
757 c
->right
.SameAs (this, wxRight
);
758 c
->height
.PercentOf(this, wxHeight
, 30);
759 m_ctrlText
->SetConstraints(c
);
761 // Lower text control
762 c
= new wxLayoutConstraints
;
763 c
->left
.SameAs (this, wxLeft
);
764 c
->right
.SameAs (this, wxRight
);
765 c
->height
.PercentOf(this, wxHeight
, 50);
766 c
->top
.SameAs(m_ctrlText
, wxBottom
);
767 m_ctrlLog
->SetConstraints(c
);
772 void DnDFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
))
777 void DnDFrame::OnPaint(wxPaintEvent
& WXUNUSED(event
))
781 GetClientSize( &w
, &h
);
784 dc
.SetFont( wxFont( 24, wxDECORATIVE
, wxNORMAL
, wxNORMAL
, FALSE
, "charter" ) );
785 dc
.DrawText( "Drag text from here!", 20, h
-50 );
789 // 4/5 is 80% taken by other windows, 20 is arbitrary margin
790 dc
.DrawBitmap(m_bitmap
,
791 w
- m_bitmap
.GetWidth() - 20,
796 void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent
& event
)
798 event
.Enable( wxTheClipboard
->IsSupported(wxDF_TEXT
) );
801 void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent
& event
)
803 event
.Enable( wxTheClipboard
->IsSupported(wxDF_BITMAP
) );
806 void DnDFrame::OnNewFrame(wxCommandEvent
& WXUNUSED(event
))
808 (new DnDShapeFrame(this))->Show(TRUE
);
810 wxLogStatus(this, "Double click the new frame to select a shape for it");
813 void DnDFrame::OnDrag(wxCommandEvent
& WXUNUSED(event
))
815 wxString strText
= wxGetTextFromUser
817 "After you enter text in this dialog, press any mouse\n"
818 "button in the bottom (empty) part of the frame and \n"
819 "drag it anywhere - you will be in fact dragging the\n"
820 "text object containing this text",
821 "Please enter some text", m_strText
, this
827 void DnDFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
829 wxMessageBox("Drag-&-Drop Demo\n"
830 "Please see \"Help|Help...\" for details\n"
831 "Copyright (c) 1998 Vadim Zeitlin",
833 wxICON_INFORMATION
| wxOK
,
837 void DnDFrame::OnHelp(wxCommandEvent
& /* event */)
839 wxMessageDialog
dialog(this,
840 "This small program demonstrates drag & drop support in wxWindows. The program window\n"
841 "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
842 "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
843 "and the right one accepts text.\n"
845 "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
846 "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
847 "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
848 "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
849 "work with files) and see what changes.\n"
851 "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
852 "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
853 "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
854 "change, don't release the mouse button until it does. You can change the string being\n"
855 "dragged in in \"File|Test drag...\" dialog.\n"
858 "Please send all questions/bug reports/suggestions &c to \n"
859 "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
865 void DnDFrame::OnLogClear(wxCommandEvent
& /* event */ )
870 void DnDFrame::OnLeftDown(wxMouseEvent
&WXUNUSED(event
) )
872 if ( !m_strText
.IsEmpty() )
874 // start drag operation
875 wxTextDataObject
textData(m_strText
);
876 wxDropSource
source(textData
, this, wxICON(mondrian
));
880 switch ( source
.DoDragDrop(TRUE
) )
882 case wxDragError
: pc
= "Error!"; break;
883 case wxDragNone
: pc
= "Nothing"; break;
884 case wxDragCopy
: pc
= "Copied"; break;
885 case wxDragMove
: pc
= "Moved"; break;
886 case wxDragCancel
: pc
= "Cancelled"; break;
887 default: pc
= "Huh?"; break;
890 SetStatusText(wxString("Drag result: ") + pc
);
894 void DnDFrame::OnRightDown(wxMouseEvent
&event
)
896 wxMenu
*menu
= new wxMenu
;
898 menu
->Append(Menu_Drag
, "&Test drag...");
899 menu
->Append(Menu_About
, "&About");
900 menu
->Append(Menu_Quit
, "E&xit");
901 menu
->Append(Menu_ToBeDeleted
, "To be deleted");
902 menu
->Append(Menu_ToBeGreyed
, "To be greyed");
904 menu
->Delete( Menu_ToBeDeleted
);
905 menu
->Enable( Menu_ToBeGreyed
, FALSE
);
907 PopupMenu( menu
, event
.GetX(), event
.GetY() );
910 DnDFrame::~DnDFrame()
912 if ( m_pLog
!= NULL
) {
913 if ( wxLog::SetActiveTarget(m_pLogPrev
) == m_pLog
)
918 // ---------------------------------------------------------------------------
920 // ---------------------------------------------------------------------------
922 void DnDFrame::OnCopyBitmap(wxCommandEvent
& WXUNUSED(event
))
924 // PNG support is not always compiled in under Windows, so use BMP there
926 wxFileDialog
dialog(this, "Open a BMP file", "", "", "BMP files (*.bmp)|*.bmp", 0);
928 wxFileDialog
dialog(this, "Open a PNG file", "", "", "PNG files (*.png)|*.png", 0);
931 if (dialog
.ShowModal() != wxID_OK
)
933 wxLogMessage( _T("Aborted file open") );
937 if (dialog
.GetPath().IsEmpty())
939 wxLogMessage( _T("Returned empty string.") );
943 if (!wxFileExists(dialog
.GetPath()))
945 wxLogMessage( _T("File doesn't exist.") );
950 image
.LoadFile( dialog
.GetPath(),
959 wxLogError( _T("Invalid image file...") );
963 wxLogStatus( _T("Decoding image file...") );
966 wxBitmap
bitmap( image
.ConvertToBitmap() );
968 if ( !wxTheClipboard
->Open() )
970 wxLogError(_T("Can't open clipboard."));
975 wxLogMessage( _T("Creating wxBitmapDataObject...") );
978 if ( !wxTheClipboard
->AddData(new wxBitmapDataObject(bitmap
)) )
980 wxLogError(_T("Can't copy image to the clipboard."));
984 wxLogMessage(_T("Image has been put on the clipboard.") );
985 wxLogMessage(_T("You can paste it now and look at it.") );
988 wxTheClipboard
->Close();
991 void DnDFrame::OnPasteBitmap(wxCommandEvent
& WXUNUSED(event
))
993 if ( !wxTheClipboard
->Open() )
995 wxLogError(_T("Can't open clipboard."));
1000 if ( !wxTheClipboard
->IsSupported(wxDF_BITMAP
) )
1002 wxLogWarning(_T("No bitmap on clipboard"));
1004 wxTheClipboard
->Close();
1008 wxBitmapDataObject data
;
1009 if ( !wxTheClipboard
->GetData(data
) )
1011 wxLogError(_T("Can't paste bitmap from the clipboard"));
1015 wxLogMessage(_T("Bitmap pasted from the clipboard") );
1016 m_bitmap
= data
.GetBitmap();
1020 wxTheClipboard
->Close();
1023 // ---------------------------------------------------------------------------
1025 // ---------------------------------------------------------------------------
1027 void DnDFrame::OnCopy(wxCommandEvent
& WXUNUSED(event
))
1029 if ( !wxTheClipboard
->Open() )
1031 wxLogError(_T("Can't open clipboard."));
1036 if ( !wxTheClipboard
->AddData(new wxTextDataObject(m_strText
)) )
1038 wxLogError(_T("Can't copy data to the clipboard"));
1042 wxLogMessage(_T("Text '%s' put on the clipboard"), m_strText
.c_str());
1045 wxTheClipboard
->Close();
1048 void DnDFrame::OnPaste(wxCommandEvent
& WXUNUSED(event
))
1050 if ( !wxTheClipboard
->Open() )
1052 wxLogError(_T("Can't open clipboard."));
1057 if ( !wxTheClipboard
->IsSupported(wxDF_TEXT
) )
1059 wxLogWarning(_T("No text data on clipboard"));
1061 wxTheClipboard
->Close();
1065 wxTextDataObject text
;
1066 if ( !wxTheClipboard
->GetData(text
) )
1068 wxLogError(_T("Can't paste data from the clipboard"));
1072 wxLogMessage(_T("Text '%s' pasted from the clipboard"),
1073 text
.GetText().c_str());
1076 wxTheClipboard
->Close();
1079 // ----------------------------------------------------------------------------
1080 // Notifications called by the base class
1081 // ----------------------------------------------------------------------------
1083 bool DnDText::OnDropText(wxCoord
, wxCoord
, const wxString
& text
)
1085 m_pOwner
->Append(text
);
1090 bool DnDFile::OnDropFiles(wxCoord
, wxCoord
, const wxArrayString
& filenames
)
1092 size_t nFiles
= filenames
.GetCount();
1094 str
.Printf( _T("%d files dropped"), nFiles
);
1095 m_pOwner
->Append(str
);
1096 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
1097 m_pOwner
->Append(filenames
[n
]);
1103 // ----------------------------------------------------------------------------
1105 // ----------------------------------------------------------------------------
1107 DnDShapeDialog::DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
)
1111 LoadFromResource(parent
, "dialogShape");
1113 m_textX
= (wxTextCtrl
*)wxFindWindowByName("textX", this);
1114 m_textY
= (wxTextCtrl
*)wxFindWindowByName("textY", this);
1115 m_textW
= (wxTextCtrl
*)wxFindWindowByName("textW", this);
1116 m_textH
= (wxTextCtrl
*)wxFindWindowByName("textH", this);
1118 m_radio
= (wxRadioBox
*)wxFindWindowByName("radio", this);
1121 DnDShape
*DnDShapeDialog::GetShape() const
1123 switch ( m_shapeKind
)
1126 case DnDShape::None
: return NULL
;
1127 case DnDShape::Triangle
: return new DnDTriangularShape(m_pos
, m_size
, m_col
);
1128 case DnDShape::Rectangle
: return new DnDRectangularShape(m_pos
, m_size
, m_col
);
1129 case DnDShape::Ellipse
: return new DnDEllipticShape(m_pos
, m_size
, m_col
);
1133 bool DnDShapeDialog::TransferDataToWindow()
1138 m_radio
->SetSelection(m_shape
->GetKind());
1139 m_pos
= m_shape
->GetPosition();
1140 m_size
= m_shape
->GetSize();
1141 m_col
= m_shape
->GetColour();
1145 m_radio
->SetSelection(DnDShape::None
);
1146 m_pos
= wxPoint(1, 1);
1147 m_size
= wxSize(100, 100);
1150 m_textX
->SetValue(wxString() << m_pos
.x
);
1151 m_textY
->SetValue(wxString() << m_pos
.y
);
1152 m_textW
->SetValue(wxString() << m_size
.x
);
1153 m_textH
->SetValue(wxString() << m_size
.y
);
1158 bool DnDShapeDialog::TransferDataFromWindow()
1160 m_shapeKind
= (DnDShape::Kind
)m_radio
->GetSelection();
1162 m_pos
.x
= atoi(m_textX
->GetValue());
1163 m_pos
.y
= atoi(m_textY
->GetValue());
1164 m_size
.x
= atoi(m_textW
->GetValue());
1165 m_size
.y
= atoi(m_textH
->GetValue());
1167 if ( !m_pos
.x
|| !m_pos
.y
|| !m_size
.x
|| !m_size
.y
)
1169 wxMessageBox("All sizes and positions should be non null!",
1170 "Invalid shape", wxICON_HAND
| wxOK
, this);
1178 void DnDShapeDialog::OnColour(wxCommandEvent
& WXUNUSED(event
))
1181 data
.SetChooseFull(TRUE
);
1182 for (int i
= 0; i
< 16; i
++)
1184 wxColour
colour(i
*16, i
*16, i
*16);
1185 data
.SetCustomColour(i
, colour
);
1188 wxColourDialog
dialog(this, &data
);
1189 if ( dialog
.ShowModal() == wxID_OK
)
1191 m_col
= dialog
.GetColourData().GetColour();
1195 // ----------------------------------------------------------------------------
1197 // ----------------------------------------------------------------------------
1199 DnDShapeFrame
*DnDShapeFrame::ms_lastDropTarget
= NULL
;
1201 DnDShapeFrame::DnDShapeFrame(wxFrame
*parent
)
1202 : wxFrame(parent
, -1, "Shape Frame",
1203 wxDefaultPosition
, wxSize(250, 150))
1207 wxMenu
*menuShape
= new wxMenu
;
1208 menuShape
->Append(Menu_Shape_New
, "&New default shape\tCtrl-S");
1209 menuShape
->Append(Menu_Shape_Edit
, "&Edit shape\tCtrl-E");
1210 menuShape
->AppendSeparator();
1211 menuShape
->Append(Menu_Shape_Clear
, "&Clear shape\tDel");
1213 wxMenu
*menuClipboard
= new wxMenu
;
1214 menuClipboard
->Append(Menu_ShapeClipboard_Copy
, "&Copy\tCtrl-C");
1215 menuClipboard
->Append(Menu_ShapeClipboard_Paste
, "&Paste\tCtrl-V");
1217 wxMenuBar
*menubar
= new wxMenuBar
;
1218 menubar
->Append(menuShape
, "&Shape");
1219 menubar
->Append(menuClipboard
, "&Clipboard");
1221 SetMenuBar(menubar
);
1223 SetStatusText("Press Ctrl-S to create a new shape");
1225 SetDropTarget(new DnDShapeDropTarget(this));
1229 SetBackgroundColour(*wxWHITE
);
1232 DnDShapeFrame::~DnDShapeFrame()
1238 void DnDShapeFrame::SetShape(DnDShape
*shape
)
1247 void DnDShapeFrame::OnDrag(wxMouseEvent
& event
)
1256 // start drag operation
1257 DnDShapeDataObject
shapeData(m_shape
);
1258 wxDropSource
source(shapeData
, this, wxICON(mondrian
));
1260 const char *pc
= NULL
;
1261 switch ( source
.DoDragDrop(TRUE
) )
1265 wxLogError("An error occured during drag and drop operation");
1269 SetStatusText("Nothing happened");
1278 if ( ms_lastDropTarget
!= this )
1280 // don't delete the shape if we dropped it on ourselves!
1286 SetStatusText("Drag and drop operation cancelled");
1292 SetStatusText(wxString("Shape successfully ") + pc
);
1294 //else: status text already set
1297 void DnDShapeFrame::OnDrop(wxCoord x
, wxCoord y
, DnDShape
*shape
)
1299 ms_lastDropTarget
= this;
1302 #ifdef __WXMSW__ //temporary hack (FIXME)
1303 pt
= ScreenToClient(pt
);
1307 s
.Printf("Shape dropped at (%ld, %ld)", pt
.x
, pt
.y
);
1314 void DnDShapeFrame::OnEditShape(wxCommandEvent
& event
)
1316 DnDShapeDialog
dlg(this, m_shape
);
1317 if ( dlg
.ShowModal() == wxID_OK
)
1319 SetShape(dlg
.GetShape());
1323 SetStatusText("You can now drag the shape to another frame");
1328 void DnDShapeFrame::OnNewShape(wxCommandEvent
& event
)
1330 SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED
));
1332 SetStatusText("You can now drag the shape to another frame");
1335 void DnDShapeFrame::OnClearShape(wxCommandEvent
& event
)
1340 void DnDShapeFrame::OnCopyShape(wxCommandEvent
& event
)
1344 wxClipboardLocker clipLocker
;
1347 wxLogError("Can't open the clipboard");
1352 wxTheClipboard
->AddData(new DnDShapeDataObject(m_shape
));
1356 void DnDShapeFrame::OnPasteShape(wxCommandEvent
& event
)
1358 wxClipboardLocker clipLocker
;
1361 wxLogError("Can't open the clipboard");
1366 DnDShapeDataObject
shapeDataObject(NULL
);
1367 if ( wxTheClipboard
->GetData(shapeDataObject
) )
1369 SetShape(shapeDataObject
.GetShape());
1373 wxLogStatus("No shape on the clipboard");
1377 void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent
& event
)
1379 event
.Enable( m_shape
!= NULL
);
1382 void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent
& event
)
1384 event
.Enable( wxTheClipboard
->IsSupported(wxDataFormat(shapeFormatId
)) );
1387 void DnDShapeFrame::OnPaint(wxPaintEvent
& event
)
1401 // ----------------------------------------------------------------------------
1403 // ----------------------------------------------------------------------------
1405 DnDShape
*DnDShape::New(const void *buf
)
1407 const ShapeDump
& dump
= *(const ShapeDump
*)buf
;
1411 return new DnDTriangularShape(wxPoint(dump
.x
, dump
.y
),
1412 wxSize(dump
.w
, dump
.h
),
1413 wxColour(dump
.r
, dump
.g
, dump
.b
));
1416 return new DnDRectangularShape(wxPoint(dump
.x
, dump
.y
),
1417 wxSize(dump
.w
, dump
.h
),
1418 wxColour(dump
.r
, dump
.g
, dump
.b
));
1421 return new DnDEllipticShape(wxPoint(dump
.x
, dump
.y
),
1422 wxSize(dump
.w
, dump
.h
),
1423 wxColour(dump
.r
, dump
.g
, dump
.b
));
1426 wxFAIL_MSG("invalid shape!");
1431 // ----------------------------------------------------------------------------
1432 // DnDShapeDataObject
1433 // ----------------------------------------------------------------------------
1435 void DnDShapeDataObject::CreateBitmap() const
1437 wxPoint pos
= m_shape
->GetPosition();
1438 wxSize size
= m_shape
->GetSize();
1439 int x
= pos
.x
+ size
.x
,
1441 wxBitmap
bitmap(x
, y
);
1443 dc
.SelectObject(bitmap
);
1444 dc
.SetBrush(wxBrush("white", wxSOLID
));
1447 dc
.SelectObject(wxNullBitmap
);
1449 DnDShapeDataObject
*self
= (DnDShapeDataObject
*)this; // const_cast
1450 self
->m_dataobj
.SetBitmap(bitmap
);
1451 self
->m_hasBitmap
= TRUE
;