1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/dcclient.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Markus Holzem, Chris Breeze
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "dcclient.h"
14 #include "wx/dcclient.h"
15 #include "wx/dcmemory.h"
17 #include "wx/module.h"
19 #include "wx/gtk/win_gtk.h"
21 #include <math.h> // for floating-point functions
25 #include <gdk/gdkprivate.h>
28 //-----------------------------------------------------------------------------
30 //-----------------------------------------------------------------------------
32 #define USE_PAINT_REGION 1
34 //-----------------------------------------------------------------------------
36 //-----------------------------------------------------------------------------
46 static GdkPixmap
*hatches
[num_hatches
];
47 static GdkPixmap
**hatch_bitmap
= (GdkPixmap
**) NULL
;
49 extern GtkWidget
*wxRootWindow
;
51 //-----------------------------------------------------------------------------
53 //-----------------------------------------------------------------------------
55 const double RAD2DEG
= 180.0 / M_PI
;
57 // ----------------------------------------------------------------------------
59 // ----------------------------------------------------------------------------
61 static inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
62 static inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
64 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
66 //-----------------------------------------------------------------------------
67 // temporary implementation of the missing GDK function
68 //-----------------------------------------------------------------------------
70 #include "gdk/gdkprivate.h"
72 void gdk_wx_draw_bitmap (GdkDrawable
*drawable
,
82 gint src_width
, src_height
;
84 GdkWindowPrivate
*drawable_private
;
85 GdkWindowPrivate
*src_private
;
86 GdkGCPrivate
*gc_private
;
89 g_return_if_fail (drawable
!= NULL
);
90 g_return_if_fail (src
!= NULL
);
91 g_return_if_fail (gc
!= NULL
);
94 if (GDK_WINDOW_DESTROYED(drawable
) || GDK_WINDOW_DESTROYED(src
))
97 gdk_drawable_get_size(src
, &src_width
, &src_height
);
99 drawable_private
= (GdkWindowPrivate
*) drawable
;
100 src_private
= (GdkWindowPrivate
*) src
;
101 if (drawable_private
->destroyed
|| src_private
->destroyed
)
104 src_width
= src_private
->width
;
105 src_height
= src_private
->height
;
107 gc_private
= (GdkGCPrivate
*) gc
;
110 if (width
== -1) width
= src_width
;
111 if (height
== -1) height
= src_height
;
114 XCopyPlane( GDK_WINDOW_XDISPLAY(drawable
),
116 GDK_WINDOW_XID(drawable
),
123 XCopyPlane( drawable_private
->xdisplay
,
124 src_private
->xwindow
,
125 drawable_private
->xwindow
,
134 //-----------------------------------------------------------------------------
135 // Implement Pool of Graphic contexts. Creating them takes too much time.
136 //-----------------------------------------------------------------------------
138 #define GC_POOL_SIZE 200
164 static wxGC wxGCPool
[GC_POOL_SIZE
];
166 static void wxInitGCPool()
168 memset( wxGCPool
, 0, GC_POOL_SIZE
*sizeof(wxGC
) );
171 static void wxCleanUpGCPool()
173 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
175 if (wxGCPool
[i
].m_gc
)
176 gdk_gc_unref( wxGCPool
[i
].m_gc
);
180 static GdkGC
* wxGetPoolGC( GdkWindow
*window
, wxPoolGCType type
)
182 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
184 if (!wxGCPool
[i
].m_gc
)
186 wxGCPool
[i
].m_gc
= gdk_gc_new( window
);
187 gdk_gc_set_exposures( wxGCPool
[i
].m_gc
, FALSE
);
188 wxGCPool
[i
].m_type
= type
;
189 wxGCPool
[i
].m_used
= FALSE
;
191 if ((!wxGCPool
[i
].m_used
) && (wxGCPool
[i
].m_type
== type
))
193 wxGCPool
[i
].m_used
= TRUE
;
194 return wxGCPool
[i
].m_gc
;
198 wxFAIL_MSG( wxT("No GC available") );
200 return (GdkGC
*) NULL
;
203 static void wxFreePoolGC( GdkGC
*gc
)
205 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
207 if (wxGCPool
[i
].m_gc
== gc
)
209 wxGCPool
[i
].m_used
= FALSE
;
214 wxFAIL_MSG( wxT("Wrong GC") );
217 //-----------------------------------------------------------------------------
219 //-----------------------------------------------------------------------------
221 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
223 wxWindowDC::wxWindowDC()
225 m_penGC
= (GdkGC
*) NULL
;
226 m_brushGC
= (GdkGC
*) NULL
;
227 m_textGC
= (GdkGC
*) NULL
;
228 m_bgGC
= (GdkGC
*) NULL
;
229 m_cmap
= (GdkColormap
*) NULL
;
231 m_isScreenDC
= FALSE
;
232 m_owner
= (wxWindow
*)NULL
;
234 m_context
= (PangoContext
*)NULL
;
235 m_fontdesc
= (PangoFontDescription
*)NULL
;
239 wxWindowDC::wxWindowDC( wxWindow
*window
)
241 m_penGC
= (GdkGC
*) NULL
;
242 m_brushGC
= (GdkGC
*) NULL
;
243 m_textGC
= (GdkGC
*) NULL
;
244 m_bgGC
= (GdkGC
*) NULL
;
245 m_cmap
= (GdkColormap
*) NULL
;
246 m_owner
= (wxWindow
*)NULL
;
248 m_isScreenDC
= FALSE
;
249 m_font
= window
->GetFont();
251 wxASSERT_MSG( window
, wxT("DC needs a window") );
253 GtkWidget
*widget
= window
->m_wxwindow
;
255 // some controls don't have m_wxwindow - like wxStaticBox, but the user
256 // code should still be able to create wxClientDCs for them, so we will
257 // use the parent window here then
260 window
= window
->GetParent();
261 widget
= window
->m_wxwindow
;
264 wxASSERT_MSG( widget
, wxT("DC needs a widget") );
267 m_context
= gtk_widget_get_pango_context( widget
);
268 m_fontdesc
= widget
->style
->font_desc
;
271 GtkPizza
*pizza
= GTK_PIZZA( widget
);
272 m_window
= pizza
->bin_window
;
277 /* don't report problems */
283 m_cmap
= gtk_widget_get_colormap( widget
? widget
: window
->m_widget
);
287 /* this must be done after SetUpDC, bacause SetUpDC calls the
288 repective SetBrush, SetPen, SetBackground etc functions
289 to set up the DC. SetBackground call m_owner->SetBackground
290 and this might not be desired as the standard dc background
291 is white whereas a window might assume gray to be the
292 standard (as e.g. wxStatusBar) */
297 wxWindowDC::~wxWindowDC()
302 void wxWindowDC::SetUpDC()
306 wxASSERT_MSG( !m_penGC
, wxT("GCs already created") );
310 m_penGC
= wxGetPoolGC( m_window
, wxPEN_SCREEN
);
311 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_SCREEN
);
312 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_SCREEN
);
313 m_bgGC
= wxGetPoolGC( m_window
, wxBG_SCREEN
);
316 if (m_isMemDC
&& (((wxMemoryDC
*)this)->m_selected
.GetDepth() == 1))
318 m_penGC
= wxGetPoolGC( m_window
, wxPEN_MONO
);
319 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_MONO
);
320 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_MONO
);
321 m_bgGC
= wxGetPoolGC( m_window
, wxBG_MONO
);
325 m_penGC
= wxGetPoolGC( m_window
, wxPEN_COLOUR
);
326 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_COLOUR
);
327 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_COLOUR
);
328 m_bgGC
= wxGetPoolGC( m_window
, wxBG_COLOUR
);
331 /* background colour */
332 m_backgroundBrush
= *wxWHITE_BRUSH
;
333 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
334 GdkColor
*bg_col
= m_backgroundBrush
.GetColour().GetColor();
337 m_textForegroundColour
.CalcPixel( m_cmap
);
338 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
340 m_textBackgroundColour
.CalcPixel( m_cmap
);
341 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
343 gdk_gc_set_fill( m_textGC
, GDK_SOLID
);
346 m_pen
.GetColour().CalcPixel( m_cmap
);
347 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
348 gdk_gc_set_background( m_penGC
, bg_col
);
350 gdk_gc_set_line_attributes( m_penGC
, 0, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
, GDK_JOIN_ROUND
);
353 m_brush
.GetColour().CalcPixel( m_cmap
);
354 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
355 gdk_gc_set_background( m_brushGC
, bg_col
);
357 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
360 gdk_gc_set_background( m_bgGC
, bg_col
);
361 gdk_gc_set_foreground( m_bgGC
, bg_col
);
363 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
366 gdk_gc_set_function( m_textGC
, GDK_COPY
);
367 gdk_gc_set_function( m_brushGC
, GDK_COPY
);
368 gdk_gc_set_function( m_penGC
, GDK_COPY
);
371 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
372 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
373 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
374 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
378 hatch_bitmap
= hatches
;
379 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
380 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
381 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
382 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
383 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
384 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
388 void wxWindowDC::DoFloodFill( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
389 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
391 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
394 bool wxWindowDC::DoGetPixel( wxCoord x1
, wxCoord y1
, wxColour
*col
) const
396 // Generic (and therefore rather inefficient) method.
397 // Could be improved.
399 wxBitmap
bitmap(1, 1);
400 memdc
.SelectObject(bitmap
);
401 memdc
.Blit(0, 0, 1, 1, (wxDC
*) this, x1
, y1
);
402 memdc
.SelectObject(wxNullBitmap
);
403 wxImage
image(bitmap
);
404 col
->Set(image
.GetRed(0, 0), image
.GetGreen(0, 0), image
.GetBlue(0, 0));
408 void wxWindowDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
410 wxCHECK_RET( Ok(), wxT("invalid window dc") );
412 if (m_pen
.GetStyle() != wxTRANSPARENT
)
415 gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
417 CalcBoundingBox(x1
, y1
);
418 CalcBoundingBox(x2
, y2
);
422 void wxWindowDC::DoCrossHair( wxCoord x
, wxCoord y
)
424 wxCHECK_RET( Ok(), wxT("invalid window dc") );
426 if (m_pen
.GetStyle() != wxTRANSPARENT
)
431 wxCoord xx
= XLOG2DEV(x
);
432 wxCoord yy
= YLOG2DEV(y
);
435 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
436 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
441 void wxWindowDC::DoDrawArc( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
,
442 wxCoord xc
, wxCoord yc
)
444 wxCHECK_RET( Ok(), wxT("invalid window dc") );
446 wxCoord xx1
= XLOG2DEV(x1
);
447 wxCoord yy1
= YLOG2DEV(y1
);
448 wxCoord xx2
= XLOG2DEV(x2
);
449 wxCoord yy2
= YLOG2DEV(y2
);
450 wxCoord xxc
= XLOG2DEV(xc
);
451 wxCoord yyc
= YLOG2DEV(yc
);
452 double dx
= xx1
- xxc
;
453 double dy
= yy1
- yyc
;
454 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
455 wxCoord r
= (wxCoord
)radius
;
456 double radius1
, radius2
;
458 if (xx1
== xx2
&& yy1
== yy2
)
466 radius1
= radius2
= 0.0;
470 radius1
= (xx1
- xxc
== 0) ?
471 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
472 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
473 radius2
= (xx2
- xxc
== 0) ?
474 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
475 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
477 wxCoord alpha1
= wxCoord(radius1
* 64.0);
478 wxCoord alpha2
= wxCoord((radius2
- radius1
) * 64.0);
479 while (alpha2
<= 0) alpha2
+= 360*64;
480 while (alpha1
> 360*64) alpha1
-= 360*64;
484 if (m_brush
.GetStyle() != wxTRANSPARENT
)
486 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
488 gdk_gc_set_ts_origin( m_textGC
,
489 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
490 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
491 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
492 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
494 if (m_brush
.GetStyle() == wxSTIPPLE
)
496 gdk_gc_set_ts_origin( m_brushGC
,
497 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
498 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
499 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
500 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
504 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
508 if (m_pen
.GetStyle() != wxTRANSPARENT
)
509 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
512 CalcBoundingBox (x1
, y1
);
513 CalcBoundingBox (x2
, y2
);
516 void wxWindowDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
518 wxCHECK_RET( Ok(), wxT("invalid window dc") );
520 wxCoord xx
= XLOG2DEV(x
);
521 wxCoord yy
= YLOG2DEV(y
);
522 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
523 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
525 // CMB: handle -ve width and/or height
526 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
527 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
531 wxCoord start
= wxCoord(sa
* 64.0);
532 wxCoord end
= wxCoord(ea
* 64.0);
534 if (m_brush
.GetStyle() != wxTRANSPARENT
)
536 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
538 gdk_gc_set_ts_origin( m_textGC
,
539 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
540 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
541 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
542 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
544 if (m_brush
.GetStyle() == wxSTIPPLE
)
546 gdk_gc_set_ts_origin( m_brushGC
,
547 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
548 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
549 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
550 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
554 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
558 if (m_pen
.GetStyle() != wxTRANSPARENT
)
559 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
562 CalcBoundingBox (x
, y
);
563 CalcBoundingBox (x
+ width
, y
+ height
);
566 void wxWindowDC::DoDrawPoint( wxCoord x
, wxCoord y
)
568 wxCHECK_RET( Ok(), wxT("invalid window dc") );
570 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
571 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
573 CalcBoundingBox (x
, y
);
576 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
578 wxCHECK_RET( Ok(), wxT("invalid window dc") );
580 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
583 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
585 for (int i
= 0; i
< n
-1; i
++)
587 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
588 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
589 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
590 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
593 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
595 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
599 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
601 wxCHECK_RET( Ok(), wxT("invalid window dc") );
605 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
607 for (i
= 0 ; i
< n
; i
++)
609 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
610 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
612 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
617 if (m_brush
.GetStyle() != wxTRANSPARENT
)
619 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
621 gdk_gc_set_ts_origin( m_textGC
,
622 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
623 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
624 gdk_draw_polygon( m_window
, m_textGC
, TRUE
, gdkpoints
, n
);
625 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
627 if (m_brush
.GetStyle() == wxSTIPPLE
)
629 gdk_gc_set_ts_origin( m_brushGC
,
630 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
631 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
632 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
633 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
637 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
641 if (m_pen
.GetStyle() != wxTRANSPARENT
)
643 for (i
= 0 ; i
< n
; i
++)
645 gdk_draw_line( m_window
, m_penGC
,
648 gdkpoints
[(i
+1)%n
].x
,
649 gdkpoints
[(i
+1)%n
].y
);
657 void wxWindowDC::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
659 wxCHECK_RET( Ok(), wxT("invalid window dc") );
661 wxCoord xx
= XLOG2DEV(x
);
662 wxCoord yy
= YLOG2DEV(y
);
663 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
664 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
666 // CMB: draw nothing if transformed w or h is 0
667 if (ww
== 0 || hh
== 0) return;
669 // CMB: handle -ve width and/or height
670 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
671 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
675 if (m_brush
.GetStyle() != wxTRANSPARENT
)
677 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
679 gdk_gc_set_ts_origin( m_textGC
,
680 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
681 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
682 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
);
683 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
685 else if (m_brush
.GetStyle() == wxSTIPPLE
)
687 gdk_gc_set_ts_origin( m_brushGC
,
688 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
689 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
690 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
691 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
695 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
699 if (m_pen
.GetStyle() != wxTRANSPARENT
)
700 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
703 CalcBoundingBox( x
, y
);
704 CalcBoundingBox( x
+ width
, y
+ height
);
707 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
709 wxCHECK_RET( Ok(), wxT("invalid window dc") );
711 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
713 wxCoord xx
= XLOG2DEV(x
);
714 wxCoord yy
= YLOG2DEV(y
);
715 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
716 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
717 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
719 // CMB: handle -ve width and/or height
720 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
721 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
723 // CMB: if radius is zero use DrawRectangle() instead to avoid
724 // X drawing errors with small radii
727 DrawRectangle( x
, y
, width
, height
);
731 // CMB: draw nothing if transformed w or h is 0
732 if (ww
== 0 || hh
== 0) return;
734 // CMB: adjust size if outline is drawn otherwise the result is
735 // 1 pixel too wide and high
736 if (m_pen
.GetStyle() != wxTRANSPARENT
)
744 // CMB: ensure dd is not larger than rectangle otherwise we
745 // get an hour glass shape
747 if (dd
> ww
) dd
= ww
;
748 if (dd
> hh
) dd
= hh
;
751 if (m_brush
.GetStyle() != wxTRANSPARENT
)
753 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
755 gdk_gc_set_ts_origin( m_textGC
,
756 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
757 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
758 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
759 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
760 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
761 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
762 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
763 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
764 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
766 else if (m_brush
.GetStyle() == wxSTIPPLE
)
768 gdk_gc_set_ts_origin( m_brushGC
,
769 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
770 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
771 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
772 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
773 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
774 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
775 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
776 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
777 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
781 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
782 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
783 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
784 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
785 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
786 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
790 if (m_pen
.GetStyle() != wxTRANSPARENT
)
792 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
, xx
+ww
-rr
, yy
);
793 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
794 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
, xx
, yy
+hh
-rr
);
795 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
, xx
+ww
, yy
+hh
-rr
);
796 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
797 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
798 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
799 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
803 // this ignores the radius
804 CalcBoundingBox( x
, y
);
805 CalcBoundingBox( x
+ width
, y
+ height
);
808 void wxWindowDC::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
810 wxCHECK_RET( Ok(), wxT("invalid window dc") );
812 wxCoord xx
= XLOG2DEV(x
);
813 wxCoord yy
= YLOG2DEV(y
);
814 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
815 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
817 // CMB: handle -ve width and/or height
818 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
819 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
823 if (m_brush
.GetStyle() != wxTRANSPARENT
)
825 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
827 gdk_gc_set_ts_origin( m_textGC
,
828 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
829 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
830 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
831 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
833 else if (m_brush
.GetStyle() == wxSTIPPLE
)
835 gdk_gc_set_ts_origin( m_brushGC
,
836 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
837 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
838 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
839 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
843 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
847 if (m_pen
.GetStyle() != wxTRANSPARENT
)
848 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
851 CalcBoundingBox( x
- width
, y
- height
);
852 CalcBoundingBox( x
+ width
, y
+ height
);
855 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
857 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
858 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
861 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
862 wxCoord x
, wxCoord y
,
865 wxCHECK_RET( Ok(), wxT("invalid window dc") );
867 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
869 bool is_mono
= (bitmap
.GetBitmap() != NULL
);
871 /* scale/translate size and position */
872 int xx
= XLOG2DEV(x
);
873 int yy
= YLOG2DEV(y
);
875 int w
= bitmap
.GetWidth();
876 int h
= bitmap
.GetHeight();
878 CalcBoundingBox( x
, y
);
879 CalcBoundingBox( x
+ w
, y
+ h
);
881 if (!m_window
) return;
883 int ww
= XLOG2DEVREL(w
);
884 int hh
= YLOG2DEVREL(h
);
886 /* compare to current clipping region */
887 if (!m_currentClippingRegion
.IsNull())
889 wxRegion
tmp( xx
,yy
,ww
,hh
);
890 tmp
.Intersect( m_currentClippingRegion
);
895 /* scale bitmap if required */
897 if ((w
!= ww
) || (h
!= hh
))
899 wxImage
image( bitmap
);
900 image
.Rescale( ww
, hh
);
902 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
904 use_bitmap
= image
.ConvertToBitmap();
911 /* apply mask if any */
912 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
913 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
917 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
918 if (!m_currentClippingRegion
.IsNull())
921 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, ww
, hh
, 1 );
922 GdkGC
*gc
= gdk_gc_new( new_mask
);
924 gdk_gc_set_foreground( gc
, &col
);
925 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
927 gdk_gc_set_background( gc
, &col
);
929 gdk_gc_set_foreground( gc
, &col
);
930 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
931 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
932 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
933 gdk_gc_set_stipple( gc
, mask
);
934 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
941 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
943 gdk_gc_set_clip_mask( m_textGC
, mask
);
944 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
949 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
951 gdk_gc_set_clip_mask( m_penGC
, mask
);
952 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
955 gdk_bitmap_unref( new_mask
);
958 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
959 drawing a mono-bitmap (XBitmap) we use the current text GC */
961 gdk_wx_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), 0, 0, xx
, yy
, -1, -1 );
963 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
965 /* remove mask again if any */
970 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
971 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
972 if (!m_currentClippingRegion
.IsNull())
973 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
977 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
978 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
979 if (!m_currentClippingRegion
.IsNull())
980 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
985 bool wxWindowDC::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
986 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
987 int logical_func
, bool useMask
)
989 /* this is the nth try to get this utterly useless function to
990 work. it now completely ignores the scaling or translation
991 of the source dc, but scales correctly on the target dc and
992 knows about possible mask information in a memory dc. */
994 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
996 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
998 if (!m_window
) return FALSE
;
1000 wxClientDC
*srcDC
= (wxClientDC
*)source
;
1001 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
1003 bool use_bitmap_method
= FALSE
;
1004 bool is_mono
= FALSE
;
1006 if (srcDC
->m_isMemDC
)
1008 if (!memDC
->m_selected
.Ok()) return FALSE
;
1010 /* we use the "XCopyArea" way to copy a memory dc into
1011 y different window if the memory dc BOTH
1012 a) doesn't have any mask or its mask isn't used
1016 if (useMask
&& (memDC
->m_selected
.GetMask()))
1018 /* we HAVE TO use the direct way for memory dcs
1019 that have mask since the XCopyArea doesn't know
1021 use_bitmap_method
= TRUE
;
1023 else if (memDC
->m_selected
.GetDepth() == 1)
1025 /* we HAVE TO use the direct way for memory dcs
1026 that are bitmaps because XCopyArea doesn't cope
1027 with different bit depths */
1029 use_bitmap_method
= TRUE
;
1031 else if ((xsrc
== 0) && (ysrc
== 0) &&
1032 (width
== memDC
->m_selected
.GetWidth()) &&
1033 (height
== memDC
->m_selected
.GetHeight()))
1035 /* we SHOULD use the direct way if all of the bitmap
1036 in the memory dc is copied in which case XCopyArea
1037 wouldn't be able able to boost performace by reducing
1038 the area to be scaled */
1039 use_bitmap_method
= TRUE
;
1043 use_bitmap_method
= FALSE
;
1047 CalcBoundingBox( xdest
, ydest
);
1048 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
1050 /* scale/translate size and position */
1051 wxCoord xx
= XLOG2DEV(xdest
);
1052 wxCoord yy
= YLOG2DEV(ydest
);
1054 wxCoord ww
= XLOG2DEVREL(width
);
1055 wxCoord hh
= YLOG2DEVREL(height
);
1057 /* compare to current clipping region */
1058 if (!m_currentClippingRegion
.IsNull())
1060 wxRegion
tmp( xx
,yy
,ww
,hh
);
1061 tmp
.Intersect( m_currentClippingRegion
);
1066 int old_logical_func
= m_logicalFunction
;
1067 SetLogicalFunction( logical_func
);
1069 if (use_bitmap_method
)
1071 /* scale/translate bitmap size */
1072 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
1073 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
1075 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
1076 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
1078 /* scale bitmap if required */
1079 wxBitmap use_bitmap
;
1081 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
1083 wxImage
image( memDC
->m_selected
);
1084 image
= image
.Scale( bm_ww
, bm_hh
);
1087 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
1089 use_bitmap
= image
.ConvertToBitmap();
1093 use_bitmap
= memDC
->m_selected
;
1096 /* apply mask if any */
1097 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
1098 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
1100 if (useMask
&& mask
)
1102 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
1103 if (!m_currentClippingRegion
.IsNull())
1106 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, bm_ww
, bm_hh
, 1 );
1107 GdkGC
*gc
= gdk_gc_new( new_mask
);
1109 gdk_gc_set_foreground( gc
, &col
);
1110 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
1112 gdk_gc_set_background( gc
, &col
);
1114 gdk_gc_set_foreground( gc
, &col
);
1115 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
1116 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
1117 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
1118 gdk_gc_set_stipple( gc
, mask
);
1119 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
1126 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
1128 gdk_gc_set_clip_mask( m_textGC
, mask
);
1129 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
1134 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
1136 gdk_gc_set_clip_mask( m_penGC
, mask
);
1137 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
1140 gdk_bitmap_unref( new_mask
);
1143 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1144 drawing a mono-bitmap (XBitmap) we use the current text GC */
1147 gdk_wx_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
1149 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
1151 /* remove mask again if any */
1152 if (useMask
&& mask
)
1156 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
1157 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
1158 if (!m_currentClippingRegion
.IsNull())
1159 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1163 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
1164 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
1165 if (!m_currentClippingRegion
.IsNull())
1166 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1170 else /* use_bitmap_method */
1172 if ((width
!= ww
) || (height
!= hh
))
1174 /* draw source window into a bitmap as we cannot scale
1175 a window in contrast to a bitmap. this would actually
1176 work with memory dcs as well, but we'd lose the mask
1177 information and waste one step in this process since
1178 a memory already has a bitmap. all this is slightly
1179 inefficient as we could take an XImage directly from
1180 an X window, but we'd then also have to care that
1181 the window is not outside the screen (in which case
1182 we'd get a BadMatch or what not).
1183 Is a double XGetImage and combined XGetPixel and
1184 XPutPixel really faster? I'm not sure. look at wxXt
1185 for a different implementation of the same problem. */
1187 wxBitmap
bitmap( width
, height
);
1189 /* copy including child window contents */
1190 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1191 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
1193 xsrc
, ysrc
, width
, height
);
1194 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1197 wxImage
image( bitmap
);
1198 image
= image
.Scale( ww
, hh
);
1200 /* convert to bitmap */
1201 bitmap
= image
.ConvertToBitmap();
1203 /* draw scaled bitmap */
1204 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
1209 /* No scaling and not a memory dc with a mask either */
1211 /* copy including child window contents */
1212 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1213 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
1215 xsrc
, ysrc
, width
, height
);
1216 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1220 SetLogicalFunction( old_logical_func
);
1224 void wxWindowDC::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
1226 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1228 if (!m_window
) return;
1230 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1232 wxCHECK_RET( font
, wxT("invalid font") );
1235 wxCHECK_RET( m_context
, wxT("no Pango context") );
1242 /* FIXME: the layout engine should probably be abstracted at a higher level in wxDC... */
1243 PangoLayout
*layout
= pango_layout_new(m_context
);
1244 pango_layout_set_font_description(layout
, m_fontdesc
);
1246 wxWX2MBbuf data
= text
.mb_str(wxConvUTF8
);
1247 pango_layout_set_text(layout
, data
, strlen(data
));
1249 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
1250 PangoRectangle rect
;
1251 pango_layout_line_get_extents(line
, NULL
, &rect
);
1252 wxCoord width
= rect
.width
;
1253 wxCoord height
= rect
.height
;
1254 gdk_draw_layout( m_window
, m_textGC
, x
, y
, layout
);
1256 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1257 wxCoord height
= font
->ascent
+ font
->descent
;
1258 /* CMB 21/5/98: draw text background if mode is wxSOLID */
1259 if (m_backgroundMode
== wxSOLID
)
1261 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
1262 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
1263 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1265 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
1268 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1269 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1270 properties (see wxXt implementation) */
1271 if (m_font
.GetUnderlined())
1273 wxCoord ul_y
= y
+ font
->ascent
;
1274 if (font
->descent
> 0) ul_y
++;
1275 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
1279 g_object_unref( G_OBJECT( layout
) );
1282 width
= wxCoord(width
/ m_scaleX
);
1283 height
= wxCoord(height
/ m_scaleY
);
1284 CalcBoundingBox (x
+ width
, y
+ height
);
1285 CalcBoundingBox (x
, y
);
1288 void wxWindowDC::DoDrawRotatedText( const wxString
&text
, wxCoord x
, wxCoord y
, double angle
)
1292 DrawText(text
, x
, y
);
1296 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1298 if (!m_window
) return;
1300 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1302 wxCHECK_RET( font
, wxT("invalid font") );
1304 // the size of the text
1305 wxCoord w
= gdk_string_width( font
, text
.mbc_str() );
1306 wxCoord h
= font
->ascent
+ font
->descent
;
1308 // draw the string normally
1311 dc
.SelectObject(src
);
1312 dc
.SetFont(GetFont());
1313 dc
.SetBackground(*wxWHITE_BRUSH
);
1314 dc
.SetBrush(*wxBLACK_BRUSH
);
1316 dc
.DrawText(text
, 0, 0);
1317 dc
.SetFont(wxNullFont
);
1318 dc
.SelectObject(wxNullBitmap
);
1320 // Calculate the size of the rotated bounding box.
1321 double rad
= DegToRad(angle
);
1322 double dx
= cos(rad
),
1325 // the rectngle vertices are counted clockwise with the first one being at
1326 // (0, 0) (or, rather, at (x, y))
1328 y2
= -w
*dy
; // y axis points to the bottom, hence minus
1331 double x3
= x4
+ x2
,
1335 wxCoord maxX
= (wxCoord
)(dmax(x2
, dmax(x3
, x4
)) + 0.5),
1336 maxY
= (wxCoord
)(dmax(y2
, dmax(y3
, y4
)) + 0.5),
1337 minX
= (wxCoord
)(dmin(x2
, dmin(x3
, x4
)) - 0.5),
1338 minY
= (wxCoord
)(dmin(y2
, dmin(y3
, y4
)) - 0.5);
1340 // prepare to blit-with-rotate the bitmap to the DC
1343 GdkColor
*colText
= m_textForegroundColour
.GetColor(),
1344 *colBack
= m_textBackgroundColour
.GetColor();
1346 bool textColSet
= TRUE
;
1348 unsigned char *data
= image
.GetData();
1350 // paint pixel by pixel
1351 for ( wxCoord srcX
= 0; srcX
< w
; srcX
++ )
1353 for ( wxCoord srcY
= 0; srcY
< h
; srcY
++ )
1355 // transform source coords to dest coords
1356 double r
= sqrt((double)srcX
*srcX
+ srcY
*srcY
);
1357 double angleOrig
= atan2((double)srcY
, (double)srcX
) - rad
;
1358 wxCoord dstX
= (wxCoord
)(r
*cos(angleOrig
) + 0.5),
1359 dstY
= (wxCoord
)(r
*sin(angleOrig
) + 0.5);
1362 bool textPixel
= data
[(srcY
*w
+ srcX
)*3] == 0;
1363 if ( textPixel
|| (m_backgroundMode
== wxSOLID
) )
1365 // change colour if needed
1366 if ( textPixel
!= textColSet
)
1368 gdk_gc_set_foreground( m_textGC
, textPixel
? colText
1371 textColSet
= textPixel
;
1374 // don't use DrawPoint() because it uses the current pen
1375 // colour, and we don't need it here
1376 gdk_draw_point( m_window
, m_textGC
,
1377 XLOG2DEV(x
+ dstX
), YLOG2DEV(y
+ dstY
) );
1382 // it would be better to draw with non underlined font and draw the line
1383 // manually here (it would be more straight...)
1385 if ( m_font
.GetUnderlined() )
1387 gdk_draw_line( m_window
, m_textGC
,
1388 XLOG2DEV(x
+ x4
), YLOG2DEV(y
+ y4
+ font
->descent
),
1389 XLOG2DEV(x
+ x3
), YLOG2DEV(y
+ y3
+ font
->descent
));
1393 // restore the font colour
1394 gdk_gc_set_foreground( m_textGC
, colText
);
1396 // update the bounding box
1397 CalcBoundingBox(x
+ minX
, y
+ minY
);
1398 CalcBoundingBox(x
+ maxX
, y
+ maxY
);
1401 void wxWindowDC::DoGetTextExtent(const wxString
&string
,
1402 wxCoord
*width
, wxCoord
*height
,
1403 wxCoord
*descent
, wxCoord
*externalLeading
,
1404 wxFont
*theFont
) const
1406 wxFont fontToUse
= m_font
;
1407 if (theFont
) fontToUse
= *theFont
;
1409 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
1410 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
1411 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1412 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
1413 if (externalLeading
) (*externalLeading
) = 0; // ??
1416 wxCoord
wxWindowDC::GetCharWidth() const
1418 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1419 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1421 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
1424 wxCoord
wxWindowDC::GetCharHeight() const
1426 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1427 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1429 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1432 void wxWindowDC::Clear()
1434 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1436 if (!m_window
) return;
1438 /* - we either are a memory dc or have a window as the
1439 owner. anything else shouldn't happen.
1440 - we don't use gdk_window_clear() as we don't set
1441 the window's background colour anymore. it is too
1442 much pain to keep the DC's and the window's back-
1443 ground colour in synch. */
1448 m_owner
->GetSize( &width
, &height
);
1449 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1456 GetSize( &width
, &height
);
1457 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1462 void wxWindowDC::SetFont( const wxFont
&font
)
1470 void wxWindowDC::SetPen( const wxPen
&pen
)
1472 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1474 if (m_pen
== pen
) return;
1478 if (!m_pen
.Ok()) return;
1480 if (!m_window
) return;
1482 gint width
= m_pen
.GetWidth();
1485 // CMB: if width is non-zero scale it with the dc
1490 // X doesn't allow different width in x and y and so we take
1493 ( fabs((double) XLOG2DEVREL(width
)) +
1494 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
1498 static const wxGTKDash dotted
[] = {1, 1};
1499 static const wxGTKDash short_dashed
[] = {2, 2};
1500 static const wxGTKDash wxCoord_dashed
[] = {2, 4};
1501 static const wxGTKDash dotted_dashed
[] = {3, 3, 1, 3};
1503 // We express dash pattern in pen width unit, so we are
1504 // independent of zoom factor and so on...
1506 const wxGTKDash
*req_dash
;
1508 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
1509 switch (m_pen
.GetStyle())
1513 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1514 req_nb_dash
= m_pen
.GetDashCount();
1515 req_dash
= (wxGTKDash
*)m_pen
.GetDash();
1520 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1527 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1529 req_dash
= wxCoord_dashed
;
1534 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1536 req_dash
= short_dashed
;
1541 // lineStyle = GDK_LINE_DOUBLE_DASH;
1542 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1544 req_dash
= dotted_dashed
;
1549 case wxSTIPPLE_MASK_OPAQUE
:
1554 lineStyle
= GDK_LINE_SOLID
;
1555 req_dash
= (wxGTKDash
*)NULL
;
1561 #if (GTK_MINOR_VERSION > 0) || (GTK_MAJOR_VERSION > 1)
1562 if (req_dash
&& req_nb_dash
)
1564 wxGTKDash
*real_req_dash
= new wxGTKDash
[req_nb_dash
];
1567 for (int i
= 0; i
< req_nb_dash
; i
++)
1568 real_req_dash
[i
] = req_dash
[i
] * width
;
1569 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
1570 delete[] real_req_dash
;
1574 // No Memory. We use non-scaled dash pattern...
1575 gdk_gc_set_dashes( m_penGC
, 0, (wxGTKDash
*)req_dash
, req_nb_dash
);
1580 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
1581 switch (m_pen
.GetCap())
1583 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
1584 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
1591 capStyle
= GDK_CAP_NOT_LAST
;
1595 capStyle
= GDK_CAP_ROUND
;
1601 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
1602 switch (m_pen
.GetJoin())
1604 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
1605 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
1607 default: { joinStyle
= GDK_JOIN_ROUND
; break; }
1610 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
1612 m_pen
.GetColour().CalcPixel( m_cmap
);
1613 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1616 void wxWindowDC::SetBrush( const wxBrush
&brush
)
1618 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1620 if (m_brush
== brush
) return;
1624 if (!m_brush
.Ok()) return;
1626 if (!m_window
) return;
1628 m_brush
.GetColour().CalcPixel( m_cmap
);
1629 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1631 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1633 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1635 if (m_brush
.GetStipple()->GetPixmap())
1637 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1638 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1642 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1643 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1647 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
1649 gdk_gc_set_fill( m_textGC
, GDK_OPAQUE_STIPPLED
);
1650 gdk_gc_set_stipple( m_textGC
, m_brush
.GetStipple()->GetMask()->GetBitmap() );
1653 if (IS_HATCH(m_brush
.GetStyle()))
1655 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1656 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1657 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1661 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1663 /* CMB 21/7/98: Added SetBackground. Sets background brush
1664 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1666 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1668 if (m_backgroundBrush
== brush
) return;
1670 m_backgroundBrush
= brush
;
1672 if (!m_backgroundBrush
.Ok()) return;
1674 if (!m_window
) return;
1676 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1677 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1678 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1679 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1680 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1682 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1684 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1686 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1688 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1689 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1693 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1694 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1698 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1700 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1701 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1702 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1706 void wxWindowDC::SetLogicalFunction( int function
)
1708 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1710 if (m_logicalFunction
== function
)
1713 // VZ: shouldn't this be a CHECK?
1717 GdkFunction mode
= GDK_COPY
;
1720 case wxXOR
: mode
= GDK_XOR
; break;
1721 case wxINVERT
: mode
= GDK_INVERT
; break;
1722 #if (GTK_MINOR_VERSION > 0)
1723 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1724 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1725 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1726 case wxSET
: mode
= GDK_SET
; break;
1727 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1728 case wxAND
: mode
= GDK_AND
; break;
1729 case wxOR
: mode
= GDK_OR
; break;
1730 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1731 case wxNAND
: mode
= GDK_NAND
; break;
1732 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1733 case wxCOPY
: mode
= GDK_COPY
; break;
1734 case wxNO_OP
: mode
= GDK_NOOP
; break;
1735 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1737 // unsupported by GTK
1738 case wxNOR
: mode
= GDK_COPY
; break;
1742 wxFAIL_MSG( wxT("unsupported logical function") );
1747 m_logicalFunction
= function
;
1749 gdk_gc_set_function( m_penGC
, mode
);
1750 gdk_gc_set_function( m_brushGC
, mode
);
1752 // to stay compatible with wxMSW, we don't apply ROPs to the text
1753 // operations (i.e. DrawText/DrawRotatedText).
1754 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1755 gdk_gc_set_function( m_textGC
, mode
);
1758 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1760 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1762 if (m_textForegroundColour
== col
) return;
1764 m_textForegroundColour
= col
;
1765 if (!m_textForegroundColour
.Ok()) return;
1767 if (!m_window
) return;
1769 m_textForegroundColour
.CalcPixel( m_cmap
);
1770 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1773 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1775 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1777 if (m_textBackgroundColour
== col
) return;
1779 m_textBackgroundColour
= col
;
1780 if (!m_textBackgroundColour
.Ok()) return;
1782 if (!m_window
) return;
1784 m_textBackgroundColour
.CalcPixel( m_cmap
);
1785 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1788 void wxWindowDC::SetBackgroundMode( int mode
)
1790 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1792 m_backgroundMode
= mode
;
1794 if (!m_window
) return;
1796 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1797 // transparent/solid background mode
1799 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1801 gdk_gc_set_fill( m_brushGC
,
1802 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1806 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1808 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1811 void wxWindowDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1813 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1815 if (!m_window
) return;
1818 rect
.x
= XLOG2DEV(x
);
1819 rect
.y
= YLOG2DEV(y
);
1820 rect
.width
= XLOG2DEVREL(width
);
1821 rect
.height
= YLOG2DEVREL(height
);
1823 if (!m_currentClippingRegion
.IsNull())
1824 m_currentClippingRegion
.Intersect( rect
);
1826 m_currentClippingRegion
.Union( rect
);
1828 #if USE_PAINT_REGION
1829 if (!m_paintClippingRegion
.IsNull())
1830 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1833 wxCoord xx
, yy
, ww
, hh
;
1834 m_currentClippingRegion
.GetBox( xx
, yy
, ww
, hh
);
1835 wxDC::DoSetClippingRegion( xx
, yy
, ww
, hh
);
1837 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1838 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1839 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1840 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1843 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1845 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1849 DestroyClippingRegion();
1853 if (!m_window
) return;
1855 if (!m_currentClippingRegion
.IsNull())
1856 m_currentClippingRegion
.Intersect( region
);
1858 m_currentClippingRegion
.Union( region
);
1860 #if USE_PAINT_REGION
1861 if (!m_paintClippingRegion
.IsNull())
1862 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1865 wxCoord xx
, yy
, ww
, hh
;
1866 m_currentClippingRegion
.GetBox( xx
, yy
, ww
, hh
);
1867 wxDC::DoSetClippingRegion( xx
, yy
, ww
, hh
);
1869 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1870 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1871 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1872 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1875 void wxWindowDC::DestroyClippingRegion()
1877 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1879 wxDC::DestroyClippingRegion();
1881 m_currentClippingRegion
.Clear();
1883 #if USE_PAINT_REGION
1884 if (!m_paintClippingRegion
.IsEmpty())
1885 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1888 if (!m_window
) return;
1890 if (m_currentClippingRegion
.IsEmpty())
1892 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1893 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1894 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1895 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1899 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1900 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1901 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1902 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1906 void wxWindowDC::Destroy()
1908 if (m_penGC
) wxFreePoolGC( m_penGC
);
1909 m_penGC
= (GdkGC
*) NULL
;
1910 if (m_brushGC
) wxFreePoolGC( m_brushGC
);
1911 m_brushGC
= (GdkGC
*) NULL
;
1912 if (m_textGC
) wxFreePoolGC( m_textGC
);
1913 m_textGC
= (GdkGC
*) NULL
;
1914 if (m_bgGC
) wxFreePoolGC( m_bgGC
);
1915 m_bgGC
= (GdkGC
*) NULL
;
1918 void wxWindowDC::ComputeScaleAndOrigin()
1920 /* CMB: copy scale to see if it changes */
1921 double origScaleX
= m_scaleX
;
1922 double origScaleY
= m_scaleY
;
1924 wxDC::ComputeScaleAndOrigin();
1926 /* CMB: if scale has changed call SetPen to recalulate the line width */
1927 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
1930 /* this is a bit artificial, but we need to force wxDC to think
1931 the pen has changed */
1938 // Resolution in pixels per logical inch
1939 wxSize
wxWindowDC::GetPPI() const
1941 return wxSize(100, 100);
1944 int wxWindowDC::GetDepth() const
1946 wxFAIL_MSG(wxT("not implemented"));
1952 // ----------------------------------- spline code ----------------------------------------
1954 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1955 double a3
, double b3
, double a4
, double b4
);
1956 void wx_clear_stack();
1957 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1958 double *y3
, double *x4
, double *y4
);
1959 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1960 double x4
, double y4
);
1961 static bool wx_spline_add_point(double x
, double y
);
1962 static void wx_spline_draw_point_array(wxDC
*dc
);
1964 wxList wx_spline_point_list
;
1966 #define half(z1, z2) ((z1+z2)/2.0)
1969 /* iterative version */
1971 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1974 register double xmid
, ymid
;
1975 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1978 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1980 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1981 xmid
= (double)half(x2
, x3
);
1982 ymid
= (double)half(y2
, y3
);
1983 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1984 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1985 wx_spline_add_point( x1
, y1
);
1986 wx_spline_add_point( xmid
, ymid
);
1988 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1989 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1990 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1991 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1996 /* utilities used by spline drawing routines */
1998 typedef struct wx_spline_stack_struct
{
1999 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
2002 #define SPLINE_STACK_DEPTH 20
2003 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
2004 static Stack
*wx_stack_top
;
2005 static int wx_stack_count
;
2007 void wx_clear_stack()
2009 wx_stack_top
= wx_spline_stack
;
2013 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
2015 wx_stack_top
->x1
= x1
;
2016 wx_stack_top
->y1
= y1
;
2017 wx_stack_top
->x2
= x2
;
2018 wx_stack_top
->y2
= y2
;
2019 wx_stack_top
->x3
= x3
;
2020 wx_stack_top
->y3
= y3
;
2021 wx_stack_top
->x4
= x4
;
2022 wx_stack_top
->y4
= y4
;
2027 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
2028 double *x3
, double *y3
, double *x4
, double *y4
)
2030 if (wx_stack_count
== 0)
2034 *x1
= wx_stack_top
->x1
;
2035 *y1
= wx_stack_top
->y1
;
2036 *x2
= wx_stack_top
->x2
;
2037 *y2
= wx_stack_top
->y2
;
2038 *x3
= wx_stack_top
->x3
;
2039 *y3
= wx_stack_top
->y3
;
2040 *x4
= wx_stack_top
->x4
;
2041 *y4
= wx_stack_top
->y4
;
2045 static bool wx_spline_add_point(double x
, double y
)
2047 wxPoint
*point
= new wxPoint
;
2050 wx_spline_point_list
.Append((wxObject
*)point
);
2054 static void wx_spline_draw_point_array(wxDC
*dc
)
2056 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
2057 wxNode
*node
= wx_spline_point_list
.First();
2060 wxPoint
*point
= (wxPoint
*)node
->Data();
2063 node
= wx_spline_point_list
.First();
2067 void wxWindowDC::DoDrawSpline( wxList
*points
)
2069 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2072 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
2073 double x1
, y1
, x2
, y2
;
2075 wxNode
*node
= points
->First();
2076 p
= (wxPoint
*)node
->Data();
2081 node
= node
->Next();
2082 p
= (wxPoint
*)node
->Data();
2086 cx1
= (double)((x1
+ x2
) / 2);
2087 cy1
= (double)((y1
+ y2
) / 2);
2088 cx2
= (double)((cx1
+ x2
) / 2);
2089 cy2
= (double)((cy1
+ y2
) / 2);
2091 wx_spline_add_point(x1
, y1
);
2093 while ((node
= node
->Next()) != NULL
)
2095 p
= (wxPoint
*)node
->Data();
2100 cx4
= (double)(x1
+ x2
) / 2;
2101 cy4
= (double)(y1
+ y2
) / 2;
2102 cx3
= (double)(x1
+ cx4
) / 2;
2103 cy3
= (double)(y1
+ cy4
) / 2;
2105 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
2109 cx2
= (double)(cx1
+ x2
) / 2;
2110 cy2
= (double)(cy1
+ y2
) / 2;
2113 wx_spline_add_point( cx1
, cy1
);
2114 wx_spline_add_point( x2
, y2
);
2116 wx_spline_draw_point_array( this );
2119 #endif // wxUSE_SPLINE
2121 //-----------------------------------------------------------------------------
2123 //-----------------------------------------------------------------------------
2125 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
2127 wxPaintDC::wxPaintDC()
2132 wxPaintDC::wxPaintDC( wxWindow
*win
)
2135 #if USE_PAINT_REGION
2136 if (!win
->m_clipPaintRegion
)
2139 m_paintClippingRegion
= win
->GetUpdateRegion();
2140 GdkRegion
*region
= m_paintClippingRegion
.GetRegion();
2143 m_currentClippingRegion
.Union( m_paintClippingRegion
);
2145 gdk_gc_set_clip_region( m_penGC
, region
);
2146 gdk_gc_set_clip_region( m_brushGC
, region
);
2147 gdk_gc_set_clip_region( m_textGC
, region
);
2148 gdk_gc_set_clip_region( m_bgGC
, region
);
2153 //-----------------------------------------------------------------------------
2155 //-----------------------------------------------------------------------------
2157 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
2159 wxClientDC::wxClientDC()
2164 wxClientDC::wxClientDC( wxWindow
*win
)
2169 // ----------------------------------------------------------------------------
2171 // ----------------------------------------------------------------------------
2173 class wxDCModule
: public wxModule
2180 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2183 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2185 bool wxDCModule::OnInit()
2191 void wxDCModule::OnExit()