wxGTK pastes text from rxvt again
[wxWidgets.git] / samples / dnd / dnd.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dnd.cpp
3 // Purpose: Drag and drop sample
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright:
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17
18 #ifndef WX_PRECOMP
19 #include "wx/wx.h"
20 #endif
21
22 #if !wxUSE_DRAG_AND_DROP
23 #error This sample requires drag and drop support in the library
24 #endif
25
26 #include "wx/intl.h"
27 #include "wx/log.h"
28
29 #include "wx/dnd.h"
30 #include "wx/dirdlg.h"
31 #include "wx/filedlg.h"
32 #include "wx/image.h"
33 #include "wx/clipbrd.h"
34 #include "wx/colordlg.h"
35 #include "wx/resource.h"
36
37 #if defined(__WXGTK__) || defined(__WXMOTIF__)
38 #include "mondrian.xpm"
39 #endif
40
41 // ----------------------------------------------------------------------------
42 // Derive two simple classes which just put in the listbox the strings (text or
43 // file names) we drop on them
44 // ----------------------------------------------------------------------------
45
46 class DnDText : public wxTextDropTarget
47 {
48 public:
49 DnDText(wxListBox *pOwner) { m_pOwner = pOwner; }
50
51 virtual bool OnDropText(wxCoord x, wxCoord y, const wxString& text);
52
53 private:
54 wxListBox *m_pOwner;
55 };
56
57 class DnDFile : public wxFileDropTarget
58 {
59 public:
60 DnDFile(wxListBox *pOwner) { m_pOwner = pOwner; }
61
62 virtual bool OnDropFiles(wxCoord x, wxCoord y,
63 const wxArrayString& filenames);
64
65 private:
66 wxListBox *m_pOwner;
67 };
68
69 // ----------------------------------------------------------------------------
70 // Define a new application type
71 // ----------------------------------------------------------------------------
72
73 class DnDApp : public wxApp
74 {
75 public:
76 virtual bool OnInit();
77 };
78
79 IMPLEMENT_APP(DnDApp);
80
81 // ----------------------------------------------------------------------------
82 // Define a new frame type for the main frame
83 // ----------------------------------------------------------------------------
84
85 class DnDFrame : public wxFrame
86 {
87 public:
88 DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h);
89 ~DnDFrame();
90
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
99 void OnCopy(wxCommandEvent& event);
100 void OnPaste(wxCommandEvent& event);
101
102 void OnCopyBitmap(wxCommandEvent& event);
103 void OnPasteBitmap(wxCommandEvent& event);
104
105 void OnCopyFiles(wxCommandEvent& event);
106
107 void OnLeftDown(wxMouseEvent& event);
108 void OnRightDown(wxMouseEvent& event);
109
110 void OnUpdateUIPasteText(wxUpdateUIEvent& event);
111 void OnUpdateUIPasteBitmap(wxUpdateUIEvent& event);
112
113 DECLARE_EVENT_TABLE()
114
115 private:
116 wxListBox *m_ctrlFile,
117 *m_ctrlText;
118 wxTextCtrl *m_ctrlLog;
119
120 wxLog *m_pLog,
121 *m_pLogPrev;
122
123 wxString m_strText;
124 wxBitmap m_bitmap;
125 };
126
127 // ----------------------------------------------------------------------------
128 // A shape is an example of application-specific data which may be transported
129 // via drag-and-drop or clipboard: in our case, we have different geometric
130 // shapes, each one with its own colour and position
131 // ----------------------------------------------------------------------------
132
133 class DnDShape
134 {
135 public:
136 enum Kind
137 {
138 None,
139 Triangle,
140 Rectangle,
141 Ellipse
142 };
143
144 DnDShape(const wxPoint& pos,
145 const wxSize& size,
146 const wxColour& col)
147 : m_pos(pos), m_size(size), m_col(col)
148 {
149 }
150
151 // this is for debugging - lets us see when exactly an object is freed
152 // (this may be later than you think if it's on the clipboard, for example)
153 virtual ~DnDShape() { }
154
155 // the functions used for drag-and-drop: they dump and restore a shape into
156 // some bitwise-copiable data (might use streams too...)
157 // ------------------------------------------------------------------------
158
159 // restore from buffer
160 static DnDShape *New(const void *buf);
161
162 virtual size_t GetDataSize() const
163 {
164 return sizeof(ShapeDump);
165 }
166
167 virtual void GetDataHere(void *buf) const
168 {
169 ShapeDump& dump = *(ShapeDump *)buf;
170 dump.x = m_pos.x;
171 dump.y = m_pos.y;
172 dump.w = m_size.x;
173 dump.h = m_size.y;
174 dump.r = m_col.Red();
175 dump.g = m_col.Green();
176 dump.b = m_col.Blue();
177 dump.k = GetKind();
178 }
179
180 // accessors
181 const wxPoint& GetPosition() const { return m_pos; }
182 const wxColour& GetColour() const { return m_col; }
183 const wxSize& GetSize() const { return m_size; }
184
185 void Move(const wxPoint& pos) { m_pos = pos; }
186
187 // to implement in derived classes
188 virtual Kind GetKind() const = 0;
189
190 virtual void Draw(wxDC& dc)
191 {
192 dc.SetPen(wxPen(m_col, 1, wxSOLID));
193 }
194
195 protected:
196 wxPoint GetCentre() const
197 { return wxPoint(m_pos.x + m_size.x / 2, m_pos.y + m_size.y / 2); }
198
199 struct ShapeDump
200 {
201 int x, y, // position
202 w, h, // size
203 r, g, b, // colour
204 k; // kind
205 };
206
207 wxPoint m_pos;
208 wxSize m_size;
209 wxColour m_col;
210 };
211
212 class DnDTriangularShape : public DnDShape
213 {
214 public:
215 DnDTriangularShape(const wxPoint& pos,
216 const wxSize& size,
217 const wxColour& col)
218 : DnDShape(pos, size, col)
219 {
220 wxLogMessage("DnDTriangularShape is being created");
221 }
222
223 virtual ~DnDTriangularShape()
224 {
225 wxLogMessage("DnDTriangularShape is being deleted");
226 }
227
228 virtual Kind GetKind() const { return Triangle; }
229 virtual void Draw(wxDC& dc)
230 {
231 DnDShape::Draw(dc);
232
233 // well, it's a bit difficult to describe a triangle by position and
234 // size, but we're not doing geometry here, do we? ;-)
235 wxPoint p1(m_pos);
236 wxPoint p2(m_pos.x + m_size.x, m_pos.y);
237 wxPoint p3(m_pos.x, m_pos.y + m_size.y);
238
239 dc.DrawLine(p1, p2);
240 dc.DrawLine(p2, p3);
241 dc.DrawLine(p3, p1);
242
243 #ifdef __WXMSW__
244 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
245 #endif
246 }
247 };
248
249 class DnDRectangularShape : public DnDShape
250 {
251 public:
252 DnDRectangularShape(const wxPoint& pos,
253 const wxSize& size,
254 const wxColour& col)
255 : DnDShape(pos, size, col)
256 {
257 wxLogMessage("DnDRectangularShape is being created");
258 }
259
260 virtual ~DnDRectangularShape()
261 {
262 wxLogMessage("DnDRectangularShape is being deleted");
263 }
264
265 virtual Kind GetKind() const { return Rectangle; }
266 virtual void Draw(wxDC& dc)
267 {
268 DnDShape::Draw(dc);
269
270 wxPoint p1(m_pos);
271 wxPoint p2(p1.x + m_size.x, p1.y);
272 wxPoint p3(p2.x, p2.y + m_size.y);
273 wxPoint p4(p1.x, p3.y);
274
275 dc.DrawLine(p1, p2);
276 dc.DrawLine(p2, p3);
277 dc.DrawLine(p3, p4);
278 dc.DrawLine(p4, p1);
279
280 #ifdef __WXMSW__
281 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
282 #endif
283 }
284 };
285
286 class DnDEllipticShape : public DnDShape
287 {
288 public:
289 DnDEllipticShape(const wxPoint& pos,
290 const wxSize& size,
291 const wxColour& col)
292 : DnDShape(pos, size, col)
293 {
294 wxLogMessage("DnDEllipticShape is being created");
295 }
296
297 virtual ~DnDEllipticShape()
298 {
299 wxLogMessage("DnDEllipticShape is being deleted");
300 }
301
302 virtual Kind GetKind() const { return Ellipse; }
303 virtual void Draw(wxDC& dc)
304 {
305 DnDShape::Draw(dc);
306
307 dc.DrawEllipse(m_pos, m_size);
308
309 #ifdef __WXMSW__
310 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
311 #endif
312 }
313 };
314
315 // ----------------------------------------------------------------------------
316 // A wxDataObject specialisation for the application-specific data
317 // ----------------------------------------------------------------------------
318
319 static const char *shapeFormatId = "wxShape";
320
321 class DnDShapeDataObject : public wxDataObject
322 {
323 public:
324 // ctor doesn't copy the pointer, so it shouldn't go away while this object
325 // is alive
326 DnDShapeDataObject(DnDShape *shape = (DnDShape *)NULL)
327 {
328 if ( shape )
329 {
330 // we need to copy the shape because the one we're handled may be
331 // deleted while it's still on the clipboard (for example) - and we
332 // reuse the serialisation methods here to copy it
333 void *buf = malloc(shape->DnDShape::GetDataSize());
334 shape->GetDataHere(buf);
335 m_shape = DnDShape::New(buf);
336
337 free(buf);
338 }
339 else
340 {
341 // nothing to copy
342 m_shape = NULL;
343 }
344
345 // this string should uniquely identify our format, but is otherwise
346 // arbitrary
347 m_formatShape.SetId(shapeFormatId);
348
349 // we don't draw the shape to a bitmap until it's really needed (i.e.
350 // we're asked to do so)
351 m_hasBitmap = FALSE;
352 }
353
354 virtual ~DnDShapeDataObject() { delete m_shape; }
355
356 // after a call to this function, the shape is owned by the caller and it
357 // is responsible for deleting it!
358 //
359 // NB: a better solution would be to make DnDShapes ref counted and this
360 // is what should probably be done in a real life program, otherwise
361 // the ownership problems become too complicated really fast
362 DnDShape *GetShape()
363 {
364 DnDShape *shape = m_shape;
365
366 m_shape = (DnDShape *)NULL;
367 m_hasBitmap = FALSE;
368
369 return shape;
370 }
371
372 // implement base class pure virtuals
373 // ----------------------------------
374
375 virtual wxDataFormat GetPreferredFormat(Direction WXUNUSED(dir)) const
376 {
377 return m_formatShape;
378 }
379
380 virtual size_t GetFormatCount(Direction dir) const
381 {
382 // our custom format is supported by both GetData() and SetData()
383 size_t nFormats = 1;
384 if ( dir == Get )
385 {
386 // but the bitmap format(s) are only supported for output
387 nFormats += m_dataobj.GetFormatCount(dir);
388 }
389
390 return nFormats;
391 }
392
393 virtual void GetAllFormats(wxDataFormat *formats, Direction dir) const
394 {
395 formats[0] = m_formatShape;
396 if ( dir == Get )
397 {
398 m_dataobj.GetAllFormats(&formats[1], dir);
399 }
400 }
401
402 virtual size_t GetDataSize(const wxDataFormat& format) const
403 {
404 if ( format == m_formatShape )
405 {
406 return m_shape->GetDataSize();
407 }
408 else
409 {
410 if ( !m_hasBitmap )
411 CreateBitmap();
412
413 return m_dataobj.GetDataSize();
414 }
415 }
416
417 virtual bool GetDataHere(const wxDataFormat& format, void *pBuf) const
418 {
419 if ( format == m_formatShape )
420 {
421 m_shape->GetDataHere(pBuf);
422
423 return TRUE;
424 }
425 else
426 {
427 if ( !m_hasBitmap )
428 CreateBitmap();
429
430 return m_dataobj.GetDataHere(pBuf);
431 }
432 }
433
434 virtual bool SetData(const wxDataFormat& format,
435 size_t len, const void *buf)
436 {
437 wxCHECK_MSG( format == m_formatShape, FALSE, "unsupported format" );
438
439 delete m_shape;
440 m_shape = DnDShape::New(buf);
441
442 // the shape has changed
443 m_hasBitmap = FALSE;
444
445 return TRUE;
446 }
447
448 private:
449 // creates a bitmap and assigns it to m_dataobj (also sets m_hasBitmap)
450 void CreateBitmap() const;
451
452 wxDataFormat m_formatShape; // our custom format
453
454 wxBitmapDataObject m_dataobj; // it handles bitmaps
455 bool m_hasBitmap; // true if m_dataobj has valid bitmap
456
457 DnDShape *m_shape; // our data
458 };
459
460 // ----------------------------------------------------------------------------
461 // A dialog to edit shape properties
462 // ----------------------------------------------------------------------------
463
464 class DnDShapeDialog : public wxDialog
465 {
466 public:
467 DnDShapeDialog(wxFrame *parent, DnDShape *shape);
468
469 DnDShape *GetShape() const;
470
471 virtual bool TransferDataToWindow();
472 virtual bool TransferDataFromWindow();
473
474 void OnColour(wxCommandEvent& event);
475
476 private:
477 // input
478 DnDShape *m_shape;
479
480 // output
481 DnDShape::Kind m_shapeKind;
482 wxPoint m_pos;
483 wxSize m_size;
484 wxColour m_col;
485
486 // controls
487 wxRadioBox *m_radio;
488 wxTextCtrl *m_textX,
489 *m_textY,
490 *m_textW,
491 *m_textH;
492
493 DECLARE_EVENT_TABLE()
494 };
495
496 // ----------------------------------------------------------------------------
497 // A frame for the shapes which can be drag-and-dropped between frames
498 // ----------------------------------------------------------------------------
499
500 class DnDShapeFrame : public wxFrame
501 {
502 public:
503 DnDShapeFrame(wxFrame *parent);
504 ~DnDShapeFrame();
505
506 void SetShape(DnDShape *shape);
507
508 // callbacks
509 void OnNewShape(wxCommandEvent& event);
510 void OnEditShape(wxCommandEvent& event);
511 void OnClearShape(wxCommandEvent& event);
512
513 void OnCopyShape(wxCommandEvent& event);
514 void OnPasteShape(wxCommandEvent& event);
515
516 void OnUpdateUICopy(wxUpdateUIEvent& event);
517 void OnUpdateUIPaste(wxUpdateUIEvent& event);
518
519 void OnDrag(wxMouseEvent& event);
520 void OnPaint(wxPaintEvent& event);
521 void OnDrop(wxCoord x, wxCoord y, DnDShape *shape);
522
523 private:
524 DnDShape *m_shape;
525
526 static DnDShapeFrame *ms_lastDropTarget;
527
528 DECLARE_EVENT_TABLE()
529 };
530
531 // ----------------------------------------------------------------------------
532 // wxDropTarget derivation for DnDShapes
533 // ----------------------------------------------------------------------------
534
535 class DnDShapeDropTarget : public wxDropTarget
536 {
537 public:
538 DnDShapeDropTarget(DnDShapeFrame *frame)
539 : wxDropTarget(new DnDShapeDataObject)
540 {
541 m_frame = frame;
542 }
543
544 // override base class (pure) virtuals
545 virtual void OnEnter()
546 { m_frame->SetStatusText("Mouse entered the frame"); }
547 virtual void OnLeave()
548 { m_frame->SetStatusText("Mouse left the frame"); }
549 virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def)
550 {
551 if ( !GetData() )
552 {
553 wxLogError("Failed to get drag and drop data");
554
555 return wxDragNone;
556 }
557
558 m_frame->OnDrop(x, y,
559 ((DnDShapeDataObject *)GetDataObject())->GetShape());
560
561 return def;
562 }
563
564 private:
565 DnDShapeFrame *m_frame;
566 };
567
568 // ----------------------------------------------------------------------------
569 // IDs for the menu commands
570 // ----------------------------------------------------------------------------
571
572 enum
573 {
574 Menu_Quit = 1,
575 Menu_Drag,
576 Menu_NewFrame,
577 Menu_About = 101,
578 Menu_Help,
579 Menu_Clear,
580 Menu_Copy,
581 Menu_Paste,
582 Menu_CopyBitmap,
583 Menu_PasteBitmap,
584 Menu_CopyFiles,
585 Menu_Shape_New = 500,
586 Menu_Shape_Edit,
587 Menu_Shape_Clear,
588 Menu_ShapeClipboard_Copy,
589 Menu_ShapeClipboard_Paste,
590 Button_Colour = 1001
591 };
592
593 BEGIN_EVENT_TABLE(DnDFrame, wxFrame)
594 EVT_MENU(Menu_Quit, DnDFrame::OnQuit)
595 EVT_MENU(Menu_About, DnDFrame::OnAbout)
596 EVT_MENU(Menu_Drag, DnDFrame::OnDrag)
597 EVT_MENU(Menu_NewFrame, DnDFrame::OnNewFrame)
598 EVT_MENU(Menu_Help, DnDFrame::OnHelp)
599 EVT_MENU(Menu_Clear, DnDFrame::OnLogClear)
600 EVT_MENU(Menu_Copy, DnDFrame::OnCopy)
601 EVT_MENU(Menu_Paste, DnDFrame::OnPaste)
602 EVT_MENU(Menu_CopyBitmap, DnDFrame::OnCopyBitmap)
603 EVT_MENU(Menu_PasteBitmap,DnDFrame::OnPasteBitmap)
604 EVT_MENU(Menu_CopyFiles, DnDFrame::OnCopyFiles)
605
606 EVT_UPDATE_UI(Menu_Paste, DnDFrame::OnUpdateUIPasteText)
607 EVT_UPDATE_UI(Menu_PasteBitmap, DnDFrame::OnUpdateUIPasteBitmap)
608
609 EVT_LEFT_DOWN( DnDFrame::OnLeftDown)
610 EVT_RIGHT_DOWN( DnDFrame::OnRightDown)
611 EVT_PAINT( DnDFrame::OnPaint)
612 END_EVENT_TABLE()
613
614 BEGIN_EVENT_TABLE(DnDShapeFrame, wxFrame)
615 EVT_MENU(Menu_Shape_New, DnDShapeFrame::OnNewShape)
616 EVT_MENU(Menu_Shape_Edit, DnDShapeFrame::OnEditShape)
617 EVT_MENU(Menu_Shape_Clear, DnDShapeFrame::OnClearShape)
618
619 EVT_MENU(Menu_ShapeClipboard_Copy, DnDShapeFrame::OnCopyShape)
620 EVT_MENU(Menu_ShapeClipboard_Paste, DnDShapeFrame::OnPasteShape)
621
622 EVT_UPDATE_UI(Menu_ShapeClipboard_Copy, DnDShapeFrame::OnUpdateUICopy)
623 EVT_UPDATE_UI(Menu_ShapeClipboard_Paste, DnDShapeFrame::OnUpdateUIPaste)
624
625 EVT_LEFT_DOWN(DnDShapeFrame::OnDrag)
626
627 EVT_PAINT(DnDShapeFrame::OnPaint)
628 END_EVENT_TABLE()
629
630 BEGIN_EVENT_TABLE(DnDShapeDialog, wxDialog)
631 EVT_BUTTON(Button_Colour, DnDShapeDialog::OnColour)
632 END_EVENT_TABLE()
633
634 // ============================================================================
635 // implementation
636 // ============================================================================
637
638 // `Main program' equivalent, creating windows and returning main app frame
639 bool DnDApp::OnInit()
640 {
641 // load our ressources
642 wxPathList pathList;
643 pathList.Add(".");
644 #ifdef __WXMSW__
645 pathList.Add("./Debug");
646 pathList.Add("./Release");
647 #endif // wxMSW
648
649 wxString path = pathList.FindValidPath("dnd.wxr");
650 if ( !path )
651 {
652 wxLogError("Can't find the resource file dnd.wxr in the current "
653 "directory, aborting.");
654
655 return FALSE;
656 }
657
658 wxDefaultResourceTable->ParseResourceFile(path);
659
660 // switch on trace messages
661 #if defined(__WXGTK__)
662 wxLog::AddTraceMask(_T("clipboard"));
663 #elif defined(__WXMSW__)
664 wxLog::AddTraceMask(wxTRACE_OleCalls);
665 #endif
666
667 #if wxUSE_LIBPNG
668 wxImage::AddHandler( new wxPNGHandler );
669 #endif
670
671 // under X we usually want to use the primary selection by default (which
672 // is shared with other apps)
673 wxTheClipboard->UsePrimarySelection();
674
675 // create the main frame window
676 DnDFrame *frame = new DnDFrame((wxFrame *) NULL,
677 "Drag-and-Drop/Clipboard wxWindows Sample",
678 10, 10, 450, 340);
679
680 // activate it
681 frame->Show(TRUE);
682
683 SetTopWindow(frame);
684
685 return TRUE;
686 }
687
688 DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
689 : wxFrame(frame, -1, title, wxPoint(x, y), wxSize(w, h)),
690 m_strText("wxWindows drag & drop works :-)")
691
692 {
693 // frame icon and status bar
694 SetIcon(wxICON(mondrian));
695
696 CreateStatusBar();
697
698 // construct menu
699 wxMenu *file_menu = new wxMenu;
700 file_menu->Append(Menu_Drag, "&Test drag...");
701 file_menu->AppendSeparator();
702 file_menu->Append(Menu_NewFrame, "&New frame\tCtrl-N");
703 file_menu->AppendSeparator();
704 file_menu->Append(Menu_Quit, "E&xit");
705
706 wxMenu *log_menu = new wxMenu;
707 log_menu->Append(Menu_Clear, "Clear\tCtrl-L");
708
709 wxMenu *help_menu = new wxMenu;
710 help_menu->Append(Menu_Help, "&Help...");
711 help_menu->AppendSeparator();
712 help_menu->Append(Menu_About, "&About");
713
714 wxMenu *clip_menu = new wxMenu;
715 clip_menu->Append(Menu_Copy, "&Copy text\tCtrl+C");
716 clip_menu->Append(Menu_Paste, "&Paste text\tCtrl+V");
717 clip_menu->AppendSeparator();
718 clip_menu->Append(Menu_CopyBitmap, "&Copy bitmap\tAlt+C");
719 clip_menu->Append(Menu_PasteBitmap, "&Paste bitmap\tAlt+V");
720 clip_menu->AppendSeparator();
721 clip_menu->Append(Menu_CopyFiles, "&Copy files\tCtrl+F");
722
723 wxMenuBar *menu_bar = new wxMenuBar;
724 menu_bar->Append(file_menu, "&File");
725 menu_bar->Append(log_menu, "&Log");
726 menu_bar->Append(clip_menu, "&Clipboard");
727 menu_bar->Append(help_menu, "&Help");
728
729 SetMenuBar(menu_bar);
730
731 // make a panel with 3 subwindows
732 wxPoint pos(0, 0);
733 wxSize size(400, 200);
734
735 wxString strFile("Drop files here!"), strText("Drop text on me");
736
737 m_ctrlFile = new wxListBox(this, -1, pos, size, 1, &strFile,
738 wxLB_HSCROLL | wxLB_ALWAYS_SB );
739 m_ctrlText = new wxListBox(this, -1, pos, size, 1, &strText,
740 wxLB_HSCROLL | wxLB_ALWAYS_SB );
741
742 m_ctrlLog = new wxTextCtrl(this, -1, "", pos, size,
743 wxTE_MULTILINE | wxTE_READONLY |
744 wxSUNKEN_BORDER );
745
746 // redirect log messages to the text window
747 m_pLog = new wxLogTextCtrl(m_ctrlLog);
748 m_pLogPrev = wxLog::SetActiveTarget(m_pLog);
749
750 // associate drop targets with 2 text controls
751 m_ctrlFile->SetDropTarget(new DnDFile(m_ctrlFile));
752 m_ctrlText->SetDropTarget(new DnDText(m_ctrlText));
753
754 wxLayoutConstraints *c;
755
756 // Top-left listbox
757 c = new wxLayoutConstraints;
758 c->left.SameAs(this, wxLeft);
759 c->top.SameAs(this, wxTop);
760 c->right.PercentOf(this, wxRight, 50);
761 c->height.PercentOf(this, wxHeight, 30);
762 m_ctrlFile->SetConstraints(c);
763
764 // Top-right listbox
765 c = new wxLayoutConstraints;
766 c->left.SameAs (m_ctrlFile, wxRight);
767 c->top.SameAs (this, wxTop);
768 c->right.SameAs (this, wxRight);
769 c->height.PercentOf(this, wxHeight, 30);
770 m_ctrlText->SetConstraints(c);
771
772 // Lower text control
773 c = new wxLayoutConstraints;
774 c->left.SameAs (this, wxLeft);
775 c->right.SameAs (this, wxRight);
776 c->height.PercentOf(this, wxHeight, 50);
777 c->top.SameAs(m_ctrlText, wxBottom);
778 m_ctrlLog->SetConstraints(c);
779
780 SetAutoLayout(TRUE);
781 }
782
783 void DnDFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
784 {
785 Close(TRUE);
786 }
787
788 void DnDFrame::OnPaint(wxPaintEvent& WXUNUSED(event))
789 {
790 int w = 0;
791 int h = 0;
792 GetClientSize( &w, &h );
793
794 wxPaintDC dc(this);
795 dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL, FALSE, "charter" ) );
796 dc.DrawText( "Drag text from here!", 20, h-50 );
797
798 if ( m_bitmap.Ok() )
799 {
800 // 4/5 is 80% taken by other windows, 20 is arbitrary margin
801 dc.DrawBitmap(m_bitmap,
802 w - m_bitmap.GetWidth() - 20,
803 (4*h)/5 + 20);
804 }
805 }
806
807 void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent& event)
808 {
809 #ifdef __WXDEBUG__
810 // too many trace messages if we don't do it - this function is called
811 // very often
812 wxLogNull nolog;
813 #endif
814
815 event.Enable( wxTheClipboard->IsSupported(wxDF_TEXT) );
816 }
817
818 void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent& event)
819 {
820 #ifdef __WXDEBUG__
821 // too many trace messages if we don't do it - this function is called
822 // very often
823 wxLogNull nolog;
824 #endif
825
826 event.Enable( wxTheClipboard->IsSupported(wxDF_BITMAP) );
827 }
828
829 void DnDFrame::OnNewFrame(wxCommandEvent& WXUNUSED(event))
830 {
831 (new DnDShapeFrame(this))->Show(TRUE);
832
833 wxLogStatus(this, "Double click the new frame to select a shape for it");
834 }
835
836 void DnDFrame::OnDrag(wxCommandEvent& WXUNUSED(event))
837 {
838 wxString strText = wxGetTextFromUser
839 (
840 "After you enter text in this dialog, press any mouse\n"
841 "button in the bottom (empty) part of the frame and \n"
842 "drag it anywhere - you will be in fact dragging the\n"
843 "text object containing this text",
844 "Please enter some text", m_strText, this
845 );
846
847 m_strText = strText;
848 }
849
850 void DnDFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
851 {
852 wxMessageBox("Drag-&-Drop Demo\n"
853 "Please see \"Help|Help...\" for details\n"
854 "Copyright (c) 1998 Vadim Zeitlin",
855 "About wxDnD",
856 wxICON_INFORMATION | wxOK,
857 this);
858 }
859
860 void DnDFrame::OnHelp(wxCommandEvent& /* event */)
861 {
862 wxMessageDialog dialog(this,
863 "This small program demonstrates drag & drop support in wxWindows. The program window\n"
864 "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
865 "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
866 "and the right one accepts text.\n"
867 "\n"
868 "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
869 "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
870 "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
871 "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
872 "work with files) and see what changes.\n"
873 "\n"
874 "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
875 "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
876 "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
877 "change, don't release the mouse button until it does. You can change the string being\n"
878 "dragged in in \"File|Test drag...\" dialog.\n"
879 "\n"
880 "\n"
881 "Please send all questions/bug reports/suggestions &c to \n"
882 "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
883 "wxDnD Help");
884
885 dialog.ShowModal();
886 }
887
888 void DnDFrame::OnLogClear(wxCommandEvent& /* event */ )
889 {
890 m_ctrlLog->Clear();
891 m_ctrlText->Clear();
892 m_ctrlFile->Clear();
893 }
894
895 void DnDFrame::OnLeftDown(wxMouseEvent &WXUNUSED(event) )
896 {
897 if ( !m_strText.IsEmpty() )
898 {
899 // start drag operation
900 wxTextDataObject textData(m_strText);
901 /*
902 wxFileDataObject textData;
903 textData.AddFile( "/file1.txt" );
904 textData.AddFile( "/file2.txt" );
905 */
906 wxDropSource source(textData, this
907
908 #ifdef __WXMSW__
909 ,wxCURSOR_PENCIL, // for copy
910 wxCURSOR_SPRAYCAN, // for move
911 wxCURSOR_QUESTION_ARROW // for nothing
912 #endif
913 );
914
915 const char *pc;
916
917 switch ( source.DoDragDrop(TRUE) )
918 {
919 case wxDragError: pc = "Error!"; break;
920 case wxDragNone: pc = "Nothing"; break;
921 case wxDragCopy: pc = "Copied"; break;
922 case wxDragMove: pc = "Moved"; break;
923 case wxDragCancel: pc = "Cancelled"; break;
924 default: pc = "Huh?"; break;
925 }
926
927 SetStatusText(wxString("Drag result: ") + pc);
928 }
929 }
930
931 void DnDFrame::OnRightDown(wxMouseEvent &event )
932 {
933 wxMenu menu("Dnd sample menu");
934
935 menu.Append(Menu_Drag, "&Test drag...");
936 menu.AppendSeparator();
937 menu.Append(Menu_About, "&About");
938
939 PopupMenu( &menu, event.GetX(), event.GetY() );
940 }
941
942 DnDFrame::~DnDFrame()
943 {
944 if ( m_pLog != NULL ) {
945 if ( wxLog::SetActiveTarget(m_pLogPrev) == m_pLog )
946 delete m_pLog;
947 }
948 }
949
950 // ---------------------------------------------------------------------------
951 // bitmap clipboard
952 // ---------------------------------------------------------------------------
953
954 void DnDFrame::OnCopyBitmap(wxCommandEvent& WXUNUSED(event))
955 {
956 // PNG support is not always compiled in under Windows, so use BMP there
957 #ifdef __WXMSW__
958 wxFileDialog dialog(this, "Open a BMP file", "", "", "BMP files (*.bmp)|*.bmp", 0);
959 #else
960 wxFileDialog dialog(this, "Open a PNG file", "", "", "PNG files (*.png)|*.png", 0);
961 #endif
962
963 if (dialog.ShowModal() != wxID_OK)
964 {
965 wxLogMessage( _T("Aborted file open") );
966 return;
967 }
968
969 if (dialog.GetPath().IsEmpty())
970 {
971 wxLogMessage( _T("Returned empty string.") );
972 return;
973 }
974
975 if (!wxFileExists(dialog.GetPath()))
976 {
977 wxLogMessage( _T("File doesn't exist.") );
978 return;
979 }
980
981 wxImage image;
982 image.LoadFile( dialog.GetPath(),
983 #ifdef __WXMSW__
984 wxBITMAP_TYPE_BMP
985 #else
986 wxBITMAP_TYPE_PNG
987 #endif
988 );
989 if (!image.Ok())
990 {
991 wxLogError( _T("Invalid image file...") );
992 return;
993 }
994
995 wxLogStatus( _T("Decoding image file...") );
996 wxYield();
997
998 wxBitmap bitmap( image.ConvertToBitmap() );
999
1000 if ( !wxTheClipboard->Open() )
1001 {
1002 wxLogError(_T("Can't open clipboard."));
1003
1004 return;
1005 }
1006
1007 wxLogMessage( _T("Creating wxBitmapDataObject...") );
1008 wxYield();
1009
1010 if ( !wxTheClipboard->AddData(new wxBitmapDataObject(bitmap)) )
1011 {
1012 wxLogError(_T("Can't copy image to the clipboard."));
1013 }
1014 else
1015 {
1016 wxLogMessage(_T("Image has been put on the clipboard.") );
1017 wxLogMessage(_T("You can paste it now and look at it.") );
1018 }
1019
1020 wxTheClipboard->Close();
1021 }
1022
1023 void DnDFrame::OnPasteBitmap(wxCommandEvent& WXUNUSED(event))
1024 {
1025 if ( !wxTheClipboard->Open() )
1026 {
1027 wxLogError(_T("Can't open clipboard."));
1028
1029 return;
1030 }
1031
1032 if ( !wxTheClipboard->IsSupported(wxDF_BITMAP) )
1033 {
1034 wxLogWarning(_T("No bitmap on clipboard"));
1035
1036 wxTheClipboard->Close();
1037 return;
1038 }
1039
1040 wxBitmapDataObject data;
1041 if ( !wxTheClipboard->GetData(data) )
1042 {
1043 wxLogError(_T("Can't paste bitmap from the clipboard"));
1044 }
1045 else
1046 {
1047 wxLogMessage(_T("Bitmap pasted from the clipboard") );
1048 m_bitmap = data.GetBitmap();
1049 Refresh();
1050 }
1051
1052 wxTheClipboard->Close();
1053 }
1054
1055 // ----------------------------------------------------------------------------
1056 // file clipboard
1057 // ----------------------------------------------------------------------------
1058
1059 void DnDFrame::OnCopyFiles(wxCommandEvent& WXUNUSED(event))
1060 {
1061 #ifdef __WXMSW__
1062 wxFileDialog dialog(this, "Select a file to copy", "", "",
1063 "All files (*.*)|*.*", 0);
1064
1065 wxArrayString filenames;
1066 while ( dialog.ShowModal() == wxID_OK )
1067 {
1068 filenames.Add(dialog.GetPath());
1069 }
1070
1071 if ( !filenames.IsEmpty() )
1072 {
1073 wxFileDataObject *dobj = new wxFileDataObject;
1074 size_t count = filenames.GetCount();
1075 for ( size_t n = 0; n < count; n++ )
1076 {
1077 dobj->AddFile(filenames[n]);
1078 }
1079
1080 wxClipboardLocker locker;
1081 if ( !locker )
1082 {
1083 wxLogError("Can't open clipboard");
1084 }
1085 else
1086 {
1087 if ( !wxTheClipboard->AddData(dobj) )
1088 {
1089 wxLogError("Can't copy file(s) to the clipboard");
1090 }
1091 else
1092 {
1093 wxLogStatus(this, "%d file%s copied to the clipboard",
1094 count, count == 1 ? "" : "s");
1095 }
1096 }
1097 }
1098 else
1099 {
1100 wxLogStatus(this, "Aborted");
1101 }
1102 #else // !MSW
1103 wxLogError("Sorry, not implemented");
1104 #endif // MSW/!MSW
1105 }
1106
1107 // ---------------------------------------------------------------------------
1108 // text clipboard
1109 // ---------------------------------------------------------------------------
1110
1111 void DnDFrame::OnCopy(wxCommandEvent& WXUNUSED(event))
1112 {
1113 if ( !wxTheClipboard->Open() )
1114 {
1115 wxLogError(_T("Can't open clipboard."));
1116
1117 return;
1118 }
1119
1120 if ( !wxTheClipboard->AddData(new wxTextDataObject(m_strText)) )
1121 {
1122 wxLogError(_T("Can't copy data to the clipboard"));
1123 }
1124 else
1125 {
1126 wxLogMessage(_T("Text '%s' put on the clipboard"), m_strText.c_str());
1127 }
1128
1129 wxTheClipboard->Close();
1130 }
1131
1132 void DnDFrame::OnPaste(wxCommandEvent& WXUNUSED(event))
1133 {
1134 if ( !wxTheClipboard->Open() )
1135 {
1136 wxLogError(_T("Can't open clipboard."));
1137
1138 return;
1139 }
1140
1141 if ( !wxTheClipboard->IsSupported(wxDF_TEXT) )
1142 {
1143 wxLogWarning(_T("No text data on clipboard"));
1144
1145 wxTheClipboard->Close();
1146 return;
1147 }
1148
1149 wxTextDataObject text;
1150 if ( !wxTheClipboard->GetData(text) )
1151 {
1152 wxLogError(_T("Can't paste data from the clipboard"));
1153 }
1154 else
1155 {
1156 wxLogMessage(_T("Text '%s' pasted from the clipboard"),
1157 text.GetText().c_str());
1158 }
1159
1160 wxTheClipboard->Close();
1161 }
1162
1163 // ----------------------------------------------------------------------------
1164 // Notifications called by the base class
1165 // ----------------------------------------------------------------------------
1166
1167 bool DnDText::OnDropText(wxCoord, wxCoord, const wxString& text)
1168 {
1169 m_pOwner->Append(text);
1170
1171 return TRUE;
1172 }
1173
1174 bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& filenames)
1175 {
1176 size_t nFiles = filenames.GetCount();
1177 wxString str;
1178 str.Printf( _T("%d files dropped"), nFiles);
1179 m_pOwner->Append(str);
1180 for ( size_t n = 0; n < nFiles; n++ ) {
1181 m_pOwner->Append(filenames[n]);
1182 }
1183
1184 return TRUE;
1185 }
1186
1187 // ----------------------------------------------------------------------------
1188 // DnDShapeDialog
1189 // ----------------------------------------------------------------------------
1190
1191 DnDShapeDialog::DnDShapeDialog(wxFrame *parent, DnDShape *shape)
1192 {
1193 m_shape = shape;
1194
1195 LoadFromResource(parent, "dialogShape");
1196
1197 m_textX = (wxTextCtrl *)wxFindWindowByName("textX", this);
1198 m_textY = (wxTextCtrl *)wxFindWindowByName("textY", this);
1199 m_textW = (wxTextCtrl *)wxFindWindowByName("textW", this);
1200 m_textH = (wxTextCtrl *)wxFindWindowByName("textH", this);
1201
1202 m_radio = (wxRadioBox *)wxFindWindowByName("radio", this);
1203 }
1204
1205 DnDShape *DnDShapeDialog::GetShape() const
1206 {
1207 switch ( m_shapeKind )
1208 {
1209 default:
1210 case DnDShape::None: return NULL;
1211 case DnDShape::Triangle: return new DnDTriangularShape(m_pos, m_size, m_col);
1212 case DnDShape::Rectangle: return new DnDRectangularShape(m_pos, m_size, m_col);
1213 case DnDShape::Ellipse: return new DnDEllipticShape(m_pos, m_size, m_col);
1214 }
1215 }
1216
1217 bool DnDShapeDialog::TransferDataToWindow()
1218 {
1219
1220 if ( m_shape )
1221 {
1222 m_radio->SetSelection(m_shape->GetKind());
1223 m_pos = m_shape->GetPosition();
1224 m_size = m_shape->GetSize();
1225 m_col = m_shape->GetColour();
1226 }
1227 else
1228 {
1229 m_radio->SetSelection(DnDShape::None);
1230 m_pos = wxPoint(1, 1);
1231 m_size = wxSize(100, 100);
1232 }
1233
1234 m_textX->SetValue(wxString() << m_pos.x);
1235 m_textY->SetValue(wxString() << m_pos.y);
1236 m_textW->SetValue(wxString() << m_size.x);
1237 m_textH->SetValue(wxString() << m_size.y);
1238
1239 return TRUE;
1240 }
1241
1242 bool DnDShapeDialog::TransferDataFromWindow()
1243 {
1244 m_shapeKind = (DnDShape::Kind)m_radio->GetSelection();
1245
1246 m_pos.x = atoi(m_textX->GetValue());
1247 m_pos.y = atoi(m_textY->GetValue());
1248 m_size.x = atoi(m_textW->GetValue());
1249 m_size.y = atoi(m_textH->GetValue());
1250
1251 if ( !m_pos.x || !m_pos.y || !m_size.x || !m_size.y )
1252 {
1253 wxMessageBox("All sizes and positions should be non null!",
1254 "Invalid shape", wxICON_HAND | wxOK, this);
1255
1256 return FALSE;
1257 }
1258
1259 return TRUE;
1260 }
1261
1262 void DnDShapeDialog::OnColour(wxCommandEvent& WXUNUSED(event))
1263 {
1264 wxColourData data;
1265 data.SetChooseFull(TRUE);
1266 for (int i = 0; i < 16; i++)
1267 {
1268 wxColour colour(i*16, i*16, i*16);
1269 data.SetCustomColour(i, colour);
1270 }
1271
1272 wxColourDialog dialog(this, &data);
1273 if ( dialog.ShowModal() == wxID_OK )
1274 {
1275 m_col = dialog.GetColourData().GetColour();
1276 }
1277 }
1278
1279 // ----------------------------------------------------------------------------
1280 // DnDShapeFrame
1281 // ----------------------------------------------------------------------------
1282
1283 DnDShapeFrame *DnDShapeFrame::ms_lastDropTarget = NULL;
1284
1285 DnDShapeFrame::DnDShapeFrame(wxFrame *parent)
1286 : wxFrame(parent, -1, "Shape Frame",
1287 wxDefaultPosition, wxSize(250, 150))
1288 {
1289 CreateStatusBar();
1290
1291 wxMenu *menuShape = new wxMenu;
1292 menuShape->Append(Menu_Shape_New, "&New default shape\tCtrl-S");
1293 menuShape->Append(Menu_Shape_Edit, "&Edit shape\tCtrl-E");
1294 menuShape->AppendSeparator();
1295 menuShape->Append(Menu_Shape_Clear, "&Clear shape\tDel");
1296
1297 wxMenu *menuClipboard = new wxMenu;
1298 menuClipboard->Append(Menu_ShapeClipboard_Copy, "&Copy\tCtrl-C");
1299 menuClipboard->Append(Menu_ShapeClipboard_Paste, "&Paste\tCtrl-V");
1300
1301 wxMenuBar *menubar = new wxMenuBar;
1302 menubar->Append(menuShape, "&Shape");
1303 menubar->Append(menuClipboard, "&Clipboard");
1304
1305 SetMenuBar(menubar);
1306
1307 SetStatusText("Press Ctrl-S to create a new shape");
1308
1309 SetDropTarget(new DnDShapeDropTarget(this));
1310
1311 m_shape = NULL;
1312
1313 SetBackgroundColour(*wxWHITE);
1314 }
1315
1316 DnDShapeFrame::~DnDShapeFrame()
1317 {
1318 if (m_shape)
1319 delete m_shape;
1320 }
1321
1322 void DnDShapeFrame::SetShape(DnDShape *shape)
1323 {
1324 if (m_shape)
1325 delete m_shape;
1326 m_shape = shape;
1327 Refresh();
1328 }
1329
1330 // callbacks
1331 void DnDShapeFrame::OnDrag(wxMouseEvent& event)
1332 {
1333 if ( !m_shape )
1334 {
1335 event.Skip();
1336
1337 return;
1338 }
1339
1340 // start drag operation
1341 DnDShapeDataObject shapeData(m_shape);
1342 wxDropSource source(shapeData, this);
1343
1344 const char *pc = NULL;
1345 switch ( source.DoDragDrop(TRUE) )
1346 {
1347 default:
1348 case wxDragError:
1349 wxLogError("An error occured during drag and drop operation");
1350 break;
1351
1352 case wxDragNone:
1353 SetStatusText("Nothing happened");
1354 break;
1355
1356 case wxDragCopy:
1357 pc = "copied";
1358 break;
1359
1360 case wxDragMove:
1361 pc = "moved";
1362 if ( ms_lastDropTarget != this )
1363 {
1364 // don't delete the shape if we dropped it on ourselves!
1365 SetShape(NULL);
1366 }
1367 break;
1368
1369 case wxDragCancel:
1370 SetStatusText("Drag and drop operation cancelled");
1371 break;
1372 }
1373
1374 if ( pc )
1375 {
1376 SetStatusText(wxString("Shape successfully ") + pc);
1377 }
1378 //else: status text already set
1379 }
1380
1381 void DnDShapeFrame::OnDrop(wxCoord x, wxCoord y, DnDShape *shape)
1382 {
1383 ms_lastDropTarget = this;
1384
1385 wxPoint pt(x, y);
1386
1387 wxString s;
1388 s.Printf("Shape dropped at (%ld, %ld)", pt.x, pt.y);
1389 SetStatusText(s);
1390
1391 shape->Move(pt);
1392 SetShape(shape);
1393 }
1394
1395 void DnDShapeFrame::OnEditShape(wxCommandEvent& event)
1396 {
1397 DnDShapeDialog dlg(this, m_shape);
1398 if ( dlg.ShowModal() == wxID_OK )
1399 {
1400 SetShape(dlg.GetShape());
1401
1402 if ( m_shape )
1403 {
1404 SetStatusText("You can now drag the shape to another frame");
1405 }
1406 }
1407 }
1408
1409 void DnDShapeFrame::OnNewShape(wxCommandEvent& event)
1410 {
1411 SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED));
1412
1413 SetStatusText("You can now drag the shape to another frame");
1414 }
1415
1416 void DnDShapeFrame::OnClearShape(wxCommandEvent& event)
1417 {
1418 SetShape(NULL);
1419 }
1420
1421 void DnDShapeFrame::OnCopyShape(wxCommandEvent& event)
1422 {
1423 if ( m_shape )
1424 {
1425 wxClipboardLocker clipLocker;
1426 if ( !clipLocker )
1427 {
1428 wxLogError("Can't open the clipboard");
1429
1430 return;
1431 }
1432
1433 wxTheClipboard->AddData(new DnDShapeDataObject(m_shape));
1434 }
1435 }
1436
1437 void DnDShapeFrame::OnPasteShape(wxCommandEvent& event)
1438 {
1439 wxClipboardLocker clipLocker;
1440 if ( !clipLocker )
1441 {
1442 wxLogError("Can't open the clipboard");
1443
1444 return;
1445 }
1446
1447 DnDShapeDataObject shapeDataObject(NULL);
1448 if ( wxTheClipboard->GetData(shapeDataObject) )
1449 {
1450 SetShape(shapeDataObject.GetShape());
1451 }
1452 else
1453 {
1454 wxLogStatus("No shape on the clipboard");
1455 }
1456 }
1457
1458 void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent& event)
1459 {
1460 event.Enable( m_shape != NULL );
1461 }
1462
1463 void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent& event)
1464 {
1465 event.Enable( wxTheClipboard->IsSupported(wxDataFormat(shapeFormatId)) );
1466 }
1467
1468 void DnDShapeFrame::OnPaint(wxPaintEvent& event)
1469 {
1470 if ( m_shape )
1471 {
1472 wxPaintDC dc(this);
1473
1474 m_shape->Draw(dc);
1475 }
1476 else
1477 {
1478 event.Skip();
1479 }
1480 }
1481
1482 // ----------------------------------------------------------------------------
1483 // DnDShape
1484 // ----------------------------------------------------------------------------
1485
1486 DnDShape *DnDShape::New(const void *buf)
1487 {
1488 const ShapeDump& dump = *(const ShapeDump *)buf;
1489 switch ( dump.k )
1490 {
1491 case Triangle:
1492 return new DnDTriangularShape(wxPoint(dump.x, dump.y),
1493 wxSize(dump.w, dump.h),
1494 wxColour(dump.r, dump.g, dump.b));
1495
1496 case Rectangle:
1497 return new DnDRectangularShape(wxPoint(dump.x, dump.y),
1498 wxSize(dump.w, dump.h),
1499 wxColour(dump.r, dump.g, dump.b));
1500
1501 case Ellipse:
1502 return new DnDEllipticShape(wxPoint(dump.x, dump.y),
1503 wxSize(dump.w, dump.h),
1504 wxColour(dump.r, dump.g, dump.b));
1505
1506 default:
1507 wxFAIL_MSG("invalid shape!");
1508 return NULL;
1509 }
1510 }
1511
1512 // ----------------------------------------------------------------------------
1513 // DnDShapeDataObject
1514 // ----------------------------------------------------------------------------
1515
1516 void DnDShapeDataObject::CreateBitmap() const
1517 {
1518 wxPoint pos = m_shape->GetPosition();
1519 wxSize size = m_shape->GetSize();
1520 int x = pos.x + size.x,
1521 y = pos.y + size.y;
1522 wxBitmap bitmap(x, y);
1523 wxMemoryDC dc;
1524 dc.SelectObject(bitmap);
1525 dc.SetBrush(wxBrush("white", wxSOLID));
1526 dc.Clear();
1527 m_shape->Draw(dc);
1528 dc.SelectObject(wxNullBitmap);
1529
1530 DnDShapeDataObject *self = (DnDShapeDataObject *)this; // const_cast
1531 self->m_dataobj.SetBitmap(bitmap);
1532 self->m_hasBitmap = TRUE;
1533 }
1534