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"
15 #define XCopyPlane XCOPYPLANE
18 #include "wx/dcclient.h"
19 #include "wx/dcmemory.h"
21 #include "wx/module.h"
23 #include "wx/gtk/win_gtk.h"
25 #include <math.h> // for floating-point functions
29 #include <gdk/gdkprivate.h>
32 //-----------------------------------------------------------------------------
34 //-----------------------------------------------------------------------------
36 #define USE_PAINT_REGION 1
38 //-----------------------------------------------------------------------------
40 //-----------------------------------------------------------------------------
50 #define IS_15_PIX_HATCH(s) ((s)==wxCROSSDIAG_HATCH || (s)==wxHORIZONTAL_HATCH || (s)==wxVERTICAL_HATCH)
51 #define IS_16_PIX_HATCH(s) ((s)!=wxCROSSDIAG_HATCH && (s)!=wxHORIZONTAL_HATCH && (s)!=wxVERTICAL_HATCH)
54 static GdkPixmap
*hatches
[num_hatches
];
55 static GdkPixmap
**hatch_bitmap
= (GdkPixmap
**) NULL
;
57 extern GtkWidget
*wxRootWindow
;
59 //-----------------------------------------------------------------------------
61 //-----------------------------------------------------------------------------
63 const double RAD2DEG
= 180.0 / M_PI
;
65 // ----------------------------------------------------------------------------
67 // ----------------------------------------------------------------------------
69 static inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
70 static inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
72 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
74 //-----------------------------------------------------------------------------
75 // temporary implementation of the missing GDK function
76 //-----------------------------------------------------------------------------
78 #include "gdk/gdkprivate.h"
80 void gdk_wx_draw_bitmap (GdkDrawable
*drawable
,
90 gint src_width
, src_height
;
92 GdkWindowPrivate
*drawable_private
;
93 GdkWindowPrivate
*src_private
;
94 GdkGCPrivate
*gc_private
;
97 g_return_if_fail (drawable
!= NULL
);
98 g_return_if_fail (src
!= NULL
);
99 g_return_if_fail (gc
!= NULL
);
102 if (GDK_WINDOW_DESTROYED(drawable
) || GDK_WINDOW_DESTROYED(src
))
105 gdk_drawable_get_size(src
, &src_width
, &src_height
);
107 drawable_private
= (GdkWindowPrivate
*) drawable
;
108 src_private
= (GdkWindowPrivate
*) src
;
109 if (drawable_private
->destroyed
|| src_private
->destroyed
)
112 src_width
= src_private
->width
;
113 src_height
= src_private
->height
;
115 gc_private
= (GdkGCPrivate
*) gc
;
118 if (width
== -1) width
= src_width
;
119 if (height
== -1) height
= src_height
;
122 XCopyPlane( GDK_WINDOW_XDISPLAY(drawable
),
124 GDK_WINDOW_XID(drawable
),
131 XCopyPlane( drawable_private
->xdisplay
,
132 src_private
->xwindow
,
133 drawable_private
->xwindow
,
142 //-----------------------------------------------------------------------------
143 // Implement Pool of Graphic contexts. Creating them takes too much time.
144 //-----------------------------------------------------------------------------
146 #define GC_POOL_SIZE 200
172 static wxGC wxGCPool
[GC_POOL_SIZE
];
174 static void wxInitGCPool()
176 memset( wxGCPool
, 0, GC_POOL_SIZE
*sizeof(wxGC
) );
179 static void wxCleanUpGCPool()
181 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
183 if (wxGCPool
[i
].m_gc
)
184 gdk_gc_unref( wxGCPool
[i
].m_gc
);
188 static GdkGC
* wxGetPoolGC( GdkWindow
*window
, wxPoolGCType type
)
190 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
192 if (!wxGCPool
[i
].m_gc
)
194 wxGCPool
[i
].m_gc
= gdk_gc_new( window
);
195 gdk_gc_set_exposures( wxGCPool
[i
].m_gc
, FALSE
);
196 wxGCPool
[i
].m_type
= type
;
197 wxGCPool
[i
].m_used
= FALSE
;
199 if ((!wxGCPool
[i
].m_used
) && (wxGCPool
[i
].m_type
== type
))
201 wxGCPool
[i
].m_used
= TRUE
;
202 return wxGCPool
[i
].m_gc
;
206 wxFAIL_MSG( wxT("No GC available") );
208 return (GdkGC
*) NULL
;
211 static void wxFreePoolGC( GdkGC
*gc
)
213 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
215 if (wxGCPool
[i
].m_gc
== gc
)
217 wxGCPool
[i
].m_used
= FALSE
;
222 wxFAIL_MSG( wxT("Wrong GC") );
225 //-----------------------------------------------------------------------------
227 //-----------------------------------------------------------------------------
229 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
231 wxWindowDC::wxWindowDC()
233 m_penGC
= (GdkGC
*) NULL
;
234 m_brushGC
= (GdkGC
*) NULL
;
235 m_textGC
= (GdkGC
*) NULL
;
236 m_bgGC
= (GdkGC
*) NULL
;
237 m_cmap
= (GdkColormap
*) NULL
;
239 m_isScreenDC
= FALSE
;
240 m_owner
= (wxWindow
*)NULL
;
242 m_context
= (PangoContext
*)NULL
;
243 m_fontdesc
= (PangoFontDescription
*)NULL
;
247 wxWindowDC::wxWindowDC( wxWindow
*window
)
249 m_penGC
= (GdkGC
*) NULL
;
250 m_brushGC
= (GdkGC
*) NULL
;
251 m_textGC
= (GdkGC
*) NULL
;
252 m_bgGC
= (GdkGC
*) NULL
;
253 m_cmap
= (GdkColormap
*) NULL
;
254 m_owner
= (wxWindow
*)NULL
;
256 m_isScreenDC
= FALSE
;
257 m_font
= window
->GetFont();
259 wxASSERT_MSG( window
, wxT("DC needs a window") );
261 GtkWidget
*widget
= window
->m_wxwindow
;
263 // some controls don't have m_wxwindow - like wxStaticBox, but the user
264 // code should still be able to create wxClientDCs for them, so we will
265 // use the parent window here then
268 window
= window
->GetParent();
269 widget
= window
->m_wxwindow
;
272 wxASSERT_MSG( widget
, wxT("DC needs a widget") );
275 m_context
= gtk_widget_get_pango_context( widget
);
276 m_fontdesc
= widget
->style
->font_desc
;
279 GtkPizza
*pizza
= GTK_PIZZA( widget
);
280 m_window
= pizza
->bin_window
;
285 /* don't report problems */
291 m_cmap
= gtk_widget_get_colormap( widget
? widget
: window
->m_widget
);
295 /* this must be done after SetUpDC, bacause SetUpDC calls the
296 repective SetBrush, SetPen, SetBackground etc functions
297 to set up the DC. SetBackground call m_owner->SetBackground
298 and this might not be desired as the standard dc background
299 is white whereas a window might assume gray to be the
300 standard (as e.g. wxStatusBar) */
305 wxWindowDC::~wxWindowDC()
310 void wxWindowDC::SetUpDC()
314 wxASSERT_MSG( !m_penGC
, wxT("GCs already created") );
318 m_penGC
= wxGetPoolGC( m_window
, wxPEN_SCREEN
);
319 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_SCREEN
);
320 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_SCREEN
);
321 m_bgGC
= wxGetPoolGC( m_window
, wxBG_SCREEN
);
324 if (m_isMemDC
&& (((wxMemoryDC
*)this)->m_selected
.GetDepth() == 1))
326 m_penGC
= wxGetPoolGC( m_window
, wxPEN_MONO
);
327 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_MONO
);
328 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_MONO
);
329 m_bgGC
= wxGetPoolGC( m_window
, wxBG_MONO
);
333 m_penGC
= wxGetPoolGC( m_window
, wxPEN_COLOUR
);
334 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_COLOUR
);
335 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_COLOUR
);
336 m_bgGC
= wxGetPoolGC( m_window
, wxBG_COLOUR
);
339 /* background colour */
340 m_backgroundBrush
= *wxWHITE_BRUSH
;
341 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
342 GdkColor
*bg_col
= m_backgroundBrush
.GetColour().GetColor();
345 m_textForegroundColour
.CalcPixel( m_cmap
);
346 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
348 m_textBackgroundColour
.CalcPixel( m_cmap
);
349 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
351 gdk_gc_set_fill( m_textGC
, GDK_SOLID
);
354 m_pen
.GetColour().CalcPixel( m_cmap
);
355 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
356 gdk_gc_set_background( m_penGC
, bg_col
);
358 gdk_gc_set_line_attributes( m_penGC
, 0, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
, GDK_JOIN_ROUND
);
361 m_brush
.GetColour().CalcPixel( m_cmap
);
362 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
363 gdk_gc_set_background( m_brushGC
, bg_col
);
365 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
368 gdk_gc_set_background( m_bgGC
, bg_col
);
369 gdk_gc_set_foreground( m_bgGC
, bg_col
);
371 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
374 gdk_gc_set_function( m_textGC
, GDK_COPY
);
375 gdk_gc_set_function( m_brushGC
, GDK_COPY
);
376 gdk_gc_set_function( m_penGC
, GDK_COPY
);
379 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
380 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
381 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
382 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
386 hatch_bitmap
= hatches
;
387 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
388 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
389 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
390 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
391 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
392 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
396 void wxWindowDC::DoGetSize( int* width
, int* height
) const
398 wxCHECK_RET( m_owner
, _T("GetSize() doesn't work without window") );
400 m_owner
->GetSize(width
, height
);
403 void wxWindowDC::DoFloodFill( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
404 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
406 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
409 bool wxWindowDC::DoGetPixel( wxCoord x1
, wxCoord y1
, wxColour
*col
) const
411 // Generic (and therefore rather inefficient) method.
412 // Could be improved.
414 wxBitmap
bitmap(1, 1);
415 memdc
.SelectObject(bitmap
);
416 memdc
.Blit(0, 0, 1, 1, (wxDC
*) this, x1
, y1
);
417 memdc
.SelectObject(wxNullBitmap
);
418 wxImage
image(bitmap
);
419 col
->Set(image
.GetRed(0, 0), image
.GetGreen(0, 0), image
.GetBlue(0, 0));
423 void wxWindowDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
425 wxCHECK_RET( Ok(), wxT("invalid window dc") );
427 if (m_pen
.GetStyle() != wxTRANSPARENT
)
430 gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
432 CalcBoundingBox(x1
, y1
);
433 CalcBoundingBox(x2
, y2
);
437 void wxWindowDC::DoCrossHair( wxCoord x
, wxCoord y
)
439 wxCHECK_RET( Ok(), wxT("invalid window dc") );
441 if (m_pen
.GetStyle() != wxTRANSPARENT
)
446 wxCoord xx
= XLOG2DEV(x
);
447 wxCoord yy
= YLOG2DEV(y
);
450 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
451 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
456 void wxWindowDC::DoDrawArc( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
,
457 wxCoord xc
, wxCoord yc
)
459 wxCHECK_RET( Ok(), wxT("invalid window dc") );
461 wxCoord xx1
= XLOG2DEV(x1
);
462 wxCoord yy1
= YLOG2DEV(y1
);
463 wxCoord xx2
= XLOG2DEV(x2
);
464 wxCoord yy2
= YLOG2DEV(y2
);
465 wxCoord xxc
= XLOG2DEV(xc
);
466 wxCoord yyc
= YLOG2DEV(yc
);
467 double dx
= xx1
- xxc
;
468 double dy
= yy1
- yyc
;
469 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
470 wxCoord r
= (wxCoord
)radius
;
471 double radius1
, radius2
;
473 if (xx1
== xx2
&& yy1
== yy2
)
481 radius1
= radius2
= 0.0;
485 radius1
= (xx1
- xxc
== 0) ?
486 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
487 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
488 radius2
= (xx2
- xxc
== 0) ?
489 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
490 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
492 wxCoord alpha1
= wxCoord(radius1
* 64.0);
493 wxCoord alpha2
= wxCoord((radius2
- radius1
) * 64.0);
494 while (alpha2
<= 0) alpha2
+= 360*64;
495 while (alpha1
> 360*64) alpha1
-= 360*64;
499 if (m_brush
.GetStyle() != wxTRANSPARENT
)
501 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
503 gdk_gc_set_ts_origin( m_textGC
,
504 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
505 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
506 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
507 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
509 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
511 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
512 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
513 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
515 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
517 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
518 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
519 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
521 if (m_brush
.GetStyle() == wxSTIPPLE
)
523 gdk_gc_set_ts_origin( m_brushGC
,
524 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
525 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
526 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
527 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
531 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
535 if (m_pen
.GetStyle() != wxTRANSPARENT
)
537 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
539 gdk_draw_line( m_window
, m_penGC
, xx1
, yy1
, xxc
, yyc
);
540 gdk_draw_line( m_window
, m_penGC
, xxc
, yyc
, xx2
, yy2
);
544 CalcBoundingBox (x1
, y1
);
545 CalcBoundingBox (x2
, y2
);
548 void wxWindowDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
550 wxCHECK_RET( Ok(), wxT("invalid window dc") );
552 wxCoord xx
= XLOG2DEV(x
);
553 wxCoord yy
= YLOG2DEV(y
);
554 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
555 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
557 // CMB: handle -ve width and/or height
558 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
559 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
563 wxCoord start
= wxCoord(sa
* 64.0);
564 wxCoord end
= wxCoord((ea
-sa
) * 64.0);
566 if (m_brush
.GetStyle() != wxTRANSPARENT
)
568 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
570 gdk_gc_set_ts_origin( m_textGC
,
571 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
572 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
573 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
574 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
576 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
578 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
579 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
580 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
582 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
584 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
585 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
586 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
588 if (m_brush
.GetStyle() == wxSTIPPLE
)
590 gdk_gc_set_ts_origin( m_brushGC
,
591 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
592 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
593 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
594 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
598 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
602 if (m_pen
.GetStyle() != wxTRANSPARENT
)
603 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
606 CalcBoundingBox (x
, y
);
607 CalcBoundingBox (x
+ width
, y
+ height
);
610 void wxWindowDC::DoDrawPoint( wxCoord x
, wxCoord y
)
612 wxCHECK_RET( Ok(), wxT("invalid window dc") );
614 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
615 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
617 CalcBoundingBox (x
, y
);
620 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
622 wxCHECK_RET( Ok(), wxT("invalid window dc") );
624 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
627 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
629 for (int i
= 0; i
< n
-1; i
++)
631 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
632 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
633 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
634 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
637 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
639 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
643 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
645 wxCHECK_RET( Ok(), wxT("invalid window dc") );
649 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
651 for (i
= 0 ; i
< n
; i
++)
653 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
654 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
656 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
661 if (m_brush
.GetStyle() != wxTRANSPARENT
)
663 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
665 gdk_gc_set_ts_origin( m_textGC
,
666 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
667 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
668 gdk_draw_polygon( m_window
, m_textGC
, TRUE
, gdkpoints
, n
);
669 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
671 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
673 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
674 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
675 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
677 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
679 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
680 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
681 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
683 if (m_brush
.GetStyle() == wxSTIPPLE
)
685 gdk_gc_set_ts_origin( m_brushGC
,
686 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
687 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
688 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
689 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
693 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
697 if (m_pen
.GetStyle() != wxTRANSPARENT
)
699 for (i
= 0 ; i
< n
; i
++)
701 gdk_draw_line( m_window
, m_penGC
,
704 gdkpoints
[(i
+1)%n
].x
,
705 gdkpoints
[(i
+1)%n
].y
);
713 void wxWindowDC::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
715 wxCHECK_RET( Ok(), wxT("invalid window dc") );
717 wxCoord xx
= XLOG2DEV(x
);
718 wxCoord yy
= YLOG2DEV(y
);
719 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
720 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
722 // CMB: draw nothing if transformed w or h is 0
723 if (ww
== 0 || hh
== 0) return;
725 // CMB: handle -ve width and/or height
726 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
727 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
731 if (m_brush
.GetStyle() != wxTRANSPARENT
)
733 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
735 gdk_gc_set_ts_origin( m_textGC
,
736 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
737 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
738 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
);
739 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
741 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
743 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
744 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
745 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
747 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
749 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
750 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
751 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
753 if (m_brush
.GetStyle() == wxSTIPPLE
)
755 gdk_gc_set_ts_origin( m_brushGC
,
756 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
757 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
758 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
759 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
763 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
767 if (m_pen
.GetStyle() != wxTRANSPARENT
)
768 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
771 CalcBoundingBox( x
, y
);
772 CalcBoundingBox( x
+ width
, y
+ height
);
775 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
777 wxCHECK_RET( Ok(), wxT("invalid window dc") );
779 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
781 wxCoord xx
= XLOG2DEV(x
);
782 wxCoord yy
= YLOG2DEV(y
);
783 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
784 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
785 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
787 // CMB: handle -ve width and/or height
788 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
789 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
791 // CMB: if radius is zero use DrawRectangle() instead to avoid
792 // X drawing errors with small radii
795 DrawRectangle( x
, y
, width
, height
);
799 // CMB: draw nothing if transformed w or h is 0
800 if (ww
== 0 || hh
== 0) return;
802 // CMB: adjust size if outline is drawn otherwise the result is
803 // 1 pixel too wide and high
804 if (m_pen
.GetStyle() != wxTRANSPARENT
)
812 // CMB: ensure dd is not larger than rectangle otherwise we
813 // get an hour glass shape
815 if (dd
> ww
) dd
= ww
;
816 if (dd
> hh
) dd
= hh
;
819 if (m_brush
.GetStyle() != wxTRANSPARENT
)
821 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
823 gdk_gc_set_ts_origin( m_textGC
,
824 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
825 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
826 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
827 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
828 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
829 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
830 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
831 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
832 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
834 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
836 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
837 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
838 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
839 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
840 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
841 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
842 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
843 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
845 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
847 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
848 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
849 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
850 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
851 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
852 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
853 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
854 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
856 if (m_brush
.GetStyle() == wxSTIPPLE
)
858 gdk_gc_set_ts_origin( m_brushGC
,
859 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
860 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
861 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
862 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
863 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
864 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
865 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
866 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
867 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
871 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
872 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
873 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
874 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
875 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
876 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
880 if (m_pen
.GetStyle() != wxTRANSPARENT
)
882 gdk_draw_line( m_window
, m_penGC
, xx
+rr
+1, yy
, xx
+ww
-rr
, yy
);
883 gdk_draw_line( m_window
, m_penGC
, xx
+rr
+1, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
884 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
+1, xx
, yy
+hh
-rr
);
885 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
+1, xx
+ww
, yy
+hh
-rr
);
886 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
887 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
888 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
889 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
893 // this ignores the radius
894 CalcBoundingBox( x
, y
);
895 CalcBoundingBox( x
+ width
, y
+ height
);
898 void wxWindowDC::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
900 wxCHECK_RET( Ok(), wxT("invalid window dc") );
902 wxCoord xx
= XLOG2DEV(x
);
903 wxCoord yy
= YLOG2DEV(y
);
904 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
905 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
907 // CMB: handle -ve width and/or height
908 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
909 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
913 if (m_brush
.GetStyle() != wxTRANSPARENT
)
915 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
917 gdk_gc_set_ts_origin( m_textGC
,
918 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
919 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
920 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
921 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
923 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
925 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
926 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
927 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
929 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
931 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
932 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
933 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
935 if (m_brush
.GetStyle() == wxSTIPPLE
)
937 gdk_gc_set_ts_origin( m_brushGC
,
938 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
939 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
940 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
941 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
945 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
949 if (m_pen
.GetStyle() != wxTRANSPARENT
)
950 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
953 CalcBoundingBox( x
- width
, y
- height
);
954 CalcBoundingBox( x
+ width
, y
+ height
);
957 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
959 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
960 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
963 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
964 wxCoord x
, wxCoord y
,
967 wxCHECK_RET( Ok(), wxT("invalid window dc") );
969 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
971 bool is_mono
= (bitmap
.GetBitmap() != NULL
);
973 /* scale/translate size and position */
974 int xx
= XLOG2DEV(x
);
975 int yy
= YLOG2DEV(y
);
977 int w
= bitmap
.GetWidth();
978 int h
= bitmap
.GetHeight();
980 CalcBoundingBox( x
, y
);
981 CalcBoundingBox( x
+ w
, y
+ h
);
983 if (!m_window
) return;
985 int ww
= XLOG2DEVREL(w
);
986 int hh
= YLOG2DEVREL(h
);
988 /* compare to current clipping region */
989 if (!m_currentClippingRegion
.IsNull())
991 wxRegion
tmp( xx
,yy
,ww
,hh
);
992 tmp
.Intersect( m_currentClippingRegion
);
997 /* scale bitmap if required */
999 if ((w
!= ww
) || (h
!= hh
))
1001 wxImage
image( bitmap
);
1002 image
.Rescale( ww
, hh
);
1004 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
1006 use_bitmap
= image
.ConvertToBitmap();
1010 use_bitmap
= bitmap
;
1013 /* apply mask if any */
1014 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
1015 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
1017 if (useMask
&& mask
)
1019 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
1020 if (!m_currentClippingRegion
.IsNull())
1023 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, ww
, hh
, 1 );
1024 GdkGC
*gc
= gdk_gc_new( new_mask
);
1026 gdk_gc_set_foreground( gc
, &col
);
1027 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
1029 gdk_gc_set_background( gc
, &col
);
1031 gdk_gc_set_foreground( gc
, &col
);
1032 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
1033 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
1034 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
1035 gdk_gc_set_stipple( gc
, mask
);
1036 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
1043 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
1045 gdk_gc_set_clip_mask( m_textGC
, mask
);
1046 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
1051 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
1053 gdk_gc_set_clip_mask( m_penGC
, mask
);
1054 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
1057 gdk_bitmap_unref( new_mask
);
1060 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1061 drawing a mono-bitmap (XBitmap) we use the current text GC */
1063 gdk_wx_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), 0, 0, xx
, yy
, -1, -1 );
1065 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
1067 /* remove mask again if any */
1068 if (useMask
&& mask
)
1072 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
1073 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
1074 if (!m_currentClippingRegion
.IsNull())
1075 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1079 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
1080 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
1081 if (!m_currentClippingRegion
.IsNull())
1082 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1087 bool wxWindowDC::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1088 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1089 int logical_func
, bool useMask
)
1091 /* this is the nth try to get this utterly useless function to
1092 work. it now completely ignores the scaling or translation
1093 of the source dc, but scales correctly on the target dc and
1094 knows about possible mask information in a memory dc. */
1096 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
1098 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
1100 if (!m_window
) return FALSE
;
1102 wxClientDC
*srcDC
= (wxClientDC
*)source
;
1103 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
1105 bool use_bitmap_method
= FALSE
;
1106 bool is_mono
= FALSE
;
1108 if (srcDC
->m_isMemDC
)
1110 if (!memDC
->m_selected
.Ok()) return FALSE
;
1112 /* we use the "XCopyArea" way to copy a memory dc into
1113 y different window if the memory dc BOTH
1114 a) doesn't have any mask or its mask isn't used
1118 if (useMask
&& (memDC
->m_selected
.GetMask()))
1120 /* we HAVE TO use the direct way for memory dcs
1121 that have mask since the XCopyArea doesn't know
1123 use_bitmap_method
= TRUE
;
1125 else if (memDC
->m_selected
.GetDepth() == 1)
1127 /* we HAVE TO use the direct way for memory dcs
1128 that are bitmaps because XCopyArea doesn't cope
1129 with different bit depths */
1131 use_bitmap_method
= TRUE
;
1133 else if ((xsrc
== 0) && (ysrc
== 0) &&
1134 (width
== memDC
->m_selected
.GetWidth()) &&
1135 (height
== memDC
->m_selected
.GetHeight()))
1137 /* we SHOULD use the direct way if all of the bitmap
1138 in the memory dc is copied in which case XCopyArea
1139 wouldn't be able able to boost performace by reducing
1140 the area to be scaled */
1141 use_bitmap_method
= TRUE
;
1145 use_bitmap_method
= FALSE
;
1149 CalcBoundingBox( xdest
, ydest
);
1150 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
1152 /* scale/translate size and position */
1153 wxCoord xx
= XLOG2DEV(xdest
);
1154 wxCoord yy
= YLOG2DEV(ydest
);
1156 wxCoord ww
= XLOG2DEVREL(width
);
1157 wxCoord hh
= YLOG2DEVREL(height
);
1159 /* compare to current clipping region */
1160 if (!m_currentClippingRegion
.IsNull())
1162 wxRegion
tmp( xx
,yy
,ww
,hh
);
1163 tmp
.Intersect( m_currentClippingRegion
);
1168 int old_logical_func
= m_logicalFunction
;
1169 SetLogicalFunction( logical_func
);
1171 if (use_bitmap_method
)
1173 /* scale/translate bitmap size */
1174 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
1175 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
1177 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
1178 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
1180 /* scale bitmap if required */
1181 wxBitmap use_bitmap
;
1183 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
1185 wxImage
image( memDC
->m_selected
);
1186 image
= image
.Scale( bm_ww
, bm_hh
);
1189 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
1191 use_bitmap
= image
.ConvertToBitmap();
1195 use_bitmap
= memDC
->m_selected
;
1198 /* apply mask if any */
1199 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
1200 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
1202 if (useMask
&& mask
)
1204 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
1205 if (!m_currentClippingRegion
.IsNull())
1208 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, bm_ww
, bm_hh
, 1 );
1209 GdkGC
*gc
= gdk_gc_new( new_mask
);
1211 gdk_gc_set_foreground( gc
, &col
);
1212 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
1214 gdk_gc_set_background( gc
, &col
);
1216 gdk_gc_set_foreground( gc
, &col
);
1217 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
1218 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
1219 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
1220 gdk_gc_set_stipple( gc
, mask
);
1221 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
1228 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
1230 gdk_gc_set_clip_mask( m_textGC
, mask
);
1231 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
1236 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
1238 gdk_gc_set_clip_mask( m_penGC
, mask
);
1239 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
1242 gdk_bitmap_unref( new_mask
);
1245 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1246 drawing a mono-bitmap (XBitmap) we use the current text GC */
1249 gdk_wx_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
1251 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
1253 /* remove mask again if any */
1254 if (useMask
&& mask
)
1258 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
1259 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
1260 if (!m_currentClippingRegion
.IsNull())
1261 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1265 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
1266 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
1267 if (!m_currentClippingRegion
.IsNull())
1268 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1272 else /* use_bitmap_method */
1274 if ((width
!= ww
) || (height
!= hh
))
1276 /* draw source window into a bitmap as we cannot scale
1277 a window in contrast to a bitmap. this would actually
1278 work with memory dcs as well, but we'd lose the mask
1279 information and waste one step in this process since
1280 a memory already has a bitmap. all this is slightly
1281 inefficient as we could take an XImage directly from
1282 an X window, but we'd then also have to care that
1283 the window is not outside the screen (in which case
1284 we'd get a BadMatch or what not).
1285 Is a double XGetImage and combined XGetPixel and
1286 XPutPixel really faster? I'm not sure. look at wxXt
1287 for a different implementation of the same problem. */
1289 wxBitmap
bitmap( width
, height
);
1291 /* copy including child window contents */
1292 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1293 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
1295 xsrc
, ysrc
, width
, height
);
1296 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1299 wxImage
image( bitmap
);
1300 image
= image
.Scale( ww
, hh
);
1302 /* convert to bitmap */
1303 bitmap
= image
.ConvertToBitmap();
1305 /* draw scaled bitmap */
1306 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
1311 /* No scaling and not a memory dc with a mask either */
1313 /* copy including child window contents */
1314 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1315 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
1317 xsrc
, ysrc
, width
, height
);
1318 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1322 SetLogicalFunction( old_logical_func
);
1326 void wxWindowDC::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
1328 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1330 if (!m_window
) return;
1332 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1334 wxCHECK_RET( font
, wxT("invalid font") );
1337 wxCHECK_RET( m_context
, wxT("no Pango context") );
1344 /* FIXME: the layout engine should probably be abstracted at a higher level in wxDC... */
1345 PangoLayout
*layout
= pango_layout_new(m_context
);
1346 pango_layout_set_font_description(layout
, m_fontdesc
);
1348 wxWX2MBbuf data
= text
.mb_str(wxConvUTF8
);
1349 pango_layout_set_text(layout
, data
, strlen(data
));
1351 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
1352 PangoRectangle rect
;
1353 pango_layout_line_get_extents(line
, NULL
, &rect
);
1354 wxCoord width
= rect
.width
;
1355 wxCoord height
= rect
.height
;
1356 gdk_draw_layout( m_window
, m_textGC
, x
, y
, layout
);
1358 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1359 wxCoord height
= font
->ascent
+ font
->descent
;
1360 /* CMB 21/5/98: draw text background if mode is wxSOLID */
1361 if (m_backgroundMode
== wxSOLID
)
1363 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
1364 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
1365 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1367 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
1370 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1371 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1372 properties (see wxXt implementation) */
1373 if (m_font
.GetUnderlined())
1375 wxCoord ul_y
= y
+ font
->ascent
;
1376 if (font
->descent
> 0) ul_y
++;
1377 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
1381 g_object_unref( G_OBJECT( layout
) );
1384 width
= wxCoord(width
/ m_scaleX
);
1385 height
= wxCoord(height
/ m_scaleY
);
1386 CalcBoundingBox (x
+ width
, y
+ height
);
1387 CalcBoundingBox (x
, y
);
1390 void wxWindowDC::DoDrawRotatedText( const wxString
&text
, wxCoord x
, wxCoord y
, double angle
)
1394 DrawText(text
, x
, y
);
1398 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1400 if (!m_window
) return;
1402 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1404 wxCHECK_RET( font
, wxT("invalid font") );
1406 // the size of the text
1407 wxCoord w
= gdk_string_width( font
, text
.mbc_str() );
1408 wxCoord h
= font
->ascent
+ font
->descent
;
1410 // draw the string normally
1413 dc
.SelectObject(src
);
1414 dc
.SetFont(GetFont());
1415 dc
.SetBackground(*wxWHITE_BRUSH
);
1416 dc
.SetBrush(*wxBLACK_BRUSH
);
1418 dc
.DrawText(text
, 0, 0);
1419 dc
.SetFont(wxNullFont
);
1420 dc
.SelectObject(wxNullBitmap
);
1422 // Calculate the size of the rotated bounding box.
1423 double rad
= DegToRad(angle
);
1424 double dx
= cos(rad
),
1427 // the rectngle vertices are counted clockwise with the first one being at
1428 // (0, 0) (or, rather, at (x, y))
1430 y2
= -w
*dy
; // y axis points to the bottom, hence minus
1433 double x3
= x4
+ x2
,
1437 wxCoord maxX
= (wxCoord
)(dmax(x2
, dmax(x3
, x4
)) + 0.5),
1438 maxY
= (wxCoord
)(dmax(y2
, dmax(y3
, y4
)) + 0.5),
1439 minX
= (wxCoord
)(dmin(x2
, dmin(x3
, x4
)) - 0.5),
1440 minY
= (wxCoord
)(dmin(y2
, dmin(y3
, y4
)) - 0.5);
1442 // prepare to blit-with-rotate the bitmap to the DC
1445 GdkColor
*colText
= m_textForegroundColour
.GetColor(),
1446 *colBack
= m_textBackgroundColour
.GetColor();
1448 bool textColSet
= TRUE
;
1450 unsigned char *data
= image
.GetData();
1452 // paint pixel by pixel
1453 for ( wxCoord srcX
= 0; srcX
< w
; srcX
++ )
1455 for ( wxCoord srcY
= 0; srcY
< h
; srcY
++ )
1457 // transform source coords to dest coords
1458 double r
= sqrt((double)srcX
*srcX
+ srcY
*srcY
);
1459 double angleOrig
= atan2((double)srcY
, (double)srcX
) - rad
;
1460 wxCoord dstX
= (wxCoord
)(r
*cos(angleOrig
) + 0.5),
1461 dstY
= (wxCoord
)(r
*sin(angleOrig
) + 0.5);
1464 bool textPixel
= data
[(srcY
*w
+ srcX
)*3] == 0;
1465 if ( textPixel
|| (m_backgroundMode
== wxSOLID
) )
1467 // change colour if needed
1468 if ( textPixel
!= textColSet
)
1470 gdk_gc_set_foreground( m_textGC
, textPixel
? colText
1473 textColSet
= textPixel
;
1476 // don't use DrawPoint() because it uses the current pen
1477 // colour, and we don't need it here
1478 gdk_draw_point( m_window
, m_textGC
,
1479 XLOG2DEV(x
+ dstX
), YLOG2DEV(y
+ dstY
) );
1484 // it would be better to draw with non underlined font and draw the line
1485 // manually here (it would be more straight...)
1487 if ( m_font
.GetUnderlined() )
1489 gdk_draw_line( m_window
, m_textGC
,
1490 XLOG2DEV(x
+ x4
), YLOG2DEV(y
+ y4
+ font
->descent
),
1491 XLOG2DEV(x
+ x3
), YLOG2DEV(y
+ y3
+ font
->descent
));
1495 // restore the font colour
1496 gdk_gc_set_foreground( m_textGC
, colText
);
1498 // update the bounding box
1499 CalcBoundingBox(x
+ minX
, y
+ minY
);
1500 CalcBoundingBox(x
+ maxX
, y
+ maxY
);
1503 void wxWindowDC::DoGetTextExtent(const wxString
&string
,
1504 wxCoord
*width
, wxCoord
*height
,
1505 wxCoord
*descent
, wxCoord
*externalLeading
,
1506 wxFont
*theFont
) const
1508 wxFont fontToUse
= m_font
;
1509 if (theFont
) fontToUse
= *theFont
;
1511 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
1512 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
1513 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1514 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
1515 if (externalLeading
) (*externalLeading
) = 0; // ??
1518 wxCoord
wxWindowDC::GetCharWidth() const
1520 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1521 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1523 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
1526 wxCoord
wxWindowDC::GetCharHeight() const
1528 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1529 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1531 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1534 void wxWindowDC::Clear()
1536 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1538 if (!m_window
) return;
1540 /* - we either are a memory dc or have a window as the
1541 owner. anything else shouldn't happen.
1542 - we don't use gdk_window_clear() as we don't set
1543 the window's background colour anymore. it is too
1544 much pain to keep the DC's and the window's back-
1545 ground colour in synch. */
1550 m_owner
->GetSize( &width
, &height
);
1551 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1558 GetSize( &width
, &height
);
1559 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1564 void wxWindowDC::SetFont( const wxFont
&font
)
1572 void wxWindowDC::SetPen( const wxPen
&pen
)
1574 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1576 if (m_pen
== pen
) return;
1580 if (!m_pen
.Ok()) return;
1582 if (!m_window
) return;
1584 gint width
= m_pen
.GetWidth();
1587 // CMB: if width is non-zero scale it with the dc
1592 // X doesn't allow different width in x and y and so we take
1595 ( fabs((double) XLOG2DEVREL(width
)) +
1596 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
1600 static const wxGTKDash dotted
[] = {1, 1};
1601 static const wxGTKDash short_dashed
[] = {2, 2};
1602 static const wxGTKDash wxCoord_dashed
[] = {2, 4};
1603 static const wxGTKDash dotted_dashed
[] = {3, 3, 1, 3};
1605 // We express dash pattern in pen width unit, so we are
1606 // independent of zoom factor and so on...
1608 const wxGTKDash
*req_dash
;
1610 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
1611 switch (m_pen
.GetStyle())
1615 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1616 req_nb_dash
= m_pen
.GetDashCount();
1617 req_dash
= (wxGTKDash
*)m_pen
.GetDash();
1622 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1629 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1631 req_dash
= wxCoord_dashed
;
1636 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1638 req_dash
= short_dashed
;
1643 // lineStyle = GDK_LINE_DOUBLE_DASH;
1644 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1646 req_dash
= dotted_dashed
;
1651 case wxSTIPPLE_MASK_OPAQUE
:
1656 lineStyle
= GDK_LINE_SOLID
;
1657 req_dash
= (wxGTKDash
*)NULL
;
1663 #if (GTK_MINOR_VERSION > 0) || (GTK_MAJOR_VERSION > 1)
1664 if (req_dash
&& req_nb_dash
)
1666 wxGTKDash
*real_req_dash
= new wxGTKDash
[req_nb_dash
];
1669 for (int i
= 0; i
< req_nb_dash
; i
++)
1670 real_req_dash
[i
] = req_dash
[i
] * width
;
1671 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
1672 delete[] real_req_dash
;
1676 // No Memory. We use non-scaled dash pattern...
1677 gdk_gc_set_dashes( m_penGC
, 0, (wxGTKDash
*)req_dash
, req_nb_dash
);
1682 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
1683 switch (m_pen
.GetCap())
1685 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
1686 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
1693 capStyle
= GDK_CAP_NOT_LAST
;
1697 capStyle
= GDK_CAP_ROUND
;
1703 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
1704 switch (m_pen
.GetJoin())
1706 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
1707 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
1709 default: { joinStyle
= GDK_JOIN_ROUND
; break; }
1712 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
1714 m_pen
.GetColour().CalcPixel( m_cmap
);
1715 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1718 void wxWindowDC::SetBrush( const wxBrush
&brush
)
1720 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1722 if (m_brush
== brush
) return;
1726 if (!m_brush
.Ok()) return;
1728 if (!m_window
) return;
1730 m_brush
.GetColour().CalcPixel( m_cmap
);
1731 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1733 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1735 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1737 if (m_brush
.GetStipple()->GetPixmap())
1739 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1740 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1744 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1745 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1749 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
1751 gdk_gc_set_fill( m_textGC
, GDK_OPAQUE_STIPPLED
);
1752 gdk_gc_set_stipple( m_textGC
, m_brush
.GetStipple()->GetMask()->GetBitmap() );
1755 if (IS_HATCH(m_brush
.GetStyle()))
1757 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1758 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1759 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1763 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1765 /* CMB 21/7/98: Added SetBackground. Sets background brush
1766 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1768 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1770 if (m_backgroundBrush
== brush
) return;
1772 m_backgroundBrush
= brush
;
1774 if (!m_backgroundBrush
.Ok()) return;
1776 if (!m_window
) return;
1778 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1779 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1780 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1781 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1782 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1784 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1786 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1788 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1790 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1791 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1795 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1796 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1800 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1802 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1803 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1804 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1808 void wxWindowDC::SetLogicalFunction( int function
)
1810 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1812 if (m_logicalFunction
== function
)
1815 // VZ: shouldn't this be a CHECK?
1819 GdkFunction mode
= GDK_COPY
;
1822 case wxXOR
: mode
= GDK_XOR
; break;
1823 case wxINVERT
: mode
= GDK_INVERT
; break;
1824 #if (GTK_MINOR_VERSION > 0)
1825 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1826 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1827 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1828 case wxSET
: mode
= GDK_SET
; break;
1829 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1830 case wxAND
: mode
= GDK_AND
; break;
1831 case wxOR
: mode
= GDK_OR
; break;
1832 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1833 case wxNAND
: mode
= GDK_NAND
; break;
1834 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1835 case wxCOPY
: mode
= GDK_COPY
; break;
1836 case wxNO_OP
: mode
= GDK_NOOP
; break;
1837 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1839 // unsupported by GTK
1840 case wxNOR
: mode
= GDK_COPY
; break;
1844 wxFAIL_MSG( wxT("unsupported logical function") );
1849 m_logicalFunction
= function
;
1851 gdk_gc_set_function( m_penGC
, mode
);
1852 gdk_gc_set_function( m_brushGC
, mode
);
1854 // to stay compatible with wxMSW, we don't apply ROPs to the text
1855 // operations (i.e. DrawText/DrawRotatedText).
1856 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1857 gdk_gc_set_function( m_textGC
, mode
);
1860 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1862 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1864 if (m_textForegroundColour
== col
) return;
1866 m_textForegroundColour
= col
;
1867 if (!m_textForegroundColour
.Ok()) return;
1869 if (!m_window
) return;
1871 m_textForegroundColour
.CalcPixel( m_cmap
);
1872 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1875 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1877 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1879 if (m_textBackgroundColour
== col
) return;
1881 m_textBackgroundColour
= col
;
1882 if (!m_textBackgroundColour
.Ok()) return;
1884 if (!m_window
) return;
1886 m_textBackgroundColour
.CalcPixel( m_cmap
);
1887 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1890 void wxWindowDC::SetBackgroundMode( int mode
)
1892 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1894 m_backgroundMode
= mode
;
1896 if (!m_window
) return;
1898 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1899 // transparent/solid background mode
1901 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1903 gdk_gc_set_fill( m_brushGC
,
1904 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1908 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1910 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1913 void wxWindowDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1915 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1917 if (!m_window
) return;
1920 rect
.x
= XLOG2DEV(x
);
1921 rect
.y
= YLOG2DEV(y
);
1922 rect
.width
= XLOG2DEVREL(width
);
1923 rect
.height
= YLOG2DEVREL(height
);
1925 if (!m_currentClippingRegion
.IsNull())
1926 m_currentClippingRegion
.Intersect( rect
);
1928 m_currentClippingRegion
.Union( rect
);
1930 #if USE_PAINT_REGION
1931 if (!m_paintClippingRegion
.IsNull())
1932 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1935 wxCoord xx
, yy
, ww
, hh
;
1936 m_currentClippingRegion
.GetBox( xx
, yy
, ww
, hh
);
1937 wxDC::DoSetClippingRegion( xx
, yy
, ww
, hh
);
1939 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1940 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1941 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1942 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1945 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1947 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1951 DestroyClippingRegion();
1955 if (!m_window
) return;
1957 if (!m_currentClippingRegion
.IsNull())
1958 m_currentClippingRegion
.Intersect( region
);
1960 m_currentClippingRegion
.Union( region
);
1962 #if USE_PAINT_REGION
1963 if (!m_paintClippingRegion
.IsNull())
1964 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1967 wxCoord xx
, yy
, ww
, hh
;
1968 m_currentClippingRegion
.GetBox( xx
, yy
, ww
, hh
);
1969 wxDC::DoSetClippingRegion( xx
, yy
, ww
, hh
);
1971 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1972 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1973 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1974 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1977 void wxWindowDC::DestroyClippingRegion()
1979 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1981 wxDC::DestroyClippingRegion();
1983 m_currentClippingRegion
.Clear();
1985 #if USE_PAINT_REGION
1986 if (!m_paintClippingRegion
.IsEmpty())
1987 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1990 if (!m_window
) return;
1992 if (m_currentClippingRegion
.IsEmpty())
1994 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1995 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1996 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1997 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
2001 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
2002 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
2003 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
2004 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
2008 void wxWindowDC::Destroy()
2010 if (m_penGC
) wxFreePoolGC( m_penGC
);
2011 m_penGC
= (GdkGC
*) NULL
;
2012 if (m_brushGC
) wxFreePoolGC( m_brushGC
);
2013 m_brushGC
= (GdkGC
*) NULL
;
2014 if (m_textGC
) wxFreePoolGC( m_textGC
);
2015 m_textGC
= (GdkGC
*) NULL
;
2016 if (m_bgGC
) wxFreePoolGC( m_bgGC
);
2017 m_bgGC
= (GdkGC
*) NULL
;
2020 void wxWindowDC::ComputeScaleAndOrigin()
2022 /* CMB: copy scale to see if it changes */
2023 double origScaleX
= m_scaleX
;
2024 double origScaleY
= m_scaleY
;
2026 wxDC::ComputeScaleAndOrigin();
2028 /* CMB: if scale has changed call SetPen to recalulate the line width */
2029 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
2032 /* this is a bit artificial, but we need to force wxDC to think
2033 the pen has changed */
2040 // Resolution in pixels per logical inch
2041 wxSize
wxWindowDC::GetPPI() const
2043 return wxSize(100, 100);
2046 int wxWindowDC::GetDepth() const
2048 wxFAIL_MSG(wxT("not implemented"));
2054 // ----------------------------------- spline code ----------------------------------------
2056 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
2057 double a3
, double b3
, double a4
, double b4
);
2058 void wx_clear_stack();
2059 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
2060 double *y3
, double *x4
, double *y4
);
2061 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
2062 double x4
, double y4
);
2063 static bool wx_spline_add_point(double x
, double y
);
2064 static void wx_spline_draw_point_array(wxDC
*dc
);
2066 wxList wx_spline_point_list
;
2068 #define half(z1, z2) ((z1+z2)/2.0)
2071 /* iterative version */
2073 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
2076 register double xmid
, ymid
;
2077 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
2080 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
2082 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
2083 xmid
= (double)half(x2
, x3
);
2084 ymid
= (double)half(y2
, y3
);
2085 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
2086 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
2087 wx_spline_add_point( x1
, y1
);
2088 wx_spline_add_point( xmid
, ymid
);
2090 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
2091 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
2092 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
2093 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
2098 /* utilities used by spline drawing routines */
2100 typedef struct wx_spline_stack_struct
{
2101 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
2104 #define SPLINE_STACK_DEPTH 20
2105 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
2106 static Stack
*wx_stack_top
;
2107 static int wx_stack_count
;
2109 void wx_clear_stack()
2111 wx_stack_top
= wx_spline_stack
;
2115 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
2117 wx_stack_top
->x1
= x1
;
2118 wx_stack_top
->y1
= y1
;
2119 wx_stack_top
->x2
= x2
;
2120 wx_stack_top
->y2
= y2
;
2121 wx_stack_top
->x3
= x3
;
2122 wx_stack_top
->y3
= y3
;
2123 wx_stack_top
->x4
= x4
;
2124 wx_stack_top
->y4
= y4
;
2129 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
2130 double *x3
, double *y3
, double *x4
, double *y4
)
2132 if (wx_stack_count
== 0)
2136 *x1
= wx_stack_top
->x1
;
2137 *y1
= wx_stack_top
->y1
;
2138 *x2
= wx_stack_top
->x2
;
2139 *y2
= wx_stack_top
->y2
;
2140 *x3
= wx_stack_top
->x3
;
2141 *y3
= wx_stack_top
->y3
;
2142 *x4
= wx_stack_top
->x4
;
2143 *y4
= wx_stack_top
->y4
;
2147 static bool wx_spline_add_point(double x
, double y
)
2149 wxPoint
*point
= new wxPoint
;
2152 wx_spline_point_list
.Append((wxObject
*)point
);
2156 static void wx_spline_draw_point_array(wxDC
*dc
)
2158 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
2159 wxNode
*node
= wx_spline_point_list
.First();
2162 wxPoint
*point
= (wxPoint
*)node
->Data();
2165 node
= wx_spline_point_list
.First();
2169 void wxWindowDC::DoDrawSpline( wxList
*points
)
2171 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2174 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
2175 double x1
, y1
, x2
, y2
;
2177 wxNode
*node
= points
->First();
2178 p
= (wxPoint
*)node
->Data();
2183 node
= node
->Next();
2184 p
= (wxPoint
*)node
->Data();
2188 cx1
= (double)((x1
+ x2
) / 2);
2189 cy1
= (double)((y1
+ y2
) / 2);
2190 cx2
= (double)((cx1
+ x2
) / 2);
2191 cy2
= (double)((cy1
+ y2
) / 2);
2193 wx_spline_add_point(x1
, y1
);
2195 while ((node
= node
->Next()) != NULL
)
2197 p
= (wxPoint
*)node
->Data();
2202 cx4
= (double)(x1
+ x2
) / 2;
2203 cy4
= (double)(y1
+ y2
) / 2;
2204 cx3
= (double)(x1
+ cx4
) / 2;
2205 cy3
= (double)(y1
+ cy4
) / 2;
2207 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
2211 cx2
= (double)(cx1
+ x2
) / 2;
2212 cy2
= (double)(cy1
+ y2
) / 2;
2215 wx_spline_add_point( cx1
, cy1
);
2216 wx_spline_add_point( x2
, y2
);
2218 wx_spline_draw_point_array( this );
2221 #endif // wxUSE_SPLINE
2223 //-----------------------------------------------------------------------------
2225 //-----------------------------------------------------------------------------
2227 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
2229 wxPaintDC::wxPaintDC()
2234 wxPaintDC::wxPaintDC( wxWindow
*win
)
2237 #if USE_PAINT_REGION
2238 if (!win
->m_clipPaintRegion
)
2241 m_paintClippingRegion
= win
->GetUpdateRegion();
2242 GdkRegion
*region
= m_paintClippingRegion
.GetRegion();
2245 m_currentClippingRegion
.Union( m_paintClippingRegion
);
2247 gdk_gc_set_clip_region( m_penGC
, region
);
2248 gdk_gc_set_clip_region( m_brushGC
, region
);
2249 gdk_gc_set_clip_region( m_textGC
, region
);
2250 gdk_gc_set_clip_region( m_bgGC
, region
);
2255 //-----------------------------------------------------------------------------
2257 //-----------------------------------------------------------------------------
2259 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
2261 wxClientDC::wxClientDC()
2266 wxClientDC::wxClientDC( wxWindow
*win
)
2271 // ----------------------------------------------------------------------------
2273 // ----------------------------------------------------------------------------
2275 class wxDCModule
: public wxModule
2282 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2285 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2287 bool wxDCModule::OnInit()
2293 void wxDCModule::OnExit()