X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/57c208c5759da71a637f0f0f5b7d3dc3eda09c02..9d5507f7a2701395e1d5c121bd877bb9066ee6ea:/src/msw/dcmemory.cpp diff --git a/src/msw/dcmemory.cpp b/src/msw/dcmemory.cpp index dd76ffcd3a..6869e6f4e4 100644 --- a/src/msw/dcmemory.cpp +++ b/src/msw/dcmemory.cpp @@ -1,129 +1,211 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: dcmemory.cpp +// Name: src/msw/dcmemory.cpp // Purpose: wxMemoryDC class // Author: Julian Smart // Modified by: // Created: 01/02/97 // RCS-ID: $Id$ -// Copyright: (c) Julian Smart and Markus Holzem -// Licence: wxWindows licence +// Copyright: (c) Julian Smart +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation "dcmemory.h" -#endif +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ -#pragma hdrstop + #pragma hdrstop #endif +#include "wx/dcmemory.h" +#include "wx/msw/dcmemory.h" + #ifndef WX_PRECOMP -#include "wx/utils.h" + #include "wx/utils.h" + #include "wx/log.h" #endif -#include "wx/dcmemory.h" +#include "wx/msw/private.h" -#include +// ---------------------------------------------------------------------------- +// wxMemoryDCImpl +// ---------------------------------------------------------------------------- -#if !USE_SHARED_LIBRARY -IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC) -#endif +IMPLEMENT_ABSTRACT_CLASS(wxMemoryDCImpl, wxMSWDCImpl) -/* - * Memory DC - * - */ +wxMemoryDCImpl::wxMemoryDCImpl( wxMemoryDC *owner ) + : wxMSWDCImpl( owner ) +{ + CreateCompatible(NULL); + Init(); +} + +wxMemoryDCImpl::wxMemoryDCImpl( wxMemoryDC *owner, wxBitmap& bitmap ) + : wxMSWDCImpl( owner ) +{ + CreateCompatible(NULL); + Init(); + DoSelect(bitmap); +} -wxMemoryDC::wxMemoryDC(void) +wxMemoryDCImpl::wxMemoryDCImpl( wxMemoryDC *owner, wxDC *dc ) + : wxMSWDCImpl( owner ) { - m_hDC = (WXHDC) ::CreateCompatibleDC((HDC) NULL); - m_ok = (m_hDC != 0); - m_bOwnsDC = TRUE; + wxCHECK_RET( dc, _T("NULL dc in wxMemoryDC ctor") ); - SetBrush(*wxWHITE_BRUSH); - SetPen(*wxBLACK_PEN); + CreateCompatible(dc); + + Init(); } -wxMemoryDC::wxMemoryDC(wxDC *old_dc) +void wxMemoryDCImpl::Init() { - old_dc->BeginDrawing(); + if ( m_ok ) + { + SetBrush(*wxWHITE_BRUSH); + SetPen(*wxBLACK_PEN); - m_hDC = (WXHDC) ::CreateCompatibleDC((HDC) old_dc->GetHDC()); - m_ok = (m_hDC != 0); + // the background mode is only used for text background and is set in + // DrawText() to OPAQUE as required, otherwise always TRANSPARENT + ::SetBkMode( GetHdc(), TRANSPARENT ); + } +} + +bool wxMemoryDCImpl::CreateCompatible(wxDC *dc) +{ + wxDCImpl *impl = dc ? dc->GetImpl() : NULL ; + wxMSWDCImpl *msw_impl = wxDynamicCast( impl, wxMSWDCImpl ); + if ( dc && !msw_impl) + { + m_ok = false; + return false; + } + + m_hDC = (WXHDC)::CreateCompatibleDC(dc ? GetHdcOf(*msw_impl) : NULL); - old_dc->EndDrawing(); + // as we created the DC, we must delete it in the dtor + m_bOwnsDC = true; - SetBrush(*wxWHITE_BRUSH); - SetPen(*wxBLACK_PEN); + m_ok = m_hDC != 0; + + return m_ok; } -wxMemoryDC::~wxMemoryDC(void) +void wxMemoryDCImpl::DoSelect( const wxBitmap& bitmap ) { + // select old bitmap out of the device context + if ( m_oldBitmap ) + { + ::SelectObject(GetHdc(), (HBITMAP) m_oldBitmap); + if ( m_selectedBitmap.Ok() ) + { +#ifdef __WXDEBUG__ + m_selectedBitmap.SetSelectedInto(NULL); +#endif + m_selectedBitmap = wxNullBitmap; + } + } + + // check for whether the bitmap is already selected into a device context + wxASSERT_MSG( !bitmap.GetSelectedInto() || + (bitmap.GetSelectedInto() == GetOwner()), + wxT("Bitmap is selected in another wxMemoryDC, delete the first wxMemoryDC or use SelectObject(NULL)") ); + + m_selectedBitmap = bitmap; + WXHBITMAP hBmp = m_selectedBitmap.GetHBITMAP(); + if ( !hBmp ) + return; + +#ifdef __WXDEBUG__ + m_selectedBitmap.SetSelectedInto(GetOwner()); +#endif + hBmp = (WXHBITMAP)::SelectObject(GetHdc(), (HBITMAP)hBmp); + + if ( !hBmp ) + { + wxLogLastError(wxT("SelectObject(memDC, bitmap)")); + + wxFAIL_MSG(wxT("Couldn't select a bitmap into wxMemoryDC")); + } + else if ( !m_oldBitmap ) + { + m_oldBitmap = hBmp; + } } -void wxMemoryDC::SelectObject(const wxBitmap& bitmap) +void wxMemoryDCImpl::DoGetSize(int *width, int *height) const { - // Select old bitmap out of the device context - if (m_oldBitmap) - { - ::SelectObject((HDC) m_hDC, (HBITMAP) m_oldBitmap); - if (m_selectedBitmap.Ok()) + if ( m_selectedBitmap.Ok() ) + { + *width = m_selectedBitmap.GetWidth(); + *height = m_selectedBitmap.GetHeight(); + } + else { - m_selectedBitmap.SetSelectedInto(NULL); - m_selectedBitmap = wxNullBitmap; + *width = 0; + *height = 0; } - } - - // Do own check for whether the bitmap is already selected into - // a device context - if (bitmap.GetSelectedInto() && (bitmap.GetSelectedInto() != this)) - { - wxFatalError("Error in wxMemoryDC::SelectObject\nBitmap is selected in another wxMemoryDC.\nDelete the first wxMemoryDC or use SelectObject(NULL)"); - return; - } - - // Check if the bitmap has the correct depth for this device context -// if (bitmap.Ok() && (bitmap.GetDepth() != GetDepth())) - // JACS 11/12/98: disabling this since the Forty Thieves sample - // shows this not working properly. In fact, if loading from a resource, - // 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()) - return; - - m_selectedBitmap.SetSelectedInto(this); - HBITMAP bm = (HBITMAP) ::SelectObject((HDC) m_hDC, (HBITMAP) m_selectedBitmap.GetHBITMAP()); - - if (bm == ERROR) - { - wxFatalError("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) - m_oldBitmap = (WXHBITMAP) bm; } -void wxMemoryDC::GetSize(int *width, int *height) const +// the rest of this file deals with drawing rectangles workaround, disabled by +// default + +#define wxUSE_MEMORY_DC_DRAW_RECTANGLE 0 + +#if wxUSE_MEMORY_DC_DRAW_RECTANGLE + +// For some reason, drawing a rectangle on a memory DC has problems. +// Use this substitute if we can. +static void wxDrawRectangle(wxDC& dc, wxCoord x, wxCoord y, wxCoord width, wxCoord height) { - if (!m_selectedBitmap.Ok()) - { - *width = 0; *height = 0; - return; - } - *width = m_selectedBitmap.GetWidth(); - *height = m_selectedBitmap.GetHeight(); + wxBrush brush(dc.GetBrush()); + wxPen pen(dc.GetPen()); + if (brush.Ok() && brush.GetStyle() != wxTRANSPARENT) + { + HBRUSH hBrush = (HBRUSH) brush.GetResourceHandle() ; + if (hBrush) + { + RECT rect; + rect.left = x; rect.top = y; + rect.right = x + width - 1; + rect.bottom = y + height - 1; + ::FillRect((HDC) dc.GetHDC(), &rect, hBrush); + } + } + width --; height --; + if (pen.Ok() && pen.GetStyle() != wxTRANSPARENT) + { + dc.DrawLine(x, y, x + width, y); + dc.DrawLine(x, y, x, y + height); + dc.DrawLine(x, y+height, x+width, y + height); + dc.DrawLine(x+width, y+height, x+width, y); + } } +#endif // wxUSE_MEMORY_DC_DRAW_RECTANGLE + +void wxMemoryDCImpl::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height) +{ + // Set this to 1 to work around an apparent video driver bug + // (visible with e.g. 70x70 rectangle on a memory DC; see Drawing sample) +#if wxUSE_MEMORY_DC_DRAW_RECTANGLE + if (m_brush.Ok() && m_pen.Ok() && + (m_brush.GetStyle() == wxSOLID || m_brush.GetStyle() == wxTRANSPARENT) && + (m_pen.GetStyle() == wxSOLID || m_pen.GetStyle() == wxTRANSPARENT) && + (GetLogicalFunction() == wxCOPY)) + { + wxDrawRectangle(* this, x, y, width, height); + } + else +#endif // wxUSE_MEMORY_DC_DRAW_RECTANGLE + { + wxMSWDCImpl::DoDrawRectangle(x, y, width, height); + } +}