X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/8e193f384f7b98daef459653ddb8485173fba8ba..b889a3a24bda7d1e9d361d866ada776400b2fb81:/samples/dnd/dnd.cpp diff --git a/samples/dnd/dnd.cpp b/samples/dnd/dnd.cpp index 5bfcff4ecc..164dd9c712 100644 --- a/samples/dnd/dnd.cpp +++ b/samples/dnd/dnd.cpp @@ -23,6 +23,18 @@ #error This sample requires drag and drop support in the library #endif +// under Windows we also support data transfer of metafiles as an extra bonus, +// but they're not available under other platforms +#ifdef __WINDOWS__ + #define USE_METAFILES +#endif // Windows + +#define USE_RESOURCES 0 +#if !wxUSE_RESOURCES +#undef USE_RESOURCES +#define USE_RESOURCES 0 +#endif + #include "wx/intl.h" #include "wx/log.h" @@ -32,10 +44,22 @@ #include "wx/image.h" #include "wx/clipbrd.h" #include "wx/colordlg.h" -#include "wx/resource.h" +#if USE_RESOURCES + #include "wx/resource.h" +#else + #include "wx/sizer.h" +#endif + +#ifdef USE_METAFILES + #include "wx/metafile.h" +#endif // Windows #if defined(__WXGTK__) || defined(__WXMOTIF__) #include "mondrian.xpm" + + #include "dnd_copy.xpm" + #include "dnd_move.xpm" + #include "dnd_none.xpm" #endif // ---------------------------------------------------------------------------- @@ -43,15 +67,12 @@ // file names) we drop on them // ---------------------------------------------------------------------------- -typedef long wxDropPointCoord; - class DnDText : public wxTextDropTarget { public: DnDText(wxListBox *pOwner) { m_pOwner = pOwner; } - virtual bool OnDropText(wxDropPointCoord x, wxDropPointCoord y, - const wxChar* psz); + virtual bool OnDropText(wxCoord x, wxCoord y, const wxString& text); private: wxListBox *m_pOwner; @@ -62,13 +83,46 @@ class DnDFile : public wxFileDropTarget public: DnDFile(wxListBox *pOwner) { m_pOwner = pOwner; } - virtual bool OnDropFiles(wxDropPointCoord x, wxDropPointCoord y, - size_t nFiles, const wxChar* const aszFiles[] ); + virtual bool OnDropFiles(wxCoord x, wxCoord y, + const wxArrayString& filenames); private: wxListBox *m_pOwner; }; +// ---------------------------------------------------------------------------- +// Define a custom dtop target accepting URLs +// ---------------------------------------------------------------------------- + +class URLDropTarget : public wxDropTarget +{ +public: + URLDropTarget() { SetDataObject(new wxURLDataObject); } + + void OnDropURL(wxCoord x, wxCoord y, const wxString& text) + { + // of course, a real program would do something more useful here... + wxMessageBox(text, _T("wxDnD sample: got URL"), + wxICON_INFORMATION | wxOK); + } + + // URLs can't be moved, only copied + virtual wxDragResult OnDragOver(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), + wxDragResult def) + { return def == wxDragMove ? wxDragCopy : def; } + + // translate this to calls to OnDropURL() just for convenience + virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def) + { + if ( !GetData() ) + return wxDragNone; + + OnDropURL(x, y, ((wxURLDataObject *)m_dataObject)->GetURL()); + + return def; + } +}; + // ---------------------------------------------------------------------------- // Define a new application type // ---------------------------------------------------------------------------- @@ -81,6 +135,81 @@ public: IMPLEMENT_APP(DnDApp); +// ---------------------------------------------------------------------------- +// Define canvas class to show a bitmap +// ---------------------------------------------------------------------------- + +class DnDCanvasBitmap : public wxScrolledWindow +{ +public: + DnDCanvasBitmap(wxWindow *parent) : wxScrolledWindow(parent) { } + + void SetBitmap(const wxBitmap& bitmap) + { + m_bitmap = bitmap; + + SetScrollbars(10, 10, + m_bitmap.GetWidth() / 10, m_bitmap.GetHeight() / 10); + + Refresh(); + } + + void OnPaint(wxPaintEvent& event) + { + wxPaintDC dc(this); + + if ( m_bitmap.Ok() ) + { + PrepareDC(dc); + + dc.DrawBitmap(m_bitmap, 0, 0); + } + } + +private: + wxBitmap m_bitmap; + + DECLARE_EVENT_TABLE() +}; + +#ifdef USE_METAFILES + +// and the same thing fo metafiles +class DnDCanvasMetafile : public wxScrolledWindow +{ +public: + DnDCanvasMetafile(wxWindow *parent) : wxScrolledWindow(parent) { } + + void SetMetafile(const wxMetafile& metafile) + { + m_metafile = metafile; + + SetScrollbars(10, 10, + m_metafile.GetWidth() / 10, m_metafile.GetHeight() / 10); + + Refresh(); + } + + void OnPaint(wxPaintEvent& event) + { + wxPaintDC dc(this); + + if ( m_metafile.Ok() ) + { + PrepareDC(dc); + + m_metafile.Play(&dc); + } + } + +private: + wxMetafile m_metafile; + + DECLARE_EVENT_TABLE() +}; + +#endif // USE_METAFILES + // ---------------------------------------------------------------------------- // Define a new frame type for the main frame // ---------------------------------------------------------------------------- @@ -98,27 +227,36 @@ public: void OnNewFrame(wxCommandEvent& event); void OnHelp (wxCommandEvent& event); void OnLogClear(wxCommandEvent& event); + void OnCopy(wxCommandEvent& event); void OnPaste(wxCommandEvent& event); + void OnCopyBitmap(wxCommandEvent& event); void OnPasteBitmap(wxCommandEvent& event); - void OnClipboardHasText(wxCommandEvent& event); - void OnClipboardHasBitmap(wxCommandEvent& event); + +#ifdef USE_METAFILES + void OnPasteMetafile(wxCommandEvent& event); +#endif // USE_METAFILES + + void OnCopyFiles(wxCommandEvent& event); void OnLeftDown(wxMouseEvent& event); void OnRightDown(wxMouseEvent& event); + void OnUpdateUIPasteText(wxUpdateUIEvent& event); + void OnUpdateUIPasteBitmap(wxUpdateUIEvent& event); + DECLARE_EVENT_TABLE() private: wxListBox *m_ctrlFile, - *m_ctrlText; + *m_ctrlText; wxTextCtrl *m_ctrlLog; - wxLog *m_pLog, *m_pLogPrev; + wxLog *m_pLog, + *m_pLogPrev; wxString m_strText; - wxBitmap m_bitmap; }; // ---------------------------------------------------------------------------- @@ -145,12 +283,12 @@ public: { } + // this is for debugging - lets us see when exactly an object is freed + // (this may be later than you think if it's on the clipboard, for example) + virtual ~DnDShape() { } + // the functions used for drag-and-drop: they dump and restore a shape into - // some bitwise-copiable data - // - // NB: here we profit from the fact that wxPoint, wxSize and wxColour are - // POD (plain old data) and so can be copied directly - but it wouldn't - // work for other types! + // some bitwise-copiable data (might use streams too...) // ------------------------------------------------------------------------ // restore from buffer @@ -179,10 +317,12 @@ public: const wxColour& GetColour() const { return m_col; } const wxSize& GetSize() const { return m_size; } + void Move(const wxPoint& pos) { m_pos = pos; } + // to implement in derived classes virtual Kind GetKind() const = 0; - virtual void Draw(wxDC& dc) = 0 + virtual void Draw(wxDC& dc) { dc.SetPen(wxPen(m_col, 1, wxSOLID)); } @@ -212,6 +352,12 @@ public: const wxColour& col) : DnDShape(pos, size, col) { + wxLogMessage(wxT("DnDTriangularShape is being created")); + } + + virtual ~DnDTriangularShape() + { + wxLogMessage(wxT("DnDTriangularShape is being deleted")); } virtual Kind GetKind() const { return Triangle; } @@ -229,7 +375,9 @@ public: dc.DrawLine(p2, p3); dc.DrawLine(p3, p1); +#ifdef __WXMSW__ dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER); +#endif } }; @@ -241,6 +389,12 @@ public: const wxColour& col) : DnDShape(pos, size, col) { + wxLogMessage(wxT("DnDRectangularShape is being created")); + } + + virtual ~DnDRectangularShape() + { + wxLogMessage(wxT("DnDRectangularShape is being deleted")); } virtual Kind GetKind() const { return Rectangle; } @@ -258,7 +412,9 @@ public: dc.DrawLine(p3, p4); dc.DrawLine(p4, p1); +#ifdef __WXMSW__ dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER); +#endif } }; @@ -270,6 +426,12 @@ public: const wxColour& col) : DnDShape(pos, size, col) { + wxLogMessage(wxT("DnDEllipticShape is being created")); + } + + virtual ~DnDEllipticShape() + { + wxLogMessage(wxT("DnDEllipticShape is being deleted")); } virtual Kind GetKind() const { return Ellipse; } @@ -279,7 +441,9 @@ public: dc.DrawEllipse(m_pos, m_size); +#ifdef __WXMSW__ dc.FloodFill(GetCentre(), m_col, wxFLOOD_BORDER); +#endif } }; @@ -287,16 +451,31 @@ public: // A wxDataObject specialisation for the application-specific data // ---------------------------------------------------------------------------- -static const char *shapeFormatId = "wxShape"; +static const wxChar *shapeFormatId = wxT("wxShape"); class DnDShapeDataObject : public wxDataObject { public: // ctor doesn't copy the pointer, so it shouldn't go away while this object // is alive - DnDShapeDataObject(DnDShape *shape) + DnDShapeDataObject(DnDShape *shape = (DnDShape *)NULL) { - m_shape = shape; + if ( shape ) + { + // we need to copy the shape because the one we're handled may be + // deleted while it's still on the clipboard (for example) - and we + // reuse the serialisation methods here to copy it + void *buf = malloc(shape->DnDShape::GetDataSize()); + shape->GetDataHere(buf); + m_shape = DnDShape::New(buf); + + free(buf); + } + else + { + // nothing to copy + m_shape = NULL; + } // this string should uniquely identify our format, but is otherwise // arbitrary @@ -305,26 +484,72 @@ public: // we don't draw the shape to a bitmap until it's really needed (i.e. // we're asked to do so) m_hasBitmap = FALSE; +#ifdef USE_METAFILES + m_hasMetaFile = FALSE; +#endif // Windows + } + + virtual ~DnDShapeDataObject() { delete m_shape; } + + // after a call to this function, the shape is owned by the caller and it + // is responsible for deleting it! + // + // NB: a better solution would be to make DnDShapes ref counted and this + // is what should probably be done in a real life program, otherwise + // the ownership problems become too complicated really fast + DnDShape *GetShape() + { + DnDShape *shape = m_shape; + + m_shape = (DnDShape *)NULL; + m_hasBitmap = FALSE; +#ifdef USE_METAFILES + m_hasMetaFile = FALSE; +#endif // Windows + + return shape; } // implement base class pure virtuals // ---------------------------------- - virtual wxDataFormat GetPreferredFormat() const + virtual wxDataFormat GetPreferredFormat(Direction WXUNUSED(dir)) const { return m_formatShape; } - virtual size_t GetFormatCount() const + virtual size_t GetFormatCount(Direction dir) const { - // +1 for our custom format - return m_dataobj.GetFormatCount() + 1; + // our custom format is supported by both GetData() and SetData() + size_t nFormats = 1; + if ( dir == Get ) + { + // but the bitmap format(s) are only supported for output + nFormats += m_dobjBitmap.GetFormatCount(dir); + +#ifdef USE_METAFILES + nFormats += m_dobjMetaFile.GetFormatCount(dir); +#endif // Windows + } + + return nFormats; } - virtual void GetAllFormats(wxDataFormat *formats) const + virtual void GetAllFormats(wxDataFormat *formats, Direction dir) const { formats[0] = m_formatShape; - m_dataobj.GetAllFormats(&formats[1]); + if ( dir == Get ) + { + // in Get direction we additionally support bitmaps and metafiles + // under Windows + m_dobjBitmap.GetAllFormats(&formats[1], dir); + +#ifdef USE_METAFILES + // don't assume that m_dobjBitmap has only 1 format + m_dobjMetaFile.GetAllFormats(&formats[1 + + m_dobjBitmap.GetFormatCount(dir)], dir); +#endif // Windows + } } virtual size_t GetDataSize(const wxDataFormat& format) const @@ -333,42 +558,91 @@ public: { return m_shape->GetDataSize(); } +#ifdef USE_METAFILES + else if ( m_dobjMetaFile.IsSupported(format) ) + { + if ( !m_hasMetaFile ) + CreateMetaFile(); + + return m_dobjMetaFile.GetDataSize(format); + } +#endif // Windows else { - wxASSERT_MSG( format == wxDF_BITMAP, "unsupported format" ); + wxASSERT_MSG( m_dobjBitmap.IsSupported(format), + wxT("unexpected format") ); if ( !m_hasBitmap ) CreateBitmap(); - return m_dataobj.GetDataSize(format); + return m_dobjBitmap.GetDataSize(); } } - virtual void GetDataHere(const wxDataFormat& format, void *pBuf) const + virtual bool GetDataHere(const wxDataFormat& format, void *pBuf) const { if ( format == m_formatShape ) { m_shape->GetDataHere(pBuf); + + return TRUE; + } +#ifdef USE_METAFILES + else if ( m_dobjMetaFile.IsSupported(format) ) + { + if ( !m_hasMetaFile ) + CreateMetaFile(); + + return m_dobjMetaFile.GetDataHere(format, pBuf); } +#endif // Windows else { - wxASSERT_MSG( format == wxDF_BITMAP, "unsupported format" ); + wxASSERT_MSG( m_dobjBitmap.IsSupported(format), + wxT("unexpected format") ); if ( !m_hasBitmap ) CreateBitmap(); - m_dataobj.GetDataHere(format, pBuf); + return m_dobjBitmap.GetDataHere(pBuf); } } + virtual bool SetData(const wxDataFormat& format, + size_t len, const void *buf) + { + wxCHECK_MSG( format == m_formatShape, FALSE, + wxT( "unsupported format") ); + + delete m_shape; + m_shape = DnDShape::New(buf); + + // the shape has changed + m_hasBitmap = FALSE; + +#ifdef USE_METAFILES + m_hasMetaFile = FALSE; +#endif // Windows + + return TRUE; + } + private: - // creates a bitmap and assigns it to m_dataobj (also sets m_hasBitmap) + // creates a bitmap and assigns it to m_dobjBitmap (also sets m_hasBitmap) void CreateBitmap() const; +#ifdef USE_METAFILES + void CreateMetaFile() const; +#endif // Windows wxDataFormat m_formatShape; // our custom format - wxBitmapDataObject m_dataobj; // it handles bitmaps - bool m_hasBitmap; // true if m_dataobj has valid bitmap + wxBitmapDataObject m_dobjBitmap; // it handles bitmaps + bool m_hasBitmap; // true if m_dobjBitmap has valid bitmap + +#ifdef USE_METAFILES + wxMetaFileDataObject m_dobjMetaFile;// handles metafiles + bool m_hasMetaFile; // true if we have valid metafile +#endif // Windows DnDShape *m_shape; // our data }; @@ -422,14 +696,25 @@ public: void SetShape(DnDShape *shape); // callbacks + void OnNewShape(wxCommandEvent& event); + void OnEditShape(wxCommandEvent& event); + void OnClearShape(wxCommandEvent& event); + + void OnCopyShape(wxCommandEvent& event); + void OnPasteShape(wxCommandEvent& event); + + void OnUpdateUICopy(wxUpdateUIEvent& event); + void OnUpdateUIPaste(wxUpdateUIEvent& event); + void OnDrag(wxMouseEvent& event); - void OnEdit(wxMouseEvent& event); void OnPaint(wxPaintEvent& event); - void OnDrop(long x, long y, DnDShape *shape); + void OnDrop(wxCoord x, wxCoord y, DnDShape *shape); private: DnDShape *m_shape; + static DnDShapeFrame *ms_lastDropTarget; + DECLARE_EVENT_TABLE() }; @@ -441,35 +726,45 @@ class DnDShapeDropTarget : public wxDropTarget { public: DnDShapeDropTarget(DnDShapeFrame *frame) + : wxDropTarget(new DnDShapeDataObject) { m_frame = frame; - - // the same as used by DnDShapeDataObject - m_formatShape.SetId(shapeFormatId); } // override base class (pure) virtuals - virtual void OnEnter() - { m_frame->SetStatusText("Mouse entered the frame"); } + virtual wxDragResult OnEnter(wxCoord x, wxCoord y, wxDragResult def) + { m_frame->SetStatusText("Mouse entered the frame"); return OnDragOver(x, y, def); } virtual void OnLeave() { m_frame->SetStatusText("Mouse left the frame"); } - virtual bool OnDrop(long x, long y, const void *pData) + virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def) { - m_frame->OnDrop(x, y, DnDShape::New(pData)); + if ( !GetData() ) + { + wxLogError(wxT("Failed to get drag and drop data")); - return TRUE; - } + return wxDragNone; + } -protected: - virtual size_t GetFormatCount() const { return 1; } - virtual wxDataFormat GetFormat(size_t WXUNUSED(n)) const - { return m_formatShape; } + m_frame->OnDrop(x, y, + ((DnDShapeDataObject *)GetDataObject())->GetShape()); + + return def; + } private: DnDShapeFrame *m_frame; - wxDataFormat m_formatShape; }; +// ---------------------------------------------------------------------------- +// functions prototypes +// ---------------------------------------------------------------------------- + +static void ShowBitmap(const wxBitmap& bitmap); + +#ifdef USE_METAFILES +static void ShowMetaFile(const wxMetaFile& metafile); +#endif // USE_METAFILES + // ---------------------------------------------------------------------------- // IDs for the menu commands // ---------------------------------------------------------------------------- @@ -486,10 +781,13 @@ enum Menu_Paste, Menu_CopyBitmap, Menu_PasteBitmap, - Menu_HasText, - Menu_HasBitmap, - Menu_ToBeGreyed, /* for testing */ - Menu_ToBeDeleted, /* for testing */ + Menu_PasteMFile, + Menu_CopyFiles, + Menu_Shape_New = 500, + Menu_Shape_Edit, + Menu_Shape_Clear, + Menu_ShapeClipboard_Copy, + Menu_ShapeClipboard_Paste, Button_Colour = 1001 }; @@ -504,8 +802,13 @@ BEGIN_EVENT_TABLE(DnDFrame, wxFrame) EVT_MENU(Menu_Paste, DnDFrame::OnPaste) EVT_MENU(Menu_CopyBitmap, DnDFrame::OnCopyBitmap) EVT_MENU(Menu_PasteBitmap,DnDFrame::OnPasteBitmap) - EVT_MENU(Menu_HasText, DnDFrame::OnClipboardHasText) - EVT_MENU(Menu_HasBitmap, DnDFrame::OnClipboardHasBitmap) +#ifdef USE_METAFILES + EVT_MENU(Menu_PasteMFile, DnDFrame::OnPasteMetafile) +#endif // USE_METAFILES + EVT_MENU(Menu_CopyFiles, DnDFrame::OnCopyFiles) + + EVT_UPDATE_UI(Menu_Paste, DnDFrame::OnUpdateUIPasteText) + EVT_UPDATE_UI(Menu_PasteBitmap, DnDFrame::OnUpdateUIPasteBitmap) EVT_LEFT_DOWN( DnDFrame::OnLeftDown) EVT_RIGHT_DOWN( DnDFrame::OnRightDown) @@ -513,15 +816,35 @@ BEGIN_EVENT_TABLE(DnDFrame, wxFrame) END_EVENT_TABLE() BEGIN_EVENT_TABLE(DnDShapeFrame, wxFrame) - EVT_RIGHT_DOWN(DnDShapeFrame::OnDrag) - EVT_LEFT_DCLICK(DnDShapeFrame::OnEdit) + EVT_MENU(Menu_Shape_New, DnDShapeFrame::OnNewShape) + EVT_MENU(Menu_Shape_Edit, DnDShapeFrame::OnEditShape) + EVT_MENU(Menu_Shape_Clear, DnDShapeFrame::OnClearShape) + + EVT_MENU(Menu_ShapeClipboard_Copy, DnDShapeFrame::OnCopyShape) + EVT_MENU(Menu_ShapeClipboard_Paste, DnDShapeFrame::OnPasteShape) + + EVT_UPDATE_UI(Menu_ShapeClipboard_Copy, DnDShapeFrame::OnUpdateUICopy) + EVT_UPDATE_UI(Menu_ShapeClipboard_Paste, DnDShapeFrame::OnUpdateUIPaste) + + EVT_LEFT_DOWN(DnDShapeFrame::OnDrag) + EVT_PAINT(DnDShapeFrame::OnPaint) END_EVENT_TABLE() BEGIN_EVENT_TABLE(DnDShapeDialog, wxDialog) - EVT_BUTTON(Button_Colour, OnColour) + EVT_BUTTON(Button_Colour, DnDShapeDialog::OnColour) END_EVENT_TABLE() +BEGIN_EVENT_TABLE(DnDCanvasBitmap, wxScrolledWindow) + EVT_PAINT(DnDCanvasBitmap::OnPaint) +END_EVENT_TABLE() + +#ifdef USE_METAFILES +BEGIN_EVENT_TABLE(DnDCanvasMetafile, wxScrolledWindow) + EVT_PAINT(DnDCanvasMetafile::OnPaint) +END_EVENT_TABLE() +#endif // USE_METAFILES + // ============================================================================ // implementation // ============================================================================ @@ -529,22 +852,52 @@ END_EVENT_TABLE() // `Main program' equivalent, creating windows and returning main app frame bool DnDApp::OnInit() { +#if USE_RESOURCES + // load our ressources + wxPathList pathList; + pathList.Add("."); +#ifdef __WXMSW__ + pathList.Add("./Debug"); + pathList.Add("./Release"); +#endif // wxMSW + + wxString path = pathList.FindValidPath("dnd.wxr"); + if ( !path ) + { + wxLogError(wxT("Can't find the resource file dnd.wxr in the current ") + wxT("directory, aborting.")); + + return FALSE; + } + + wxDefaultResourceTable->ParseResourceFile(path); +#endif + + // switch on trace messages +#if defined(__WXGTK__) + wxLog::AddTraceMask(_T("clipboard")); +#elif defined(__WXMSW__) + wxLog::AddTraceMask(wxTRACE_OleCalls); +#endif + #if wxUSE_LIBPNG wxImage::AddHandler( new wxPNGHandler ); #endif + // under X we usually want to use the primary selection by default (which + // is shared with other apps) + wxTheClipboard->UsePrimarySelection(); + // create the main frame window DnDFrame *frame = new DnDFrame((wxFrame *) NULL, "Drag-and-Drop/Clipboard wxWindows Sample", - 50, 50, 450, 340); + 10, 100, 650, 340); // activate it frame->Show(TRUE); SetTopWindow(frame); - wxDefaultResourceTable->ParseResourceFile("dnd.wxr"); - return TRUE; } @@ -567,7 +920,7 @@ DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h) file_menu->Append(Menu_Quit, "E&xit"); wxMenu *log_menu = new wxMenu; - log_menu->Append(Menu_Clear, "Clear"); + log_menu->Append(Menu_Clear, "Clear\tCtrl-L"); wxMenu *help_menu = new wxMenu; help_menu->Append(Menu_Help, "&Help..."); @@ -578,11 +931,14 @@ DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h) clip_menu->Append(Menu_Copy, "&Copy text\tCtrl+C"); clip_menu->Append(Menu_Paste, "&Paste text\tCtrl+V"); clip_menu->AppendSeparator(); - clip_menu->Append(Menu_CopyBitmap, "&Copy bitmap"); - clip_menu->Append(Menu_PasteBitmap, "&Paste bitmap"); + clip_menu->Append(Menu_CopyBitmap, "Copy &bitmap\tAlt+C"); + clip_menu->Append(Menu_PasteBitmap, "Paste b&itmap\tAlt+V"); +#ifdef USE_METAFILES + clip_menu->AppendSeparator(); + clip_menu->Append(Menu_PasteMFile, "Paste &metafile\tCtrl-M"); +#endif // USE_METAFILES clip_menu->AppendSeparator(); - clip_menu->Append(Menu_HasText, "Clipboard has &text\tCtrl+T"); - clip_menu->Append(Menu_HasBitmap, "Clipboard has a &bitmap\tCtrl+B"); + clip_menu->Append(Menu_CopyFiles, "Copy &files\tCtrl+F"); wxMenuBar *menu_bar = new wxMenuBar; menu_bar->Append(file_menu, "&File"); @@ -598,22 +954,23 @@ DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h) wxString strFile("Drop files here!"), strText("Drop text on me"); - m_ctrlFile = new wxListBox(this, -1, pos, size, 1, &strFile, wxLB_HSCROLL | wxLB_ALWAYS_SB ); - m_ctrlText = new wxListBox(this, -1, pos, size, 1, &strText, wxLB_HSCROLL | wxLB_ALWAYS_SB ); + m_ctrlFile = new wxListBox(this, -1, pos, size, 1, &strFile, + wxLB_HSCROLL | wxLB_ALWAYS_SB ); + m_ctrlText = new wxListBox(this, -1, pos, size, 1, &strText, + wxLB_HSCROLL | wxLB_ALWAYS_SB ); m_ctrlLog = new wxTextCtrl(this, -1, "", pos, size, - wxTE_MULTILINE | wxTE_READONLY | - wxSUNKEN_BORDER ); + wxTE_MULTILINE | wxTE_READONLY | + wxSUNKEN_BORDER ); - // redirect log messages to the text window and switch on OLE messages - // logging - wxLog::AddTraceMask(wxTRACE_OleCalls); + // redirect log messages to the text window m_pLog = new wxLogTextCtrl(m_ctrlLog); m_pLogPrev = wxLog::SetActiveTarget(m_pLog); - // associate drop targets with 2 text controls + // associate drop targets with the controls m_ctrlFile->SetDropTarget(new DnDFile(m_ctrlFile)); m_ctrlText->SetDropTarget(new DnDText(m_ctrlText)); + m_ctrlLog->SetDropTarget(new URLDropTarget); wxLayoutConstraints *c; @@ -637,7 +994,7 @@ DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h) c = new wxLayoutConstraints; c->left.SameAs (this, wxLeft); c->right.SameAs (this, wxRight); - c->height.PercentOf(this, wxHeight, 30); + c->height.PercentOf(this, wxHeight, 50); c->top.SameAs(m_ctrlText, wxBottom); m_ctrlLog->SetConstraints(c); @@ -657,59 +1014,36 @@ void DnDFrame::OnPaint(wxPaintEvent& WXUNUSED(event)) wxPaintDC dc(this); dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL, FALSE, "charter" ) ); - dc.DrawText( "Drag text from here!", 20, h-50 ); - - if (m_bitmap.Ok()) - dc.DrawBitmap( m_bitmap, 280, h-120, TRUE ); + dc.DrawText( "Drag text from here!", 100, h-50 ); } -void DnDFrame::OnClipboardHasText(wxCommandEvent& WXUNUSED(event)) +void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent& event) { - if ( !wxTheClipboard->Open() ) - { - wxLogError( _T("Can't open clipboard.") ); - - return; - } - - if ( !wxTheClipboard->IsSupported( wxDF_TEXT ) ) - { - wxLogMessage( _T("No text on the clipboard") ); - } - else - { - wxLogMessage( _T("There is text on the clipboard") ); - } +#ifdef __WXDEBUG__ + // too many trace messages if we don't do it - this function is called + // very often + wxLogNull nolog; +#endif - wxTheClipboard->Close(); + event.Enable( wxTheClipboard->IsSupported(wxDF_TEXT) ); } -void DnDFrame::OnClipboardHasBitmap(wxCommandEvent& WXUNUSED(event)) +void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent& event) { - if ( !wxTheClipboard->Open() ) - { - wxLogError( _T("Can't open clipboard.") ); - - return; - } - - if ( !wxTheClipboard->IsSupported( wxDF_BITMAP ) ) - { - wxLogMessage( _T("No bitmap on the clipboard") ); - } - else - { - wxLogMessage( _T("There is a bitmap on the clipboard") ); - } +#ifdef __WXDEBUG__ + // too many trace messages if we don't do it - this function is called + // very often + wxLogNull nolog; +#endif - wxTheClipboard->Close(); + event.Enable( wxTheClipboard->IsSupported(wxDF_BITMAP) ); } void DnDFrame::OnNewFrame(wxCommandEvent& WXUNUSED(event)) { (new DnDShapeFrame(this))->Show(TRUE); - wxLogStatus(this, "Double click the new frame to select a shape for it"); + wxLogStatus(this, wxT("Double click the new frame to select a shape for it")); } void DnDFrame::OnDrag(wxCommandEvent& WXUNUSED(event)) @@ -767,6 +1101,8 @@ void DnDFrame::OnHelp(wxCommandEvent& /* event */) void DnDFrame::OnLogClear(wxCommandEvent& /* event */ ) { m_ctrlLog->Clear(); + m_ctrlText->Clear(); + m_ctrlFile->Clear(); } void DnDFrame::OnLeftDown(wxMouseEvent &WXUNUSED(event) ) @@ -775,7 +1111,15 @@ void DnDFrame::OnLeftDown(wxMouseEvent &WXUNUSED(event) ) { // start drag operation wxTextDataObject textData(m_strText); - wxDropSource source(textData, this, wxICON(mondrian)); +/* + wxFileDataObject textData; + textData.AddFile( "/file1.txt" ); + textData.AddFile( "/file2.txt" ); +*/ + wxDropSource source(textData, this, + wxDROP_ICON(dnd_copy), + wxDROP_ICON(dnd_move), + wxDROP_ICON(dnd_none)); const char *pc; @@ -795,18 +1139,13 @@ void DnDFrame::OnLeftDown(wxMouseEvent &WXUNUSED(event) ) void DnDFrame::OnRightDown(wxMouseEvent &event ) { - wxMenu *menu = new wxMenu; - - menu->Append(Menu_Drag, "&Test drag..."); - menu->Append(Menu_About, "&About"); - menu->Append(Menu_Quit, "E&xit"); - menu->Append(Menu_ToBeDeleted, "To be deleted"); - menu->Append(Menu_ToBeGreyed, "To be greyed"); + wxMenu menu("Dnd sample menu"); - menu->Delete( Menu_ToBeDeleted ); - menu->Enable( Menu_ToBeGreyed, FALSE ); + menu.Append(Menu_Drag, "&Test drag..."); + menu.AppendSeparator(); + menu.Append(Menu_About, "&About"); - PopupMenu( menu, event.GetX(), event.GetY() ); + PopupMenu( &menu, event.GetX(), event.GetY() ); } DnDFrame::~DnDFrame() @@ -908,20 +1247,112 @@ void DnDFrame::OnPasteBitmap(wxCommandEvent& WXUNUSED(event)) } wxBitmapDataObject data; - if ( !wxTheClipboard->GetData(&data) ) + if ( !wxTheClipboard->GetData(data) ) { wxLogError(_T("Can't paste bitmap from the clipboard")); } else { - wxLogMessage(_T("Bitmap pasted from the clipboard") ); - m_bitmap = data.GetBitmap(); - Refresh(); + const wxBitmap& bmp = data.GetBitmap(); + + wxLogMessage(_T("Bitmap %dx%d pasted from the clipboard"), + bmp.GetWidth(), bmp.GetHeight()); + ShowBitmap(bmp); } wxTheClipboard->Close(); } +#ifdef USE_METAFILES + +void DnDFrame::OnPasteMetafile(wxCommandEvent& WXUNUSED(event)) +{ + if ( !wxTheClipboard->Open() ) + { + wxLogError(_T("Can't open clipboard.")); + + return; + } + + if ( !wxTheClipboard->IsSupported(wxDF_METAFILE) ) + { + wxLogWarning(_T("No metafile on clipboard")); + } + else + { + wxMetaFileDataObject data; + if ( !wxTheClipboard->GetData(data) ) + { + wxLogError(_T("Can't paste metafile from the clipboard")); + } + else + { + const wxMetaFile& mf = data.GetMetafile(); + + wxLogMessage(_T("Metafile %dx%d pasted from the clipboard"), + mf.GetWidth(), mf.GetHeight()); + + ShowMetaFile(mf); + } + } + + wxTheClipboard->Close(); +} + +#endif // USE_METAFILES + +// ---------------------------------------------------------------------------- +// file clipboard +// ---------------------------------------------------------------------------- + +void DnDFrame::OnCopyFiles(wxCommandEvent& WXUNUSED(event)) +{ +#ifdef __WXMSW__ + wxFileDialog dialog(this, "Select a file to copy", "", "", + "All files (*.*)|*.*", 0); + + wxArrayString filenames; + while ( dialog.ShowModal() == wxID_OK ) + { + filenames.Add(dialog.GetPath()); + } + + if ( !filenames.IsEmpty() ) + { + wxFileDataObject *dobj = new wxFileDataObject; + size_t count = filenames.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + dobj->AddFile(filenames[n]); + } + + wxClipboardLocker locker; + if ( !locker ) + { + wxLogError(wxT("Can't open clipboard")); + } + else + { + if ( !wxTheClipboard->AddData(dobj) ) + { + wxLogError(wxT("Can't copy file(s) to the clipboard")); + } + else + { + wxLogStatus(this, wxT("%d file%s copied to the clipboard"), + count, count == 1 ? wxT("") : wxT("s")); + } + } + } + else + { + wxLogStatus(this, wxT("Aborted")); + } +#else // !MSW + wxLogError(wxT("Sorry, not implemented")); +#endif // MSW/!MSW +} + // --------------------------------------------------------------------------- // text clipboard // --------------------------------------------------------------------------- @@ -965,7 +1396,7 @@ void DnDFrame::OnPaste(wxCommandEvent& WXUNUSED(event)) } wxTextDataObject text; - if ( !wxTheClipboard->GetData(&text) ) + if ( !wxTheClipboard->GetData(text) ) { wxLogError(_T("Can't paste data from the clipboard")); } @@ -982,21 +1413,21 @@ void DnDFrame::OnPaste(wxCommandEvent& WXUNUSED(event)) // Notifications called by the base class // ---------------------------------------------------------------------------- -bool DnDText::OnDropText( wxDropPointCoord, wxDropPointCoord, const wxChar *psz ) +bool DnDText::OnDropText(wxCoord, wxCoord, const wxString& text) { - m_pOwner->Append(psz); + m_pOwner->Append(text); return TRUE; } -bool DnDFile::OnDropFiles( wxDropPointCoord, wxDropPointCoord, size_t nFiles, - const wxChar* const aszFiles[]) +bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& filenames) { + size_t nFiles = filenames.GetCount(); wxString str; str.Printf( _T("%d files dropped"), nFiles); m_pOwner->Append(str); for ( size_t n = 0; n < nFiles; n++ ) { - m_pOwner->Append(aszFiles[n]); + m_pOwner->Append(filenames[n]); } return TRUE; @@ -1007,9 +1438,14 @@ bool DnDFile::OnDropFiles( wxDropPointCoord, wxDropPointCoord, size_t nFiles, // ---------------------------------------------------------------------------- DnDShapeDialog::DnDShapeDialog(wxFrame *parent, DnDShape *shape) +#if !USE_RESOURCES + :wxDialog( parent, 6001, wxT("Choose Shape"), wxPoint( 10, 10 ), + wxSize( 40, 40 ), + wxRAISED_BORDER|wxCAPTION|wxTHICK_FRAME|wxSYSTEM_MENU ) +#endif { m_shape = shape; - +#if USE_RESOURCES LoadFromResource(parent, "dialogShape"); m_textX = (wxTextCtrl *)wxFindWindowByName("textX", this); @@ -1018,6 +1454,69 @@ DnDShapeDialog::DnDShapeDialog(wxFrame *parent, DnDShape *shape) m_textH = (wxTextCtrl *)wxFindWindowByName("textH", this); m_radio = (wxRadioBox *)wxFindWindowByName("radio", this); +#else + wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL ); + + // radio box + wxBoxSizer* shapesSizer = new wxBoxSizer( wxHORIZONTAL ); + const wxString choices[] = { wxT("None"), wxT("Triangle"), + wxT("Rectangle"), wxT("Ellipse") }; + + m_radio = new wxRadioBox( this, -1, wxT("&Shape"), + wxDefaultPosition, wxDefaultSize, 4, choices, 4, + wxRA_SPECIFY_COLS ); + shapesSizer->Add( m_radio, 0, wxGROW|wxALL, 5 ); + topSizer->Add( shapesSizer, 0, wxALL, 2 ); + + // attributes + wxStaticBox* box = new wxStaticBox( this, -1, wxT("&Attributes") ); + wxStaticBoxSizer* attrSizer = new wxStaticBoxSizer( box, wxHORIZONTAL ); + wxFlexGridSizer* xywhSizer = new wxFlexGridSizer( 4, 2 ); + + wxStaticText* st; + + st = new wxStaticText( this, -1, wxT("Position &X:") ); + m_textX = new wxTextCtrl( this, -1, wxEmptyString, wxDefaultPosition, + wxSize( 30, 20 ) ); + xywhSizer->Add( st, 1, wxGROW|wxALL, 2 ); + xywhSizer->Add( m_textX, 1, wxGROW|wxALL, 2 ); + + st = new wxStaticText( this, -1, wxT("Size &width:") ); + m_textW = new wxTextCtrl( this, -1, wxEmptyString, wxDefaultPosition, + wxSize( 30, 20 ) ); + xywhSizer->Add( st, 1, wxGROW|wxALL, 2 ); + xywhSizer->Add( m_textW, 1, wxGROW|wxALL, 2 ); + + st = new wxStaticText( this, -1, wxT("&Y:") ); + m_textY = new wxTextCtrl( this, -1, wxEmptyString, wxDefaultPosition, + wxSize( 30, 20 ) ); + xywhSizer->Add( st, 1, wxALL|wxALIGN_RIGHT, 2 ); + xywhSizer->Add( m_textY, 1, wxGROW|wxALL, 2 ); + + st = new wxStaticText( this, -1, wxT("&height:") ); + m_textH = new wxTextCtrl( this, -1, wxEmptyString, wxDefaultPosition, + wxSize( 30, 20 ) ); + xywhSizer->Add( st, 1, wxALL|wxALIGN_RIGHT, 2 ); + xywhSizer->Add( m_textH, 1, wxGROW|wxALL, 2 ); + + wxButton* col = new wxButton( this, Button_Colour, wxT("&Colour...") ); + attrSizer->Add( xywhSizer, 1, wxGROW ); + attrSizer->Add( col, 0, wxALL|wxALIGN_CENTRE_VERTICAL, 2 ); + topSizer->Add( attrSizer, 0, wxGROW|wxALL, 5 ); + + // buttons + wxBoxSizer* buttonSizer = new wxBoxSizer( wxHORIZONTAL ); + wxButton* bt; + bt = new wxButton( this, wxID_OK, wxT("Ok") ); + buttonSizer->Add( bt, 0, wxALL, 2 ); + bt = new wxButton( this, wxID_CANCEL, wxT("Cancel") ); + buttonSizer->Add( bt, 0, wxALL, 2 ); + topSizer->Add( buttonSizer, 0, wxALL|wxALIGN_RIGHT, 2 ); + + SetAutoLayout( TRUE ); + SetSizer( topSizer ); + topSizer->Fit( this ); +#endif } DnDShape *DnDShapeDialog::GetShape() const @@ -1034,6 +1533,7 @@ DnDShape *DnDShapeDialog::GetShape() const bool DnDShapeDialog::TransferDataToWindow() { + if ( m_shape ) { m_radio->SetSelection(m_shape->GetKind()); @@ -1060,10 +1560,10 @@ bool DnDShapeDialog::TransferDataFromWindow() { m_shapeKind = (DnDShape::Kind)m_radio->GetSelection(); - m_pos.x = atoi(m_textX->GetValue()); - m_pos.y = atoi(m_textY->GetValue()); - m_size.x = atoi(m_textW->GetValue()); - m_size.y = atoi(m_textH->GetValue()); + m_pos.x = wxAtoi(m_textX->GetValue()); + m_pos.y = wxAtoi(m_textY->GetValue()); + m_size.x = wxAtoi(m_textW->GetValue()); + m_size.y = wxAtoi(m_textH->GetValue()); if ( !m_pos.x || !m_pos.y || !m_size.x || !m_size.y ) { @@ -1097,29 +1597,49 @@ void DnDShapeDialog::OnColour(wxCommandEvent& WXUNUSED(event)) // DnDShapeFrame // ---------------------------------------------------------------------------- +DnDShapeFrame *DnDShapeFrame::ms_lastDropTarget = NULL; + DnDShapeFrame::DnDShapeFrame(wxFrame *parent) : wxFrame(parent, -1, "Shape Frame", wxDefaultPosition, wxSize(250, 150)) { - SetBackgroundColour(*wxWHITE); - CreateStatusBar(); - SetStatusText("Double click the frame to create a shape"); + wxMenu *menuShape = new wxMenu; + menuShape->Append(Menu_Shape_New, "&New default shape\tCtrl-S"); + menuShape->Append(Menu_Shape_Edit, "&Edit shape\tCtrl-E"); + menuShape->AppendSeparator(); + menuShape->Append(Menu_Shape_Clear, "&Clear shape\tCtrl-L"); + + wxMenu *menuClipboard = new wxMenu; + menuClipboard->Append(Menu_ShapeClipboard_Copy, "&Copy\tCtrl-C"); + menuClipboard->Append(Menu_ShapeClipboard_Paste, "&Paste\tCtrl-V"); + + wxMenuBar *menubar = new wxMenuBar; + menubar->Append(menuShape, "&Shape"); + menubar->Append(menuClipboard, "&Clipboard"); + + SetMenuBar(menubar); + + SetStatusText("Press Ctrl-S to create a new shape"); SetDropTarget(new DnDShapeDropTarget(this)); m_shape = NULL; + + SetBackgroundColour(*wxWHITE); } DnDShapeFrame::~DnDShapeFrame() { - delete m_shape; + if (m_shape) + delete m_shape; } void DnDShapeFrame::SetShape(DnDShape *shape) { - delete m_shape; + if (m_shape) + delete m_shape; m_shape = shape; Refresh(); } @@ -1136,14 +1656,14 @@ void DnDShapeFrame::OnDrag(wxMouseEvent& event) // start drag operation DnDShapeDataObject shapeData(m_shape); - wxDropSource source(shapeData, this, wxICON(mondrian)); + wxDropSource source(shapeData, this); const char *pc = NULL; switch ( source.DoDragDrop(TRUE) ) { default: case wxDragError: - wxLogError("An error occured during drag and drop operation"); + wxLogError(wxT("An error occured during drag and drop operation")); break; case wxDragNone: @@ -1156,7 +1676,11 @@ void DnDShapeFrame::OnDrag(wxMouseEvent& event) case wxDragMove: pc = "moved"; - SetShape(NULL); + if ( ms_lastDropTarget != this ) + { + // don't delete the shape if we dropped it on ourselves! + SetShape(NULL); + } break; case wxDragCancel: @@ -1171,7 +1695,21 @@ void DnDShapeFrame::OnDrag(wxMouseEvent& event) //else: status text already set } -void DnDShapeFrame::OnEdit(wxMouseEvent& event) +void DnDShapeFrame::OnDrop(wxCoord x, wxCoord y, DnDShape *shape) +{ + ms_lastDropTarget = this; + + wxPoint pt(x, y); + + wxString s; + s.Printf(wxT("Shape dropped at (%ld, %ld)"), pt.x, pt.y); + SetStatusText(s); + + shape->Move(pt); + SetShape(shape); +} + +void DnDShapeFrame::OnEditShape(wxCommandEvent& event) { DnDShapeDialog dlg(this, m_shape); if ( dlg.ShowModal() == wxID_OK ) @@ -1180,26 +1718,82 @@ void DnDShapeFrame::OnEdit(wxMouseEvent& event) if ( m_shape ) { - SetStatusText("Right click now drag the shape to another frame"); + SetStatusText("You can now drag the shape to another frame"); } } } -void DnDShapeFrame::OnPaint(wxPaintEvent& event) +void DnDShapeFrame::OnNewShape(wxCommandEvent& event) +{ + SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED)); + + SetStatusText("You can now drag the shape to another frame"); +} + +void DnDShapeFrame::OnClearShape(wxCommandEvent& event) +{ + SetShape(NULL); +} + +void DnDShapeFrame::OnCopyShape(wxCommandEvent& event) { if ( m_shape ) - m_shape->Draw(wxPaintDC(this)); + { + wxClipboardLocker clipLocker; + if ( !clipLocker ) + { + wxLogError(wxT("Can't open the clipboard")); + + return; + } + + wxTheClipboard->AddData(new DnDShapeDataObject(m_shape)); + } +} + +void DnDShapeFrame::OnPasteShape(wxCommandEvent& event) +{ + wxClipboardLocker clipLocker; + if ( !clipLocker ) + { + wxLogError(wxT("Can't open the clipboard")); + + return; + } + + DnDShapeDataObject shapeDataObject(NULL); + if ( wxTheClipboard->GetData(shapeDataObject) ) + { + SetShape(shapeDataObject.GetShape()); + } else - event.Skip(); + { + wxLogStatus(wxT("No shape on the clipboard")); + } } -void DnDShapeFrame::OnDrop(long x, long y, DnDShape *shape) +void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent& event) { - wxString s; - s.Printf("Drop occured at (%ld, %ld)", x, y); - SetStatusText(s); + event.Enable( m_shape != NULL ); +} - SetShape(shape); +void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent& event) +{ + event.Enable( wxTheClipboard->IsSupported(wxDataFormat(shapeFormatId)) ); +} + +void DnDShapeFrame::OnPaint(wxPaintEvent& event) +{ + if ( m_shape ) + { + wxPaintDC dc(this); + + m_shape->Draw(dc); + } + else + { + event.Skip(); + } } // ---------------------------------------------------------------------------- @@ -1227,7 +1821,7 @@ DnDShape *DnDShape::New(const void *buf) wxColour(dump.r, dump.g, dump.b)); default: - wxFAIL_MSG("invalid shape!"); + wxFAIL_MSG(wxT("invalid shape!")); return NULL; } } @@ -1236,16 +1830,81 @@ DnDShape *DnDShape::New(const void *buf) // DnDShapeDataObject // ---------------------------------------------------------------------------- +#ifdef USE_METAFILES + +void DnDShapeDataObject::CreateMetaFile() const +{ + wxPoint pos = m_shape->GetPosition(); + wxSize size = m_shape->GetSize(); + + wxMetaFileDC dcMF(wxEmptyString, pos.x + size.x, pos.y + size.y); + + m_shape->Draw(dcMF); + + wxMetafile *mf = dcMF.Close(); + + DnDShapeDataObject *self = (DnDShapeDataObject *)this; // const_cast + self->m_dobjMetaFile.SetMetafile(*mf); + self->m_hasMetaFile = TRUE; + + delete mf; +} + +#endif // Windows + void DnDShapeDataObject::CreateBitmap() const { - wxBitmap bitmap; + wxPoint pos = m_shape->GetPosition(); + wxSize size = m_shape->GetSize(); + int x = pos.x + size.x, + y = pos.y + size.y; + wxBitmap bitmap(x, y); wxMemoryDC dc; dc.SelectObject(bitmap); + dc.SetBrush(wxBrush("white", wxSOLID)); + dc.Clear(); m_shape->Draw(dc); dc.SelectObject(wxNullBitmap); DnDShapeDataObject *self = (DnDShapeDataObject *)this; // const_cast - self->m_dataobj.SetBitmap(bitmap); + self->m_dobjBitmap.SetBitmap(bitmap); self->m_hasBitmap = TRUE; } +// ---------------------------------------------------------------------------- +// global functions +// ---------------------------------------------------------------------------- + +static void ShowBitmap(const wxBitmap& bitmap) +{ + wxFrame *frame = new wxFrame(NULL, -1, _T("Bitmap view")); + frame->CreateStatusBar(); + DnDCanvasBitmap *canvas = new DnDCanvasBitmap(frame); + canvas->SetBitmap(bitmap); + + int w = bitmap.GetWidth(), + h = bitmap.GetHeight(); + frame->SetStatusText(wxString::Format(_T("%dx%d"), w, h)); + + frame->SetClientSize(w > 100 ? 100 : w, h > 100 ? 100 : h); + frame->Show(TRUE); +} + +#ifdef USE_METAFILES + +static void ShowMetaFile(const wxMetaFile& metafile) +{ + wxFrame *frame = new wxFrame(NULL, -1, _T("Metafile view")); + frame->CreateStatusBar(); + DnDCanvasMetafile *canvas = new DnDCanvasMetafile(frame); + canvas->SetMetafile(metafile); + + wxSize size = metafile.GetSize(); + frame->SetStatusText(wxString::Format(_T("%dx%d"), size.x, size.y)); + + frame->SetClientSize(size.x > 100 ? 100 : size.x, + size.y > 100 ? 100 : size.y); + frame->Show(); +} + +#endif // USE_METAFILES