1. more drag and drop and clipboard changes:

a) OLE clipboard works fine
 b) wxBitmapDataObject now accepts DIBs (but doesn't give them back :-( )
 c) bugs in sample corrected
2. wxFatalExit() replaced with wxFAIL_MSG() in bitmap.cpp and dcmemory.cpp
3. wxFrame::ClientToScreen and ScreenToClient() replaced with DoXXX() - like
   this, they don't hide the base class versions


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4039 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
1999-10-18 00:08:40 +00:00
parent 23d277e683
commit d59ceba572
9 changed files with 820 additions and 333 deletions

View File

@@ -84,9 +84,16 @@ public:
// clears wxTheClipboard and the system's clipboard if possible // clears wxTheClipboard and the system's clipboard if possible
virtual void Clear(); virtual void Clear();
/// X11 has two clipboards which get selected by this call. Empty on MSW. // flushes the clipboard: this means that the data which is currently on
// clipboard will stay available even after the application exits (possibly
// eating memory), otherwise the clipboard will be emptied on exit
virtual bool Flush();
// X11 has two clipboards which get selected by this call. Empty on MSW.
void UsePrimarySelection( bool WXUNUSED(primary) = FALSE ) { } void UsePrimarySelection( bool WXUNUSED(primary) = FALSE ) { }
private:
bool m_clearOnExit;
}; };
// The global clipboard object // The global clipboard object

View File

@@ -57,9 +57,6 @@ public:
virtual bool Destroy(); virtual bool Destroy();
virtual void ClientToScreen(int *x, int *y) const;
virtual void ScreenToClient(int *x, int *y) const;
void OnSize(wxSizeEvent& event); void OnSize(wxSizeEvent& event);
void OnMenuHighlight(wxMenuEvent& event); void OnMenuHighlight(wxMenuEvent& event);
void OnActivate(wxActivateEvent& event); void OnActivate(wxActivateEvent& event);
@@ -179,6 +176,9 @@ protected:
virtual void DoSetClientSize(int width, int height); virtual void DoSetClientSize(int width, int height);
virtual void DoClientToScreen(int *x, int *y) const;
virtual void DoScreenToClient(int *x, int *y) const;
// a plug in for MDI frame classes which need to do something special when // a plug in for MDI frame classes which need to do something special when
// the menubar is set // the menubar is set
virtual void InternalSetMenuBar(); virtual void InternalSetMenuBar();

View File

@@ -23,8 +23,12 @@ public:
typedef unsigned int NativeFormat; typedef unsigned int NativeFormat;
wxDataFormat(NativeFormat format = wxDF_INVALID) { m_format = format; } wxDataFormat(NativeFormat format = wxDF_INVALID) { m_format = format; }
wxDataFormat(const wxChar *format) { SetId(format); }
wxDataFormat& operator=(NativeFormat format) wxDataFormat& operator=(NativeFormat format)
{ m_format = format; return *this; } { m_format = format; return *this; }
wxDataFormat& operator=(const wxDataFormat& format)
{ m_format = format.m_format; return *this; }
// defautl copy ctor/assignment operators ok // defautl copy ctor/assignment operators ok
@@ -62,14 +66,11 @@ private:
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// forward declarations // forward declarations
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
struct IDataObject; struct IDataObject;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxDataObject is a "smart" and polymorphic piece of data. // wxDataObject is a "smart" and polymorphic piece of data.
//
// TODO it's currently "read-only" from COM point of view, i.e. we don't
// support SetData. We don't support all advise functions neither (but
// it's easy to do if we really want them)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
class WXDLLEXPORT wxDataObject class WXDLLEXPORT wxDataObject
@@ -80,18 +81,26 @@ public:
virtual ~wxDataObject(); virtual ~wxDataObject();
// pure virtuals to override // pure virtuals to override
// get the best suited format for our data // get the best suited format for rendering our data
virtual wxDataFormat GetPreferredFormat() const = 0; virtual wxDataFormat GetPreferredFormat() const = 0;
// get the number of formats we support // get the number of formats we support: it is understood that if we
virtual size_t GetFormatCount() const // can accept data in some format, then we can render data in this
// format as well, but the contrary is not necessarily true. For the
// default value of the argument, all formats we support should be
// returned, but if outputOnlyToo == FALSE, then we should only return
// the formats which our SetData() understands
virtual size_t GetFormatCount(bool outputOnlyToo = TRUE) const
{ return 1; } { return 1; }
// return all formats in the provided array (of size GetFormatCount()) // return all formats in the provided array (of size GetFormatCount())
virtual void GetAllFormats(wxDataFormat *formats) const virtual void GetAllFormats(wxDataFormat *formats,
bool outputOnlyToo = TRUE) const
{ formats[0] = GetPreferredFormat(); } { formats[0] = GetPreferredFormat(); }
// get the (total) size of data for the given format // get the (total) size of data for the given format
virtual size_t GetDataSize(const wxDataFormat& format) const = 0; virtual size_t GetDataSize(const wxDataFormat& format) const = 0;
// copy raw data (in the specified format) to provided pointer // copy raw data (in the specified format) to provided pointer
virtual void GetDataHere(const wxDataFormat& format, void *pBuf) const = 0; virtual bool GetDataHere(const wxDataFormat& format, void *buf) const = 0;
// get data from the buffer (in the given format)
virtual bool SetData(const wxDataFormat& format, const void *buf) = 0;
// accessors // accessors
// retrieve IDataObject interface (for other OLE related classes) // retrieve IDataObject interface (for other OLE related classes)
@@ -105,6 +114,13 @@ public:
// format) -- now uses GetAllFormats() // format) -- now uses GetAllFormats()
virtual bool IsSupportedFormat(const wxDataFormat& format) const; virtual bool IsSupportedFormat(const wxDataFormat& format) const;
// implementation only from now on
// -------------------------------
// tell the object that it should be now owned by IDataObject - i.e. when
// it is deleted, it should delete us as well
void SetAutoDelete();
#ifdef __WXDEBUG__ #ifdef __WXDEBUG__
// function to return symbolic name of clipboard format (for debug messages) // function to return symbolic name of clipboard format (for debug messages)
static const char *GetFormatName(wxDataFormat format); static const char *GetFormatName(wxDataFormat format);
@@ -133,8 +149,10 @@ public:
{ return format == wxDF_TEXT || format == wxDF_LOCALE; } { return format == wxDF_TEXT || format == wxDF_LOCALE; }
virtual size_t GetDataSize(const wxDataFormat& format) const virtual size_t GetDataSize(const wxDataFormat& format) const
{ return m_strText.Len() + 1; } // +1 for trailing '\0'of course { return m_strText.Len() + 1; } // +1 for trailing '\0'of course
virtual void GetDataHere(const wxDataFormat& format, void *pBuf) const virtual bool GetDataHere(const wxDataFormat& format, void *buf) const
{ memcpy(pBuf, m_strText.c_str(), GetDataSize(format)); } { memcpy(buf, m_strText.c_str(), GetDataSize(format)); return TRUE; }
virtual bool SetData(const wxDataFormat& format, const void *buf)
{ m_strText = (const wxChar *)buf; return TRUE; }
// additional helpers // additional helpers
void SetText(const wxString& strText) { m_strText = strText; } void SetText(const wxString& strText) { m_strText = strText; }
@@ -144,16 +162,10 @@ private:
wxString m_strText; wxString m_strText;
}; };
// ----------------------------------------------------------------------------
// TODO: wx{Bitmap|Metafile|...}DataObject
// ----------------------------------------------------------------------------
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxBitmapDataObject is a specialization of wxDataObject for bitmap data // wxBitmapDataObject is a specialization of wxDataObject for bitmap data
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// TODO: implement OLE side of things. At present, it's just for clipboard
// use.
#include "wx/bitmap.h" #include "wx/bitmap.h"
class WXDLLEXPORT wxBitmapDataObject : public wxDataObject class WXDLLEXPORT wxBitmapDataObject : public wxDataObject
@@ -168,12 +180,13 @@ public:
const wxBitmap GetBitmap() const { return m_bitmap; } const wxBitmap GetBitmap() const { return m_bitmap; }
// implement base class pure virtuals // implement base class pure virtuals
virtual wxDataFormat GetPreferredFormat() const virtual wxDataFormat GetPreferredFormat() const { return wxDF_BITMAP; }
{ return wxDF_BITMAP; } virtual size_t GetFormatCount(bool outputOnlyToo = TRUE) const;
virtual bool IsSupportedFormat(const wxDataFormat& format) const virtual void GetAllFormats(wxDataFormat *formats,
{ return format == wxDF_BITMAP; } bool outputOnlyToo = TRUE) const;
virtual size_t GetDataSize(const wxDataFormat& format) const; virtual size_t GetDataSize(const wxDataFormat& format) const;
virtual void GetDataHere(const wxDataFormat& format, void *pBuf) const; virtual bool GetDataHere(const wxDataFormat& format, void *buf) const;
virtual bool SetData(const wxDataFormat& format, const void *buf);
private: private:
wxBitmap m_bitmap; wxBitmap m_bitmap;

