X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/d225267e66d4b0383302c853ab2970ecdf5fa3a9..fc5d9e38ee002c024be3019e37b63f1a1d88e7c2:/src/gtk/dcclient.cpp diff --git a/src/gtk/dcclient.cpp b/src/gtk/dcclient.cpp index 31995574ad..a7c10579f3 100644 --- a/src/gtk/dcclient.cpp +++ b/src/gtk/dcclient.cpp @@ -28,6 +28,7 @@ #include "wx/fontutil.h" #include "wx/gtk/private.h" +#include "wx/gtk/private/object.h" #include @@ -954,6 +955,14 @@ void wxWindowDCImpl::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord bool originChanged; DrawingSetup(gc, originChanged); + // If the pen is transparent pen we increase the size + // for better compatibility with other platforms. + if (m_pen.GetStyle() == wxPENSTYLE_TRANSPARENT) + { + ++ww; + ++hh; + } + gdk_draw_arc(m_gdkwindow, gc, true, xx, yy, ww, hh, 0, 360*64); if (originChanged) @@ -961,7 +970,7 @@ void wxWindowDCImpl::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord } if (m_pen.GetStyle() != wxPENSTYLE_TRANSPARENT) - gdk_draw_arc( m_gdkwindow, m_penGC, FALSE, xx, yy, ww, hh, 0, 360*64 ); + gdk_draw_arc( m_gdkwindow, m_penGC, false, xx, yy, ww, hh, 0, 360*64 ); } CalcBoundingBox( x, y ); @@ -974,6 +983,76 @@ void wxWindowDCImpl::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y ) DoDrawBitmap( (const wxBitmap&)icon, x, y, true ); } +// compare to current clipping region +bool wxWindowDCImpl::IsOutsideOfClippingRegion(int x, int y, int w, int h) +{ + if (m_currentClippingRegion.IsNull()) + return false; + + wxRegion region(x, y, w, h); + region.Intersect( m_currentClippingRegion ); + return region.IsEmpty(); +} + +void wxWindowDCImpl::RemoveClipMask(GdkGC *gc) +{ + gdk_gc_set_clip_mask(gc, NULL); + gdk_gc_set_clip_origin(gc, 0, 0); + if (!m_currentClippingRegion.IsNull()) + gdk_gc_set_clip_region(gc, m_currentClippingRegion.GetRegion()); +} + +// For drawing a mono-bitmap (XBitmap) we use the current text GC +void wxWindowDCImpl::DoDrawMonoBitmap(const wxBitmap& bitmap, + int bmp_w, int bmp_h, + int xsrc, int ysrc, + int xdest, int ydest, + int width, int height) +{ + wxGtkObject + bitmap2(gdk_pixmap_new( wxGetRootWindow()->window, bmp_w, bmp_h, -1 )); + wxGtkObject gc(gdk_gc_new( bitmap2 )); + gdk_gc_set_foreground( gc, m_textForegroundColour.GetColor() ); + gdk_gc_set_background( gc, m_textBackgroundColour.GetColor() ); + gdk_wx_draw_bitmap(bitmap2, gc, bitmap.GetPixmap(), 0, 0); + + gdk_draw_drawable(m_gdkwindow, m_textGC, bitmap2, xsrc, ysrc, xdest, ydest, + width, height); +} + +// Returns a new mask that is the intersection of the old mask +// and m_currentClippingRegion with proper offsets +GdkBitmap* wxWindowDCImpl::GetClippedMask(GdkBitmap* mask, int w, int h, + int x, int y, + int xsrcMask, int ysrcMask) +{ + // create monochrome bitmap that will be used as the new mask + GdkBitmap *new_mask = gdk_pixmap_new( wxGetRootWindow()->window, w, h, 1 ); + + GdkColor c0, c1; + c0.pixel = 0; + c1.pixel = 1; + wxGtkObject gc(gdk_gc_new( new_mask )); + + // zero-ing new_mask + gdk_gc_set_foreground( gc, &c0 ); + gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, w, h ); + + // clipping region + gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() ); + gdk_gc_set_clip_origin( gc, -x, -y ); + + // copy the old mask to the new_mask in the clip region area + gdk_gc_set_background( gc, &c0 ); + gdk_gc_set_foreground( gc, &c1 ); + gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED ); + gdk_gc_set_ts_origin( gc, -xsrcMask, -ysrcMask ); + gdk_gc_set_stipple( gc, mask ); + gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, w, h ); + + return new_mask; +} + void wxWindowDCImpl::DoDrawBitmap( const wxBitmap &bitmap, wxCoord x, wxCoord y, bool useMask ) @@ -991,9 +1070,6 @@ void wxWindowDCImpl::DoDrawBitmap( const wxBitmap &bitmap, int w = bitmap.GetWidth(); int h = bitmap.GetHeight(); - if (m_window && m_window->GetLayoutDirection() == wxLayout_RightToLeft) - xx -= w; - CalcBoundingBox( x, y ); CalcBoundingBox( x + w, y + h ); @@ -1002,70 +1078,43 @@ void wxWindowDCImpl::DoDrawBitmap( const wxBitmap &bitmap, int ww = XLOG2DEVREL(w); int hh = YLOG2DEVREL(h); - // compare to current clipping region - if (!m_currentClippingRegion.IsNull()) - { - wxRegion tmp( xx,yy,ww,hh ); - tmp.Intersect( m_currentClippingRegion ); - if (tmp.IsEmpty()) - return; - } + if (m_window && m_window->GetLayoutDirection() == wxLayout_RightToLeft) + xx -= ww; + + if (IsOutsideOfClippingRegion( xx,yy,ww,hh )) + return; // scale bitmap if required wxBitmap use_bitmap = bitmap; if ((w != ww) || (h != hh)) - use_bitmap = use_bitmap.Rescale( 0, 0, ww, hh, ww, hh ); + use_bitmap = use_bitmap.Rescale( 0, 0, w, h, ww, hh ); - // apply mask if any + // get mask if any GdkBitmap *mask = (GdkBitmap *) NULL; if (useMask && use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap(); + // for drawing a mono-bitmap we use the current text GC GdkGC* use_gc = is_mono ? m_textGC : m_penGC; - GdkBitmap *new_mask = (GdkBitmap*) NULL; + bool mask_owned = false; if (mask != NULL) { if (!m_currentClippingRegion.IsNull()) { - GdkColor col; - new_mask = gdk_pixmap_new( wxGetRootWindow()->window, ww, hh, 1 ); - GdkGC *gc = gdk_gc_new( new_mask ); - col.pixel = 0; - gdk_gc_set_foreground( gc, &col ); - gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh ); - col.pixel = 0; - gdk_gc_set_background( gc, &col ); - col.pixel = 1; - gdk_gc_set_foreground( gc, &col ); - gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() ); - gdk_gc_set_clip_origin( gc, -xx, -yy ); - gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED ); - gdk_gc_set_stipple( gc, mask ); - gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh ); - mask = new_mask; - g_object_unref (gc); + mask = GetClippedMask(mask, ww, hh, xx, yy, 0, 0); + mask_owned = true; } gdk_gc_set_clip_mask(use_gc, mask); gdk_gc_set_clip_origin(use_gc, xx, yy); } - // Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For - // drawing a mono-bitmap (XBitmap) we use the current text GC + // Draw XPixmap or XBitmap, depending on what the wxBitmap contains. if (is_mono) { - GdkPixmap *bitmap2 = gdk_pixmap_new( wxGetRootWindow()->window, ww, hh, -1 ); - GdkGC *gc = gdk_gc_new( bitmap2 ); - gdk_gc_set_foreground( gc, m_textForegroundColour.GetColor() ); - gdk_gc_set_background( gc, m_textBackgroundColour.GetColor() ); - gdk_wx_draw_bitmap(bitmap2, gc, use_bitmap.GetPixmap(), 0, 0); - - gdk_draw_drawable(m_gdkwindow, use_gc, bitmap2, 0, 0, xx, yy, -1, -1); - - g_object_unref (bitmap2); - g_object_unref (gc); + DoDrawMonoBitmap(use_bitmap, ww, hh, 0, 0, xx, yy, -1, -1); } else { @@ -1087,12 +1136,9 @@ void wxWindowDCImpl::DoDrawBitmap( const wxBitmap &bitmap, // remove mask again if any if (mask != NULL) { - gdk_gc_set_clip_mask(use_gc, NULL); - gdk_gc_set_clip_origin(use_gc, 0, 0); - if (!m_currentClippingRegion.IsNull()) - gdk_gc_set_clip_region(use_gc, m_currentClippingRegion.GetRegion()); - if (new_mask != NULL) - g_object_unref(new_mask); + RemoveClipMask(use_gc); + if (mask_owned) + g_object_unref(mask); } } @@ -1179,13 +1225,8 @@ bool wxWindowDCImpl::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord hh = YLOG2DEVREL(height); // compare to current clipping region - if (!m_currentClippingRegion.IsNull()) - { - wxRegion tmp( xx,yy,ww,hh ); - tmp.Intersect( m_currentClippingRegion ); - if (tmp.IsEmpty()) - return true; - } + if (IsOutsideOfClippingRegion( xx,yy,ww,hh )) + return true; int old_logical_func = m_logicalFunction; SetLogicalFunction( logical_func ); @@ -1237,55 +1278,29 @@ bool wxWindowDCImpl::DoBlit( wxCoord xdest, wxCoord ydest, GdkGC* use_gc = is_mono ? m_textGC : m_penGC; - GdkBitmap *new_mask = (GdkBitmap*) NULL; + bool mask_owned = false; if (mask != NULL) { if (!m_currentClippingRegion.IsNull()) { - GdkColor col; - new_mask = gdk_pixmap_new( wxGetRootWindow()->window, bm_ww, bm_hh, 1 ); - GdkGC *gc = gdk_gc_new( new_mask ); - col.pixel = 0; - gdk_gc_set_foreground( gc, &col ); - gdk_gc_set_ts_origin( gc, -xsrcMask, -ysrcMask); - gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh ); - col.pixel = 0; - gdk_gc_set_background( gc, &col ); - col.pixel = 1; - gdk_gc_set_foreground( gc, &col ); - gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() ); - // was: gdk_gc_set_clip_origin( gc, -xx, -yy ); - gdk_gc_set_clip_origin( gc, -cx, -cy ); - gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED ); - gdk_gc_set_stipple( gc, mask ); - gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh ); - mask = new_mask; - g_object_unref (gc); + mask = GetClippedMask(mask, bm_ww, bm_hh, cx, cy, + xsrcMask, ysrcMask); + mask_owned = true; } gdk_gc_set_clip_mask(use_gc, mask); - if (new_mask != NULL) + if (mask_owned) gdk_gc_set_clip_origin(use_gc, cx, cy); else gdk_gc_set_clip_origin(use_gc, cx - xsrcMask, cy - ysrcMask); } - // Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For - // drawing a mono-bitmap (XBitmap) we use the current text GC - + // Draw XPixmap or XBitmap, depending on what the wxBitmap contains. if (is_mono) { - GdkPixmap *bitmap = gdk_pixmap_new( wxGetRootWindow()->window, bm_ww, bm_hh, -1 ); - GdkGC *gc = gdk_gc_new( bitmap ); - gdk_gc_set_foreground( gc, m_textForegroundColour.GetColor() ); - gdk_gc_set_background( gc, m_textBackgroundColour.GetColor() ); - gdk_wx_draw_bitmap(bitmap, gc, use_bitmap.GetPixmap(), 0, 0); - - gdk_draw_drawable(m_gdkwindow, use_gc, bitmap, xsrc, ysrc, cx, cy, cw, ch); - - g_object_unref (bitmap); - g_object_unref (gc); + DoDrawMonoBitmap(use_bitmap, bm_ww, bm_hh, + xsrc, ysrc, cx, cy, cw, ch); } else { @@ -1296,31 +1311,18 @@ bool wxWindowDCImpl::DoBlit( wxCoord xdest, wxCoord ydest, // remove mask again if any if (mask != NULL) { - gdk_gc_set_clip_mask(use_gc, NULL); - gdk_gc_set_clip_origin(use_gc, 0, 0); - if (!m_currentClippingRegion.IsNull()) - gdk_gc_set_clip_region(use_gc, m_currentClippingRegion.GetRegion()); + RemoveClipMask(use_gc); + if (mask_owned) + g_object_unref (mask); } - - if (new_mask) - g_object_unref (new_mask); } else // use_bitmap_method { if (selected.IsOk() && ((width != ww) || (height != hh))) { - // get clip coords - wxRegion tmp( xx,yy,ww,hh ); - tmp.Intersect( m_currentClippingRegion ); - wxCoord cx,cy,cw,ch; - tmp.GetBox(cx,cy,cw,ch); - - // rescale bitmap - wxBitmap bitmap = selected.Rescale( cx-xx, cy-yy, cw, ch, ww, hh ); - + wxBitmap bitmap = selected.Rescale( xsrc, ysrc, width, height, ww, hh ); // draw scaled bitmap - // was: gdk_draw_drawable( m_gdkwindow, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 ); - gdk_draw_drawable( m_gdkwindow, m_penGC, bitmap.GetPixmap(), 0, 0, cx, cy, -1, -1 ); + gdk_draw_drawable( m_gdkwindow, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 ); } else { @@ -1366,7 +1368,7 @@ void wxWindowDCImpl::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) wxCHECK_RET( m_layout, wxT("no Pango layout") ); wxCHECK_RET( m_fontdesc, wxT("no Pango font description") ); - gdk_pango_context_set_colormap( m_context, m_cmap ); + gdk_pango_context_set_colormap( m_context, m_cmap ); // not needed in gtk+ >= 2.6 bool underlined = m_font.IsOk() && m_font.GetUnderlined(); @@ -1436,31 +1438,30 @@ void wxWindowDCImpl::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) const bool isScaled = fabs(m_scaleY - 1.0) > 0.00001; if (isScaled) { - // If there is a user or actually any scale applied to - // the device context, scale the font. + // If there is a user or actually any scale applied to + // the device context, scale the font. - // scale font description + // scale font description oldSize = pango_font_description_get_size(m_fontdesc); pango_font_description_set_size(m_fontdesc, int(oldSize * m_scaleY)); - // actually apply scaled font - pango_layout_set_font_description( m_layout, m_fontdesc ); + // actually apply scaled font + pango_layout_set_font_description( m_layout, m_fontdesc ); } int w, h; pango_layout_get_pixel_size(m_layout, &w, &h); - if (m_backgroundMode == wxBRUSHSTYLE_SOLID) - { - gdk_gc_set_foreground(m_textGC, m_textBackgroundColour.GetColor()); - gdk_draw_rectangle(m_gdkwindow, m_textGC, true, x, y, w, h); - gdk_gc_set_foreground(m_textGC, m_textForegroundColour.GetColor()); - } // Draw layout. int x_rtl = x; if (m_window && m_window->GetLayoutDirection() == wxLayout_RightToLeft) x_rtl -= w; - gdk_draw_layout(m_gdkwindow, m_textGC, x_rtl, y, m_layout); + + const GdkColor* bg_col = NULL; + if (m_backgroundMode == wxBRUSHSTYLE_SOLID) + bg_col = m_textBackgroundColour.GetColor(); + + gdk_draw_layout_with_colors(m_gdkwindow, m_textGC, x_rtl, y, m_layout, NULL, bg_col); if (isScaled) { @@ -1480,19 +1481,106 @@ void wxWindowDCImpl::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) CalcBoundingBox(x, y); } - -// TODO: There is an example of rotating text with GTK2 that would probably be -// a better approach here: -// http://www.daa.com.au/pipermail/pygtk/2003-April/005052.html - +// TODO: When GTK2.6 is required, merge DoDrawText and DoDrawRotatedText to +// avoid code duplication void wxWindowDCImpl::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle ) { -#if wxUSE_IMAGE if (!m_gdkwindow || text.empty()) return; wxCHECK_RET( IsOk(), wxT("invalid window dc") ); +#if __WXGTK26__ + if (!gtk_check_version(2,6,0)) + { + x = XLOG2DEV(x); + y = YLOG2DEV(y); + + pango_layout_set_text(m_layout, wxGTK_CONV(text), -1); + + if (m_font.GetUnderlined()) + { + PangoAttrList *attrs = pango_attr_list_new(); + PangoAttribute *a = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); + pango_attr_list_insert(attrs, a); + pango_layout_set_attributes(m_layout, attrs); + pango_attr_list_unref(attrs); + } + + int oldSize = 0; + const bool isScaled = fabs(m_scaleY - 1.0) > 0.00001; + if (isScaled) + { + //TODO: when Pango >= 1.6 is required, use pango_matrix_scale() + // If there is a user or actually any scale applied to + // the device context, scale the font. + + // scale font description + oldSize = pango_font_description_get_size(m_fontdesc); + pango_font_description_set_size(m_fontdesc, int(oldSize * m_scaleY)); + + // actually apply scaled font + pango_layout_set_font_description( m_layout, m_fontdesc ); + } + + int w, h; + pango_layout_get_pixel_size(m_layout, &w, &h); + + const GdkColor* bg_col = NULL; + if (m_backgroundMode == wxBRUSHSTYLE_SOLID) + bg_col = m_textBackgroundColour.GetColor(); + + // rotate the text + PangoMatrix matrix = PANGO_MATRIX_INIT; + pango_matrix_rotate (&matrix, angle); + pango_context_set_matrix (m_context, &matrix); + pango_layout_context_changed (m_layout); + + // To be compatible with MSW, the rotation axis must be in the old + // top-left corner. + // Calculate the vertices of the rotated rectangle containing the text, + // relative to the old top-left vertex. + // We could use the matrix for this, but it's simpler with trignonometry. + double rad = DegToRad(angle); + // the rectangle vertices are counted clockwise with the first one + // being at (0, 0) + double x2 = w * cos(rad); + double y2 = -w * sin(rad); // y axis points to the bottom, hence minus + double x4 = h * sin(rad); + double y4 = h * cos(rad); + double x3 = x4 + x2; + double y3 = y4 + y2; + // Then we calculate max and min of the rotated rectangle. + wxCoord maxX = (wxCoord)(dmax(dmax(0, x2), dmax(x3, x4)) + 0.5), + maxY = (wxCoord)(dmax(dmax(0, y2), dmax(y3, y4)) + 0.5), + minX = (wxCoord)(dmin(dmin(0, x2), dmin(x3, x4)) - 0.5), + minY = (wxCoord)(dmin(dmin(0, y2), dmin(y3, y4)) - 0.5); + + gdk_draw_layout_with_colors(m_gdkwindow, m_textGC, x+minX, y+minY, + m_layout, NULL, bg_col); + + if (m_font.GetUnderlined()) + pango_layout_set_attributes(m_layout, NULL); + + // clean up the transformation matrix + pango_context_set_matrix(m_context, NULL); + + if (isScaled) + { + // reset unscaled size + pango_font_description_set_size( m_fontdesc, oldSize ); + + // actually apply unscaled font + pango_layout_set_font_description( m_layout, m_fontdesc ); + } + + CalcBoundingBox(x+minX, y+minY); + CalcBoundingBox(x+maxX, y+maxY); + } + else +#endif //__WXGTK26__ + { +#if wxUSE_IMAGE if ( wxIsNullDouble(angle) ) { DoDrawText(text, x, y); @@ -1592,6 +1680,7 @@ void wxWindowDCImpl::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord wxUnusedVar(y); wxUnusedVar(angle); #endif // wxUSE_IMAGE/!wxUSE_IMAGE + } } void wxWindowDCImpl::DoGetTextExtent(const wxString &string, @@ -2009,9 +2098,7 @@ void wxWindowDCImpl::SetLogicalFunction( int function ) case wxCOPY: mode = GDK_COPY; break; case wxNO_OP: mode = GDK_NOOP; break; case wxSRC_INVERT: mode = GDK_COPY_INVERT; break; - - // unsupported by GTK - case wxNOR: mode = GDK_COPY; break; + case wxNOR: mode = GDK_NOR; break; default: wxFAIL_MSG( wxT("unsupported logical function") ); mode = GDK_COPY; @@ -2094,28 +2181,10 @@ void wxWindowDCImpl::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, w rect.x -= rect.width; } - if (!m_currentClippingRegion.IsNull()) - m_currentClippingRegion.Intersect( rect ); - else - m_currentClippingRegion.Union( rect ); - -#if USE_PAINT_REGION - if (!m_paintClippingRegion.IsNull()) - m_currentClippingRegion.Intersect( m_paintClippingRegion ); -#endif - - wxCoord xx, yy, ww, hh; - m_currentClippingRegion.GetBox( xx, yy, ww, hh ); - wxGTKDCImpl::DoSetClippingRegion( xx, yy, ww, hh ); - - GdkRegion* gdkRegion = m_currentClippingRegion.GetRegion(); - gdk_gc_set_clip_region(m_penGC, gdkRegion); - gdk_gc_set_clip_region(m_brushGC, gdkRegion); - gdk_gc_set_clip_region(m_textGC, gdkRegion); - gdk_gc_set_clip_region(m_bgGC, gdkRegion); + DoSetDeviceClippingRegion(wxRegion(rect)); } -void wxWindowDCImpl::DoSetClippingRegionAsRegion( const wxRegion ®ion ) +void wxWindowDCImpl::DoSetDeviceClippingRegion( const wxRegion ®ion ) { wxCHECK_RET( IsOk(), wxT("invalid window dc") );