]> git.saurik.com Git - wxWidgets.git/blame - samples/dnd/dnd.cpp
applied (part of) patch 433176 (reduce flicker)
[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"
f6bcfd97
BP
49
50 #include "dnd_copy.xpm"
51 #include "dnd_move.xpm"
52 #include "dnd_none.xpm"
47908e25
RR
53#endif
54
457814b5 55// ----------------------------------------------------------------------------
2845ddc2 56// Derive two simple classes which just put in the listbox the strings (text or
457814b5
JS
57// file names) we drop on them
58// ----------------------------------------------------------------------------
ab8884ac 59
457814b5
JS
60class DnDText : public wxTextDropTarget
61{
62public:
c50f1fb9 63 DnDText(wxListBox *pOwner) { m_pOwner = pOwner; }
457814b5 64
9e2896e5 65 virtual bool OnDropText(wxCoord x, wxCoord y, const wxString& text);
457814b5
JS
66
67private:
c50f1fb9 68 wxListBox *m_pOwner;
457814b5
JS
69};
70
71class DnDFile : public wxFileDropTarget
72{
73public:
c50f1fb9 74 DnDFile(wxListBox *pOwner) { m_pOwner = pOwner; }
457814b5 75
9e2896e5
VZ
76 virtual bool OnDropFiles(wxCoord x, wxCoord y,
77 const wxArrayString& filenames);
457814b5
JS
78
79private:
c50f1fb9 80 wxListBox *m_pOwner;
457814b5
JS
81};
82
83// ----------------------------------------------------------------------------
84// Define a new application type
85// ----------------------------------------------------------------------------
ab8884ac 86
457814b5 87class DnDApp : public wxApp
8bbe427f 88{
457814b5 89public:
8e193f38 90 virtual bool OnInit();
457814b5
JS
91};
92
93IMPLEMENT_APP(DnDApp);
94
ae3dd4a5
VZ
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
457814b5 170// ----------------------------------------------------------------------------
8e193f38 171// Define a new frame type for the main frame
457814b5 172// ----------------------------------------------------------------------------
8e193f38 173
457814b5 174class DnDFrame : public wxFrame
8bbe427f 175{
457814b5 176public:
c50f1fb9
VZ
177 DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h);
178 ~DnDFrame();
457814b5 179
c50f1fb9
VZ
180 void OnPaint(wxPaintEvent& event);
181 void OnQuit (wxCommandEvent& event);
182 void OnAbout(wxCommandEvent& event);
183 void OnDrag (wxCommandEvent& event);
8e193f38 184 void OnNewFrame(wxCommandEvent& event);
c50f1fb9
VZ
185 void OnHelp (wxCommandEvent& event);
186 void OnLogClear(wxCommandEvent& event);
51edda6a 187
c50f1fb9
VZ
188 void OnCopy(wxCommandEvent& event);
189 void OnPaste(wxCommandEvent& event);
51edda6a 190
e2acb9ae
RR
191 void OnCopyBitmap(wxCommandEvent& event);
192 void OnPasteBitmap(wxCommandEvent& event);
43d811ea 193
5a1c877f
VZ
194#ifdef USE_METAFILES
195 void OnPasteMetafile(wxCommandEvent& event);
196#endif // USE_METAFILES
197
51edda6a
VZ
198 void OnCopyFiles(wxCommandEvent& event);
199
c50f1fb9
VZ
200 void OnLeftDown(wxMouseEvent& event);
201 void OnRightDown(wxMouseEvent& event);
8bbe427f 202
d59ceba5
VZ
203 void OnUpdateUIPasteText(wxUpdateUIEvent& event);
204 void OnUpdateUIPasteBitmap(wxUpdateUIEvent& event);
205
c50f1fb9 206 DECLARE_EVENT_TABLE()
457814b5
JS
207
208private:
e2acb9ae 209 wxListBox *m_ctrlFile,
90e12284 210 *m_ctrlText;
e2acb9ae 211 wxTextCtrl *m_ctrlLog;
457814b5 212
90e12284
VZ
213 wxLog *m_pLog,
214 *m_pLogPrev;
43d811ea 215
e2acb9ae 216 wxString m_strText;
457814b5
JS
217};
218
8e193f38
VZ
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
9e2896e5
VZ
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
8e193f38 247 // the functions used for drag-and-drop: they dump and restore a shape into
d59ceba5 248 // some bitwise-copiable data (might use streams too...)
8e193f38
VZ
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
d59ceba5
VZ
277 void Move(const wxPoint& pos) { m_pos = pos; }
278
8e193f38
VZ
279 // to implement in derived classes
280 virtual Kind GetKind() const = 0;
281
1dd989e1 282 virtual void Draw(wxDC& dc)
8e193f38
VZ
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 {
90e12284 312 wxLogMessage("DnDTriangularShape is being created");
8e193f38
VZ
313 }
314
9e2896e5
VZ
315 virtual ~DnDTriangularShape()
316 {
317 wxLogMessage("DnDTriangularShape is being deleted");
318 }
319
8e193f38
VZ
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
1dd989e1 335#ifdef __WXMSW__
8e193f38 336 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
1dd989e1 337#endif
8e193f38
VZ
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 {
90e12284 349 wxLogMessage("DnDRectangularShape is being created");
8e193f38
VZ
350 }
351
9e2896e5
VZ
352 virtual ~DnDRectangularShape()
353 {
354 wxLogMessage("DnDRectangularShape is being deleted");
355 }
356
8e193f38
VZ
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
1dd989e1 372#ifdef __WXMSW__
8e193f38 373 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
1dd989e1 374#endif
8e193f38
VZ
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 {
90e12284 386 wxLogMessage("DnDEllipticShape is being created");
8e193f38
VZ
387 }
388
9e2896e5
VZ
389 virtual ~DnDEllipticShape()
390 {
391 wxLogMessage("DnDEllipticShape is being deleted");
392 }
393
8e193f38
VZ
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
1dd989e1 401#ifdef __WXMSW__
8e193f38 402 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
1dd989e1 403#endif
8e193f38
VZ
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
9e2896e5 418 DnDShapeDataObject(DnDShape *shape = (DnDShape *)NULL)
8e193f38 419 {
9e2896e5
VZ
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 }
8e193f38
VZ
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;
5a1c877f
VZ
444#ifdef USE_METAFILES
445 m_hasMetaFile = FALSE;
446#endif // Windows
8e193f38
VZ
447 }
448
9e2896e5
VZ
449 virtual ~DnDShapeDataObject() { delete m_shape; }
450
90e12284
VZ
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;
5a1c877f
VZ
463#ifdef USE_METAFILES
464 m_hasMetaFile = FALSE;
465#endif // Windows
90e12284
VZ
466
467 return shape;
468 }
d59ceba5 469
8e193f38
VZ
470 // implement base class pure virtuals
471 // ----------------------------------
472
9e2896e5 473 virtual wxDataFormat GetPreferredFormat(Direction WXUNUSED(dir)) const
8e193f38
VZ
474 {
475 return m_formatShape;
476 }
477
9e2896e5 478 virtual size_t GetFormatCount(Direction dir) const
8e193f38 479 {
d59ceba5
VZ
480 // our custom format is supported by both GetData() and SetData()
481 size_t nFormats = 1;
9e2896e5 482 if ( dir == Get )
d59ceba5
VZ
483 {
484 // but the bitmap format(s) are only supported for output
5a1c877f
VZ
485 nFormats += m_dobjBitmap.GetFormatCount(dir);
486
487#ifdef USE_METAFILES
488 nFormats += m_dobjMetaFile.GetFormatCount(dir);
489#endif // Windows
d59ceba5
VZ
490 }
491
492 return nFormats;
8e193f38
VZ
493 }
494
9e2896e5 495 virtual void GetAllFormats(wxDataFormat *formats, Direction dir) const
8e193f38
VZ
496 {
497 formats[0] = m_formatShape;
9e2896e5 498 if ( dir == Get )
d59ceba5 499 {
5a1c877f
VZ
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
d59ceba5 509 }
8e193f38
VZ
510 }
511
512 virtual size_t GetDataSize(const wxDataFormat& format) const
513 {
514 if ( format == m_formatShape )
515 {
516 return m_shape->GetDataSize();
517 }
5a1c877f 518#ifdef USE_METAFILES
ae3dd4a5 519 else if ( m_dobjMetaFile.IsSupported(format) )
5a1c877f
VZ
520 {
521 if ( !m_hasMetaFile )
522 CreateMetaFile();
523
ae3dd4a5 524 return m_dobjMetaFile.GetDataSize(format);
5a1c877f
VZ
525 }
526#endif // Windows
8e193f38
VZ
527 else
528 {
ae3dd4a5
VZ
529 wxASSERT_MSG( m_dobjBitmap.IsSupported(format),
530 "unexpected format" );
531
8e193f38
VZ
532 if ( !m_hasBitmap )
533 CreateBitmap();
534
5a1c877f 535 return m_dobjBitmap.GetDataSize();
8e193f38
VZ
536 }
537 }
538
d59ceba5 539 virtual bool GetDataHere(const wxDataFormat& format, void *pBuf) const
8e193f38
VZ
540 {
541 if ( format == m_formatShape )
542 {
543 m_shape->GetDataHere(pBuf);
d59ceba5
VZ
544
545 return TRUE;
8e193f38 546 }
5a1c877f 547#ifdef USE_METAFILES
ae3dd4a5 548 else if ( m_dobjMetaFile.IsSupported(format) )
5a1c877f
VZ
549 {
550 if ( !m_hasMetaFile )
551 CreateMetaFile();
552
ae3dd4a5 553 return m_dobjMetaFile.GetDataHere(format, pBuf);
5a1c877f
VZ
554 }
555#endif // Windows
8e193f38
VZ
556 else
557 {
ae3dd4a5
VZ
558 wxASSERT_MSG( m_dobjBitmap.IsSupported(format),
559 "unexpected format" );
560
8e193f38
VZ
561 if ( !m_hasBitmap )
562 CreateBitmap();
563
5a1c877f 564 return m_dobjBitmap.GetDataHere(pBuf);
8e193f38
VZ
565 }
566 }
567
9e2896e5
VZ
568 virtual bool SetData(const wxDataFormat& format,
569 size_t len, const void *buf)
d59ceba5
VZ
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
5a1c877f
VZ
579#ifdef USE_METAFILES
580 m_hasMetaFile = FALSE;
581#endif // Windows
582
d59ceba5
VZ
583 return TRUE;
584 }
585
8e193f38 586private:
5a1c877f 587 // creates a bitmap and assigns it to m_dobjBitmap (also sets m_hasBitmap)
8e193f38 588 void CreateBitmap() const;
5a1c877f
VZ
589#ifdef USE_METAFILES
590 void CreateMetaFile() const;
591#endif // Windows
8e193f38
VZ
592
593 wxDataFormat m_formatShape; // our custom format
594
5a1c877f
VZ
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
8e193f38
VZ
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
d59ceba5
VZ
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
8e193f38 665 void OnDrag(wxMouseEvent& event);
8e193f38 666 void OnPaint(wxPaintEvent& event);
90e12284 667 void OnDrop(wxCoord x, wxCoord y, DnDShape *shape);
8e193f38
VZ
668
669private:
670 DnDShape *m_shape;
671
d59ceba5
VZ
672 static DnDShapeFrame *ms_lastDropTarget;
673
8e193f38
VZ
674 DECLARE_EVENT_TABLE()
675};
676
677// ----------------------------------------------------------------------------
678// wxDropTarget derivation for DnDShapes
679// ----------------------------------------------------------------------------
680
681class DnDShapeDropTarget : public wxDropTarget
682{
683public:
684 DnDShapeDropTarget(DnDShapeFrame *frame)
9e2896e5 685 : wxDropTarget(new DnDShapeDataObject)
8e193f38
VZ
686 {
687 m_frame = frame;
8e193f38
VZ
688 }
689
690 // override base class (pure) virtuals
72a7edf0 691 virtual wxDragResult OnEnter(wxCoord x, wxCoord y, wxDragResult def)
5a1c877f 692 { m_frame->SetStatusText("Mouse entered the frame"); return OnDragOver(x, y, def); }
8e193f38
VZ
693 virtual void OnLeave()
694 { m_frame->SetStatusText("Mouse left the frame"); }
8ee9d618 695 virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def)
8e193f38 696 {
9e2896e5
VZ
697 if ( !GetData() )
698 {
699 wxLogError("Failed to get drag and drop data");
700
8ee9d618 701 return wxDragNone;
9e2896e5
VZ
702 }
703
704 m_frame->OnDrop(x, y,
705 ((DnDShapeDataObject *)GetDataObject())->GetShape());
8e193f38 706
8ee9d618 707 return def;
8e193f38
VZ
708 }
709
8e193f38
VZ
710private:
711 DnDShapeFrame *m_frame;
8e193f38
VZ
712};
713
ae3dd4a5
VZ
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
457814b5
JS
724// ----------------------------------------------------------------------------
725// IDs for the menu commands
726// ----------------------------------------------------------------------------
ab8884ac 727
457814b5
JS
728enum
729{
c50f1fb9
VZ
730 Menu_Quit = 1,
731 Menu_Drag,
8e193f38 732 Menu_NewFrame,
c50f1fb9
VZ
733 Menu_About = 101,
734 Menu_Help,
735 Menu_Clear,
736 Menu_Copy,
e2acb9ae
RR
737 Menu_Paste,
738 Menu_CopyBitmap,
739 Menu_PasteBitmap,
5a1c877f 740 Menu_PasteMFile,
51edda6a 741 Menu_CopyFiles,
d59ceba5
VZ
742 Menu_Shape_New = 500,
743 Menu_Shape_Edit,
744 Menu_Shape_Clear,
745 Menu_ShapeClipboard_Copy,
746 Menu_ShapeClipboard_Paste,
8e193f38 747 Button_Colour = 1001
457814b5
JS
748};
749
750BEGIN_EVENT_TABLE(DnDFrame, wxFrame)
e2acb9ae
RR
751 EVT_MENU(Menu_Quit, DnDFrame::OnQuit)
752 EVT_MENU(Menu_About, DnDFrame::OnAbout)
753 EVT_MENU(Menu_Drag, DnDFrame::OnDrag)
8e193f38 754 EVT_MENU(Menu_NewFrame, DnDFrame::OnNewFrame)
e2acb9ae
RR
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)
5a1c877f
VZ
761#ifdef USE_METAFILES
762 EVT_MENU(Menu_PasteMFile, DnDFrame::OnPasteMetafile)
763#endif // USE_METAFILES
51edda6a 764 EVT_MENU(Menu_CopyFiles, DnDFrame::OnCopyFiles)
d59ceba5
VZ
765
766 EVT_UPDATE_UI(Menu_Paste, DnDFrame::OnUpdateUIPasteText)
767 EVT_UPDATE_UI(Menu_PasteBitmap, DnDFrame::OnUpdateUIPasteBitmap)
e2acb9ae
RR
768
769 EVT_LEFT_DOWN( DnDFrame::OnLeftDown)
770 EVT_RIGHT_DOWN( DnDFrame::OnRightDown)
771 EVT_PAINT( DnDFrame::OnPaint)
457814b5
JS
772END_EVENT_TABLE()
773
8e193f38 774BEGIN_EVENT_TABLE(DnDShapeFrame, wxFrame)
d59ceba5
VZ
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
8e193f38
VZ
787 EVT_PAINT(DnDShapeFrame::OnPaint)
788END_EVENT_TABLE()
789
790BEGIN_EVENT_TABLE(DnDShapeDialog, wxDialog)
b0a6c154 791 EVT_BUTTON(Button_Colour, DnDShapeDialog::OnColour)
8e193f38
VZ
792END_EVENT_TABLE()
793
ae3dd4a5
VZ
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
8e193f38
VZ
804// ============================================================================
805// implementation
806// ============================================================================
807
808// `Main program' equivalent, creating windows and returning main app frame
8bbe427f 809bool DnDApp::OnInit()
457814b5 810{
ae125753
VZ
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
61b04ac6
VZ
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
e2acb9ae
RR
837#if wxUSE_LIBPNG
838 wxImage::AddHandler( new wxPNGHandler );
839#endif
840
74d38ad8
VZ
841 // under X we usually want to use the primary selection by default (which
842 // is shared with other apps)
843 wxTheClipboard->UsePrimarySelection();
844
c50f1fb9
VZ
845 // create the main frame window
846 DnDFrame *frame = new DnDFrame((wxFrame *) NULL,
847 "Drag-and-Drop/Clipboard wxWindows Sample",
5a1c877f 848 10, 100, 650, 340);
457814b5 849
c50f1fb9
VZ
850 // activate it
851 frame->Show(TRUE);
457814b5 852
c50f1fb9 853 SetTopWindow(frame);
457814b5 854
c50f1fb9 855 return TRUE;
457814b5
JS
856}
857
858DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
43d811ea
JS
859 : wxFrame(frame, -1, title, wxPoint(x, y), wxSize(w, h)),
860 m_strText("wxWindows drag & drop works :-)")
861
457814b5 862{
c50f1fb9
VZ
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();
8e193f38 872 file_menu->Append(Menu_NewFrame, "&New frame\tCtrl-N");
d1b15f03 873 file_menu->AppendSeparator();
8e193f38 874 file_menu->Append(Menu_Quit, "E&xit");
c50f1fb9
VZ
875
876 wxMenu *log_menu = new wxMenu;
810b5e1f 877 log_menu->Append(Menu_Clear, "Clear\tCtrl-L");
c50f1fb9
VZ
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;
e2acb9ae
RR
885 clip_menu->Append(Menu_Copy, "&Copy text\tCtrl+C");
886 clip_menu->Append(Menu_Paste, "&Paste text\tCtrl+V");
887 clip_menu->AppendSeparator();
5a1c877f
VZ
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
51edda6a 891 clip_menu->AppendSeparator();
5a1c877f
VZ
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");
8e193f38 896
c50f1fb9
VZ
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
d59ceba5
VZ
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 );
c50f1fb9
VZ
915
916 m_ctrlLog = new wxTextCtrl(this, -1, "", pos, size,
d59ceba5
VZ
917 wxTE_MULTILINE | wxTE_READONLY |
918 wxSUNKEN_BORDER );
8e193f38 919
61b04ac6 920 // redirect log messages to the text window
e2acb9ae
RR
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);
d59ceba5 950 c->height.PercentOf(this, wxHeight, 50);
e2acb9ae
RR
951 c->top.SameAs(m_ctrlText, wxBottom);
952 m_ctrlLog->SetConstraints(c);
953
954 SetAutoLayout(TRUE);
457814b5
JS
955}
956
e2acb9ae 957void DnDFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
457814b5 958{
c50f1fb9 959 Close(TRUE);
457814b5
JS
960}
961
e2acb9ae 962void DnDFrame::OnPaint(wxPaintEvent& WXUNUSED(event))
b527aac5 963{
c50f1fb9
VZ
964 int w = 0;
965 int h = 0;
966 GetClientSize( &w, &h );
8bbe427f 967
c50f1fb9
VZ
968 wxPaintDC dc(this);
969 dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL, FALSE, "charter" ) );
ae3dd4a5 970 dc.DrawText( "Drag text from here!", 100, h-50 );
e2acb9ae
RR
971}
972
d59ceba5 973void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent& event)
e2acb9ae 974{
61b04ac6
VZ
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
d59ceba5
VZ
981 event.Enable( wxTheClipboard->IsSupported(wxDF_TEXT) );
982}
e2acb9ae 983
d59ceba5
VZ
984void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent& event)
985{
61b04ac6
VZ
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
d59ceba5 992 event.Enable( wxTheClipboard->IsSupported(wxDF_BITMAP) );
e2acb9ae
RR
993}
994
8e193f38
VZ
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
e2acb9ae 1002void DnDFrame::OnDrag(wxCommandEvent& WXUNUSED(event))
43d811ea 1003{
c50f1fb9
VZ
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;
43d811ea
JS
1014}
1015
e2acb9ae 1016void DnDFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
457814b5 1017{
c50f1fb9
VZ
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);
457814b5
JS
1024}
1025
1026void DnDFrame::OnHelp(wxCommandEvent& /* event */)
1027{
c50f1fb9
VZ
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();
457814b5
JS
1052}
1053
e3e65dac 1054void DnDFrame::OnLogClear(wxCommandEvent& /* event */ )
43d811ea 1055{
c50f1fb9 1056 m_ctrlLog->Clear();
810b5e1f
VZ
1057 m_ctrlText->Clear();
1058 m_ctrlFile->Clear();
43d811ea
JS
1059}
1060
30dea054 1061void DnDFrame::OnLeftDown(wxMouseEvent &WXUNUSED(event) )
43d811ea 1062{
8e193f38 1063 if ( !m_strText.IsEmpty() )
c50f1fb9
VZ
1064 {
1065 // start drag operation
c50f1fb9 1066 wxTextDataObject textData(m_strText);
2d68e1b4
RR
1067/*
1068 wxFileDataObject textData;
810b5e1f
VZ
1069 textData.AddFile( "/file1.txt" );
1070 textData.AddFile( "/file2.txt" );
2d68e1b4 1071*/
f6bcfd97
BP
1072 wxDropSource source(textData, this,
1073 wxDROP_ICON(dnd_copy),
1074 wxDROP_ICON(dnd_move),
1075 wxDROP_ICON(dnd_none));
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;
f6bcfd97 1514
572c6194 1515 SetBackgroundColour(*wxWHITE);
8e193f38
VZ
1516}
1517
1518DnDShapeFrame::~DnDShapeFrame()
1519{
f6bcfd97 1520 if (m_shape)
572c6194 1521 delete m_shape;
8e193f38
VZ
1522}
1523
1524void DnDShapeFrame::SetShape(DnDShape *shape)
1525{
f6bcfd97 1526 if (m_shape)
572c6194 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