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