]> git.saurik.com Git - wxWidgets.git/blame_incremental - samples/dnd/dnd.cpp
wxFileSelector should have file name only, not path, passed to 3rd arg
[wxWidgets.git] / samples / dnd / dnd.cpp
... / ...
CommitLineData
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
50 #include "dnd_copy.xpm"
51 #include "dnd_move.xpm"
52 #include "dnd_none.xpm"
53#endif
54
55// ----------------------------------------------------------------------------
56// Derive two simple classes which just put in the listbox the strings (text or
57// file names) we drop on them
58// ----------------------------------------------------------------------------
59
60class DnDText : public wxTextDropTarget
61{
62public:
63 DnDText(wxListBox *pOwner) { m_pOwner = pOwner; }
64
65 virtual bool OnDropText(wxCoord x, wxCoord y, const wxString& text);
66
67private:
68 wxListBox *m_pOwner;
69};
70
71class DnDFile : public wxFileDropTarget
72{
73public:
74 DnDFile(wxListBox *pOwner) { m_pOwner = pOwner; }
75
76 virtual bool OnDropFiles(wxCoord x, wxCoord y,
77 const wxArrayString& filenames);
78
79private:
80 wxListBox *m_pOwner;
81};
82
83// ----------------------------------------------------------------------------
84// Define a new application type
85// ----------------------------------------------------------------------------
86
87class DnDApp : public wxApp
88{
89public:
90 virtual bool OnInit();
91};
92
93IMPLEMENT_APP(DnDApp);
94
95// ----------------------------------------------------------------------------
96// Define canvas class to show a bitmap
97// ----------------------------------------------------------------------------
98
99class DnDCanvasBitmap : public wxScrolledWindow
100{
101public:
102 DnDCanvasBitmap(wxWindow *parent) : wxScrolledWindow(parent) { }
103
104 void SetBitmap(const wxBitmap& bitmap)
105 {
106 m_bitmap = bitmap;
107
108 SetScrollbars(10, 10,
109 m_bitmap.GetWidth() / 10, m_bitmap.GetHeight() / 10);
110
111 Refresh();
112 }
113
114 void OnPaint(wxPaintEvent& event)
115 {
116 wxPaintDC dc(this);
117
118 if ( m_bitmap.Ok() )
119 {
120 PrepareDC(dc);
121
122 dc.DrawBitmap(m_bitmap, 0, 0);
123 }
124 }
125
126private:
127 wxBitmap m_bitmap;
128
129 DECLARE_EVENT_TABLE()
130};
131
132#ifdef USE_METAFILES
133
134// and the same thing fo metafiles
135class DnDCanvasMetafile : public wxScrolledWindow
136{
137public:
138 DnDCanvasMetafile(wxWindow *parent) : wxScrolledWindow(parent) { }
139
140 void SetMetafile(const wxMetafile& metafile)
141 {
142 m_metafile = metafile;
143
144 SetScrollbars(10, 10,
145 m_metafile.GetWidth() / 10, m_metafile.GetHeight() / 10);
146
147 Refresh();
148 }
149
150 void OnPaint(wxPaintEvent& event)
151 {
152 wxPaintDC dc(this);
153
154 if ( m_metafile.Ok() )
155 {
156 PrepareDC(dc);
157
158 m_metafile.Play(&dc);
159 }
160 }
161
162private:
163 wxMetafile m_metafile;
164
165 DECLARE_EVENT_TABLE()
166};
167
168#endif // USE_METAFILES
169
170// ----------------------------------------------------------------------------
171// Define a new frame type for the main frame
172// ----------------------------------------------------------------------------
173
174class DnDFrame : public wxFrame
175{
176public:
177 DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h);
178 ~DnDFrame();
179
180 void OnPaint(wxPaintEvent& event);
181 void OnQuit (wxCommandEvent& event);
182 void OnAbout(wxCommandEvent& event);
183 void OnDrag (wxCommandEvent& event);
184 void OnNewFrame(wxCommandEvent& event);
185 void OnHelp (wxCommandEvent& event);
186 void OnLogClear(wxCommandEvent& event);
187
188 void OnCopy(wxCommandEvent& event);
189 void OnPaste(wxCommandEvent& event);
190
191 void OnCopyBitmap(wxCommandEvent& event);
192 void OnPasteBitmap(wxCommandEvent& event);
193
194#ifdef USE_METAFILES
195 void OnPasteMetafile(wxCommandEvent& event);
196#endif // USE_METAFILES
197
198 void OnCopyFiles(wxCommandEvent& event);
199
200 void OnLeftDown(wxMouseEvent& event);
201 void OnRightDown(wxMouseEvent& event);
202
203 void OnUpdateUIPasteText(wxUpdateUIEvent& event);
204 void OnUpdateUIPasteBitmap(wxUpdateUIEvent& event);
205
206 DECLARE_EVENT_TABLE()
207
208private:
209 wxListBox *m_ctrlFile,
210 *m_ctrlText;
211 wxTextCtrl *m_ctrlLog;
212
213 wxLog *m_pLog,
214 *m_pLogPrev;
215
216 wxString m_strText;
217};
218
219// ----------------------------------------------------------------------------
220// A shape is an example of application-specific data which may be transported
221// via drag-and-drop or clipboard: in our case, we have different geometric
222// shapes, each one with its own colour and position
223// ----------------------------------------------------------------------------
224
225class DnDShape
226{
227public:
228 enum Kind
229 {
230 None,
231 Triangle,
232 Rectangle,
233 Ellipse
234 };
235
236 DnDShape(const wxPoint& pos,
237 const wxSize& size,
238 const wxColour& col)
239 : m_pos(pos), m_size(size), m_col(col)
240 {
241 }
242
243 // this is for debugging - lets us see when exactly an object is freed
244 // (this may be later than you think if it's on the clipboard, for example)
245 virtual ~DnDShape() { }
246
247 // the functions used for drag-and-drop: they dump and restore a shape into
248 // some bitwise-copiable data (might use streams too...)
249 // ------------------------------------------------------------------------
250
251 // restore from buffer
252 static DnDShape *New(const void *buf);
253
254 virtual size_t GetDataSize() const
255 {
256 return sizeof(ShapeDump);
257 }
258
259 virtual void GetDataHere(void *buf) const
260 {
261 ShapeDump& dump = *(ShapeDump *)buf;
262 dump.x = m_pos.x;
263 dump.y = m_pos.y;
264 dump.w = m_size.x;
265 dump.h = m_size.y;
266 dump.r = m_col.Red();
267 dump.g = m_col.Green();
268 dump.b = m_col.Blue();
269 dump.k = GetKind();
270 }
271
272 // accessors
273 const wxPoint& GetPosition() const { return m_pos; }
274 const wxColour& GetColour() const { return m_col; }
275 const wxSize& GetSize() const { return m_size; }
276
277 void Move(const wxPoint& pos) { m_pos = pos; }
278
279 // to implement in derived classes
280 virtual Kind GetKind() const = 0;
281
282 virtual void Draw(wxDC& dc)
283 {
284 dc.SetPen(wxPen(m_col, 1, wxSOLID));
285 }
286
287protected:
288 wxPoint GetCentre() const
289 { return wxPoint(m_pos.x + m_size.x / 2, m_pos.y + m_size.y / 2); }
290
291 struct ShapeDump
292 {
293 int x, y, // position
294 w, h, // size
295 r, g, b, // colour
296 k; // kind
297 };
298
299 wxPoint m_pos;
300 wxSize m_size;
301 wxColour m_col;
302};
303
304class DnDTriangularShape : public DnDShape
305{
306public:
307 DnDTriangularShape(const wxPoint& pos,
308 const wxSize& size,
309 const wxColour& col)
310 : DnDShape(pos, size, col)
311 {
312 wxLogMessage("DnDTriangularShape is being created");
313 }
314
315 virtual ~DnDTriangularShape()
316 {
317 wxLogMessage("DnDTriangularShape is being deleted");
318 }
319
320 virtual Kind GetKind() const { return Triangle; }
321 virtual void Draw(wxDC& dc)
322 {
323 DnDShape::Draw(dc);
324
325 // well, it's a bit difficult to describe a triangle by position and
326 // size, but we're not doing geometry here, do we? ;-)
327 wxPoint p1(m_pos);
328 wxPoint p2(m_pos.x + m_size.x, m_pos.y);
329 wxPoint p3(m_pos.x, m_pos.y + m_size.y);
330
331 dc.DrawLine(p1, p2);
332 dc.DrawLine(p2, p3);
333 dc.DrawLine(p3, p1);
334
335#ifdef __WXMSW__
336 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
337#endif
338 }
339};
340
341class DnDRectangularShape : public DnDShape
342{
343public:
344 DnDRectangularShape(const wxPoint& pos,
345 const wxSize& size,
346 const wxColour& col)
347 : DnDShape(pos, size, col)
348 {
349 wxLogMessage("DnDRectangularShape is being created");
350 }
351
352 virtual ~DnDRectangularShape()
353 {
354 wxLogMessage("DnDRectangularShape is being deleted");
355 }
356
357 virtual Kind GetKind() const { return Rectangle; }
358 virtual void Draw(wxDC& dc)
359 {
360 DnDShape::Draw(dc);
361
362 wxPoint p1(m_pos);
363 wxPoint p2(p1.x + m_size.x, p1.y);
364 wxPoint p3(p2.x, p2.y + m_size.y);
365 wxPoint p4(p1.x, p3.y);
366
367 dc.DrawLine(p1, p2);
368 dc.DrawLine(p2, p3);
369 dc.DrawLine(p3, p4);
370 dc.DrawLine(p4, p1);
371
372#ifdef __WXMSW__
373 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
374#endif
375 }
376};
377
378class DnDEllipticShape : public DnDShape
379{
380public:
381 DnDEllipticShape(const wxPoint& pos,
382 const wxSize& size,
383 const wxColour& col)
384 : DnDShape(pos, size, col)
385 {
386 wxLogMessage("DnDEllipticShape is being created");
387 }
388
389 virtual ~DnDEllipticShape()
390 {
391 wxLogMessage("DnDEllipticShape is being deleted");
392 }
393
394 virtual Kind GetKind() const { return Ellipse; }
395 virtual void Draw(wxDC& dc)
396 {
397 DnDShape::Draw(dc);
398
399 dc.DrawEllipse(m_pos, m_size);
400
401#ifdef __WXMSW__
402 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
403#endif
404 }
405};
406
407// ----------------------------------------------------------------------------
408// A wxDataObject specialisation for the application-specific data
409// ----------------------------------------------------------------------------
410
411static const char *shapeFormatId = "wxShape";
412
413class DnDShapeDataObject : public wxDataObject
414{
415public:
416 // ctor doesn't copy the pointer, so it shouldn't go away while this object
417 // is alive
418 DnDShapeDataObject(DnDShape *shape = (DnDShape *)NULL)
419 {
420 if ( shape )
421 {
422 // we need to copy the shape because the one we're handled may be
423 // deleted while it's still on the clipboard (for example) - and we
424 // reuse the serialisation methods here to copy it
425 void *buf = malloc(shape->DnDShape::GetDataSize());
426 shape->GetDataHere(buf);
427 m_shape = DnDShape::New(buf);
428
429 free(buf);
430 }
431 else
432 {
433 // nothing to copy
434 m_shape = NULL;
435 }
436
437 // this string should uniquely identify our format, but is otherwise
438 // arbitrary
439 m_formatShape.SetId(shapeFormatId);
440
441 // we don't draw the shape to a bitmap until it's really needed (i.e.
442 // we're asked to do so)
443 m_hasBitmap = FALSE;
444#ifdef USE_METAFILES
445 m_hasMetaFile = FALSE;
446#endif // Windows
447 }
448
449 virtual ~DnDShapeDataObject() { delete m_shape; }
450
451 // after a call to this function, the shape is owned by the caller and it
452 // is responsible for deleting it!
453 //
454 // NB: a better solution would be to make DnDShapes ref counted and this
455 // is what should probably be done in a real life program, otherwise
456 // the ownership problems become too complicated really fast
457 DnDShape *GetShape()
458 {
459 DnDShape *shape = m_shape;
460
461 m_shape = (DnDShape *)NULL;
462 m_hasBitmap = FALSE;
463#ifdef USE_METAFILES
464 m_hasMetaFile = FALSE;
465#endif // Windows
466
467 return shape;
468 }
469
470 // implement base class pure virtuals
471 // ----------------------------------
472
473 virtual wxDataFormat GetPreferredFormat(Direction WXUNUSED(dir)) const
474 {
475 return m_formatShape;
476 }
477
478 virtual size_t GetFormatCount(Direction dir) const
479 {
480 // our custom format is supported by both GetData() and SetData()
481 size_t nFormats = 1;
482 if ( dir == Get )
483 {
484 // but the bitmap format(s) are only supported for output
485 nFormats += m_dobjBitmap.GetFormatCount(dir);
486
487#ifdef USE_METAFILES
488 nFormats += m_dobjMetaFile.GetFormatCount(dir);
489#endif // Windows
490 }
491
492 return nFormats;
493 }
494
495 virtual void GetAllFormats(wxDataFormat *formats, Direction dir) const
496 {
497 formats[0] = m_formatShape;
498 if ( dir == Get )
499 {
500 // in Get direction we additionally support bitmaps and metafiles
501 // under Windows
502 m_dobjBitmap.GetAllFormats(&formats[1], dir);
503
504#ifdef USE_METAFILES
505 // don't assume that m_dobjBitmap has only 1 format
506 m_dobjMetaFile.GetAllFormats(&formats[1 +
507 m_dobjBitmap.GetFormatCount(dir)], dir);
508#endif // Windows
509 }
510 }
511
512 virtual size_t GetDataSize(const wxDataFormat& format) const
513 {
514 if ( format == m_formatShape )
515 {
516 return m_shape->GetDataSize();
517 }
518#ifdef USE_METAFILES
519 else if ( m_dobjMetaFile.IsSupported(format) )
520 {
521 if ( !m_hasMetaFile )
522 CreateMetaFile();
523
524 return m_dobjMetaFile.GetDataSize(format);
525 }
526#endif // Windows
527 else
528 {
529 wxASSERT_MSG( m_dobjBitmap.IsSupported(format),
530 "unexpected format" );
531
532 if ( !m_hasBitmap )
533 CreateBitmap();
534
535 return m_dobjBitmap.GetDataSize();
536 }
537 }
538
539 virtual bool GetDataHere(const wxDataFormat& format, void *pBuf) const
540 {
541 if ( format == m_formatShape )
542 {
543 m_shape->GetDataHere(pBuf);
544
545 return TRUE;
546 }
547#ifdef USE_METAFILES
548 else if ( m_dobjMetaFile.IsSupported(format) )
549 {
550 if ( !m_hasMetaFile )
551 CreateMetaFile();
552
553 return m_dobjMetaFile.GetDataHere(format, pBuf);
554 }
555#endif // Windows
556 else
557 {
558 wxASSERT_MSG( m_dobjBitmap.IsSupported(format),
559 "unexpected format" );
560
561 if ( !m_hasBitmap )
562 CreateBitmap();
563
564 return m_dobjBitmap.GetDataHere(pBuf);
565 }
566 }
567
568 virtual bool SetData(const wxDataFormat& format,
569 size_t len, const void *buf)
570 {
571 wxCHECK_MSG( format == m_formatShape, FALSE, "unsupported format" );
572
573 delete m_shape;
574 m_shape = DnDShape::New(buf);
575
576 // the shape has changed
577 m_hasBitmap = FALSE;
578
579#ifdef USE_METAFILES
580 m_hasMetaFile = FALSE;
581#endif // Windows
582
583 return TRUE;
584 }
585
586private:
587 // creates a bitmap and assigns it to m_dobjBitmap (also sets m_hasBitmap)
588 void CreateBitmap() const;
589#ifdef USE_METAFILES
590 void CreateMetaFile() const;
591#endif // Windows
592
593 wxDataFormat m_formatShape; // our custom format
594
595 wxBitmapDataObject m_dobjBitmap; // it handles bitmaps
596 bool m_hasBitmap; // true if m_dobjBitmap has valid bitmap
597
598#ifdef USE_METAFILES
599 wxMetaFileDataObject m_dobjMetaFile;// handles metafiles
600 bool m_hasMetaFile; // true if we have valid metafile
601#endif // Windows
602
603 DnDShape *m_shape; // our data
604};
605
606// ----------------------------------------------------------------------------
607// A dialog to edit shape properties
608// ----------------------------------------------------------------------------
609
610class DnDShapeDialog : public wxDialog
611{
612public:
613 DnDShapeDialog(wxFrame *parent, DnDShape *shape);
614
615 DnDShape *GetShape() const;
616
617 virtual bool TransferDataToWindow();
618 virtual bool TransferDataFromWindow();
619
620 void OnColour(wxCommandEvent& event);
621
622private:
623 // input
624 DnDShape *m_shape;
625
626 // output
627 DnDShape::Kind m_shapeKind;
628 wxPoint m_pos;
629 wxSize m_size;
630 wxColour m_col;
631
632 // controls
633 wxRadioBox *m_radio;
634 wxTextCtrl *m_textX,
635 *m_textY,
636 *m_textW,
637 *m_textH;
638
639 DECLARE_EVENT_TABLE()
640};
641
642// ----------------------------------------------------------------------------
643// A frame for the shapes which can be drag-and-dropped between frames
644// ----------------------------------------------------------------------------
645
646class DnDShapeFrame : public wxFrame
647{
648public:
649 DnDShapeFrame(wxFrame *parent);
650 ~DnDShapeFrame();
651
652 void SetShape(DnDShape *shape);
653
654 // callbacks
655 void OnNewShape(wxCommandEvent& event);
656 void OnEditShape(wxCommandEvent& event);
657 void OnClearShape(wxCommandEvent& event);
658
659 void OnCopyShape(wxCommandEvent& event);
660 void OnPasteShape(wxCommandEvent& event);
661
662 void OnUpdateUICopy(wxUpdateUIEvent& event);
663 void OnUpdateUIPaste(wxUpdateUIEvent& event);
664
665 void OnDrag(wxMouseEvent& event);
666 void OnPaint(wxPaintEvent& event);
667 void OnDrop(wxCoord x, wxCoord y, DnDShape *shape);
668
669private:
670 DnDShape *m_shape;
671
672 static DnDShapeFrame *ms_lastDropTarget;
673
674 DECLARE_EVENT_TABLE()
675};
676
677// ----------------------------------------------------------------------------
678// wxDropTarget derivation for DnDShapes
679// ----------------------------------------------------------------------------
680
681class DnDShapeDropTarget : public wxDropTarget
682{
683public:
684 DnDShapeDropTarget(DnDShapeFrame *frame)
685 : wxDropTarget(new DnDShapeDataObject)
686 {
687 m_frame = frame;
688 }
689
690 // override base class (pure) virtuals
691 virtual wxDragResult OnEnter(wxCoord x, wxCoord y, wxDragResult def)
692 { m_frame->SetStatusText("Mouse entered the frame"); return OnDragOver(x, y, def); }
693 virtual void OnLeave()
694 { m_frame->SetStatusText("Mouse left the frame"); }
695 virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def)
696 {
697 if ( !GetData() )
698 {
699 wxLogError("Failed to get drag and drop data");
700
701 return wxDragNone;
702 }
703
704 m_frame->OnDrop(x, y,
705 ((DnDShapeDataObject *)GetDataObject())->GetShape());
706
707 return def;
708 }
709
710private:
711 DnDShapeFrame *m_frame;
712};
713
714// ----------------------------------------------------------------------------
715// functions prototypes
716// ----------------------------------------------------------------------------
717
718static void ShowBitmap(const wxBitmap& bitmap);
719
720#ifdef USE_METAFILES
721static void ShowMetaFile(const wxMetaFile& metafile);
722#endif // USE_METAFILES
723
724// ----------------------------------------------------------------------------
725// IDs for the menu commands
726// ----------------------------------------------------------------------------
727
728enum
729{
730 Menu_Quit = 1,
731 Menu_Drag,
732 Menu_NewFrame,
733 Menu_About = 101,
734 Menu_Help,
735 Menu_Clear,
736 Menu_Copy,
737 Menu_Paste,
738 Menu_CopyBitmap,
739 Menu_PasteBitmap,
740 Menu_PasteMFile,
741 Menu_CopyFiles,
742 Menu_Shape_New = 500,
743 Menu_Shape_Edit,
744 Menu_Shape_Clear,
745 Menu_ShapeClipboard_Copy,
746 Menu_ShapeClipboard_Paste,
747 Button_Colour = 1001
748};
749
750BEGIN_EVENT_TABLE(DnDFrame, wxFrame)
751 EVT_MENU(Menu_Quit, DnDFrame::OnQuit)
752 EVT_MENU(Menu_About, DnDFrame::OnAbout)
753 EVT_MENU(Menu_Drag, DnDFrame::OnDrag)
754 EVT_MENU(Menu_NewFrame, DnDFrame::OnNewFrame)
755 EVT_MENU(Menu_Help, DnDFrame::OnHelp)
756 EVT_MENU(Menu_Clear, DnDFrame::OnLogClear)
757 EVT_MENU(Menu_Copy, DnDFrame::OnCopy)
758 EVT_MENU(Menu_Paste, DnDFrame::OnPaste)
759 EVT_MENU(Menu_CopyBitmap, DnDFrame::OnCopyBitmap)
760 EVT_MENU(Menu_PasteBitmap,DnDFrame::OnPasteBitmap)
761#ifdef USE_METAFILES
762 EVT_MENU(Menu_PasteMFile, DnDFrame::OnPasteMetafile)
763#endif // USE_METAFILES
764 EVT_MENU(Menu_CopyFiles, DnDFrame::OnCopyFiles)
765
766 EVT_UPDATE_UI(Menu_Paste, DnDFrame::OnUpdateUIPasteText)
767 EVT_UPDATE_UI(Menu_PasteBitmap, DnDFrame::OnUpdateUIPasteBitmap)
768
769 EVT_LEFT_DOWN( DnDFrame::OnLeftDown)
770 EVT_RIGHT_DOWN( DnDFrame::OnRightDown)
771 EVT_PAINT( DnDFrame::OnPaint)
772END_EVENT_TABLE()
773
774BEGIN_EVENT_TABLE(DnDShapeFrame, wxFrame)
775 EVT_MENU(Menu_Shape_New, DnDShapeFrame::OnNewShape)
776 EVT_MENU(Menu_Shape_Edit, DnDShapeFrame::OnEditShape)
777 EVT_MENU(Menu_Shape_Clear, DnDShapeFrame::OnClearShape)
778
779 EVT_MENU(Menu_ShapeClipboard_Copy, DnDShapeFrame::OnCopyShape)
780 EVT_MENU(Menu_ShapeClipboard_Paste, DnDShapeFrame::OnPasteShape)
781
782 EVT_UPDATE_UI(Menu_ShapeClipboard_Copy, DnDShapeFrame::OnUpdateUICopy)
783 EVT_UPDATE_UI(Menu_ShapeClipboard_Paste, DnDShapeFrame::OnUpdateUIPaste)
784
785 EVT_LEFT_DOWN(DnDShapeFrame::OnDrag)
786
787 EVT_PAINT(DnDShapeFrame::OnPaint)
788END_EVENT_TABLE()
789
790BEGIN_EVENT_TABLE(DnDShapeDialog, wxDialog)
791 EVT_BUTTON(Button_Colour, DnDShapeDialog::OnColour)
792END_EVENT_TABLE()
793
794BEGIN_EVENT_TABLE(DnDCanvasBitmap, wxScrolledWindow)
795 EVT_PAINT(DnDCanvasBitmap::OnPaint)
796END_EVENT_TABLE()
797
798#ifdef USE_METAFILES
799BEGIN_EVENT_TABLE(DnDCanvasMetafile, wxScrolledWindow)
800 EVT_PAINT(DnDCanvasMetafile::OnPaint)
801END_EVENT_TABLE()
802#endif // USE_METAFILES
803
804// ============================================================================
805// implementation
806// ============================================================================
807
808// `Main program' equivalent, creating windows and returning main app frame
809bool DnDApp::OnInit()
810{
811 // load our ressources
812 wxPathList pathList;
813 pathList.Add(".");
814#ifdef __WXMSW__
815 pathList.Add("./Debug");
816 pathList.Add("./Release");
817#endif // wxMSW
818
819 wxString path = pathList.FindValidPath("dnd.wxr");
820 if ( !path )
821 {
822 wxLogError("Can't find the resource file dnd.wxr in the current "
823 "directory, aborting.");
824
825 return FALSE;
826 }
827
828 wxDefaultResourceTable->ParseResourceFile(path);
829
830 // switch on trace messages
831#if defined(__WXGTK__)
832 wxLog::AddTraceMask(_T("clipboard"));
833#elif defined(__WXMSW__)
834 wxLog::AddTraceMask(wxTRACE_OleCalls);
835#endif
836
837#if wxUSE_LIBPNG
838 wxImage::AddHandler( new wxPNGHandler );
839#endif
840
841 // under X we usually want to use the primary selection by default (which
842 // is shared with other apps)
843 wxTheClipboard->UsePrimarySelection();
844
845 // create the main frame window
846 DnDFrame *frame = new DnDFrame((wxFrame *) NULL,
847 "Drag-and-Drop/Clipboard wxWindows Sample",
848 10, 100, 650, 340);
849
850 // activate it
851 frame->Show(TRUE);
852
853 SetTopWindow(frame);
854
855 return TRUE;
856}
857
858DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
859 : wxFrame(frame, -1, title, wxPoint(x, y), wxSize(w, h)),
860 m_strText("wxWindows drag & drop works :-)")
861
862{
863 // frame icon and status bar
864 SetIcon(wxICON(mondrian));
865
866 CreateStatusBar();
867
868 // construct menu
869 wxMenu *file_menu = new wxMenu;
870 file_menu->Append(Menu_Drag, "&Test drag...");
871 file_menu->AppendSeparator();
872 file_menu->Append(Menu_NewFrame, "&New frame\tCtrl-N");
873 file_menu->AppendSeparator();
874 file_menu->Append(Menu_Quit, "E&xit");
875
876 wxMenu *log_menu = new wxMenu;
877 log_menu->Append(Menu_Clear, "Clear\tCtrl-L");
878
879 wxMenu *help_menu = new wxMenu;
880 help_menu->Append(Menu_Help, "&Help...");
881 help_menu->AppendSeparator();
882 help_menu->Append(Menu_About, "&About");
883
884 wxMenu *clip_menu = new wxMenu;
885 clip_menu->Append(Menu_Copy, "&Copy text\tCtrl+C");
886 clip_menu->Append(Menu_Paste, "&Paste text\tCtrl+V");
887 clip_menu->AppendSeparator();
888 clip_menu->Append(Menu_CopyBitmap, "Copy &bitmap\tAlt+C");
889 clip_menu->Append(Menu_PasteBitmap, "Paste b&itmap\tAlt+V");
890#ifdef USE_METAFILES
891 clip_menu->AppendSeparator();
892 clip_menu->Append(Menu_PasteMFile, "Paste &metafile\tCtrl-M");
893#endif // USE_METAFILES
894 clip_menu->AppendSeparator();
895 clip_menu->Append(Menu_CopyFiles, "Copy &files\tCtrl+F");
896
897 wxMenuBar *menu_bar = new wxMenuBar;
898 menu_bar->Append(file_menu, "&File");
899 menu_bar->Append(log_menu, "&Log");
900 menu_bar->Append(clip_menu, "&Clipboard");
901 menu_bar->Append(help_menu, "&Help");
902
903 SetMenuBar(menu_bar);
904
905 // make a panel with 3 subwindows
906 wxPoint pos(0, 0);
907 wxSize size(400, 200);
908
909 wxString strFile("Drop files here!"), strText("Drop text on me");
910
911 m_ctrlFile = new wxListBox(this, -1, pos, size, 1, &strFile,
912 wxLB_HSCROLL | wxLB_ALWAYS_SB );
913 m_ctrlText = new wxListBox(this, -1, pos, size, 1, &strText,
914 wxLB_HSCROLL | wxLB_ALWAYS_SB );
915
916 m_ctrlLog = new wxTextCtrl(this, -1, "", pos, size,
917 wxTE_MULTILINE | wxTE_READONLY |
918 wxSUNKEN_BORDER );
919
920 // redirect log messages to the text window
921 m_pLog = new wxLogTextCtrl(m_ctrlLog);
922 m_pLogPrev = wxLog::SetActiveTarget(m_pLog);
923
924 // associate drop targets with 2 text controls
925 m_ctrlFile->SetDropTarget(new DnDFile(m_ctrlFile));
926 m_ctrlText->SetDropTarget(new DnDText(m_ctrlText));
927
928 wxLayoutConstraints *c;
929
930 // Top-left listbox
931 c = new wxLayoutConstraints;
932 c->left.SameAs(this, wxLeft);
933 c->top.SameAs(this, wxTop);
934 c->right.PercentOf(this, wxRight, 50);
935 c->height.PercentOf(this, wxHeight, 30);
936 m_ctrlFile->SetConstraints(c);
937
938 // Top-right listbox
939 c = new wxLayoutConstraints;
940 c->left.SameAs (m_ctrlFile, wxRight);
941 c->top.SameAs (this, wxTop);
942 c->right.SameAs (this, wxRight);
943 c->height.PercentOf(this, wxHeight, 30);
944 m_ctrlText->SetConstraints(c);
945
946 // Lower text control
947 c = new wxLayoutConstraints;
948 c->left.SameAs (this, wxLeft);
949 c->right.SameAs (this, wxRight);
950 c->height.PercentOf(this, wxHeight, 50);
951 c->top.SameAs(m_ctrlText, wxBottom);
952 m_ctrlLog->SetConstraints(c);
953
954 SetAutoLayout(TRUE);
955}
956
957void DnDFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
958{
959 Close(TRUE);
960}
961
962void DnDFrame::OnPaint(wxPaintEvent& WXUNUSED(event))
963{
964 int w = 0;
965 int h = 0;
966 GetClientSize( &w, &h );
967
968 wxPaintDC dc(this);
969 dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL, FALSE, "charter" ) );
970 dc.DrawText( "Drag text from here!", 100, h-50 );
971}
972
973void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent& event)
974{
975#ifdef __WXDEBUG__
976 // too many trace messages if we don't do it - this function is called
977 // very often
978 wxLogNull nolog;
979#endif
980
981 event.Enable( wxTheClipboard->IsSupported(wxDF_TEXT) );
982}
983
984void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent& event)
985{
986#ifdef __WXDEBUG__
987 // too many trace messages if we don't do it - this function is called
988 // very often
989 wxLogNull nolog;
990#endif
991
992 event.Enable( wxTheClipboard->IsSupported(wxDF_BITMAP) );
993}
994
995void DnDFrame::OnNewFrame(wxCommandEvent& WXUNUSED(event))
996{
997 (new DnDShapeFrame(this))->Show(TRUE);
998
999 wxLogStatus(this, "Double click the new frame to select a shape for it");
1000}
1001
1002void DnDFrame::OnDrag(wxCommandEvent& WXUNUSED(event))
1003{
1004 wxString strText = wxGetTextFromUser
1005 (
1006 "After you enter text in this dialog, press any mouse\n"
1007 "button in the bottom (empty) part of the frame and \n"
1008 "drag it anywhere - you will be in fact dragging the\n"
1009 "text object containing this text",
1010 "Please enter some text", m_strText, this
1011 );
1012
1013 m_strText = strText;
1014}
1015
1016void DnDFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
1017{
1018 wxMessageBox("Drag-&-Drop Demo\n"
1019 "Please see \"Help|Help...\" for details\n"
1020 "Copyright (c) 1998 Vadim Zeitlin",
1021 "About wxDnD",
1022 wxICON_INFORMATION | wxOK,
1023 this);
1024}
1025
1026void DnDFrame::OnHelp(wxCommandEvent& /* event */)
1027{
1028 wxMessageDialog dialog(this,
1029 "This small program demonstrates drag & drop support in wxWindows. The program window\n"
1030 "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
1031 "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
1032 "and the right one accepts text.\n"
1033 "\n"
1034 "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
1035 "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
1036 "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
1037 "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
1038 "work with files) and see what changes.\n"
1039 "\n"
1040 "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
1041 "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
1042 "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
1043 "change, don't release the mouse button until it does. You can change the string being\n"
1044 "dragged in in \"File|Test drag...\" dialog.\n"
1045 "\n"
1046 "\n"
1047 "Please send all questions/bug reports/suggestions &c to \n"
1048 "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
1049 "wxDnD Help");
1050
1051 dialog.ShowModal();
1052}
1053
1054void DnDFrame::OnLogClear(wxCommandEvent& /* event */ )
1055{
1056 m_ctrlLog->Clear();
1057 m_ctrlText->Clear();
1058 m_ctrlFile->Clear();
1059}
1060
1061void DnDFrame::OnLeftDown(wxMouseEvent &WXUNUSED(event) )
1062{
1063 if ( !m_strText.IsEmpty() )
1064 {
1065 // start drag operation
1066 wxTextDataObject textData(m_strText);
1067/*
1068 wxFileDataObject textData;
1069 textData.AddFile( "/file1.txt" );
1070 textData.AddFile( "/file2.txt" );
1071*/
1072 wxDropSource source(textData, this,
1073 wxDROP_ICON(dnd_copy),
1074 wxDROP_ICON(dnd_move),
1075 wxDROP_ICON(dnd_none));
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
1093void 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
1104DnDFrame::~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
1116void 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
1185void 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
1221void 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
1261void 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
1313void 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
1334void 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
1369bool DnDText::OnDropText(wxCoord, wxCoord, const wxString& text)
1370{
1371 m_pOwner->Append(text);
1372
1373 return TRUE;
1374}
1375
1376bool 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
1393DnDShapeDialog::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
1407DnDShape *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
1419bool 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
1444bool 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
1464void 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
1485DnDShapeFrame *DnDShapeFrame::ms_lastDropTarget = NULL;
1486
1487DnDShapeFrame::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
1518DnDShapeFrame::~DnDShapeFrame()
1519{
1520 if (m_shape)
1521 delete m_shape;
1522}
1523
1524void DnDShapeFrame::SetShape(DnDShape *shape)
1525{
1526 if (m_shape)
1527 delete m_shape;
1528 m_shape = shape;
1529 Refresh();
1530}
1531
1532// callbacks
1533void 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
1583void 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
1597void 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
1611void 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
1618void DnDShapeFrame::OnClearShape(wxCommandEvent& event)
1619{
1620 SetShape(NULL);
1621}
1622
1623void 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
1639void 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
1660void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent& event)
1661{
1662 event.Enable( m_shape != NULL );
1663}
1664
1665void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent& event)
1666{
1667 event.Enable( wxTheClipboard->IsSupported(wxDataFormat(shapeFormatId)) );
1668}
1669
1670void 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
1688DnDShape *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
1720void 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
1740void 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
1763static 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(TRUE);
1776}
1777
1778#ifdef USE_METAFILES
1779
1780static 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