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