]> git.saurik.com Git - wxWidgets.git/blame - samples/dnd/dnd.cpp
Change version to 3.0.0.
[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
43d811ea 7// Copyright:
8bbe427f 8// Licence: wxWindows licence
43d811ea
JS
9/////////////////////////////////////////////////////////////////////////////
10
c50f1fb9 11#include "wx/wxprec.h"
457814b5
JS
12
13#ifdef __BORLANDC__
14#pragma hdrstop
15#endif
16
17#ifndef WX_PRECOMP
c50f1fb9 18#include "wx/wx.h"
457814b5
JS
19#endif
20
c50f1fb9 21#include "wx/dnd.h"
c5035065 22#include "wx/dataobj.h"
e2acb9ae
RR
23#include "wx/image.h"
24#include "wx/clipbrd.h"
8e193f38 25#include "wx/colordlg.h"
f2555abd 26#include "wx/metafile.h"
f3955fdf 27#include "wx/dirctrl.h"
5a1c877f 28
e7092398 29#ifndef wxHAS_IMAGES_IN_RESOURCES
62a2a12d 30 #include "../sample.xpm"
c1a48eaf 31#if wxUSE_DRAG_AND_DROP
f6bcfd97
BP
32 #include "dnd_copy.xpm"
33 #include "dnd_move.xpm"
34 #include "dnd_none.xpm"
47908e25 35#endif
c1a48eaf 36#endif
47908e25 37
3265e00f
JS
38#if wxUSE_DRAG_AND_DROP
39
457814b5 40// ----------------------------------------------------------------------------
2845ddc2 41// Derive two simple classes which just put in the listbox the strings (text or
457814b5
JS
42// file names) we drop on them
43// ----------------------------------------------------------------------------
ab8884ac 44
457814b5
JS
45class DnDText : public wxTextDropTarget
46{
47public:
c50f1fb9 48 DnDText(wxListBox *pOwner) { m_pOwner = pOwner; }
457814b5 49
9e2896e5 50 virtual bool OnDropText(wxCoord x, wxCoord y, const wxString& text);
457814b5
JS
51
52private:
c50f1fb9 53 wxListBox *m_pOwner;
457814b5
JS
54};
55
56class DnDFile : public wxFileDropTarget
57{
58public:
f3955fdf 59 DnDFile(wxListBox *pOwner = NULL) { m_pOwner = pOwner; }
457814b5 60
9e2896e5
VZ
61 virtual bool OnDropFiles(wxCoord x, wxCoord y,
62 const wxArrayString& filenames);
457814b5
JS
63
64private:
c50f1fb9 65 wxListBox *m_pOwner;
457814b5
JS
66};
67
444ad3a7
VZ
68// ----------------------------------------------------------------------------
69// Define a custom dtop target accepting URLs
70// ----------------------------------------------------------------------------
71
4693b20c 72class URLDropTarget : public wxDropTarget
444ad3a7
VZ
73{
74public:
75 URLDropTarget() { SetDataObject(new wxURLDataObject); }
76
d1f47235 77 void OnDropURL(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), const wxString& text)
444ad3a7
VZ
78 {
79 // of course, a real program would do something more useful here...
9a83f860 80 wxMessageBox(text, wxT("wxDnD sample: got URL"),
444ad3a7
VZ
81 wxICON_INFORMATION | wxOK);
82 }
83
84 // URLs can't be moved, only copied
85 virtual wxDragResult OnDragOver(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
d1f47235 86 wxDragResult WXUNUSED(def))
e6d318c2
RD
87 {
88 return wxDragLink; // At least IE 5.x needs wxDragLink, the
89 // other browsers on MSW seem okay with it too.
90 }
444ad3a7
VZ
91
92 // translate this to calls to OnDropURL() just for convenience
93 virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def)
94 {
95 if ( !GetData() )
96 return wxDragNone;
97
98 OnDropURL(x, y, ((wxURLDataObject *)m_dataObject)->GetURL());
99
100 return def;
101 }
102};
103
3265e00f
JS
104#endif // wxUSE_DRAG_AND_DROP
105
457814b5
JS
106// ----------------------------------------------------------------------------
107// Define a new application type
108// ----------------------------------------------------------------------------
ab8884ac 109
457814b5 110class DnDApp : public wxApp
8bbe427f 111{
457814b5 112public:
8e193f38 113 virtual bool OnInit();
457814b5
JS
114};
115
714cfcbd 116IMPLEMENT_APP(DnDApp)
457814b5 117
08938fe1 118#if wxUSE_DRAG_AND_DROP || wxUSE_CLIPBOARD
3265e00f 119
ae3dd4a5
VZ
120// ----------------------------------------------------------------------------
121// Define canvas class to show a bitmap
122// ----------------------------------------------------------------------------
123
124class DnDCanvasBitmap : public wxScrolledWindow
125{
126public:
127 DnDCanvasBitmap(wxWindow *parent) : wxScrolledWindow(parent) { }
128
129 void SetBitmap(const wxBitmap& bitmap)
130 {
131 m_bitmap = bitmap;
132
133 SetScrollbars(10, 10,
134 m_bitmap.GetWidth() / 10, m_bitmap.GetHeight() / 10);
135
136 Refresh();
137 }
138
d1f47235 139 void OnPaint(wxPaintEvent& WXUNUSED(event))
ae3dd4a5
VZ
140 {
141 wxPaintDC dc(this);
142
a1b806b9 143 if ( m_bitmap.IsOk() )
ae3dd4a5
VZ
144 {
145 PrepareDC(dc);
146
147 dc.DrawBitmap(m_bitmap, 0, 0);
148 }
149 }
150
151private:
152 wxBitmap m_bitmap;
153
154 DECLARE_EVENT_TABLE()
155};
156
f2555abd 157#if wxUSE_METAFILE
ae3dd4a5
VZ
158
159// and the same thing fo metafiles
160class DnDCanvasMetafile : public wxScrolledWindow
161{
162public:
163 DnDCanvasMetafile(wxWindow *parent) : wxScrolledWindow(parent) { }
164
165 void SetMetafile(const wxMetafile& metafile)
166 {
167 m_metafile = metafile;
168
169 SetScrollbars(10, 10,
170 m_metafile.GetWidth() / 10, m_metafile.GetHeight() / 10);
171
172 Refresh();
173 }
174
f2555abd 175 void OnPaint(wxPaintEvent&)
ae3dd4a5
VZ
176 {
177 wxPaintDC dc(this);
178
a1b806b9 179 if ( m_metafile.IsOk() )
ae3dd4a5
VZ
180 {
181 PrepareDC(dc);
182
183 m_metafile.Play(&dc);
184 }
185 }
186
187private:
188 wxMetafile m_metafile;
189
190 DECLARE_EVENT_TABLE()
191};
192
f2555abd 193#endif // wxUSE_METAFILE
ae3dd4a5 194
457814b5 195// ----------------------------------------------------------------------------
8e193f38 196// Define a new frame type for the main frame
457814b5 197// ----------------------------------------------------------------------------
8e193f38 198
457814b5 199class DnDFrame : public wxFrame
8bbe427f 200{
457814b5 201public:
f3955fdf 202 DnDFrame();
2245b2b2 203 virtual ~DnDFrame();
457814b5 204
c50f1fb9 205 void OnPaint(wxPaintEvent& event);
fcf689db 206 void OnSize(wxSizeEvent& event);
2245b2b2 207 void OnQuit(wxCommandEvent& event);
c50f1fb9 208 void OnAbout(wxCommandEvent& event);
2245b2b2
VZ
209 void OnDrag(wxCommandEvent& event);
210 void OnDragMoveByDefault(wxCommandEvent& event);
211 void OnDragMoveAllow(wxCommandEvent& event);
8e193f38 212 void OnNewFrame(wxCommandEvent& event);
c50f1fb9 213 void OnHelp (wxCommandEvent& event);
b29903d4 214#if wxUSE_LOG
c50f1fb9 215 void OnLogClear(wxCommandEvent& event);
b29903d4 216#endif // wxUSE_LOG
51edda6a 217
c50f1fb9
VZ
218 void OnCopy(wxCommandEvent& event);
219 void OnPaste(wxCommandEvent& event);
51edda6a 220
e2acb9ae
RR
221 void OnCopyBitmap(wxCommandEvent& event);
222 void OnPasteBitmap(wxCommandEvent& event);
43d811ea 223
f2555abd 224#if wxUSE_METAFILE
5a1c877f 225 void OnPasteMetafile(wxCommandEvent& event);
f2555abd 226#endif // wxUSE_METAFILE
5a1c877f 227
51edda6a 228 void OnCopyFiles(wxCommandEvent& event);
62490e9e 229 void OnCopyURL(wxCommandEvent& event);
51edda6a 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 343 {
de914436 344 dc.SetPen(wxPen(m_col));
8e193f38
VZ
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
de914436 397 dc.SetBrush(wxBrush(m_col));
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
de914436 433 dc.SetBrush(wxBrush(m_col));
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
de914436 461 dc.SetBrush(wxBrush(m_col));
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,
62490e9e 819 Menu_CopyURL,
531030e2 820 Menu_UsePrimary,
d59ceba5
VZ
821 Menu_Shape_New = 500,
822 Menu_Shape_Edit,
823 Menu_Shape_Clear,
824 Menu_ShapeClipboard_Copy,
825 Menu_ShapeClipboard_Paste,
8e193f38 826 Button_Colour = 1001
457814b5
JS
827};
828
829BEGIN_EVENT_TABLE(DnDFrame, wxFrame)
e2acb9ae
RR
830 EVT_MENU(Menu_Quit, DnDFrame::OnQuit)
831 EVT_MENU(Menu_About, DnDFrame::OnAbout)
832 EVT_MENU(Menu_Drag, DnDFrame::OnDrag)
2245b2b2
VZ
833 EVT_MENU(Menu_DragMoveDef, DnDFrame::OnDragMoveByDefault)
834 EVT_MENU(Menu_DragMoveAllow,DnDFrame::OnDragMoveAllow)
8e193f38 835 EVT_MENU(Menu_NewFrame, DnDFrame::OnNewFrame)
e2acb9ae 836 EVT_MENU(Menu_Help, DnDFrame::OnHelp)
b29903d4 837#if wxUSE_LOG
e2acb9ae 838 EVT_MENU(Menu_Clear, DnDFrame::OnLogClear)
b29903d4 839#endif // wxUSE_LOG
e2acb9ae
RR
840 EVT_MENU(Menu_Copy, DnDFrame::OnCopy)
841 EVT_MENU(Menu_Paste, DnDFrame::OnPaste)
842 EVT_MENU(Menu_CopyBitmap, DnDFrame::OnCopyBitmap)
843 EVT_MENU(Menu_PasteBitmap,DnDFrame::OnPasteBitmap)
f2555abd 844#if wxUSE_METAFILE
5a1c877f 845 EVT_MENU(Menu_PasteMFile, DnDFrame::OnPasteMetafile)
f2555abd 846#endif // wxUSE_METAFILE
51edda6a 847 EVT_MENU(Menu_CopyFiles, DnDFrame::OnCopyFiles)
62490e9e 848 EVT_MENU(Menu_CopyURL, DnDFrame::OnCopyURL)
531030e2 849 EVT_MENU(Menu_UsePrimary, DnDFrame::OnUsePrimary)
d59ceba5 850
2245b2b2
VZ
851 EVT_UPDATE_UI(Menu_DragMoveDef, DnDFrame::OnUpdateUIMoveByDefault)
852
d59ceba5
VZ
853 EVT_UPDATE_UI(Menu_Paste, DnDFrame::OnUpdateUIPasteText)
854 EVT_UPDATE_UI(Menu_PasteBitmap, DnDFrame::OnUpdateUIPasteBitmap)
e2acb9ae
RR
855
856 EVT_LEFT_DOWN( DnDFrame::OnLeftDown)
857 EVT_RIGHT_DOWN( DnDFrame::OnRightDown)
858 EVT_PAINT( DnDFrame::OnPaint)
fcf689db 859 EVT_SIZE( DnDFrame::OnSize)
457814b5
JS
860END_EVENT_TABLE()
861
08938fe1
MB
862#if wxUSE_DRAG_AND_DROP
863
8e193f38 864BEGIN_EVENT_TABLE(DnDShapeFrame, wxFrame)
d59ceba5
VZ
865 EVT_MENU(Menu_Shape_New, DnDShapeFrame::OnNewShape)
866 EVT_MENU(Menu_Shape_Edit, DnDShapeFrame::OnEditShape)
867 EVT_MENU(Menu_Shape_Clear, DnDShapeFrame::OnClearShape)
868
869 EVT_MENU(Menu_ShapeClipboard_Copy, DnDShapeFrame::OnCopyShape)
870 EVT_MENU(Menu_ShapeClipboard_Paste, DnDShapeFrame::OnPasteShape)
871
872 EVT_UPDATE_UI(Menu_ShapeClipboard_Copy, DnDShapeFrame::OnUpdateUICopy)
873 EVT_UPDATE_UI(Menu_ShapeClipboard_Paste, DnDShapeFrame::OnUpdateUIPaste)
874
875 EVT_LEFT_DOWN(DnDShapeFrame::OnDrag)
876
8e193f38
VZ
877 EVT_PAINT(DnDShapeFrame::OnPaint)
878END_EVENT_TABLE()
879
880BEGIN_EVENT_TABLE(DnDShapeDialog, wxDialog)
b0a6c154 881 EVT_BUTTON(Button_Colour, DnDShapeDialog::OnColour)
8e193f38
VZ
882END_EVENT_TABLE()
883
08938fe1
MB
884#endif // wxUSE_DRAG_AND_DROP
885
ae3dd4a5
VZ
886BEGIN_EVENT_TABLE(DnDCanvasBitmap, wxScrolledWindow)
887 EVT_PAINT(DnDCanvasBitmap::OnPaint)
888END_EVENT_TABLE()
889
f2555abd 890#if wxUSE_METAFILE
ae3dd4a5
VZ
891BEGIN_EVENT_TABLE(DnDCanvasMetafile, wxScrolledWindow)
892 EVT_PAINT(DnDCanvasMetafile::OnPaint)
893END_EVENT_TABLE()
f2555abd 894#endif // wxUSE_METAFILE
3265e00f
JS
895
896#endif // wxUSE_DRAG_AND_DROP
ae3dd4a5 897
8e193f38
VZ
898// ============================================================================
899// implementation
900// ============================================================================
901
902// `Main program' equivalent, creating windows and returning main app frame
8bbe427f 903bool DnDApp::OnInit()
457814b5 904{
45e6e6f8
VZ
905 if ( !wxApp::OnInit() )
906 return false;
907
08938fe1 908#if wxUSE_DRAG_AND_DROP || wxUSE_CLIPBOARD
61b04ac6 909 // switch on trace messages
b29903d4 910#if wxUSE_LOG
61b04ac6 911#if defined(__WXGTK__)
9a83f860 912 wxLog::AddTraceMask(wxT("clipboard"));
61b04ac6
VZ
913#elif defined(__WXMSW__)
914 wxLog::AddTraceMask(wxTRACE_OleCalls);
915#endif
b29903d4 916#endif // wxUSE_LOG
61b04ac6 917
e2acb9ae
RR
918#if wxUSE_LIBPNG
919 wxImage::AddHandler( new wxPNGHandler );
920#endif
921
c50f1fb9 922 // create the main frame window
f3955fdf 923 new DnDFrame();
457814b5 924
9230b621 925 return true;
3265e00f 926#else
9a83f860 927 wxMessageBox( wxT("This sample has to be compiled with wxUSE_DRAG_AND_DROP"), wxT("Building error"), wxOK);
9230b621 928 return false;
3265e00f 929#endif // wxUSE_DRAG_AND_DROP
457814b5
JS
930}
931
08938fe1 932#if wxUSE_DRAG_AND_DROP || wxUSE_CLIPBOARD
3265e00f 933
f3955fdf 934DnDFrame::DnDFrame()
9a83f860 935 : wxFrame(NULL, wxID_ANY, wxT("Drag-and-Drop/Clipboard wxWidgets Sample"),
f3955fdf 936 wxPoint(10, 100)),
9a83f860 937 m_strText(wxT("wxWidgets drag & drop works :-)"))
43d811ea 938
457814b5 939{
c50f1fb9 940 // frame icon and status bar
84ff9d5f 941 SetIcon(wxICON(sample));
c50f1fb9 942
8520f137 943#if wxUSE_STATUSBAR
c50f1fb9 944 CreateStatusBar();
8520f137 945#endif // wxUSE_STATUSBAR
c50f1fb9
VZ
946
947 // construct menu
948 wxMenu *file_menu = new wxMenu;
9a83f860
VZ
949 file_menu->Append(Menu_Drag, wxT("&Test drag..."));
950 file_menu->AppendCheckItem(Menu_DragMoveDef, wxT("&Move by default"));
951 file_menu->AppendCheckItem(Menu_DragMoveAllow, wxT("&Allow moving"));
c50f1fb9 952 file_menu->AppendSeparator();
9a83f860 953 file_menu->Append(Menu_NewFrame, wxT("&New frame\tCtrl-N"));
d1b15f03 954 file_menu->AppendSeparator();
9a83f860 955 file_menu->Append(Menu_Quit, wxT("E&xit\tCtrl-Q"));
c50f1fb9 956
b29903d4 957#if wxUSE_LOG
c50f1fb9 958 wxMenu *log_menu = new wxMenu;
9a83f860 959 log_menu->Append(Menu_Clear, wxT("Clear\tCtrl-L"));
b29903d4 960#endif // wxUSE_LOG
c50f1fb9
VZ
961
962 wxMenu *help_menu = new wxMenu;
9a83f860 963 help_menu->Append(Menu_Help, wxT("&Help..."));
c50f1fb9 964 help_menu->AppendSeparator();
9a83f860 965 help_menu->Append(Menu_About, wxT("&About"));
c50f1fb9
VZ
966
967 wxMenu *clip_menu = new wxMenu;
9a83f860
VZ
968 clip_menu->Append(Menu_Copy, wxT("&Copy text\tCtrl-C"));
969 clip_menu->Append(Menu_Paste, wxT("&Paste text\tCtrl-V"));
e2acb9ae 970 clip_menu->AppendSeparator();
9a83f860
VZ
971 clip_menu->Append(Menu_CopyBitmap, wxT("Copy &bitmap\tCtrl-Shift-C"));
972 clip_menu->Append(Menu_PasteBitmap, wxT("Paste b&itmap\tCtrl-Shift-V"));
f2555abd 973#if wxUSE_METAFILE
51edda6a 974 clip_menu->AppendSeparator();
9a83f860 975 clip_menu->Append(Menu_PasteMFile, wxT("Paste &metafile\tCtrl-M"));
f2555abd 976#endif // wxUSE_METAFILE
5a1c877f 977 clip_menu->AppendSeparator();
9a83f860 978 clip_menu->Append(Menu_CopyFiles, wxT("Copy &files\tCtrl-F"));
62490e9e 979 clip_menu->Append(Menu_CopyURL, wxT("Copy &URL\tCtrl-U"));
531030e2 980 clip_menu->AppendSeparator();
9a83f860 981 clip_menu->AppendCheckItem(Menu_UsePrimary, wxT("Use &primary selection\tCtrl-P"));
8e193f38 982
c50f1fb9 983 wxMenuBar *menu_bar = new wxMenuBar;
9a83f860 984 menu_bar->Append(file_menu, wxT("&File"));
b29903d4 985#if wxUSE_LOG
9a83f860 986 menu_bar->Append(log_menu, wxT("&Log"));
b29903d4 987#endif // wxUSE_LOG
9a83f860
VZ
988 menu_bar->Append(clip_menu, wxT("&Clipboard"));
989 menu_bar->Append(help_menu, wxT("&Help"));
c50f1fb9
VZ
990
991 SetMenuBar(menu_bar);
992
f3955fdf
VZ
993 // create the child controls
994 SetBackgroundColour(*wxWHITE); // labels read better on this background
995
9a83f860 996 wxString strFile(wxT("Drop files here!")), strText(wxT("Drop text on me"));
c50f1fb9 997
9230b621 998 m_ctrlFile = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 1, &strFile,
d59ceba5 999 wxLB_HSCROLL | wxLB_ALWAYS_SB );
9230b621 1000 m_ctrlText = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 1, &strText,
d59ceba5 1001 wxLB_HSCROLL | wxLB_ALWAYS_SB );
f3955fdf 1002 m_ctrlDir = new wxGenericDirCtrl(this);
c50f1fb9 1003
b29903d4 1004#if wxUSE_LOG
f3955fdf
VZ
1005 m_ctrlLog = new wxTextCtrl(this, wxID_ANY, wxEmptyString,
1006 wxDefaultPosition, wxDefaultSize,
d59ceba5
VZ
1007 wxTE_MULTILINE | wxTE_READONLY |
1008 wxSUNKEN_BORDER );
8e193f38 1009
61b04ac6 1010 // redirect log messages to the text window
e2acb9ae
RR
1011 m_pLog = new wxLogTextCtrl(m_ctrlLog);
1012 m_pLogPrev = wxLog::SetActiveTarget(m_pLog);
b29903d4 1013#endif // wxUSE_LOG
e2acb9ae 1014
08938fe1 1015#if wxUSE_DRAG_AND_DROP
444ad3a7 1016 // associate drop targets with the controls
e2acb9ae
RR
1017 m_ctrlFile->SetDropTarget(new DnDFile(m_ctrlFile));
1018 m_ctrlText->SetDropTarget(new DnDText(m_ctrlText));
f3955fdf 1019
ba4ed8f4 1020#if wxUSE_DRAG_AND_DROP
f3955fdf
VZ
1021 m_ctrlDir->Connect
1022 (
1023 wxID_ANY,
ce7fe42e 1024 wxEVT_TREE_BEGIN_DRAG,
f3955fdf
VZ
1025 wxTreeEventHandler(DnDFrame::OnBeginDrag),
1026 NULL,
1027 this
1028 );
ba4ed8f4 1029#endif // wxUSE_DRAG_AND_DROP
f3955fdf 1030
b29903d4 1031#if wxUSE_LOG
444ad3a7 1032 m_ctrlLog->SetDropTarget(new URLDropTarget);
b29903d4 1033#endif // wxUSE_LOG
08938fe1 1034#endif // wxUSE_DRAG_AND_DROP
e2acb9ae 1035
84ff9d5f
VZ
1036 wxBoxSizer *sizer_top = new wxBoxSizer( wxHORIZONTAL );
1037 sizer_top->Add(m_ctrlFile, 1, wxEXPAND );
1038 sizer_top->Add(m_ctrlText, 1, wxEXPAND );
9230b621 1039
f3955fdf
VZ
1040 wxBoxSizer *sizerDirCtrl = new wxBoxSizer(wxVERTICAL);
1041 sizerDirCtrl->Add(new wxStaticText(this, wxID_ANY, "Drag files from here"),
1042 wxSizerFlags().Centre().Border());
1043 sizerDirCtrl->Add(m_ctrlDir, wxSizerFlags(1).Expand());
1044 sizer_top->Add(sizerDirCtrl, 1, wxEXPAND );
1045
1046 // make all columns of reasonable minimal size
1047 for ( unsigned n = 0; n < sizer_top->GetChildren().size(); n++ )
1048 sizer_top->SetItemMinSize(n, 200, 300);
1049
84ff9d5f
VZ
1050 wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
1051 sizer->Add(sizer_top, 1, wxEXPAND );
b29903d4 1052#if wxUSE_LOG
84ff9d5f 1053 sizer->Add(m_ctrlLog, 2, wxEXPAND);
f3955fdf 1054 sizer->SetItemMinSize(m_ctrlLog, 450, 200);
b29903d4 1055#endif // wxUSE_LOG
84ff9d5f 1056 sizer->AddSpacer(50);
9230b621 1057
2245b2b2 1058 // copy data by default but allow moving it as well
9230b621
VS
1059 m_moveByDefault = false;
1060 m_moveAllow = true;
1061 menu_bar->Check(Menu_DragMoveAllow, true);
f3955fdf
VZ
1062
1063 // set the correct size and show the frame
1064 SetSizerAndFit(sizer);
1065 Show();
457814b5
JS
1066}
1067
e2acb9ae 1068void DnDFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
457814b5 1069{
9230b621 1070 Close(true);
457814b5
JS
1071}
1072
fcf689db
VZ
1073void DnDFrame::OnSize(wxSizeEvent& event)
1074{
1075 Refresh();
1076
1077 event.Skip();
1078}
1079
e2acb9ae 1080void DnDFrame::OnPaint(wxPaintEvent& WXUNUSED(event))
b527aac5 1081{
c50f1fb9
VZ
1082 int w = 0;
1083 int h = 0;
1084 GetClientSize( &w, &h );
8bbe427f 1085
c50f1fb9 1086 wxPaintDC dc(this);
82cf15a4 1087 // dc.Clear(); -- this kills wxGTK
9a83f860
VZ
1088 dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL, false, wxT("charter") ) );
1089 dc.DrawText( wxT("Drag text from here!"), 100, h-50 );
e2acb9ae
RR
1090}
1091
2245b2b2
VZ
1092void DnDFrame::OnUpdateUIMoveByDefault(wxUpdateUIEvent& event)
1093{
1094 // only can move by default if moving is allowed at all
1095 event.Enable(m_moveAllow);
1096}
1097
d59ceba5 1098void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent& event)
e2acb9ae 1099{
61b04ac6
VZ
1100#ifdef __WXDEBUG__
1101 // too many trace messages if we don't do it - this function is called
1102 // very often
1103 wxLogNull nolog;
1104#endif
1105
d59ceba5
VZ
1106 event.Enable( wxTheClipboard->IsSupported(wxDF_TEXT) );
1107}
e2acb9ae 1108
d59ceba5
VZ
1109void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent& event)
1110{
61b04ac6
VZ
1111#ifdef __WXDEBUG__
1112 // too many trace messages if we don't do it - this function is called
1113 // very often
1114 wxLogNull nolog;
1115#endif
1116
d59ceba5 1117 event.Enable( wxTheClipboard->IsSupported(wxDF_BITMAP) );
e2acb9ae
RR
1118}
1119
8e193f38
VZ
1120void DnDFrame::OnNewFrame(wxCommandEvent& WXUNUSED(event))
1121{
08938fe1 1122#if wxUSE_DRAG_AND_DROP
9230b621 1123 (new DnDShapeFrame(this))->Show(true);
8e193f38 1124
4693b20c 1125 wxLogStatus(this, wxT("Double click the new frame to select a shape for it"));
08938fe1 1126#endif // wxUSE_DRAG_AND_DROP
8e193f38
VZ
1127}
1128
e2acb9ae 1129void DnDFrame::OnDrag(wxCommandEvent& WXUNUSED(event))
43d811ea 1130{
08938fe1 1131#if wxUSE_DRAG_AND_DROP
c50f1fb9
VZ
1132 wxString strText = wxGetTextFromUser
1133 (
9a83f860
VZ
1134 wxT("After you enter text in this dialog, press any mouse\n")
1135 wxT("button in the bottom (empty) part of the frame and \n")
1136 wxT("drag it anywhere - you will be in fact dragging the\n")
1137 wxT("text object containing this text"),
1138 wxT("Please enter some text"), m_strText, this
c50f1fb9
VZ
1139 );
1140
1141 m_strText = strText;
08938fe1 1142#endif // wxUSE_DRAG_AND_DROP
43d811ea
JS
1143}
1144
2245b2b2
VZ
1145void DnDFrame::OnDragMoveByDefault(wxCommandEvent& event)
1146{
1147 m_moveByDefault = event.IsChecked();
1148}
1149
1150void DnDFrame::OnDragMoveAllow(wxCommandEvent& event)
1151{
1152 m_moveAllow = event.IsChecked();
1153}
1154
e2acb9ae 1155void DnDFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
457814b5 1156{
9a83f860
VZ
1157 wxMessageBox(wxT("Drag-&-Drop Demo\n")
1158 wxT("Please see \"Help|Help...\" for details\n")
1159 wxT("Copyright (c) 1998 Vadim Zeitlin"),
1160 wxT("About wxDnD"),
c50f1fb9
VZ
1161 wxICON_INFORMATION | wxOK,
1162 this);
457814b5
JS
1163}
1164
1165void DnDFrame::OnHelp(wxCommandEvent& /* event */)
1166{
c50f1fb9 1167 wxMessageDialog dialog(this,
9a83f860
VZ
1168 wxT("This small program demonstrates drag & drop support in wxWidgets. The program window\n")
1169 wxT("consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n")
1170 wxT("going on inside. The top part is split into 2 listboxes, the left one accepts files\n")
1171 wxT("and the right one accepts text.\n")
1172 wxT("\n")
1173 wxT("To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n")
1174 wxT("the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n")
1175 wxT("Also, try dragging some files (you can select several at once) from Windows Explorer (or \n")
1176 wxT("File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n")
1177 wxT("work with files) and see what changes.\n")
1178 wxT("\n")
1179 wxT("To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n")
1180 wxT("it to wordpad or any other droptarget accepting text (and of course you can just drag it\n")
1181 wxT("to the right pane). Due to a lot of trace messages, the cursor might take some time to \n")
1182 wxT("change, don't release the mouse button until it does. You can change the string being\n")
d13b34d3 1183 wxT("dragged in \"File|Test drag...\" dialog.\n")
9a83f860
VZ
1184 wxT("\n")
1185 wxT("\n")
1186 wxT("Please send all questions/bug reports/suggestions &c to \n")
1187 wxT("Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>"),
1188 wxT("wxDnD Help"));
c50f1fb9
VZ
1189
1190 dialog.ShowModal();
457814b5
JS
1191}
1192
b29903d4 1193#if wxUSE_LOG
e3e65dac 1194void DnDFrame::OnLogClear(wxCommandEvent& /* event */ )
43d811ea 1195{
c50f1fb9 1196 m_ctrlLog->Clear();
810b5e1f
VZ
1197 m_ctrlText->Clear();
1198 m_ctrlFile->Clear();
43d811ea 1199}
b29903d4 1200#endif // wxUSE_LOG
43d811ea 1201
ba4ed8f4
VZ
1202#if wxUSE_DRAG_AND_DROP
1203
f3955fdf
VZ
1204void DnDFrame::LogDragResult(wxDragResult result)
1205{
1206#if wxUSE_STATUSBAR
1207 const wxChar *pc;
1208 switch ( result )
1209 {
9a83f860
VZ
1210 case wxDragError: pc = wxT("Error!"); break;
1211 case wxDragNone: pc = wxT("Nothing"); break;
1212 case wxDragCopy: pc = wxT("Copied"); break;
1213 case wxDragMove: pc = wxT("Moved"); break;
1214 case wxDragCancel: pc = wxT("Cancelled"); break;
1215 default: pc = wxT("Huh?"); break;
f3955fdf
VZ
1216 }
1217
9a83f860 1218 SetStatusText(wxString(wxT("Drag result: ")) + pc);
f3955fdf
VZ
1219#else
1220 wxUnusedVar(result);
1221#endif // wxUSE_STATUSBAR
1222}
1223
ba4ed8f4
VZ
1224#endif // wxUSE_DRAG_AND_DROP
1225
30dea054 1226void DnDFrame::OnLeftDown(wxMouseEvent &WXUNUSED(event) )
43d811ea 1227{
08938fe1 1228#if wxUSE_DRAG_AND_DROP
1c067fe3 1229 if ( !m_strText.empty() )
c50f1fb9
VZ
1230 {
1231 // start drag operation
c50f1fb9 1232 wxTextDataObject textData(m_strText);
f6bcfd97
BP
1233 wxDropSource source(textData, this,
1234 wxDROP_ICON(dnd_copy),
1235 wxDROP_ICON(dnd_move),
1236 wxDROP_ICON(dnd_none));
8e193f38 1237
2245b2b2
VZ
1238 int flags = 0;
1239 if ( m_moveByDefault )
1240 flags |= wxDrag_DefaultMove;
1241 else if ( m_moveAllow )
1242 flags |= wxDrag_AllowMove;
c50f1fb9 1243
f3955fdf 1244 LogDragResult(source.DoDragDrop(flags));
43d811ea 1245 }
08938fe1 1246#endif // wxUSE_DRAG_AND_DROP
43d811ea
JS
1247}
1248
30dea054
RR
1249void DnDFrame::OnRightDown(wxMouseEvent &event )
1250{
9a83f860 1251 wxMenu menu(wxT("Dnd sample menu"));
8bbe427f 1252
9a83f860 1253 menu.Append(Menu_Drag, wxT("&Test drag..."));
51edda6a 1254 menu.AppendSeparator();
9a83f860 1255 menu.Append(Menu_About, wxT("&About"));
8e193f38 1256
51edda6a 1257 PopupMenu( &menu, event.GetX(), event.GetY() );
30dea054
RR
1258}
1259
457814b5
JS
1260DnDFrame::~DnDFrame()
1261{
b29903d4 1262#if wxUSE_LOG
c50f1fb9
VZ
1263 if ( m_pLog != NULL ) {
1264 if ( wxLog::SetActiveTarget(m_pLogPrev) == m_pLog )
1265 delete m_pLog;
1266 }
b29903d4 1267#endif // wxUSE_LOG
531030e2
VZ
1268}
1269
1270void DnDFrame::OnUsePrimary(wxCommandEvent& event)
1271{
1272 const bool usePrimary = event.IsChecked();
1273 wxTheClipboard->UsePrimarySelection(usePrimary);
1274
9a83f860
VZ
1275 wxLogStatus(wxT("Now using %s selection"), usePrimary ? wxT("primary")
1276 : wxT("clipboard"));
c50f1fb9
VZ
1277}
1278
ba4ed8f4
VZ
1279#if wxUSE_DRAG_AND_DROP
1280
f3955fdf
VZ
1281void DnDFrame::OnBeginDrag(wxTreeEvent& WXUNUSED(event))
1282{
1283 wxFileDataObject data;
1284 data.AddFile(m_ctrlDir->GetPath());
1285
1286 wxDropSource dragSource(this);
1287 dragSource.SetData(data);
1288
1289 LogDragResult(dragSource.DoDragDrop());
1290}
1291
ba4ed8f4
VZ
1292#endif // wxUSE_DRAG_AND_DROP
1293
c50f1fb9 1294// ---------------------------------------------------------------------------
e2acb9ae
RR
1295// bitmap clipboard
1296// ---------------------------------------------------------------------------
1297
1298void DnDFrame::OnCopyBitmap(wxCommandEvent& WXUNUSED(event))
1299{
1bd1d102 1300 // PNG support is not always compiled in under Windows, so use BMP there
3265e00f 1301#if wxUSE_LIBPNG
9a83f860 1302 wxFileDialog dialog(this, wxT("Open a PNG file"), wxEmptyString, wxEmptyString, wxT("PNG files (*.png)|*.png"), 0);
3265e00f 1303#else
9a83f860 1304 wxFileDialog dialog(this, wxT("Open a BMP file"), wxEmptyString, wxEmptyString, wxT("BMP files (*.bmp)|*.bmp"), 0);
1bd1d102 1305#endif
e2acb9ae
RR
1306
1307 if (dialog.ShowModal() != wxID_OK)
8e193f38 1308 {
9a83f860 1309 wxLogMessage( wxT("Aborted file open") );
e2acb9ae
RR
1310 return;
1311 }
8e193f38 1312
1c067fe3 1313 if (dialog.GetPath().empty())
8e193f38 1314 {
9a83f860 1315 wxLogMessage( wxT("Returned empty string.") );
e2acb9ae
RR
1316 return;
1317 }
8e193f38 1318
e2acb9ae
RR
1319 if (!wxFileExists(dialog.GetPath()))
1320 {
9a83f860 1321 wxLogMessage( wxT("File doesn't exist.") );
e2acb9ae
RR
1322 return;
1323 }
8e193f38 1324
e2acb9ae 1325 wxImage image;
8e193f38 1326 image.LoadFile( dialog.GetPath(),
1c9c480e 1327#if wxUSE_LIBPNG
1bd1d102 1328 wxBITMAP_TYPE_PNG
1c9c480e
JS
1329#else
1330 wxBITMAP_TYPE_BMP
1bd1d102
VZ
1331#endif
1332 );
a1b806b9 1333 if (!image.IsOk())
e2acb9ae 1334 {
9a83f860 1335 wxLogError( wxT("Invalid image file...") );
e2acb9ae
RR
1336 return;
1337 }
8e193f38 1338
9a83f860 1339 wxLogStatus( wxT("Decoding image file...") );
e2acb9ae 1340 wxYield();
8e193f38 1341
368d59f0 1342 wxBitmap bitmap( image );
e2acb9ae
RR
1343
1344 if ( !wxTheClipboard->Open() )
1345 {
9a83f860 1346 wxLogError(wxT("Can't open clipboard."));
e2acb9ae
RR
1347
1348 return;
1349 }
1350
9a83f860 1351 wxLogMessage( wxT("Creating wxBitmapDataObject...") );
e2acb9ae 1352 wxYield();
8e193f38 1353
e2acb9ae
RR
1354 if ( !wxTheClipboard->AddData(new wxBitmapDataObject(bitmap)) )
1355 {
9a83f860 1356 wxLogError(wxT("Can't copy image to the clipboard."));
e2acb9ae
RR
1357 }
1358 else
1359 {
9a83f860
VZ
1360 wxLogMessage(wxT("Image has been put on the clipboard.") );
1361 wxLogMessage(wxT("You can paste it now and look at it.") );
e2acb9ae
RR
1362 }
1363
1364 wxTheClipboard->Close();
1365}
1366
1367void DnDFrame::OnPasteBitmap(wxCommandEvent& WXUNUSED(event))
1368{
1369 if ( !wxTheClipboard->Open() )
1370 {
9a83f860 1371 wxLogError(wxT("Can't open clipboard."));
e2acb9ae
RR
1372
1373 return;
1374 }
1375
1376 if ( !wxTheClipboard->IsSupported(wxDF_BITMAP) )
1377 {
9a83f860 1378 wxLogWarning(wxT("No bitmap on clipboard"));
e2acb9ae
RR
1379
1380 wxTheClipboard->Close();
1381 return;
1382 }
1383
1384 wxBitmapDataObject data;
79ec2ce2 1385 if ( !wxTheClipboard->GetData(data) )
e2acb9ae 1386 {
9a83f860 1387 wxLogError(wxT("Can't paste bitmap from the clipboard"));
e2acb9ae
RR
1388 }
1389 else
1390 {
ae3dd4a5
VZ
1391 const wxBitmap& bmp = data.GetBitmap();
1392
9a83f860 1393 wxLogMessage(wxT("Bitmap %dx%d pasted from the clipboard"),
ae3dd4a5
VZ
1394 bmp.GetWidth(), bmp.GetHeight());
1395 ShowBitmap(bmp);
e2acb9ae
RR
1396 }
1397
1398 wxTheClipboard->Close();
1399}
1400
f2555abd 1401#if wxUSE_METAFILE
5a1c877f
VZ
1402
1403void DnDFrame::OnPasteMetafile(wxCommandEvent& WXUNUSED(event))
1404{
1405 if ( !wxTheClipboard->Open() )
1406 {
9a83f860 1407 wxLogError(wxT("Can't open clipboard."));
5a1c877f
VZ
1408
1409 return;
1410 }
1411
1412 if ( !wxTheClipboard->IsSupported(wxDF_METAFILE) )
1413 {
9a83f860 1414 wxLogWarning(wxT("No metafile on clipboard"));
5a1c877f
VZ
1415 }
1416 else
1417 {
1418 wxMetaFileDataObject data;
1419 if ( !wxTheClipboard->GetData(data) )
1420 {
9a83f860 1421 wxLogError(wxT("Can't paste metafile from the clipboard"));
5a1c877f
VZ
1422 }
1423 else
1424 {
ae3dd4a5 1425 const wxMetaFile& mf = data.GetMetafile();
5a1c877f 1426
9a83f860 1427 wxLogMessage(wxT("Metafile %dx%d pasted from the clipboard"),
ae3dd4a5
VZ
1428 mf.GetWidth(), mf.GetHeight());
1429
1430 ShowMetaFile(mf);
5a1c877f
VZ
1431 }
1432 }
1433
1434 wxTheClipboard->Close();
1435}
1436
f2555abd 1437#endif // wxUSE_METAFILE
5a1c877f 1438
51edda6a
VZ
1439// ----------------------------------------------------------------------------
1440// file clipboard
1441// ----------------------------------------------------------------------------
1442
1443void DnDFrame::OnCopyFiles(wxCommandEvent& WXUNUSED(event))
1444{
1445#ifdef __WXMSW__
9a83f860
VZ
1446 wxFileDialog dialog(this, wxT("Select a file to copy"), wxEmptyString, wxEmptyString,
1447 wxT("All files (*.*)|*.*"), 0);
51edda6a 1448
3f2711d5
VZ
1449 wxArrayString filenames;
1450 while ( dialog.ShowModal() == wxID_OK )
51edda6a 1451 {
3f2711d5
VZ
1452 filenames.Add(dialog.GetPath());
1453 }
1454
1455 if ( !filenames.IsEmpty() )
1456 {
1457 wxFileDataObject *dobj = new wxFileDataObject;
1458 size_t count = filenames.GetCount();
1459 for ( size_t n = 0; n < count; n++ )
1460 {
1461 dobj->AddFile(filenames[n]);
1462 }
51edda6a
VZ
1463
1464 wxClipboardLocker locker;
1465 if ( !locker )
1466 {
4693b20c 1467 wxLogError(wxT("Can't open clipboard"));
51edda6a
VZ
1468 }
1469 else
1470 {
1471 if ( !wxTheClipboard->AddData(dobj) )
1472 {
4693b20c 1473 wxLogError(wxT("Can't copy file(s) to the clipboard"));
51edda6a
VZ
1474 }
1475 else
1476 {
4693b20c 1477 wxLogStatus(this, wxT("%d file%s copied to the clipboard"),
1c067fe3 1478 count, count == 1 ? wxEmptyString : wxEmptyString);
51edda6a
VZ
1479 }
1480 }
1481 }
1482 else
1483 {
4693b20c 1484 wxLogStatus(this, wxT("Aborted"));
51edda6a
VZ
1485 }
1486#else // !MSW
4693b20c 1487 wxLogError(wxT("Sorry, not implemented"));
51edda6a
VZ
1488#endif // MSW/!MSW
1489}
1490
62490e9e
VZ
1491void DnDFrame::OnCopyURL(wxCommandEvent& WXUNUSED(event))
1492{
1493 // Just hard code it for now, we could ask the user but the point here is
1494 // to test copying URLs, it doesn't really matter what it is.
1495 const wxString url("http://www.wxwidgets.org/");
1496
1497 wxClipboardLocker locker;
1498 if ( !!locker && wxTheClipboard->AddData(new wxURLDataObject(url)) )
1499 {
1500 wxLogStatus(this, "Copied URL \"%s\" to %s.",
1501 url,
1502 GetMenuBar()->IsChecked(Menu_UsePrimary)
1503 ? "primary selection"
1504 : "clipboard");
1505 }
1506 else
1507 {
1508 wxLogError("Failed to copy URL.");
1509 }
1510}
1511
e2acb9ae
RR
1512// ---------------------------------------------------------------------------
1513// text clipboard
c50f1fb9
VZ
1514// ---------------------------------------------------------------------------
1515
1516void DnDFrame::OnCopy(wxCommandEvent& WXUNUSED(event))
1517{
1518 if ( !wxTheClipboard->Open() )
1519 {
9a83f860 1520 wxLogError(wxT("Can't open clipboard."));
c50f1fb9
VZ
1521
1522 return;
1523 }
1524
1525 if ( !wxTheClipboard->AddData(new wxTextDataObject(m_strText)) )
1526 {
9a83f860 1527 wxLogError(wxT("Can't copy data to the clipboard"));
c50f1fb9
VZ
1528 }
1529 else
1530 {
9a83f860 1531 wxLogMessage(wxT("Text '%s' put on the clipboard"), m_strText.c_str());
c50f1fb9
VZ
1532 }
1533
1534 wxTheClipboard->Close();
1535}
1536
1537void DnDFrame::OnPaste(wxCommandEvent& WXUNUSED(event))
1538{
1539 if ( !wxTheClipboard->Open() )
1540 {
9a83f860 1541 wxLogError(wxT("Can't open clipboard."));
c50f1fb9
VZ
1542
1543 return;
1544 }
1545
1546 if ( !wxTheClipboard->IsSupported(wxDF_TEXT) )
1547 {
9a83f860 1548 wxLogWarning(wxT("No text data on clipboard"));
c50f1fb9 1549
e2acb9ae 1550 wxTheClipboard->Close();
c50f1fb9
VZ
1551 return;
1552 }
1553
1554 wxTextDataObject text;
79ec2ce2 1555 if ( !wxTheClipboard->GetData(text) )
c50f1fb9 1556 {
9a83f860 1557 wxLogError(wxT("Can't paste data from the clipboard"));
c50f1fb9
VZ
1558 }
1559 else
1560 {
9a83f860 1561 wxLogMessage(wxT("Text '%s' pasted from the clipboard"),
c50f1fb9
VZ
1562 text.GetText().c_str());
1563 }
1564
1565 wxTheClipboard->Close();
457814b5
JS
1566}
1567
08938fe1
MB
1568#if wxUSE_DRAG_AND_DROP
1569
457814b5
JS
1570// ----------------------------------------------------------------------------
1571// Notifications called by the base class
1572// ----------------------------------------------------------------------------
e2acb9ae 1573
9e2896e5 1574bool DnDText::OnDropText(wxCoord, wxCoord, const wxString& text)
457814b5 1575{
9e2896e5 1576 m_pOwner->Append(text);
457814b5 1577
9230b621 1578 return true;
457814b5
JS
1579}
1580
9e2896e5 1581bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& filenames)
457814b5 1582{
9e2896e5 1583 size_t nFiles = filenames.GetCount();
c50f1fb9 1584 wxString str;
9a83f860 1585 str.Printf( wxT("%d files dropped"), (int)nFiles);
f3955fdf
VZ
1586
1587 if (m_pOwner != NULL)
1588 {
1589 m_pOwner->Append(str);
1590 for ( size_t n = 0; n < nFiles; n++ )
1591 m_pOwner->Append(filenames[n]);
c50f1fb9
VZ
1592 }
1593
9230b621 1594 return true;
457814b5 1595}
8e193f38
VZ
1596
1597// ----------------------------------------------------------------------------
1598// DnDShapeDialog
1599// ----------------------------------------------------------------------------
1600
1601DnDShapeDialog::DnDShapeDialog(wxFrame *parent, DnDShape *shape)
4693b20c
MB
1602 :wxDialog( parent, 6001, wxT("Choose Shape"), wxPoint( 10, 10 ),
1603 wxSize( 40, 40 ),
1c067fe3 1604 wxDEFAULT_DIALOG_STYLE | wxRAISED_BORDER | wxRESIZE_BORDER )
8e193f38
VZ
1605{
1606 m_shape = shape;
4693b20c
MB
1607 wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL );
1608
1609 // radio box
1610 wxBoxSizer* shapesSizer = new wxBoxSizer( wxHORIZONTAL );
1611 const wxString choices[] = { wxT("None"), wxT("Triangle"),
1612 wxT("Rectangle"), wxT("Ellipse") };
1613
9230b621 1614 m_radio = new wxRadioBox( this, wxID_ANY, wxT("&Shape"),
4693b20c
MB
1615 wxDefaultPosition, wxDefaultSize, 4, choices, 4,
1616 wxRA_SPECIFY_COLS );
1617 shapesSizer->Add( m_radio, 0, wxGROW|wxALL, 5 );
1618 topSizer->Add( shapesSizer, 0, wxALL, 2 );
1619
1620 // attributes
9230b621 1621 wxStaticBox* box = new wxStaticBox( this, wxID_ANY, wxT("&Attributes") );
4693b20c 1622 wxStaticBoxSizer* attrSizer = new wxStaticBoxSizer( box, wxHORIZONTAL );
bb9e19db 1623 wxFlexGridSizer* xywhSizer = new wxFlexGridSizer( 2 );
e6d318c2 1624
4693b20c
MB
1625 wxStaticText* st;
1626
9230b621
VS
1627 st = new wxStaticText( this, wxID_ANY, wxT("Position &X:") );
1628 m_textX = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition,
4693b20c 1629 wxSize( 30, 20 ) );
e6d318c2
RD
1630 xywhSizer->Add( st, 1, wxGROW|wxALL, 2 );
1631 xywhSizer->Add( m_textX, 1, wxGROW|wxALL, 2 );
4693b20c 1632
9230b621
VS
1633 st = new wxStaticText( this, wxID_ANY, wxT("Size &width:") );
1634 m_textW = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition,
4693b20c 1635 wxSize( 30, 20 ) );
e6d318c2
RD
1636 xywhSizer->Add( st, 1, wxGROW|wxALL, 2 );
1637 xywhSizer->Add( m_textW, 1, wxGROW|wxALL, 2 );
4693b20c 1638
9230b621
VS
1639 st = new wxStaticText( this, wxID_ANY, wxT("&Y:") );
1640 m_textY = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition,
4693b20c 1641 wxSize( 30, 20 ) );
e6d318c2
RD
1642 xywhSizer->Add( st, 1, wxALL|wxALIGN_RIGHT, 2 );
1643 xywhSizer->Add( m_textY, 1, wxGROW|wxALL, 2 );
4693b20c 1644
9230b621
VS
1645 st = new wxStaticText( this, wxID_ANY, wxT("&height:") );
1646 m_textH = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition,
4693b20c 1647 wxSize( 30, 20 ) );
e6d318c2
RD
1648 xywhSizer->Add( st, 1, wxALL|wxALIGN_RIGHT, 2 );
1649 xywhSizer->Add( m_textH, 1, wxGROW|wxALL, 2 );
4693b20c
MB
1650
1651 wxButton* col = new wxButton( this, Button_Colour, wxT("&Colour...") );
1652 attrSizer->Add( xywhSizer, 1, wxGROW );
1653 attrSizer->Add( col, 0, wxALL|wxALIGN_CENTRE_VERTICAL, 2 );
1654 topSizer->Add( attrSizer, 0, wxGROW|wxALL, 5 );
1655
1656 // buttons
1657 wxBoxSizer* buttonSizer = new wxBoxSizer( wxHORIZONTAL );
1658 wxButton* bt;
1659 bt = new wxButton( this, wxID_OK, wxT("Ok") );
1660 buttonSizer->Add( bt, 0, wxALL, 2 );
1661 bt = new wxButton( this, wxID_CANCEL, wxT("Cancel") );
1662 buttonSizer->Add( bt, 0, wxALL, 2 );
1663 topSizer->Add( buttonSizer, 0, wxALL|wxALIGN_RIGHT, 2 );
1664
92c01615 1665 SetSizerAndFit( topSizer );
8e193f38
VZ
1666}
1667
1668DnDShape *DnDShapeDialog::GetShape() const
1669{
1670 switch ( m_shapeKind )
1671 {
1672 default:
1673 case DnDShape::None: return NULL;
1674 case DnDShape::Triangle: return new DnDTriangularShape(m_pos, m_size, m_col);
1675 case DnDShape::Rectangle: return new DnDRectangularShape(m_pos, m_size, m_col);
1676 case DnDShape::Ellipse: return new DnDEllipticShape(m_pos, m_size, m_col);
1677 }
1678}
1679
1680bool DnDShapeDialog::TransferDataToWindow()
1681{
a3e7d24d 1682
8e193f38
VZ
1683 if ( m_shape )
1684 {
1685 m_radio->SetSelection(m_shape->GetKind());
1686 m_pos = m_shape->GetPosition();
1687 m_size = m_shape->GetSize();
1688 m_col = m_shape->GetColour();
1689 }
1690 else
1691 {
1692 m_radio->SetSelection(DnDShape::None);
1693 m_pos = wxPoint(1, 1);
1694 m_size = wxSize(100, 100);
1695 }
1696
1697 m_textX->SetValue(wxString() << m_pos.x);
1698 m_textY->SetValue(wxString() << m_pos.y);
1699 m_textW->SetValue(wxString() << m_size.x);
1700 m_textH->SetValue(wxString() << m_size.y);
1701
9230b621 1702 return true;
8e193f38
VZ
1703}
1704
1705bool DnDShapeDialog::TransferDataFromWindow()
1706{
1707 m_shapeKind = (DnDShape::Kind)m_radio->GetSelection();
1708
4693b20c
MB
1709 m_pos.x = wxAtoi(m_textX->GetValue());
1710 m_pos.y = wxAtoi(m_textY->GetValue());
1711 m_size.x = wxAtoi(m_textW->GetValue());
1712 m_size.y = wxAtoi(m_textH->GetValue());
8e193f38
VZ
1713
1714 if ( !m_pos.x || !m_pos.y || !m_size.x || !m_size.y )
1715 {
9a83f860
VZ
1716 wxMessageBox(wxT("All sizes and positions should be non null!"),
1717 wxT("Invalid shape"), wxICON_HAND | wxOK, this);
8e193f38 1718
9230b621 1719 return false;
8e193f38
VZ
1720 }
1721
9230b621 1722 return true;
8e193f38
VZ
1723}
1724
1725void DnDShapeDialog::OnColour(wxCommandEvent& WXUNUSED(event))
1726{
1727 wxColourData data;
9230b621 1728 data.SetChooseFull(true);
8e193f38
VZ
1729 for (int i = 0; i < 16; i++)
1730 {
958d3a7e 1731 wxColour colour((unsigned char)(i*16), (unsigned char)(i*16), (unsigned char)(i*16));
8e193f38
VZ
1732 data.SetCustomColour(i, colour);
1733 }
1734
1735 wxColourDialog dialog(this, &data);
1736 if ( dialog.ShowModal() == wxID_OK )
1737 {
1738 m_col = dialog.GetColourData().GetColour();
1739 }
1740}
1741
1742// ----------------------------------------------------------------------------
1743// DnDShapeFrame
1744// ----------------------------------------------------------------------------
1745
d59ceba5
VZ
1746DnDShapeFrame *DnDShapeFrame::ms_lastDropTarget = NULL;
1747
8e193f38 1748DnDShapeFrame::DnDShapeFrame(wxFrame *parent)
9a83f860 1749 : wxFrame(parent, wxID_ANY, wxT("Shape Frame"))
8e193f38 1750{
8520f137 1751#if wxUSE_STATUSBAR
8e193f38 1752 CreateStatusBar();
8520f137 1753#endif // wxUSE_STATUSBAR
8e193f38 1754
d59ceba5 1755 wxMenu *menuShape = new wxMenu;
9a83f860
VZ
1756 menuShape->Append(Menu_Shape_New, wxT("&New default shape\tCtrl-S"));
1757 menuShape->Append(Menu_Shape_Edit, wxT("&Edit shape\tCtrl-E"));
d59ceba5 1758 menuShape->AppendSeparator();
9a83f860 1759 menuShape->Append(Menu_Shape_Clear, wxT("&Clear shape\tCtrl-L"));
d59ceba5
VZ
1760
1761 wxMenu *menuClipboard = new wxMenu;
9a83f860
VZ
1762 menuClipboard->Append(Menu_ShapeClipboard_Copy, wxT("&Copy\tCtrl-C"));
1763 menuClipboard->Append(Menu_ShapeClipboard_Paste, wxT("&Paste\tCtrl-V"));
d59ceba5
VZ
1764
1765 wxMenuBar *menubar = new wxMenuBar;
9a83f860
VZ
1766 menubar->Append(menuShape, wxT("&Shape"));
1767 menubar->Append(menuClipboard, wxT("&Clipboard"));
d59ceba5
VZ
1768
1769 SetMenuBar(menubar);
1770
8520f137 1771#if wxUSE_STATUSBAR
9a83f860 1772 SetStatusText(wxT("Press Ctrl-S to create a new shape"));
8520f137 1773#endif // wxUSE_STATUSBAR
8e193f38
VZ
1774
1775 SetDropTarget(new DnDShapeDropTarget(this));
1776
1777 m_shape = NULL;
f6bcfd97 1778
572c6194 1779 SetBackgroundColour(*wxWHITE);
8e193f38
VZ
1780}
1781
1782DnDShapeFrame::~DnDShapeFrame()
1783{
f6bcfd97 1784 if (m_shape)
572c6194 1785 delete m_shape;
8e193f38
VZ
1786}
1787
1788void DnDShapeFrame::SetShape(DnDShape *shape)
1789{
f6bcfd97 1790 if (m_shape)
572c6194 1791 delete m_shape;
8e193f38
VZ
1792 m_shape = shape;
1793 Refresh();
1794}
1795
1796// callbacks
1797void DnDShapeFrame::OnDrag(wxMouseEvent& event)
1798{
1799 if ( !m_shape )
1800 {
1801 event.Skip();
1802
1803 return;
1804 }
1805
1806 // start drag operation
1807 DnDShapeDataObject shapeData(m_shape);
2d93e133 1808 wxDropSource source(shapeData, this);
8e193f38 1809
9f84eccd 1810 const wxChar *pc = NULL;
9230b621 1811 switch ( source.DoDragDrop(true) )
8e193f38
VZ
1812 {
1813 default:
1814 case wxDragError:
3103e8a9 1815 wxLogError(wxT("An error occurred during drag and drop operation"));
8e193f38
VZ
1816 break;
1817
1818 case wxDragNone:
8520f137 1819#if wxUSE_STATUSBAR
9a83f860 1820 SetStatusText(wxT("Nothing happened"));
8520f137 1821#endif // wxUSE_STATUSBAR
8e193f38
VZ
1822 break;
1823
1824 case wxDragCopy:
9a83f860 1825 pc = wxT("copied");
8e193f38
VZ
1826 break;
1827
1828 case wxDragMove:
9a83f860 1829 pc = wxT("moved");
d59ceba5
VZ
1830 if ( ms_lastDropTarget != this )
1831 {
1832 // don't delete the shape if we dropped it on ourselves!
1833 SetShape(NULL);
1834 }
8e193f38
VZ
1835 break;
1836
1837 case wxDragCancel:
8520f137 1838#if wxUSE_STATUSBAR
9a83f860 1839 SetStatusText(wxT("Drag and drop operation cancelled"));
8520f137 1840#endif // wxUSE_STATUSBAR
8e193f38
VZ
1841 break;
1842 }
1843
1844 if ( pc )
1845 {
8520f137 1846#if wxUSE_STATUSBAR
9a83f860 1847 SetStatusText(wxString(wxT("Shape successfully ")) + pc);
8520f137 1848#endif // wxUSE_STATUSBAR
8e193f38
VZ
1849 }
1850 //else: status text already set
1851}
1852
90e12284 1853void DnDShapeFrame::OnDrop(wxCoord x, wxCoord y, DnDShape *shape)
9e2896e5
VZ
1854{
1855 ms_lastDropTarget = this;
1856
90e12284 1857 wxPoint pt(x, y);
90e12284 1858
8520f137 1859#if wxUSE_STATUSBAR
9e2896e5 1860 wxString s;
508d586e 1861 s.Printf(wxT("Shape dropped at (%d, %d)"), pt.x, pt.y);
9e2896e5 1862 SetStatusText(s);
8520f137 1863#endif // wxUSE_STATUSBAR
9e2896e5 1864
90e12284 1865 shape->Move(pt);
9e2896e5
VZ
1866 SetShape(shape);
1867}
1868
87728739 1869void DnDShapeFrame::OnEditShape(wxCommandEvent& WXUNUSED(event))
8e193f38
VZ
1870{
1871 DnDShapeDialog dlg(this, m_shape);
1872 if ( dlg.ShowModal() == wxID_OK )
1873 {
1874 SetShape(dlg.GetShape());
1875
8520f137 1876#if wxUSE_STATUSBAR
8e193f38
VZ
1877 if ( m_shape )
1878 {
9a83f860 1879 SetStatusText(wxT("You can now drag the shape to another frame"));
8e193f38 1880 }
8520f137 1881#endif // wxUSE_STATUSBAR
8e193f38
VZ
1882 }
1883}
1884
87728739 1885void DnDShapeFrame::OnNewShape(wxCommandEvent& WXUNUSED(event))
d59ceba5
VZ
1886{
1887 SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED));
1888
8520f137 1889#if wxUSE_STATUSBAR
9a83f860 1890 SetStatusText(wxT("You can now drag the shape to another frame"));
8520f137 1891#endif // wxUSE_STATUSBAR
d59ceba5
VZ
1892}
1893
87728739 1894void DnDShapeFrame::OnClearShape(wxCommandEvent& WXUNUSED(event))
d59ceba5
VZ
1895{
1896 SetShape(NULL);
1897}
1898
87728739 1899void DnDShapeFrame::OnCopyShape(wxCommandEvent& WXUNUSED(event))
d59ceba5
VZ
1900{
1901 if ( m_shape )
ae125753
VZ
1902 {
1903 wxClipboardLocker clipLocker;
1904 if ( !clipLocker )
1905 {
4693b20c 1906 wxLogError(wxT("Can't open the clipboard"));
ae125753
VZ
1907
1908 return;
1909 }
1910
d59ceba5 1911 wxTheClipboard->AddData(new DnDShapeDataObject(m_shape));
ae125753 1912 }
d59ceba5
VZ
1913}
1914
87728739 1915void DnDShapeFrame::OnPasteShape(wxCommandEvent& WXUNUSED(event))
d59ceba5 1916{
ae125753
VZ
1917 wxClipboardLocker clipLocker;
1918 if ( !clipLocker )
1919 {
4693b20c 1920 wxLogError(wxT("Can't open the clipboard"));
ae125753
VZ
1921
1922 return;
1923 }
1924
d59ceba5 1925 DnDShapeDataObject shapeDataObject(NULL);
79ec2ce2 1926 if ( wxTheClipboard->GetData(shapeDataObject) )
d59ceba5
VZ
1927 {
1928 SetShape(shapeDataObject.GetShape());
1929 }
1930 else
1931 {
4693b20c 1932 wxLogStatus(wxT("No shape on the clipboard"));
d59ceba5
VZ
1933 }
1934}
1935
1936void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent& event)
1937{
1938 event.Enable( m_shape != NULL );
1939}
1940
1941void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent& event)
1942{
1943 event.Enable( wxTheClipboard->IsSupported(wxDataFormat(shapeFormatId)) );
1944}
1945
8e193f38
VZ
1946void DnDShapeFrame::OnPaint(wxPaintEvent& event)
1947{
1948 if ( m_shape )
79ec2ce2
VZ
1949 {
1950 wxPaintDC dc(this);
1951
1952 m_shape->Draw(dc);
1953 }
8e193f38 1954 else
79ec2ce2 1955 {
8e193f38 1956 event.Skip();
79ec2ce2 1957 }
8e193f38
VZ
1958}
1959
8e193f38
VZ
1960// ----------------------------------------------------------------------------
1961// DnDShape
1962// ----------------------------------------------------------------------------
1963
1964DnDShape *DnDShape::New(const void *buf)
1965{
1966 const ShapeDump& dump = *(const ShapeDump *)buf;
1967 switch ( dump.k )
1968 {
1969 case Triangle:
1970 return new DnDTriangularShape(wxPoint(dump.x, dump.y),
1971 wxSize(dump.w, dump.h),
1972 wxColour(dump.r, dump.g, dump.b));
1973
1974 case Rectangle:
1975 return new DnDRectangularShape(wxPoint(dump.x, dump.y),
1976 wxSize(dump.w, dump.h),
1977 wxColour(dump.r, dump.g, dump.b));
1978
1979 case Ellipse:
1980 return new DnDEllipticShape(wxPoint(dump.x, dump.y),
1981 wxSize(dump.w, dump.h),
1982 wxColour(dump.r, dump.g, dump.b));
1983
1984 default:
4693b20c 1985 wxFAIL_MSG(wxT("invalid shape!"));
8e193f38
VZ
1986 return NULL;
1987 }
1988}
1989
1990// ----------------------------------------------------------------------------
1991// DnDShapeDataObject
1992// ----------------------------------------------------------------------------
1993
f2555abd 1994#if wxUSE_METAFILE
5a1c877f
VZ
1995
1996void DnDShapeDataObject::CreateMetaFile() const
1997{
ae3dd4a5
VZ
1998 wxPoint pos = m_shape->GetPosition();
1999 wxSize size = m_shape->GetSize();
2000
2001 wxMetaFileDC dcMF(wxEmptyString, pos.x + size.x, pos.y + size.y);
5a1c877f
VZ
2002
2003 m_shape->Draw(dcMF);
2004
2005 wxMetafile *mf = dcMF.Close();
2006
5a1c877f
VZ
2007 DnDShapeDataObject *self = (DnDShapeDataObject *)this; // const_cast
2008 self->m_dobjMetaFile.SetMetafile(*mf);
9230b621 2009 self->m_hasMetaFile = true;
ae3dd4a5
VZ
2010
2011 delete mf;
5a1c877f
VZ
2012}
2013
f2555abd 2014#endif // wxUSE_METAFILE
5a1c877f 2015
8e193f38
VZ
2016void DnDShapeDataObject::CreateBitmap() const
2017{
d59ceba5
VZ
2018 wxPoint pos = m_shape->GetPosition();
2019 wxSize size = m_shape->GetSize();
2020 int x = pos.x + size.x,
2021 y = pos.y + size.y;
2022 wxBitmap bitmap(x, y);
8e193f38
VZ
2023 wxMemoryDC dc;
2024 dc.SelectObject(bitmap);
de914436 2025 dc.SetBrush(*wxWHITE_BRUSH);
d59ceba5 2026 dc.Clear();
8e193f38
VZ
2027 m_shape->Draw(dc);
2028 dc.SelectObject(wxNullBitmap);
2029
2030 DnDShapeDataObject *self = (DnDShapeDataObject *)this; // const_cast
5a1c877f 2031 self->m_dobjBitmap.SetBitmap(bitmap);
9230b621 2032 self->m_hasBitmap = true;
8e193f38
VZ
2033}
2034
08938fe1
MB
2035#endif // wxUSE_DRAG_AND_DROP
2036
ae3dd4a5
VZ
2037// ----------------------------------------------------------------------------
2038// global functions
2039// ----------------------------------------------------------------------------
2040
2041static void ShowBitmap(const wxBitmap& bitmap)
2042{
9a83f860 2043 wxFrame *frame = new wxFrame(NULL, wxID_ANY, wxT("Bitmap view"));
8520f137 2044#if wxUSE_STATUSBAR
ae3dd4a5 2045 frame->CreateStatusBar();
8520f137 2046#endif // wxUSE_STATUSBAR
ae3dd4a5
VZ
2047 DnDCanvasBitmap *canvas = new DnDCanvasBitmap(frame);
2048 canvas->SetBitmap(bitmap);
2049
2050 int w = bitmap.GetWidth(),
2051 h = bitmap.GetHeight();
8520f137 2052#if wxUSE_STATUSBAR
9a83f860 2053 frame->SetStatusText(wxString::Format(wxT("%dx%d"), w, h));
8520f137 2054#endif // wxUSE_STATUSBAR
ae3dd4a5
VZ
2055
2056 frame->SetClientSize(w > 100 ? 100 : w, h > 100 ? 100 : h);
9230b621 2057 frame->Show(true);
ae3dd4a5
VZ
2058}
2059
f2555abd 2060#if wxUSE_METAFILE
ae3dd4a5
VZ
2061
2062static void ShowMetaFile(const wxMetaFile& metafile)
2063{
9a83f860 2064 wxFrame *frame = new wxFrame(NULL, wxID_ANY, wxT("Metafile view"));
ae3dd4a5
VZ
2065 frame->CreateStatusBar();
2066 DnDCanvasMetafile *canvas = new DnDCanvasMetafile(frame);
2067 canvas->SetMetafile(metafile);
2068
2069 wxSize size = metafile.GetSize();
9a83f860 2070 frame->SetStatusText(wxString::Format(wxT("%dx%d"), size.x, size.y));
ae3dd4a5
VZ
2071
2072 frame->SetClientSize(size.x > 100 ? 100 : size.x,
2073 size.y > 100 ? 100 : size.y);
2074 frame->Show();
2075}
2076
f2555abd 2077#endif // wxUSE_METAFILE
3265e00f 2078
08938fe1 2079#endif // wxUSE_DRAG_AND_DROP || wxUSE_CLIPBOARD