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