home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / samples / dnd / dnd.cpp < prev    next >
C/C++ Source or Header  |  2002-12-16  |  57KB  |  1,969 lines

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