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