]> git.saurik.com Git - wxWidgets.git/blame - samples/dnd/dnd.cpp
another BC++ fix
[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
c50f1fb9
VZ
26#include "wx/intl.h"
27#include "wx/log.h"
457814b5 28
c50f1fb9 29#include "wx/dnd.h"
956dbab1 30#include "wx/dirdlg.h"
e2acb9ae
RR
31#include "wx/filedlg.h"
32#include "wx/image.h"
33#include "wx/clipbrd.h"
8e193f38
VZ
34#include "wx/colordlg.h"
35#include "wx/resource.h"
acbd13a3
JS
36
37#if defined(__WXGTK__) || defined(__WXMOTIF__)
c50f1fb9 38 #include "mondrian.xpm"
47908e25
RR
39#endif
40
457814b5 41// ----------------------------------------------------------------------------
2845ddc2 42// Derive two simple classes which just put in the listbox the strings (text or
457814b5
JS
43// file names) we drop on them
44// ----------------------------------------------------------------------------
ab8884ac 45
457814b5
JS
46class DnDText : public wxTextDropTarget
47{
48public:
c50f1fb9 49 DnDText(wxListBox *pOwner) { m_pOwner = pOwner; }
457814b5 50
9e2896e5 51 virtual bool OnDropText(wxCoord x, wxCoord y, const wxString& text);
457814b5
JS
52
53private:
c50f1fb9 54 wxListBox *m_pOwner;
457814b5
JS
55};
56
57class DnDFile : public wxFileDropTarget
58{
59public:
c50f1fb9 60 DnDFile(wxListBox *pOwner) { m_pOwner = pOwner; }
457814b5 61
9e2896e5
VZ
62 virtual bool OnDropFiles(wxCoord x, wxCoord y,
63 const wxArrayString& filenames);
457814b5
JS
64
65private:
c50f1fb9 66 wxListBox *m_pOwner;
457814b5
JS
67};
68
69// ----------------------------------------------------------------------------
70// Define a new application type
71// ----------------------------------------------------------------------------
ab8884ac 72
457814b5 73class DnDApp : public wxApp
8bbe427f 74{
457814b5 75public:
8e193f38 76 virtual bool OnInit();
457814b5
JS
77};
78
79IMPLEMENT_APP(DnDApp);
80
81// ----------------------------------------------------------------------------
8e193f38 82// Define a new frame type for the main frame
457814b5 83// ----------------------------------------------------------------------------
8e193f38 84
457814b5 85class DnDFrame : public wxFrame
8bbe427f 86{
457814b5 87public:
c50f1fb9
VZ
88 DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h);
89 ~DnDFrame();
457814b5 90
c50f1fb9
VZ
91 void OnPaint(wxPaintEvent& event);
92 void OnQuit (wxCommandEvent& event);
93 void OnAbout(wxCommandEvent& event);
94 void OnDrag (wxCommandEvent& event);
8e193f38 95 void OnNewFrame(wxCommandEvent& event);
c50f1fb9
VZ
96 void OnHelp (wxCommandEvent& event);
97 void OnLogClear(wxCommandEvent& event);
98 void OnCopy(wxCommandEvent& event);
99 void OnPaste(wxCommandEvent& event);
e2acb9ae
RR
100 void OnCopyBitmap(wxCommandEvent& event);
101 void OnPasteBitmap(wxCommandEvent& event);
43d811ea 102
c50f1fb9
VZ
103 void OnLeftDown(wxMouseEvent& event);
104 void OnRightDown(wxMouseEvent& event);
8bbe427f 105
d59ceba5
VZ
106 void OnUpdateUIPasteText(wxUpdateUIEvent& event);
107 void OnUpdateUIPasteBitmap(wxUpdateUIEvent& event);
108
c50f1fb9 109 DECLARE_EVENT_TABLE()
457814b5
JS
110
111private:
e2acb9ae 112 wxListBox *m_ctrlFile,
90e12284 113 *m_ctrlText;
e2acb9ae 114 wxTextCtrl *m_ctrlLog;
457814b5 115
90e12284
VZ
116 wxLog *m_pLog,
117 *m_pLogPrev;
43d811ea 118
e2acb9ae
RR
119 wxString m_strText;
120 wxBitmap m_bitmap;
457814b5
JS
121};
122
8e193f38
VZ
123// ----------------------------------------------------------------------------
124// A shape is an example of application-specific data which may be transported
125// via drag-and-drop or clipboard: in our case, we have different geometric
126// shapes, each one with its own colour and position
127// ----------------------------------------------------------------------------
128
129class DnDShape
130{
131public:
132 enum Kind
133 {
134 None,
135 Triangle,
136 Rectangle,
137 Ellipse
138 };
139
140 DnDShape(const wxPoint& pos,
141 const wxSize& size,
142 const wxColour& col)
143 : m_pos(pos), m_size(size), m_col(col)
144 {
145 }
146
9e2896e5
VZ
147 // this is for debugging - lets us see when exactly an object is freed
148 // (this may be later than you think if it's on the clipboard, for example)
149 virtual ~DnDShape() { }
150
8e193f38 151 // the functions used for drag-and-drop: they dump and restore a shape into
d59ceba5 152 // some bitwise-copiable data (might use streams too...)
8e193f38
VZ
153 // ------------------------------------------------------------------------
154
155 // restore from buffer
156 static DnDShape *New(const void *buf);
157
158 virtual size_t GetDataSize() const
159 {
160 return sizeof(ShapeDump);
161 }
162
163 virtual void GetDataHere(void *buf) const
164 {
165 ShapeDump& dump = *(ShapeDump *)buf;
166 dump.x = m_pos.x;
167 dump.y = m_pos.y;
168 dump.w = m_size.x;
169 dump.h = m_size.y;
170 dump.r = m_col.Red();
171 dump.g = m_col.Green();
172 dump.b = m_col.Blue();
173 dump.k = GetKind();
174 }
175
176 // accessors
177 const wxPoint& GetPosition() const { return m_pos; }
178 const wxColour& GetColour() const { return m_col; }
179 const wxSize& GetSize() const { return m_size; }
180
d59ceba5
VZ
181 void Move(const wxPoint& pos) { m_pos = pos; }
182
8e193f38
VZ
183 // to implement in derived classes
184 virtual Kind GetKind() const = 0;
185
1dd989e1 186 virtual void Draw(wxDC& dc)
8e193f38
VZ
187 {
188 dc.SetPen(wxPen(m_col, 1, wxSOLID));
189 }
190
191protected:
192 wxPoint GetCentre() const
193 { return wxPoint(m_pos.x + m_size.x / 2, m_pos.y + m_size.y / 2); }
194
195 struct ShapeDump
196 {
197 int x, y, // position
198 w, h, // size
199 r, g, b, // colour
200 k; // kind
201 };
202
203 wxPoint m_pos;
204 wxSize m_size;
205 wxColour m_col;
206};
207
208class DnDTriangularShape : public DnDShape
209{
210public:
211 DnDTriangularShape(const wxPoint& pos,
212 const wxSize& size,
213 const wxColour& col)
214 : DnDShape(pos, size, col)
215 {
90e12284 216 wxLogMessage("DnDTriangularShape is being created");
8e193f38
VZ
217 }
218
9e2896e5
VZ
219 virtual ~DnDTriangularShape()
220 {
221 wxLogMessage("DnDTriangularShape is being deleted");
222 }
223
8e193f38
VZ
224 virtual Kind GetKind() const { return Triangle; }
225 virtual void Draw(wxDC& dc)
226 {
227 DnDShape::Draw(dc);
228
229 // well, it's a bit difficult to describe a triangle by position and
230 // size, but we're not doing geometry here, do we? ;-)
231 wxPoint p1(m_pos);
232 wxPoint p2(m_pos.x + m_size.x, m_pos.y);
233 wxPoint p3(m_pos.x, m_pos.y + m_size.y);
234
235 dc.DrawLine(p1, p2);
236 dc.DrawLine(p2, p3);
237 dc.DrawLine(p3, p1);
238
1dd989e1 239#ifdef __WXMSW__
8e193f38 240 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
1dd989e1 241#endif
8e193f38
VZ
242 }
243};
244
245class DnDRectangularShape : public DnDShape
246{
247public:
248 DnDRectangularShape(const wxPoint& pos,
249 const wxSize& size,
250 const wxColour& col)
251 : DnDShape(pos, size, col)
252 {
90e12284 253 wxLogMessage("DnDRectangularShape is being created");
8e193f38
VZ
254 }
255
9e2896e5
VZ
256 virtual ~DnDRectangularShape()
257 {
258 wxLogMessage("DnDRectangularShape is being deleted");
259 }
260
8e193f38
VZ
261 virtual Kind GetKind() const { return Rectangle; }
262 virtual void Draw(wxDC& dc)
263 {
264 DnDShape::Draw(dc);
265
266 wxPoint p1(m_pos);
267 wxPoint p2(p1.x + m_size.x, p1.y);
268 wxPoint p3(p2.x, p2.y + m_size.y);
269 wxPoint p4(p1.x, p3.y);
270
271 dc.DrawLine(p1, p2);
272 dc.DrawLine(p2, p3);
273 dc.DrawLine(p3, p4);
274 dc.DrawLine(p4, p1);
275
1dd989e1 276#ifdef __WXMSW__
8e193f38 277 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
1dd989e1 278#endif
8e193f38
VZ
279 }
280};
281
282class DnDEllipticShape : public DnDShape
283{
284public:
285 DnDEllipticShape(const wxPoint& pos,
286 const wxSize& size,
287 const wxColour& col)
288 : DnDShape(pos, size, col)
289 {
90e12284 290 wxLogMessage("DnDEllipticShape is being created");
8e193f38
VZ
291 }
292
9e2896e5
VZ
293 virtual ~DnDEllipticShape()
294 {
295 wxLogMessage("DnDEllipticShape is being deleted");
296 }
297
8e193f38
VZ
298 virtual Kind GetKind() const { return Ellipse; }
299 virtual void Draw(wxDC& dc)
300 {
301 DnDShape::Draw(dc);
302
303 dc.DrawEllipse(m_pos, m_size);
304
1dd989e1 305#ifdef __WXMSW__
8e193f38 306 dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER);
1dd989e1 307#endif
8e193f38
VZ
308 }
309};
310
311// ----------------------------------------------------------------------------
312// A wxDataObject specialisation for the application-specific data
313// ----------------------------------------------------------------------------
314
315static const char *shapeFormatId = "wxShape";
316
317class DnDShapeDataObject : public wxDataObject
318{
319public:
320 // ctor doesn't copy the pointer, so it shouldn't go away while this object
321 // is alive
9e2896e5 322 DnDShapeDataObject(DnDShape *shape = (DnDShape *)NULL)
8e193f38 323 {
9e2896e5
VZ
324 if ( shape )
325 {
326 // we need to copy the shape because the one we're handled may be
327 // deleted while it's still on the clipboard (for example) - and we
328 // reuse the serialisation methods here to copy it
329 void *buf = malloc(shape->DnDShape::GetDataSize());
330 shape->GetDataHere(buf);
331 m_shape = DnDShape::New(buf);
332
333 free(buf);
334 }
335 else
336 {
337 // nothing to copy
338 m_shape = NULL;
339 }
8e193f38
VZ
340
341 // this string should uniquely identify our format, but is otherwise
342 // arbitrary
343 m_formatShape.SetId(shapeFormatId);
344
345 // we don't draw the shape to a bitmap until it's really needed (i.e.
346 // we're asked to do so)
347 m_hasBitmap = FALSE;
348 }
349
9e2896e5
VZ
350 virtual ~DnDShapeDataObject() { delete m_shape; }
351
90e12284
VZ
352 // after a call to this function, the shape is owned by the caller and it
353 // is responsible for deleting it!
354 //
355 // NB: a better solution would be to make DnDShapes ref counted and this
356 // is what should probably be done in a real life program, otherwise
357 // the ownership problems become too complicated really fast
358 DnDShape *GetShape()
359 {
360 DnDShape *shape = m_shape;
361
362 m_shape = (DnDShape *)NULL;
363 m_hasBitmap = FALSE;
364
365 return shape;
366 }
d59ceba5 367
8e193f38
VZ
368 // implement base class pure virtuals
369 // ----------------------------------
370
9e2896e5 371 virtual wxDataFormat GetPreferredFormat(Direction WXUNUSED(dir)) const
8e193f38
VZ
372 {
373 return m_formatShape;
374 }
375
9e2896e5 376 virtual size_t GetFormatCount(Direction dir) const
8e193f38 377 {
d59ceba5
VZ
378 // our custom format is supported by both GetData() and SetData()
379 size_t nFormats = 1;
9e2896e5 380 if ( dir == Get )
d59ceba5
VZ
381 {
382 // but the bitmap format(s) are only supported for output
9e2896e5 383 nFormats += m_dataobj.GetFormatCount(dir);
d59ceba5
VZ
384 }
385
386 return nFormats;
8e193f38
VZ
387 }
388
9e2896e5 389 virtual void GetAllFormats(wxDataFormat *formats, Direction dir) const
8e193f38
VZ
390 {
391 formats[0] = m_formatShape;
9e2896e5 392 if ( dir == Get )
d59ceba5 393 {
9e2896e5 394 m_dataobj.GetAllFormats(&formats[1], dir);
d59ceba5 395 }
8e193f38
VZ
396 }
397
398 virtual size_t GetDataSize(const wxDataFormat& format) const
399 {
400 if ( format == m_formatShape )
401 {
402 return m_shape->GetDataSize();
403 }
404 else
405 {
8e193f38
VZ
406 if ( !m_hasBitmap )
407 CreateBitmap();
408
9e2896e5 409 return m_dataobj.GetDataSize();
8e193f38
VZ
410 }
411 }
412
d59ceba5 413 virtual bool GetDataHere(const wxDataFormat& format, void *pBuf) const
8e193f38
VZ
414 {
415 if ( format == m_formatShape )
416 {
417 m_shape->GetDataHere(pBuf);
d59ceba5
VZ
418
419 return TRUE;
8e193f38
VZ
420 }
421 else
422 {
423 wxASSERT_MSG( format == wxDF_BITMAP, "unsupported format" );
424
425 if ( !m_hasBitmap )
426 CreateBitmap();
427
9e2896e5 428 return m_dataobj.GetDataHere(pBuf);
8e193f38
VZ
429 }
430 }
431
9e2896e5
VZ
432 virtual bool SetData(const wxDataFormat& format,
433 size_t len, const void *buf)
d59ceba5
VZ
434 {
435 wxCHECK_MSG( format == m_formatShape, FALSE, "unsupported format" );
436
437 delete m_shape;
438 m_shape = DnDShape::New(buf);
439
440 // the shape has changed
441 m_hasBitmap = FALSE;
442
443 return TRUE;
444 }
445
8e193f38
VZ
446private:
447 // creates a bitmap and assigns it to m_dataobj (also sets m_hasBitmap)
448 void CreateBitmap() const;
449
450 wxDataFormat m_formatShape; // our custom format
451
452 wxBitmapDataObject m_dataobj; // it handles bitmaps
453 bool m_hasBitmap; // true if m_dataobj has valid bitmap
454
455 DnDShape *m_shape; // our data
456};
457
458// ----------------------------------------------------------------------------
459// A dialog to edit shape properties
460// ----------------------------------------------------------------------------
461
462class DnDShapeDialog : public wxDialog
463{
464public:
465 DnDShapeDialog(wxFrame *parent, DnDShape *shape);
466
467 DnDShape *GetShape() const;
468
469 virtual bool TransferDataToWindow();
470 virtual bool TransferDataFromWindow();
471
472 void OnColour(wxCommandEvent& event);
473
474private:
475 // input
476 DnDShape *m_shape;
477
478 // output
479 DnDShape::Kind m_shapeKind;
480 wxPoint m_pos;
481 wxSize m_size;
482 wxColour m_col;
483
484 // controls
485 wxRadioBox *m_radio;
486 wxTextCtrl *m_textX,
487 *m_textY,
488 *m_textW,
489 *m_textH;
490
491 DECLARE_EVENT_TABLE()
492};
493
494// ----------------------------------------------------------------------------
495// A frame for the shapes which can be drag-and-dropped between frames
496// ----------------------------------------------------------------------------
497
498class DnDShapeFrame : public wxFrame
499{
500public:
501 DnDShapeFrame(wxFrame *parent);
502 ~DnDShapeFrame();
503
504 void SetShape(DnDShape *shape);
505
506 // callbacks
d59ceba5
VZ
507 void OnNewShape(wxCommandEvent& event);
508 void OnEditShape(wxCommandEvent& event);
509 void OnClearShape(wxCommandEvent& event);
510
511 void OnCopyShape(wxCommandEvent& event);
512 void OnPasteShape(wxCommandEvent& event);
513
514 void OnUpdateUICopy(wxUpdateUIEvent& event);
515 void OnUpdateUIPaste(wxUpdateUIEvent& event);
516
8e193f38 517 void OnDrag(wxMouseEvent& event);
8e193f38 518 void OnPaint(wxPaintEvent& event);
90e12284 519 void OnDrop(wxCoord x, wxCoord y, DnDShape *shape);
8e193f38
VZ
520
521private:
522 DnDShape *m_shape;
523
d59ceba5
VZ
524 static DnDShapeFrame *ms_lastDropTarget;
525
8e193f38
VZ
526 DECLARE_EVENT_TABLE()
527};
528
529// ----------------------------------------------------------------------------
530// wxDropTarget derivation for DnDShapes
531// ----------------------------------------------------------------------------
532
533class DnDShapeDropTarget : public wxDropTarget
534{
535public:
536 DnDShapeDropTarget(DnDShapeFrame *frame)
9e2896e5 537 : wxDropTarget(new DnDShapeDataObject)
8e193f38
VZ
538 {
539 m_frame = frame;
8e193f38
VZ
540 }
541
542 // override base class (pure) virtuals
543 virtual void OnEnter()
544 { m_frame->SetStatusText("Mouse entered the frame"); }
545 virtual void OnLeave()
546 { m_frame->SetStatusText("Mouse left the frame"); }
9e2896e5 547 virtual bool OnData(wxCoord x, wxCoord y)
8e193f38 548 {
9e2896e5
VZ
549 if ( !GetData() )
550 {
551 wxLogError("Failed to get drag and drop data");
552
553 return FALSE;
554 }
555
556 m_frame->OnDrop(x, y,
557 ((DnDShapeDataObject *)GetDataObject())->GetShape());
8e193f38
VZ
558
559 return TRUE;
560 }
561
8e193f38
VZ
562private:
563 DnDShapeFrame *m_frame;
8e193f38
VZ
564};
565
457814b5
JS
566// ----------------------------------------------------------------------------
567// IDs for the menu commands
568// ----------------------------------------------------------------------------
ab8884ac 569
457814b5
JS
570enum
571{
c50f1fb9
VZ
572 Menu_Quit = 1,
573 Menu_Drag,
8e193f38 574 Menu_NewFrame,
c50f1fb9
VZ
575 Menu_About = 101,
576 Menu_Help,
577 Menu_Clear,
578 Menu_Copy,
e2acb9ae
RR
579 Menu_Paste,
580 Menu_CopyBitmap,
581 Menu_PasteBitmap,
d1b15f03 582 Menu_ToBeGreyed, /* for testing */
8e193f38 583 Menu_ToBeDeleted, /* for testing */
d59ceba5
VZ
584 Menu_Shape_New = 500,
585 Menu_Shape_Edit,
586 Menu_Shape_Clear,
587 Menu_ShapeClipboard_Copy,
588 Menu_ShapeClipboard_Paste,
8e193f38 589 Button_Colour = 1001
457814b5
JS
590};
591
592BEGIN_EVENT_TABLE(DnDFrame, wxFrame)
e2acb9ae
RR
593 EVT_MENU(Menu_Quit, DnDFrame::OnQuit)
594 EVT_MENU(Menu_About, DnDFrame::OnAbout)
595 EVT_MENU(Menu_Drag, DnDFrame::OnDrag)
8e193f38 596 EVT_MENU(Menu_NewFrame, DnDFrame::OnNewFrame)
e2acb9ae
RR
597 EVT_MENU(Menu_Help, DnDFrame::OnHelp)
598 EVT_MENU(Menu_Clear, DnDFrame::OnLogClear)
599 EVT_MENU(Menu_Copy, DnDFrame::OnCopy)
600 EVT_MENU(Menu_Paste, DnDFrame::OnPaste)
601 EVT_MENU(Menu_CopyBitmap, DnDFrame::OnCopyBitmap)
602 EVT_MENU(Menu_PasteBitmap,DnDFrame::OnPasteBitmap)
d59ceba5
VZ
603
604 EVT_UPDATE_UI(Menu_Paste, DnDFrame::OnUpdateUIPasteText)
605 EVT_UPDATE_UI(Menu_PasteBitmap, DnDFrame::OnUpdateUIPasteBitmap)
e2acb9ae
RR
606
607 EVT_LEFT_DOWN( DnDFrame::OnLeftDown)
608 EVT_RIGHT_DOWN( DnDFrame::OnRightDown)
609 EVT_PAINT( DnDFrame::OnPaint)
457814b5
JS
610END_EVENT_TABLE()
611
8e193f38 612BEGIN_EVENT_TABLE(DnDShapeFrame, wxFrame)
d59ceba5
VZ
613 EVT_MENU(Menu_Shape_New, DnDShapeFrame::OnNewShape)
614 EVT_MENU(Menu_Shape_Edit, DnDShapeFrame::OnEditShape)
615 EVT_MENU(Menu_Shape_Clear, DnDShapeFrame::OnClearShape)
616
617 EVT_MENU(Menu_ShapeClipboard_Copy, DnDShapeFrame::OnCopyShape)
618 EVT_MENU(Menu_ShapeClipboard_Paste, DnDShapeFrame::OnPasteShape)
619
620 EVT_UPDATE_UI(Menu_ShapeClipboard_Copy, DnDShapeFrame::OnUpdateUICopy)
621 EVT_UPDATE_UI(Menu_ShapeClipboard_Paste, DnDShapeFrame::OnUpdateUIPaste)
622
623 EVT_LEFT_DOWN(DnDShapeFrame::OnDrag)
624
8e193f38
VZ
625 EVT_PAINT(DnDShapeFrame::OnPaint)
626END_EVENT_TABLE()
627
628BEGIN_EVENT_TABLE(DnDShapeDialog, wxDialog)
629 EVT_BUTTON(Button_Colour, OnColour)
630END_EVENT_TABLE()
631
632// ============================================================================
633// implementation
634// ============================================================================
635
636// `Main program' equivalent, creating windows and returning main app frame
8bbe427f 637bool DnDApp::OnInit()
457814b5 638{
ae125753
VZ
639 // load our ressources
640 wxPathList pathList;
641 pathList.Add(".");
642#ifdef __WXMSW__
643 pathList.Add("./Debug");
644 pathList.Add("./Release");
645#endif // wxMSW
646
647 wxString path = pathList.FindValidPath("dnd.wxr");
648 if ( !path )
649 {
650 wxLogError("Can't find the resource file dnd.wxr in the current "
651 "directory, aborting.");
652
653 return FALSE;
654 }
655
656 wxDefaultResourceTable->ParseResourceFile(path);
657
e2acb9ae
RR
658#if wxUSE_LIBPNG
659 wxImage::AddHandler( new wxPNGHandler );
660#endif
661
c50f1fb9
VZ
662 // create the main frame window
663 DnDFrame *frame = new DnDFrame((wxFrame *) NULL,
664 "Drag-and-Drop/Clipboard wxWindows Sample",
665 50, 50, 450, 340);
457814b5 666
c50f1fb9
VZ
667 // activate it
668 frame->Show(TRUE);
457814b5 669
c50f1fb9 670 SetTopWindow(frame);
457814b5 671
c50f1fb9 672 return TRUE;
457814b5
JS
673}
674
675DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
43d811ea
JS
676 : wxFrame(frame, -1, title, wxPoint(x, y), wxSize(w, h)),
677 m_strText("wxWindows drag & drop works :-)")
678
457814b5 679{
c50f1fb9
VZ
680 // frame icon and status bar
681 SetIcon(wxICON(mondrian));
682
683 CreateStatusBar();
684
685 // construct menu
686 wxMenu *file_menu = new wxMenu;
687 file_menu->Append(Menu_Drag, "&Test drag...");
688 file_menu->AppendSeparator();
8e193f38 689 file_menu->Append(Menu_NewFrame, "&New frame\tCtrl-N");
d1b15f03 690 file_menu->AppendSeparator();
8e193f38 691 file_menu->Append(Menu_Quit, "E&xit");
c50f1fb9
VZ
692
693 wxMenu *log_menu = new wxMenu;
d59ceba5 694 log_menu->Append(Menu_Clear, "Clear\tDel");
c50f1fb9
VZ
695
696 wxMenu *help_menu = new wxMenu;
697 help_menu->Append(Menu_Help, "&Help...");
698 help_menu->AppendSeparator();
699 help_menu->Append(Menu_About, "&About");
700
701 wxMenu *clip_menu = new wxMenu;
e2acb9ae
RR
702 clip_menu->Append(Menu_Copy, "&Copy text\tCtrl+C");
703 clip_menu->Append(Menu_Paste, "&Paste text\tCtrl+V");
704 clip_menu->AppendSeparator();
d59ceba5
VZ
705 clip_menu->Append(Menu_CopyBitmap, "&Copy bitmap\tAlt+C");
706 clip_menu->Append(Menu_PasteBitmap, "&Paste bitmap\tAlt+V");
8e193f38 707
c50f1fb9
VZ
708 wxMenuBar *menu_bar = new wxMenuBar;
709 menu_bar->Append(file_menu, "&File");
710 menu_bar->Append(log_menu, "&Log");
711 menu_bar->Append(clip_menu, "&Clipboard");
712 menu_bar->Append(help_menu, "&Help");
713
714 SetMenuBar(menu_bar);
715
716 // make a panel with 3 subwindows
717 wxPoint pos(0, 0);
718 wxSize size(400, 200);
719
720 wxString strFile("Drop files here!"), strText("Drop text on me");
721
d59ceba5
VZ
722 m_ctrlFile = new wxListBox(this, -1, pos, size, 1, &strFile,
723 wxLB_HSCROLL | wxLB_ALWAYS_SB );
724 m_ctrlText = new wxListBox(this, -1, pos, size, 1, &strText,
725 wxLB_HSCROLL | wxLB_ALWAYS_SB );
c50f1fb9
VZ
726
727 m_ctrlLog = new wxTextCtrl(this, -1, "", pos, size,
d59ceba5
VZ
728 wxTE_MULTILINE | wxTE_READONLY |
729 wxSUNKEN_BORDER );
8e193f38 730
1dd989e1 731#ifdef __WXMSW__
8e193f38
VZ
732 // redirect log messages to the text window and switch on OLE messages
733 // logging
734 wxLog::AddTraceMask(wxTRACE_OleCalls);
1dd989e1 735#endif
e2acb9ae
RR
736 m_pLog = new wxLogTextCtrl(m_ctrlLog);
737 m_pLogPrev = wxLog::SetActiveTarget(m_pLog);
738
739 // associate drop targets with 2 text controls
740 m_ctrlFile->SetDropTarget(new DnDFile(m_ctrlFile));
741 m_ctrlText->SetDropTarget(new DnDText(m_ctrlText));
742
743 wxLayoutConstraints *c;
744
745 // Top-left listbox
746 c = new wxLayoutConstraints;
747 c->left.SameAs(this, wxLeft);
748 c->top.SameAs(this, wxTop);
749 c->right.PercentOf(this, wxRight, 50);
750 c->height.PercentOf(this, wxHeight, 30);
751 m_ctrlFile->SetConstraints(c);
752
753 // Top-right listbox
754 c = new wxLayoutConstraints;
755 c->left.SameAs (m_ctrlFile, wxRight);
756 c->top.SameAs (this, wxTop);
757 c->right.SameAs (this, wxRight);
758 c->height.PercentOf(this, wxHeight, 30);
759 m_ctrlText->SetConstraints(c);
760
761 // Lower text control
762 c = new wxLayoutConstraints;
763 c->left.SameAs (this, wxLeft);
764 c->right.SameAs (this, wxRight);
d59ceba5 765 c->height.PercentOf(this, wxHeight, 50);
e2acb9ae
RR
766 c->top.SameAs(m_ctrlText, wxBottom);
767 m_ctrlLog->SetConstraints(c);
768
769 SetAutoLayout(TRUE);
457814b5
JS
770}
771
e2acb9ae 772void DnDFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
457814b5 773{
c50f1fb9 774 Close(TRUE);
457814b5
JS
775}
776
e2acb9ae 777void DnDFrame::OnPaint(wxPaintEvent& WXUNUSED(event))
b527aac5 778{
c50f1fb9
VZ
779 int w = 0;
780 int h = 0;
781 GetClientSize( &w, &h );
8bbe427f 782
c50f1fb9
VZ
783 wxPaintDC dc(this);
784 dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL, FALSE, "charter" ) );
e2acb9ae 785 dc.DrawText( "Drag text from here!", 20, h-50 );
8e193f38 786
d59ceba5 787 if ( m_bitmap.Ok() )
e2acb9ae 788 {
d59ceba5
VZ
789 // 4/5 is 80% taken by other windows, 20 is arbitrary margin
790 dc.DrawBitmap(m_bitmap,
791 w - m_bitmap.GetWidth() - 20,
792 (4*h)/5 + 20);
e2acb9ae 793 }
e2acb9ae
RR
794}
795
d59ceba5 796void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent& event)
e2acb9ae 797{
d59ceba5
VZ
798 event.Enable( wxTheClipboard->IsSupported(wxDF_TEXT) );
799}
e2acb9ae 800
d59ceba5
VZ
801void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent& event)
802{
803 event.Enable( wxTheClipboard->IsSupported(wxDF_BITMAP) );
e2acb9ae
RR
804}
805
8e193f38
VZ
806void DnDFrame::OnNewFrame(wxCommandEvent& WXUNUSED(event))
807{
808 (new DnDShapeFrame(this))->Show(TRUE);
809
810 wxLogStatus(this, "Double click the new frame to select a shape for it");
811}
812
e2acb9ae 813void DnDFrame::OnDrag(wxCommandEvent& WXUNUSED(event))
43d811ea 814{
c50f1fb9
VZ
815 wxString strText = wxGetTextFromUser
816 (
817 "After you enter text in this dialog, press any mouse\n"
818 "button in the bottom (empty) part of the frame and \n"
819 "drag it anywhere - you will be in fact dragging the\n"
820 "text object containing this text",
821 "Please enter some text", m_strText, this
822 );
823
824 m_strText = strText;
43d811ea
JS
825}
826
e2acb9ae 827void DnDFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
457814b5 828{
c50f1fb9
VZ
829 wxMessageBox("Drag-&-Drop Demo\n"
830 "Please see \"Help|Help...\" for details\n"
831 "Copyright (c) 1998 Vadim Zeitlin",
832 "About wxDnD",
833 wxICON_INFORMATION | wxOK,
834 this);
457814b5
JS
835}
836
837void DnDFrame::OnHelp(wxCommandEvent& /* event */)
838{
c50f1fb9
VZ
839 wxMessageDialog dialog(this,
840 "This small program demonstrates drag & drop support in wxWindows. The program window\n"
841 "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
842 "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
843 "and the right one accepts text.\n"
844 "\n"
845 "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
846 "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
847 "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
848 "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
849 "work with files) and see what changes.\n"
850 "\n"
851 "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
852 "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
853 "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
854 "change, don't release the mouse button until it does. You can change the string being\n"
855 "dragged in in \"File|Test drag...\" dialog.\n"
856 "\n"
857 "\n"
858 "Please send all questions/bug reports/suggestions &c to \n"
859 "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
860 "wxDnD Help");
861
862 dialog.ShowModal();
457814b5
JS
863}
864
e3e65dac 865void DnDFrame::OnLogClear(wxCommandEvent& /* event */ )
43d811ea 866{
c50f1fb9 867 m_ctrlLog->Clear();
43d811ea
JS
868}
869
30dea054 870void DnDFrame::OnLeftDown(wxMouseEvent &WXUNUSED(event) )
43d811ea 871{
8e193f38 872 if ( !m_strText.IsEmpty() )
c50f1fb9
VZ
873 {
874 // start drag operation
c50f1fb9 875 wxTextDataObject textData(m_strText);
8e193f38
VZ
876 wxDropSource source(textData, this, wxICON(mondrian));
877
c50f1fb9
VZ
878 const char *pc;
879
8e193f38 880 switch ( source.DoDragDrop(TRUE) )
c50f1fb9
VZ
881 {
882 case wxDragError: pc = "Error!"; break;
883 case wxDragNone: pc = "Nothing"; break;
884 case wxDragCopy: pc = "Copied"; break;
885 case wxDragMove: pc = "Moved"; break;
886 case wxDragCancel: pc = "Cancelled"; break;
887 default: pc = "Huh?"; break;
888 }
889
890 SetStatusText(wxString("Drag result: ") + pc);
43d811ea 891 }
43d811ea
JS
892}
893
30dea054
RR
894void DnDFrame::OnRightDown(wxMouseEvent &event )
895{
c50f1fb9 896 wxMenu *menu = new wxMenu;
8bbe427f 897
c50f1fb9
VZ
898 menu->Append(Menu_Drag, "&Test drag...");
899 menu->Append(Menu_About, "&About");
900 menu->Append(Menu_Quit, "E&xit");
d1b15f03
RR
901 menu->Append(Menu_ToBeDeleted, "To be deleted");
902 menu->Append(Menu_ToBeGreyed, "To be greyed");
8e193f38 903
d1b15f03
RR
904 menu->Delete( Menu_ToBeDeleted );
905 menu->Enable( Menu_ToBeGreyed, FALSE );
8bbe427f 906
c50f1fb9 907 PopupMenu( menu, event.GetX(), event.GetY() );
30dea054
RR
908}
909
457814b5
JS
910DnDFrame::~DnDFrame()
911{
c50f1fb9
VZ
912 if ( m_pLog != NULL ) {
913 if ( wxLog::SetActiveTarget(m_pLogPrev) == m_pLog )
914 delete m_pLog;
915 }
916}
917
918// ---------------------------------------------------------------------------
e2acb9ae
RR
919// bitmap clipboard
920// ---------------------------------------------------------------------------
921
922void DnDFrame::OnCopyBitmap(wxCommandEvent& WXUNUSED(event))
923{
1bd1d102
VZ
924 // PNG support is not always compiled in under Windows, so use BMP there
925#ifdef __WXMSW__
926 wxFileDialog dialog(this, "Open a BMP file", "", "", "BMP files (*.bmp)|*.bmp", 0);
927#else
e2acb9ae 928 wxFileDialog dialog(this, "Open a PNG file", "", "", "PNG files (*.png)|*.png", 0);
1bd1d102 929#endif
e2acb9ae
RR
930
931 if (dialog.ShowModal() != wxID_OK)
8e193f38 932 {
e2acb9ae
RR
933 wxLogMessage( _T("Aborted file open") );
934 return;
935 }
8e193f38 936
e2acb9ae 937 if (dialog.GetPath().IsEmpty())
8e193f38 938 {
e2acb9ae
RR
939 wxLogMessage( _T("Returned empty string.") );
940 return;
941 }
8e193f38 942
e2acb9ae
RR
943 if (!wxFileExists(dialog.GetPath()))
944 {
945 wxLogMessage( _T("File doesn't exist.") );
946 return;
947 }
8e193f38 948
e2acb9ae 949 wxImage image;
8e193f38 950 image.LoadFile( dialog.GetPath(),
1bd1d102
VZ
951#ifdef __WXMSW__
952 wxBITMAP_TYPE_BMP
953#else
954 wxBITMAP_TYPE_PNG
955#endif
956 );
e2acb9ae
RR
957 if (!image.Ok())
958 {
8e193f38 959 wxLogError( _T("Invalid image file...") );
e2acb9ae
RR
960 return;
961 }
8e193f38
VZ
962
963 wxLogStatus( _T("Decoding image file...") );
e2acb9ae 964 wxYield();
8e193f38 965
e2acb9ae
RR
966 wxBitmap bitmap( image.ConvertToBitmap() );
967
968 if ( !wxTheClipboard->Open() )
969 {
970 wxLogError(_T("Can't open clipboard."));
971
972 return;
973 }
974
975 wxLogMessage( _T("Creating wxBitmapDataObject...") );
976 wxYield();
8e193f38 977
e2acb9ae
RR
978 if ( !wxTheClipboard->AddData(new wxBitmapDataObject(bitmap)) )
979 {
980 wxLogError(_T("Can't copy image to the clipboard."));
981 }
982 else
983 {
984 wxLogMessage(_T("Image has been put on the clipboard.") );
985 wxLogMessage(_T("You can paste it now and look at it.") );
986 }
987
988 wxTheClipboard->Close();
989}
990
991void DnDFrame::OnPasteBitmap(wxCommandEvent& WXUNUSED(event))
992{
993 if ( !wxTheClipboard->Open() )
994 {
995 wxLogError(_T("Can't open clipboard."));
996
997 return;
998 }
999
1000 if ( !wxTheClipboard->IsSupported(wxDF_BITMAP) )
1001 {
1002 wxLogWarning(_T("No bitmap on clipboard"));
1003
1004 wxTheClipboard->Close();
1005 return;
1006 }
1007
1008 wxBitmapDataObject data;
79ec2ce2 1009 if ( !wxTheClipboard->GetData(data) )
e2acb9ae
RR
1010 {
1011 wxLogError(_T("Can't paste bitmap from the clipboard"));
1012 }
1013 else
1014 {
1015 wxLogMessage(_T("Bitmap pasted from the clipboard") );
8e193f38
VZ
1016 m_bitmap = data.GetBitmap();
1017 Refresh();
e2acb9ae
RR
1018 }
1019
1020 wxTheClipboard->Close();
1021}
1022
1023// ---------------------------------------------------------------------------
1024// text clipboard
c50f1fb9
VZ
1025// ---------------------------------------------------------------------------
1026
1027void DnDFrame::OnCopy(wxCommandEvent& WXUNUSED(event))
1028{
1029 if ( !wxTheClipboard->Open() )
1030 {
b56baa2d 1031 wxLogError(_T("Can't open clipboard."));
c50f1fb9
VZ
1032
1033 return;
1034 }
1035
1036 if ( !wxTheClipboard->AddData(new wxTextDataObject(m_strText)) )
1037 {
b56baa2d 1038 wxLogError(_T("Can't copy data to the clipboard"));
c50f1fb9
VZ
1039 }
1040 else
1041 {
b56baa2d 1042 wxLogMessage(_T("Text '%s' put on the clipboard"), m_strText.c_str());
c50f1fb9
VZ
1043 }
1044
1045 wxTheClipboard->Close();
1046}
1047
1048void DnDFrame::OnPaste(wxCommandEvent& WXUNUSED(event))
1049{
1050 if ( !wxTheClipboard->Open() )
1051 {
b56baa2d 1052 wxLogError(_T("Can't open clipboard."));
c50f1fb9
VZ
1053
1054 return;
1055 }
1056
1057 if ( !wxTheClipboard->IsSupported(wxDF_TEXT) )
1058 {
b56baa2d 1059 wxLogWarning(_T("No text data on clipboard"));
c50f1fb9 1060
e2acb9ae 1061 wxTheClipboard->Close();
c50f1fb9
VZ
1062 return;
1063 }
1064
1065 wxTextDataObject text;
79ec2ce2 1066 if ( !wxTheClipboard->GetData(text) )
c50f1fb9 1067 {
b56baa2d 1068 wxLogError(_T("Can't paste data from the clipboard"));
c50f1fb9
VZ
1069 }
1070 else
1071 {
b56baa2d 1072 wxLogMessage(_T("Text '%s' pasted from the clipboard"),
c50f1fb9
VZ
1073 text.GetText().c_str());
1074 }
1075
1076 wxTheClipboard->Close();
457814b5
JS
1077}
1078
1079// ----------------------------------------------------------------------------
1080// Notifications called by the base class
1081// ----------------------------------------------------------------------------
e2acb9ae 1082
9e2896e5 1083bool DnDText::OnDropText(wxCoord, wxCoord, const wxString& text)
457814b5 1084{
9e2896e5 1085 m_pOwner->Append(text);
457814b5 1086
c50f1fb9 1087 return TRUE;
457814b5
JS
1088}
1089
9e2896e5 1090bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& filenames)
457814b5 1091{
9e2896e5 1092 size_t nFiles = filenames.GetCount();
c50f1fb9
VZ
1093 wxString str;
1094 str.Printf( _T("%d files dropped"), nFiles);
1095 m_pOwner->Append(str);
1096 for ( size_t n = 0; n < nFiles; n++ ) {
9e2896e5 1097 m_pOwner->Append(filenames[n]);
c50f1fb9
VZ
1098 }
1099
1100 return TRUE;
457814b5 1101}
8e193f38
VZ
1102
1103// ----------------------------------------------------------------------------
1104// DnDShapeDialog
1105// ----------------------------------------------------------------------------
1106
1107DnDShapeDialog::DnDShapeDialog(wxFrame *parent, DnDShape *shape)
1108{
1109 m_shape = shape;
1110
1111 LoadFromResource(parent, "dialogShape");
1112
1113 m_textX = (wxTextCtrl *)wxFindWindowByName("textX", this);
1114 m_textY = (wxTextCtrl *)wxFindWindowByName("textY", this);
1115 m_textW = (wxTextCtrl *)wxFindWindowByName("textW", this);
1116 m_textH = (wxTextCtrl *)wxFindWindowByName("textH", this);
1117
1118 m_radio = (wxRadioBox *)wxFindWindowByName("radio", this);
1119}
1120
1121DnDShape *DnDShapeDialog::GetShape() const
1122{
1123 switch ( m_shapeKind )
1124 {
1125 default:
1126 case DnDShape::None: return NULL;
1127 case DnDShape::Triangle: return new DnDTriangularShape(m_pos, m_size, m_col);
1128 case DnDShape::Rectangle: return new DnDRectangularShape(m_pos, m_size, m_col);
1129 case DnDShape::Ellipse: return new DnDEllipticShape(m_pos, m_size, m_col);
1130 }
1131}
1132
1133bool DnDShapeDialog::TransferDataToWindow()
1134{
a3e7d24d 1135
8e193f38
VZ
1136 if ( m_shape )
1137 {
1138 m_radio->SetSelection(m_shape->GetKind());
1139 m_pos = m_shape->GetPosition();
1140 m_size = m_shape->GetSize();
1141 m_col = m_shape->GetColour();
1142 }
1143 else
1144 {
1145 m_radio->SetSelection(DnDShape::None);
1146 m_pos = wxPoint(1, 1);
1147 m_size = wxSize(100, 100);
1148 }
1149
1150 m_textX->SetValue(wxString() << m_pos.x);
1151 m_textY->SetValue(wxString() << m_pos.y);
1152 m_textW->SetValue(wxString() << m_size.x);
1153 m_textH->SetValue(wxString() << m_size.y);
1154
1155 return TRUE;
1156}
1157
1158bool DnDShapeDialog::TransferDataFromWindow()
1159{
1160 m_shapeKind = (DnDShape::Kind)m_radio->GetSelection();
1161
1162 m_pos.x = atoi(m_textX->GetValue());
1163 m_pos.y = atoi(m_textY->GetValue());
1164 m_size.x = atoi(m_textW->GetValue());
1165 m_size.y = atoi(m_textH->GetValue());
1166
1167 if ( !m_pos.x || !m_pos.y || !m_size.x || !m_size.y )
1168 {
1169 wxMessageBox("All sizes and positions should be non null!",
1170 "Invalid shape", wxICON_HAND | wxOK, this);
1171
1172 return FALSE;
1173 }
1174
1175 return TRUE;
1176}
1177
1178void DnDShapeDialog::OnColour(wxCommandEvent& WXUNUSED(event))
1179{
1180 wxColourData data;
1181 data.SetChooseFull(TRUE);
1182 for (int i = 0; i < 16; i++)
1183 {
1184 wxColour colour(i*16, i*16, i*16);
1185 data.SetCustomColour(i, colour);
1186 }
1187
1188 wxColourDialog dialog(this, &data);
1189 if ( dialog.ShowModal() == wxID_OK )
1190 {
1191 m_col = dialog.GetColourData().GetColour();
1192 }
1193}
1194
1195// ----------------------------------------------------------------------------
1196// DnDShapeFrame
1197// ----------------------------------------------------------------------------
1198
d59ceba5
VZ
1199DnDShapeFrame *DnDShapeFrame::ms_lastDropTarget = NULL;
1200
8e193f38
VZ
1201DnDShapeFrame::DnDShapeFrame(wxFrame *parent)
1202 : wxFrame(parent, -1, "Shape Frame",
1203 wxDefaultPosition, wxSize(250, 150))
1204{
8e193f38
VZ
1205 CreateStatusBar();
1206
d59ceba5
VZ
1207 wxMenu *menuShape = new wxMenu;
1208 menuShape->Append(Menu_Shape_New, "&New default shape\tCtrl-S");
1209 menuShape->Append(Menu_Shape_Edit, "&Edit shape\tCtrl-E");
1210 menuShape->AppendSeparator();
1211 menuShape->Append(Menu_Shape_Clear, "&Clear shape\tDel");
1212
1213 wxMenu *menuClipboard = new wxMenu;
1214 menuClipboard->Append(Menu_ShapeClipboard_Copy, "&Copy\tCtrl-C");
1215 menuClipboard->Append(Menu_ShapeClipboard_Paste, "&Paste\tCtrl-V");
1216
1217 wxMenuBar *menubar = new wxMenuBar;
1218 menubar->Append(menuShape, "&Shape");
1219 menubar->Append(menuClipboard, "&Clipboard");
1220
1221 SetMenuBar(menubar);
1222
1223 SetStatusText("Press Ctrl-S to create a new shape");
8e193f38
VZ
1224
1225 SetDropTarget(new DnDShapeDropTarget(this));
1226
1227 m_shape = NULL;
572c6194
RR
1228
1229 SetBackgroundColour(*wxWHITE);
8e193f38
VZ
1230}
1231
1232DnDShapeFrame::~DnDShapeFrame()
1233{
572c6194
RR
1234 if (m_shape)
1235 delete m_shape;
8e193f38
VZ
1236}
1237
1238void DnDShapeFrame::SetShape(DnDShape *shape)
1239{
572c6194
RR
1240 if (m_shape)
1241 delete m_shape;
8e193f38
VZ
1242 m_shape = shape;
1243 Refresh();
1244}
1245
1246// callbacks
1247void DnDShapeFrame::OnDrag(wxMouseEvent& event)
1248{
1249 if ( !m_shape )
1250 {
1251 event.Skip();
1252
1253 return;
1254 }
1255
1256 // start drag operation
1257 DnDShapeDataObject shapeData(m_shape);
1258 wxDropSource source(shapeData, this, wxICON(mondrian));
1259
1260 const char *pc = NULL;
1261 switch ( source.DoDragDrop(TRUE) )
1262 {
1263 default:
1264 case wxDragError:
1265 wxLogError("An error occured during drag and drop operation");
1266 break;
1267
1268 case wxDragNone:
1269 SetStatusText("Nothing happened");
1270 break;
1271
1272 case wxDragCopy:
1273 pc = "copied";
1274 break;
1275
1276 case wxDragMove:
1277 pc = "moved";
d59ceba5
VZ
1278 if ( ms_lastDropTarget != this )
1279 {
1280 // don't delete the shape if we dropped it on ourselves!
1281 SetShape(NULL);
1282 }
8e193f38
VZ
1283 break;
1284
1285 case wxDragCancel:
1286 SetStatusText("Drag and drop operation cancelled");
1287 break;
1288 }
1289
1290 if ( pc )
1291 {
1292 SetStatusText(wxString("Shape successfully ") + pc);
1293 }
1294 //else: status text already set
1295}
1296
90e12284 1297void DnDShapeFrame::OnDrop(wxCoord x, wxCoord y, DnDShape *shape)
9e2896e5
VZ
1298{
1299 ms_lastDropTarget = this;
1300
90e12284
VZ
1301 wxPoint pt(x, y);
1302#ifdef __WXMSW__ //temporary hack (FIXME)
1303 pt = ScreenToClient(pt);
1304#endif
1305
9e2896e5 1306 wxString s;
90e12284 1307 s.Printf("Shape dropped at (%ld, %ld)", pt.x, pt.y);
9e2896e5
VZ
1308 SetStatusText(s);
1309
90e12284 1310 shape->Move(pt);
9e2896e5
VZ
1311 SetShape(shape);
1312}
1313
d59ceba5 1314void DnDShapeFrame::OnEditShape(wxCommandEvent& event)
8e193f38
VZ
1315{
1316 DnDShapeDialog dlg(this, m_shape);
1317 if ( dlg.ShowModal() == wxID_OK )
1318 {
1319 SetShape(dlg.GetShape());
1320
1321 if ( m_shape )
1322 {
d59ceba5 1323 SetStatusText("You can now drag the shape to another frame");
8e193f38
VZ
1324 }
1325 }
1326}
1327
d59ceba5
VZ
1328void DnDShapeFrame::OnNewShape(wxCommandEvent& event)
1329{
1330 SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED));
1331
1332 SetStatusText("You can now drag the shape to another frame");
1333}
1334
1335void DnDShapeFrame::OnClearShape(wxCommandEvent& event)
1336{
1337 SetShape(NULL);
1338}
1339
1340void DnDShapeFrame::OnCopyShape(wxCommandEvent& event)
1341{
1342 if ( m_shape )
ae125753
VZ
1343 {
1344 wxClipboardLocker clipLocker;
1345 if ( !clipLocker )
1346 {
1347 wxLogError("Can't open the clipboard");
1348
1349 return;
1350 }
1351
d59ceba5 1352 wxTheClipboard->AddData(new DnDShapeDataObject(m_shape));
ae125753 1353 }
d59ceba5
VZ
1354}
1355
1356void DnDShapeFrame::OnPasteShape(wxCommandEvent& event)
1357{
ae125753
VZ
1358 wxClipboardLocker clipLocker;
1359 if ( !clipLocker )
1360 {
1361 wxLogError("Can't open the clipboard");
1362
1363 return;
1364 }
1365
d59ceba5 1366 DnDShapeDataObject shapeDataObject(NULL);
79ec2ce2 1367 if ( wxTheClipboard->GetData(shapeDataObject) )
d59ceba5
VZ
1368 {
1369 SetShape(shapeDataObject.GetShape());
1370 }
1371 else
1372 {
1373 wxLogStatus("No shape on the clipboard");
1374 }
1375}
1376
1377void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent& event)
1378{
1379 event.Enable( m_shape != NULL );
1380}
1381
1382void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent& event)
1383{
1384 event.Enable( wxTheClipboard->IsSupported(wxDataFormat(shapeFormatId)) );
1385}
1386
8e193f38
VZ
1387void DnDShapeFrame::OnPaint(wxPaintEvent& event)
1388{
1389 if ( m_shape )
79ec2ce2
VZ
1390 {
1391 wxPaintDC dc(this);
1392
1393 m_shape->Draw(dc);
1394 }
8e193f38 1395 else
79ec2ce2 1396 {
8e193f38 1397 event.Skip();
79ec2ce2 1398 }
8e193f38
VZ
1399}
1400
8e193f38
VZ
1401// ----------------------------------------------------------------------------
1402// DnDShape
1403// ----------------------------------------------------------------------------
1404
1405DnDShape *DnDShape::New(const void *buf)
1406{
1407 const ShapeDump& dump = *(const ShapeDump *)buf;
1408 switch ( dump.k )
1409 {
1410 case Triangle:
1411 return new DnDTriangularShape(wxPoint(dump.x, dump.y),
1412 wxSize(dump.w, dump.h),
1413 wxColour(dump.r, dump.g, dump.b));
1414
1415 case Rectangle:
1416 return new DnDRectangularShape(wxPoint(dump.x, dump.y),
1417 wxSize(dump.w, dump.h),
1418 wxColour(dump.r, dump.g, dump.b));
1419
1420 case Ellipse:
1421 return new DnDEllipticShape(wxPoint(dump.x, dump.y),
1422 wxSize(dump.w, dump.h),
1423 wxColour(dump.r, dump.g, dump.b));
1424
1425 default:
1426 wxFAIL_MSG("invalid shape!");
1427 return NULL;
1428 }
1429}
1430
1431// ----------------------------------------------------------------------------
1432// DnDShapeDataObject
1433// ----------------------------------------------------------------------------
1434
1435void DnDShapeDataObject::CreateBitmap() const
1436{
d59ceba5
VZ
1437 wxPoint pos = m_shape->GetPosition();
1438 wxSize size = m_shape->GetSize();
1439 int x = pos.x + size.x,
1440 y = pos.y + size.y;
1441 wxBitmap bitmap(x, y);
8e193f38
VZ
1442 wxMemoryDC dc;
1443 dc.SelectObject(bitmap);
d59ceba5
VZ
1444 dc.SetBrush(wxBrush("white", wxSOLID));
1445 dc.Clear();
8e193f38
VZ
1446 m_shape->Draw(dc);
1447 dc.SelectObject(wxNullBitmap);
1448
1449 DnDShapeDataObject *self = (DnDShapeDataObject *)this; // const_cast
1450 self->m_dataobj.SetBitmap(bitmap);
1451 self->m_hasBitmap = TRUE;
1452}
1453