Use wxHAS_IMAGES_IN_RESOURCES instead of explicit platform checks.
[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 #include "wx/dnd.h"
23 #include "wx/dataobj.h"
24 #include "wx/image.h"
25 #include "wx/clipbrd.h"
26 #include "wx/colordlg.h"
27 #include "wx/metafile.h"
28 #include "wx/dirctrl.h"
29
30 #ifndef wxHAS_IMAGES_IN_RESOURCES
31 #include "../sample.xpm"
32 #if wxUSE_DRAG_AND_DROP
33 #include "dnd_copy.xpm"
34 #include "dnd_move.xpm"
35 #include "dnd_none.xpm"
36 #endif
37 #endif
38
39 #if wxUSE_DRAG_AND_DROP
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 = NULL) { 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 custom dtop target accepting URLs
71 // ----------------------------------------------------------------------------
72
73 class URLDropTarget : public wxDropTarget
74 {
75 public:
76 URLDropTarget() { SetDataObject(new wxURLDataObject); }
77
78 void OnDropURL(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), const wxString& text)
79 {
80 // of course, a real program would do something more useful here...
81 wxMessageBox(text, wxT("wxDnD sample: got URL"),
82 wxICON_INFORMATION | wxOK);
83 }
84
85 // URLs can't be moved, only copied
86 virtual wxDragResult OnDragOver(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
87 wxDragResult WXUNUSED(def))
88 {
89 return wxDragLink; // At least IE 5.x needs wxDragLink, the
90 // other browsers on MSW seem okay with it too.
91 }
92
93 // translate this to calls to OnDropURL() just for convenience
94 virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def)
95 {
96 if ( !GetData() )
97 return wxDragNone;
98
99 OnDropURL(x, y, ((wxURLDataObject *)m_dataObject)->GetURL());
100
101 return def;
102 }
103 };
104
105 #endif // wxUSE_DRAG_AND_DROP
106
107 // ----------------------------------------------------------------------------
108 // Define a new application type
109 // ----------------------------------------------------------------------------
110
111 class DnDApp : public wxApp
112 {
113 public:
114 virtual bool OnInit();
115 };
116
117 IMPLEMENT_APP(DnDApp)
118
119 #if wxUSE_DRAG_AND_DROP || wxUSE_CLIPBOARD
120
121 // ----------------------------------------------------------------------------
122 // Define canvas class to show a bitmap
123 // ----------------------------------------------------------------------------
124
125 class DnDCanvasBitmap : public wxScrolledWindow
126 {
127 public:
128 DnDCanvasBitmap(wxWindow *parent) : wxScrolledWindow(parent) { }
129
130 void SetBitmap(const wxBitmap& bitmap)
131 {
132 m_bitmap = bitmap;
133
134 SetScrollbars(10, 10,
135 m_bitmap.GetWidth() / 10, m_bitmap.GetHeight() / 10);
136
137 Refresh();
138 }
139
140 void OnPaint(wxPaintEvent& WXUNUSED(event))
141 {
142 wxPaintDC dc(this);
143
144 if ( m_bitmap.IsOk() )
145 {
146 PrepareDC(dc);
147
148 dc.DrawBitmap(m_bitmap, 0, 0);
149 }
150 }
151
152 private:
153 wxBitmap m_bitmap;
154
155 DECLARE_EVENT_TABLE()
156 };
157
158 #if wxUSE_METAFILE
159
160 // and the same thing fo metafiles
161 class DnDCanvasMetafile : public wxScrolledWindow
162 {
163 public:
164 DnDCanvasMetafile(wxWindow *parent) : wxScrolledWindow(parent) { }
165
166 void SetMetafile(const wxMetafile& metafile)
167 {
168 m_metafile = metafile;
169
170 SetScrollbars(10, 10,
171 m_metafile.GetWidth() / 10, m_metafile.GetHeight() / 10);
172
173 Refresh();
174 }
175
176 void OnPaint(wxPaintEvent&)
177 {
178 wxPaintDC dc(this);
179
180 if ( m_metafile.IsOk() )
181 {
182 PrepareDC(dc);
183
184 m_metafile.Play(&dc);
185 }
186 }
187
188 private:
189 wxMetafile m_metafile;
190
191 DECLARE_EVENT_TABLE()
192 };
193
194 #endif // wxUSE_METAFILE
195
196 // ----------------------------------------------------------------------------
197 // Define a new frame type for the main frame
198 // ----------------------------------------------------------------------------
199
200 class DnDFrame : public wxFrame
201 {
202 public:
203 DnDFrame();
204 virtual ~DnDFrame();
205
206 void OnPaint(wxPaintEvent& event);
207 void OnSize(wxSizeEvent& event);
208 void OnQuit(wxCommandEvent& event);
209 void OnAbout(wxCommandEvent& event);
210 void OnDrag(wxCommandEvent& event);
211 void OnDragMoveByDefault(wxCommandEvent& event);
212 void OnDragMoveAllow(wxCommandEvent& event);
213 void OnNewFrame(wxCommandEvent& event);
214 void OnHelp (wxCommandEvent& event);
215 #if wxUSE_LOG
216 void OnLogClear(wxCommandEvent& event);
217 #endif // wxUSE_LOG
218
219 void OnCopy(wxCommandEvent& event);
220 void OnPaste(wxCommandEvent& event);
221
222 void OnCopyBitmap(wxCommandEvent& event);
223 void OnPasteBitmap(wxCommandEvent& event);
224
225 #if wxUSE_METAFILE
226 void OnPasteMetafile(wxCommandEvent& event);
227 #endif // wxUSE_METAFILE
228
229 void OnCopyFiles(wxCommandEvent& event);
230
231 void OnUsePrimary(wxCommandEvent& event);
232
233 void OnLeftDown(wxMouseEvent& event);
234 void OnRightDown(wxMouseEvent& event);
235
236 #if wxUSE_DRAG_AND_DROP
237 void OnBeginDrag(wxTreeEvent& event);
238 #endif // wxUSE_DRAG_AND_DROP
239
240 void OnUpdateUIMoveByDefault(wxUpdateUIEvent& event);
241
242 void OnUpdateUIPasteText(wxUpdateUIEvent& event);
243 void OnUpdateUIPasteBitmap(wxUpdateUIEvent& event);
244
245 private:
246 #if wxUSE_DRAG_AND_DROP
247 // show the result of a dnd operation in the status bar
248 void LogDragResult(wxDragResult result);
249 #endif // wxUSE_DRAG_AND_DROP
250
251
252 // GUI controls
253 wxListBox *m_ctrlFile,
254 *m_ctrlText;
255 wxGenericDirCtrl *m_ctrlDir;
256
257 #if wxUSE_LOG
258 wxTextCtrl *m_ctrlLog;
259
260 wxLog *m_pLog,
261 *m_pLogPrev;
262 #endif // wxUSE_LOG
263
264 // move the text by default (or copy)?
265 bool m_moveByDefault;
266
267 // allow moving the text at all?
268 bool m_moveAllow;
269
270 // the text we drag
271 wxString m_strText;
272
273
274 DECLARE_EVENT_TABLE()
275 };
276
277 // ----------------------------------------------------------------------------
278 // A shape is an example of application-specific data which may be transported
279 // via drag-and-drop or clipboard: in our case, we have different geometric
280 // shapes, each one with its own colour and position
281 // ----------------------------------------------------------------------------
282
283 #if wxUSE_DRAG_AND_DROP
284
285 class DnDShape
286 {
287 public:
288 enum Kind
289 {
290 None,
291 Triangle,
292 Rectangle,
293 Ellipse
294 };
295
296 DnDShape(const wxPoint& pos,
297 const wxSize& size,
298 const wxColour& col)
299 : m_pos(pos), m_size(size), m_col(col)
300 {
301 }
302
303 // this is for debugging - lets us see when exactly an object is freed
304 // (this may be later than you think if it's on the clipboard, for example)
305 virtual ~DnDShape() { }
306
307 // the functions used for drag-and-drop: they dump and restore a shape into
308 // some bitwise-copiable data (might use streams too...)
309 // ------------------------------------------------------------------------
310
311 // restore from buffer
312 static DnDShape *New(const void *buf);
313
314 virtual size_t GetDataSize() const
315 {
316 return sizeof(ShapeDump);
317 }
318
319 virtual void GetDataHere(void *buf) const
320 {
321 ShapeDump& dump = *(ShapeDump *)buf;
322 dump.x = m_pos.x;
323 dump.y = m_pos.y;
324 dump.w = m_size.x;
325 dump.h = m_size.y;
326 dump.r = m_col.Red();
327 dump.g = m_col.Green();
328 dump.b = m_col.Blue();
329 dump.k = GetKind();
330 }
331
332 // accessors
333 const wxPoint& GetPosition() const { return m_pos; }
334 const wxColour& GetColour() const { return m_col; }
335 const wxSize& GetSize() const { return m_size; }
336
337 void Move(const wxPoint& pos) { m_pos = pos; }
338
339 // to implement in derived classes
340 virtual Kind GetKind() const = 0;
341
342 virtual void Draw(wxDC& dc)
343 {
344 dc.SetPen(wxPen(m_col, 1, wxSOLID));
345 }
346
347 protected:
348 //get a point 1 up and 1 left, otherwise the mid-point of a triangle is on the line
349 wxPoint GetCentre() const
350 { return wxPoint(m_pos.x + m_size.x / 2 - 1, m_pos.y + m_size.y / 2 - 1); }
351
352 struct ShapeDump
353 {
354 wxCoord x, y, // position
355 w, h; // size
356 int k; // kind
357 unsigned char r, g, b; // colour
358 };
359
360 wxPoint m_pos;
361 wxSize m_size;
362 wxColour m_col;
363 };
364
365 class DnDTriangularShape : public DnDShape
366 {
367 public:
368 DnDTriangularShape(const wxPoint& pos,
369 const wxSize& size,
370 const wxColour& col)
371 : DnDShape(pos, size, col)
372 {
373 wxLogMessage(wxT("DnDTriangularShape is being created"));
374 }
375
376 virtual ~DnDTriangularShape()
377 {
378 wxLogMessage(wxT("DnDTriangularShape is being deleted"));
379 }
380
381 virtual Kind GetKind() const { return Triangle; }
382 virtual void Draw(wxDC& dc)
383 {
384 DnDShape::Draw(dc);
385
386 // well, it's a bit difficult to describe a triangle by position and
387 // size, but we're not doing geometry here, do we? ;-)
388 wxPoint p1(m_pos);
389 wxPoint p2(m_pos.x + m_size.x, m_pos.y);
390 wxPoint p3(m_pos.x, m_pos.y + m_size.y);
391
392 dc.DrawLine(p1, p2);
393 dc.DrawLine(p2, p3);
394 dc.DrawLine(p3, p1);
395
396 //works in multicolor modes; on GTK (at least) will fail in 16-bit color
397 dc.SetBrush(wxBrush(m_col, wxSOLID));
398 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
399 }
400 };
401
402 class DnDRectangularShape : public DnDShape
403 {
404 public:
405 DnDRectangularShape(const wxPoint& pos,
406 const wxSize& size,
407 const wxColour& col)
408 : DnDShape(pos, size, col)
409 {
410 wxLogMessage(wxT("DnDRectangularShape is being created"));
411 }
412
413 virtual ~DnDRectangularShape()
414 {
415 wxLogMessage(wxT("DnDRectangularShape is being deleted"));
416 }
417
418 virtual Kind GetKind() const { return Rectangle; }
419 virtual void Draw(wxDC& dc)
420 {
421 DnDShape::Draw(dc);
422
423 wxPoint p1(m_pos);
424 wxPoint p2(p1.x + m_size.x, p1.y);
425 wxPoint p3(p2.x, p2.y + m_size.y);
426 wxPoint p4(p1.x, p3.y);
427
428 dc.DrawLine(p1, p2);
429 dc.DrawLine(p2, p3);
430 dc.DrawLine(p3, p4);
431 dc.DrawLine(p4, p1);
432
433 dc.SetBrush(wxBrush(m_col, wxSOLID));
434 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
435 }
436 };
437
438 class DnDEllipticShape : public DnDShape
439 {
440 public:
441 DnDEllipticShape(const wxPoint& pos,
442 const wxSize& size,
443 const wxColour& col)
444 : DnDShape(pos, size, col)
445 {
446 wxLogMessage(wxT("DnDEllipticShape is being created"));
447 }
448
449 virtual ~DnDEllipticShape()
450 {
451 wxLogMessage(wxT("DnDEllipticShape is being deleted"));
452 }
453
454 virtual Kind GetKind() const { return Ellipse; }
455 virtual void Draw(wxDC& dc)
456 {
457 DnDShape::Draw(dc);
458
459 dc.DrawEllipse(m_pos, m_size);
460
461 dc.SetBrush(wxBrush(m_col, wxSOLID));
462 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
463 }
464 };
465
466 // ----------------------------------------------------------------------------
467 // A wxDataObject specialisation for the application-specific data
468 // ----------------------------------------------------------------------------
469
470 static const wxChar *shapeFormatId = wxT("wxShape");
471
472 class DnDShapeDataObject : public wxDataObject
473 {
474 public:
475 // ctor doesn't copy the pointer, so it shouldn't go away while this object
476 // is alive
477 DnDShapeDataObject(DnDShape *shape = (DnDShape *)NULL)
478 {
479 if ( shape )
480 {
481 // we need to copy the shape because the one we're handled may be
482 // deleted while it's still on the clipboard (for example) - and we
483 // reuse the serialisation methods here to copy it
484 void *buf = malloc(shape->DnDShape::GetDataSize());
485 shape->GetDataHere(buf);
486 m_shape = DnDShape::New(buf);
487
488 free(buf);
489 }
490 else
491 {
492 // nothing to copy
493 m_shape = NULL;
494 }
495
496 // this string should uniquely identify our format, but is otherwise
497 // arbitrary
498 m_formatShape.SetId(shapeFormatId);
499
500 // we don't draw the shape to a bitmap until it's really needed (i.e.
501 // we're asked to do so)
502 m_hasBitmap = false;
503 #if wxUSE_METAFILE
504 m_hasMetaFile = false;
505 #endif // wxUSE_METAFILE
506 }
507
508 virtual ~DnDShapeDataObject() { delete m_shape; }
509
510 // after a call to this function, the shape is owned by the caller and it
511 // is responsible for deleting it!
512 //
513 // NB: a better solution would be to make DnDShapes ref counted and this
514 // is what should probably be done in a real life program, otherwise
515 // the ownership problems become too complicated really fast
516 DnDShape *GetShape()
517 {
518 DnDShape *shape = m_shape;
519
520 m_shape = (DnDShape *)NULL;
521 m_hasBitmap = false;
522 #if wxUSE_METAFILE
523 m_hasMetaFile = false;
524 #endif // wxUSE_METAFILE
525
526 return shape;
527 }
528
529 // implement base class pure virtuals
530 // ----------------------------------
531
532 virtual wxDataFormat GetPreferredFormat(Direction WXUNUSED(dir)) const
533 {
534 return m_formatShape;
535 }
536
537 virtual size_t GetFormatCount(Direction dir) const
538 {
539 // our custom format is supported by both GetData() and SetData()
540 size_t nFormats = 1;
541 if ( dir == Get )
542 {
543 // but the bitmap format(s) are only supported for output
544 nFormats += m_dobjBitmap.GetFormatCount(dir);
545
546 #if wxUSE_METAFILE
547 nFormats += m_dobjMetaFile.GetFormatCount(dir);
548 #endif // wxUSE_METAFILE
549 }
550
551 return nFormats;
552 }
553
554 virtual void GetAllFormats(wxDataFormat *formats, Direction dir) const
555 {
556 formats[0] = m_formatShape;
557 if ( dir == Get )
558 {
559 // in Get direction we additionally support bitmaps and metafiles
560 // under Windows
561 m_dobjBitmap.GetAllFormats(&formats[1], dir);
562
563 #if wxUSE_METAFILE
564 // don't assume that m_dobjBitmap has only 1 format
565 m_dobjMetaFile.GetAllFormats(&formats[1 +
566 m_dobjBitmap.GetFormatCount(dir)], dir);
567 #endif // wxUSE_METAFILE
568 }
569 }
570
571 virtual size_t GetDataSize(const wxDataFormat& format) const
572 {
573 if ( format == m_formatShape )
574 {
575 return m_shape->GetDataSize();
576 }
577 #if wxUSE_METAFILE
578 else if ( m_dobjMetaFile.IsSupported(format) )
579 {
580 if ( !m_hasMetaFile )
581 CreateMetaFile();
582
583 return m_dobjMetaFile.GetDataSize(format);
584 }
585 #endif // wxUSE_METAFILE
586 else
587 {
588 wxASSERT_MSG( m_dobjBitmap.IsSupported(format),
589 wxT("unexpected format") );
590
591 if ( !m_hasBitmap )
592 CreateBitmap();
593
594 return m_dobjBitmap.GetDataSize();
595 }
596 }
597
598 virtual bool GetDataHere(const wxDataFormat& format, void *pBuf) const
599 {
600 if ( format == m_formatShape )
601 {
602 m_shape->GetDataHere(pBuf);
603
604 return true;
605 }
606 #if wxUSE_METAFILE
607 else if ( m_dobjMetaFile.IsSupported(format) )
608 {
609 if ( !m_hasMetaFile )
610 CreateMetaFile();
611
612 return m_dobjMetaFile.GetDataHere(format, pBuf);
613 }
614 #endif // wxUSE_METAFILE
615 else
616 {
617 wxASSERT_MSG( m_dobjBitmap.IsSupported(format),
618 wxT("unexpected format") );
619
620 if ( !m_hasBitmap )
621 CreateBitmap();
622
623 return m_dobjBitmap.GetDataHere(pBuf);
624 }
625 }
626
627 virtual bool SetData(const wxDataFormat& format,
628 size_t WXUNUSED(len), const void *buf)
629 {
630 wxCHECK_MSG( format == m_formatShape, false,
631 wxT( "unsupported format") );
632
633 delete m_shape;
634 m_shape = DnDShape::New(buf);
635
636 // the shape has changed
637 m_hasBitmap = false;
638
639 #if wxUSE_METAFILE
640 m_hasMetaFile = false;
641 #endif // wxUSE_METAFILE
642
643 return true;
644 }
645
646 private:
647 // creates a bitmap and assigns it to m_dobjBitmap (also sets m_hasBitmap)
648 void CreateBitmap() const;
649 #if wxUSE_METAFILE
650 void CreateMetaFile() const;
651 #endif // wxUSE_METAFILE
652
653 wxDataFormat m_formatShape; // our custom format
654
655 wxBitmapDataObject m_dobjBitmap; // it handles bitmaps
656 bool m_hasBitmap; // true if m_dobjBitmap has valid bitmap
657
658 #if wxUSE_METAFILE
659 wxMetaFileDataObject m_dobjMetaFile;// handles metafiles
660 bool m_hasMetaFile; // true if we have valid metafile
661 #endif // wxUSE_METAFILE
662
663 DnDShape *m_shape; // our data
664 };
665
666 // ----------------------------------------------------------------------------
667 // A dialog to edit shape properties
668 // ----------------------------------------------------------------------------
669
670 class DnDShapeDialog : public wxDialog
671 {
672 public:
673 DnDShapeDialog(wxFrame *parent, DnDShape *shape);
674
675 DnDShape *GetShape() const;
676
677 virtual bool TransferDataToWindow();
678 virtual bool TransferDataFromWindow();
679
680 void OnColour(wxCommandEvent& event);
681
682 private:
683 // input
684 DnDShape *m_shape;
685
686 // output
687 DnDShape::Kind m_shapeKind;
688 wxPoint m_pos;
689 wxSize m_size;
690 wxColour m_col;
691
692 // controls
693 wxRadioBox *m_radio;
694 wxTextCtrl *m_textX,
695 *m_textY,
696 *m_textW,
697 *m_textH;
698
699 DECLARE_EVENT_TABLE()
700 };
701
702 // ----------------------------------------------------------------------------
703 // A frame for the shapes which can be drag-and-dropped between frames
704 // ----------------------------------------------------------------------------
705
706 class DnDShapeFrame : public wxFrame
707 {
708 public:
709 DnDShapeFrame(wxFrame *parent);
710 ~DnDShapeFrame();
711
712 void SetShape(DnDShape *shape);
713 virtual bool SetShape(const wxRegion &region)
714 {
715 return wxFrame::SetShape( region );
716 }
717
718 // callbacks
719 void OnNewShape(wxCommandEvent& event);
720 void OnEditShape(wxCommandEvent& event);
721 void OnClearShape(wxCommandEvent& event);
722
723 void OnCopyShape(wxCommandEvent& event);
724 void OnPasteShape(wxCommandEvent& event);
725
726 void OnUpdateUICopy(wxUpdateUIEvent& event);
727 void OnUpdateUIPaste(wxUpdateUIEvent& event);
728
729 void OnDrag(wxMouseEvent& event);
730 void OnPaint(wxPaintEvent& event);
731 void OnDrop(wxCoord x, wxCoord y, DnDShape *shape);
732
733 private:
734 DnDShape *m_shape;
735
736 static DnDShapeFrame *ms_lastDropTarget;
737
738 DECLARE_EVENT_TABLE()
739 };
740
741 // ----------------------------------------------------------------------------
742 // wxDropTarget derivation for DnDShapes
743 // ----------------------------------------------------------------------------
744
745 class DnDShapeDropTarget : public wxDropTarget
746 {
747 public:
748 DnDShapeDropTarget(DnDShapeFrame *frame)
749 : wxDropTarget(new DnDShapeDataObject)
750 {
751 m_frame = frame;
752 }
753
754 // override base class (pure) virtuals
755 virtual wxDragResult OnEnter(wxCoord x, wxCoord y, wxDragResult def)
756 {
757 #if wxUSE_STATUSBAR
758 m_frame->SetStatusText(wxT("Mouse entered the frame"));
759 #endif // wxUSE_STATUSBAR
760 return OnDragOver(x, y, def);
761 }
762 virtual void OnLeave()
763 {
764 #if wxUSE_STATUSBAR
765 m_frame->SetStatusText(wxT("Mouse left the frame"));
766 #endif // wxUSE_STATUSBAR
767 }
768 virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def)
769 {
770 if ( !GetData() )
771 {
772 wxLogError(wxT("Failed to get drag and drop data"));
773
774 return wxDragNone;
775 }
776
777 m_frame->OnDrop(x, y,
778 ((DnDShapeDataObject *)GetDataObject())->GetShape());
779
780 return def;
781 }
782
783 private:
784 DnDShapeFrame *m_frame;
785 };
786
787 #endif // wxUSE_DRAG_AND_DROP
788
789 // ----------------------------------------------------------------------------
790 // functions prototypes
791 // ----------------------------------------------------------------------------
792
793 static void ShowBitmap(const wxBitmap& bitmap);
794
795 #if wxUSE_METAFILE
796 static void ShowMetaFile(const wxMetaFile& metafile);
797 #endif // wxUSE_METAFILE
798
799 // ----------------------------------------------------------------------------
800 // IDs for the menu commands
801 // ----------------------------------------------------------------------------
802
803 enum
804 {
805 Menu_Quit = 1,
806 Menu_Drag,
807 Menu_DragMoveDef,
808 Menu_DragMoveAllow,
809 Menu_NewFrame,
810 Menu_About = 101,
811 Menu_Help,
812 Menu_Clear,
813 Menu_Copy,
814 Menu_Paste,
815 Menu_CopyBitmap,
816 Menu_PasteBitmap,
817 Menu_PasteMFile,
818 Menu_CopyFiles,
819 Menu_UsePrimary,
820 Menu_Shape_New = 500,
821 Menu_Shape_Edit,
822 Menu_Shape_Clear,
823 Menu_ShapeClipboard_Copy,
824 Menu_ShapeClipboard_Paste,
825 Button_Colour = 1001
826 };
827
828 BEGIN_EVENT_TABLE(DnDFrame, wxFrame)
829 EVT_MENU(Menu_Quit, DnDFrame::OnQuit)
830 EVT_MENU(Menu_About, DnDFrame::OnAbout)
831 EVT_MENU(Menu_Drag, DnDFrame::OnDrag)
832 EVT_MENU(Menu_DragMoveDef, DnDFrame::OnDragMoveByDefault)
833 EVT_MENU(Menu_DragMoveAllow,DnDFrame::OnDragMoveAllow)
834 EVT_MENU(Menu_NewFrame, DnDFrame::OnNewFrame)
835 EVT_MENU(Menu_Help, DnDFrame::OnHelp)
836 #if wxUSE_LOG
837 EVT_MENU(Menu_Clear, DnDFrame::OnLogClear)
838 #endif // wxUSE_LOG
839 EVT_MENU(Menu_Copy, DnDFrame::OnCopy)
840 EVT_MENU(Menu_Paste, DnDFrame::OnPaste)
841 EVT_MENU(Menu_CopyBitmap, DnDFrame::OnCopyBitmap)
842 EVT_MENU(Menu_PasteBitmap,DnDFrame::OnPasteBitmap)
843 #if wxUSE_METAFILE
844 EVT_MENU(Menu_PasteMFile, DnDFrame::OnPasteMetafile)
845 #endif // wxUSE_METAFILE
846 EVT_MENU(Menu_CopyFiles, DnDFrame::OnCopyFiles)
847 EVT_MENU(Menu_UsePrimary, DnDFrame::OnUsePrimary)
848
849 EVT_UPDATE_UI(Menu_DragMoveDef, DnDFrame::OnUpdateUIMoveByDefault)
850
851 EVT_UPDATE_UI(Menu_Paste, DnDFrame::OnUpdateUIPasteText)
852 EVT_UPDATE_UI(Menu_PasteBitmap, DnDFrame::OnUpdateUIPasteBitmap)
853
854 EVT_LEFT_DOWN( DnDFrame::OnLeftDown)
855 EVT_RIGHT_DOWN( DnDFrame::OnRightDown)
856 EVT_PAINT( DnDFrame::OnPaint)
857 EVT_SIZE( DnDFrame::OnSize)
858 END_EVENT_TABLE()
859
860 #if wxUSE_DRAG_AND_DROP
861
862 BEGIN_EVENT_TABLE(DnDShapeFrame, wxFrame)
863 EVT_MENU(Menu_Shape_New, DnDShapeFrame::OnNewShape)
864 EVT_MENU(Menu_Shape_Edit, DnDShapeFrame::OnEditShape)
865 EVT_MENU(Menu_Shape_Clear, DnDShapeFrame::OnClearShape)
866
867 EVT_MENU(Menu_ShapeClipboard_Copy, DnDShapeFrame::OnCopyShape)
868 EVT_MENU(Menu_ShapeClipboard_Paste, DnDShapeFrame::OnPasteShape)
869
870 EVT_UPDATE_UI(Menu_ShapeClipboard_Copy, DnDShapeFrame::OnUpdateUICopy)
871 EVT_UPDATE_UI(Menu_ShapeClipboard_Paste, DnDShapeFrame::OnUpdateUIPaste)
872
873 EVT_LEFT_DOWN(DnDShapeFrame::OnDrag)
874
875 EVT_PAINT(DnDShapeFrame::OnPaint)
876 END_EVENT_TABLE()
877
878 BEGIN_EVENT_TABLE(DnDShapeDialog, wxDialog)
879 EVT_BUTTON(Button_Colour, DnDShapeDialog::OnColour)
880 END_EVENT_TABLE()
881
882 #endif // wxUSE_DRAG_AND_DROP
883
884 BEGIN_EVENT_TABLE(DnDCanvasBitmap, wxScrolledWindow)
885 EVT_PAINT(DnDCanvasBitmap::OnPaint)
886 END_EVENT_TABLE()
887
888 #if wxUSE_METAFILE
889 BEGIN_EVENT_TABLE(DnDCanvasMetafile, wxScrolledWindow)
890 EVT_PAINT(DnDCanvasMetafile::OnPaint)
891 END_EVENT_TABLE()
892 #endif // wxUSE_METAFILE
893
894 #endif // wxUSE_DRAG_AND_DROP
895
896 // ============================================================================
897 // implementation
898 // ============================================================================
899
900 // `Main program' equivalent, creating windows and returning main app frame
901 bool DnDApp::OnInit()
902 {
903 if ( !wxApp::OnInit() )
904 return false;
905
906 #if wxUSE_DRAG_AND_DROP || wxUSE_CLIPBOARD
907 // switch on trace messages
908 #if wxUSE_LOG
909 #if defined(__WXGTK__)
910 wxLog::AddTraceMask(wxT("clipboard"));
911 #elif defined(__WXMSW__)
912 wxLog::AddTraceMask(wxTRACE_OleCalls);
913 #endif
914 #endif // wxUSE_LOG
915
916 #if wxUSE_LIBPNG
917 wxImage::AddHandler( new wxPNGHandler );
918 #endif
919
920 // create the main frame window
921 new DnDFrame();
922
923 return true;
924 #else
925 wxMessageBox( wxT("This sample has to be compiled with wxUSE_DRAG_AND_DROP"), wxT("Building error"), wxOK);
926 return false;
927 #endif // wxUSE_DRAG_AND_DROP
928 }
929
930 #if wxUSE_DRAG_AND_DROP || wxUSE_CLIPBOARD
931
932 DnDFrame::DnDFrame()
933 : wxFrame(NULL, wxID_ANY, wxT("Drag-and-Drop/Clipboard wxWidgets Sample"),
934 wxPoint(10, 100)),
935 m_strText(wxT("wxWidgets drag & drop works :-)"))
936
937 {
938 // frame icon and status bar
939 SetIcon(wxICON(sample));
940
941 #if wxUSE_STATUSBAR
942 CreateStatusBar();
943 #endif // wxUSE_STATUSBAR
944
945 // construct menu
946 wxMenu *file_menu = new wxMenu;
947 file_menu->Append(Menu_Drag, wxT("&Test drag..."));
948 file_menu->AppendCheckItem(Menu_DragMoveDef, wxT("&Move by default"));
949 file_menu->AppendCheckItem(Menu_DragMoveAllow, wxT("&Allow moving"));
950 file_menu->AppendSeparator();
951 file_menu->Append(Menu_NewFrame, wxT("&New frame\tCtrl-N"));
952 file_menu->AppendSeparator();
953 file_menu->Append(Menu_Quit, wxT("E&xit\tCtrl-Q"));
954
955 #if wxUSE_LOG
956 wxMenu *log_menu = new wxMenu;
957 log_menu->Append(Menu_Clear, wxT("Clear\tCtrl-L"));
958 #endif // wxUSE_LOG
959
960 wxMenu *help_menu = new wxMenu;
961 help_menu->Append(Menu_Help, wxT("&Help..."));
962 help_menu->AppendSeparator();
963 help_menu->Append(Menu_About, wxT("&About"));
964
965 wxMenu *clip_menu = new wxMenu;
966 clip_menu->Append(Menu_Copy, wxT("&Copy text\tCtrl-C"));
967 clip_menu->Append(Menu_Paste, wxT("&Paste text\tCtrl-V"));
968 clip_menu->AppendSeparator();
969 clip_menu->Append(Menu_CopyBitmap, wxT("Copy &bitmap\tCtrl-Shift-C"));
970 clip_menu->Append(Menu_PasteBitmap, wxT("Paste b&itmap\tCtrl-Shift-V"));
971 #if wxUSE_METAFILE
972 clip_menu->AppendSeparator();
973 clip_menu->Append(Menu_PasteMFile, wxT("Paste &metafile\tCtrl-M"));
974 #endif // wxUSE_METAFILE
975 clip_menu->AppendSeparator();
976 clip_menu->Append(Menu_CopyFiles, wxT("Copy &files\tCtrl-F"));
977 clip_menu->AppendSeparator();
978 clip_menu->AppendCheckItem(Menu_UsePrimary, wxT("Use &primary selection\tCtrl-P"));
979
980 wxMenuBar *menu_bar = new wxMenuBar;
981 menu_bar->Append(file_menu, wxT("&File"));
982 #if wxUSE_LOG
983 menu_bar->Append(log_menu, wxT("&Log"));
984 #endif // wxUSE_LOG
985 menu_bar->Append(clip_menu, wxT("&Clipboard"));
986 menu_bar->Append(help_menu, wxT("&Help"));
987
988 SetMenuBar(menu_bar);
989
990 // create the child controls
991 SetBackgroundColour(*wxWHITE); // labels read better on this background
992
993 wxString strFile(wxT("Drop files here!")), strText(wxT("Drop text on me"));
994
995 m_ctrlFile = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 1, &strFile,
996 wxLB_HSCROLL | wxLB_ALWAYS_SB );
997 m_ctrlText = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 1, &strText,
998 wxLB_HSCROLL | wxLB_ALWAYS_SB );
999 m_ctrlDir = new wxGenericDirCtrl(this);
1000
1001 #if wxUSE_LOG
1002 m_ctrlLog = new wxTextCtrl(this, wxID_ANY, wxEmptyString,
1003 wxDefaultPosition, wxDefaultSize,
1004 wxTE_MULTILINE | wxTE_READONLY |
1005 wxSUNKEN_BORDER );
1006
1007 // redirect log messages to the text window
1008 m_pLog = new wxLogTextCtrl(m_ctrlLog);
1009 m_pLogPrev = wxLog::SetActiveTarget(m_pLog);
1010 #endif // wxUSE_LOG
1011
1012 #if wxUSE_DRAG_AND_DROP
1013 // associate drop targets with the controls
1014 m_ctrlFile->SetDropTarget(new DnDFile(m_ctrlFile));
1015 m_ctrlText->SetDropTarget(new DnDText(m_ctrlText));
1016
1017 #if wxUSE_DRAG_AND_DROP
1018 m_ctrlDir->Connect
1019 (
1020 wxID_ANY,
1021 wxEVT_COMMAND_TREE_BEGIN_DRAG,
1022 wxTreeEventHandler(DnDFrame::OnBeginDrag),
1023 NULL,
1024 this
1025 );
1026 #endif // wxUSE_DRAG_AND_DROP
1027
1028 #if wxUSE_LOG
1029 m_ctrlLog->SetDropTarget(new URLDropTarget);
1030 #endif // wxUSE_LOG
1031 #endif // wxUSE_DRAG_AND_DROP
1032
1033 wxBoxSizer *sizer_top = new wxBoxSizer( wxHORIZONTAL );
1034 sizer_top->Add(m_ctrlFile, 1, wxEXPAND );
1035 sizer_top->Add(m_ctrlText, 1, wxEXPAND );
1036
1037 wxBoxSizer *sizerDirCtrl = new wxBoxSizer(wxVERTICAL);
1038 sizerDirCtrl->Add(new wxStaticText(this, wxID_ANY, "Drag files from here"),
1039 wxSizerFlags().Centre().Border());
1040 sizerDirCtrl->Add(m_ctrlDir, wxSizerFlags(1).Expand());
1041 sizer_top->Add(sizerDirCtrl, 1, wxEXPAND );
1042
1043 // make all columns of reasonable minimal size
1044 for ( unsigned n = 0; n < sizer_top->GetChildren().size(); n++ )
1045 sizer_top->SetItemMinSize(n, 200, 300);
1046
1047 wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
1048 sizer->Add(sizer_top, 1, wxEXPAND );
1049 #if wxUSE_LOG
1050 sizer->Add(m_ctrlLog, 2, wxEXPAND);
1051 sizer->SetItemMinSize(m_ctrlLog, 450, 200);
1052 #endif // wxUSE_LOG
1053 sizer->AddSpacer(50);
1054
1055 // copy data by default but allow moving it as well
1056 m_moveByDefault = false;
1057 m_moveAllow = true;
1058 menu_bar->Check(Menu_DragMoveAllow, true);
1059
1060 // set the correct size and show the frame
1061 SetSizerAndFit(sizer);
1062 Show();
1063 }
1064
1065 void DnDFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
1066 {
1067 Close(true);
1068 }
1069
1070 void DnDFrame::OnSize(wxSizeEvent& event)
1071 {
1072 Refresh();
1073
1074 event.Skip();
1075 }
1076
1077 void DnDFrame::OnPaint(wxPaintEvent& WXUNUSED(event))
1078 {
1079 int w = 0;
1080 int h = 0;
1081 GetClientSize( &w, &h );
1082
1083 wxPaintDC dc(this);
1084 // dc.Clear(); -- this kills wxGTK
1085 dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL, false, wxT("charter") ) );
1086 dc.DrawText( wxT("Drag text from here!"), 100, h-50 );
1087 }
1088
1089 void DnDFrame::OnUpdateUIMoveByDefault(wxUpdateUIEvent& event)
1090 {
1091 // only can move by default if moving is allowed at all
1092 event.Enable(m_moveAllow);
1093 }
1094
1095 void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent& event)
1096 {
1097 #ifdef __WXDEBUG__
1098 // too many trace messages if we don't do it - this function is called
1099 // very often
1100 wxLogNull nolog;
1101 #endif
1102
1103 event.Enable( wxTheClipboard->IsSupported(wxDF_TEXT) );
1104 }
1105
1106 void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent& event)
1107 {
1108 #ifdef __WXDEBUG__
1109 // too many trace messages if we don't do it - this function is called
1110 // very often
1111 wxLogNull nolog;
1112 #endif
1113
1114 event.Enable( wxTheClipboard->IsSupported(wxDF_BITMAP) );
1115 }
1116
1117 void DnDFrame::OnNewFrame(wxCommandEvent& WXUNUSED(event))
1118 {
1119 #if wxUSE_DRAG_AND_DROP
1120 (new DnDShapeFrame(this))->Show(true);
1121
1122 wxLogStatus(this, wxT("Double click the new frame to select a shape for it"));
1123 #endif // wxUSE_DRAG_AND_DROP
1124 }
1125
1126 void DnDFrame::OnDrag(wxCommandEvent& WXUNUSED(event))
1127 {
1128 #if wxUSE_DRAG_AND_DROP
1129 wxString strText = wxGetTextFromUser
1130 (
1131 wxT("After you enter text in this dialog, press any mouse\n")
1132 wxT("button in the bottom (empty) part of the frame and \n")
1133 wxT("drag it anywhere - you will be in fact dragging the\n")
1134 wxT("text object containing this text"),
1135 wxT("Please enter some text"), m_strText, this
1136 );
1137
1138 m_strText = strText;
1139 #endif // wxUSE_DRAG_AND_DROP
1140 }
1141
1142 void DnDFrame::OnDragMoveByDefault(wxCommandEvent& event)
1143 {
1144 m_moveByDefault = event.IsChecked();
1145 }
1146
1147 void DnDFrame::OnDragMoveAllow(wxCommandEvent& event)
1148 {
1149 m_moveAllow = event.IsChecked();
1150 }
1151
1152 void DnDFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
1153 {
1154 wxMessageBox(wxT("Drag-&-Drop Demo\n")
1155 wxT("Please see \"Help|Help...\" for details\n")
1156 wxT("Copyright (c) 1998 Vadim Zeitlin"),
1157 wxT("About wxDnD"),
1158 wxICON_INFORMATION | wxOK,
1159 this);
1160 }
1161
1162 void DnDFrame::OnHelp(wxCommandEvent& /* event */)
1163 {
1164 wxMessageDialog dialog(this,
1165 wxT("This small program demonstrates drag & drop support in wxWidgets. The program window\n")
1166 wxT("consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n")
1167 wxT("going on inside. The top part is split into 2 listboxes, the left one accepts files\n")
1168 wxT("and the right one accepts text.\n")
1169 wxT("\n")
1170 wxT("To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n")
1171 wxT("the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n")
1172 wxT("Also, try dragging some files (you can select several at once) from Windows Explorer (or \n")
1173 wxT("File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n")
1174 wxT("work with files) and see what changes.\n")
1175 wxT("\n")
1176 wxT("To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n")
1177 wxT("it to wordpad or any other droptarget accepting text (and of course you can just drag it\n")
1178 wxT("to the right pane). Due to a lot of trace messages, the cursor might take some time to \n")
1179 wxT("change, don't release the mouse button until it does. You can change the string being\n")
1180 wxT("dragged in \"File|Test drag...\" dialog.\n")
1181 wxT("\n")
1182 wxT("\n")
1183 wxT("Please send all questions/bug reports/suggestions &c to \n")
1184 wxT("Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>"),
1185 wxT("wxDnD Help"));
1186
1187 dialog.ShowModal();
1188 }
1189
1190 #if wxUSE_LOG
1191 void DnDFrame::OnLogClear(wxCommandEvent& /* event */ )
1192 {
1193 m_ctrlLog->Clear();
1194 m_ctrlText->Clear();
1195 m_ctrlFile->Clear();
1196 }
1197 #endif // wxUSE_LOG
1198
1199 #if wxUSE_DRAG_AND_DROP
1200
1201 void DnDFrame::LogDragResult(wxDragResult result)
1202 {
1203 #if wxUSE_STATUSBAR
1204 const wxChar *pc;
1205 switch ( result )
1206 {
1207 case wxDragError: pc = wxT("Error!"); break;
1208 case wxDragNone: pc = wxT("Nothing"); break;
1209 case wxDragCopy: pc = wxT("Copied"); break;
1210 case wxDragMove: pc = wxT("Moved"); break;
1211 case wxDragCancel: pc = wxT("Cancelled"); break;
1212 default: pc = wxT("Huh?"); break;
1213 }
1214
1215 SetStatusText(wxString(wxT("Drag result: ")) + pc);
1216 #else
1217 wxUnusedVar(result);
1218 #endif // wxUSE_STATUSBAR
1219 }
1220
1221 #endif // wxUSE_DRAG_AND_DROP
1222
1223 void DnDFrame::OnLeftDown(wxMouseEvent &WXUNUSED(event) )
1224 {
1225 #if wxUSE_DRAG_AND_DROP
1226 if ( !m_strText.empty() )
1227 {
1228 // start drag operation
1229 wxTextDataObject textData(m_strText);
1230 wxDropSource source(textData, this,
1231 wxDROP_ICON(dnd_copy),
1232 wxDROP_ICON(dnd_move),
1233 wxDROP_ICON(dnd_none));
1234
1235 int flags = 0;
1236 if ( m_moveByDefault )
1237 flags |= wxDrag_DefaultMove;
1238 else if ( m_moveAllow )
1239 flags |= wxDrag_AllowMove;
1240
1241 LogDragResult(source.DoDragDrop(flags));
1242 }
1243 #endif // wxUSE_DRAG_AND_DROP
1244 }
1245
1246 void DnDFrame::OnRightDown(wxMouseEvent &event )
1247 {
1248 wxMenu menu(wxT("Dnd sample menu"));
1249
1250 menu.Append(Menu_Drag, wxT("&Test drag..."));
1251 menu.AppendSeparator();
1252 menu.Append(Menu_About, wxT("&About"));
1253
1254 PopupMenu( &menu, event.GetX(), event.GetY() );
1255 }
1256
1257 DnDFrame::~DnDFrame()
1258 {
1259 #if wxUSE_LOG
1260 if ( m_pLog != NULL ) {
1261 if ( wxLog::SetActiveTarget(m_pLogPrev) == m_pLog )
1262 delete m_pLog;
1263 }
1264 #endif // wxUSE_LOG
1265 }
1266
1267 void DnDFrame::OnUsePrimary(wxCommandEvent& event)
1268 {
1269 const bool usePrimary = event.IsChecked();
1270 wxTheClipboard->UsePrimarySelection(usePrimary);
1271
1272 wxLogStatus(wxT("Now using %s selection"), usePrimary ? wxT("primary")
1273 : wxT("clipboard"));
1274 }
1275
1276 #if wxUSE_DRAG_AND_DROP
1277
1278 void DnDFrame::OnBeginDrag(wxTreeEvent& WXUNUSED(event))
1279 {
1280 wxFileDataObject data;
1281 data.AddFile(m_ctrlDir->GetPath());
1282
1283 wxDropSource dragSource(this);
1284 dragSource.SetData(data);
1285
1286 LogDragResult(dragSource.DoDragDrop());
1287 }
1288
1289 #endif // wxUSE_DRAG_AND_DROP
1290
1291 // ---------------------------------------------------------------------------
1292 // bitmap clipboard
1293 // ---------------------------------------------------------------------------
1294
1295 void DnDFrame::OnCopyBitmap(wxCommandEvent& WXUNUSED(event))
1296 {
1297 // PNG support is not always compiled in under Windows, so use BMP there
1298 #if wxUSE_LIBPNG
1299 wxFileDialog dialog(this, wxT("Open a PNG file"), wxEmptyString, wxEmptyString, wxT("PNG files (*.png)|*.png"), 0);
1300 #else
1301 wxFileDialog dialog(this, wxT("Open a BMP file"), wxEmptyString, wxEmptyString, wxT("BMP files (*.bmp)|*.bmp"), 0);
1302 #endif
1303
1304 if (dialog.ShowModal() != wxID_OK)
1305 {
1306 wxLogMessage( wxT("Aborted file open") );
1307 return;
1308 }
1309
1310 if (dialog.GetPath().empty())
1311 {
1312 wxLogMessage( wxT("Returned empty string.") );
1313 return;
1314 }
1315
1316 if (!wxFileExists(dialog.GetPath()))
1317 {
1318 wxLogMessage( wxT("File doesn't exist.") );
1319 return;
1320 }
1321
1322 wxImage image;
1323 image.LoadFile( dialog.GetPath(),
1324 #if wxUSE_LIBPNG
1325 wxBITMAP_TYPE_PNG
1326 #else
1327 wxBITMAP_TYPE_BMP
1328 #endif
1329 );
1330 if (!image.IsOk())
1331 {
1332 wxLogError( wxT("Invalid image file...") );
1333 return;
1334 }
1335
1336 wxLogStatus( wxT("Decoding image file...") );
1337 wxYield();
1338
1339 wxBitmap bitmap( image );
1340
1341 if ( !wxTheClipboard->Open() )
1342 {
1343 wxLogError(wxT("Can't open clipboard."));
1344
1345 return;
1346 }
1347
1348 wxLogMessage( wxT("Creating wxBitmapDataObject...") );
1349 wxYield();
1350
1351 if ( !wxTheClipboard->AddData(new wxBitmapDataObject(bitmap)) )
1352 {
1353 wxLogError(wxT("Can't copy image to the clipboard."));
1354 }
1355 else
1356 {
1357 wxLogMessage(wxT("Image has been put on the clipboard.") );
1358 wxLogMessage(wxT("You can paste it now and look at it.") );
1359 }
1360
1361 wxTheClipboard->Close();
1362 }
1363
1364 void DnDFrame::OnPasteBitmap(wxCommandEvent& WXUNUSED(event))
1365 {
1366 if ( !wxTheClipboard->Open() )
1367 {
1368 wxLogError(wxT("Can't open clipboard."));
1369
1370 return;
1371 }
1372
1373 if ( !wxTheClipboard->IsSupported(wxDF_BITMAP) )
1374 {
1375 wxLogWarning(wxT("No bitmap on clipboard"));
1376
1377 wxTheClipboard->Close();
1378 return;
1379 }
1380
1381 wxBitmapDataObject data;
1382 if ( !wxTheClipboard->GetData(data) )
1383 {
1384 wxLogError(wxT("Can't paste bitmap from the clipboard"));
1385 }
1386 else
1387 {
1388 const wxBitmap& bmp = data.GetBitmap();
1389
1390 wxLogMessage(wxT("Bitmap %dx%d pasted from the clipboard"),
1391 bmp.GetWidth(), bmp.GetHeight());
1392 ShowBitmap(bmp);
1393 }
1394
1395 wxTheClipboard->Close();
1396 }
1397
1398 #if wxUSE_METAFILE
1399
1400 void DnDFrame::OnPasteMetafile(wxCommandEvent& WXUNUSED(event))
1401 {
1402 if ( !wxTheClipboard->Open() )
1403 {
1404 wxLogError(wxT("Can't open clipboard."));
1405
1406 return;
1407 }
1408
1409 if ( !wxTheClipboard->IsSupported(wxDF_METAFILE) )
1410 {
1411 wxLogWarning(wxT("No metafile on clipboard"));
1412 }
1413 else
1414 {
1415 wxMetaFileDataObject data;
1416 if ( !wxTheClipboard->GetData(data) )
1417 {
1418 wxLogError(wxT("Can't paste metafile from the clipboard"));
1419 }
1420 else
1421 {
1422 const wxMetaFile& mf = data.GetMetafile();
1423
1424 wxLogMessage(wxT("Metafile %dx%d pasted from the clipboard"),
1425 mf.GetWidth(), mf.GetHeight());
1426
1427 ShowMetaFile(mf);
1428 }
1429 }
1430
1431 wxTheClipboard->Close();
1432 }
1433
1434 #endif // wxUSE_METAFILE
1435
1436 // ----------------------------------------------------------------------------
1437 // file clipboard
1438 // ----------------------------------------------------------------------------
1439
1440 void DnDFrame::OnCopyFiles(wxCommandEvent& WXUNUSED(event))
1441 {
1442 #ifdef __WXMSW__
1443 wxFileDialog dialog(this, wxT("Select a file to copy"), wxEmptyString, wxEmptyString,
1444 wxT("All files (*.*)|*.*"), 0);
1445
1446 wxArrayString filenames;
1447 while ( dialog.ShowModal() == wxID_OK )
1448 {
1449 filenames.Add(dialog.GetPath());
1450 }
1451
1452 if ( !filenames.IsEmpty() )
1453 {
1454 wxFileDataObject *dobj = new wxFileDataObject;
1455 size_t count = filenames.GetCount();
1456 for ( size_t n = 0; n < count; n++ )
1457 {
1458 dobj->AddFile(filenames[n]);
1459 }
1460
1461 wxClipboardLocker locker;
1462 if ( !locker )
1463 {
1464 wxLogError(wxT("Can't open clipboard"));
1465 }
1466 else
1467 {
1468 if ( !wxTheClipboard->AddData(dobj) )
1469 {
1470 wxLogError(wxT("Can't copy file(s) to the clipboard"));
1471 }
1472 else
1473 {
1474 wxLogStatus(this, wxT("%d file%s copied to the clipboard"),
1475 count, count == 1 ? wxEmptyString : wxEmptyString);
1476 }
1477 }
1478 }
1479 else
1480 {
1481 wxLogStatus(this, wxT("Aborted"));
1482 }
1483 #else // !MSW
1484 wxLogError(wxT("Sorry, not implemented"));
1485 #endif // MSW/!MSW
1486 }
1487
1488 // ---------------------------------------------------------------------------
1489 // text clipboard
1490 // ---------------------------------------------------------------------------
1491
1492 void DnDFrame::OnCopy(wxCommandEvent& WXUNUSED(event))
1493 {
1494 if ( !wxTheClipboard->Open() )
1495 {
1496 wxLogError(wxT("Can't open clipboard."));
1497
1498 return;
1499 }
1500
1501 if ( !wxTheClipboard->AddData(new wxTextDataObject(m_strText)) )
1502 {
1503 wxLogError(wxT("Can't copy data to the clipboard"));
1504 }
1505 else
1506 {
1507 wxLogMessage(wxT("Text '%s' put on the clipboard"), m_strText.c_str());
1508 }
1509
1510 wxTheClipboard->Close();
1511 }
1512
1513 void DnDFrame::OnPaste(wxCommandEvent& WXUNUSED(event))
1514 {
1515 if ( !wxTheClipboard->Open() )
1516 {
1517 wxLogError(wxT("Can't open clipboard."));
1518
1519 return;
1520 }
1521
1522 if ( !wxTheClipboard->IsSupported(wxDF_TEXT) )
1523 {
1524 wxLogWarning(wxT("No text data on clipboard"));
1525
1526 wxTheClipboard->Close();
1527 return;
1528 }
1529
1530 wxTextDataObject text;
1531 if ( !wxTheClipboard->GetData(text) )
1532 {
1533 wxLogError(wxT("Can't paste data from the clipboard"));
1534 }
1535 else
1536 {
1537 wxLogMessage(wxT("Text '%s' pasted from the clipboard"),
1538 text.GetText().c_str());
1539 }
1540
1541 wxTheClipboard->Close();
1542 }
1543
1544 #if wxUSE_DRAG_AND_DROP
1545
1546 // ----------------------------------------------------------------------------
1547 // Notifications called by the base class
1548 // ----------------------------------------------------------------------------
1549
1550 bool DnDText::OnDropText(wxCoord, wxCoord, const wxString& text)
1551 {
1552 m_pOwner->Append(text);
1553
1554 return true;
1555 }
1556
1557 bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& filenames)
1558 {
1559 size_t nFiles = filenames.GetCount();
1560 wxString str;
1561 str.Printf( wxT("%d files dropped"), (int)nFiles);
1562
1563 if (m_pOwner != NULL)
1564 {
1565 m_pOwner->Append(str);
1566 for ( size_t n = 0; n < nFiles; n++ )
1567 m_pOwner->Append(filenames[n]);
1568 }
1569
1570 return true;
1571 }
1572
1573 // ----------------------------------------------------------------------------
1574 // DnDShapeDialog
1575 // ----------------------------------------------------------------------------
1576
1577 DnDShapeDialog::DnDShapeDialog(wxFrame *parent, DnDShape *shape)
1578 :wxDialog( parent, 6001, wxT("Choose Shape"), wxPoint( 10, 10 ),
1579 wxSize( 40, 40 ),
1580 wxDEFAULT_DIALOG_STYLE | wxRAISED_BORDER | wxRESIZE_BORDER )
1581 {
1582 m_shape = shape;
1583 wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL );
1584
1585 // radio box
1586 wxBoxSizer* shapesSizer = new wxBoxSizer( wxHORIZONTAL );
1587 const wxString choices[] = { wxT("None"), wxT("Triangle"),
1588 wxT("Rectangle"), wxT("Ellipse") };
1589
1590 m_radio = new wxRadioBox( this, wxID_ANY, wxT("&Shape"),
1591 wxDefaultPosition, wxDefaultSize, 4, choices, 4,
1592 wxRA_SPECIFY_COLS );
1593 shapesSizer->Add( m_radio, 0, wxGROW|wxALL, 5 );
1594 topSizer->Add( shapesSizer, 0, wxALL, 2 );
1595
1596 // attributes
1597 wxStaticBox* box = new wxStaticBox( this, wxID_ANY, wxT("&Attributes") );
1598 wxStaticBoxSizer* attrSizer = new wxStaticBoxSizer( box, wxHORIZONTAL );
1599 wxFlexGridSizer* xywhSizer = new wxFlexGridSizer( 2 );
1600
1601 wxStaticText* st;
1602
1603 st = new wxStaticText( this, wxID_ANY, wxT("Position &X:") );
1604 m_textX = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition,
1605 wxSize( 30, 20 ) );
1606 xywhSizer->Add( st, 1, wxGROW|wxALL, 2 );
1607 xywhSizer->Add( m_textX, 1, wxGROW|wxALL, 2 );
1608
1609 st = new wxStaticText( this, wxID_ANY, wxT("Size &width:") );
1610 m_textW = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition,
1611 wxSize( 30, 20 ) );
1612 xywhSizer->Add( st, 1, wxGROW|wxALL, 2 );
1613 xywhSizer->Add( m_textW, 1, wxGROW|wxALL, 2 );
1614
1615 st = new wxStaticText( this, wxID_ANY, wxT("&Y:") );
1616 m_textY = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition,
1617 wxSize( 30, 20 ) );
1618 xywhSizer->Add( st, 1, wxALL|wxALIGN_RIGHT, 2 );
1619 xywhSizer->Add( m_textY, 1, wxGROW|wxALL, 2 );
1620
1621 st = new wxStaticText( this, wxID_ANY, wxT("&height:") );
1622 m_textH = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition,
1623 wxSize( 30, 20 ) );
1624 xywhSizer->Add( st, 1, wxALL|wxALIGN_RIGHT, 2 );
1625 xywhSizer->Add( m_textH, 1, wxGROW|wxALL, 2 );
1626
1627 wxButton* col = new wxButton( this, Button_Colour, wxT("&Colour...") );
1628 attrSizer->Add( xywhSizer, 1, wxGROW );
1629 attrSizer->Add( col, 0, wxALL|wxALIGN_CENTRE_VERTICAL, 2 );
1630 topSizer->Add( attrSizer, 0, wxGROW|wxALL, 5 );
1631
1632 // buttons
1633 wxBoxSizer* buttonSizer = new wxBoxSizer( wxHORIZONTAL );
1634 wxButton* bt;
1635 bt = new wxButton( this, wxID_OK, wxT("Ok") );
1636 buttonSizer->Add( bt, 0, wxALL, 2 );
1637 bt = new wxButton( this, wxID_CANCEL, wxT("Cancel") );
1638 buttonSizer->Add( bt, 0, wxALL, 2 );
1639 topSizer->Add( buttonSizer, 0, wxALL|wxALIGN_RIGHT, 2 );
1640
1641 SetSizerAndFit( topSizer );
1642 }
1643
1644 DnDShape *DnDShapeDialog::GetShape() const
1645 {
1646 switch ( m_shapeKind )
1647 {
1648 default:
1649 case DnDShape::None: return NULL;
1650 case DnDShape::Triangle: return new DnDTriangularShape(m_pos, m_size, m_col);
1651 case DnDShape::Rectangle: return new DnDRectangularShape(m_pos, m_size, m_col);
1652 case DnDShape::Ellipse: return new DnDEllipticShape(m_pos, m_size, m_col);
1653 }
1654 }
1655
1656 bool DnDShapeDialog::TransferDataToWindow()
1657 {
1658
1659 if ( m_shape )
1660 {
1661 m_radio->SetSelection(m_shape->GetKind());
1662 m_pos = m_shape->GetPosition();
1663 m_size = m_shape->GetSize();
1664 m_col = m_shape->GetColour();
1665 }
1666 else
1667 {
1668 m_radio->SetSelection(DnDShape::None);
1669 m_pos = wxPoint(1, 1);
1670 m_size = wxSize(100, 100);
1671 }
1672
1673 m_textX->SetValue(wxString() << m_pos.x);
1674 m_textY->SetValue(wxString() << m_pos.y);
1675 m_textW->SetValue(wxString() << m_size.x);
1676 m_textH->SetValue(wxString() << m_size.y);
1677
1678 return true;
1679 }
1680
1681 bool DnDShapeDialog::TransferDataFromWindow()
1682 {
1683 m_shapeKind = (DnDShape::Kind)m_radio->GetSelection();
1684
1685 m_pos.x = wxAtoi(m_textX->GetValue());
1686 m_pos.y = wxAtoi(m_textY->GetValue());
1687 m_size.x = wxAtoi(m_textW->GetValue());
1688 m_size.y = wxAtoi(m_textH->GetValue());
1689
1690 if ( !m_pos.x || !m_pos.y || !m_size.x || !m_size.y )
1691 {
1692 wxMessageBox(wxT("All sizes and positions should be non null!"),
1693 wxT("Invalid shape"), wxICON_HAND | wxOK, this);
1694
1695 return false;
1696 }
1697
1698 return true;
1699 }
1700
1701 void DnDShapeDialog::OnColour(wxCommandEvent& WXUNUSED(event))
1702 {
1703 wxColourData data;
1704 data.SetChooseFull(true);
1705 for (int i = 0; i < 16; i++)
1706 {
1707 wxColour colour((unsigned char)(i*16), (unsigned char)(i*16), (unsigned char)(i*16));
1708 data.SetCustomColour(i, colour);
1709 }
1710
1711 wxColourDialog dialog(this, &data);
1712 if ( dialog.ShowModal() == wxID_OK )
1713 {
1714 m_col = dialog.GetColourData().GetColour();
1715 }
1716 }
1717
1718 // ----------------------------------------------------------------------------
1719 // DnDShapeFrame
1720 // ----------------------------------------------------------------------------
1721
1722 DnDShapeFrame *DnDShapeFrame::ms_lastDropTarget = NULL;
1723
1724 DnDShapeFrame::DnDShapeFrame(wxFrame *parent)
1725 : wxFrame(parent, wxID_ANY, wxT("Shape Frame"))
1726 {
1727 #if wxUSE_STATUSBAR
1728 CreateStatusBar();
1729 #endif // wxUSE_STATUSBAR
1730
1731 wxMenu *menuShape = new wxMenu;
1732 menuShape->Append(Menu_Shape_New, wxT("&New default shape\tCtrl-S"));
1733 menuShape->Append(Menu_Shape_Edit, wxT("&Edit shape\tCtrl-E"));
1734 menuShape->AppendSeparator();
1735 menuShape->Append(Menu_Shape_Clear, wxT("&Clear shape\tCtrl-L"));
1736
1737 wxMenu *menuClipboard = new wxMenu;
1738 menuClipboard->Append(Menu_ShapeClipboard_Copy, wxT("&Copy\tCtrl-C"));
1739 menuClipboard->Append(Menu_ShapeClipboard_Paste, wxT("&Paste\tCtrl-V"));
1740
1741 wxMenuBar *menubar = new wxMenuBar;
1742 menubar->Append(menuShape, wxT("&Shape"));
1743 menubar->Append(menuClipboard, wxT("&Clipboard"));
1744
1745 SetMenuBar(menubar);
1746
1747 #if wxUSE_STATUSBAR
1748 SetStatusText(wxT("Press Ctrl-S to create a new shape"));
1749 #endif // wxUSE_STATUSBAR
1750
1751 SetDropTarget(new DnDShapeDropTarget(this));
1752
1753 m_shape = NULL;
1754
1755 SetBackgroundColour(*wxWHITE);
1756 }
1757
1758 DnDShapeFrame::~DnDShapeFrame()
1759 {
1760 if (m_shape)
1761 delete m_shape;
1762 }
1763
1764 void DnDShapeFrame::SetShape(DnDShape *shape)
1765 {
1766 if (m_shape)
1767 delete m_shape;
1768 m_shape = shape;
1769 Refresh();
1770 }
1771
1772 // callbacks
1773 void DnDShapeFrame::OnDrag(wxMouseEvent& event)
1774 {
1775 if ( !m_shape )
1776 {
1777 event.Skip();
1778
1779 return;
1780 }
1781
1782 // start drag operation
1783 DnDShapeDataObject shapeData(m_shape);
1784 wxDropSource source(shapeData, this);
1785
1786 const wxChar *pc = NULL;
1787 switch ( source.DoDragDrop(true) )
1788 {
1789 default:
1790 case wxDragError:
1791 wxLogError(wxT("An error occurred during drag and drop operation"));
1792 break;
1793
1794 case wxDragNone:
1795 #if wxUSE_STATUSBAR
1796 SetStatusText(wxT("Nothing happened"));
1797 #endif // wxUSE_STATUSBAR
1798 break;
1799
1800 case wxDragCopy:
1801 pc = wxT("copied");
1802 break;
1803
1804 case wxDragMove:
1805 pc = wxT("moved");
1806 if ( ms_lastDropTarget != this )
1807 {
1808 // don't delete the shape if we dropped it on ourselves!
1809 SetShape(NULL);
1810 }
1811 break;
1812
1813 case wxDragCancel:
1814 #if wxUSE_STATUSBAR
1815 SetStatusText(wxT("Drag and drop operation cancelled"));
1816 #endif // wxUSE_STATUSBAR
1817 break;
1818 }
1819
1820 if ( pc )
1821 {
1822 #if wxUSE_STATUSBAR
1823 SetStatusText(wxString(wxT("Shape successfully ")) + pc);
1824 #endif // wxUSE_STATUSBAR
1825 }
1826 //else: status text already set
1827 }
1828
1829 void DnDShapeFrame::OnDrop(wxCoord x, wxCoord y, DnDShape *shape)
1830 {
1831 ms_lastDropTarget = this;
1832
1833 wxPoint pt(x, y);
1834
1835 #if wxUSE_STATUSBAR
1836 wxString s;
1837 s.Printf(wxT("Shape dropped at (%d, %d)"), pt.x, pt.y);
1838 SetStatusText(s);
1839 #endif // wxUSE_STATUSBAR
1840
1841 shape->Move(pt);
1842 SetShape(shape);
1843 }
1844
1845 void DnDShapeFrame::OnEditShape(wxCommandEvent& WXUNUSED(event))
1846 {
1847 DnDShapeDialog dlg(this, m_shape);
1848 if ( dlg.ShowModal() == wxID_OK )
1849 {
1850 SetShape(dlg.GetShape());
1851
1852 #if wxUSE_STATUSBAR
1853 if ( m_shape )
1854 {
1855 SetStatusText(wxT("You can now drag the shape to another frame"));
1856 }
1857 #endif // wxUSE_STATUSBAR
1858 }
1859 }
1860
1861 void DnDShapeFrame::OnNewShape(wxCommandEvent& WXUNUSED(event))
1862 {
1863 SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED));
1864
1865 #if wxUSE_STATUSBAR
1866 SetStatusText(wxT("You can now drag the shape to another frame"));
1867 #endif // wxUSE_STATUSBAR
1868 }
1869
1870 void DnDShapeFrame::OnClearShape(wxCommandEvent& WXUNUSED(event))
1871 {
1872 SetShape(NULL);
1873 }
1874
1875 void DnDShapeFrame::OnCopyShape(wxCommandEvent& WXUNUSED(event))
1876 {
1877 if ( m_shape )
1878 {
1879 wxClipboardLocker clipLocker;
1880 if ( !clipLocker )
1881 {
1882 wxLogError(wxT("Can't open the clipboard"));
1883
1884 return;
1885 }
1886
1887 wxTheClipboard->AddData(new DnDShapeDataObject(m_shape));
1888 }
1889 }
1890
1891 void DnDShapeFrame::OnPasteShape(wxCommandEvent& WXUNUSED(event))
1892 {
1893 wxClipboardLocker clipLocker;
1894 if ( !clipLocker )
1895 {
1896 wxLogError(wxT("Can't open the clipboard"));
1897
1898 return;
1899 }
1900
1901 DnDShapeDataObject shapeDataObject(NULL);
1902 if ( wxTheClipboard->GetData(shapeDataObject) )
1903 {
1904 SetShape(shapeDataObject.GetShape());
1905 }
1906 else
1907 {
1908 wxLogStatus(wxT("No shape on the clipboard"));
1909 }
1910 }
1911
1912 void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent& event)
1913 {
1914 event.Enable( m_shape != NULL );
1915 }
1916
1917 void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent& event)
1918 {
1919 event.Enable( wxTheClipboard->IsSupported(wxDataFormat(shapeFormatId)) );
1920 }
1921
1922 void DnDShapeFrame::OnPaint(wxPaintEvent& event)
1923 {
1924 if ( m_shape )
1925 {
1926 wxPaintDC dc(this);
1927
1928 m_shape->Draw(dc);
1929 }
1930 else
1931 {
1932 event.Skip();
1933 }
1934 }
1935
1936 // ----------------------------------------------------------------------------
1937 // DnDShape
1938 // ----------------------------------------------------------------------------
1939
1940 DnDShape *DnDShape::New(const void *buf)
1941 {
1942 const ShapeDump& dump = *(const ShapeDump *)buf;
1943 switch ( dump.k )
1944 {
1945 case Triangle:
1946 return new DnDTriangularShape(wxPoint(dump.x, dump.y),
1947 wxSize(dump.w, dump.h),
1948 wxColour(dump.r, dump.g, dump.b));
1949
1950 case Rectangle:
1951 return new DnDRectangularShape(wxPoint(dump.x, dump.y),
1952 wxSize(dump.w, dump.h),
1953 wxColour(dump.r, dump.g, dump.b));
1954
1955 case Ellipse:
1956 return new DnDEllipticShape(wxPoint(dump.x, dump.y),
1957 wxSize(dump.w, dump.h),
1958 wxColour(dump.r, dump.g, dump.b));
1959
1960 default:
1961 wxFAIL_MSG(wxT("invalid shape!"));
1962 return NULL;
1963 }
1964 }
1965
1966 // ----------------------------------------------------------------------------
1967 // DnDShapeDataObject
1968 // ----------------------------------------------------------------------------
1969
1970 #if wxUSE_METAFILE
1971
1972 void DnDShapeDataObject::CreateMetaFile() const
1973 {
1974 wxPoint pos = m_shape->GetPosition();
1975 wxSize size = m_shape->GetSize();
1976
1977 wxMetaFileDC dcMF(wxEmptyString, pos.x + size.x, pos.y + size.y);
1978
1979 m_shape->Draw(dcMF);
1980
1981 wxMetafile *mf = dcMF.Close();
1982
1983 DnDShapeDataObject *self = (DnDShapeDataObject *)this; // const_cast
1984 self->m_dobjMetaFile.SetMetafile(*mf);
1985 self->m_hasMetaFile = true;
1986
1987 delete mf;
1988 }
1989
1990 #endif // wxUSE_METAFILE
1991
1992 void DnDShapeDataObject::CreateBitmap() const
1993 {
1994 wxPoint pos = m_shape->GetPosition();
1995 wxSize size = m_shape->GetSize();
1996 int x = pos.x + size.x,
1997 y = pos.y + size.y;
1998 wxBitmap bitmap(x, y);
1999 wxMemoryDC dc;
2000 dc.SelectObject(bitmap);
2001 dc.SetBrush(wxBrush(wxT("white"), wxSOLID));
2002 dc.Clear();
2003 m_shape->Draw(dc);
2004 dc.SelectObject(wxNullBitmap);
2005
2006 DnDShapeDataObject *self = (DnDShapeDataObject *)this; // const_cast
2007 self->m_dobjBitmap.SetBitmap(bitmap);
2008 self->m_hasBitmap = true;
2009 }
2010
2011 #endif // wxUSE_DRAG_AND_DROP
2012
2013 // ----------------------------------------------------------------------------
2014 // global functions
2015 // ----------------------------------------------------------------------------
2016
2017 static void ShowBitmap(const wxBitmap& bitmap)
2018 {
2019 wxFrame *frame = new wxFrame(NULL, wxID_ANY, wxT("Bitmap view"));
2020 #if wxUSE_STATUSBAR
2021 frame->CreateStatusBar();
2022 #endif // wxUSE_STATUSBAR
2023 DnDCanvasBitmap *canvas = new DnDCanvasBitmap(frame);
2024 canvas->SetBitmap(bitmap);
2025
2026 int w = bitmap.GetWidth(),
2027 h = bitmap.GetHeight();
2028 #if wxUSE_STATUSBAR
2029 frame->SetStatusText(wxString::Format(wxT("%dx%d"), w, h));
2030 #endif // wxUSE_STATUSBAR
2031
2032 frame->SetClientSize(w > 100 ? 100 : w, h > 100 ? 100 : h);
2033 frame->Show(true);
2034 }
2035
2036 #if wxUSE_METAFILE
2037
2038 static void ShowMetaFile(const wxMetaFile& metafile)
2039 {
2040 wxFrame *frame = new wxFrame(NULL, wxID_ANY, wxT("Metafile view"));
2041 frame->CreateStatusBar();
2042 DnDCanvasMetafile *canvas = new DnDCanvasMetafile(frame);
2043 canvas->SetMetafile(metafile);
2044
2045 wxSize size = metafile.GetSize();
2046 frame->SetStatusText(wxString::Format(wxT("%dx%d"), size.x, size.y));
2047
2048 frame->SetClientSize(size.x > 100 ? 100 : size.x,
2049 size.y > 100 ? 100 : size.y);
2050 frame->Show();
2051 }
2052
2053 #endif // wxUSE_METAFILE
2054
2055 #endif // wxUSE_DRAG_AND_DROP || wxUSE_CLIPBOARD