+ WXMICROWIN_CHECK_HDC
+
+ // Do things less efficiently if we have offsets
+ if (xoffset != 0 || yoffset != 0)
+ {
+ POINT *cpoints = new POINT[n];
+ int i;
+ for (i = 0; i < n; i++)
+ {
+ cpoints[i].x = (int)(points[i].x + xoffset);
+ cpoints[i].y = (int)(points[i].y + yoffset);
+
+ CalcBoundingBox(cpoints[i].x, cpoints[i].y);
+ }
+ (void)Polyline(GetHdc(), cpoints, n);
+ delete[] cpoints;
+ }
+ else
+ {
+ int i;
+ for (i = 0; i < n; i++)
+ CalcBoundingBox(points[i].x, points[i].y);
+
+ (void)Polyline(GetHdc(), (POINT*) points, n);
+ }
+}
+
+void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
+{
+ WXMICROWIN_CHECK_HDC
+
+ wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
+
+ wxCoord x2 = x + width;
+ wxCoord y2 = y + height;
+
+ if ((m_logicalFunction == wxCOPY) && (m_pen.GetStyle() == wxTRANSPARENT))
+ {
+ RECT rect;
+ rect.left = XLOG2DEV(x);
+ rect.top = YLOG2DEV(y);
+ rect.right = XLOG2DEV(x2);
+ rect.bottom = YLOG2DEV(y2);
+ (void)FillRect(GetHdc(), &rect, (HBRUSH)m_brush.GetResourceHandle() );
+ }
+ else
+ {
+ // Windows draws the filled rectangles without outline (i.e. drawn with a
+ // transparent pen) one pixel smaller in both directions and we want them
+ // to have the same size regardless of which pen is used - adjust
+
+ // I wonder if this shouldnt be done after the LOG2DEV() conversions. RR.
+ if ( m_pen.GetStyle() == wxTRANSPARENT )
+ {
+ // Apparently not needed for WinCE (see e.g. Life! demo)
+#ifndef __WXWINCE__
+ x2++;
+ y2++;
+#endif
+ }
+
+ (void)Rectangle(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2));
+ }
+
+
+ CalcBoundingBox(x, y);
+ CalcBoundingBox(x2, y2);
+}
+
+void wxDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius)
+{
+ WXMICROWIN_CHECK_HDC
+
+ wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
+
+ // Now, a negative radius value is interpreted to mean
+ // 'the proportion of the smallest X or Y dimension'
+
+ if (radius < 0.0)
+ {
+ double smallest = (width < height) ? width : height;
+ radius = (- radius * smallest);
+ }
+
+ wxCoord x2 = (x+width);
+ wxCoord y2 = (y+height);
+
+ // Windows draws the filled rectangles without outline (i.e. drawn with a
+ // transparent pen) one pixel smaller in both directions and we want them
+ // to have the same size regardless of which pen is used - adjust
+ if ( m_pen.GetStyle() == wxTRANSPARENT )
+ {
+ x2++;
+ y2++;
+ }
+
+ (void)RoundRect(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2),
+ YLOG2DEV(y2), (int) (2*XLOG2DEV(radius)), (int)( 2*YLOG2DEV(radius)));
+
+ CalcBoundingBox(x, y);
+ CalcBoundingBox(x2, y2);
+}
+
+void wxDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
+{
+ WXMICROWIN_CHECK_HDC
+
+ wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
+
+ wxCoord x2 = (x+width);
+ wxCoord y2 = (y+height);
+
+ (void)Ellipse(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2));
+
+ CalcBoundingBox(x, y);
+ CalcBoundingBox(x2, y2);
+}
+
+#if wxUSE_SPLINES
+void wxDC::DoDrawSpline(wxList *points)
+{
+#ifdef __WXWINCE__
+ // WinCE does not support ::PolyBezier so use generic version
+ wxDCBase::DoDrawSpline(points);
+#else
+ // quadratic b-spline to cubic bezier spline conversion
+ //
+ // quadratic spline with control points P0,P1,P2
+ // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
+ //
+ // bezier spline with control points B0,B1,B2,B3
+ // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
+ //
+ // control points of bezier spline calculated from b-spline
+ // B0 = P0
+ // B1 = (2*P1 + P0)/3
+ // B2 = (2*P1 + P2)/3
+ // B3 = P2
+
+ WXMICROWIN_CHECK_HDC
+
+ wxASSERT_MSG( points, wxT("NULL pointer to spline points?") );
+
+ const size_t n_points = points->GetCount();
+ wxASSERT_MSG( n_points > 2 , wxT("incomplete list of spline points?") );
+
+ const size_t n_bezier_points = n_points * 3 + 1;
+ POINT *lppt = (POINT *)malloc(n_bezier_points*sizeof(POINT));
+ size_t bezier_pos = 0;
+ wxCoord x1, y1, x2, y2, cx1, cy1, cx4, cy4;
+
+ wxList::compatibility_iterator node = points->GetFirst();
+ wxPoint *p = (wxPoint *)node->GetData();
+ lppt[ bezier_pos ].x = x1 = p->x;
+ lppt[ bezier_pos ].y = y1 = p->y;
+ bezier_pos++;
+ lppt[ bezier_pos ] = lppt[ bezier_pos-1 ];
+ bezier_pos++;
+
+ node = node->GetNext();
+ p = (wxPoint *)node->GetData();
+
+ x2 = p->x;
+ y2 = p->y;
+ cx1 = ( x1 + x2 ) / 2;
+ cy1 = ( y1 + y2 ) / 2;
+ lppt[ bezier_pos ].x = XLOG2DEV(cx1);
+ lppt[ bezier_pos ].y = YLOG2DEV(cy1);
+ bezier_pos++;
+ lppt[ bezier_pos ] = lppt[ bezier_pos-1 ];
+ bezier_pos++;
+
+#if !wxUSE_STL
+ while ((node = node->GetNext()) != NULL)
+#else
+ while ((node = node->GetNext()))
+#endif // !wxUSE_STL
+ {
+ p = (wxPoint *)node->GetData();
+ x1 = x2;
+ y1 = y2;
+ x2 = p->x;
+ y2 = p->y;
+ cx4 = (x1 + x2) / 2;
+ cy4 = (y1 + y2) / 2;
+ // B0 is B3 of previous segment
+ // B1:
+ lppt[ bezier_pos ].x = XLOG2DEV((x1*2+cx1)/3);
+ lppt[ bezier_pos ].y = YLOG2DEV((y1*2+cy1)/3);
+ bezier_pos++;
+ // B2:
+ lppt[ bezier_pos ].x = XLOG2DEV((x1*2+cx4)/3);
+ lppt[ bezier_pos ].y = YLOG2DEV((y1*2+cy4)/3);
+ bezier_pos++;
+ // B3:
+ lppt[ bezier_pos ].x = XLOG2DEV(cx4);
+ lppt[ bezier_pos ].y = YLOG2DEV(cy4);
+ bezier_pos++;
+ cx1 = cx4;
+ cy1 = cy4;
+ }
+
+ lppt[ bezier_pos ] = lppt[ bezier_pos-1 ];
+ bezier_pos++;
+ lppt[ bezier_pos ].x = XLOG2DEV(x2);
+ lppt[ bezier_pos ].y = YLOG2DEV(y2);
+ bezier_pos++;
+ lppt[ bezier_pos ] = lppt[ bezier_pos-1 ];
+ bezier_pos++;
+
+ ::PolyBezier( GetHdc(), lppt, bezier_pos );
+
+ free(lppt);
+#endif
+}
+#endif
+
+// Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
+void wxDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
+{
+#ifdef __WXWINCE__
+ DoDrawEllipticArcRot( x, y, w, h, sa, ea );
+#else
+
+ WXMICROWIN_CHECK_HDC
+
+ wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
+
+ wxCoord x2 = x + w;
+ wxCoord y2 = y + h;
+
+ int rx1 = XLOG2DEV(x+w/2);
+ int ry1 = YLOG2DEV(y+h/2);
+ int rx2 = rx1;
+ int ry2 = ry1;
+
+ sa = DegToRad(sa);
+ ea = DegToRad(ea);
+
+ rx1 += (int)(100.0 * abs(w) * cos(sa));
+ ry1 -= (int)(100.0 * abs(h) * m_signY * sin(sa));
+ rx2 += (int)(100.0 * abs(w) * cos(ea));
+ ry2 -= (int)(100.0 * abs(h) * m_signY * sin(ea));
+
+ // draw pie with NULL_PEN first and then outline otherwise a line is
+ // drawn from the start and end points to the centre
+ HPEN hpenOld = (HPEN) ::SelectObject(GetHdc(), (HPEN) ::GetStockObject(NULL_PEN));
+ if (m_signY > 0)
+ {
+ (void)Pie(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2)+1, YLOG2DEV(y2)+1,
+ rx1, ry1, rx2, ry2);
+ }
+ else
+ {
+ (void)Pie(GetHdc(), XLOG2DEV(x), YLOG2DEV(y)-1, XLOG2DEV(x2)+1, YLOG2DEV(y2),
+ rx1, ry1-1, rx2, ry2-1);
+ }
+
+ ::SelectObject(GetHdc(), hpenOld);
+
+ (void)Arc(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2),
+ rx1, ry1, rx2, ry2);
+
+ CalcBoundingBox(x, y);
+ CalcBoundingBox(x2, y2);
+#endif
+}
+
+void wxDC::DoDrawIcon(const wxIcon& icon, wxCoord x, wxCoord y)
+{
+ WXMICROWIN_CHECK_HDC
+
+ wxCHECK_RET( icon.Ok(), wxT("invalid icon in DrawIcon") );
+
+#ifdef __WIN32__
+ ::DrawIconEx(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), GetHiconOf(icon), icon.GetWidth(), icon.GetHeight(), 0, NULL, DI_NORMAL);
+#else
+ ::DrawIcon(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), GetHiconOf(icon));
+#endif
+
+ CalcBoundingBox(x, y);
+ CalcBoundingBox(x + icon.GetWidth(), y + icon.GetHeight());
+}
+
+void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask )
+{
+ WXMICROWIN_CHECK_HDC
+
+ wxCHECK_RET( bmp.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
+
+ int width = bmp.GetWidth(),
+ height = bmp.GetHeight();
+
+ HBITMAP hbmpMask = 0;
+
+#if wxUSE_PALETTE
+ HPALETTE oldPal = 0;
+#endif // wxUSE_PALETTE
+
+ if ( bmp.HasAlpha() )
+ {
+ MemoryHDC hdcMem;
+ SelectInHDC select(hdcMem, GetHbitmapOf(bmp));
+
+ if ( AlphaBlt(GetHdc(), x, y, width, height, 0, 0, width, height, hdcMem, bmp) )
+ return;
+ }
+
+ if ( useMask )
+ {
+ wxMask *mask = bmp.GetMask();
+ if ( mask )
+ hbmpMask = (HBITMAP)mask->GetMaskBitmap();
+
+ if ( !hbmpMask )
+ {
+ // don't give assert here because this would break existing
+ // programs - just silently ignore useMask parameter
+ useMask = false;
+ }
+ }
+ if ( useMask )
+ {
+#ifdef __WIN32__
+ // use MaskBlt() with ROP which doesn't do anything to dst in the mask
+ // points
+ // On some systems, MaskBlt succeeds yet is much much slower
+ // than the wxWidgets fall-back implementation. So we need
+ // to be able to switch this on and off at runtime.
+ bool ok = false;
+#if wxUSE_SYSTEM_OPTIONS
+ if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
+#endif
+ {
+ HDC cdc = GetHdc();
+ HDC hdcMem = ::CreateCompatibleDC(GetHdc());
+ HGDIOBJ hOldBitmap = ::SelectObject(hdcMem, GetHbitmapOf(bmp));
+#if wxUSE_PALETTE
+ wxPalette *pal = bmp.GetPalette();
+ if ( pal && ::GetDeviceCaps(cdc,BITSPIXEL) <= 8 )
+ {
+ oldPal = ::SelectPalette(hdcMem, GetHpaletteOf(*pal), FALSE);
+ ::RealizePalette(hdcMem);
+ }
+#endif // wxUSE_PALETTE
+
+ ok = ::MaskBlt(cdc, x, y, width, height,
+ hdcMem, 0, 0,
+ hbmpMask, 0, 0,
+ MAKEROP4(SRCCOPY, DSTCOPY)) != 0;
+
+#if wxUSE_PALETTE
+ if (oldPal)
+ ::SelectPalette(hdcMem, oldPal, FALSE);
+#endif // wxUSE_PALETTE
+
+ ::SelectObject(hdcMem, hOldBitmap);
+ ::DeleteDC(hdcMem);
+ }
+
+ if ( !ok )
+#endif // Win32
+ {
+ // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
+ // level
+ wxMemoryDC memDC;
+
+ memDC.SelectObjectAsSource(bmp);
+
+ Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask);
+
+ memDC.SelectObject(wxNullBitmap);
+ }
+ }
+ else // no mask, just use BitBlt()
+ {
+ HDC cdc = GetHdc();
+ HDC memdc = ::CreateCompatibleDC( cdc );
+ HBITMAP hbitmap = (HBITMAP) bmp.GetHBITMAP( );
+
+ wxASSERT_MSG( hbitmap, wxT("bitmap is ok but HBITMAP is NULL?") );
+
+ COLORREF old_textground = ::GetTextColor(GetHdc());
+ COLORREF old_background = ::GetBkColor(GetHdc());
+ if (m_textForegroundColour.Ok())
+ {
+ ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() );
+ }
+ if (m_textBackgroundColour.Ok())
+ {
+ ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
+ }
+
+#if wxUSE_PALETTE
+ wxPalette *pal = bmp.GetPalette();
+ if ( pal && ::GetDeviceCaps(cdc,BITSPIXEL) <= 8 )
+ {
+ oldPal = ::SelectPalette(memdc, GetHpaletteOf(*pal), FALSE);
+ ::RealizePalette(memdc);
+ }
+#endif // wxUSE_PALETTE
+
+ HGDIOBJ hOldBitmap = ::SelectObject( memdc, hbitmap );
+ ::BitBlt( cdc, x, y, width, height, memdc, 0, 0, SRCCOPY);
+
+#if wxUSE_PALETTE
+ if (oldPal)
+ ::SelectPalette(memdc, oldPal, FALSE);
+#endif // wxUSE_PALETTE
+
+ ::SelectObject( memdc, hOldBitmap );
+ ::DeleteDC( memdc );
+
+ ::SetTextColor(GetHdc(), old_textground);
+ ::SetBkColor(GetHdc(), old_background);
+ }
+}
+
+void wxDC::DoDrawText(const wxString& text, wxCoord x, wxCoord y)
+{
+ WXMICROWIN_CHECK_HDC
+
+ DrawAnyText(text, x, y);
+
+ // update the bounding box
+ CalcBoundingBox(x, y);
+
+ wxCoord w, h;
+ GetTextExtent(text, &w, &h);
+ CalcBoundingBox(x + w, y + h);
+}
+
+void wxDC::DrawAnyText(const wxString& text, wxCoord x, wxCoord y)
+{
+ WXMICROWIN_CHECK_HDC
+
+ // prepare for drawing the text
+ if ( m_textForegroundColour.Ok() )
+ SetTextColor(GetHdc(), m_textForegroundColour.GetPixel());
+
+ DWORD old_background = 0;
+ if ( m_textBackgroundColour.Ok() )
+ {
+ old_background = SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
+ }
+
+ SetBkMode(GetHdc(), m_backgroundMode == wxTRANSPARENT ? TRANSPARENT
+ : OPAQUE);
+
+#ifdef __WXWINCE__
+ if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), 0, NULL,
+ text.c_str(), text.length(), NULL) == 0 )
+ {
+ wxLogLastError(wxT("TextOut"));
+ }
+#else
+ if ( ::TextOut(GetHdc(), XLOG2DEV(x), YLOG2DEV(y),
+ text.c_str(), text.length()) == 0 )
+ {
+ wxLogLastError(wxT("TextOut"));
+ }
+#endif
+
+ // restore the old parameters (text foreground colour may be left because
+ // it never is set to anything else, but background should remain
+ // transparent even if we just drew an opaque string)
+ if ( m_textBackgroundColour.Ok() )
+ (void)SetBkColor(GetHdc(), old_background);
+
+ SetBkMode(GetHdc(), TRANSPARENT);
+}
+
+void wxDC::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.Ok() )
+ {
+ 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.Ok() ? 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;
+ 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 wxDC::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.Ok() )
+ {
+ HPALETTE oldPal = ::SelectPalette(GetHdc(),
+ GetHpaletteOf(m_palette),
+ false);
+ if (!m_oldPalette)
+ m_oldPalette = (WXHPALETTE) oldPal;
+
+ if (realize)
+ ::RealizePalette(GetHdc());
+ }
+}
+
+void wxDC::SetPalette(const wxPalette& palette)
+{
+ if ( palette.Ok() )
+ {
+ m_palette = palette;
+ DoSelectPalette(true);
+ }
+}
+
+void wxDC::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_canvas->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 wxDC::SetFont(const wxFont& font)
+{
+ WXMICROWIN_CHECK_HDC
+
+ if ( font == m_font )
+ return;
+
+ if ( font.Ok() )
+ {
+ HGDIOBJ hfont = ::SelectObject(GetHdc(), GetHfontOf(font));
+ if ( hfont == HGDI_ERROR )
+ {
+ wxLogLastError(_T("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(_T("SelectObject(old font)"));
+ }
+
+ m_oldFont = 0;
+ }
+
+ m_font = wxNullFont;
+ }
+}
+
+void wxDC::SetPen(const wxPen& pen)
+{
+ WXMICROWIN_CHECK_HDC
+
+ if ( pen == m_pen )
+ return;
+
+ if ( pen.Ok() )
+ {
+ HGDIOBJ hpen = ::SelectObject(GetHdc(), GetHpenOf(pen));
+ if ( hpen == HGDI_ERROR )
+ {
+ wxLogLastError(_T("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(_T("SelectObject(old pen)"));
+ }
+
+ m_oldPen = 0;
+ }
+
+ m_pen = wxNullPen;
+ }
+}
+
+void wxDC::SetBrush(const wxBrush& brush)
+{
+ WXMICROWIN_CHECK_HDC
+
+ if ( brush == m_brush )
+ return;
+
+ if ( brush.Ok() )
+ {
+ // we must make sure the brush is aligned with the logical coordinates
+ // before selecting it
+ wxBitmap *stipple = brush.GetStipple();
+ if ( stipple && stipple->Ok() )
+ {
+ if ( !::SetBrushOrgEx
+ (
+ GetHdc(),
+ m_deviceOriginX % stipple->GetWidth(),
+ m_deviceOriginY % stipple->GetHeight(),
+ NULL // [out] previous brush origin
+ ) )
+ {
+ wxLogLastError(_T("SetBrushOrgEx()"));
+ }
+ }
+
+ HGDIOBJ hbrush = ::SelectObject(GetHdc(), GetHbrushOf(brush));
+ if ( hbrush == HGDI_ERROR )
+ {
+ wxLogLastError(_T("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(_T("SelectObject(old brush)"));
+ }
+
+ m_oldBrush = 0;
+ }
+
+ m_brush = wxNullBrush;
+ }
+}
+
+void wxDC::SetBackground(const wxBrush& brush)
+{
+ WXMICROWIN_CHECK_HDC
+
+ m_backgroundBrush = brush;
+
+ if ( m_backgroundBrush.Ok() )
+ {
+ (void)SetBkColor(GetHdc(), m_backgroundBrush.GetColour().GetPixel());
+ }
+}
+
+void wxDC::SetBackgroundMode(int mode)
+{
+ WXMICROWIN_CHECK_HDC
+
+ m_backgroundMode = mode;
+
+ // SetBackgroundColour now only refers to text background
+ // and m_backgroundMode is used there
+}
+
+void wxDC::SetLogicalFunction(int function)
+{
+ WXMICROWIN_CHECK_HDC
+
+ m_logicalFunction = function;
+
+ SetRop(m_hDC);
+}
+
+void wxDC::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( wxT("unsupported logical function") );
+ return;
+ }
+
+ SetROP2(GetHdc(), rop);
+}
+
+bool wxDC::StartDoc(const wxString& WXUNUSED(message))
+{
+ // We might be previewing, so return true to let it continue.
+ return true;
+}
+
+void wxDC::EndDoc()
+{
+}
+
+void wxDC::StartPage()
+{
+}
+
+void wxDC::EndPage()
+{
+}
+
+// ---------------------------------------------------------------------------
+// text metrics
+// ---------------------------------------------------------------------------
+
+wxCoord wxDC::GetCharHeight() const
+{
+ WXMICROWIN_CHECK_HDC_RET(0)
+
+ TEXTMETRIC lpTextMetric;
+
+ GetTextMetrics(GetHdc(), &lpTextMetric);
+
+ return lpTextMetric.tmHeight;
+}
+
+wxCoord wxDC::GetCharWidth() const
+{
+ WXMICROWIN_CHECK_HDC_RET(0)
+
+ TEXTMETRIC lpTextMetric;
+
+ GetTextMetrics(GetHdc(), &lpTextMetric);
+
+ return lpTextMetric.tmAveCharWidth;
+}
+
+void wxDC::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->Ok(), _T("invalid font in wxDC::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(_T("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)
+
+ TEXTMETRIC tm;
+ ::GetTextMetrics(GetHdc(), &tm);
+
+ if (x)
+ *x = sizeRect.cx;
+ if (y)
+ *y = sizeRect.cy;
+ if (descent)
+ *descent = tm.tmDescent;
+ if (externalLeading)
+ *externalLeading = tm.tmExternalLeading;
+
+ if ( hfontOld )
+ {
+ ::SelectObject(GetHdc(), hfontOld);
+ }