]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/dcclient.cpp
Modified generic wxTreeCtrl to work under non-Unix platforms simultaneously
[wxWidgets.git] / src / gtk / dcclient.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
e5131165 2// Name: gtk/dcclient.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
6f65e337 5// RCS-ID: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling, Markus Holzem, Chris Breeze
e5131165 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
10#ifdef __GNUG__
11#pragma implementation "dcclient.h"
12#endif
13
14#include "wx/dcclient.h"
6f65e337 15#include "wx/dcmemory.h"
4bc67cc5 16#include "wx/image.h"
e5131165
VZ
17#include "wx/module.h"
18
ed673c6a 19#include "wx/gtk/win_gtk.h"
c801d85f 20
071a2d78 21#include <math.h> // for floating-point functions
e5131165 22
071a2d78 23#include <gdk/gdk.h>
993f97ee 24#include <gdk/gdkx.h>
8943b403 25#include <gdk/gdkprivate.h>
071a2d78 26#include <gtk/gtk.h>
83624f79 27
809934d2
RR
28//-----------------------------------------------------------------------------
29// local defines
30//-----------------------------------------------------------------------------
31
e1208c31 32#define USE_PAINT_REGION 1
809934d2 33
c801d85f
KB
34//-----------------------------------------------------------------------------
35// local data
36//-----------------------------------------------------------------------------
37
38#include "bdiag.xbm"
39#include "fdiag.xbm"
40#include "cdiag.xbm"
41#include "horiz.xbm"
42#include "verti.xbm"
43#include "cross.xbm"
44#define num_hatches 6
45
46static GdkPixmap *hatches[num_hatches];
c67daf87 47static GdkPixmap **hatch_bitmap = (GdkPixmap **) NULL;
c801d85f 48
3d2d8da1
RR
49extern GtkWidget *wxRootWindow;
50
c801d85f
KB
51//-----------------------------------------------------------------------------
52// constants
53//-----------------------------------------------------------------------------
54
95724b1a 55const double RAD2DEG = 180.0 / M_PI;
c801d85f 56
9a8c7620
VZ
57// ----------------------------------------------------------------------------
58// private functions
59// ----------------------------------------------------------------------------
60
61static inline double dmax(double a, double b) { return a > b ? a : b; }
62static inline double dmin(double a, double b) { return a < b ? a : b; }
63
64static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
65
6f65e337
JS
66//-----------------------------------------------------------------------------
67// temporary implementation of the missing GDK function
68//-----------------------------------------------------------------------------
b0e0d661 69
6f65e337 70#include "gdk/gdkprivate.h"
b0e0d661 71
f6bcfd97 72void gdk_wx_draw_bitmap (GdkDrawable *drawable,
b0e0d661
VZ
73 GdkGC *gc,
74 GdkDrawable *src,
75 gint xsrc,
76 gint ysrc,
77 gint xdest,
78 gint ydest,
79 gint width,
80 gint height)
6f65e337 81{
8943b403 82 gint src_width, src_height;
3419e8e7 83#ifndef __WXGTK20__
265898fd
RR
84 GdkWindowPrivate *drawable_private;
85 GdkWindowPrivate *src_private;
86 GdkGCPrivate *gc_private;
8943b403 87#endif
265898fd
RR
88
89 g_return_if_fail (drawable != NULL);
90 g_return_if_fail (src != NULL);
91 g_return_if_fail (gc != NULL);
92
8943b403
OK
93#ifdef __WXGTK20__
94 if (GDK_WINDOW_DESTROYED(drawable) || GDK_WINDOW_DESTROYED(src))
95 return;
96
97 gdk_drawable_get_size(src, &src_width, &src_height);
98#else
265898fd
RR
99 drawable_private = (GdkWindowPrivate*) drawable;
100 src_private = (GdkWindowPrivate*) src;
101 if (drawable_private->destroyed || src_private->destroyed)
102 return;
7d5af6fa 103
8943b403
OK
104 src_width = src_private->width;
105 src_height = src_private->height;
106
265898fd 107 gc_private = (GdkGCPrivate*) gc;
8943b403 108#endif
265898fd 109
8943b403
OK
110 if (width == -1) width = src_width;
111 if (height == -1) height = src_height;
265898fd 112
8943b403
OK
113#ifdef __WXGTK20__
114 XCopyPlane( GDK_WINDOW_XDISPLAY(drawable),
115 GDK_WINDOW_XID(src),
116 GDK_WINDOW_XID(drawable),
117 GDK_GC_XGC(gc),
118 xsrc, ysrc,
119 width, height,
120 xdest, ydest,
121 1 );
122#else
265898fd 123 XCopyPlane( drawable_private->xdisplay,
b0e0d661
VZ
124 src_private->xwindow,
125 drawable_private->xwindow,
126 gc_private->xgc,
127 xsrc, ysrc,
128 width, height,
129 xdest, ydest,
130 1 );
8943b403 131#endif
6f65e337
JS
132}
133
3d2d8da1
RR
134//-----------------------------------------------------------------------------
135// Implement Pool of Graphic contexts. Creating them takes too much time.
136//-----------------------------------------------------------------------------
137
e1208c31
RR
138#define GC_POOL_SIZE 200
139
0e09f76e
RR
140enum wxPoolGCType
141{
142 wxGC_ERROR = 0,
143 wxTEXT_MONO,
144 wxBG_MONO,
145 wxPEN_MONO,
146 wxBRUSH_MONO,
147 wxTEXT_COLOUR,
148 wxBG_COLOUR,
149 wxPEN_COLOUR,
f6bcfd97
BP
150 wxBRUSH_COLOUR,
151 wxTEXT_SCREEN,
152 wxBG_SCREEN,
153 wxPEN_SCREEN,
154 wxBRUSH_SCREEN
0e09f76e
RR
155};
156
3d2d8da1
RR
157struct wxGC
158{
0e09f76e
RR
159 GdkGC *m_gc;
160 wxPoolGCType m_type;
161 bool m_used;
3d2d8da1
RR
162};
163
e1208c31 164static wxGC wxGCPool[GC_POOL_SIZE];
3d2d8da1
RR
165
166static void wxInitGCPool()
167{
e1208c31 168 memset( wxGCPool, 0, GC_POOL_SIZE*sizeof(wxGC) );
3d2d8da1
RR
169}
170
171static void wxCleanUpGCPool()
172{
e1208c31 173 for (int i = 0; i < GC_POOL_SIZE; i++)
3d2d8da1
RR
174 {
175 if (wxGCPool[i].m_gc)
176 gdk_gc_unref( wxGCPool[i].m_gc );
177 }
178}
179
0e09f76e 180static GdkGC* wxGetPoolGC( GdkWindow *window, wxPoolGCType type )
3d2d8da1 181{
e1208c31 182 for (int i = 0; i < GC_POOL_SIZE; i++)
3d2d8da1
RR
183 {
184 if (!wxGCPool[i].m_gc)
185 {
186 wxGCPool[i].m_gc = gdk_gc_new( window );
187 gdk_gc_set_exposures( wxGCPool[i].m_gc, FALSE );
0e09f76e 188 wxGCPool[i].m_type = type;
3d2d8da1
RR
189 wxGCPool[i].m_used = FALSE;
190 }
0e09f76e 191 if ((!wxGCPool[i].m_used) && (wxGCPool[i].m_type == type))
3d2d8da1
RR
192 {
193 wxGCPool[i].m_used = TRUE;
194 return wxGCPool[i].m_gc;
195 }
196 }
5f170f33 197
3d2d8da1 198 wxFAIL_MSG( wxT("No GC available") );
5f170f33 199
3d2d8da1
RR
200 return (GdkGC*) NULL;
201}
202
203static void wxFreePoolGC( GdkGC *gc )
204{
e1208c31 205 for (int i = 0; i < GC_POOL_SIZE; i++)
3d2d8da1
RR
206 {
207 if (wxGCPool[i].m_gc == gc)
208 {
209 wxGCPool[i].m_used = FALSE;
210 return;
211 }
212 }
5f170f33 213
3d2d8da1
RR
214 wxFAIL_MSG( wxT("Wrong GC") );
215}
216
c801d85f 217//-----------------------------------------------------------------------------
ec758a20 218// wxWindowDC
c801d85f
KB
219//-----------------------------------------------------------------------------
220
b0e0d661 221IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
c801d85f 222
4bc67cc5 223wxWindowDC::wxWindowDC()
c801d85f 224{
265898fd
RR
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;
230 m_isMemDC = FALSE;
e1208c31 231 m_isScreenDC = FALSE;
bbbbe360 232 m_owner = (wxWindow *)NULL;
8943b403
OK
233#ifdef __WXGTK20__
234 m_context = (PangoContext *)NULL;
235 m_fontdesc = (PangoFontDescription *)NULL;
236#endif
903f689b 237}
c801d85f 238
ec758a20 239wxWindowDC::wxWindowDC( wxWindow *window )
c801d85f 240{
265898fd
RR
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;
bbbbe360 246 m_owner = (wxWindow *)NULL;
6db90681 247 m_isMemDC = FALSE;
e1208c31 248 m_isScreenDC = FALSE;
3b245d60 249 m_font = window->GetFont();
7d5af6fa 250
223d09f6 251 wxASSERT_MSG( window, wxT("DC needs a window") );
7d5af6fa 252
a2053b27 253 GtkWidget *widget = window->m_wxwindow;
7d5af6fa 254
b7f1f77f
VZ
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
258 if ( !widget )
259 {
260 window = window->GetParent();
261 widget = window->m_wxwindow;
262 }
263
223d09f6 264 wxASSERT_MSG( widget, wxT("DC needs a widget") );
7d5af6fa 265
8943b403
OK
266#ifdef __WXGTK20__
267 m_context = gtk_widget_get_pango_context( widget );
268 m_fontdesc = widget->style->font_desc;
269#endif
270
da048e3d
RR
271 GtkPizza *pizza = GTK_PIZZA( widget );
272 m_window = pizza->bin_window;
7d5af6fa 273
1e133b7d
RR
274 /* not realized ? */
275 if (!m_window)
276 {
6db90681 277 /* don't report problems */
7d5af6fa
VZ
278 m_ok = TRUE;
279
280 return;
1e133b7d 281 }
7d5af6fa 282
b7f1f77f 283 m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget );
7d5af6fa 284
265898fd 285 SetUpDC();
bbbbe360
RR
286
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) */
7d5af6fa 293
bbbbe360 294 m_owner = window;
903f689b 295}
c801d85f 296
4bc67cc5 297wxWindowDC::~wxWindowDC()
c801d85f 298{
265898fd 299 Destroy();
903f689b 300}
c801d85f 301
809934d2
RR
302void wxWindowDC::SetUpDC()
303{
304 m_ok = TRUE;
5f170f33 305
809934d2 306 wxASSERT_MSG( !m_penGC, wxT("GCs already created") );
5f170f33 307
f6bcfd97
BP
308 if (m_isScreenDC)
309 {
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 );
314 }
315 else
809934d2
RR
316 if (m_isMemDC && (((wxMemoryDC*)this)->m_selected.GetDepth() == 1))
317 {
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 );
322 }
323 else
324 {
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 );
329 }
330
331 /* background colour */
332 m_backgroundBrush = *wxWHITE_BRUSH;
333 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
334 GdkColor *bg_col = m_backgroundBrush.GetColour().GetColor();
335
336 /* m_textGC */
337 m_textForegroundColour.CalcPixel( m_cmap );
338 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
339
340 m_textBackgroundColour.CalcPixel( m_cmap );
341 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
342
343 gdk_gc_set_fill( m_textGC, GDK_SOLID );
344
345 /* m_penGC */
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 );
5f170f33 349
809934d2 350 gdk_gc_set_line_attributes( m_penGC, 0, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_ROUND );
5f170f33 351
809934d2
RR
352 /* m_brushGC */
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 );
5f170f33 356
809934d2 357 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
5f170f33 358
809934d2
RR
359 /* m_bgGC */
360 gdk_gc_set_background( m_bgGC, bg_col );
361 gdk_gc_set_foreground( m_bgGC, bg_col );
362
363 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
5f170f33 364
809934d2
RR
365 /* ROPs */
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 );
5f170f33 369
809934d2
RR
370 /* clipping */
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 );
375
376 if (!hatch_bitmap)
377 {
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 );
385 }
386}
387
72cdf4c9 388void wxWindowDC::DoFloodFill( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
463c1fa1 389 const wxColour &WXUNUSED(col), int WXUNUSED(style) )
c801d85f 390{
223d09f6 391 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
903f689b 392}
c801d85f 393
dc1efb1d 394bool wxWindowDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const
c801d85f 395{
dc1efb1d
JS
396 // Generic (and therefore rather inefficient) method.
397 // Could be improved.
398 wxMemoryDC memdc;
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));
405 return TRUE;
903f689b 406}
c801d85f 407
72cdf4c9 408void wxWindowDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
c801d85f 409{
223d09f6 410 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 411
265898fd
RR
412 if (m_pen.GetStyle() != wxTRANSPARENT)
413 {
6db90681
RR
414 if (m_window)
415 gdk_draw_line( m_window, m_penGC, XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2) );
7d5af6fa 416
ed880dd4
RR
417 CalcBoundingBox(x1, y1);
418 CalcBoundingBox(x2, y2);
265898fd 419 }
903f689b 420}
c801d85f 421
72cdf4c9 422void wxWindowDC::DoCrossHair( wxCoord x, wxCoord y )
c801d85f 423{
223d09f6 424 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 425
265898fd
RR
426 if (m_pen.GetStyle() != wxTRANSPARENT)
427 {
428 int w = 0;
429 int h = 0;
430 GetSize( &w, &h );
72cdf4c9
VZ
431 wxCoord xx = XLOG2DEV(x);
432 wxCoord yy = YLOG2DEV(y);
6db90681 433 if (m_window)
7d5af6fa 434 {
6db90681
RR
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) );
7d5af6fa 437 }
265898fd 438 }
903f689b 439}
c801d85f 440
72cdf4c9
VZ
441void wxWindowDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2,
442 wxCoord xc, wxCoord yc )
c801d85f 443{
223d09f6 444 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 445
72cdf4c9
VZ
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);
7d5af6fa 452 double dx = xx1 - xxc;
265898fd 453 double dy = yy1 - yyc;
de87c353 454 double radius = sqrt((double)(dx*dx+dy*dy));
72cdf4c9 455 wxCoord r = (wxCoord)radius;
265898fd
RR
456 double radius1, radius2;
457
7d5af6fa 458 if (xx1 == xx2 && yy1 == yy2)
265898fd
RR
459 {
460 radius1 = 0.0;
461 radius2 = 360.0;
7d5af6fa
VZ
462 }
463 else
464 if (radius == 0.0)
265898fd
RR
465 {
466 radius1 = radius2 = 0.0;
7d5af6fa
VZ
467 }
468 else
265898fd
RR
469 {
470 radius1 = (xx1 - xxc == 0) ?
b0e0d661
VZ
471 (yy1 - yyc < 0) ? 90.0 : -90.0 :
472 -atan2(double(yy1-yyc), double(xx1-xxc)) * RAD2DEG;
265898fd 473 radius2 = (xx2 - xxc == 0) ?
b0e0d661
VZ
474 (yy2 - yyc < 0) ? 90.0 : -90.0 :
475 -atan2(double(yy2-yyc), double(xx2-xxc)) * RAD2DEG;
265898fd 476 }
72cdf4c9
VZ
477 wxCoord alpha1 = wxCoord(radius1 * 64.0);
478 wxCoord alpha2 = wxCoord((radius2 - radius1) * 64.0);
265898fd
RR
479 while (alpha2 <= 0) alpha2 += 360*64;
480 while (alpha1 > 360*64) alpha1 -= 360*64;
481
6db90681
RR
482 if (m_window)
483 {
484 if (m_brush.GetStyle() != wxTRANSPARENT)
e9f88d04
VZ
485 {
486 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
487 {
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 );
493 } else
494 if (m_brush.GetStyle() == wxSTIPPLE)
495 {
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 );
501 }
502 else
503 {
504 gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
505 }
506 }
7d5af6fa 507
6db90681
RR
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 );
510 }
7d5af6fa 511
265898fd
RR
512 CalcBoundingBox (x1, y1);
513 CalcBoundingBox (x2, y2);
903f689b 514}
c801d85f 515
72cdf4c9 516void wxWindowDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea )
c801d85f 517{
223d09f6 518 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 519
72cdf4c9
VZ
520 wxCoord xx = XLOG2DEV(x);
521 wxCoord yy = YLOG2DEV(y);
522 wxCoord ww = m_signX * XLOG2DEVREL(width);
523 wxCoord hh = m_signY * YLOG2DEVREL(height);
7d5af6fa 524
265898fd
RR
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; }
7d5af6fa 528
6db90681
RR
529 if (m_window)
530 {
72cdf4c9
VZ
531 wxCoord start = wxCoord(sa * 64.0);
532 wxCoord end = wxCoord(ea * 64.0);
7d5af6fa 533
6db90681 534 if (m_brush.GetStyle() != wxTRANSPARENT)
e9f88d04
VZ
535 {
536 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
537 {
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 );
543 } else
544 if (m_brush.GetStyle() == wxSTIPPLE)
545 {
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 );
551 }
552 else
553 {
554 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
555 }
556 }
7d5af6fa 557
6db90681
RR
558 if (m_pen.GetStyle() != wxTRANSPARENT)
559 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, start, end );
560 }
7d5af6fa 561
265898fd
RR
562 CalcBoundingBox (x, y);
563 CalcBoundingBox (x + width, y + height);
903f689b 564}
c801d85f 565
72cdf4c9 566void wxWindowDC::DoDrawPoint( wxCoord x, wxCoord y )
c801d85f 567{
223d09f6 568 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 569
6db90681 570 if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window)
265898fd 571 gdk_draw_point( m_window, m_penGC, XLOG2DEV(x), YLOG2DEV(y) );
7d5af6fa 572
265898fd 573 CalcBoundingBox (x, y);
903f689b 574}
c801d85f 575
72cdf4c9 576void wxWindowDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset )
c801d85f 577{
223d09f6 578 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 579
265898fd
RR
580 if (m_pen.GetStyle() == wxTRANSPARENT) return;
581 if (n <= 0) return;
7d5af6fa 582
265898fd 583 CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset );
7d5af6fa 584
265898fd
RR
585 for (int i = 0; i < n-1; i++)
586 {
72cdf4c9
VZ
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);
7d5af6fa
VZ
591
592 if (m_window)
6db90681 593 gdk_draw_line( m_window, m_penGC, x1, y1, x2, y2 );
7d5af6fa 594
265898fd
RR
595 CalcBoundingBox( points[i+1].x + xoffset, points[i+1].y + yoffset );
596 }
903f689b 597}
c801d85f 598
72cdf4c9 599void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle) )
cf7a7e13 600{
223d09f6 601 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 602
4bc67cc5 603 if (n <= 0) return;
7d5af6fa 604
265898fd
RR
605 GdkPoint *gdkpoints = new GdkPoint[n+1];
606 int i;
607 for (i = 0 ; i < n ; i++)
608 {
609 gdkpoints[i].x = XLOG2DEV(points[i].x + xoffset);
610 gdkpoints[i].y = YLOG2DEV(points[i].y + yoffset);
7d5af6fa 611
265898fd
RR
612 CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset );
613 }
7d5af6fa 614
de2d2cdc 615 if (m_window)
72174350 616 {
e1208c31 617 if (m_brush.GetStyle() != wxTRANSPARENT)
72174350 618 {
e1208c31
RR
619 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
620 {
5f170f33
VZ
621 gdk_gc_set_ts_origin( m_textGC,
622 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
e1208c31
RR
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 );
626 } else
627 if (m_brush.GetStyle() == wxSTIPPLE)
628 {
5f170f33
VZ
629 gdk_gc_set_ts_origin( m_brushGC,
630 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
e1208c31
RR
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 );
634 }
635 else
636 {
637 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
638 }
72174350 639 }
7d5af6fa 640
e1208c31 641 if (m_pen.GetStyle() != wxTRANSPARENT)
b0e0d661 642 {
e1208c31
RR
643 for (i = 0 ; i < n ; i++)
644 {
645 gdk_draw_line( m_window, m_penGC,
646 gdkpoints[i%n].x,
647 gdkpoints[i%n].y,
648 gdkpoints[(i+1)%n].x,
649 gdkpoints[(i+1)%n].y);
650 }
265898fd 651 }
6db90681 652 }
7d5af6fa 653
265898fd 654 delete[] gdkpoints;
903f689b 655}
c801d85f 656
72cdf4c9 657void wxWindowDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 658{
223d09f6 659 wxCHECK_RET( Ok(), wxT("invalid window dc") );
c801d85f 660
72cdf4c9
VZ
661 wxCoord xx = XLOG2DEV(x);
662 wxCoord yy = YLOG2DEV(y);
663 wxCoord ww = m_signX * XLOG2DEVREL(width);
664 wxCoord hh = m_signY * YLOG2DEVREL(height);
7d5af6fa 665
265898fd
RR
666 // CMB: draw nothing if transformed w or h is 0
667 if (ww == 0 || hh == 0) return;
6f65e337 668
265898fd
RR
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; }
6f65e337 672
6db90681
RR
673 if (m_window)
674 {
e1208c31 675 if (m_brush.GetStyle() != wxTRANSPARENT)
72174350 676 {
e1208c31
RR
677 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
678 {
5f170f33
VZ
679 gdk_gc_set_ts_origin( m_textGC,
680 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
e1208c31
RR
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 );
684 }
685 else if (m_brush.GetStyle() == wxSTIPPLE)
686 {
5f170f33
VZ
687 gdk_gc_set_ts_origin( m_brushGC,
688 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
e1208c31 689 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
72174350 690 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
e1208c31
RR
691 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
692 }
693 else
694 {
695 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
696 }
72174350 697 }
e1208c31
RR
698
699 if (m_pen.GetStyle() != wxTRANSPARENT)
700 gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 );
6db90681 701 }
7d5af6fa 702
265898fd
RR
703 CalcBoundingBox( x, y );
704 CalcBoundingBox( x + width, y + height );
903f689b 705}
c801d85f 706
72cdf4c9 707void wxWindowDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
c801d85f 708{
223d09f6 709 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 710
265898fd 711 if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
7d5af6fa 712
72cdf4c9
VZ
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);
265898fd
RR
718
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; }
722
723 // CMB: if radius is zero use DrawRectangle() instead to avoid
724 // X drawing errors with small radii
725 if (rr == 0)
726 {
727 DrawRectangle( x, y, width, height );
728 return;
729 }
730
731 // CMB: draw nothing if transformed w or h is 0
732 if (ww == 0 || hh == 0) return;
733
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)
737 {
738 ww--;
739 hh--;
740 }
741
6db90681 742 if (m_window)
265898fd 743 {
6db90681
RR
744 // CMB: ensure dd is not larger than rectangle otherwise we
745 // get an hour glass shape
72cdf4c9 746 wxCoord dd = 2 * rr;
6db90681
RR
747 if (dd > ww) dd = ww;
748 if (dd > hh) dd = hh;
749 rr = dd / 2;
750
751 if (m_brush.GetStyle() != wxTRANSPARENT)
752 {
a56fcaaf
RR
753 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
754 {
5f170f33
VZ
755 gdk_gc_set_ts_origin( m_textGC,
756 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
a56fcaaf
RR
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 );
765 }
766 else if (m_brush.GetStyle() == wxSTIPPLE)
767 {
5f170f33
VZ
768 gdk_gc_set_ts_origin( m_brushGC,
769 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
a56fcaaf
RR
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 );
778 }
779 else
780 {
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 );
787 }
6db90681 788 }
7d5af6fa 789
6db90681 790 if (m_pen.GetStyle() != wxTRANSPARENT)
7d5af6fa 791 {
6db90681
RR
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 );
7d5af6fa 800 }
265898fd 801 }
7d5af6fa 802
265898fd
RR
803 // this ignores the radius
804 CalcBoundingBox( x, y );
805 CalcBoundingBox( x + width, y + height );
903f689b 806}
c801d85f 807
72cdf4c9 808void wxWindowDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 809{
223d09f6 810 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 811
72cdf4c9
VZ
812 wxCoord xx = XLOG2DEV(x);
813 wxCoord yy = YLOG2DEV(y);
814 wxCoord ww = m_signX * XLOG2DEVREL(width);
815 wxCoord hh = m_signY * YLOG2DEVREL(height);
6f65e337 816
265898fd
RR
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; }
7d5af6fa 820
6db90681
RR
821 if (m_window)
822 {
823 if (m_brush.GetStyle() != wxTRANSPARENT)
a56fcaaf
RR
824 {
825 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
826 {
5f170f33
VZ
827 gdk_gc_set_ts_origin( m_textGC,
828 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
a56fcaaf
RR
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 );
832 }
833 else if (m_brush.GetStyle() == wxSTIPPLE)
834 {
5f170f33
VZ
835 gdk_gc_set_ts_origin( m_brushGC,
836 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
a56fcaaf
RR
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 );
840 }
841 else
842 {
843 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
844 }
845 }
7d5af6fa 846
6db90681
RR
847 if (m_pen.GetStyle() != wxTRANSPARENT)
848 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, 0, 360*64 );
849 }
7d5af6fa 850
ed880dd4 851 CalcBoundingBox( x - width, y - height );
265898fd 852 CalcBoundingBox( x + width, y + height );
903f689b 853}
c801d85f 854
72cdf4c9 855void wxWindowDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
c801d85f 856{
b0e0d661
VZ
857 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
858 DoDrawBitmap( (const wxBitmap&)icon, x, y, (bool)TRUE );
903f689b 859}
c801d85f 860
b0e0d661 861void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap,
72cdf4c9 862 wxCoord x, wxCoord y,
b0e0d661 863 bool useMask )
4bc67cc5 864{
223d09f6 865 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 866
223d09f6 867 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
7d5af6fa 868
cf214c35 869 bool is_mono = (bitmap.GetBitmap() != NULL);
82ea63e6 870
6e13c196 871 /* scale/translate size and position */
265898fd
RR
872 int xx = XLOG2DEV(x);
873 int yy = YLOG2DEV(y);
7d5af6fa 874
4bc67cc5
RR
875 int w = bitmap.GetWidth();
876 int h = bitmap.GetHeight();
7d5af6fa 877
6453876e
RR
878 CalcBoundingBox( x, y );
879 CalcBoundingBox( x + w, y + h );
7d5af6fa 880
6453876e 881 if (!m_window) return;
7d5af6fa 882
4bc67cc5
RR
883 int ww = XLOG2DEVREL(w);
884 int hh = YLOG2DEVREL(h);
7d5af6fa 885
3d2d8da1 886 /* compare to current clipping region */
e1208c31 887 if (!m_currentClippingRegion.IsNull())
3d2d8da1
RR
888 {
889 wxRegion tmp( xx,yy,ww,hh );
890 tmp.Intersect( m_currentClippingRegion );
891 if (tmp.IsEmpty())
892 return;
893 }
5f170f33 894
6e13c196 895 /* scale bitmap if required */
4bc67cc5 896 wxBitmap use_bitmap;
4bc67cc5 897 if ((w != ww) || (h != hh))
265898fd 898 {
4bc67cc5 899 wxImage image( bitmap );
82ea63e6
RR
900 image.Rescale( ww, hh );
901 if (is_mono)
902 use_bitmap = image.ConvertToMonoBitmap(255,255,255);
903 else
904 use_bitmap = image.ConvertToBitmap();
265898fd 905 }
4bc67cc5 906 else
265898fd 907 {
4bc67cc5 908 use_bitmap = bitmap;
265898fd 909 }
7d5af6fa 910
6e13c196 911 /* apply mask if any */
463c1fa1 912 GdkBitmap *mask = (GdkBitmap *) NULL;
4bc67cc5 913 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
7d5af6fa 914
3d2d8da1 915 if (useMask && mask)
82ea63e6 916 {
3d2d8da1 917 GdkBitmap *new_mask = (GdkBitmap*) NULL;
e1208c31 918 if (!m_currentClippingRegion.IsNull())
3d2d8da1
RR
919 {
920 GdkColor col;
921 new_mask = gdk_pixmap_new( wxRootWindow->window, ww, hh, 1 );
922 GdkGC *gc = gdk_gc_new( new_mask );
923 col.pixel = 0;
924 gdk_gc_set_foreground( gc, &col );
925 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh );
926 col.pixel = 0;
927 gdk_gc_set_background( gc, &col );
928 col.pixel = 1;
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 );
935 gdk_gc_unref( gc );
936 }
5f170f33 937
3d2d8da1
RR
938 if (is_mono)
939 {
940 if (new_mask)
941 gdk_gc_set_clip_mask( m_textGC, new_mask );
942 else
943 gdk_gc_set_clip_mask( m_textGC, mask );
944 gdk_gc_set_clip_origin( m_textGC, xx, yy );
945 }
946 else
947 {
948 if (new_mask)
949 gdk_gc_set_clip_mask( m_penGC, new_mask );
950 else
951 gdk_gc_set_clip_mask( m_penGC, mask );
952 gdk_gc_set_clip_origin( m_penGC, xx, yy );
953 }
954 if (new_mask)
955 gdk_bitmap_unref( new_mask );
b0e0d661 956 }
7d5af6fa 957
82ea63e6
RR
958 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
959 drawing a mono-bitmap (XBitmap) we use the current text GC */
960 if (is_mono)
f6bcfd97 961 gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), 0, 0, xx, yy, -1, -1 );
82ea63e6
RR
962 else
963 gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
72174350 964
6e13c196 965 /* remove mask again if any */
7d5af6fa 966 if (useMask && mask)
463c1fa1 967 {
82ea63e6
RR
968 if (is_mono)
969 {
970 gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL );
971 gdk_gc_set_clip_origin( m_textGC, 0, 0 );
e1208c31 972 if (!m_currentClippingRegion.IsNull())
3d2d8da1 973 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
82ea63e6
RR
974 }
975 else
976 {
977 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
978 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
e1208c31 979 if (!m_currentClippingRegion.IsNull())
3d2d8da1 980 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
82ea63e6 981 }
463c1fa1 982 }
463c1fa1
RR
983}
984
72cdf4c9
VZ
985bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
986 wxDC *source, wxCoord xsrc, wxCoord ysrc,
b0e0d661 987 int logical_func, bool useMask )
c801d85f 988{
6e13c196
RR
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. */
993
223d09f6 994 wxCHECK_MSG( Ok(), FALSE, wxT("invalid window dc") );
7d5af6fa 995
223d09f6 996 wxCHECK_MSG( source, FALSE, wxT("invalid source dc") );
7d5af6fa 997
6db90681 998 if (!m_window) return FALSE;
7d5af6fa 999
6e13c196
RR
1000 wxClientDC *srcDC = (wxClientDC*)source;
1001 wxMemoryDC *memDC = (wxMemoryDC*)source;
7d5af6fa 1002
6e13c196 1003 bool use_bitmap_method = FALSE;
82ea63e6 1004 bool is_mono = FALSE;
7d5af6fa 1005
6e13c196
RR
1006 if (srcDC->m_isMemDC)
1007 {
b0e0d661 1008 if (!memDC->m_selected.Ok()) return FALSE;
7d5af6fa 1009
6e13c196 1010 /* we use the "XCopyArea" way to copy a memory dc into
b0e0d661
VZ
1011 y different window if the memory dc BOTH
1012 a) doesn't have any mask or its mask isn't used
1013 b) it is clipped
1014 c) is not 1-bit */
7d5af6fa 1015
f234c60c 1016 if (useMask && (memDC->m_selected.GetMask()))
b0e0d661
VZ
1017 {
1018 /* we HAVE TO use the direct way for memory dcs
1019 that have mask since the XCopyArea doesn't know
1020 about masks */
1021 use_bitmap_method = TRUE;
1022 }
1023 else if (memDC->m_selected.GetDepth() == 1)
1024 {
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 */
82ea63e6 1028 is_mono = TRUE;
b0e0d661
VZ
1029 use_bitmap_method = TRUE;
1030 }
1031 else if ((xsrc == 0) && (ysrc == 0) &&
1032 (width == memDC->m_selected.GetWidth()) &&
1033 (height == memDC->m_selected.GetHeight()))
1034 {
7d5af6fa
VZ
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
b0e0d661
VZ
1038 the area to be scaled */
1039 use_bitmap_method = TRUE;
1040 }
1041 else
1042 {
1043 use_bitmap_method = FALSE;
1044 }
6e13c196 1045 }
7d5af6fa 1046
265898fd
RR
1047 CalcBoundingBox( xdest, ydest );
1048 CalcBoundingBox( xdest + width, ydest + height );
7d5af6fa 1049
3d2d8da1
RR
1050 /* scale/translate size and position */
1051 wxCoord xx = XLOG2DEV(xdest);
1052 wxCoord yy = YLOG2DEV(ydest);
1053
1054 wxCoord ww = XLOG2DEVREL(width);
1055 wxCoord hh = YLOG2DEVREL(height);
1056
1057 /* compare to current clipping region */
e1208c31 1058 if (!m_currentClippingRegion.IsNull())
3d2d8da1
RR
1059 {
1060 wxRegion tmp( xx,yy,ww,hh );
1061 tmp.Intersect( m_currentClippingRegion );
1062 if (tmp.IsEmpty())
1063 return TRUE;
1064 }
1065
4bc67cc5
RR
1066 int old_logical_func = m_logicalFunction;
1067 SetLogicalFunction( logical_func );
5f170f33 1068
6e13c196 1069 if (use_bitmap_method)
6f65e337 1070 {
6e13c196 1071 /* scale/translate bitmap size */
72cdf4c9
VZ
1072 wxCoord bm_width = memDC->m_selected.GetWidth();
1073 wxCoord bm_height = memDC->m_selected.GetHeight();
7d5af6fa 1074
72cdf4c9
VZ
1075 wxCoord bm_ww = XLOG2DEVREL( bm_width );
1076 wxCoord bm_hh = YLOG2DEVREL( bm_height );
7d5af6fa 1077
6e13c196 1078 /* scale bitmap if required */
6e13c196 1079 wxBitmap use_bitmap;
7d5af6fa 1080
6e13c196
RR
1081 if ((bm_width != bm_ww) || (bm_height != bm_hh))
1082 {
1083 wxImage image( memDC->m_selected );
b0e0d661 1084 image = image.Scale( bm_ww, bm_hh );
7d5af6fa 1085
82ea63e6
RR
1086 if (is_mono)
1087 use_bitmap = image.ConvertToMonoBitmap(255,255,255);
1088 else
1089 use_bitmap = image.ConvertToBitmap();
6e13c196
RR
1090 }
1091 else
e23d0e95 1092 {
6e13c196
RR
1093 use_bitmap = memDC->m_selected;
1094 }
7d5af6fa 1095
6e13c196 1096 /* apply mask if any */
6e13c196
RR
1097 GdkBitmap *mask = (GdkBitmap *) NULL;
1098 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
7d5af6fa
VZ
1099
1100 if (useMask && mask)
6e13c196 1101 {
3d2d8da1 1102 GdkBitmap *new_mask = (GdkBitmap*) NULL;
e1208c31 1103 if (!m_currentClippingRegion.IsNull())
3d2d8da1
RR
1104 {
1105 GdkColor col;
1106 new_mask = gdk_pixmap_new( wxRootWindow->window, bm_ww, bm_hh, 1 );
1107 GdkGC *gc = gdk_gc_new( new_mask );
1108 col.pixel = 0;
1109 gdk_gc_set_foreground( gc, &col );
1110 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
1111 col.pixel = 0;
1112 gdk_gc_set_background( gc, &col );
1113 col.pixel = 1;
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 );
1120 gdk_gc_unref( gc );
1121 }
5f170f33 1122
82ea63e6
RR
1123 if (is_mono)
1124 {
3d2d8da1
RR
1125 if (new_mask)
1126 gdk_gc_set_clip_mask( m_textGC, new_mask );
1127 else
1128 gdk_gc_set_clip_mask( m_textGC, mask );
82ea63e6
RR
1129 gdk_gc_set_clip_origin( m_textGC, xx, yy );
1130 }
1131 else
6e13c196 1132 {
3d2d8da1
RR
1133 if (new_mask)
1134 gdk_gc_set_clip_mask( m_penGC, new_mask );
1135 else
1136 gdk_gc_set_clip_mask( m_penGC, mask );
82ea63e6 1137 gdk_gc_set_clip_origin( m_penGC, xx, yy );
b0e0d661 1138 }
3d2d8da1
RR
1139 if (new_mask)
1140 gdk_bitmap_unref( new_mask );
6e13c196 1141 }
7d5af6fa 1142
82ea63e6
RR
1143 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1144 drawing a mono-bitmap (XBitmap) we use the current text GC */
5f170f33 1145
82ea63e6 1146 if (is_mono)
f6bcfd97 1147 gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), xsrc, ysrc, xx, yy, ww, hh );
82ea63e6
RR
1148 else
1149 gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, xx, yy, ww, hh );
1150
6e13c196 1151 /* remove mask again if any */
7d5af6fa 1152 if (useMask && mask)
6e13c196 1153 {
82ea63e6
RR
1154 if (is_mono)
1155 {
1156 gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL );
1157 gdk_gc_set_clip_origin( m_textGC, 0, 0 );
e1208c31 1158 if (!m_currentClippingRegion.IsNull())
3d2d8da1 1159 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
82ea63e6
RR
1160 }
1161 else
1162 {
1163 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
1164 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
e1208c31 1165 if (!m_currentClippingRegion.IsNull())
3d2d8da1 1166 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
82ea63e6 1167 }
265898fd 1168 }
6f65e337 1169 }
6e13c196
RR
1170 else /* use_bitmap_method */
1171 {
6e13c196 1172 if ((width != ww) || (height != hh))
b0e0d661
VZ
1173 {
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. */
7d5af6fa 1186
b0e0d661 1187 wxBitmap bitmap( width, height );
5f170f33 1188
a56fcaaf
RR
1189 /* copy including child window contents */
1190 gdk_gc_set_subwindow( m_penGC, GDK_INCLUDE_INFERIORS );
e1208c31 1191 gdk_window_copy_area( bitmap.GetPixmap(), m_penGC, 0, 0,
6e13c196 1192 srcDC->GetWindow(),
b0e0d661 1193 xsrc, ysrc, width, height );
a56fcaaf 1194 gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN );
5f170f33 1195
b0e0d661 1196 /* scale image */
6e13c196 1197 wxImage image( bitmap );
b0e0d661 1198 image = image.Scale( ww, hh );
7d5af6fa 1199
b0e0d661 1200 /* convert to bitmap */
b0e0d661 1201 bitmap = image.ConvertToBitmap();
7d5af6fa 1202
b0e0d661 1203 /* draw scaled bitmap */
6e13c196 1204 gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
7d5af6fa 1205
b0e0d661
VZ
1206 }
1207 else
1208 {
993f97ee
RR
1209 /* No scaling and not a memory dc with a mask either */
1210
a56fcaaf
RR
1211 /* copy including child window contents */
1212 gdk_gc_set_subwindow( m_penGC, GDK_INCLUDE_INFERIORS );
6e13c196
RR
1213 gdk_window_copy_area( m_window, m_penGC, xx, yy,
1214 srcDC->GetWindow(),
1215 xsrc, ysrc, width, height );
a56fcaaf 1216 gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN );
b0e0d661 1217 }
6e13c196 1218 }
c801d85f 1219
4bc67cc5
RR
1220 SetLogicalFunction( old_logical_func );
1221 return TRUE;
903f689b 1222}
c801d85f 1223
72cdf4c9 1224void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y )
c801d85f 1225{
223d09f6 1226 wxCHECK_RET( Ok(), wxT("invalid window dc") );
18a2fa37 1227
6db90681 1228 if (!m_window) return;
7d5af6fa 1229
265898fd 1230 GdkFont *font = m_font.GetInternalFont( m_scaleY );
6f65e337 1231
a1fffa9f
VZ
1232 wxCHECK_RET( font, wxT("invalid font") );
1233
8943b403
OK
1234#ifdef __WXGTK20__
1235 wxCHECK_RET( m_context, wxT("no Pango context") );
1236#endif
1237
265898fd
RR
1238 x = XLOG2DEV(x);
1239 y = YLOG2DEV(y);
18a2fa37 1240
8943b403
OK
1241#ifdef __WXGTK20__
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);
1245 {
1246 wxWX2MBbuf data = text.mb_str(wxConvUTF8);
1247 pango_layout_set_text(layout, data, strlen(data));
1248 }
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 );
1255#else
1256 wxCoord width = gdk_string_width( font, text.mbc_str() );
1257 wxCoord height = font->ascent + font->descent;
bbbbe360 1258 /* CMB 21/5/98: draw text background if mode is wxSOLID */
265898fd
RR
1259 if (m_backgroundMode == wxSOLID)
1260 {
265898fd
RR
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() );
1264 }
93c5dd39 1265 gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text.mbc_str() );
8943b403 1266#endif
18a2fa37 1267
bbbbe360
RR
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) */
265898fd
RR
1271 if (m_font.GetUnderlined())
1272 {
13111b2a 1273 wxCoord ul_y = y + font->ascent;
265898fd
RR
1274 if (font->descent > 0) ul_y++;
1275 gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y);
1276 }
7d5af6fa 1277
8943b403
OK
1278#ifdef __WXGTK20__
1279 g_object_unref( G_OBJECT( layout ) );
1280#endif
1281
1282 width = wxCoord(width / m_scaleX);
1283 height = wxCoord(height / m_scaleY);
1284 CalcBoundingBox (x + width, y + height);
265898fd 1285 CalcBoundingBox (x, y);
903f689b 1286}
c801d85f 1287
95724b1a
VZ
1288void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle )
1289{
1290 if (angle == 0.0)
1291 {
1292 DrawText(text, x, y);
1293 return;
1294 }
1295
1296 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1297
1298 if (!m_window) return;
1299
1300 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1301
1302 wxCHECK_RET( font, wxT("invalid font") );
1303
9a8c7620 1304 // the size of the text
13111b2a
VZ
1305 wxCoord w = gdk_string_width( font, text.mbc_str() );
1306 wxCoord h = font->ascent + font->descent;
95724b1a 1307
9a8c7620
VZ
1308 // draw the string normally
1309 wxBitmap src(w, h);
95724b1a
VZ
1310 wxMemoryDC dc;
1311 dc.SelectObject(src);
1312 dc.SetFont(GetFont());
1313 dc.SetBackground(*wxWHITE_BRUSH);
1314 dc.SetBrush(*wxBLACK_BRUSH);
1315 dc.Clear();
1316 dc.DrawText(text, 0, 0);
1317 dc.SetFont(wxNullFont);
9a8c7620 1318 dc.SelectObject(wxNullBitmap);
95724b1a
VZ
1319
1320 // Calculate the size of the rotated bounding box.
9a8c7620
VZ
1321 double rad = DegToRad(angle);
1322 double dx = cos(rad),
1323 dy = sin(rad);
1324
1325 // the rectngle vertices are counted clockwise with the first one being at
1326 // (0, 0) (or, rather, at (x, y))
1327 double x2 = w*dx,
1328 y2 = -w*dy; // y axis points to the bottom, hence minus
1329 double x4 = h*dy,
1330 y4 = h*dx;
1331 double x3 = x4 + x2,
1332 y3 = y4 + y2;
1333
72174350 1334 // calc max and min
9a8c7620
VZ
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);
1339
1340 // prepare to blit-with-rotate the bitmap to the DC
1341 wxImage image(src);
1342
1343 GdkColor *colText = m_textForegroundColour.GetColor(),
1344 *colBack = m_textBackgroundColour.GetColor();
72174350 1345
9a8c7620
VZ
1346 bool textColSet = TRUE;
1347
1348 unsigned char *data = image.GetData();
1349
1350 // paint pixel by pixel
1351 for ( wxCoord srcX = 0; srcX < w; srcX++ )
95724b1a 1352 {
9a8c7620 1353 for ( wxCoord srcY = 0; srcY < h; srcY++ )
95724b1a 1354 {
9a8c7620 1355 // transform source coords to dest coords
f6bcfd97
BP
1356 double r = sqrt((double)srcX*srcX + srcY*srcY);
1357 double angleOrig = atan2((double)srcY, (double)srcX) - rad;
9a8c7620
VZ
1358 wxCoord dstX = (wxCoord)(r*cos(angleOrig) + 0.5),
1359 dstY = (wxCoord)(r*sin(angleOrig) + 0.5);
1360
1361 // black pixel?
1362 bool textPixel = data[(srcY*w + srcX)*3] == 0;
1363 if ( textPixel || (m_backgroundMode == wxSOLID) )
95724b1a 1364 {
9a8c7620
VZ
1365 // change colour if needed
1366 if ( textPixel != textColSet )
95724b1a 1367 {
9a8c7620
VZ
1368 gdk_gc_set_foreground( m_textGC, textPixel ? colText
1369 : colBack );
1370
1371 textColSet = textPixel;
95724b1a 1372 }
9a8c7620
VZ
1373
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) );
95724b1a
VZ
1378 }
1379 }
1380 }
1381
9a8c7620
VZ
1382 // it would be better to draw with non underlined font and draw the line
1383 // manually here (it would be more straight...)
1384#if 0
1385 if ( m_font.GetUnderlined() )
1386 {
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));
1390 }
1391#endif // 0
1392
1393 // restore the font colour
1394 gdk_gc_set_foreground( m_textGC, colText );
1395
1396 // update the bounding box
1397 CalcBoundingBox(x + minX, y + minY);
1398 CalcBoundingBox(x + maxX, y + maxY);
95724b1a
VZ
1399}
1400
72cdf4c9
VZ
1401void wxWindowDC::DoGetTextExtent(const wxString &string,
1402 wxCoord *width, wxCoord *height,
1403 wxCoord *descent, wxCoord *externalLeading,
1404 wxFont *theFont) const
c801d85f 1405{
265898fd
RR
1406 wxFont fontToUse = m_font;
1407 if (theFont) fontToUse = *theFont;
7d5af6fa 1408
265898fd 1409 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
72cdf4c9
VZ
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);
265898fd 1413 if (externalLeading) (*externalLeading) = 0; // ??
903f689b 1414}
c801d85f 1415
72cdf4c9 1416wxCoord wxWindowDC::GetCharWidth() const
c801d85f 1417{
265898fd 1418 GdkFont *font = m_font.GetInternalFont( m_scaleY );
58c837a4 1419 wxCHECK_MSG( font, -1, wxT("invalid font") );
7beba2fc 1420
72cdf4c9 1421 return wxCoord(gdk_string_width( font, "H" ) / m_scaleX);
903f689b 1422}
c801d85f 1423
72cdf4c9 1424wxCoord wxWindowDC::GetCharHeight() const
c801d85f 1425{
265898fd 1426 GdkFont *font = m_font.GetInternalFont( m_scaleY );
58c837a4 1427 wxCHECK_MSG( font, -1, wxT("invalid font") );
7beba2fc 1428
72cdf4c9 1429 return wxCoord((font->ascent + font->descent) / m_scaleY);
903f689b 1430}
c801d85f 1431
4bc67cc5 1432void wxWindowDC::Clear()
c801d85f 1433{
223d09f6 1434 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1435
6db90681 1436 if (!m_window) return;
7d5af6fa 1437
f234c60c
RR
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. */
7d5af6fa 1444
f234c60c 1445 if (m_owner)
265898fd 1446 {
f234c60c
RR
1447 int width,height;
1448 m_owner->GetSize( &width, &height );
1449 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
b0e0d661 1450 return;
265898fd 1451 }
f234c60c
RR
1452
1453 if (m_isMemDC)
265898fd
RR
1454 {
1455 int width,height;
1456 GetSize( &width, &height );
1457 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
b0e0d661 1458 return;
265898fd 1459 }
903f689b 1460}
c801d85f 1461
ec758a20 1462void wxWindowDC::SetFont( const wxFont &font )
c801d85f 1463{
265898fd 1464 m_font = font;
8943b403
OK
1465#ifdef __WXGTK20__
1466 // fix fontdesc?
1467#endif
903f689b 1468}
c801d85f 1469
ec758a20 1470void wxWindowDC::SetPen( const wxPen &pen )
c801d85f 1471{
223d09f6 1472 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1473
265898fd 1474 if (m_pen == pen) return;
7d5af6fa 1475
265898fd 1476 m_pen = pen;
7d5af6fa 1477
265898fd 1478 if (!m_pen.Ok()) return;
7d5af6fa 1479
6db90681 1480 if (!m_window) return;
7d5af6fa 1481
265898fd 1482 gint width = m_pen.GetWidth();
265898fd
RR
1483 if (width <= 0)
1484 {
112c5086 1485 // CMB: if width is non-zero scale it with the dc
265898fd
RR
1486 width = 1;
1487 }
1488 else
1489 {
1490 // X doesn't allow different width in x and y and so we take
1491 // the average
503f414e
VZ
1492 double w = 0.5 +
1493 ( fabs((double) XLOG2DEVREL(width)) +
1494 fabs((double) YLOG2DEVREL(width)) ) / 2.0;
265898fd
RR
1495 width = (int)w;
1496 }
7d5af6fa 1497
2eca425d
RL
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};
7d5af6fa 1502
112c5086
RR
1503 // We express dash pattern in pen width unit, so we are
1504 // independent of zoom factor and so on...
1505 int req_nb_dash;
2eca425d 1506 const wxGTKDash *req_dash;
7d5af6fa 1507
265898fd
RR
1508 GdkLineStyle lineStyle = GDK_LINE_SOLID;
1509 switch (m_pen.GetStyle())
1510 {
112c5086 1511 case wxUSER_DASH:
7d5af6fa
VZ
1512 {
1513 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086 1514 req_nb_dash = m_pen.GetDashCount();
2eca425d 1515 req_dash = (wxGTKDash*)m_pen.GetDash();
112c5086 1516 break;
7d5af6fa
VZ
1517 }
1518 case wxDOT:
1519 {
1520 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1521 req_nb_dash = 2;
1522 req_dash = dotted;
7d5af6fa
VZ
1523 break;
1524 }
1525 case wxLONG_DASH:
1526 {
1527 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086 1528 req_nb_dash = 2;
72cdf4c9 1529 req_dash = wxCoord_dashed;
7d5af6fa
VZ
1530 break;
1531 }
1532 case wxSHORT_DASH:
1533 {
1534 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1535 req_nb_dash = 2;
1536 req_dash = short_dashed;
7d5af6fa
VZ
1537 break;
1538 }
1539 case wxDOT_DASH:
1540 {
1541// lineStyle = GDK_LINE_DOUBLE_DASH;
1542 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1543 req_nb_dash = 4;
1544 req_dash = dotted_dashed;
7d5af6fa
VZ
1545 break;
1546 }
1547
1548 case wxTRANSPARENT:
72174350 1549 case wxSTIPPLE_MASK_OPAQUE:
7d5af6fa
VZ
1550 case wxSTIPPLE:
1551 case wxSOLID:
1552 default:
1553 {
1554 lineStyle = GDK_LINE_SOLID;
2eca425d 1555 req_dash = (wxGTKDash*)NULL;
112c5086 1556 req_nb_dash = 0;
7d5af6fa
VZ
1557 break;
1558 }
265898fd 1559 }
7d5af6fa 1560
2eca425d 1561#if (GTK_MINOR_VERSION > 0) || (GTK_MAJOR_VERSION > 1)
112c5086
RR
1562 if (req_dash && req_nb_dash)
1563 {
2eca425d 1564 wxGTKDash *real_req_dash = new wxGTKDash[req_nb_dash];
112c5086
RR
1565 if (real_req_dash)
1566 {
1567 for (int i = 0; i < req_nb_dash; i++)
1568 real_req_dash[i] = req_dash[i] * width;
2eca425d 1569 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
112c5086
RR
1570 delete[] real_req_dash;
1571 }
1572 else
1573 {
1574 // No Memory. We use non-scaled dash pattern...
2eca425d 1575 gdk_gc_set_dashes( m_penGC, 0, (wxGTKDash*)req_dash, req_nb_dash );
112c5086
RR
1576 }
1577 }
953704c1 1578#endif
7d5af6fa 1579
265898fd
RR
1580 GdkCapStyle capStyle = GDK_CAP_ROUND;
1581 switch (m_pen.GetCap())
1582 {
265898fd
RR
1583 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
1584 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
d4aa3a4b
RR
1585 case wxCAP_ROUND:
1586 default:
72174350 1587 {
d4aa3a4b
RR
1588 if (width <= 1)
1589 {
1590 width = 0;
1591 capStyle = GDK_CAP_NOT_LAST;
1592 }
1593 else
1594 {
1595 capStyle = GDK_CAP_ROUND;
1596 }
72174350 1597 break;
d4aa3a4b 1598 }
265898fd 1599 }
7d5af6fa 1600
265898fd
RR
1601 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
1602 switch (m_pen.GetJoin())
1603 {
1604 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
265898fd 1605 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
d4aa3a4b
RR
1606 case wxJOIN_ROUND:
1607 default: { joinStyle = GDK_JOIN_ROUND; break; }
265898fd 1608 }
7d5af6fa 1609
265898fd 1610 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
7d5af6fa 1611
265898fd
RR
1612 m_pen.GetColour().CalcPixel( m_cmap );
1613 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
903f689b 1614}
c801d85f 1615
ec758a20 1616void wxWindowDC::SetBrush( const wxBrush &brush )
c801d85f 1617{
223d09f6 1618 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1619
265898fd 1620 if (m_brush == brush) return;
7d5af6fa 1621
265898fd 1622 m_brush = brush;
7d5af6fa 1623
265898fd 1624 if (!m_brush.Ok()) return;
7d5af6fa 1625
6db90681 1626 if (!m_window) return;
7d5af6fa 1627
265898fd
RR
1628 m_brush.GetColour().CalcPixel( m_cmap );
1629 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
7d5af6fa 1630
956dbab1 1631 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
7d5af6fa 1632
4fcd73bd 1633 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
265898fd 1634 {
4fcd73bd 1635 if (m_brush.GetStipple()->GetPixmap())
7d5af6fa 1636 {
956dbab1 1637 gdk_gc_set_fill( m_brushGC, GDK_TILED );
cd25b18c 1638 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
7d5af6fa 1639 }
b0e0d661 1640 else
7d5af6fa 1641 {
956dbab1 1642 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
4fcd73bd 1643 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
7d5af6fa 1644 }
265898fd 1645 }
7d5af6fa 1646
de2d2cdc
VZ
1647 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
1648 {
e1208c31
RR
1649 gdk_gc_set_fill( m_textGC, GDK_OPAQUE_STIPPLED);
1650 gdk_gc_set_stipple( m_textGC, m_brush.GetStipple()->GetMask()->GetBitmap() );
de2d2cdc
VZ
1651 }
1652
265898fd
RR
1653 if (IS_HATCH(m_brush.GetStyle()))
1654 {
956dbab1 1655 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
265898fd
RR
1656 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
1657 gdk_gc_set_stipple( m_brushGC, hatches[num] );
1658 }
903f689b 1659}
c801d85f 1660
ec758a20 1661void wxWindowDC::SetBackground( const wxBrush &brush )
46dc76ba 1662{
bbbbe360
RR
1663 /* CMB 21/7/98: Added SetBackground. Sets background brush
1664 * for Clear() and bg colour for shapes filled with cross-hatch brush */
7d5af6fa 1665
223d09f6 1666 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1667
265898fd 1668 if (m_backgroundBrush == brush) return;
7d5af6fa 1669
265898fd 1670 m_backgroundBrush = brush;
7d5af6fa 1671
265898fd 1672 if (!m_backgroundBrush.Ok()) return;
7d5af6fa 1673
6db90681 1674 if (!m_window) return;
7d5af6fa 1675
265898fd
RR
1676 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
1677 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
a802c3a1 1678 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
031b2a7b 1679 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
265898fd 1680 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
3417c2cd
RR
1681
1682 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
7d5af6fa 1683
cd25b18c 1684 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
265898fd 1685 {
fd128b0c 1686 if (m_backgroundBrush.GetStipple()->GetPixmap())
7d5af6fa 1687 {
3417c2cd 1688 gdk_gc_set_fill( m_bgGC, GDK_TILED );
fd128b0c 1689 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
7d5af6fa 1690 }
cd25b18c 1691 else
7d5af6fa 1692 {
3417c2cd 1693 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
fd128b0c 1694 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() );
7d5af6fa 1695 }
265898fd 1696 }
7d5af6fa 1697
265898fd
RR
1698 if (IS_HATCH(m_backgroundBrush.GetStyle()))
1699 {
3417c2cd 1700 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
265898fd
RR
1701 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
1702 gdk_gc_set_stipple( m_bgGC, hatches[num] );
bbbbe360 1703 }
903f689b 1704}
46dc76ba 1705
ec758a20 1706void wxWindowDC::SetLogicalFunction( int function )
c801d85f 1707{
223d09f6 1708 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1709
72174350
VZ
1710 if (m_logicalFunction == function)
1711 return;
1712
1713 // VZ: shouldn't this be a CHECK?
1714 if (!m_window)
1715 return;
01eaf507 1716
265898fd
RR
1717 GdkFunction mode = GDK_COPY;
1718 switch (function)
1719 {
3c679789
RR
1720 case wxXOR: mode = GDK_XOR; break;
1721 case wxINVERT: mode = GDK_INVERT; break;
01eaf507 1722#if (GTK_MINOR_VERSION > 0)
3c679789
RR
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;
7d5af6fa
VZ
1733 case wxCOPY: mode = GDK_COPY; break;
1734 case wxNO_OP: mode = GDK_NOOP; break;
1735 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
72174350 1736
2d52841d
RR
1737 // unsupported by GTK
1738 case wxNOR: mode = GDK_COPY; break;
c96faa7c 1739#endif
01eaf507 1740 default:
7d5af6fa 1741 {
223d09f6 1742 wxFAIL_MSG( wxT("unsupported logical function") );
7d5af6fa
VZ
1743 break;
1744 }
265898fd 1745 }
7d5af6fa 1746
265898fd 1747 m_logicalFunction = function;
7d5af6fa 1748
265898fd
RR
1749 gdk_gc_set_function( m_penGC, mode );
1750 gdk_gc_set_function( m_brushGC, mode );
72174350
VZ
1751
1752 // to stay compatible with wxMSW, we don't apply ROPs to the text
3d2d8da1
RR
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 );
903f689b 1756}
c801d85f 1757
ec758a20 1758void wxWindowDC::SetTextForeground( const wxColour &col )
c801d85f 1759{
223d09f6 1760 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1761
265898fd 1762 if (m_textForegroundColour == col) return;
7d5af6fa 1763
265898fd
RR
1764 m_textForegroundColour = col;
1765 if (!m_textForegroundColour.Ok()) return;
7d5af6fa 1766
6db90681 1767 if (!m_window) return;
7d5af6fa 1768
265898fd
RR
1769 m_textForegroundColour.CalcPixel( m_cmap );
1770 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
903f689b 1771}
c801d85f 1772
ec758a20 1773void wxWindowDC::SetTextBackground( const wxColour &col )
c801d85f 1774{
223d09f6 1775 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1776
265898fd 1777 if (m_textBackgroundColour == col) return;
7d5af6fa 1778
265898fd
RR
1779 m_textBackgroundColour = col;
1780 if (!m_textBackgroundColour.Ok()) return;
7d5af6fa 1781
6db90681 1782 if (!m_window) return;
7d5af6fa 1783
265898fd
RR
1784 m_textBackgroundColour.CalcPixel( m_cmap );
1785 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
903f689b 1786}
c801d85f 1787
ec758a20 1788void wxWindowDC::SetBackgroundMode( int mode )
c801d85f 1789{
223d09f6 1790 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1791
265898fd 1792 m_backgroundMode = mode;
46dc76ba 1793
6db90681 1794 if (!m_window) return;
7d5af6fa 1795
265898fd
RR
1796 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1797 // transparent/solid background mode
7d5af6fa 1798
265898fd
RR
1799 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
1800 {
1801 gdk_gc_set_fill( m_brushGC,
1802 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
1803 }
903f689b 1804}
c801d85f 1805
ec758a20 1806void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
c801d85f 1807{
223d09f6 1808 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
903f689b 1809}
c801d85f 1810
72cdf4c9 1811void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 1812{
223d09f6 1813 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1814
6db90681 1815 if (!m_window) return;
7d5af6fa 1816
3d2d8da1 1817 wxRect rect;
265898fd
RR
1818 rect.x = XLOG2DEV(x);
1819 rect.y = YLOG2DEV(y);
1820 rect.width = XLOG2DEVREL(width);
1821 rect.height = YLOG2DEVREL(height);
5f170f33 1822
e1208c31 1823 if (!m_currentClippingRegion.IsNull())
993f97ee
RR
1824 m_currentClippingRegion.Intersect( rect );
1825 else
1826 m_currentClippingRegion.Union( rect );
5f170f33
VZ
1827
1828#if USE_PAINT_REGION
e1208c31 1829 if (!m_paintClippingRegion.IsNull())
3d2d8da1 1830 m_currentClippingRegion.Intersect( m_paintClippingRegion );
809934d2 1831#endif
3d2d8da1 1832
ee8dbe63
RL
1833 wxCoord xx, yy, ww, hh;
1834 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
1835 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
1836
3d2d8da1
RR
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() );
903f689b 1841}
c801d85f 1842
b0e0d661 1843void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
463c1fa1 1844{
223d09f6 1845 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1846
463c1fa1
RR
1847 if (region.Empty())
1848 {
1849 DestroyClippingRegion();
1850 return;
1851 }
7d5af6fa 1852
6db90681 1853 if (!m_window) return;
5f170f33 1854
e1208c31 1855 if (!m_currentClippingRegion.IsNull())
993f97ee
RR
1856 m_currentClippingRegion.Intersect( region );
1857 else
1858 m_currentClippingRegion.Union( region );
5f170f33
VZ
1859
1860#if USE_PAINT_REGION
e1208c31 1861 if (!m_paintClippingRegion.IsNull())
3d2d8da1 1862 m_currentClippingRegion.Intersect( m_paintClippingRegion );
809934d2 1863#endif
3d2d8da1 1864
ee8dbe63
RL
1865 wxCoord xx, yy, ww, hh;
1866 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
1867 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
1868
3d2d8da1
RR
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() );
463c1fa1
RR
1873}
1874
4bc67cc5 1875void wxWindowDC::DestroyClippingRegion()
c801d85f 1876{
223d09f6 1877 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1878
265898fd 1879 wxDC::DestroyClippingRegion();
7d5af6fa 1880
3d2d8da1 1881 m_currentClippingRegion.Clear();
5f170f33
VZ
1882
1883#if USE_PAINT_REGION
3d2d8da1
RR
1884 if (!m_paintClippingRegion.IsEmpty())
1885 m_currentClippingRegion.Union( m_paintClippingRegion );
993f97ee 1886#endif
3d2d8da1 1887
6db90681 1888 if (!m_window) return;
7d5af6fa 1889
3d2d8da1
RR
1890 if (m_currentClippingRegion.IsEmpty())
1891 {
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 );
1896 }
1897 else
1898 {
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() );
1903 }
903f689b 1904}
c801d85f 1905
4bc67cc5 1906void wxWindowDC::Destroy()
dbf858b5 1907{
3d2d8da1 1908 if (m_penGC) wxFreePoolGC( m_penGC );
265898fd 1909 m_penGC = (GdkGC*) NULL;
3d2d8da1 1910 if (m_brushGC) wxFreePoolGC( m_brushGC );
265898fd 1911 m_brushGC = (GdkGC*) NULL;
3d2d8da1 1912 if (m_textGC) wxFreePoolGC( m_textGC );
265898fd 1913 m_textGC = (GdkGC*) NULL;
3d2d8da1 1914 if (m_bgGC) wxFreePoolGC( m_bgGC );
265898fd 1915 m_bgGC = (GdkGC*) NULL;
dbf858b5
RR
1916}
1917
238d735d
RR
1918void wxWindowDC::ComputeScaleAndOrigin()
1919{
1920 /* CMB: copy scale to see if it changes */
1921 double origScaleX = m_scaleX;
1922 double origScaleY = m_scaleY;
1923
1924 wxDC::ComputeScaleAndOrigin();
1925
1926 /* CMB: if scale has changed call SetPen to recalulate the line width */
1927 if ((m_scaleX != origScaleX || m_scaleY != origScaleY) &&
1928 (m_pen.Ok()))
1929 {
1930 /* this is a bit artificial, but we need to force wxDC to think
1931 the pen has changed */
1932 wxPen pen = m_pen;
1933 m_pen = wxNullPen;
1934 SetPen( pen );
1935 }
1936}
1937
b0e0d661
VZ
1938// Resolution in pixels per logical inch
1939wxSize wxWindowDC::GetPPI() const
1940{
1941 return wxSize(100, 100);
1942}
1943
1944int wxWindowDC::GetDepth() const
c801d85f 1945{
223d09f6 1946 wxFAIL_MSG(wxT("not implemented"));
b0e0d661
VZ
1947
1948 return -1;
903f689b 1949}
c801d85f 1950
d54e4256 1951#if wxUSE_SPLINES
c801d85f
KB
1952// ----------------------------------- spline code ----------------------------------------
1953
1954void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1955 double a3, double b3, double a4, double b4);
4bc67cc5 1956void wx_clear_stack();
c801d85f
KB
1957int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1958 double *y3, double *x4, double *y4);
1959void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1960 double x4, double y4);
1961static bool wx_spline_add_point(double x, double y);
1962static void wx_spline_draw_point_array(wxDC *dc);
1963
1964wxList wx_spline_point_list;
1965
b0e0d661
VZ
1966#define half(z1, z2) ((z1+z2)/2.0)
1967#define THRESHOLD 5
c801d85f
KB
1968
1969/* iterative version */
1970
1971void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1972 double b4)
1973{
1974 register double xmid, ymid;
1975 double x1, y1, x2, y2, x3, y3, x4, y4;
1976
1977 wx_clear_stack();
1978 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1979
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);
b0e0d661
VZ
1983 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1984 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
c801d85f
KB
1985 wx_spline_add_point( x1, y1 );
1986 wx_spline_add_point( xmid, ymid );
b0e0d661 1987 } else {
c801d85f
KB
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);
b0e0d661 1992 }
c801d85f
KB
1993 }
1994}
1995
1996/* utilities used by spline drawing routines */
1997
1998typedef struct wx_spline_stack_struct {
1999 double x1, y1, x2, y2, x3, y3, x4, y4;
2000} Stack;
2001
2002#define SPLINE_STACK_DEPTH 20
2003static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
2004static Stack *wx_stack_top;
2005static int wx_stack_count;
2006
4bc67cc5 2007void wx_clear_stack()
c801d85f
KB
2008{
2009 wx_stack_top = wx_spline_stack;
2010 wx_stack_count = 0;
2011}
2012
2013void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
2014{
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;
2023 wx_stack_top++;
2024 wx_stack_count++;
2025}
2026
2027int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
2028 double *x3, double *y3, double *x4, double *y4)
2029{
2030 if (wx_stack_count == 0)
b0e0d661 2031 return (0);
c801d85f
KB
2032 wx_stack_top--;
2033 wx_stack_count--;
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;
2042 return (1);
2043}
2044
2045static bool wx_spline_add_point(double x, double y)
2046{
2047 wxPoint *point = new wxPoint ;
2048 point->x = (int) x;
2049 point->y = (int) y;
2050 wx_spline_point_list.Append((wxObject*)point);
2051 return TRUE;
2052}
2053
2054static void wx_spline_draw_point_array(wxDC *dc)
2055{
2056 dc->DrawLines(&wx_spline_point_list, 0, 0 );
2057 wxNode *node = wx_spline_point_list.First();
2058 while (node)
2059 {
2060 wxPoint *point = (wxPoint *)node->Data();
2061 delete point;
2062 delete node;
2063 node = wx_spline_point_list.First();
2064 }
2065}
2066
b0e0d661 2067void wxWindowDC::DoDrawSpline( wxList *points )
c801d85f 2068{
223d09f6 2069 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 2070
c801d85f
KB
2071 wxPoint *p;
2072 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
2073 double x1, y1, x2, y2;
2074
2075 wxNode *node = points->First();
2076 p = (wxPoint *)node->Data();
2077
2078 x1 = p->x;
2079 y1 = p->y;
2080
2081 node = node->Next();
2082 p = (wxPoint *)node->Data();
2083
2084 x2 = p->x;
2085 y2 = p->y;
2086 cx1 = (double)((x1 + x2) / 2);
2087 cy1 = (double)((y1 + y2) / 2);
2088 cx2 = (double)((cx1 + x2) / 2);
2089 cy2 = (double)((cy1 + y2) / 2);
2090
2091 wx_spline_add_point(x1, y1);
2092
2093 while ((node = node->Next()) != NULL)
2094 {
2095 p = (wxPoint *)node->Data();
b0e0d661
VZ
2096 x1 = x2;
2097 y1 = y2;
2098 x2 = p->x;
2099 y2 = p->y;
c801d85f
KB
2100 cx4 = (double)(x1 + x2) / 2;
2101 cy4 = (double)(y1 + y2) / 2;
2102 cx3 = (double)(x1 + cx4) / 2;
2103 cy3 = (double)(y1 + cy4) / 2;
2104
2105 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
2106
b0e0d661
VZ
2107 cx1 = cx4;
2108 cy1 = cy4;
c801d85f
KB
2109 cx2 = (double)(cx1 + x2) / 2;
2110 cy2 = (double)(cy1 + y2) / 2;
2111 }
2112
2113 wx_spline_add_point( cx1, cy1 );
2114 wx_spline_add_point( x2, y2 );
2115
2116 wx_spline_draw_point_array( this );
903f689b 2117}
ec758a20 2118
b0e0d661 2119#endif // wxUSE_SPLINE
ec758a20
RR
2120
2121//-----------------------------------------------------------------------------
2122// wxPaintDC
2123//-----------------------------------------------------------------------------
2124
2125IMPLEMENT_DYNAMIC_CLASS(wxPaintDC,wxWindowDC)
2126
4bc67cc5 2127wxPaintDC::wxPaintDC()
ec758a20
RR
2128 : wxWindowDC()
2129{
2130}
2131
2132wxPaintDC::wxPaintDC( wxWindow *win )
2133 : wxWindowDC( win )
2134{
b6fa52db
RR
2135#if USE_PAINT_REGION
2136 if (!win->m_clipPaintRegion)
2137 return;
2138
e1208c31 2139 m_paintClippingRegion = win->GetUpdateRegion();
5f170f33
VZ
2140 GdkRegion *region = m_paintClippingRegion.GetRegion();
2141 if ( region )
2142 {
2143 m_currentClippingRegion.Union( m_paintClippingRegion );
2144
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 );
2149 }
809934d2 2150#endif
ec758a20
RR
2151}
2152
2153//-----------------------------------------------------------------------------
2154// wxClientDC
2155//-----------------------------------------------------------------------------
2156
2157IMPLEMENT_DYNAMIC_CLASS(wxClientDC,wxWindowDC)
2158
4bc67cc5 2159wxClientDC::wxClientDC()
ec758a20
RR
2160 : wxWindowDC()
2161{
2162}
2163
2164wxClientDC::wxClientDC( wxWindow *win )
2165 : wxWindowDC( win )
2166{
2167}
2168
3d2d8da1
RR
2169// ----------------------------------------------------------------------------
2170// wxDCModule
2171// ----------------------------------------------------------------------------
2172
2173class wxDCModule : public wxModule
2174{
2175public:
2176 bool OnInit();
2177 void OnExit();
2178
2179private:
2180 DECLARE_DYNAMIC_CLASS(wxDCModule)
2181};
2182
2183IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
2184
2185bool wxDCModule::OnInit()
2186{
2187 wxInitGCPool();
2188 return TRUE;
2189}
2190
2191void wxDCModule::OnExit()
2192{
2193 wxCleanUpGCPool();
2194}