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