]> git.saurik.com Git - wxWidgets.git/blame - samples/dnd/dnd.cpp
Added conversion of menu labels (&->~)
[wxWidgets.git] / samples / dnd / dnd.cpp
CommitLineData
43d811ea 1/////////////////////////////////////////////////////////////////////////////
457814b5
JS
2// Name: dnd.cpp
3// Purpose: Drag and drop sample
4// Author: Vadim Zeitlin
43d811ea
JS
5// Modified by:
6// Created: 04/01/98
8bbe427f 7// RCS-ID: $Id$
43d811ea 8// Copyright:
8bbe427f 9// Licence: wxWindows licence
43d811ea
JS
10/////////////////////////////////////////////////////////////////////////////
11
c50f1fb9 12#include "wx/wxprec.h"
457814b5
JS
13
14#ifdef __BORLANDC__
15#pragma hdrstop
16#endif
17
18#ifndef WX_PRECOMP
c50f1fb9 19#include "wx/wx.h"
457814b5
JS
20#endif
21
8e193f38
VZ
22#if !wxUSE_DRAG_AND_DROP
23 #error This sample requires drag and drop support in the library
e2acb9ae
RR
24#endif
25
5a1c877f
VZ
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
c50f1fb9
VZ
32#include "wx/intl.h"
33#include "wx/log.h"
457814b5 34
c50f1fb9 35#include "wx/dnd.h"
956dbab1 36#include "wx/dirdlg.h"
e2acb9ae
RR
37#include "wx/filedlg.h"
38#include "wx/image.h"
39#include "wx/clipbrd.h"
8e193f38
VZ
40#include "wx/colordlg.h"
41#include "wx/resource.h"
acbd13a3 42
5a1c877f
VZ
43#ifdef USE_METAFILES
44 #include "wx/metafile.h"
45#endif // Windows
46
acbd13a3 47#if defined(__WXGTK__) || defined(__WXMOTIF__)
c50f1fb9 48 #include "mondrian.xpm"
47908e25
RR
49#endif
50
457814b5 51// ----------------------------------------------------------------------------
2845ddc2 52// Derive two simple classes which just put in the listbox the strings (text or
457814b5
JS
53// file names) we drop on them
54// ----------------------------------------------------------------------------
ab8884ac 55
457814b5
JS
56class DnDText : public wxTextDropTarget
57{
58public:
c50f1fb9 59 DnDText(wxListBox *pOwner) { m_pOwner = pOwner; }
457814b5 60
9e2896e5 61 virtual bool OnDropText(wxCoord x, wxCoord y, const wxString& text);
457814b5
JS
62
63private:
c50f1fb9 64 wxListBox *m_pOwner;
457814b5
JS
65};
66
67class DnDFile : public wxFileDropTarget
68{
69public:
c50f1fb9 70 DnDFile(wxListBox *pOwner) { m_pOwner = pOwner; }
457814b5 71
9e2896e5
VZ
72 virtual bool OnDropFiles(wxCoord x, wxCoord y,
73 const wxArrayString& filenames);
457814b5
JS
74
75private:
c50f1fb9 76 wxListBox *m_pOwner;
457814b5
JS
77};
78
79// ----------------------------------------------------------------------------
80// Define a new application type
81// ----------------------------------------------------------------------------
ab8884ac 82
457814b5 83class DnDApp : public wxApp
8bbe427f 84{
457814b5 85public:
8e193f38 86 virtual bool OnInit();
457814b5
JS
87};
88
89IMPLEMENT_APP(DnDApp);
90
ae3dd4a5
VZ
91// ----------------------------------------------------------------------------
92// Define canvas class to show a bitmap
93// ----------------------------------------------------------------------------
94
95class DnDCanvasBitmap : public wxScrolledWindow
96{
97public:
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
122private:
123 wxBitmap m_bitmap;
124
125 DECLARE_EVENT_TABLE()
126};
127
128#ifdef USE_METAFILES
129
130// and the same thing fo metafiles
131class DnDCanvasMetafile : public wxScrolledWindow
132{
133public:
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
158private:
159 wxMetafile m_metafile;
160
161 DECLARE_EVENT_TABLE()
162};
163
164#endif // USE_METAFILES
165
457814b5 166// ----------------------------------------------------------------------------
8e193f38 167// Define a new frame type for the main frame
457814b5 168// ----------------------------------------------------------------------------
8e193f38 169
457814b5 170class DnDFrame : public wxFrame
8bbe427f 171{
457814b5 172public:
c50f1fb9
VZ
173 DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h);
174 ~DnDFrame();
457814b5 175
c50f1fb9
VZ
176 void OnPaint(wxPaintEvent& event);
177 void OnQuit (wxCommandEvent& event);
178 void OnAbout(wxCommandEvent& event);
179 void OnDrag (wxCommandEvent& event);
8e193f38 180 void OnNewFrame(wxCommandEvent& event);
c50f1fb9
VZ
181 void OnHelp (wxCommandEvent& event);
182 void OnLogClear(wxCommandEvent& event);
51edda6a 183
c50f1fb9
VZ
184 void OnCopy(wxCommandEvent& event);
185 void OnPaste(wxCommandEvent& event);
51edda6a 186
e2acb9ae
RR
187 void OnCopyBitmap(wxCommandEvent& event);
188 void OnPasteBitmap(wxCommandEvent& event);
43d811ea 189
5a1c877f
VZ
190#ifdef USE_METAFILES
191 void OnPasteMetafile(wxCommandEvent& event);
192#endif // USE_METAFILES
193
51edda6a
VZ
194 void OnCopyFiles(wxCommandEvent& event);
195
c50f1fb9
VZ
196 void OnLeftDown(wxMouseEvent& event);
197 void OnRightDown(wxMouseEvent& event);
8bbe427f 198
d59ceba5
VZ
199 void OnUpdateUIPasteText(wxUpdateUIEvent& event);
200 void OnUpdateUIPasteBitmap(wxUpdateUIEvent& event);
201
c50f1fb9 202 DECLARE_EVENT_TABLE()
457814b5
JS
203
204private:
e2acb9ae 205 wxListBox *m_ctrlFile,
90e12284 206 *m_ctrlText;
e2acb9ae 207 wxTextCtrl *m_ctrlLog;
457814b5 208
90e12284
VZ
209 wxLog *m_pLog,
210 *m_pLogPrev;
43d811ea 211
e2acb9ae 212 wxString m_strText;
457814b5
JS
213};
214
8e193f38
VZ
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
221class DnDShape
222{
223public:
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
9e2896e5
VZ
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
8e193f38 243 // the functions used for drag-and-drop: they dump and restore a shape into
d59ceba5 244 // some bitwise-copiable data (might use streams too...)
8e193f38
VZ
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
d59ceba5
VZ
273 void Move(const wxPoint& pos) { m_pos = pos; }
274
8e193f38
VZ
275 // to implement in derived classes
276 virtual Kind GetKind() const = 0;
277
1dd989e1 278 virtual void Draw(wxDC& dc)
8e193f38
VZ
279 {
280 dc.SetPen(wxPen(m_col, 1, wxSOLID));
281 }
282
283protected:
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
300class DnDTriangularShape : public DnDShape
301{
302public:
303 DnDTriangularShape(const wxPoint& pos,
304 const wxSize& size,
305 const wxColour& col)
306 : DnDShape(pos, size, col)
307 {
90e12284 308 wxLogMessage("DnDTriangularShape is being created");
8e193f38
VZ
309 }
310
9e2896e5
VZ
311 virtual ~DnDTriangularShape()
312 {
313 wxLogMessage("DnDTriangularShape is being deleted");
314 }
315
8e193f38
VZ
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
1dd989e1 331#ifdef __WXMSW__
8e193f38 332 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
1dd989e1 333#endif
8e193f38
VZ
334 }
335};
336
337class DnDRectangularShape : public DnDShape
338{
339public:
340 DnDRectangularShape(const wxPoint& pos,
341 const wxSize& size,
342 const wxColour& col)
343 : DnDShape(pos, size, col)
344 {
90e12284 345 wxLogMessage("DnDRectangularShape is being created");
8e193f38
VZ
346 }
347
9e2896e5
VZ
348 virtual ~DnDRectangularShape()
349 {
350 wxLogMessage("DnDRectangularShape is being deleted");
351 }
352
8e193f38
VZ
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
1dd989e1 368#ifdef __WXMSW__
8e193f38 369 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
1dd989e1 370#endif
8e193f38
VZ
371 }
372};
373
374class DnDEllipticShape : public DnDShape
375{
376public:
377 DnDEllipticShape(const wxPoint& pos,
378 const wxSize& size,
379 const wxColour& col)
380 : DnDShape(pos, size, col)
381 {
90e12284 382 wxLogMessage("DnDEllipticShape is being created");
8e193f38
VZ
383 }
384
9e2896e5
VZ
385 virtual ~DnDEllipticShape()
386 {
387 wxLogMessage("DnDEllipticShape is being deleted");
388 }
389
8e193f38
VZ
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
1dd989e1 397#ifdef __WXMSW__
8e193f38 398 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
1dd989e1 399#endif
8e193f38
VZ
400 }
401};
402
403// ----------------------------------------------------------------------------
404// A wxDataObject specialisation for the application-specific data
405// ----------------------------------------------------------------------------
406
407static const char *shapeFormatId = "wxShape";
408
409class DnDShapeDataObject : public wxDataObject
410{
411public:
412 // ctor doesn't copy the pointer, so it shouldn't go away while this object
413 // is alive
9e2896e5 414 DnDShapeDataObject(DnDShape *shape = (DnDShape *)NULL)
8e193f38 415 {
9e2896e5
VZ
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 }
8e193f38
VZ
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;
5a1c877f
VZ
440#ifdef USE_METAFILES
441 m_hasMetaFile = FALSE;
442#endif // Windows
8e193f38
VZ
443 }
444
9e2896e5
VZ
445 virtual ~DnDShapeDataObject() { delete m_shape; }
446
90e12284
VZ
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;
5a1c877f
VZ
459#ifdef USE_METAFILES
460 m_hasMetaFile = FALSE;
461#endif // Windows
90e12284
VZ
462
463 return shape;
464 }
d59ceba5 465
8e193f38
VZ
466 // implement base class pure virtuals
467 // ----------------------------------
468
9e2896e5 469 virtual wxDataFormat GetPreferredFormat(Direction WXUNUSED(dir)) const
8e193f38
VZ
470 {
471 return m_formatShape;
472 }
473
9e2896e5 474 virtual size_t GetFormatCount(Direction dir) const
8e193f38 475 {
d59ceba5
VZ
476 // our custom format is supported by both GetData() and SetData()
477 size_t nFormats = 1;
9e2896e5 478 if ( dir == Get )
d59ceba5
VZ
479 {
480 // but the bitmap format(s) are only supported for output
5a1c877f
VZ
481 nFormats += m_dobjBitmap.GetFormatCount(dir);
482
483#ifdef USE_METAFILES
484 nFormats += m_dobjMetaFile.GetFormatCount(dir);
485#endif // Windows
d59ceba5
VZ
486 }
487
488 return nFormats;
8e193f38
VZ
489 }
490
9e2896e5 491 virtual void GetAllFormats(wxDataFormat *formats, Direction dir) const
8e193f38
VZ
492 {
493 formats[0] = m_formatShape;
9e2896e5 494 if ( dir == Get )
d59ceba5 495 {
5a1c877f
VZ
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
d59ceba5 505 }
8e193f38
VZ
506 }
507
508 virtual size_t GetDataSize(const wxDataFormat& format) const
509 {
510 if ( format == m_formatShape )
511 {
512 return m_shape->GetDataSize();
513 }
5a1c877f 514#ifdef USE_METAFILES
ae3dd4a5 515 else if ( m_dobjMetaFile.IsSupported(format) )
5a1c877f
VZ
516 {
517 if ( !m_hasMetaFile )
518 CreateMetaFile();
519
ae3dd4a5 520 return m_dobjMetaFile.GetDataSize(format);
5a1c877f
VZ
521 }
522#endif // Windows
8e193f38
VZ
523 else
524 {
ae3dd4a5
VZ
525 wxASSERT_MSG( m_dobjBitmap.IsSupported(format),
526 "unexpected format" );
527
8e193f38
VZ
528 if ( !m_hasBitmap )
529 CreateBitmap();
530
5a1c877f 531 return m_dobjBitmap.GetDataSize();
8e193f38
VZ
532 }
533 }
534
d59ceba5 535 virtual bool GetDataHere(const wxDataFormat& format, void *pBuf) const
8e193f38
VZ
536 {
537 if ( format == m_formatShape )
538 {
539 m_shape->GetDataHere(pBuf);
d59ceba5
VZ
540
541 return TRUE;
8e193f38 542 }
5a1c877f 543#ifdef USE_METAFILES
ae3dd4a5 544 else if ( m_dobjMetaFile.IsSupported(format) )
5a1c877f
VZ
545 {
546 if ( !m_hasMetaFile )
547 CreateMetaFile();
548
ae3dd4a5 549 return m_dobjMetaFile.GetDataHere(format, pBuf);
5a1c877f
VZ
550 }
551#endif // Windows
8e193f38
VZ
552 else
553 {
ae3dd4a5
VZ
554 wxASSERT_MSG( m_dobjBitmap.IsSupported(format),
555 "unexpected format" );
556
8e193f38
VZ
557 if ( !m_hasBitmap )
558 CreateBitmap();
559
5a1c877f 560 return m_dobjBitmap.GetDataHere(pBuf);
8e193f38
VZ
561 }
562 }
563
9e2896e5
VZ
564 virtual bool SetData(const wxDataFormat& format,
565 size_t len, const void *buf)
d59ceba5
VZ
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
5a1c877f
VZ
575#ifdef USE_METAFILES
576 m_hasMetaFile = FALSE;
577#endif // Windows
578
d59ceba5
VZ
579 return TRUE;
580 }
581
8e193f38 582private:
5a1c877f 583 // creates a bitmap and assigns it to m_dobjBitmap (also sets m_hasBitmap)
8e193f38 584 void CreateBitmap() const;
5a1c877f
VZ
585#ifdef USE_METAFILES
586 void CreateMetaFile() const;
587#endif // Windows
8e193f38
VZ
588
589 wxDataFormat m_formatShape; // our custom format
590
5a1c877f
VZ
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
8e193f38
VZ
598
599 DnDShape *m_shape; // our data
600};
601
602// ----------------------------------------------------------------------------
603// A dialog to edit shape properties
604// ----------------------------------------------------------------------------
605
606class DnDShapeDialog : public wxDialog
607{
608public:
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
618private:
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
642class DnDShapeFrame : public wxFrame
643{
644public:
645 DnDShapeFrame(wxFrame *parent);
646 ~DnDShapeFrame();
647
648 void SetShape(DnDShape *shape);
649
650 // callbacks
d59ceba5
VZ
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
8e193f38 661 void OnDrag(wxMouseEvent& event);
8e193f38 662 void OnPaint(wxPaintEvent& event);
90e12284 663 void OnDrop(wxCoord x, wxCoord y, DnDShape *shape);
8e193f38
VZ
664
665private:
666 DnDShape *m_shape;
667
d59ceba5
VZ
668 static DnDShapeFrame *ms_lastDropTarget;
669
8e193f38
VZ
670 DECLARE_EVENT_TABLE()
671};
672
673// ----------------------------------------------------------------------------
674// wxDropTarget derivation for DnDShapes
675// ----------------------------------------------------------------------------
676
677class DnDShapeDropTarget : public wxDropTarget
678{
679public:
680 DnDShapeDropTarget(DnDShapeFrame *frame)
9e2896e5 681 : wxDropTarget(new DnDShapeDataObject)
8e193f38
VZ
682 {
683 m_frame = frame;
8e193f38
VZ
684 }
685
686 // override base class (pure) virtuals
72a7edf0 687 virtual wxDragResult OnEnter(wxCoord x, wxCoord y, wxDragResult def)
5a1c877f 688 { m_frame->SetStatusText("Mouse entered the frame"); return OnDragOver(x, y, def); }
8e193f38
VZ
689 virtual void OnLeave()
690 { m_frame->SetStatusText("Mouse left the frame"); }
8ee9d618 691 virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def)
8e193f38 692 {
9e2896e5
VZ
693 if ( !GetData() )
694 {
695 wxLogError("Failed to get drag and drop data");
696
8ee9d618 697 return wxDragNone;
9e2896e5
VZ
698 }
699
700 m_frame->OnDrop(x, y,
701 ((DnDShapeDataObject *)GetDataObject())->GetShape());
8e193f38 702
8ee9d618 703 return def;
8e193f38
VZ
704 }
705
8e193f38
VZ
706private:
707 DnDShapeFrame *m_frame;
8e193f38
VZ
708};
709
ae3dd4a5
VZ
710// ----------------------------------------------------------------------------
711// functions prototypes
712// ----------------------------------------------------------------------------
713
714static void ShowBitmap(const wxBitmap& bitmap);
715
716#ifdef USE_METAFILES
717static void ShowMetaFile(const wxMetaFile& metafile);
718#endif // USE_METAFILES
719
457814b5
JS
720// ----------------------------------------------------------------------------
721// IDs for the menu commands
722// ----------------------------------------------------------------------------
ab8884ac 723
457814b5
JS
724enum
725{
c50f1fb9
VZ
726 Menu_Quit = 1,
727 Menu_Drag,
8e193f38 728 Menu_NewFrame,
c50f1fb9
VZ
729 Menu_About = 101,
730 Menu_Help,
731 Menu_Clear,
732 Menu_Copy,
e2acb9ae
RR
733 Menu_Paste,
734 Menu_CopyBitmap,
735 Menu_PasteBitmap,
5a1c877f 736 Menu_PasteMFile,
51edda6a 737 Menu_CopyFiles,
d59ceba5
VZ
738 Menu_Shape_New = 500,
739 Menu_Shape_Edit,
740 Menu_Shape_Clear,
741 Menu_ShapeClipboard_Copy,
742 Menu_ShapeClipboard_Paste,
8e193f38 743 Button_Colour = 1001
457814b5
JS
744};
745
746BEGIN_EVENT_TABLE(DnDFrame, wxFrame)
e2acb9ae
RR
747 EVT_MENU(Menu_Quit, DnDFrame::OnQuit)
748 EVT_MENU(Menu_About, DnDFrame::OnAbout)
749 EVT_MENU(Menu_Drag, DnDFrame::OnDrag)
8e193f38 750 EVT_MENU(Menu_NewFrame, DnDFrame::OnNewFrame)
e2acb9ae
RR
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)
5a1c877f
VZ
757#ifdef USE_METAFILES
758 EVT_MENU(Menu_PasteMFile, DnDFrame::OnPasteMetafile)
759#endif // USE_METAFILES
51edda6a 760 EVT_MENU(Menu_CopyFiles, DnDFrame::OnCopyFiles)
d59ceba5
VZ
761
762 EVT_UPDATE_UI(Menu_Paste, DnDFrame::OnUpdateUIPasteText)
763 EVT_UPDATE_UI(Menu_PasteBitmap, DnDFrame::OnUpdateUIPasteBitmap)
e2acb9ae
RR
764
765 EVT_LEFT_DOWN( DnDFrame::OnLeftDown)
766 EVT_RIGHT_DOWN( DnDFrame::OnRightDown)
767 EVT_PAINT( DnDFrame::OnPaint)
457814b5
JS
768END_EVENT_TABLE()
769
8e193f38 770BEGIN_EVENT_TABLE(DnDShapeFrame, wxFrame)
d59ceba5
VZ
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
8e193f38
VZ
783 EVT_PAINT(DnDShapeFrame::OnPaint)
784END_EVENT_TABLE()
785
786BEGIN_EVENT_TABLE(DnDShapeDialog, wxDialog)
b0a6c154 787 EVT_BUTTON(Button_Colour, DnDShapeDialog::OnColour)
8e193f38
VZ
788END_EVENT_TABLE()
789
ae3dd4a5
VZ
790BEGIN_EVENT_TABLE(DnDCanvasBitmap, wxScrolledWindow)
791 EVT_PAINT(DnDCanvasBitmap::OnPaint)
792END_EVENT_TABLE()
793
794#ifdef USE_METAFILES
795BEGIN_EVENT_TABLE(DnDCanvasMetafile, wxScrolledWindow)
796 EVT_PAINT(DnDCanvasMetafile::OnPaint)
797END_EVENT_TABLE()
798#endif // USE_METAFILES
799
8e193f38
VZ
800// ============================================================================
801// implementation
802// ============================================================================
803
804// `Main program' equivalent, creating windows and returning main app frame
8bbe427f 805bool DnDApp::OnInit()
457814b5 806{
ae125753
VZ
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
61b04ac6
VZ
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
e2acb9ae
RR
833#if wxUSE_LIBPNG
834 wxImage::AddHandler( new wxPNGHandler );
835#endif
836
74d38ad8
VZ
837 // under X we usually want to use the primary selection by default (which
838 // is shared with other apps)
839 wxTheClipboard->UsePrimarySelection();
840
c50f1fb9
VZ
841 // create the main frame window
842 DnDFrame *frame = new DnDFrame((wxFrame *) NULL,
843 "Drag-and-Drop/Clipboard wxWindows Sample",
5a1c877f 844 10, 100, 650, 340);
457814b5 845
c50f1fb9
VZ
846 // activate it
847 frame->Show(TRUE);
457814b5 848
c50f1fb9 849 SetTopWindow(frame);
457814b5 850
c50f1fb9 851 return TRUE;
457814b5
JS
852}
853
854DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
43d811ea
JS
855 : wxFrame(frame, -1, title, wxPoint(x, y), wxSize(w, h)),
856 m_strText("wxWindows drag & drop works :-)")
857
457814b5 858{
c50f1fb9
VZ
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();
8e193f38 868 file_menu->Append(Menu_NewFrame, "&New frame\tCtrl-N");
d1b15f03 869 file_menu->AppendSeparator();
8e193f38 870 file_menu->Append(Menu_Quit, "E&xit");
c50f1fb9
VZ
871
872 wxMenu *log_menu = new wxMenu;
810b5e1f 873 log_menu->Append(Menu_Clear, "Clear\tCtrl-L");
c50f1fb9
VZ
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;
e2acb9ae
RR
881 clip_menu->Append(Menu_Copy, "&Copy text\tCtrl+C");
882 clip_menu->Append(Menu_Paste, "&Paste text\tCtrl+V");
883 clip_menu->AppendSeparator();
5a1c877f
VZ
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
51edda6a 887 clip_menu->AppendSeparator();
5a1c877f
VZ
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");
8e193f38 892
c50f1fb9
VZ
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
d59ceba5
VZ
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 );
c50f1fb9
VZ
911
912 m_ctrlLog = new wxTextCtrl(this, -1, "", pos, size,
d59ceba5
VZ
913 wxTE_MULTILINE | wxTE_READONLY |
914 wxSUNKEN_BORDER );
8e193f38 915
61b04ac6 916 // redirect log messages to the text window
e2acb9ae
RR
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);
d59ceba5 946 c->height.PercentOf(this, wxHeight, 50);
e2acb9ae
RR
947 c->top.SameAs(m_ctrlText, wxBottom);
948 m_ctrlLog->SetConstraints(c);
949
950 SetAutoLayout(TRUE);
457814b5
JS
951}
952
e2acb9ae 953void DnDFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
457814b5 954{
c50f1fb9 955 Close(TRUE);
457814b5
JS
956}
957
e2acb9ae 958void DnDFrame::OnPaint(wxPaintEvent& WXUNUSED(event))
b527aac5 959{
c50f1fb9
VZ
960 int w = 0;
961 int h = 0;
962 GetClientSize( &w, &h );
8bbe427f 963
c50f1fb9
VZ
964 wxPaintDC dc(this);
965 dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL, FALSE, "charter" ) );
ae3dd4a5 966 dc.DrawText( "Drag text from here!", 100, h-50 );
e2acb9ae
RR
967}
968
d59ceba5 969void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent& event)
e2acb9ae 970{
61b04ac6
VZ
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
d59ceba5
VZ
977 event.Enable( wxTheClipboard->IsSupported(wxDF_TEXT) );
978}
e2acb9ae 979
d59ceba5
VZ
980void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent& event)
981{
61b04ac6
VZ
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
d59ceba5 988 event.Enable( wxTheClipboard->IsSupported(wxDF_BITMAP) );
e2acb9ae
RR
989}
990
8e193f38
VZ
991void 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
e2acb9ae 998void DnDFrame::OnDrag(wxCommandEvent& WXUNUSED(event))
43d811ea 999{
c50f1fb9
VZ
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;
43d811ea
JS
1010}
1011
e2acb9ae 1012void DnDFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
457814b5 1013{
c50f1fb9
VZ
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);
457814b5
JS
1020}
1021
1022void DnDFrame::OnHelp(wxCommandEvent& /* event */)
1023{
c50f1fb9
VZ
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();
457814b5
JS
1048}
1049
e3e65dac 1050void DnDFrame::OnLogClear(wxCommandEvent& /* event */ )
43d811ea 1051{
c50f1fb9 1052 m_ctrlLog->Clear();
810b5e1f
VZ
1053 m_ctrlText->Clear();
1054 m_ctrlFile->Clear();
43d811ea
JS
1055}
1056
30dea054 1057void DnDFrame::OnLeftDown(wxMouseEvent &WXUNUSED(event) )
43d811ea 1058{
8e193f38 1059 if ( !m_strText.IsEmpty() )
c50f1fb9
VZ
1060 {
1061 // start drag operation
c50f1fb9 1062 wxTextDataObject textData(m_strText);
2d68e1b4
RR
1063/*
1064 wxFileDataObject textData;
810b5e1f
VZ
1065 textData.AddFile( "/file1.txt" );
1066 textData.AddFile( "/file2.txt" );
2d68e1b4 1067*/
354aa1e3 1068 wxDropSource source(textData, this
3f2711d5 1069
354aa1e3 1070#ifdef __WXMSW__
810b5e1f 1071 ,wxCURSOR_PENCIL, // for copy
2d93e133 1072 wxCURSOR_SPRAYCAN, // for move
810b5e1f 1073 wxCURSOR_QUESTION_ARROW // for nothing
354aa1e3 1074#endif
810b5e1f 1075 );
8e193f38 1076
c50f1fb9
VZ
1077 const char *pc;
1078
8e193f38 1079 switch ( source.DoDragDrop(TRUE) )
c50f1fb9
VZ
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);
43d811ea 1090 }
43d811ea
JS
1091}
1092
30dea054
RR
1093void DnDFrame::OnRightDown(wxMouseEvent &event )
1094{
51edda6a 1095 wxMenu menu("Dnd sample menu");
8bbe427f 1096
51edda6a
VZ
1097 menu.Append(Menu_Drag, "&Test drag...");
1098 menu.AppendSeparator();
1099 menu.Append(Menu_About, "&About");
8e193f38 1100
51edda6a 1101 PopupMenu( &menu, event.GetX(), event.GetY() );
30dea054
RR
1102}
1103
457814b5
JS
1104DnDFrame::~DnDFrame()
1105{
c50f1fb9
VZ
1106 if ( m_pLog != NULL ) {
1107 if ( wxLog::SetActiveTarget(m_pLogPrev) == m_pLog )
1108 delete m_pLog;
1109 }
1110}
1111
1112// ---------------------------------------------------------------------------
e2acb9ae
RR
1113// bitmap clipboard
1114// ---------------------------------------------------------------------------
1115
1116void DnDFrame::OnCopyBitmap(wxCommandEvent& WXUNUSED(event))
1117{
1bd1d102
VZ
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
e2acb9ae 1122 wxFileDialog dialog(this, "Open a PNG file", "", "", "PNG files (*.png)|*.png", 0);
1bd1d102 1123#endif
e2acb9ae
RR
1124
1125 if (dialog.ShowModal() != wxID_OK)
8e193f38 1126 {
e2acb9ae
RR
1127 wxLogMessage( _T("Aborted file open") );
1128 return;
1129 }
8e193f38 1130
e2acb9ae 1131 if (dialog.GetPath().IsEmpty())
8e193f38 1132 {
e2acb9ae
RR
1133 wxLogMessage( _T("Returned empty string.") );
1134 return;
1135 }
8e193f38 1136
e2acb9ae
RR
1137 if (!wxFileExists(dialog.GetPath()))
1138 {
1139 wxLogMessage( _T("File doesn't exist.") );
1140 return;
1141 }
8e193f38 1142
e2acb9ae 1143 wxImage image;
8e193f38 1144 image.LoadFile( dialog.GetPath(),
1bd1d102
VZ
1145#ifdef __WXMSW__
1146 wxBITMAP_TYPE_BMP
1147#else
1148 wxBITMAP_TYPE_PNG
1149#endif
1150 );
e2acb9ae
RR
1151 if (!image.Ok())
1152 {
8e193f38 1153 wxLogError( _T("Invalid image file...") );
e2acb9ae
RR
1154 return;
1155 }
8e193f38
VZ
1156
1157 wxLogStatus( _T("Decoding image file...") );
e2acb9ae 1158 wxYield();
8e193f38 1159
e2acb9ae
RR
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();
8e193f38 1171
e2acb9ae
RR
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;
79ec2ce2 1203 if ( !wxTheClipboard->GetData(data) )
e2acb9ae
RR
1204 {
1205 wxLogError(_T("Can't paste bitmap from the clipboard"));
1206 }
1207 else
1208 {
ae3dd4a5
VZ
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);
e2acb9ae
RR
1214 }
1215
1216 wxTheClipboard->Close();
1217}
1218
5a1c877f
VZ
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 {
ae3dd4a5 1243 const wxMetaFile& mf = data.GetMetafile();
5a1c877f 1244
ae3dd4a5
VZ
1245 wxLogMessage(_T("Metafile %dx%d pasted from the clipboard"),
1246 mf.GetWidth(), mf.GetHeight());
1247
1248 ShowMetaFile(mf);
5a1c877f
VZ
1249 }
1250 }
1251
1252 wxTheClipboard->Close();
1253}
1254
1255#endif // USE_METAFILES
1256
51edda6a
VZ
1257// ----------------------------------------------------------------------------
1258// file clipboard
1259// ----------------------------------------------------------------------------
1260
1261void DnDFrame::OnCopyFiles(wxCommandEvent& WXUNUSED(event))
1262{
1263#ifdef __WXMSW__
51edda6a
VZ
1264 wxFileDialog dialog(this, "Select a file to copy", "", "",
1265 "All files (*.*)|*.*", 0);
1266
3f2711d5
VZ
1267 wxArrayString filenames;
1268 while ( dialog.ShowModal() == wxID_OK )
51edda6a 1269 {
3f2711d5
VZ
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 }
51edda6a
VZ
1281
1282 wxClipboardLocker locker;
1283 if ( !locker )
1284 {
1285 wxLogError("Can't open clipboard");
1286 }
1287 else
1288 {
1289 if ( !wxTheClipboard->AddData(dobj) )
1290 {
3f2711d5 1291 wxLogError("Can't copy file(s) to the clipboard");
51edda6a
VZ
1292 }
1293 else
1294 {
3f2711d5
VZ
1295 wxLogStatus(this, "%d file%s copied to the clipboard",
1296 count, count == 1 ? "" : "s");
51edda6a
VZ
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
e2acb9ae
RR
1309// ---------------------------------------------------------------------------
1310// text clipboard
c50f1fb9
VZ
1311// ---------------------------------------------------------------------------
1312
1313void DnDFrame::OnCopy(wxCommandEvent& WXUNUSED(event))
1314{
1315 if ( !wxTheClipboard->Open() )
1316 {
b56baa2d 1317 wxLogError(_T("Can't open clipboard."));
c50f1fb9
VZ
1318
1319 return;
1320 }
1321
1322 if ( !wxTheClipboard->AddData(new wxTextDataObject(m_strText)) )
1323 {
b56baa2d 1324 wxLogError(_T("Can't copy data to the clipboard"));
c50f1fb9
VZ
1325 }
1326 else
1327 {
b56baa2d 1328 wxLogMessage(_T("Text '%s' put on the clipboard"), m_strText.c_str());
c50f1fb9
VZ
1329 }
1330
1331 wxTheClipboard->Close();
1332}
1333
1334void DnDFrame::OnPaste(wxCommandEvent& WXUNUSED(event))
1335{
1336 if ( !wxTheClipboard->Open() )
1337 {
b56baa2d 1338 wxLogError(_T("Can't open clipboard."));
c50f1fb9
VZ
1339
1340 return;
1341 }
1342
1343 if ( !wxTheClipboard->IsSupported(wxDF_TEXT) )
1344 {
b56baa2d 1345 wxLogWarning(_T("No text data on clipboard"));
c50f1fb9 1346
e2acb9ae 1347 wxTheClipboard->Close();
c50f1fb9
VZ
1348 return;
1349 }
1350
1351 wxTextDataObject text;
79ec2ce2 1352 if ( !wxTheClipboard->GetData(text) )
c50f1fb9 1353 {
b56baa2d 1354 wxLogError(_T("Can't paste data from the clipboard"));
c50f1fb9
VZ
1355 }
1356 else
1357 {
b56baa2d 1358 wxLogMessage(_T("Text '%s' pasted from the clipboard"),
c50f1fb9
VZ
1359 text.GetText().c_str());
1360 }
1361
1362 wxTheClipboard->Close();
457814b5
JS
1363}
1364
1365// ----------------------------------------------------------------------------
1366// Notifications called by the base class
1367// ----------------------------------------------------------------------------
e2acb9ae 1368
9e2896e5 1369bool DnDText::OnDropText(wxCoord, wxCoord, const wxString& text)
457814b5 1370{
9e2896e5 1371 m_pOwner->Append(text);
457814b5 1372
c50f1fb9 1373 return TRUE;
457814b5
JS
1374}
1375
9e2896e5 1376bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& filenames)
457814b5 1377{
9e2896e5 1378 size_t nFiles = filenames.GetCount();
c50f1fb9
VZ
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++ ) {
9e2896e5 1383 m_pOwner->Append(filenames[n]);
c50f1fb9
VZ
1384 }
1385
1386 return TRUE;
457814b5 1387}
8e193f38
VZ
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{
a3e7d24d 1421
8e193f38
VZ
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
d59ceba5
VZ
1485DnDShapeFrame *DnDShapeFrame::ms_lastDropTarget = NULL;
1486
8e193f38
VZ
1487DnDShapeFrame::DnDShapeFrame(wxFrame *parent)
1488 : wxFrame(parent, -1, "Shape Frame",
1489 wxDefaultPosition, wxSize(250, 150))
1490{
8e193f38
VZ
1491 CreateStatusBar();
1492
d59ceba5
VZ
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();
5a1c877f 1497 menuShape->Append(Menu_Shape_Clear, "&Clear shape\tCtrl-L");
d59ceba5
VZ
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");
8e193f38
VZ
1510
1511 SetDropTarget(new DnDShapeDropTarget(this));
1512
1513 m_shape = NULL;
572c6194
RR
1514
1515 SetBackgroundColour(*wxWHITE);
8e193f38
VZ
1516}
1517
1518DnDShapeFrame::~DnDShapeFrame()
1519{
572c6194
RR
1520 if (m_shape)
1521 delete m_shape;
8e193f38
VZ
1522}
1523
1524void DnDShapeFrame::SetShape(DnDShape *shape)
1525{
572c6194
RR
1526 if (m_shape)
1527 delete m_shape;
8e193f38
VZ
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);
2d93e133 1544 wxDropSource source(shapeData, this);
8e193f38
VZ
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";
d59ceba5
VZ
1564 if ( ms_lastDropTarget != this )
1565 {
1566 // don't delete the shape if we dropped it on ourselves!
1567 SetShape(NULL);
1568 }
8e193f38
VZ
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
90e12284 1583void DnDShapeFrame::OnDrop(wxCoord x, wxCoord y, DnDShape *shape)
9e2896e5
VZ
1584{
1585 ms_lastDropTarget = this;
1586
90e12284 1587 wxPoint pt(x, y);
90e12284 1588
9e2896e5 1589 wxString s;
90e12284 1590 s.Printf("Shape dropped at (%ld, %ld)", pt.x, pt.y);
9e2896e5
VZ
1591 SetStatusText(s);
1592
90e12284 1593 shape->Move(pt);
9e2896e5
VZ
1594 SetShape(shape);
1595}
1596
d59ceba5 1597void DnDShapeFrame::OnEditShape(wxCommandEvent& event)
8e193f38
VZ
1598{
1599 DnDShapeDialog dlg(this, m_shape);
1600 if ( dlg.ShowModal() == wxID_OK )
1601 {
1602 SetShape(dlg.GetShape());
1603
1604 if ( m_shape )
1605 {
d59ceba5 1606 SetStatusText("You can now drag the shape to another frame");
8e193f38
VZ
1607 }
1608 }
1609}
1610
d59ceba5
VZ
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 )
ae125753
VZ
1626 {
1627 wxClipboardLocker clipLocker;
1628 if ( !clipLocker )
1629 {
1630 wxLogError("Can't open the clipboard");
1631
1632 return;
1633 }
1634
d59ceba5 1635 wxTheClipboard->AddData(new DnDShapeDataObject(m_shape));
ae125753 1636 }
d59ceba5
VZ
1637}
1638
1639void DnDShapeFrame::OnPasteShape(wxCommandEvent& event)
1640{
ae125753
VZ
1641 wxClipboardLocker clipLocker;
1642 if ( !clipLocker )
1643 {
1644 wxLogError("Can't open the clipboard");
1645
1646 return;
1647 }
1648
d59ceba5 1649 DnDShapeDataObject shapeDataObject(NULL);
79ec2ce2 1650 if ( wxTheClipboard->GetData(shapeDataObject) )
d59ceba5
VZ
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
8e193f38
VZ
1670void DnDShapeFrame::OnPaint(wxPaintEvent& event)
1671{
1672 if ( m_shape )
79ec2ce2
VZ
1673 {
1674 wxPaintDC dc(this);
1675
1676 m_shape->Draw(dc);
1677 }
8e193f38 1678 else
79ec2ce2 1679 {
8e193f38 1680 event.Skip();
79ec2ce2 1681 }
8e193f38
VZ
1682}
1683
8e193f38
VZ
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
5a1c877f
VZ
1718#ifdef USE_METAFILES
1719
1720void DnDShapeDataObject::CreateMetaFile() const
1721{
ae3dd4a5
VZ
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);
5a1c877f
VZ
1726
1727 m_shape->Draw(dcMF);
1728
1729 wxMetafile *mf = dcMF.Close();
1730
5a1c877f
VZ
1731 DnDShapeDataObject *self = (DnDShapeDataObject *)this; // const_cast
1732 self->m_dobjMetaFile.SetMetafile(*mf);
1733 self->m_hasMetaFile = TRUE;
ae3dd4a5
VZ
1734
1735 delete mf;
5a1c877f
VZ
1736}
1737
1738#endif // Windows
1739
8e193f38
VZ
1740void DnDShapeDataObject::CreateBitmap() const
1741{
d59ceba5
VZ
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);
8e193f38
VZ
1747 wxMemoryDC dc;
1748 dc.SelectObject(bitmap);
d59ceba5
VZ
1749 dc.SetBrush(wxBrush("white", wxSOLID));
1750 dc.Clear();
8e193f38
VZ
1751 m_shape->Draw(dc);
1752 dc.SelectObject(wxNullBitmap);
1753
1754 DnDShapeDataObject *self = (DnDShapeDataObject *)this; // const_cast
5a1c877f 1755 self->m_dobjBitmap.SetBitmap(bitmap);
8e193f38
VZ
1756 self->m_hasBitmap = TRUE;
1757}
1758
ae3dd4a5
VZ
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);
e680a378 1775 frame->Show(TRUE);
ae3dd4a5
VZ
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