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