+ WXMICROWIN_CHECK_HDC
+
+ // prepare for drawing the text
+ wxTextColoursChanger textCol(GetHdc(), *this);
+
+ wxBkModeChanger bkMode(GetHdc(), m_backgroundMode);
+
+ if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), 0, NULL,
+ text.c_str(), text.length(), NULL) == 0 )
+ {
+ wxLogLastError(wxT("TextOut"));
+ }
+}
+
+void wxMSWDCImpl::DoDrawRotatedText(const wxString& text,
+ wxCoord x, wxCoord y,
+ double angle)
+{
+ WXMICROWIN_CHECK_HDC
+
+ // we test that we have some font because otherwise we should still use the
+ // "else" part below to avoid that DrawRotatedText(angle = 180) and
+ // DrawRotatedText(angle = 0) use different fonts (we can't use the default
+ // font for drawing rotated fonts unfortunately)
+ if ( (angle == 0.0) && m_font.IsOk() )
+ {
+ DoDrawText(text, x, y);
+ }
+#ifndef __WXMICROWIN__
+ else
+ {
+ // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
+ // because it's not TrueType and so can't have non zero
+ // orientation/escapement under Win9x
+ wxFont font = m_font.IsOk() ? m_font : *wxSWISS_FONT;
+ HFONT hfont = (HFONT)font.GetResourceHandle();
+ LOGFONT lf;
+ if ( ::GetObject(hfont, sizeof(lf), &lf) == 0 )
+ {
+ wxLogLastError(wxT("GetObject(hfont)"));
+ }
+
+ // GDI wants the angle in tenth of degree
+ long angle10 = (long)(angle * 10);
+ lf.lfEscapement = angle10;
+ lf. lfOrientation = angle10;
+
+ hfont = ::CreateFontIndirect(&lf);
+ if ( !hfont )
+ {
+ wxLogLastError(wxT("CreateFont"));
+ }
+ else
+ {
+ HFONT hfontOld = (HFONT)::SelectObject(GetHdc(), hfont);
+
+ DrawAnyText(text, x, y);
+
+ (void)::SelectObject(GetHdc(), hfontOld);
+ (void)::DeleteObject(hfont);
+ }
+
+ // call the bounding box by adding all four vertices of the rectangle
+ // containing the text to it (simpler and probably not slower than
+ // determining which of them is really topmost/leftmost/...)
+ wxCoord w, h;
+ GetOwner()->GetTextExtent(text, &w, &h);
+
+ double rad = DegToRad(angle);
+
+ // "upper left" and "upper right"
+ CalcBoundingBox(x, y);
+ CalcBoundingBox(x + wxCoord(w*cos(rad)), y - wxCoord(w*sin(rad)));
+
+ // "bottom left" and "bottom right"
+ x += (wxCoord)(h*sin(rad));
+ y += (wxCoord)(h*cos(rad));
+ CalcBoundingBox(x, y);
+ CalcBoundingBox(x + wxCoord(w*cos(rad)), y - wxCoord(w*sin(rad)));
+ }
+#endif
+}
+
+// ---------------------------------------------------------------------------
+// set GDI objects
+// ---------------------------------------------------------------------------
+
+#if wxUSE_PALETTE
+
+void wxMSWDCImpl::DoSelectPalette(bool realize)
+{
+ WXMICROWIN_CHECK_HDC
+
+ // Set the old object temporarily, in case the assignment deletes an object
+ // that's not yet selected out.
+ if (m_oldPalette)
+ {
+ ::SelectPalette(GetHdc(), (HPALETTE) m_oldPalette, FALSE);
+ m_oldPalette = 0;
+ }
+
+ if ( m_palette.IsOk() )
+ {
+ HPALETTE oldPal = ::SelectPalette(GetHdc(),
+ GetHpaletteOf(m_palette),
+ false);
+ if (!m_oldPalette)
+ m_oldPalette = (WXHPALETTE) oldPal;
+
+ if (realize)
+ ::RealizePalette(GetHdc());
+ }
+}
+
+void wxMSWDCImpl::SetPalette(const wxPalette& palette)
+{
+ if ( palette.IsOk() )
+ {
+ m_palette = palette;
+ DoSelectPalette(true);
+ }
+}
+
+void wxMSWDCImpl::InitializePalette()
+{
+ if ( wxDisplayDepth() <= 8 )
+ {
+ // look for any window or parent that has a custom palette. If any has
+ // one then we need to use it in drawing operations
+ wxWindow *win = m_window->GetAncestorWithCustomPalette();
+
+ m_hasCustomPalette = win && win->HasCustomPalette();
+ if ( m_hasCustomPalette )
+ {
+ m_palette = win->GetPalette();
+
+ // turn on MSW translation for this palette
+ DoSelectPalette();
+ }
+ }
+}
+
+#endif // wxUSE_PALETTE
+
+// SetFont/Pen/Brush() really ask to be implemented as a single template
+// function... but doing it is not worth breaking OpenWatcom build <sigh>
+
+void wxMSWDCImpl::SetFont(const wxFont& font)
+{
+ WXMICROWIN_CHECK_HDC
+
+ if ( font == m_font )
+ return;
+
+ if ( font.IsOk() )
+ {
+ HGDIOBJ hfont = ::SelectObject(GetHdc(), GetHfontOf(font));
+ if ( hfont == HGDI_ERROR )
+ {
+ wxLogLastError(wxT("SelectObject(font)"));
+ }
+ else // selected ok
+ {
+ if ( !m_oldFont )
+ m_oldFont = (WXHFONT)hfont;
+
+ m_font = font;
+ }
+ }
+ else // invalid font, reset the current font
+ {
+ if ( m_oldFont )
+ {
+ if ( ::SelectObject(GetHdc(), (HPEN) m_oldFont) == HGDI_ERROR )
+ {
+ wxLogLastError(wxT("SelectObject(old font)"));
+ }
+
+ m_oldFont = 0;
+ }
+
+ m_font = wxNullFont;
+ }
+}
+
+void wxMSWDCImpl::SetPen(const wxPen& pen)
+{
+ WXMICROWIN_CHECK_HDC
+
+ if ( pen == m_pen )
+ return;
+
+ if ( pen.IsOk() )
+ {
+ HGDIOBJ hpen = ::SelectObject(GetHdc(), GetHpenOf(pen));
+ if ( hpen == HGDI_ERROR )
+ {
+ wxLogLastError(wxT("SelectObject(pen)"));
+ }
+ else // selected ok
+ {
+ if ( !m_oldPen )
+ m_oldPen = (WXHPEN)hpen;
+
+ m_pen = pen;
+ }
+ }
+ else // invalid pen, reset the current pen
+ {
+ if ( m_oldPen )
+ {
+ if ( ::SelectObject(GetHdc(), (HPEN) m_oldPen) == HGDI_ERROR )
+ {
+ wxLogLastError(wxT("SelectObject(old pen)"));
+ }
+
+ m_oldPen = 0;
+ }
+
+ m_pen = wxNullPen;
+ }
+}
+
+void wxMSWDCImpl::SetBrush(const wxBrush& brush)
+{
+ WXMICROWIN_CHECK_HDC
+
+ if ( brush == m_brush )
+ return;
+
+ if ( brush.IsOk() )
+ {
+ // we must make sure the brush is aligned with the logical coordinates
+ // before selecting it or using the same brush for the background of
+ // different windows would result in discontinuities
+ wxSize sizeBrushBitmap = wxDefaultSize;
+ wxBitmap *stipple = brush.GetStipple();
+ if ( stipple && stipple->IsOk() )
+ sizeBrushBitmap = stipple->GetSize();
+ else if ( brush.IsHatch() )
+ sizeBrushBitmap = wxSize(8, 8);
+
+ if ( sizeBrushBitmap.IsFullySpecified() )
+ {
+ if ( !::SetBrushOrgEx
+ (
+ GetHdc(),
+ m_deviceOriginX % sizeBrushBitmap.x,
+ m_deviceOriginY % sizeBrushBitmap.y,
+ NULL // [out] previous brush origin
+ ) )
+ {
+ wxLogLastError(wxT("SetBrushOrgEx()"));
+ }
+ }
+
+ HGDIOBJ hbrush = ::SelectObject(GetHdc(), GetHbrushOf(brush));
+ if ( hbrush == HGDI_ERROR )
+ {
+ wxLogLastError(wxT("SelectObject(brush)"));
+ }
+ else // selected ok
+ {
+ if ( !m_oldBrush )
+ m_oldBrush = (WXHBRUSH)hbrush;
+
+ m_brush = brush;
+ }
+ }
+ else // invalid brush, reset the current brush
+ {
+ if ( m_oldBrush )
+ {
+ if ( ::SelectObject(GetHdc(), (HPEN) m_oldBrush) == HGDI_ERROR )
+ {
+ wxLogLastError(wxT("SelectObject(old brush)"));
+ }
+
+ m_oldBrush = 0;
+ }
+
+ m_brush = wxNullBrush;
+ }
+}
+
+void wxMSWDCImpl::SetBackground(const wxBrush& brush)
+{
+ WXMICROWIN_CHECK_HDC
+
+ m_backgroundBrush = brush;
+
+ if ( m_backgroundBrush.IsOk() )
+ {
+ (void)SetBkColor(GetHdc(), m_backgroundBrush.GetColour().GetPixel());
+ }
+}
+
+void wxMSWDCImpl::SetBackgroundMode(int mode)
+{
+ WXMICROWIN_CHECK_HDC
+
+ m_backgroundMode = mode;
+
+ // SetBackgroundColour now only refers to text background
+ // and m_backgroundMode is used there
+}
+
+void wxMSWDCImpl::SetLogicalFunction(wxRasterOperationMode function)
+{
+ WXMICROWIN_CHECK_HDC
+
+ m_logicalFunction = function;
+
+ SetRop(m_hDC);
+}
+
+void wxMSWDCImpl::SetRop(WXHDC dc)
+{
+ if ( !dc || m_logicalFunction < 0 )
+ return;
+
+ int rop;
+
+ switch (m_logicalFunction)
+ {
+ case wxCLEAR: rop = R2_BLACK; break;
+ case wxXOR: rop = R2_XORPEN; break;
+ case wxINVERT: rop = R2_NOT; break;
+ case wxOR_REVERSE: rop = R2_MERGEPENNOT; break;
+ case wxAND_REVERSE: rop = R2_MASKPENNOT; break;
+ case wxCOPY: rop = R2_COPYPEN; break;
+ case wxAND: rop = R2_MASKPEN; break;
+ case wxAND_INVERT: rop = R2_MASKNOTPEN; break;
+ case wxNO_OP: rop = R2_NOP; break;
+ case wxNOR: rop = R2_NOTMERGEPEN; break;
+ case wxEQUIV: rop = R2_NOTXORPEN; break;
+ case wxSRC_INVERT: rop = R2_NOTCOPYPEN; break;
+ case wxOR_INVERT: rop = R2_MERGENOTPEN; break;
+ case wxNAND: rop = R2_NOTMASKPEN; break;
+ case wxOR: rop = R2_MERGEPEN; break;
+ case wxSET: rop = R2_WHITE; break;
+ default:
+ wxFAIL_MSG( wxS("unknown logical function") );
+ return;
+ }
+
+ SetROP2(GetHdc(), rop);
+}
+
+bool wxMSWDCImpl::StartDoc(const wxString& WXUNUSED(message))
+{
+ // We might be previewing, so return true to let it continue.
+ return true;
+}
+
+void wxMSWDCImpl::EndDoc()
+{
+}
+
+void wxMSWDCImpl::StartPage()
+{
+}
+
+void wxMSWDCImpl::EndPage()
+{
+}
+
+// ---------------------------------------------------------------------------
+// text metrics
+// ---------------------------------------------------------------------------
+
+wxCoord wxMSWDCImpl::GetCharHeight() const
+{
+ WXMICROWIN_CHECK_HDC_RET(0)
+
+ TEXTMETRIC lpTextMetric;
+
+ GetTextMetrics(GetHdc(), &lpTextMetric);
+
+ return lpTextMetric.tmHeight;
+}
+
+wxCoord wxMSWDCImpl::GetCharWidth() const
+{
+ WXMICROWIN_CHECK_HDC_RET(0)
+
+ TEXTMETRIC lpTextMetric;
+
+ GetTextMetrics(GetHdc(), &lpTextMetric);
+
+ return lpTextMetric.tmAveCharWidth;
+}
+
+void wxMSWDCImpl::DoGetFontMetrics(int *height,
+ int *ascent,
+ int *descent,
+ int *internalLeading,
+ int *externalLeading,
+ int *averageWidth) const
+{
+ TEXTMETRIC tm;
+
+ GetTextMetrics(GetHdc(), &tm);
+
+ if ( height )
+ *height = tm.tmHeight;
+ if ( ascent )
+ *ascent = tm.tmAscent;
+ if ( descent )
+ *descent = tm.tmDescent;
+ if ( internalLeading )
+ *internalLeading = tm.tmInternalLeading;
+ if ( externalLeading )
+ *externalLeading = tm.tmExternalLeading;
+ if ( averageWidth )
+ *averageWidth = tm.tmAveCharWidth;
+}
+
+void wxMSWDCImpl::DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y,
+ wxCoord *descent, wxCoord *externalLeading,
+ const wxFont *font) const
+{
+#ifdef __WXMICROWIN__
+ if (!GetHDC())
+ {
+ if (x) *x = 0;
+ if (y) *y = 0;
+ if (descent) *descent = 0;
+ if (externalLeading) *externalLeading = 0;
+ return;
+ }
+#endif // __WXMICROWIN__
+
+ HFONT hfontOld;
+ if ( font )
+ {
+ wxASSERT_MSG( font->IsOk(), wxT("invalid font in wxMSWDCImpl::GetTextExtent") );
+
+ hfontOld = (HFONT)::SelectObject(GetHdc(), GetHfontOf(*font));
+ }
+ else // don't change the font
+ {
+ hfontOld = 0;
+ }
+
+ SIZE sizeRect;
+ const size_t len = string.length();
+ if ( !::GetTextExtentPoint32(GetHdc(), string.wx_str(), len, &sizeRect) )
+ {
+ wxLogLastError(wxT("GetTextExtentPoint32()"));
+ }
+
+#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
+ // the result computed by GetTextExtentPoint32() may be too small as it
+ // accounts for under/overhang of the first/last character while we want
+ // just the bounding rect for this string so adjust the width as needed
+ // (using API not available in 2002 SDKs of WinCE)
+ if ( len > 0 )
+ {
+ ABC width;
+ const wxChar chFirst = *string.begin();
+ if ( ::GetCharABCWidths(GetHdc(), chFirst, chFirst, &width) )
+ {
+ if ( width.abcA < 0 )
+ sizeRect.cx -= width.abcA;
+
+ if ( len > 1 )
+ {
+ const wxChar chLast = *string.rbegin();
+ ::GetCharABCWidths(GetHdc(), chLast, chLast, &width);
+ }
+ //else: we already have the width of the last character
+
+ if ( width.abcC < 0 )
+ sizeRect.cx -= width.abcC;
+ }
+ //else: GetCharABCWidths() failed, not a TrueType font?
+ }
+#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
+
+ if (x)
+ *x = sizeRect.cx;
+ if (y)
+ *y = sizeRect.cy;
+
+ if ( descent || externalLeading )
+ {
+ DoGetFontMetrics(NULL, NULL, descent, NULL, externalLeading, NULL);
+ }
+
+ if ( hfontOld )
+ {
+ ::SelectObject(GetHdc(), hfontOld);
+ }
+}
+
+
+// Each element of the array will be the width of the string up to and
+// including the coresoponding character in text.
+
+bool wxMSWDCImpl::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
+{
+ static int maxLenText = -1;
+ static int maxWidth = -1;
+ int fit = 0;
+ SIZE sz = {0,0};
+ int stlen = text.length();
+
+ if (maxLenText == -1)
+ {
+ // Win9x and WinNT+ have different limits
+ int version = wxGetOsVersion();
+ maxLenText = version == wxOS_WINDOWS_NT ? 65535 : 8192;
+ maxWidth = version == wxOS_WINDOWS_NT ? INT_MAX : 32767;
+ }
+
+ widths.Empty();
+ widths.Add(0, stlen); // fill the array with zeros
+ if (stlen == 0)
+ return true;
+
+ if (!::GetTextExtentExPoint(GetHdc(),
+ text.c_str(), // string to check
+ wxMin(stlen, maxLenText),
+ maxWidth,
+ &fit, // [out] count of chars
+ // that will fit
+ &widths[0], // array to fill
+ &sz))
+ {
+ // API failed
+ wxLogLastError(wxT("GetTextExtentExPoint"));
+ return false;
+ }