]> git.saurik.com Git - wxWidgets.git/blob - samples/dnd/dnd.cpp
assert in OnSelected() fixed
[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 #if wxUSE_LIBPNG
661 wxImage::AddHandler( new wxPNGHandler );
662 #endif
663
664 // under X we usually want to use the primary selection by default (which
665 // is shared with other apps)
666 wxTheClipboard->UsePrimarySelection();
667
668 // create the main frame window
669 DnDFrame *frame = new DnDFrame((wxFrame *) NULL,
670 "Drag-and-Drop/Clipboard wxWindows Sample",
671 10, 10, 450, 340);
672
673 // activate it
674 frame->Show(TRUE);
675
676 SetTopWindow(frame);
677
678 return TRUE;
679 }
680
681 DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
682 : wxFrame(frame, -1, title, wxPoint(x, y), wxSize(w, h)),
683 m_strText("wxWindows drag & drop works :-)")
684
685 {
686 // frame icon and status bar
687 SetIcon(wxICON(mondrian));
688
689 CreateStatusBar();
690
691 // construct menu
692 wxMenu *file_menu = new wxMenu;
693 file_menu->Append(Menu_Drag, "&Test drag...");
694 file_menu->AppendSeparator();
695 file_menu->Append(Menu_NewFrame, "&New frame\tCtrl-N");
696 file_menu->AppendSeparator();
697 file_menu->Append(Menu_Quit, "E&xit");
698
699 wxMenu *log_menu = new wxMenu;
700 log_menu->Append(Menu_Clear, "Clear\tCtrl-L");
701
702 wxMenu *help_menu = new wxMenu;
703 help_menu->Append(Menu_Help, "&Help...");
704 help_menu->AppendSeparator();
705 help_menu->Append(Menu_About, "&About");
706
707 wxMenu *clip_menu = new wxMenu;
708 clip_menu->Append(Menu_Copy, "&Copy text\tCtrl+C");
709 clip_menu->Append(Menu_Paste, "&Paste text\tCtrl+V");
710 clip_menu->AppendSeparator();
711 clip_menu->Append(Menu_CopyBitmap, "&Copy bitmap\tAlt+C");
712 clip_menu->Append(Menu_PasteBitmap, "&Paste bitmap\tAlt+V");
713 clip_menu->AppendSeparator();
714 clip_menu->Append(Menu_CopyFiles, "&Copy files\tCtrl+F");
715
716 wxMenuBar *menu_bar = new wxMenuBar;
717 menu_bar->Append(file_menu, "&File");
718 menu_bar->Append(log_menu, "&Log");
719 menu_bar->Append(clip_menu, "&Clipboard");
720 menu_bar->Append(help_menu, "&Help");
721
722 SetMenuBar(menu_bar);
723
724 // make a panel with 3 subwindows
725 wxPoint pos(0, 0);
726 wxSize size(400, 200);
727
728 wxString strFile("Drop files here!"), strText("Drop text on me");
729
730 m_ctrlFile = new wxListBox(this, -1, pos, size, 1, &strFile,
731 wxLB_HSCROLL | wxLB_ALWAYS_SB );
732 m_ctrlText = new wxListBox(this, -1, pos, size, 1, &strText,
733 wxLB_HSCROLL | wxLB_ALWAYS_SB );
734
735 m_ctrlLog = new wxTextCtrl(this, -1, "", pos, size,
736 wxTE_MULTILINE | wxTE_READONLY |
737 wxSUNKEN_BORDER );
738
739 #ifdef __WXMSW__
740 // redirect log messages to the text window and switch on OLE messages
741 // logging
742 wxLog::AddTraceMask(wxTRACE_OleCalls);
743 #endif
744 m_pLog = new wxLogTextCtrl(m_ctrlLog);
745 m_pLogPrev = wxLog::SetActiveTarget(m_pLog);
746
747 // associate drop targets with 2 text controls
748 m_ctrlFile->SetDropTarget(new DnDFile(m_ctrlFile));
749 m_ctrlText->SetDropTarget(new DnDText(m_ctrlText));
750
751 wxLayoutConstraints *c;
752
753 // Top-left listbox
754 c = new wxLayoutConstraints;
755 c->left.SameAs(this, wxLeft);
756 c->top.SameAs(this, wxTop);
757 c->right.PercentOf(this, wxRight, 50);
758 c->height.PercentOf(this, wxHeight, 30);
759 m_ctrlFile->SetConstraints(c);
760
761 // Top-right listbox
762 c = new wxLayoutConstraints;
763 c->left.SameAs (m_ctrlFile, wxRight);
764 c->top.SameAs (this, wxTop);
765 c->right.SameAs (this, wxRight);
766 c->height.PercentOf(this, wxHeight, 30);
767 m_ctrlText->SetConstraints(c);
768
769 // Lower text control
770 c = new wxLayoutConstraints;
771 c->left.SameAs (this, wxLeft);
772 c->right.SameAs (this, wxRight);
773 c->height.PercentOf(this, wxHeight, 50);
774 c->top.SameAs(m_ctrlText, wxBottom);
775 m_ctrlLog->SetConstraints(c);
776
777 SetAutoLayout(TRUE);
778 }
779
780 void DnDFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
781 {
782 Close(TRUE);
783 }
784
785 void DnDFrame::OnPaint(wxPaintEvent& WXUNUSED(event))
786 {
787 int w = 0;
788 int h = 0;
789 GetClientSize( &w, &h );
790
791 wxPaintDC dc(this);
792 dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL, FALSE, "charter" ) );
793 dc.DrawText( "Drag text from here!", 20, h-50 );
794
795 if ( m_bitmap.Ok() )
796 {
797 // 4/5 is 80% taken by other windows, 20 is arbitrary margin
798 dc.DrawBitmap(m_bitmap,
799 w - m_bitmap.GetWidth() - 20,
800 (4*h)/5 + 20);
801 }
802 }
803
804 void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent& event)
805 {
806 event.Enable( wxTheClipboard->IsSupported(wxDF_TEXT) );
807 // event.Enable( TRUE );
808 }
809
810 void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent& event)
811 {
812 event.Enable( wxTheClipboard->IsSupported(wxDF_BITMAP) );
813 }
814
815 void DnDFrame::OnNewFrame(wxCommandEvent& WXUNUSED(event))
816 {
817 (new DnDShapeFrame(this))->Show(TRUE);
818
819 wxLogStatus(this, "Double click the new frame to select a shape for it");
820 }
821
822 void DnDFrame::OnDrag(wxCommandEvent& WXUNUSED(event))
823 {
824 wxString strText = wxGetTextFromUser
825 (
826 "After you enter text in this dialog, press any mouse\n"
827 "button in the bottom (empty) part of the frame and \n"
828 "drag it anywhere - you will be in fact dragging the\n"
829 "text object containing this text",
830 "Please enter some text", m_strText, this
831 );
832
833 m_strText = strText;
834 }
835
836 void DnDFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
837 {
838 wxMessageBox("Drag-&-Drop Demo\n"
839 "Please see \"Help|Help...\" for details\n"
840 "Copyright (c) 1998 Vadim Zeitlin",
841 "About wxDnD",
842 wxICON_INFORMATION | wxOK,
843 this);
844 }
845
846 void DnDFrame::OnHelp(wxCommandEvent& /* event */)
847 {
848 wxMessageDialog dialog(this,
849 "This small program demonstrates drag & drop support in wxWindows. The program window\n"
850 "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
851 "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
852 "and the right one accepts text.\n"
853 "\n"
854 "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
855 "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
856 "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
857 "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
858 "work with files) and see what changes.\n"
859 "\n"
860 "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
861 "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
862 "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
863 "change, don't release the mouse button until it does. You can change the string being\n"
864 "dragged in in \"File|Test drag...\" dialog.\n"
865 "\n"
866 "\n"
867 "Please send all questions/bug reports/suggestions &c to \n"
868 "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
869 "wxDnD Help");
870
871 dialog.ShowModal();
872 }
873
874 void DnDFrame::OnLogClear(wxCommandEvent& /* event */ )
875 {
876 m_ctrlLog->Clear();
877 m_ctrlText->Clear();
878 m_ctrlFile->Clear();
879 }
880
881 void DnDFrame::OnLeftDown(wxMouseEvent &WXUNUSED(event) )
882 {
883 if ( !m_strText.IsEmpty() )
884 {
885 // start drag operation
886 wxTextDataObject textData(m_strText);
887 /*
888 wxFileDataObject textData;
889 textData.AddFile( "/file1.txt" );
890 textData.AddFile( "/file2.txt" );
891 */
892 wxDropSource source(textData, this
893
894 #ifdef __WXMSW__
895 ,wxCURSOR_PENCIL, // for copy
896 wxCURSOR_SPRAYCAN, // for move
897 wxCURSOR_QUESTION_ARROW // for nothing
898 #endif
899 );
900
901 const char *pc;
902
903 switch ( source.DoDragDrop(TRUE) )
904 {
905 case wxDragError: pc = "Error!"; break;
906 case wxDragNone: pc = "Nothing"; break;
907 case wxDragCopy: pc = "Copied"; break;
908 case wxDragMove: pc = "Moved"; break;
909 case wxDragCancel: pc = "Cancelled"; break;
910 default: pc = "Huh?"; break;
911 }
912
913 SetStatusText(wxString("Drag result: ") + pc);
914 }
915 }
916
917 void DnDFrame::OnRightDown(wxMouseEvent &event )
918 {
919 wxMenu menu("Dnd sample menu");
920
921 menu.Append(Menu_Drag, "&Test drag...");
922 menu.AppendSeparator();
923 menu.Append(Menu_About, "&About");
924
925 PopupMenu( &menu, event.GetX(), event.GetY() );
926 }
927
928 DnDFrame::~DnDFrame()
929 {
930 if ( m_pLog != NULL ) {
931 if ( wxLog::SetActiveTarget(m_pLogPrev) == m_pLog )
932 delete m_pLog;
933 }
934 }
935
936 // ---------------------------------------------------------------------------
937 // bitmap clipboard
938 // ---------------------------------------------------------------------------
939
940 void DnDFrame::OnCopyBitmap(wxCommandEvent& WXUNUSED(event))
941 {
942 // PNG support is not always compiled in under Windows, so use BMP there
943 #ifdef __WXMSW__
944 wxFileDialog dialog(this, "Open a BMP file", "", "", "BMP files (*.bmp)|*.bmp", 0);
945 #else
946 wxFileDialog dialog(this, "Open a PNG file", "", "", "PNG files (*.png)|*.png", 0);
947 #endif
948
949 if (dialog.ShowModal() != wxID_OK)
950 {
951 wxLogMessage( _T("Aborted file open") );
952 return;
953 }
954
955 if (dialog.GetPath().IsEmpty())
956 {
957 wxLogMessage( _T("Returned empty string.") );
958 return;
959 }
960
961 if (!wxFileExists(dialog.GetPath()))
962 {
963 wxLogMessage( _T("File doesn't exist.") );
964 return;
965 }
966
967 wxImage image;
968 image.LoadFile( dialog.GetPath(),
969 #ifdef __WXMSW__
970 wxBITMAP_TYPE_BMP
971 #else
972 wxBITMAP_TYPE_PNG
973 #endif
974 );
975 if (!image.Ok())
976 {
977 wxLogError( _T("Invalid image file...") );
978 return;
979 }
980
981 wxLogStatus( _T("Decoding image file...") );
982 wxYield();
983
984 wxBitmap bitmap( image.ConvertToBitmap() );
985
986 if ( !wxTheClipboard->Open() )
987 {
988 wxLogError(_T("Can't open clipboard."));
989
990 return;
991 }
992
993 wxLogMessage( _T("Creating wxBitmapDataObject...") );
994 wxYield();
995
996 if ( !wxTheClipboard->AddData(new wxBitmapDataObject(bitmap)) )
997 {
998 wxLogError(_T("Can't copy image to the clipboard."));
999 }
1000 else
1001 {
1002 wxLogMessage(_T("Image has been put on the clipboard.") );
1003 wxLogMessage(_T("You can paste it now and look at it.") );
1004 }
1005
1006 wxTheClipboard->Close();
1007 }
1008
1009 void DnDFrame::OnPasteBitmap(wxCommandEvent& WXUNUSED(event))
1010 {
1011 if ( !wxTheClipboard->Open() )
1012 {
1013 wxLogError(_T("Can't open clipboard."));
1014
1015 return;
1016 }
1017
1018 if ( !wxTheClipboard->IsSupported(wxDF_BITMAP) )
1019 {
1020 wxLogWarning(_T("No bitmap on clipboard"));
1021
1022 wxTheClipboard->Close();
1023 return;
1024 }
1025
1026 wxBitmapDataObject data;
1027 if ( !wxTheClipboard->GetData(data) )
1028 {
1029 wxLogError(_T("Can't paste bitmap from the clipboard"));
1030 }
1031 else
1032 {
1033 wxLogMessage(_T("Bitmap pasted from the clipboard") );
1034 m_bitmap = data.GetBitmap();
1035 Refresh();
1036 }
1037
1038 wxTheClipboard->Close();
1039 }
1040
1041 // ----------------------------------------------------------------------------
1042 // file clipboard
1043 // ----------------------------------------------------------------------------
1044
1045 void DnDFrame::OnCopyFiles(wxCommandEvent& WXUNUSED(event))
1046 {
1047 #ifdef __WXMSW__
1048 wxFileDialog dialog(this, "Select a file to copy", "", "",
1049 "All files (*.*)|*.*", 0);
1050
1051 wxArrayString filenames;
1052 while ( dialog.ShowModal() == wxID_OK )
1053 {
1054 filenames.Add(dialog.GetPath());
1055 }
1056
1057 if ( !filenames.IsEmpty() )
1058 {
1059 wxFileDataObject *dobj = new wxFileDataObject;
1060 size_t count = filenames.GetCount();
1061 for ( size_t n = 0; n < count; n++ )
1062 {
1063 dobj->AddFile(filenames[n]);
1064 }
1065
1066 wxClipboardLocker locker;
1067 if ( !locker )
1068 {
1069 wxLogError("Can't open clipboard");
1070 }
1071 else
1072 {
1073 if ( !wxTheClipboard->AddData(dobj) )
1074 {
1075 wxLogError("Can't copy file(s) to the clipboard");
1076 }
1077 else
1078 {
1079 wxLogStatus(this, "%d file%s copied to the clipboard",
1080 count, count == 1 ? "" : "s");
1081 }
1082 }
1083 }
1084 else
1085 {
1086 wxLogStatus(this, "Aborted");
1087 }
1088 #else // !MSW
1089 wxLogError("Sorry, not implemented");
1090 #endif // MSW/!MSW
1091 }
1092
1093 // ---------------------------------------------------------------------------
1094 // text clipboard
1095 // ---------------------------------------------------------------------------
1096
1097 void DnDFrame::OnCopy(wxCommandEvent& WXUNUSED(event))
1098 {
1099 if ( !wxTheClipboard->Open() )
1100 {
1101 wxLogError(_T("Can't open clipboard."));
1102
1103 return;
1104 }
1105
1106 if ( !wxTheClipboard->AddData(new wxTextDataObject(m_strText)) )
1107 {
1108 wxLogError(_T("Can't copy data to the clipboard"));
1109 }
1110 else
1111 {
1112 wxLogMessage(_T("Text '%s' put on the clipboard"), m_strText.c_str());
1113 }
1114
1115 wxTheClipboard->Close();
1116 }
1117
1118 void DnDFrame::OnPaste(wxCommandEvent& WXUNUSED(event))
1119 {
1120 if ( !wxTheClipboard->Open() )
1121 {
1122 wxLogError(_T("Can't open clipboard."));
1123
1124 return;
1125 }
1126
1127 if ( !wxTheClipboard->IsSupported(wxDF_TEXT) )
1128 {
1129 wxLogWarning(_T("No text data on clipboard"));
1130
1131 wxTheClipboard->Close();
1132 return;
1133 }
1134
1135 wxTextDataObject text;
1136 if ( !wxTheClipboard->GetData(text) )
1137 {
1138 wxLogError(_T("Can't paste data from the clipboard"));
1139 }
1140 else
1141 {
1142 wxLogMessage(_T("Text '%s' pasted from the clipboard"),
1143 text.GetText().c_str());
1144 }
1145
1146 wxTheClipboard->Close();
1147 }
1148
1149 // ----------------------------------------------------------------------------
1150 // Notifications called by the base class
1151 // ----------------------------------------------------------------------------
1152
1153 bool DnDText::OnDropText(wxCoord, wxCoord, const wxString& text)
1154 {
1155 m_pOwner->Append(text);
1156
1157 return TRUE;
1158 }
1159
1160 bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& filenames)
1161 {
1162 size_t nFiles = filenames.GetCount();
1163 wxString str;
1164 str.Printf( _T("%d files dropped"), nFiles);
1165 m_pOwner->Append(str);
1166 for ( size_t n = 0; n < nFiles; n++ ) {
1167 m_pOwner->Append(filenames[n]);
1168 }
1169
1170 return TRUE;
1171 }
1172
1173 // ----------------------------------------------------------------------------
1174 // DnDShapeDialog
1175 // ----------------------------------------------------------------------------
1176
1177 DnDShapeDialog::DnDShapeDialog(wxFrame *parent, DnDShape *shape)
1178 {
1179 m_shape = shape;
1180
1181 LoadFromResource(parent, "dialogShape");
1182
1183 m_textX = (wxTextCtrl *)wxFindWindowByName("textX", this);
1184 m_textY = (wxTextCtrl *)wxFindWindowByName("textY", this);
1185 m_textW = (wxTextCtrl *)wxFindWindowByName("textW", this);
1186 m_textH = (wxTextCtrl *)wxFindWindowByName("textH", this);
1187
1188 m_radio = (wxRadioBox *)wxFindWindowByName("radio", this);
1189 }
1190
1191 DnDShape *DnDShapeDialog::GetShape() const
1192 {
1193 switch ( m_shapeKind )
1194 {
1195 default:
1196 case DnDShape::None: return NULL;
1197 case DnDShape::Triangle: return new DnDTriangularShape(m_pos, m_size, m_col);
1198 case DnDShape::Rectangle: return new DnDRectangularShape(m_pos, m_size, m_col);
1199 case DnDShape::Ellipse: return new DnDEllipticShape(m_pos, m_size, m_col);
1200 }
1201 }
1202
1203 bool DnDShapeDialog::TransferDataToWindow()
1204 {
1205
1206 if ( m_shape )
1207 {
1208 m_radio->SetSelection(m_shape->GetKind());
1209 m_pos = m_shape->GetPosition();
1210 m_size = m_shape->GetSize();
1211 m_col = m_shape->GetColour();
1212 }
1213 else
1214 {
1215 m_radio->SetSelection(DnDShape::None);
1216 m_pos = wxPoint(1, 1);
1217 m_size = wxSize(100, 100);
1218 }
1219
1220 m_textX->SetValue(wxString() << m_pos.x);
1221 m_textY->SetValue(wxString() << m_pos.y);
1222 m_textW->SetValue(wxString() << m_size.x);
1223 m_textH->SetValue(wxString() << m_size.y);
1224
1225 return TRUE;
1226 }
1227
1228 bool DnDShapeDialog::TransferDataFromWindow()
1229 {
1230 m_shapeKind = (DnDShape::Kind)m_radio->GetSelection();
1231
1232 m_pos.x = atoi(m_textX->GetValue());
1233 m_pos.y = atoi(m_textY->GetValue());
1234 m_size.x = atoi(m_textW->GetValue());
1235 m_size.y = atoi(m_textH->GetValue());
1236
1237 if ( !m_pos.x || !m_pos.y || !m_size.x || !m_size.y )
1238 {
1239 wxMessageBox("All sizes and positions should be non null!",
1240 "Invalid shape", wxICON_HAND | wxOK, this);
1241
1242 return FALSE;
1243 }
1244
1245 return TRUE;
1246 }
1247
1248 void DnDShapeDialog::OnColour(wxCommandEvent& WXUNUSED(event))
1249 {
1250 wxColourData data;
1251 data.SetChooseFull(TRUE);
1252 for (int i = 0; i < 16; i++)
1253 {
1254 wxColour colour(i*16, i*16, i*16);
1255 data.SetCustomColour(i, colour);
1256 }
1257
1258 wxColourDialog dialog(this, &data);
1259 if ( dialog.ShowModal() == wxID_OK )
1260 {
1261 m_col = dialog.GetColourData().GetColour();
1262 }
1263 }
1264
1265 // ----------------------------------------------------------------------------
1266 // DnDShapeFrame
1267 // ----------------------------------------------------------------------------
1268
1269 DnDShapeFrame *DnDShapeFrame::ms_lastDropTarget = NULL;
1270
1271 DnDShapeFrame::DnDShapeFrame(wxFrame *parent)
1272 : wxFrame(parent, -1, "Shape Frame",
1273 wxDefaultPosition, wxSize(250, 150))
1274 {
1275 CreateStatusBar();
1276
1277 wxMenu *menuShape = new wxMenu;
1278 menuShape->Append(Menu_Shape_New, "&New default shape\tCtrl-S");
1279 menuShape->Append(Menu_Shape_Edit, "&Edit shape\tCtrl-E");
1280 menuShape->AppendSeparator();
1281 menuShape->Append(Menu_Shape_Clear, "&Clear shape\tDel");
1282
1283 wxMenu *menuClipboard = new wxMenu;
1284 menuClipboard->Append(Menu_ShapeClipboard_Copy, "&Copy\tCtrl-C");
1285 menuClipboard->Append(Menu_ShapeClipboard_Paste, "&Paste\tCtrl-V");
1286
1287 wxMenuBar *menubar = new wxMenuBar;
1288 menubar->Append(menuShape, "&Shape");
1289 menubar->Append(menuClipboard, "&Clipboard");
1290
1291 SetMenuBar(menubar);
1292
1293 SetStatusText("Press Ctrl-S to create a new shape");
1294
1295 SetDropTarget(new DnDShapeDropTarget(this));
1296
1297 m_shape = NULL;
1298
1299 SetBackgroundColour(*wxWHITE);
1300 }
1301
1302 DnDShapeFrame::~DnDShapeFrame()
1303 {
1304 if (m_shape)
1305 delete m_shape;
1306 }
1307
1308 void DnDShapeFrame::SetShape(DnDShape *shape)
1309 {
1310 if (m_shape)
1311 delete m_shape;
1312 m_shape = shape;
1313 Refresh();
1314 }
1315
1316 // callbacks
1317 void DnDShapeFrame::OnDrag(wxMouseEvent& event)
1318 {
1319 if ( !m_shape )
1320 {
1321 event.Skip();
1322
1323 return;
1324 }
1325
1326 // start drag operation
1327 DnDShapeDataObject shapeData(m_shape);
1328 wxDropSource source(shapeData, this);
1329
1330 const char *pc = NULL;
1331 switch ( source.DoDragDrop(TRUE) )
1332 {
1333 default:
1334 case wxDragError:
1335 wxLogError("An error occured during drag and drop operation");
1336 break;
1337
1338 case wxDragNone:
1339 SetStatusText("Nothing happened");
1340 break;
1341
1342 case wxDragCopy:
1343 pc = "copied";
1344 break;
1345
1346 case wxDragMove:
1347 pc = "moved";
1348 if ( ms_lastDropTarget != this )
1349 {
1350 // don't delete the shape if we dropped it on ourselves!
1351 SetShape(NULL);
1352 }
1353 break;
1354
1355 case wxDragCancel:
1356 SetStatusText("Drag and drop operation cancelled");
1357 break;
1358 }
1359
1360 if ( pc )
1361 {
1362 SetStatusText(wxString("Shape successfully ") + pc);
1363 }
1364 //else: status text already set
1365 }
1366
1367 void DnDShapeFrame::OnDrop(wxCoord x, wxCoord y, DnDShape *shape)
1368 {
1369 ms_lastDropTarget = this;
1370
1371 wxPoint pt(x, y);
1372
1373 wxString s;
1374 s.Printf("Shape dropped at (%ld, %ld)", pt.x, pt.y);
1375 SetStatusText(s);
1376
1377 shape->Move(pt);
1378 SetShape(shape);
1379 }
1380
1381 void DnDShapeFrame::OnEditShape(wxCommandEvent& event)
1382 {
1383 DnDShapeDialog dlg(this, m_shape);
1384 if ( dlg.ShowModal() == wxID_OK )
1385 {
1386 SetShape(dlg.GetShape());
1387
1388 if ( m_shape )
1389 {
1390 SetStatusText("You can now drag the shape to another frame");
1391 }
1392 }
1393 }
1394
1395 void DnDShapeFrame::OnNewShape(wxCommandEvent& event)
1396 {
1397 SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED));
1398
1399 SetStatusText("You can now drag the shape to another frame");
1400 }
1401
1402 void DnDShapeFrame::OnClearShape(wxCommandEvent& event)
1403 {
1404 SetShape(NULL);
1405 }
1406
1407 void DnDShapeFrame::OnCopyShape(wxCommandEvent& event)
1408 {
1409 if ( m_shape )
1410 {
1411 wxClipboardLocker clipLocker;
1412 if ( !clipLocker )
1413 {
1414 wxLogError("Can't open the clipboard");
1415
1416 return;
1417 }
1418
1419 wxTheClipboard->AddData(new DnDShapeDataObject(m_shape));
1420 }
1421 }
1422
1423 void DnDShapeFrame::OnPasteShape(wxCommandEvent& event)
1424 {
1425 wxClipboardLocker clipLocker;
1426 if ( !clipLocker )
1427 {
1428 wxLogError("Can't open the clipboard");
1429
1430 return;
1431 }
1432
1433 DnDShapeDataObject shapeDataObject(NULL);
1434 if ( wxTheClipboard->GetData(shapeDataObject) )
1435 {
1436 SetShape(shapeDataObject.GetShape());
1437 }
1438 else
1439 {
1440 wxLogStatus("No shape on the clipboard");
1441 }
1442 }
1443
1444 void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent& event)
1445 {
1446 event.Enable( m_shape != NULL );
1447 }
1448
1449 void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent& event)
1450 {
1451 event.Enable( wxTheClipboard->IsSupported(wxDataFormat(shapeFormatId)) );
1452 }
1453
1454 void DnDShapeFrame::OnPaint(wxPaintEvent& event)
1455 {
1456 if ( m_shape )
1457 {
1458 wxPaintDC dc(this);
1459
1460 m_shape->Draw(dc);
1461 }
1462 else
1463 {
1464 event.Skip();
1465 }
1466 }
1467
1468 // ----------------------------------------------------------------------------
1469 // DnDShape
1470 // ----------------------------------------------------------------------------
1471
1472 DnDShape *DnDShape::New(const void *buf)
1473 {
1474 const ShapeDump& dump = *(const ShapeDump *)buf;
1475 switch ( dump.k )
1476 {
1477 case Triangle:
1478 return new DnDTriangularShape(wxPoint(dump.x, dump.y),
1479 wxSize(dump.w, dump.h),
1480 wxColour(dump.r, dump.g, dump.b));
1481
1482 case Rectangle:
1483 return new DnDRectangularShape(wxPoint(dump.x, dump.y),
1484 wxSize(dump.w, dump.h),
1485 wxColour(dump.r, dump.g, dump.b));
1486
1487 case Ellipse:
1488 return new DnDEllipticShape(wxPoint(dump.x, dump.y),
1489 wxSize(dump.w, dump.h),
1490 wxColour(dump.r, dump.g, dump.b));
1491
1492 default:
1493 wxFAIL_MSG("invalid shape!");
1494 return NULL;
1495 }
1496 }
1497
1498 // ----------------------------------------------------------------------------
1499 // DnDShapeDataObject
1500 // ----------------------------------------------------------------------------
1501
1502 void DnDShapeDataObject::CreateBitmap() const
1503 {
1504 wxPoint pos = m_shape->GetPosition();
1505 wxSize size = m_shape->GetSize();
1506 int x = pos.x + size.x,
1507 y = pos.y + size.y;
1508 wxBitmap bitmap(x, y);
1509 wxMemoryDC dc;
1510 dc.SelectObject(bitmap);
1511 dc.SetBrush(wxBrush("white", wxSOLID));
1512 dc.Clear();
1513 m_shape->Draw(dc);
1514 dc.SelectObject(wxNullBitmap);
1515
1516 DnDShapeDataObject *self = (DnDShapeDataObject *)this; // const_cast
1517 self->m_dataobj.SetBitmap(bitmap);
1518 self->m_hasBitmap = TRUE;
1519 }
1520