📄 dc.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// Name: src/msw/dc.cpp
// Purpose: wxDC class for MSW port
// Author: Julian Smart
// Modified by:
// Created: 01/02/97
// RCS-ID: $Id: dc.cpp,v 1.193.2.3 2006/03/15 09:50:11 JS Exp $
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ===========================================================================
// declarations
// ===========================================================================
// ---------------------------------------------------------------------------
// headers
// ---------------------------------------------------------------------------
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "dc.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/image.h"
#include "wx/window.h"
#include "wx/dc.h"
#include "wx/utils.h"
#include "wx/dialog.h"
#include "wx/app.h"
#include "wx/bitmap.h"
#include "wx/dcmemory.h"
#include "wx/log.h"
#include "wx/icon.h"
#endif
#include "wx/sysopt.h"
#include "wx/dcprint.h"
#include "wx/module.h"
#include "wx/dynlib.h"
#ifdef wxHAVE_RAW_BITMAP
#include "wx/rawbmp.h"
#endif
#include <string.h>
#include "wx/msw/wrapcdlg.h"
#ifndef __WIN32__
#include <print.h>
#endif
#ifndef AC_SRC_ALPHA
#define AC_SRC_ALPHA 1
#endif
/* Quaternary raster codes */
#ifndef MAKEROP4
#define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
#endif
// apparently with MicroWindows it is possible that HDC is 0 so we have to
// check for this ourselves
#ifdef __WXMICROWIN__
#define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
#define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
#else
#define WXMICROWIN_CHECK_HDC
#define WXMICROWIN_CHECK_HDC_RET(x)
#endif
IMPLEMENT_ABSTRACT_CLASS(wxDC, wxDCBase)
// ---------------------------------------------------------------------------
// constants
// ---------------------------------------------------------------------------
static const int VIEWPORT_EXTENT = 1000;
static const int MM_POINTS = 9;
static const int MM_METRIC = 10;
// ROPs which don't have standard names (see "Ternary Raster Operations" in the
// MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
#define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
// ----------------------------------------------------------------------------
// macros for logical <-> device coords conversion
// ----------------------------------------------------------------------------
/*
We currently let Windows do all the translations itself so these macros are
not really needed (any more) but keep them to enhance readability of the
code by allowing to see where are the logical and where are the device
coordinates used.
*/
#ifdef __WXWINCE__
#define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX)
#define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY)
#define XDEV2LOG(x) ((x)*m_signX+m_logicalOriginX)
#define YDEV2LOG(y) ((y)*m_signY+m_logicalOriginY)
#else
#define XLOG2DEV(x) (x)
#define YLOG2DEV(y) (y)
#define XDEV2LOG(x) (x)
#define YDEV2LOG(y) (y)
#endif
// ---------------------------------------------------------------------------
// private functions
// ---------------------------------------------------------------------------
// convert degrees to radians
static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
// call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
//
// NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
// to pass it to this function but as we already have it at the point
// of call anyhow we do
//
// return true if we could draw the bitmap in one way or the other, false
// otherwise
static bool AlphaBlt(HDC hdcDst,
int x, int y, int w, int h,
int srcX, int srcY, HDC hdcSrc,
const wxBitmap& bmpSrc);
#ifdef wxHAVE_RAW_BITMAP
// our (limited) AlphaBlend() replacement
static void
wxAlphaBlend(HDC hdcDst, int x, int y, int w, int h, int srcX, int srcY, const wxBitmap& bmp);
#endif
// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------
// instead of duplicating the same code which sets and then restores text
// colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
// encapsulate this in a small helper class
// wxColourChanger: changes the text colours in the ctor if required and
// restores them in the dtor
class wxColourChanger
{
public:
wxColourChanger(wxDC& dc);
~wxColourChanger();
private:
wxDC& m_dc;
COLORREF m_colFgOld, m_colBgOld;
bool m_changed;
DECLARE_NO_COPY_CLASS(wxColourChanger)
};
// this class saves the old stretch blit mode during its life time
class StretchBltModeChanger
{
public:
StretchBltModeChanger(HDC hdc,
int WXUNUSED_IN_WINCE(mode))
: m_hdc(hdc)
{
#ifndef __WXWINCE__
m_modeOld = ::SetStretchBltMode(m_hdc, mode);
if ( !m_modeOld )
wxLogLastError(_T("SetStretchBltMode"));
#endif
}
~StretchBltModeChanger()
{
#ifndef __WXWINCE__
if ( !::SetStretchBltMode(m_hdc, m_modeOld) )
wxLogLastError(_T("SetStretchBltMode"));
#endif
}
private:
const HDC m_hdc;
int m_modeOld;
DECLARE_NO_COPY_CLASS(StretchBltModeChanger)
};
// ===========================================================================
// implementation
// ===========================================================================
// ----------------------------------------------------------------------------
// wxColourChanger
// ----------------------------------------------------------------------------
wxColourChanger::wxColourChanger(wxDC& dc) : m_dc(dc)
{
const wxBrush& brush = dc.GetBrush();
if ( brush.Ok() && brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE )
{
HDC hdc = GetHdcOf(dc);
m_colFgOld = ::GetTextColor(hdc);
m_colBgOld = ::GetBkColor(hdc);
// note that Windows convention is opposite to wxWidgets one, this is
// why text colour becomes the background one and vice versa
const wxColour& colFg = dc.GetTextForeground();
if ( colFg.Ok() )
{
::SetBkColor(hdc, colFg.GetPixel());
}
const wxColour& colBg = dc.GetTextBackground();
if ( colBg.Ok() )
{
::SetTextColor(hdc, colBg.GetPixel());
}
SetBkMode(hdc,
dc.GetBackgroundMode() == wxTRANSPARENT ? TRANSPARENT
: OPAQUE);
// flag which telsl us to undo changes in the dtor
m_changed = true;
}
else
{
// nothing done, nothing to undo
m_changed = false;
}
}
wxColourChanger::~wxColourChanger()
{
if ( m_changed )
{
// restore the colours we changed
HDC hdc = GetHdcOf(m_dc);
::SetBkMode(hdc, TRANSPARENT);
::SetTextColor(hdc, m_colFgOld);
::SetBkColor(hdc, m_colBgOld);
}
}
// ---------------------------------------------------------------------------
// wxDC
// ---------------------------------------------------------------------------
// Default constructor
wxDC::wxDC()
{
m_canvas = NULL;
m_oldBitmap = 0;
m_oldPen = 0;
m_oldBrush = 0;
m_oldFont = 0;
#if wxUSE_PALETTE
m_oldPalette = 0;
#endif // wxUSE_PALETTE
m_bOwnsDC = false;
m_hDC = 0;
}
wxDC::~wxDC()
{
if ( m_hDC != 0 )
{
SelectOldObjects(m_hDC);
// if we own the HDC, we delete it, otherwise we just release it
if ( m_bOwnsDC )
{
::DeleteDC(GetHdc());
}
else // we don't own our HDC
{
if (m_canvas)
{
::ReleaseDC(GetHwndOf(m_canvas), GetHdc());
}
else
{
// Must have been a wxScreenDC
::ReleaseDC((HWND) NULL, GetHdc());
}
}
}
}
// This will select current objects out of the DC,
// which is what you have to do before deleting the
// DC.
void wxDC::SelectOldObjects(WXHDC dc)
{
if (dc)
{
if (m_oldBitmap)
{
::SelectObject((HDC) dc, (HBITMAP) m_oldBitmap);
#ifdef __WXDEBUG__
if (m_selectedBitmap.Ok())
{
m_selectedBitmap.SetSelectedInto(NULL);
}
#endif
}
m_oldBitmap = 0;
if (m_oldPen)
{
::SelectObject((HDC) dc, (HPEN) m_oldPen);
}
m_oldPen = 0;
if (m_oldBrush)
{
::SelectObject((HDC) dc, (HBRUSH) m_oldBrush);
}
m_oldBrush = 0;
if (m_oldFont)
{
::SelectObject((HDC) dc, (HFONT) m_oldFont);
}
m_oldFont = 0;
#if wxUSE_PALETTE
if (m_oldPalette)
{
::SelectPalette((HDC) dc, (HPALETTE) m_oldPalette, FALSE);
}
m_oldPalette = 0;
#endif // wxUSE_PALETTE
}
m_brush = wxNullBrush;
m_pen = wxNullPen;
#if wxUSE_PALETTE
m_palette = wxNullPalette;
#endif // wxUSE_PALETTE
m_font = wxNullFont;
m_backgroundBrush = wxNullBrush;
m_selectedBitmap = wxNullBitmap;
}
// ---------------------------------------------------------------------------
// clipping
// ---------------------------------------------------------------------------
void wxDC::UpdateClipBox()
{
WXMICROWIN_CHECK_HDC
RECT rect;
::GetClipBox(GetHdc(), &rect);
m_clipX1 = (wxCoord) XDEV2LOG(rect.left);
m_clipY1 = (wxCoord) YDEV2LOG(rect.top);
m_clipX2 = (wxCoord) XDEV2LOG(rect.right);
m_clipY2 = (wxCoord) YDEV2LOG(rect.bottom);
}
void
wxDC::DoGetClippingBox(wxCoord *x, wxCoord *y, wxCoord *w, wxCoord *h) const
{
// check if we should try to retrieve the clipping region possibly not set
// by our SetClippingRegion() but preset by Windows:this can only happen
// when we're associated with an existing HDC usign SetHDC(), see there
if ( m_clipping && !m_clipX1 && !m_clipX2 )
{
wxDC *self = wxConstCast(this, wxDC);
self->UpdateClipBox();
if ( !m_clipX1 && !m_clipX2 )
self->m_clipping = false;
}
wxDCBase::DoGetClippingBox(x, y, w, h);
}
// common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
void wxDC::SetClippingHrgn(WXHRGN hrgn)
{
wxCHECK_RET( hrgn, wxT("invalid clipping region") );
WXMICROWIN_CHECK_HDC
// note that we combine the new clipping region with the existing one: this
// is compatible with what the other ports do and is the documented
// behaviour now (starting with 2.3.3)
#if defined(__WXWINCE__)
RECT rectClip;
if ( !::GetClipBox(GetHdc(), &rectClip) )
return;
// GetClipBox returns logical coordinates, so transform to device
rectClip.left = LogicalToDeviceX(rectClip.left);
rectClip.top = LogicalToDeviceY(rectClip.top);
rectClip.right = LogicalToDeviceX(rectClip.right);
rectClip.bottom = LogicalToDeviceY(rectClip.bottom);
HRGN hrgnDest = ::CreateRectRgn(0, 0, 0, 0);
HRGN hrgnClipOld = ::CreateRectRgn(rectClip.left, rectClip.top,
rectClip.right, rectClip.bottom);
if ( ::CombineRgn(hrgnDest, hrgnClipOld, (HRGN)hrgn, RGN_AND) != ERROR )
{
::SelectClipRgn(GetHdc(), hrgnDest);
}
::DeleteObject(hrgnClipOld);
::DeleteObject(hrgnDest);
#else // !WinCE
if ( ::ExtSelectClipRgn(GetHdc(), (HRGN)hrgn, RGN_AND) == ERROR )
{
wxLogLastError(_T("ExtSelectClipRgn"));
return;
}
#endif // WinCE/!WinCE
m_clipping = true;
UpdateClipBox();
}
void wxDC::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -