home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / samples / dnd / dnd.cpp < prev    next >
C/C++ Source or Header  |  2002-08-02  |  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 2002/08/02 08:16:14 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, char *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("Mouse entered the frame"); return OnDragOver(x, y, def); }
  752.     virtual void OnLeave()
  753.         { m_frame->SetStatusText("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(".");
  881. #ifdef __WXMSW__
  882.     pathList.Add("./Debug");
  883.     pathList.Add("./Release");
  884. #endif // wxMSW
  885.  
  886.     wxString path = pathList.FindValidPath("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.                                    "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, char *title, int x, int y, int w, int h)
  927.         : wxFrame(frame, -1, title, wxPoint(x, y), wxSize(w, h)),
  928.           m_strText("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, "&Test drag...");
  939.     file_menu->AppendCheckItem(Menu_DragMoveDef, "&Move by default");
  940.     file_menu->AppendCheckItem(Menu_DragMoveAllow, "&Allow moving");
  941.     file_menu->AppendSeparator();
  942.     file_menu->Append(Menu_NewFrame, "&New frame\tCtrl-N");
  943.     file_menu->AppendSeparator();
  944.     file_menu->Append(Menu_Quit, "E&xit\tCtrl-Q");
  945.  
  946.     wxMenu *log_menu = new wxMenu;
  947.     log_menu->Append(Menu_Clear, "Clear\tCtrl-L");
  948.  
  949.     wxMenu *help_menu = new wxMenu;
  950.     help_menu->Append(Menu_Help, "&Help...");
  951.     help_menu->AppendSeparator();
  952.     help_menu->Append(Menu_About, "&About");
  953.  
  954.     wxMenu *clip_menu = new wxMenu;
  955.     clip_menu->Append(Menu_Copy, "&Copy text\tCtrl-C");
  956.     clip_menu->Append(Menu_Paste, "&Paste text\tCtrl-V");
  957.     clip_menu->AppendSeparator();
  958.     clip_menu->Append(Menu_CopyBitmap, "Copy &bitmap\tCtrl-Shift-C");
  959.     clip_menu->Append(Menu_PasteBitmap, "Paste b&itmap\tCtrl-Shift-V");
  960. #ifdef USE_METAFILES
  961.     clip_menu->AppendSeparator();
  962.     clip_menu->Append(Menu_PasteMFile, "Paste &metafile\tCtrl-M");
  963. #endif // USE_METAFILES
  964.     clip_menu->AppendSeparator();
  965.     clip_menu->Append(Menu_CopyFiles, "Copy &files\tCtrl-F");
  966.  
  967.     wxMenuBar *menu_bar = new wxMenuBar;
  968.     menu_bar->Append(file_menu, "&File");
  969.     menu_bar->Append(log_menu,  "&Log");
  970.     menu_bar->Append(clip_menu, "&Clipboard");
  971.     menu_bar->Append(help_menu, "&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("Drop files here!"), strText("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, "", 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, "charter" ) );
  1054.     dc.DrawText( "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.          "After you enter text in this dialog, press any mouse\n"
  1097.          "button in the bottom (empty) part of the frame and \n"
  1098.          "drag it anywhere - you will be in fact dragging the\n"
  1099.          "text object containing this text",
  1100.          "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("Drag-&-Drop Demo\n"
  1119.                  "Please see \"Help|Help...\" for details\n"
  1120.                  "Copyright (c) 1998 Vadim Zeitlin",
  1121.                  "About wxDnD",
  1122.                  wxICON_INFORMATION | wxOK,
  1123.                  this);
  1124. }
  1125.  
  1126. void DnDFrame::OnHelp(wxCommandEvent& /* event */)
  1127. {
  1128.     wxMessageDialog dialog(this,
  1129.             "This small program demonstrates drag & drop support in wxWindows. The program window\n"
  1130.             "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
  1131.             "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
  1132.             "and the right one accepts text.\n"
  1133.             "\n"
  1134.             "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
  1135.             "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
  1136.             "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
  1137.             "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
  1138.             "work with files) and see what changes.\n"
  1139.             "\n"
  1140.             "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
  1141.             "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
  1142.             "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
  1143.             "change, don't release the mouse button until it does. You can change the string being\n"
  1144.             "dragged in in \"File|Test drag...\" dialog.\n"
  1145.             "\n"
  1146.             "\n"
  1147.             "Please send all questions/bug reports/suggestions &c to \n"
  1148.             "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
  1149.             "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 char *pc;
  1184.         switch ( source.DoDragDrop(flags) )
  1185.         {
  1186.             case wxDragError:   pc = "Error!";    break;
  1187.             case wxDragNone:    pc = "Nothing";   break;
  1188.             case wxDragCopy:    pc = "Copied";    break;
  1189.             case wxDragMove:    pc = "Moved";     break;
  1190.             case wxDragCancel:  pc = "Cancelled"; break;
  1191.             default:            pc = "Huh?";      break;
  1192.         }
  1193.  
  1194.         SetStatusText(wxString("Drag result: ") + pc);
  1195.     }
  1196. }
  1197.  
  1198. void DnDFrame::OnRightDown(wxMouseEvent &event )
  1199. {
  1200.     wxMenu menu("Dnd sample menu");
  1201.  
  1202.     menu.Append(Menu_Drag, "&Test drag...");
  1203.     menu.AppendSeparator();
  1204.     menu.Append(Menu_About, "&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, "Open a BMP file", "", "", "BMP files (*.bmp)|*.bmp", 0);
  1226. #else
  1227.     wxFileDialog dialog(this, "Open a PNG file", "", "", "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, "Select a file to copy", "", "",
  1370.                          "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, "dialogShape");
  1508.  
  1509.     m_textX = (wxTextCtrl *)wxFindWindowByName("textX", this);
  1510.     m_textY = (wxTextCtrl *)wxFindWindowByName("textY", this);
  1511.     m_textW = (wxTextCtrl *)wxFindWindowByName("textW", this);
  1512.     m_textH = (wxTextCtrl *)wxFindWindowByName("textH", this);
  1513.  
  1514.     m_radio = (wxRadioBox *)wxFindWindowByName("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("All sizes and positions should be non null!",
  1629.                      "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, "Shape Frame",
  1662.                        wxDefaultPosition, wxSize(250, 150))
  1663. {
  1664.     CreateStatusBar();
  1665.  
  1666.     wxMenu *menuShape = new wxMenu;
  1667.     menuShape->Append(Menu_Shape_New, "&New default shape\tCtrl-S");
  1668.     menuShape->Append(Menu_Shape_Edit, "&Edit shape\tCtrl-E");
  1669.     menuShape->AppendSeparator();
  1670.     menuShape->Append(Menu_Shape_Clear, "&Clear shape\tCtrl-L");
  1671.  
  1672.     wxMenu *menuClipboard = new wxMenu;
  1673.     menuClipboard->Append(Menu_ShapeClipboard_Copy, "&Copy\tCtrl-C");
  1674.     menuClipboard->Append(Menu_ShapeClipboard_Paste, "&Paste\tCtrl-V");
  1675.  
  1676.     wxMenuBar *menubar = new wxMenuBar;
  1677.     menubar->Append(menuShape, "&Shape");
  1678.     menubar->Append(menuClipboard, "&Clipboard");
  1679.  
  1680.     SetMenuBar(menubar);
  1681.  
  1682.     SetStatusText("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 char *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("Nothing happened");
  1729.             break;
  1730.  
  1731.         case wxDragCopy:
  1732.             pc = "copied";
  1733.             break;
  1734.  
  1735.         case wxDragMove:
  1736.             pc = "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("Drag and drop operation cancelled");
  1746.             break;
  1747.     }
  1748.  
  1749.     if ( pc )
  1750.     {
  1751.         SetStatusText(wxString("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("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("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.