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