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