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