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()
623 wxImage::AddHandler( new wxPNGHandler
);
626 // create the main frame window
627 DnDFrame
*frame
= new DnDFrame((wxFrame
*) NULL
,
628 "Drag-and-Drop/Clipboard wxWindows Sample",
636 wxDefaultResourceTable
->ParseResourceFile("dnd.wxr");
641 DnDFrame::DnDFrame(wxFrame
*frame
, char *title
, int x
, int y
, int w
, int h
)
642 : wxFrame(frame
, -1, title
, wxPoint(x
, y
), wxSize(w
, h
)),
643 m_strText("wxWindows drag & drop works :-)")
646 // frame icon and status bar
647 SetIcon(wxICON(mondrian
));
652 wxMenu
*file_menu
= new wxMenu
;
653 file_menu
->Append(Menu_Drag
, "&Test drag...");
654 file_menu
->AppendSeparator();
655 file_menu
->Append(Menu_NewFrame
, "&New frame\tCtrl-N");
656 file_menu
->AppendSeparator();
657 file_menu
->Append(Menu_Quit
, "E&xit");
659 wxMenu
*log_menu
= new wxMenu
;
660 log_menu
->Append(Menu_Clear
, "Clear\tDel");
662 wxMenu
*help_menu
= new wxMenu
;
663 help_menu
->Append(Menu_Help
, "&Help...");
664 help_menu
->AppendSeparator();
665 help_menu
->Append(Menu_About
, "&About");
667 wxMenu
*clip_menu
= new wxMenu
;
668 clip_menu
->Append(Menu_Copy
, "&Copy text\tCtrl+C");
669 clip_menu
->Append(Menu_Paste
, "&Paste text\tCtrl+V");
670 clip_menu
->AppendSeparator();
671 clip_menu
->Append(Menu_CopyBitmap
, "&Copy bitmap\tAlt+C");
672 clip_menu
->Append(Menu_PasteBitmap
, "&Paste bitmap\tAlt+V");
674 wxMenuBar
*menu_bar
= new wxMenuBar
;
675 menu_bar
->Append(file_menu
, "&File");
676 menu_bar
->Append(log_menu
, "&Log");
677 menu_bar
->Append(clip_menu
, "&Clipboard");
678 menu_bar
->Append(help_menu
, "&Help");
680 SetMenuBar(menu_bar
);
682 // make a panel with 3 subwindows
684 wxSize
size(400, 200);
686 wxString
strFile("Drop files here!"), strText("Drop text on me");
688 m_ctrlFile
= new wxListBox(this, -1, pos
, size
, 1, &strFile
,
689 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
690 m_ctrlText
= new wxListBox(this, -1, pos
, size
, 1, &strText
,
691 wxLB_HSCROLL
| wxLB_ALWAYS_SB
);
693 m_ctrlLog
= new wxTextCtrl(this, -1, "", pos
, size
,
694 wxTE_MULTILINE
| wxTE_READONLY
|
698 // redirect log messages to the text window and switch on OLE messages
700 wxLog::AddTraceMask(wxTRACE_OleCalls
);
702 m_pLog
= new wxLogTextCtrl(m_ctrlLog
);
703 m_pLogPrev
= wxLog::SetActiveTarget(m_pLog
);
705 // associate drop targets with 2 text controls
706 m_ctrlFile
->SetDropTarget(new DnDFile(m_ctrlFile
));
707 m_ctrlText
->SetDropTarget(new DnDText(m_ctrlText
));
709 wxLayoutConstraints
*c
;
712 c
= new wxLayoutConstraints
;
713 c
->left
.SameAs(this, wxLeft
);
714 c
->top
.SameAs(this, wxTop
);
715 c
->right
.PercentOf(this, wxRight
, 50);
716 c
->height
.PercentOf(this, wxHeight
, 30);
717 m_ctrlFile
->SetConstraints(c
);
720 c
= new wxLayoutConstraints
;
721 c
->left
.SameAs (m_ctrlFile
, wxRight
);
722 c
->top
.SameAs (this, wxTop
);
723 c
->right
.SameAs (this, wxRight
);
724 c
->height
.PercentOf(this, wxHeight
, 30);
725 m_ctrlText
->SetConstraints(c
);
727 // Lower text control
728 c
= new wxLayoutConstraints
;
729 c
->left
.SameAs (this, wxLeft
);
730 c
->right
.SameAs (this, wxRight
);
731 c
->height
.PercentOf(this, wxHeight
, 50);
732 c
->top
.SameAs(m_ctrlText
, wxBottom
);
733 m_ctrlLog
->SetConstraints(c
);
738 void DnDFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
))
743 void DnDFrame::OnPaint(wxPaintEvent
& WXUNUSED(event
))
747 GetClientSize( &w
, &h
);
750 dc
.SetFont( wxFont( 24, wxDECORATIVE
, wxNORMAL
, wxNORMAL
, FALSE
, "charter" ) );
751 dc
.DrawText( "Drag text from here!", 20, h
-50 );
755 // 4/5 is 80% taken by other windows, 20 is arbitrary margin
756 dc
.DrawBitmap(m_bitmap
,
757 w
- m_bitmap
.GetWidth() - 20,
762 void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent
& event
)
764 event
.Enable( wxTheClipboard
->IsSupported(wxDF_TEXT
) );
767 void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent
& event
)
769 event
.Enable( wxTheClipboard
->IsSupported(wxDF_BITMAP
) );
772 void DnDFrame::OnNewFrame(wxCommandEvent
& WXUNUSED(event
))
774 (new DnDShapeFrame(this))->Show(TRUE
);
776 wxLogStatus(this, "Double click the new frame to select a shape for it");
779 void DnDFrame::OnDrag(wxCommandEvent
& WXUNUSED(event
))
781 wxString strText
= wxGetTextFromUser
783 "After you enter text in this dialog, press any mouse\n"
784 "button in the bottom (empty) part of the frame and \n"
785 "drag it anywhere - you will be in fact dragging the\n"
786 "text object containing this text",
787 "Please enter some text", m_strText
, this
793 void DnDFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
795 wxMessageBox("Drag-&-Drop Demo\n"
796 "Please see \"Help|Help...\" for details\n"
797 "Copyright (c) 1998 Vadim Zeitlin",
799 wxICON_INFORMATION
| wxOK
,
803 void DnDFrame::OnHelp(wxCommandEvent
& /* event */)
805 wxMessageDialog
dialog(this,
806 "This small program demonstrates drag & drop support in wxWindows. The program window\n"
807 "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
808 "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
809 "and the right one accepts text.\n"
811 "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
812 "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
813 "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
814 "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
815 "work with files) and see what changes.\n"
817 "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
818 "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
819 "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
820 "change, don't release the mouse button until it does. You can change the string being\n"
821 "dragged in in \"File|Test drag...\" dialog.\n"
824 "Please send all questions/bug reports/suggestions &c to \n"
825 "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
831 void DnDFrame::OnLogClear(wxCommandEvent
& /* event */ )
836 void DnDFrame::OnLeftDown(wxMouseEvent
&WXUNUSED(event
) )
838 if ( !m_strText
.IsEmpty() )
840 // start drag operation
841 wxTextDataObject
textData(m_strText
);
842 wxDropSource
source(textData
, this, wxICON(mondrian
));
846 switch ( source
.DoDragDrop(TRUE
) )
848 case wxDragError
: pc
= "Error!"; break;
849 case wxDragNone
: pc
= "Nothing"; break;
850 case wxDragCopy
: pc
= "Copied"; break;
851 case wxDragMove
: pc
= "Moved"; break;
852 case wxDragCancel
: pc
= "Cancelled"; break;
853 default: pc
= "Huh?"; break;
856 SetStatusText(wxString("Drag result: ") + pc
);
860 void DnDFrame::OnRightDown(wxMouseEvent
&event
)
862 wxMenu
*menu
= new wxMenu
;
864 menu
->Append(Menu_Drag
, "&Test drag...");
865 menu
->Append(Menu_About
, "&About");
866 menu
->Append(Menu_Quit
, "E&xit");
867 menu
->Append(Menu_ToBeDeleted
, "To be deleted");
868 menu
->Append(Menu_ToBeGreyed
, "To be greyed");
870 menu
->Delete( Menu_ToBeDeleted
);
871 menu
->Enable( Menu_ToBeGreyed
, FALSE
);
873 PopupMenu( menu
, event
.GetX(), event
.GetY() );
876 DnDFrame::~DnDFrame()
878 if ( m_pLog
!= NULL
) {
879 if ( wxLog::SetActiveTarget(m_pLogPrev
) == m_pLog
)
884 // ---------------------------------------------------------------------------
886 // ---------------------------------------------------------------------------
888 void DnDFrame::OnCopyBitmap(wxCommandEvent
& WXUNUSED(event
))
890 // PNG support is not always compiled in under Windows, so use BMP there
892 wxFileDialog
dialog(this, "Open a BMP file", "", "", "BMP files (*.bmp)|*.bmp", 0);
894 wxFileDialog
dialog(this, "Open a PNG file", "", "", "PNG files (*.png)|*.png", 0);
897 if (dialog
.ShowModal() != wxID_OK
)
899 wxLogMessage( _T("Aborted file open") );
903 if (dialog
.GetPath().IsEmpty())
905 wxLogMessage( _T("Returned empty string.") );
909 if (!wxFileExists(dialog
.GetPath()))
911 wxLogMessage( _T("File doesn't exist.") );
916 image
.LoadFile( dialog
.GetPath(),
925 wxLogError( _T("Invalid image file...") );
929 wxLogStatus( _T("Decoding image file...") );
932 wxBitmap
bitmap( image
.ConvertToBitmap() );
934 if ( !wxTheClipboard
->Open() )
936 wxLogError(_T("Can't open clipboard."));
941 wxLogMessage( _T("Creating wxBitmapDataObject...") );
944 if ( !wxTheClipboard
->AddData(new wxBitmapDataObject(bitmap
)) )
946 wxLogError(_T("Can't copy image to the clipboard."));
950 wxLogMessage(_T("Image has been put on the clipboard.") );
951 wxLogMessage(_T("You can paste it now and look at it.") );
954 wxTheClipboard
->Close();
957 void DnDFrame::OnPasteBitmap(wxCommandEvent
& WXUNUSED(event
))
959 if ( !wxTheClipboard
->Open() )
961 wxLogError(_T("Can't open clipboard."));
966 if ( !wxTheClipboard
->IsSupported(wxDF_BITMAP
) )
968 wxLogWarning(_T("No bitmap on clipboard"));
970 wxTheClipboard
->Close();
974 wxBitmapDataObject data
;
975 if ( !wxTheClipboard
->GetData(data
) )
977 wxLogError(_T("Can't paste bitmap from the clipboard"));
981 wxLogMessage(_T("Bitmap pasted from the clipboard") );
982 m_bitmap
= data
.GetBitmap();
986 wxTheClipboard
->Close();
989 // ---------------------------------------------------------------------------
991 // ---------------------------------------------------------------------------
993 void DnDFrame::OnCopy(wxCommandEvent
& WXUNUSED(event
))
995 if ( !wxTheClipboard
->Open() )
997 wxLogError(_T("Can't open clipboard."));
1002 if ( !wxTheClipboard
->AddData(new wxTextDataObject(m_strText
)) )
1004 wxLogError(_T("Can't copy data to the clipboard"));
1008 wxLogMessage(_T("Text '%s' put on the clipboard"), m_strText
.c_str());
1011 wxTheClipboard
->Close();
1014 void DnDFrame::OnPaste(wxCommandEvent
& WXUNUSED(event
))
1016 if ( !wxTheClipboard
->Open() )
1018 wxLogError(_T("Can't open clipboard."));
1023 if ( !wxTheClipboard
->IsSupported(wxDF_TEXT
) )
1025 wxLogWarning(_T("No text data on clipboard"));
1027 wxTheClipboard
->Close();
1031 wxTextDataObject text
;
1032 if ( !wxTheClipboard
->GetData(text
) )
1034 wxLogError(_T("Can't paste data from the clipboard"));
1038 wxLogMessage(_T("Text '%s' pasted from the clipboard"),
1039 text
.GetText().c_str());
1042 wxTheClipboard
->Close();
1045 // ----------------------------------------------------------------------------
1046 // Notifications called by the base class
1047 // ----------------------------------------------------------------------------
1049 bool DnDText::OnDropText(wxCoord
, wxCoord
, const wxString
& text
)
1051 m_pOwner
->Append(text
);
1056 bool DnDFile::OnDropFiles(wxCoord
, wxCoord
, const wxArrayString
& filenames
)
1058 size_t nFiles
= filenames
.GetCount();
1060 str
.Printf( _T("%d files dropped"), nFiles
);
1061 m_pOwner
->Append(str
);
1062 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
1063 m_pOwner
->Append(filenames
[n
]);
1069 // ----------------------------------------------------------------------------
1071 // ----------------------------------------------------------------------------
1073 DnDShapeDialog::DnDShapeDialog(wxFrame
*parent
, DnDShape
*shape
)
1077 LoadFromResource(parent
, "dialogShape");
1079 m_textX
= (wxTextCtrl
*)wxFindWindowByName("textX", this);
1080 m_textY
= (wxTextCtrl
*)wxFindWindowByName("textY", this);
1081 m_textW
= (wxTextCtrl
*)wxFindWindowByName("textW", this);
1082 m_textH
= (wxTextCtrl
*)wxFindWindowByName("textH", this);
1084 m_radio
= (wxRadioBox
*)wxFindWindowByName("radio", this);
1087 DnDShape
*DnDShapeDialog::GetShape() const
1089 switch ( m_shapeKind
)
1092 case DnDShape::None
: return NULL
;
1093 case DnDShape::Triangle
: return new DnDTriangularShape(m_pos
, m_size
, m_col
);
1094 case DnDShape::Rectangle
: return new DnDRectangularShape(m_pos
, m_size
, m_col
);
1095 case DnDShape::Ellipse
: return new DnDEllipticShape(m_pos
, m_size
, m_col
);
1099 bool DnDShapeDialog::TransferDataToWindow()
1104 m_radio
->SetSelection(m_shape
->GetKind());
1105 m_pos
= m_shape
->GetPosition();
1106 m_size
= m_shape
->GetSize();
1107 m_col
= m_shape
->GetColour();
1111 m_radio
->SetSelection(DnDShape::None
);
1112 m_pos
= wxPoint(1, 1);
1113 m_size
= wxSize(100, 100);
1116 m_textX
->SetValue(wxString() << m_pos
.x
);
1117 m_textY
->SetValue(wxString() << m_pos
.y
);
1118 m_textW
->SetValue(wxString() << m_size
.x
);
1119 m_textH
->SetValue(wxString() << m_size
.y
);
1124 bool DnDShapeDialog::TransferDataFromWindow()
1126 m_shapeKind
= (DnDShape::Kind
)m_radio
->GetSelection();
1128 m_pos
.x
= atoi(m_textX
->GetValue());
1129 m_pos
.y
= atoi(m_textY
->GetValue());
1130 m_size
.x
= atoi(m_textW
->GetValue());
1131 m_size
.y
= atoi(m_textH
->GetValue());
1133 if ( !m_pos
.x
|| !m_pos
.y
|| !m_size
.x
|| !m_size
.y
)
1135 wxMessageBox("All sizes and positions should be non null!",
1136 "Invalid shape", wxICON_HAND
| wxOK
, this);
1144 void DnDShapeDialog::OnColour(wxCommandEvent
& WXUNUSED(event
))
1147 data
.SetChooseFull(TRUE
);
1148 for (int i
= 0; i
< 16; i
++)
1150 wxColour
colour(i
*16, i
*16, i
*16);
1151 data
.SetCustomColour(i
, colour
);
1154 wxColourDialog
dialog(this, &data
);
1155 if ( dialog
.ShowModal() == wxID_OK
)
1157 m_col
= dialog
.GetColourData().GetColour();
1161 // ----------------------------------------------------------------------------
1163 // ----------------------------------------------------------------------------
1165 DnDShapeFrame
*DnDShapeFrame::ms_lastDropTarget
= NULL
;
1167 DnDShapeFrame::DnDShapeFrame(wxFrame
*parent
)
1168 : wxFrame(parent
, -1, "Shape Frame",
1169 wxDefaultPosition
, wxSize(250, 150))
1171 SetBackgroundColour(*wxWHITE
);
1175 wxMenu
*menuShape
= new wxMenu
;
1176 menuShape
->Append(Menu_Shape_New
, "&New default shape\tCtrl-S");
1177 menuShape
->Append(Menu_Shape_Edit
, "&Edit shape\tCtrl-E");
1178 menuShape
->AppendSeparator();
1179 menuShape
->Append(Menu_Shape_Clear
, "&Clear shape\tDel");
1181 wxMenu
*menuClipboard
= new wxMenu
;
1182 menuClipboard
->Append(Menu_ShapeClipboard_Copy
, "&Copy\tCtrl-C");
1183 menuClipboard
->Append(Menu_ShapeClipboard_Paste
, "&Paste\tCtrl-V");
1185 wxMenuBar
*menubar
= new wxMenuBar
;
1186 menubar
->Append(menuShape
, "&Shape");
1187 menubar
->Append(menuClipboard
, "&Clipboard");
1189 SetMenuBar(menubar
);
1191 SetStatusText("Press Ctrl-S to create a new shape");
1193 SetDropTarget(new DnDShapeDropTarget(this));
1198 DnDShapeFrame::~DnDShapeFrame()
1203 void DnDShapeFrame::SetShape(DnDShape
*shape
)
1211 void DnDShapeFrame::OnDrag(wxMouseEvent
& event
)
1220 // start drag operation
1221 DnDShapeDataObject
shapeData(m_shape
);
1222 wxDropSource
source(shapeData
, this, wxICON(mondrian
));
1224 const char *pc
= NULL
;
1225 switch ( source
.DoDragDrop(TRUE
) )
1229 wxLogError("An error occured during drag and drop operation");
1233 SetStatusText("Nothing happened");
1242 if ( ms_lastDropTarget
!= this )
1244 // don't delete the shape if we dropped it on ourselves!
1250 SetStatusText("Drag and drop operation cancelled");
1256 SetStatusText(wxString("Shape successfully ") + pc
);
1258 //else: status text already set
1261 void DnDShapeFrame::OnDrop(long x
, long y
, DnDShape
*shape
)
1263 ms_lastDropTarget
= this;
1266 s
.Printf("Shape dropped at (%ld, %ld)", x
, y
);
1269 shape
->Move(ScreenToClient(wxPoint(x
, y
)));
1273 void DnDShapeFrame::OnEditShape(wxCommandEvent
& event
)
1275 DnDShapeDialog
dlg(this, m_shape
);
1276 if ( dlg
.ShowModal() == wxID_OK
)
1278 SetShape(dlg
.GetShape());
1282 SetStatusText("You can now drag the shape to another frame");
1287 void DnDShapeFrame::OnNewShape(wxCommandEvent
& event
)
1289 SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED
));
1291 SetStatusText("You can now drag the shape to another frame");
1294 void DnDShapeFrame::OnClearShape(wxCommandEvent
& event
)
1299 void DnDShapeFrame::OnCopyShape(wxCommandEvent
& event
)
1302 wxTheClipboard
->AddData(new DnDShapeDataObject(m_shape
));
1305 void DnDShapeFrame::OnPasteShape(wxCommandEvent
& event
)
1307 DnDShapeDataObject
shapeDataObject(NULL
);
1308 if ( wxTheClipboard
->GetData(shapeDataObject
) )
1310 SetShape(shapeDataObject
.GetShape());
1314 wxLogStatus("No shape on the clipboard");
1318 void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent
& event
)
1320 event
.Enable( m_shape
!= NULL
);
1323 void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent
& event
)
1325 event
.Enable( wxTheClipboard
->IsSupported(wxDataFormat(shapeFormatId
)) );
1328 void DnDShapeFrame::OnPaint(wxPaintEvent
& event
)
1342 // ----------------------------------------------------------------------------
1344 // ----------------------------------------------------------------------------
1346 DnDShape
*DnDShape::New(const void *buf
)
1348 const ShapeDump
& dump
= *(const ShapeDump
*)buf
;
1352 return new DnDTriangularShape(wxPoint(dump
.x
, dump
.y
),
1353 wxSize(dump
.w
, dump
.h
),
1354 wxColour(dump
.r
, dump
.g
, dump
.b
));
1357 return new DnDRectangularShape(wxPoint(dump
.x
, dump
.y
),
1358 wxSize(dump
.w
, dump
.h
),
1359 wxColour(dump
.r
, dump
.g
, dump
.b
));
1362 return new DnDEllipticShape(wxPoint(dump
.x
, dump
.y
),
1363 wxSize(dump
.w
, dump
.h
),
1364 wxColour(dump
.r
, dump
.g
, dump
.b
));
1367 wxFAIL_MSG("invalid shape!");
1372 // ----------------------------------------------------------------------------
1373 // DnDShapeDataObject
1374 // ----------------------------------------------------------------------------
1376 void DnDShapeDataObject::CreateBitmap() const
1378 wxPoint pos
= m_shape
->GetPosition();
1379 wxSize size
= m_shape
->GetSize();
1380 int x
= pos
.x
+ size
.x
,
1382 wxBitmap
bitmap(x
, y
);
1384 dc
.SelectObject(bitmap
);
1385 dc
.SetBrush(wxBrush("white", wxSOLID
));
1388 dc
.SelectObject(wxNullBitmap
);
1390 DnDShapeDataObject
*self
= (DnDShapeDataObject
*)this; // const_cast
1391 self
->m_dataobj
.SetBitmap(bitmap
);
1392 self
->m_hasBitmap
= TRUE
;