View File

@@ -102,12 +102,13 @@ public:
void OnPaste(wxCommandEvent& event); void OnPaste(wxCommandEvent& event);
void OnCopyBitmap(wxCommandEvent& event); void OnCopyBitmap(wxCommandEvent& event);
void OnPasteBitmap(wxCommandEvent& event); void OnPasteBitmap(wxCommandEvent& event);
void OnClipboardHasText(wxCommandEvent& event);
void OnClipboardHasBitmap(wxCommandEvent& event);
void OnLeftDown(wxMouseEvent& event); void OnLeftDown(wxMouseEvent& event);
void OnRightDown(wxMouseEvent& event); void OnRightDown(wxMouseEvent& event);
void OnUpdateUIPasteText(wxUpdateUIEvent& event);
void OnUpdateUIPasteBitmap(wxUpdateUIEvent& event);
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
private: private:
@@ -146,11 +147,7 @@ public:
} }
// the functions used for drag-and-drop: they dump and restore a shape into // the functions used for drag-and-drop: they dump and restore a shape into
// some bitwise-copiable data // some bitwise-copiable data (might use streams too...)
//
// 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!
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// restore from buffer // restore from buffer
@@ -179,6 +176,8 @@ public:
const wxColour& GetColour() const { return m_col; } const wxColour& GetColour() const { return m_col; }
const wxSize& GetSize() const { return m_size; } const wxSize& GetSize() const { return m_size; }
void Move(const wxPoint& pos) { m_pos = pos; }
// to implement in derived classes // to implement in derived classes
virtual Kind GetKind() const = 0; virtual Kind GetKind() const = 0;
@@ -307,6 +306,9 @@ public:
m_hasBitmap = FALSE; m_hasBitmap = FALSE;
} }
// accessors
DnDShape *GetShape() const { return m_shape; }
// implement base class pure virtuals // implement base class pure virtuals
// ---------------------------------- // ----------------------------------
@@ -315,16 +317,26 @@ public:
return m_formatShape; return m_formatShape;
} }
virtual size_t GetFormatCount() const virtual size_t GetFormatCount(bool outputOnlyToo) const
{ {
// +1 for our custom format // our custom format is supported by both GetData() and SetData()
return m_dataobj.GetFormatCount() + 1; size_t nFormats = 1;
if ( outputOnlyToo )
{
// but the bitmap format(s) are only supported for output
nFormats += m_dataobj.GetFormatCount();
}
return nFormats;
} }
virtual void GetAllFormats(wxDataFormat *formats) const virtual void GetAllFormats(wxDataFormat *formats, bool outputOnlyToo) const
{ {
formats[0] = m_formatShape; formats[0] = m_formatShape;
m_dataobj.GetAllFormats(&formats[1]); if ( outputOnlyToo )
{
m_dataobj.GetAllFormats(&formats[1]);
}
} }
virtual size_t GetDataSize(const wxDataFormat& format) const virtual size_t GetDataSize(const wxDataFormat& format) const
@@ -335,8 +347,6 @@ public:
} }
else else
{ {
wxASSERT_MSG( format == wxDF_BITMAP, "unsupported format" );
if ( !m_hasBitmap ) if ( !m_hasBitmap )
CreateBitmap(); CreateBitmap();
@@ -344,11 +354,13 @@ public:
} }
} }
virtual void GetDataHere(const wxDataFormat& format, void *pBuf) const virtual bool GetDataHere(const wxDataFormat& format, void *pBuf) const
{ {
if ( format == m_formatShape ) if ( format == m_formatShape )
{ {
m_shape->GetDataHere(pBuf); m_shape->GetDataHere(pBuf);
return TRUE;
} }
else else
{ {
@@ -357,10 +369,23 @@ public:
if ( !m_hasBitmap ) if ( !m_hasBitmap )
CreateBitmap(); CreateBitmap();
m_dataobj.GetDataHere(format, pBuf); return m_dataobj.GetDataHere(format, pBuf);
} }
} }
virtual bool SetData(const wxDataFormat& format, const void *buf)
{
wxCHECK_MSG( format == m_formatShape, FALSE, "unsupported format" );
delete m_shape;
m_shape = DnDShape::New(buf);
// the shape has changed
m_hasBitmap = FALSE;
return TRUE;
}
private: private:
// creates a bitmap and assigns it to m_dataobj (also sets m_hasBitmap) // creates a bitmap and assigns it to m_dataobj (also sets m_hasBitmap)
void CreateBitmap() const; void CreateBitmap() const;
@@ -422,14 +447,25 @@ public:
void SetShape(DnDShape *shape); void SetShape(DnDShape *shape);
// callbacks // 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 OnDrag(wxMouseEvent& event);
void OnEdit(wxMouseEvent& event);
void OnPaint(wxPaintEvent& event); void OnPaint(wxPaintEvent& event);
void OnDrop(long x, long y, DnDShape *shape); void OnDrop(long x, long y, DnDShape *shape);
private: private:
DnDShape *m_shape; DnDShape *m_shape;
static DnDShapeFrame *ms_lastDropTarget;
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
}; };
@@ -486,10 +522,13 @@ enum
Menu_Paste, Menu_Paste,
Menu_CopyBitmap, Menu_CopyBitmap,
Menu_PasteBitmap, Menu_PasteBitmap,
Menu_HasText,
Menu_HasBitmap,
Menu_ToBeGreyed, /* for testing */ Menu_ToBeGreyed, /* for testing */
Menu_ToBeDeleted, /* for testing */ Menu_ToBeDeleted, /* for testing */
Menu_Shape_New = 500,
Menu_Shape_Edit,
Menu_Shape_Clear,
Menu_ShapeClipboard_Copy,
Menu_ShapeClipboard_Paste,
Button_Colour = 1001 Button_Colour = 1001
}; };
@@ -504,8 +543,9 @@ BEGIN_EVENT_TABLE(DnDFrame, wxFrame)
EVT_MENU(Menu_Paste, DnDFrame::OnPaste) EVT_MENU(Menu_Paste, DnDFrame::OnPaste)
EVT_MENU(Menu_CopyBitmap, DnDFrame::OnCopyBitmap) EVT_MENU(Menu_CopyBitmap, DnDFrame::OnCopyBitmap)
EVT_MENU(Menu_PasteBitmap,DnDFrame::OnPasteBitmap) EVT_MENU(Menu_PasteBitmap,DnDFrame::OnPasteBitmap)
EVT_MENU(Menu_HasText, DnDFrame::OnClipboardHasText)
EVT_MENU(Menu_HasBitmap, DnDFrame::OnClipboardHasBitmap) EVT_UPDATE_UI(Menu_Paste, DnDFrame::OnUpdateUIPasteText)
EVT_UPDATE_UI(Menu_PasteBitmap, DnDFrame::OnUpdateUIPasteBitmap)
EVT_LEFT_DOWN( DnDFrame::OnLeftDown) EVT_LEFT_DOWN( DnDFrame::OnLeftDown)
EVT_RIGHT_DOWN( DnDFrame::OnRightDown) EVT_RIGHT_DOWN( DnDFrame::OnRightDown)
@@ -513,8 +553,18 @@ BEGIN_EVENT_TABLE(DnDFrame, wxFrame)
END_EVENT_TABLE() END_EVENT_TABLE()
BEGIN_EVENT_TABLE(DnDShapeFrame, wxFrame) BEGIN_EVENT_TABLE(DnDShapeFrame, wxFrame)
EVT_RIGHT_DOWN(DnDShapeFrame::OnDrag) EVT_MENU(Menu_Shape_New, DnDShapeFrame::OnNewShape)
EVT_LEFT_DCLICK(DnDShapeFrame::OnEdit) 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) EVT_PAINT(DnDShapeFrame::OnPaint)
END_EVENT_TABLE() END_EVENT_TABLE()
@@ -567,7 +617,7 @@ DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
file_menu->Append(Menu_Quit, "E&xit"); file_menu->Append(Menu_Quit, "E&xit");
wxMenu *log_menu = new wxMenu; wxMenu *log_menu = new wxMenu;
log_menu->Append(Menu_Clear, "Clear"); log_menu->Append(Menu_Clear, "Clear\tDel");
wxMenu *help_menu = new wxMenu; wxMenu *help_menu = new wxMenu;
help_menu->Append(Menu_Help, "&Help..."); help_menu->Append(Menu_Help, "&Help...");
@@ -578,11 +628,8 @@ 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_Copy, "&Copy text\tCtrl+C");
clip_menu->Append(Menu_Paste, "&Paste text\tCtrl+V"); clip_menu->Append(Menu_Paste, "&Paste text\tCtrl+V");
clip_menu->AppendSeparator(); clip_menu->AppendSeparator();
clip_menu->Append(Menu_CopyBitmap, "&Copy bitmap"); clip_menu->Append(Menu_CopyBitmap, "&Copy bitmap\tAlt+C");
clip_menu->Append(Menu_PasteBitmap, "&Paste bitmap"); clip_menu->Append(Menu_PasteBitmap, "&Paste bitmap\tAlt+V");
clip_menu->AppendSeparator();
clip_menu->Append(Menu_HasText, "Clipboard has &text\tCtrl+T");
clip_menu->Append(Menu_HasBitmap, "Clipboard has a &bitmap\tCtrl+B");
wxMenuBar *menu_bar = new wxMenuBar; wxMenuBar *menu_bar = new wxMenuBar;
menu_bar->Append(file_menu, "&File"); menu_bar->Append(file_menu, "&File");
@@ -598,12 +645,14 @@ DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
wxString strFile("Drop files here!"), strText("Drop text on me"); 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_ctrlFile = new wxListBox(this, -1, pos, size, 1, &strFile,
m_ctrlText = new wxListBox(this, -1, pos, size, 1, &strText, wxLB_HSCROLL | wxLB_ALWAYS_SB ); 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, m_ctrlLog = new wxTextCtrl(this, -1, "", pos, size,
wxTE_MULTILINE | wxTE_READONLY | wxTE_MULTILINE | wxTE_READONLY |
wxSUNKEN_BORDER ); wxSUNKEN_BORDER );
// redirect log messages to the text window and switch on OLE messages // redirect log messages to the text window and switch on OLE messages
// logging // logging
@@ -637,7 +686,7 @@ DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
c = new wxLayoutConstraints; c = new wxLayoutConstraints;
c->left.SameAs (this, wxLeft); c->left.SameAs (this, wxLeft);
c->right.SameAs (this, wxRight); c->right.SameAs (this, wxRight);
c->height.PercentOf(this, wxHeight, 30); c->height.PercentOf(this, wxHeight, 50);
c->top.SameAs(m_ctrlText, wxBottom); c->top.SameAs(m_ctrlText, wxBottom);
m_ctrlLog->SetConstraints(c); m_ctrlLog->SetConstraints(c);
@@ -659,50 +708,23 @@ void DnDFrame::OnPaint(wxPaintEvent& WXUNUSED(event))
dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL, FALSE, "charter" ) ); dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL, FALSE, "charter" ) );
dc.DrawText( "Drag text from here!", 20, h-50 ); dc.DrawText( "Drag text from here!", 20, h-50 );
if (m_bitmap.Ok()) if ( m_bitmap.Ok() )
dc.DrawBitmap( m_bitmap, 280, h-120, TRUE ); {
// 4/5 is 80% taken by other windows, 20 is arbitrary margin
dc.DrawBitmap(m_bitmap,
w - m_bitmap.GetWidth() - 20,
(4*h)/5 + 20);
}
} }
void DnDFrame::OnClipboardHasText(wxCommandEvent& WXUNUSED(event)) void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent& event)
{ {
if ( !wxTheClipboard->Open() ) event.Enable( wxTheClipboard->IsSupported(wxDF_TEXT) );
{
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") );
}
wxTheClipboard->Close();
} }
void DnDFrame::OnClipboardHasBitmap(wxCommandEvent& WXUNUSED(event)) void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent& event)
{ {
if ( !wxTheClipboard->Open() ) event.Enable( wxTheClipboard->IsSupported(wxDF_BITMAP) );
{
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") );
}
wxTheClipboard->Close();
} }
void DnDFrame::OnNewFrame(wxCommandEvent& WXUNUSED(event)) void DnDFrame::OnNewFrame(wxCommandEvent& WXUNUSED(event))
@@ -1097,6 +1119,8 @@ void DnDShapeDialog::OnColour(wxCommandEvent& WXUNUSED(event))
// DnDShapeFrame // DnDShapeFrame
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
DnDShapeFrame *DnDShapeFrame::ms_lastDropTarget = NULL;
DnDShapeFrame::DnDShapeFrame(wxFrame *parent) DnDShapeFrame::DnDShapeFrame(wxFrame *parent)
: wxFrame(parent, -1, "Shape Frame", : wxFrame(parent, -1, "Shape Frame",
wxDefaultPosition, wxSize(250, 150)) wxDefaultPosition, wxSize(250, 150))
@@ -1105,7 +1129,23 @@ DnDShapeFrame::DnDShapeFrame(wxFrame *parent)
CreateStatusBar(); 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\tDel");
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)); SetDropTarget(new DnDShapeDropTarget(this));
@@ -1156,7 +1196,11 @@ void DnDShapeFrame::OnDrag(wxMouseEvent& event)
case wxDragMove: case wxDragMove:
pc = "moved"; pc = "moved";
SetShape(NULL); if ( ms_lastDropTarget != this )
{
// don't delete the shape if we dropped it on ourselves!
SetShape(NULL);
}
break; break;
case wxDragCancel: case wxDragCancel:
@@ -1171,7 +1215,7 @@ void DnDShapeFrame::OnDrag(wxMouseEvent& event)
//else: status text already set //else: status text already set
} }
void DnDShapeFrame::OnEdit(wxMouseEvent& event) void DnDShapeFrame::OnEditShape(wxCommandEvent& event)
{ {
DnDShapeDialog dlg(this, m_shape); DnDShapeDialog dlg(this, m_shape);
if ( dlg.ShowModal() == wxID_OK ) if ( dlg.ShowModal() == wxID_OK )
@@ -1180,11 +1224,52 @@ void DnDShapeFrame::OnEdit(wxMouseEvent& event)
if ( m_shape ) 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::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 )
wxTheClipboard->AddData(new DnDShapeDataObject(m_shape));
}
void DnDShapeFrame::OnPasteShape(wxCommandEvent& event)
{
DnDShapeDataObject shapeDataObject(NULL);
if ( wxTheClipboard->GetData(&shapeDataObject) )
{
SetShape(shapeDataObject.GetShape());
}
else
{
wxLogStatus("No shape on the clipboard");
}
}
void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent& event)
{
event.Enable( m_shape != NULL );
}
void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent& event)
{
event.Enable( wxTheClipboard->IsSupported(wxDataFormat(shapeFormatId)) );
}
void DnDShapeFrame::OnPaint(wxPaintEvent& event) void DnDShapeFrame::OnPaint(wxPaintEvent& event)
{ {
if ( m_shape ) if ( m_shape )
@@ -1195,10 +1280,13 @@ void DnDShapeFrame::OnPaint(wxPaintEvent& event)
void DnDShapeFrame::OnDrop(long x, long y, DnDShape *shape) void DnDShapeFrame::OnDrop(long x, long y, DnDShape *shape)
{ {
ms_lastDropTarget = this;
wxString s; wxString s;
s.Printf("Drop occured at (%ld, %ld)", x, y); s.Printf("Shape dropped at (%ld, %ld)", x, y);
SetStatusText(s); SetStatusText(s);
shape->Move(ScreenToClient(wxPoint(x, y)));
SetShape(shape); SetShape(shape);
} }
@@ -1238,9 +1326,15 @@ DnDShape *DnDShape::New(const void *buf)
void DnDShapeDataObject::CreateBitmap() const 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; wxMemoryDC dc;
dc.SelectObject(bitmap); dc.SelectObject(bitmap);
dc.SetBrush(wxBrush("white", wxSOLID));
dc.Clear();
m_shape->Draw(dc); m_shape->Draw(dc);
dc.SelectObject(wxNullBitmap); dc.SelectObject(wxNullBitmap);

View File

@@ -77,22 +77,14 @@ wxBitmapRefData::wxBitmapRefData()
wxBitmapRefData::~wxBitmapRefData() wxBitmapRefData::~wxBitmapRefData()
{ {
if (m_selectedInto) wxASSERT_MSG( !m_selectedInto,
{ wxT("deleting bitmap still selected into wxMemoryDC") );
wxChar buf[200];
wxSprintf(buf, wxT("Bitmap was deleted without selecting out of wxMemoryDC %lX."), (unsigned long) m_selectedInto);
wxFatalError(buf);
}
if (m_hBitmap)
{
DeleteObject((HBITMAP) m_hBitmap);
}
m_hBitmap = 0 ;
if (m_bitmapMask) if ( m_hBitmap)
delete m_bitmapMask; DeleteObject((HBITMAP) m_hBitmap);
m_bitmapMask = NULL;
if ( m_bitmapMask )
delete m_bitmapMask;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -143,12 +135,9 @@ bool wxBitmap::FreeResource(bool WXUNUSED(force))
if ( !M_BITMAPDATA ) if ( !M_BITMAPDATA )
return FALSE; return FALSE;
if (M_BITMAPDATA->m_selectedInto) wxASSERT_MSG( !M_BITMAPDATA->m_selectedInto,
{ wxT("freeing bitmap still selected into wxMemoryDC") );
wxChar buf[200];
wxSprintf(buf, wxT("Bitmap %lX was deleted without selecting out of wxMemoryDC %lX."), (unsigned long) this, (unsigned long) M_BITMAPDATA->m_selectedInto);
wxFatalError(buf);
}
if (M_BITMAPDATA->m_hBitmap) if (M_BITMAPDATA->m_hBitmap)
{ {
DeleteObject((HBITMAP) M_BITMAPDATA->m_hBitmap); DeleteObject((HBITMAP) M_BITMAPDATA->m_hBitmap);

View File

@@ -57,14 +57,24 @@
#include "wx/msw/private.h" #include "wx/msw/private.h"
#include "wx/msw/dib.h" #include "wx/msw/dib.h"
// wxDataObject is tied to OLE/drag and drop implementation, // wxDataObject is tied to OLE/drag and drop implementation, therefore so are
// therefore so is wxClipboard :-( // the functions using wxDataObject in wxClipboard
#if wxUSE_DRAG_AND_DROP #define wxUSE_DATAOBJ wxUSE_DRAG_AND_DROP
#if wxUSE_DATAOBJ
#include "wx/dataobj.h" #include "wx/dataobj.h"
static bool wxSetClipboardData(wxDataObject *data); // use OLE clipboard
#define wxUSE_OLE_CLIPBOARD 1
#else // !wxUSE_DATAOBJ
// use Win clipboard API
#define wxUSE_OLE_CLIPBOARD 0
#endif #endif
#if wxUSE_OLE_CLIPBOARD
#include <ole2.h>
#endif // wxUSE_OLE_CLIPBOARD
#ifdef __WIN16__ #ifdef __WIN16__
#define memcpy hmemcpy #define memcpy hmemcpy
#endif #endif
@@ -136,41 +146,12 @@ bool wxIsClipboardOpened()
bool wxIsClipboardFormatAvailable(wxDataFormat dataFormat) bool wxIsClipboardFormatAvailable(wxDataFormat dataFormat)
{ {
return ::IsClipboardFormatAvailable(dataFormat) != 0; // for bitmaps, DIBs will also do
return (::IsClipboardFormatAvailable(dataFormat) != 0) ||
(dataFormat.GetFormatId() == CF_BITMAP &&
::IsClipboardFormatAvailable(CF_DIB));
} }
#if wxUSE_DRAG_AND_DROP
static bool wxSetClipboardData(wxDataObject *data)
{
wxDataFormat format = data->GetPreferredFormat();
size_t size = data->GetDataSize(format);
HANDLE hGlobal = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
if ( !hGlobal )
{
wxLogSysError(_("Failed to allocate %dKb of memory for clipboard "
"transfer."), size / 1024);
return FALSE;
}
LPVOID lpGlobalMemory = ::GlobalLock(hGlobal);
data->GetDataHere(format, lpGlobalMemory);
GlobalUnlock(hGlobal);
if ( !::SetClipboardData(format, hGlobal) )
{
wxLogSysError(_("Failed to set clipboard data in format %s"),
wxDataObject::GetFormatName(format));
return FALSE;
}
return TRUE;
}
#endif // wxUSE_DRAG_AND_DROP
bool wxSetClipboardData(wxDataFormat dataFormat, bool wxSetClipboardData(wxDataFormat dataFormat,
const void *data, const void *data,
int width, int height) int width, int height)
@@ -223,7 +204,7 @@ bool wxSetClipboardData(wxDataFormat dataFormat,
// NULL palette means to use the system one // NULL palette means to use the system one
HANDLE hDIB = wxBitmapToDIB(hBitmap, (HPALETTE)NULL); HANDLE hDIB = wxBitmapToDIB(hBitmap, (HPALETTE)NULL);
handle = SetClipboardData(CF_DIB, hDIB); handle = SetClipboardData(CF_DIB, hDIB);
#endif #endif // wxUSE_IMAGE_LOADING_IN_MSW
break; break;
} }
@@ -442,20 +423,51 @@ wxClipboard* wxTheClipboard = (wxClipboard *)NULL;
wxClipboard::wxClipboard() wxClipboard::wxClipboard()
{ {
m_clearOnExit = FALSE;
} }
wxClipboard::~wxClipboard() wxClipboard::~wxClipboard()
{ {
Clear(); if ( m_clearOnExit )
{
Clear();
}
} }
void wxClipboard::Clear() void wxClipboard::Clear()
{ {
#if wxUSE_OLE_CLIPBOARD
if ( FAILED(OleSetClipboard(NULL)) )
{
wxLogLastError("OleSetClipboard(NULL)");
}
#endif
}
bool wxClipboard::Flush()
{
if ( FAILED(OleFlushClipboard()) )
{
wxLogLastError("OleFlushClipboard");
return FALSE;
}
else
{
m_clearOnExit = FALSE;
return TRUE;
}
} }
bool wxClipboard::Open() bool wxClipboard::Open()
{ {
// OLE opens clipboard for us
#if wxUSE_OLE_CLIPBOARD
return TRUE;
#else
return wxOpenClipboard(); return wxOpenClipboard();
#endif
} }
bool wxClipboard::SetData( wxDataObject *data ) bool wxClipboard::SetData( wxDataObject *data )
@@ -472,7 +484,32 @@ bool wxClipboard::AddData( wxDataObject *data )
{ {
wxCHECK_MSG( data, FALSE, wxT("data is invalid") ); wxCHECK_MSG( data, FALSE, wxT("data is invalid") );
#if wxUSE_DRAG_AND_DROP #if wxUSE_OLE_CLIPBOARD
HRESULT hr = OleSetClipboard(data->GetInterface());
if ( FAILED(hr) )
{
wxLogSysError(hr, _("Failed to put data on the clipboard"));
// don't free anything in this case
return FALSE;
}
// we have a problem here because we should delete wxDataObject, but we
// can't do it because IDataObject which we just gave to the clipboard
// would try to use it when it will need the data. IDataObject is ref
// counted and so doesn't suffer from such problem, so we release it now
// and tell it to delete wxDataObject when it is deleted itself.
data->SetAutoDelete();
// we have to call either OleSetClipboard(NULL) or OleFlushClipboard() when
// using OLE clipboard when the app terminates - by default, we call
// OleSetClipboard(NULL) which won't waste RAM, but the app can call
// wxClipboard::Flush() to chaneg this
m_clearOnExit = TRUE;
return TRUE;
#elif wxUSE_DATAOBJ
wxCHECK_MSG( wxIsClipboardOpened(), FALSE, wxT("clipboard not open") ); wxCHECK_MSG( wxIsClipboardOpened(), FALSE, wxT("clipboard not open") );
wxDataFormat format = data->GetFormat(); wxDataFormat format = data->GetFormat();
@@ -510,14 +547,17 @@ bool wxClipboard::AddData( wxDataObject *data )
default: default:
return wxSetClipboardData(data); return wxSetClipboardData(data);
} }
#else // !wxUSE_DRAG_AND_DROP #else // !wxUSE_DATAOBJ
return FALSE; return FALSE;
#endif // wxUSE_DRAG_AND_DROP/!wxUSE_DRAG_AND_DROP #endif // wxUSE_DATAOBJ/!wxUSE_DATAOBJ
} }
void wxClipboard::Close() void wxClipboard::Close()
{ {
// OLE closes clipboard for us
#if !wxUSE_OLE_CLIPBOARD
wxCloseClipboard(); wxCloseClipboard();
#endif
} }
bool wxClipboard::IsSupported( wxDataFormat format ) bool wxClipboard::IsSupported( wxDataFormat format )
@@ -527,9 +567,145 @@ bool wxClipboard::IsSupported( wxDataFormat format )
bool wxClipboard::GetData( wxDataObject *data ) bool wxClipboard::GetData( wxDataObject *data )
{ {
wxCHECK_MSG( data, FALSE, wxT("invalid data object") );
#if wxUSE_OLE_CLIPBOARD
IDataObject *pDataObject = NULL;
HRESULT hr = OleGetClipboard(&pDataObject);
if ( FAILED(hr) || !pDataObject )
{
wxLogSysError(hr, _("Failed to get data from the clipboard"));
return FALSE;
}
// build the list of supported formats
size_t nFormats = data->GetFormatCount(FALSE /* for SetData() */);
wxDataFormat format, *formats;
if ( nFormats == 1 )
{
// the most common case
formats = &format;
}
else
{
// bad luck, need to alloc mem
formats = new wxDataFormat[nFormats];
}
data->GetAllFormats(formats, FALSE);
// get the format enumerator
bool result = FALSE;
wxArrayInt supportedFormats;
IEnumFORMATETC *pEnumFormatEtc = NULL;
hr = pDataObject->EnumFormatEtc(DATADIR_GET, &pEnumFormatEtc);
if ( FAILED(hr) || !pEnumFormatEtc )
{
wxLogSysError(hr,
_("Failed to retrieve the supported clipboard formats"));
}
else
{
// ask for the supported formats and see if there are any we support
FORMATETC formatEtc;
for ( ;; )
{
ULONG nCount;
hr = pEnumFormatEtc->Next(1, &formatEtc, &nCount);
// don't use FAILED() because S_FALSE would pass it
if ( hr != S_OK )
{
// no more formats
break;
}
CLIPFORMAT cf = formatEtc.cfFormat;
#ifdef __WXDEBUG__
wxLogTrace(wxTRACE_OleCalls,
wxT("Object on the clipboard supports format %s."),
wxDataObject::GetFormatName(cf));
#endif // Debug
// is supported?
for ( size_t n = 0; n < nFormats; n++ )
{
if ( formats[n].GetFormatId() == cf )
{
if ( supportedFormats.Index(cf) == wxNOT_FOUND )
{
supportedFormats.Add(cf);
}
}
}
}
pEnumFormatEtc->Release();
}
if ( formats != &format )
{
delete [] formats;
}
//else: we didn't allocate any memory
if ( !supportedFormats.IsEmpty() )
{
FORMATETC formatEtc;
formatEtc.ptd = NULL;
formatEtc.dwAspect = DVASPECT_CONTENT;
formatEtc.lindex = -1;
formatEtc.tymed = TYMED_HGLOBAL;
size_t nSupportedFormats = supportedFormats.GetCount();
for ( size_t n = 0; !result && (n < nSupportedFormats); n++ )
{
STGMEDIUM medium;
formatEtc.cfFormat = supportedFormats[n];
// try to get data
hr = pDataObject->GetData(&formatEtc, &medium);
if ( FAILED(hr) )
{
// try other tymed for GDI objects
if ( formatEtc.cfFormat == CF_BITMAP )
{
formatEtc.tymed = TYMED_HGLOBAL;
hr = pDataObject->GetData(&formatEtc, &medium);
}
}
if ( SUCCEEDED(hr) )
{
// pass the data to the data object
hr = data->GetInterface()->SetData(&formatEtc, &medium, TRUE);
if ( FAILED(hr) )
{
wxLogDebug(wxT("Failed to set data in wxIDataObject"));
// IDataObject only takes the ownership of data if it
// successfully got it - which is not the case here
ReleaseStgMedium(&medium);
}
else
{
result = TRUE;
}
}
//else: unsupported tymed?
}
}
//else: unsupported format
// clean up and return
pDataObject->Release();
return result;
#elif wxUSE_DATAOBJ
wxCHECK_MSG( wxIsClipboardOpened(), FALSE, wxT("clipboard not open") ); wxCHECK_MSG( wxIsClipboardOpened(), FALSE, wxT("clipboard not open") );
#if wxUSE_DRAG_AND_DROP
wxDataFormat format = data->GetFormat(); wxDataFormat format = data->GetFormat();
switch ( format ) switch ( format )
{ {
@@ -593,9 +769,9 @@ bool wxClipboard::GetData( wxDataObject *data )
return FALSE; return FALSE;
} }
#else #else // !wxUSE_DATAOBJ
return FALSE; return FALSE;
#endif #endif // wxUSE_DATAOBJ/!wxUSE_DATAOBJ
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@@ -6,136 +6,137 @@
// Created: 01/02/97 // Created: 01/02/97
// RCS-ID: $Id$ // RCS-ID: $Id$
// Copyright: (c) Julian Smart and Markus Holzem // Copyright: (c) Julian Smart and Markus Holzem
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#ifdef __GNUG__ #ifdef __GNUG__
#pragma implementation "dcmemory.h" #pragma implementation "dcmemory.h"
#endif #endif
// For compilers that support precompilation, includes "wx.h". // For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h" #include "wx/wxprec.h"
#ifdef __BORLANDC__ #ifdef __BORLANDC__
#pragma hdrstop #pragma hdrstop
#endif #endif
#ifndef WX_PRECOMP #ifndef WX_PRECOMP
#include "wx/utils.h" #include "wx/utils.h"
#endif #endif
#include "wx/msw/private.h" #include "wx/msw/private.h"
#include "wx/dcmemory.h" #include "wx/dcmemory.h"
// ----------------------------------------------------------------------------
// wxWin macros
// ----------------------------------------------------------------------------
#if !USE_SHARED_LIBRARY #if !USE_SHARED_LIBRARY
IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC) IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC)
#endif #endif
/* // ============================================================================
* Memory DC // implementation
* // ============================================================================
*/
wxMemoryDC::wxMemoryDC(void) // ----------------------------------------------------------------------------
// wxMemoryDC
// ----------------------------------------------------------------------------
wxMemoryDC::wxMemoryDC()
{ {
m_hDC = (WXHDC) ::CreateCompatibleDC((HDC) NULL); m_hDC = (WXHDC) ::CreateCompatibleDC((HDC) NULL);
m_ok = (m_hDC != 0); m_ok = (m_hDC != 0);
m_bOwnsDC = TRUE; m_bOwnsDC = TRUE;
SetBrush(*wxWHITE_BRUSH); SetBrush(*wxWHITE_BRUSH);
SetPen(*wxBLACK_PEN); SetPen(*wxBLACK_PEN);
// the background mode is only used for text background
// and is set in DrawText() to OPAQUE as required, other-
// wise always TRANSPARENT, RR
::SetBkMode( GetHdc(), TRANSPARENT );
// the background mode is only used for text background and is set in
// DrawText() to OPAQUE as required, otherwise always TRANSPARENT
::SetBkMode( GetHdc(), TRANSPARENT );
} }
wxMemoryDC::wxMemoryDC(wxDC *old_dc) wxMemoryDC::wxMemoryDC(wxDC *old_dc)
{ {
old_dc->BeginDrawing(); old_dc->BeginDrawing();
m_hDC = (WXHDC) ::CreateCompatibleDC((HDC) old_dc->GetHDC()); m_hDC = (WXHDC) ::CreateCompatibleDC(GetHdcOf(*old_dc));
m_ok = (m_hDC != 0); m_ok = (m_hDC != 0);
old_dc->EndDrawing(); old_dc->EndDrawing();
SetBrush(*wxWHITE_BRUSH); SetBrush(*wxWHITE_BRUSH);
SetPen(*wxBLACK_PEN); SetPen(*wxBLACK_PEN);
// the background mode is only used for text background
// and is set in DrawText() to OPAQUE as required, other-
// wise always TRANSPARENT, RR
::SetBkMode( GetHdc(), TRANSPARENT );
// the background mode is only used for text background and is set in
// DrawText() to OPAQUE as required, otherwise always TRANSPARENT
::SetBkMode( GetHdc(), TRANSPARENT );
} }
wxMemoryDC::~wxMemoryDC(void) wxMemoryDC::~wxMemoryDC()
{ {
} }
void wxMemoryDC::SelectObject(const wxBitmap& bitmap) void wxMemoryDC::SelectObject(const wxBitmap& bitmap)
{ {
// Select old bitmap out of the device context // select old bitmap out of the device context
if (m_oldBitmap) if ( m_oldBitmap )
{
::SelectObject((HDC) m_hDC, (HBITMAP) m_oldBitmap);
if (m_selectedBitmap.Ok())
{ {
m_selectedBitmap.SetSelectedInto(NULL); ::SelectObject(GetHdc(), (HBITMAP) m_oldBitmap);
m_selectedBitmap = wxNullBitmap; if ( m_selectedBitmap.Ok() )
{
m_selectedBitmap.SetSelectedInto(NULL);
m_selectedBitmap = wxNullBitmap;
}
} }
}
// Do own check for whether the bitmap is already selected into // check for whether the bitmap is already selected into a device context
// a device context wxCHECK_RET( !bitmap.GetSelectedInto() ||
if (bitmap.GetSelectedInto() && (bitmap.GetSelectedInto() != this)) (bitmap.GetSelectedInto() == this),
{ wxT("Bitmap is selected in another wxMemoryDC, delete the "
wxFatalError(wxT("Error in wxMemoryDC::SelectObject\nBitmap is selected in another wxMemoryDC.\nDelete the first wxMemoryDC or use SelectObject(NULL)")); "first wxMemoryDC or use SelectObject(NULL)") );
return;
}
// Check if the bitmap has the correct depth for this device context m_selectedBitmap = bitmap;
// if (bitmap.Ok() && (bitmap.GetDepth() != GetDepth())) WXHBITMAP hBmp = m_selectedBitmap.GetHBITMAP();
// JACS 11/12/98: disabling this since the Forty Thieves sample if ( !hBmp )
// shows this not working properly. In fact, if loading from a resource, return;
// the depth should become the screen depth, so why was it being called?
// if (0)
// {
// // Make a new bitmap that has the correct depth.
// wxBitmap newBitmap = bitmap.GetBitmapForDC(* this);
//
// m_selectedBitmap = newBitmap ;
// }
// else
// {
m_selectedBitmap = bitmap;
// }
if (!m_selectedBitmap.Ok()) m_selectedBitmap.SetSelectedInto(this);
return; hBmp = (WXHBITMAP)::SelectObject(GetHdc(), (HBITMAP)hBmp);
m_selectedBitmap.SetSelectedInto(this); if ( !hBmp )
HBITMAP bm = (HBITMAP) ::SelectObject((HDC) m_hDC, (HBITMAP) m_selectedBitmap.GetHBITMAP()); {
wxLogLastError("SelectObject(memDC, bitmap)");
if (bm == ERROR) wxFAIL_MSG(wxT("Couldn't select a bitmap into wxMemoryDC"));
{ }
wxFatalError(wxT("Error in wxMemoryDC::SelectObject\nBitmap may not be loaded, or may be selected in another wxMemoryDC.\nDelete the first wxMemoryDC to deselect bitmap.")); else if ( !m_oldBitmap )
} {
else if (!m_oldBitmap) m_oldBitmap = hBmp;
m_oldBitmap = (WXHBITMAP) bm; }
} }
void wxMemoryDC::DoGetSize(int *width, int *height) const void wxMemoryDC::DoGetSize(int *width, int *height) const
{ {
if (!m_selectedBitmap.Ok()) if ( m_selectedBitmap.Ok() )
{ {
*width = 0; *height = 0; *width = m_selectedBitmap.GetWidth();
return; *height = m_selectedBitmap.GetHeight();
} }
*width = m_selectedBitmap.GetWidth(); else
*height = m_selectedBitmap.GetHeight(); {
*width = 0;
*height = 0;
}
} }

View File

@@ -705,9 +705,9 @@ wxPoint wxFrame::GetClientAreaOrigin() const
return pt; return pt;
} }
void wxFrame::ScreenToClient(int *x, int *y) const void wxFrame::DoScreenToClient(int *x, int *y) const
{ {
wxWindow::ScreenToClient(x, y); wxWindow::DoScreenToClient(x, y);
// We may be faking the client origin. // We may be faking the client origin.
// So a window that's really at (0, 30) may appear // So a window that's really at (0, 30) may appear
@@ -717,7 +717,7 @@ void wxFrame::ScreenToClient(int *x, int *y) const
*y -= pt.y; *y -= pt.y;
} }
void wxFrame::ClientToScreen(int *x, int *y) const void wxFrame::DoClientToScreen(int *x, int *y) const
{ {
// We may be faking the client origin. // We may be faking the client origin.
// So a window that's really at (0, 30) may appear // So a window that's really at (0, 30) may appear
@@ -726,7 +726,7 @@ void wxFrame::ClientToScreen(int *x, int *y) const
*x += pt1.x; *x += pt1.x;
*y += pt1.y; *y += pt1.y;
wxWindow::ClientToScreen(x, y); wxWindow::DoClientToScreen(x, y);
} }
#if wxUSE_TOOLBAR #if wxUSE_TOOLBAR

