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