View File

@@ -55,7 +55,7 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#ifdef __WXDEBUG__ #ifdef __WXDEBUG__
static const char *GetTymedName(DWORD tymed); static const wxChar *GetTymedName(DWORD tymed);
#endif // Debug #endif // Debug
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -90,6 +90,12 @@ class wxIDataObject : public IDataObject
{ {
public: public:
wxIDataObject(wxDataObject *pDataObject); wxIDataObject(wxDataObject *pDataObject);
~wxIDataObject();
// normally, wxDataObject controls our lifetime (i.e. we're deleted when it
// is), but in some cases, the situation is inversed, that is we delete it
// when this object is deleted - setting this flag enables such logic
void SetDeleteFlag() { m_mustDelete = TRUE; }
DECLARE_IUNKNOWN_METHODS; DECLARE_IUNKNOWN_METHODS;
@@ -106,6 +112,24 @@ public:
private: private:
wxDataObject *m_pDataObject; // pointer to C++ class we belong to wxDataObject *m_pDataObject; // pointer to C++ class we belong to
bool m_mustDelete;
};
// ----------------------------------------------------------------------------
// small helper class for getting screen DC (we're working with bitmaps and
// DIBs here)
// ----------------------------------------------------------------------------
class ScreenHDC
{
public:
ScreenHDC() { m_hdc = GetDC(NULL); }
~ScreenHDC() { ReleaseDC(NULL, m_hdc); }
operator HDC() const { return m_hdc; }
private:
HDC m_hdc;
}; };
// ============================================================================ // ============================================================================
@@ -251,6 +275,15 @@ wxIDataObject::wxIDataObject(wxDataObject *pDataObject)
{ {
m_cRef = 0; m_cRef = 0;
m_pDataObject = pDataObject; m_pDataObject = pDataObject;
m_mustDelete = FALSE;
}
wxIDataObject::~wxIDataObject()
{
if ( m_mustDelete )
{
delete m_pDataObject;
}
} }
// get data functions // get data functions
@@ -323,7 +356,8 @@ STDMETHODIMP wxIDataObject::GetDataHere(FORMATETC *pformatetc,
switch ( pmedium->tymed ) switch ( pmedium->tymed )
{ {
case TYMED_GDI: case TYMED_GDI:
m_pDataObject->GetDataHere(wxDF_BITMAP, &pmedium->hBitmap); if ( !m_pDataObject->GetDataHere(wxDF_BITMAP, &pmedium->hBitmap) )
return E_UNEXPECTED;
break; break;
case TYMED_MFPICT: case TYMED_MFPICT:
@@ -342,7 +376,8 @@ STDMETHODIMP wxIDataObject::GetDataHere(FORMATETC *pformatetc,
} }
wxDataFormat format = (wxDataFormatId)pformatetc->cfFormat; wxDataFormat format = (wxDataFormatId)pformatetc->cfFormat;
m_pDataObject->GetDataHere(format, pBuf); if ( !m_pDataObject->GetDataHere(format, pBuf) )
return E_UNEXPECTED;
GlobalUnlock(pmedium->hGlobal); GlobalUnlock(pmedium->hGlobal);
} }
@@ -360,66 +395,117 @@ STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc,
STGMEDIUM *pmedium, STGMEDIUM *pmedium,
BOOL fRelease) BOOL fRelease)
{ {
wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::SetData")); wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::SetData"));
return E_NOTIMPL; switch ( pmedium->tymed )
{
case TYMED_GDI:
m_pDataObject->SetData(wxDF_BITMAP, &pmedium->hBitmap);
break;
case TYMED_MFPICT:
// this should be copied on bitmaps - but I don't have time for
// this now
wxFAIL_MSG(wxT("TODO - no support for metafiles in wxDataObject"));
break;
case TYMED_HGLOBAL:
{
// copy data
void *pBuf = GlobalLock(pmedium->hGlobal);
if ( pBuf == NULL ) {
wxLogLastError("GlobalLock");
return E_OUTOFMEMORY;
}
wxDataFormat format = (wxDataFormatId)pformatetc->cfFormat;
m_pDataObject->SetData(format, pBuf);
GlobalUnlock(pmedium->hGlobal);
}
break;
default:
return DV_E_TYMED;
}
if ( fRelease ) {
// we own the medium, so we must release it - but do *not* free the
// bitmap handle fi we have it because we have copied it elsewhere
if ( pmedium->tymed == TYMED_GDI )
{
pmedium->hBitmap = 0;
}
ReleaseStgMedium(pmedium);
}
return S_OK;
} }
// information functions // information functions
STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc) STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc)
{ {
// do we accept data in this format? // do we accept data in this format?
if ( pformatetc == NULL ) { if ( pformatetc == NULL ) {
wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: invalid ptr.")); wxLogTrace(wxTRACE_OleCalls,
wxT("wxIDataObject::QueryGetData: invalid ptr."));
return E_INVALIDARG; return E_INVALIDARG;
} }
// the only one allowed by current COM implementation // the only one allowed by current COM implementation
if ( pformatetc->lindex != -1 ) { if ( pformatetc->lindex != -1 ) {
wxLogTrace(wxTRACE_OleCalls, wxLogTrace(wxTRACE_OleCalls,
wxT("wxIDataObject::QueryGetData: bad lindex %d"), wxT("wxIDataObject::QueryGetData: bad lindex %d"),
pformatetc->lindex); pformatetc->lindex);
return DV_E_LINDEX;
}
// we don't support anything other (THUMBNAIL, ICON, DOCPRINT...) return DV_E_LINDEX;
if ( pformatetc->dwAspect != DVASPECT_CONTENT ) { }
wxLogTrace(wxTRACE_OleCalls,
wxT("wxIDataObject::QueryGetData: bad dwAspect %d"),
pformatetc->dwAspect);
return DV_E_DVASPECT;
}
// we only transfer data by global memory, except for some particular cases // we don't support anything other (THUMBNAIL, ICON, DOCPRINT...)
wxDataFormat format = (wxDataFormatId)pformatetc->cfFormat; if ( pformatetc->dwAspect != DVASPECT_CONTENT ) {
DWORD tymed = pformatetc->tymed; wxLogTrace(wxTRACE_OleCalls,
if ( (format == wxDF_BITMAP && !(tymed & TYMED_GDI)) || wxT("wxIDataObject::QueryGetData: bad dwAspect %d"),
!(tymed & TYMED_HGLOBAL) ) { pformatetc->dwAspect);
// it's not what we're waiting for
return DV_E_DVASPECT;
}
// and now check the type of data requested
wxDataFormat format = (wxDataFormatId)pformatetc->cfFormat;
if ( m_pDataObject->IsSupportedFormat(format) ) {
#ifdef __WXDEBUG__ #ifdef __WXDEBUG__
wxLogTrace(wxTRACE_OleCalls, wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: %s ok"),
wxT("wxIDataObject::QueryGetData: %s & %s == 0."), wxDataObject::GetFormatName(format));
GetTymedName(tymed),
GetTymedName(format == wxDF_BITMAP ? TYMED_GDI : TYMED_HGLOBAL));
#endif // Debug #endif // Debug
return DV_E_TYMED; }
} else {
wxLogTrace(wxTRACE_OleCalls,
wxT("wxIDataObject::QueryGetData: %s unsupported"),
wxDataObject::GetFormatName(format));
// and now check the type of data requested return DV_E_FORMATETC;
if ( m_pDataObject->IsSupportedFormat(format) ) { }
// we only transfer data by global memory, except for some particular cases
DWORD tymed = pformatetc->tymed;
if ( (format == wxDF_BITMAP && !(tymed & TYMED_GDI)) &&
!(tymed & TYMED_HGLOBAL) ) {
// it's not what we're waiting for
#ifdef __WXDEBUG__ #ifdef __WXDEBUG__
wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: %s ok"), wxLogTrace(wxTRACE_OleCalls,
wxDataObject::GetFormatName(format)); wxT("wxIDataObject::QueryGetData: %s != %s"),
GetTymedName(tymed),
GetTymedName(format == wxDF_BITMAP ? TYMED_GDI
: TYMED_HGLOBAL));
#endif // Debug #endif // Debug
return DV_E_TYMED;
}
return S_OK; return S_OK;
}
else {
wxLogTrace(wxTRACE_OleCalls,
wxT("wxIDataObject::QueryGetData: %s unsupported"),
wxDataObject::GetFormatName((wxDataFormatId)pformatetc->cfFormat));
return DV_E_FORMATETC;
}
} }
STDMETHODIMP wxIDataObject::GetCanonicalFormatEtc(FORMATETC *pFormatetcIn, STDMETHODIMP wxIDataObject::GetCanonicalFormatEtc(FORMATETC *pFormatetcIn,
@@ -439,12 +525,9 @@ STDMETHODIMP wxIDataObject::EnumFormatEtc(DWORD dwDirection,
{ {
wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::EnumFormatEtc")); wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::EnumFormatEtc"));
if ( dwDirection == DATADIR_SET ) { bool allowOutputOnly = dwDirection == DATADIR_GET;
// we don't allow setting of data anyhow
return E_NOTIMPL;
}
size_t nFormatCount = m_pDataObject->GetFormatCount(); size_t nFormatCount = m_pDataObject->GetFormatCount(allowOutputOnly);
wxDataFormat format, *formats; wxDataFormat format, *formats;
if ( nFormatCount == 1 ) { if ( nFormatCount == 1 ) {
// this is the most common case, this is why we consider it separately // this is the most common case, this is why we consider it separately
@@ -454,7 +537,7 @@ STDMETHODIMP wxIDataObject::EnumFormatEtc(DWORD dwDirection,
else { else {
// bad luck, build the array with all formats // bad luck, build the array with all formats
formats = new wxDataFormat[nFormatCount]; formats = new wxDataFormat[nFormatCount];
m_pDataObject->GetAllFormats(formats); m_pDataObject->GetAllFormats(formats, allowOutputOnly);
} }
wxIEnumFORMATETC *pEnum = new wxIEnumFORMATETC(formats, nFormatCount); wxIEnumFORMATETC *pEnum = new wxIEnumFORMATETC(formats, nFormatCount);
@@ -493,13 +576,22 @@ STDMETHODIMP wxIDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
wxDataObject::wxDataObject() wxDataObject::wxDataObject()
{ {
m_pIDataObject = new wxIDataObject(this); m_pIDataObject = new wxIDataObject(this);
m_pIDataObject->AddRef(); m_pIDataObject->AddRef();
} }
wxDataObject::~wxDataObject() wxDataObject::~wxDataObject()
{ {
m_pIDataObject->Release(); ReleaseInterface(m_pIDataObject);
}
void wxDataObject::SetAutoDelete()
{
((wxIDataObject *)m_pIDataObject)->SetDeleteFlag();
m_pIDataObject->Release();
// so that the dtor doesnt' crash
m_pIDataObject = NULL;
} }
bool wxDataObject::IsSupportedFormat(const wxDataFormat& format) const bool wxDataObject::IsSupportedFormat(const wxDataFormat& format) const
@@ -552,7 +644,7 @@ const char *wxDataObject::GetFormatName(wxDataFormat format)
case CF_HDROP: return "CF_HDROP"; case CF_HDROP: return "CF_HDROP";
case CF_LOCALE: return "CF_LOCALE"; case CF_LOCALE: return "CF_LOCALE";
default: default:
sprintf(s_szBuf, "clipboard format %d (unknown)", format); sprintf(s_szBuf, "clipboard format 0x%x (unknown)", format);
return s_szBuf; return s_szBuf;
} }
@@ -604,9 +696,21 @@ void wxPrivateDataObject::WriteData( const void *data, void *dest ) const
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxBitmapDataObject // wxBitmapDataObject: it supports standard CF_BITMAP and CF_DIB formats
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
size_t wxBitmapDataObject::GetFormatCount(bool outputOnlyToo) const
{
return 2;
}
void wxBitmapDataObject::GetAllFormats(wxDataFormat *formats,
bool outputOnlyToo) const
{
formats[0] = CF_BITMAP;
formats[1] = CF_DIB;
}
// the bitmaps aren't passed by value as other types of data (i.e. by copyign // the bitmaps aren't passed by value as other types of data (i.e. by copyign
// the data into a global memory chunk and passing it to the clipboard or // the data into a global memory chunk and passing it to the clipboard or
// another application or whatever), but by handle, so these generic functions // another application or whatever), but by handle, so these generic functions
@@ -614,15 +718,118 @@ void wxPrivateDataObject::WriteData( const void *data, void *dest ) const
size_t wxBitmapDataObject::GetDataSize(const wxDataFormat& format) const size_t wxBitmapDataObject::GetDataSize(const wxDataFormat& format) const
{ {
// no data to copy anyhow if ( format.GetFormatId() == CF_DIB )
return 0; {
// create the DIB
ScreenHDC hdc;
// shouldn't be selected into a DC or GetDIBits() would fail
wxASSERT_MSG( !m_bitmap.GetSelectedInto(),
wxT("can't copy bitmap selected into wxMemoryDC") );
// first get the info
BITMAPINFO bi;
if ( !GetDIBits(hdc, (HBITMAP)m_bitmap.GetHBITMAP(), 0, 0,
NULL, &bi, DIB_RGB_COLORS) )
{
wxLogLastError("GetDIBits(NULL)");
return 0;
}
return sizeof(BITMAPINFO) + bi.bmiHeader.biSizeImage;
}
else // CF_BITMAP
{
// no data to copy - we don't pass HBITMAP via global memory
return 0;
}
} }
void wxBitmapDataObject::GetDataHere(const wxDataFormat& format, bool wxBitmapDataObject::GetDataHere(const wxDataFormat& format,
void *pBuf) const void *pBuf) const
{ {
// we put a bitmap handle into pBuf wxASSERT_MSG( m_bitmap.Ok(), wxT("copying invalid bitmap") );
*(WXHBITMAP *)pBuf = m_bitmap.GetHBITMAP();
HBITMAP hbmp = (HBITMAP)m_bitmap.GetHBITMAP();
if ( format.GetFormatId() == CF_DIB )
{
// create the DIB
ScreenHDC hdc;
// shouldn't be selected into a DC or GetDIBits() would fail
wxASSERT_MSG( !m_bitmap.GetSelectedInto(),
wxT("can't copy bitmap selected into wxMemoryDC") );
// first get the info
BITMAPINFO *pbi = (BITMAPINFO *)pBuf;
if ( !GetDIBits(hdc, hbmp, 0, 0, NULL, pbi, DIB_RGB_COLORS) )
{
wxLogLastError("GetDIBits(NULL)");
return 0;
}
// and now copy the bits
if ( !GetDIBits(hdc, hbmp, 0, pbi->bmiHeader.biHeight, pbi + 1,
pbi, DIB_RGB_COLORS) )
{
wxLogLastError("GetDIBits");
return FALSE;
}
}
else // CF_BITMAP
{
// we put a bitmap handle into pBuf
*(HBITMAP *)pBuf = hbmp;
}
return TRUE;
}
bool wxBitmapDataObject::SetData(const wxDataFormat& format, const void *pBuf)
{
HBITMAP hbmp;
if ( format.GetFormatId() == CF_DIB )
{
// here we get BITMAPINFO struct followed by the actual bitmap bits and
// BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
ScreenHDC hdc;
BITMAPINFO *pbmi = (BITMAPINFO *)pBuf;
BITMAPINFOHEADER *pbmih = &pbmi->bmiHeader;
hbmp = CreateDIBitmap(hdc, pbmih, CBM_INIT,
pbmi + 1, pbmi, DIB_RGB_COLORS);
if ( !hbmp )
{
wxLogLastError("CreateDIBitmap");
}
m_bitmap.SetWidth(pbmih->biWidth);
m_bitmap.SetHeight(pbmih->biHeight);
}
else // CF_BITMAP
{
// it's easy with bitmaps: we pass them by handle
hbmp = *(HBITMAP *)pBuf;
BITMAP bmp;
if ( !GetObject(hbmp, sizeof(BITMAP), &bmp) )
{
wxLogLastError("GetObject(HBITMAP)");
}
m_bitmap.SetWidth(bmp.bmWidth);
m_bitmap.SetHeight(bmp.bmHeight);
m_bitmap.SetDepth(bmp.bmPlanes);
}
m_bitmap.SetHBITMAP((WXHBITMAP)hbmp);
wxASSERT_MSG( m_bitmap.Ok(), wxT("pasting invalid bitmap") );
return TRUE;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -631,24 +838,24 @@ void wxBitmapDataObject::GetDataHere(const wxDataFormat& format,
#ifdef __WXDEBUG__ #ifdef __WXDEBUG__
static const char *GetTymedName(DWORD tymed) static const wxChar *GetTymedName(DWORD tymed)
{ {
static char s_szBuf[128]; static wxChar s_szBuf[128];
switch ( tymed ) { switch ( tymed ) {
case TYMED_HGLOBAL: return "TYMED_HGLOBAL"; case TYMED_HGLOBAL: return wxT("TYMED_HGLOBAL");
case TYMED_FILE: return "TYMED_FILE"; case TYMED_FILE: return wxT("TYMED_FILE");
case TYMED_ISTREAM: return "TYMED_ISTREAM"; case TYMED_ISTREAM: return wxT("TYMED_ISTREAM");
case TYMED_ISTORAGE: return "TYMED_ISTORAGE"; case TYMED_ISTORAGE: return wxT("TYMED_ISTORAGE");
case TYMED_GDI: return "TYMED_GDI"; case TYMED_GDI: return wxT("TYMED_GDI");
case TYMED_MFPICT: return "TYMED_MFPICT"; case TYMED_MFPICT: return wxT("TYMED_MFPICT");
case TYMED_ENHMF: return "TYMED_ENHMF"; case TYMED_ENHMF: return wxT("TYMED_ENHMF");
default: default:
sprintf(s_szBuf, "type of media format %d (unknown)", tymed); wxSprintf(s_szBuf, wxT("type of media format %d (unknown)"), tymed);
return s_szBuf; return s_szBuf;
} }
} }
#endif // Debug #endif // Debug
#endif #endif // not using OLE at all