]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/dcclient.cpp
forgot to uncomment a few things
[wxWidgets.git] / src / gtk / dcclient.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: dcclient.cpp
3// Purpose:
4// Author: Robert Roebling
6f65e337 5// RCS-ID: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling, Markus Holzem, Chris Breeze
b0e0d661 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"
ed673c6a 17#include "wx/gtk/win_gtk.h"
c801d85f 18
071a2d78
RR
19#include <math.h> // for floating-point functions
20#include <gdk/gdk.h>
21#include <gtk/gtk.h>
83624f79 22
c801d85f
KB
23//-----------------------------------------------------------------------------
24// local data
25//-----------------------------------------------------------------------------
26
27#include "bdiag.xbm"
28#include "fdiag.xbm"
29#include "cdiag.xbm"
30#include "horiz.xbm"
31#include "verti.xbm"
32#include "cross.xbm"
33#define num_hatches 6
34
35static GdkPixmap *hatches[num_hatches];
c67daf87 36static GdkPixmap **hatch_bitmap = (GdkPixmap **) NULL;
c801d85f 37
3d2d8da1
RR
38extern GtkWidget *wxRootWindow;
39
c801d85f
KB
40//-----------------------------------------------------------------------------
41// constants
42//-----------------------------------------------------------------------------
43
95724b1a 44const double RAD2DEG = 180.0 / M_PI;
c801d85f 45
9a8c7620
VZ
46// ----------------------------------------------------------------------------
47// private functions
48// ----------------------------------------------------------------------------
49
50static inline double dmax(double a, double b) { return a > b ? a : b; }
51static inline double dmin(double a, double b) { return a < b ? a : b; }
52
53static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
54
6f65e337
JS
55//-----------------------------------------------------------------------------
56// temporary implementation of the missing GDK function
57//-----------------------------------------------------------------------------
b0e0d661 58
6f65e337 59#include "gdk/gdkprivate.h"
b0e0d661
VZ
60
61void gdk_draw_bitmap (GdkDrawable *drawable,
62 GdkGC *gc,
63 GdkDrawable *src,
64 gint xsrc,
65 gint ysrc,
66 gint xdest,
67 gint ydest,
68 gint width,
69 gint height)
6f65e337 70{
265898fd
RR
71 GdkWindowPrivate *drawable_private;
72 GdkWindowPrivate *src_private;
73 GdkGCPrivate *gc_private;
74
75 g_return_if_fail (drawable != NULL);
76 g_return_if_fail (src != NULL);
77 g_return_if_fail (gc != NULL);
78
79 drawable_private = (GdkWindowPrivate*) drawable;
80 src_private = (GdkWindowPrivate*) src;
81 if (drawable_private->destroyed || src_private->destroyed)
82 return;
7d5af6fa 83
265898fd
RR
84 gc_private = (GdkGCPrivate*) gc;
85
86 if (width == -1) width = src_private->width;
87 if (height == -1) height = src_private->height;
88
89 XCopyPlane( drawable_private->xdisplay,
b0e0d661
VZ
90 src_private->xwindow,
91 drawable_private->xwindow,
92 gc_private->xgc,
93 xsrc, ysrc,
94 width, height,
95 xdest, ydest,
96 1 );
6f65e337
JS
97}
98
3d2d8da1
RR
99//-----------------------------------------------------------------------------
100// Implement Pool of Graphic contexts. Creating them takes too much time.
101//-----------------------------------------------------------------------------
102
0e09f76e
RR
103enum wxPoolGCType
104{
105 wxGC_ERROR = 0,
106 wxTEXT_MONO,
107 wxBG_MONO,
108 wxPEN_MONO,
109 wxBRUSH_MONO,
110 wxTEXT_COLOUR,
111 wxBG_COLOUR,
112 wxPEN_COLOUR,
113 wxBRUSH_COLOUR
114};
115
3d2d8da1
RR
116struct wxGC
117{
0e09f76e
RR
118 GdkGC *m_gc;
119 wxPoolGCType m_type;
120 bool m_used;
3d2d8da1
RR
121};
122
123static wxGC wxGCPool[200];
124
125static void wxInitGCPool()
126{
127 memset( wxGCPool, 0, 200*sizeof(wxGC) );
128}
129
130static void wxCleanUpGCPool()
131{
132 for (int i = 0; i < 200; i++)
133 {
134 if (wxGCPool[i].m_gc)
135 gdk_gc_unref( wxGCPool[i].m_gc );
136 }
137}
138
0e09f76e 139static GdkGC* wxGetPoolGC( GdkWindow *window, wxPoolGCType type )
3d2d8da1
RR
140{
141 for (int i = 0; i < 200; i++)
142 {
143 if (!wxGCPool[i].m_gc)
144 {
145 wxGCPool[i].m_gc = gdk_gc_new( window );
146 gdk_gc_set_exposures( wxGCPool[i].m_gc, FALSE );
0e09f76e 147 wxGCPool[i].m_type = type;
3d2d8da1
RR
148 wxGCPool[i].m_used = FALSE;
149 }
0e09f76e 150 if ((!wxGCPool[i].m_used) && (wxGCPool[i].m_type == type))
3d2d8da1
RR
151 {
152 wxGCPool[i].m_used = TRUE;
153 return wxGCPool[i].m_gc;
154 }
155 }
156
157 wxFAIL_MSG( wxT("No GC available") );
158
159 return (GdkGC*) NULL;
160}
161
162static void wxFreePoolGC( GdkGC *gc )
163{
164 for (int i = 0; i < 200; i++)
165 {
166 if (wxGCPool[i].m_gc == gc)
167 {
168 wxGCPool[i].m_used = FALSE;
169 return;
170 }
171 }
172
173 wxFAIL_MSG( wxT("Wrong GC") );
174}
175
c801d85f 176//-----------------------------------------------------------------------------
ec758a20 177// wxWindowDC
c801d85f
KB
178//-----------------------------------------------------------------------------
179
b0e0d661 180IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
c801d85f 181
4bc67cc5 182wxWindowDC::wxWindowDC()
c801d85f 183{
265898fd
RR
184 m_penGC = (GdkGC *) NULL;
185 m_brushGC = (GdkGC *) NULL;
186 m_textGC = (GdkGC *) NULL;
187 m_bgGC = (GdkGC *) NULL;
188 m_cmap = (GdkColormap *) NULL;
189 m_isMemDC = FALSE;
bbbbe360 190 m_owner = (wxWindow *)NULL;
903f689b 191}
c801d85f 192
ec758a20 193wxWindowDC::wxWindowDC( wxWindow *window )
c801d85f 194{
265898fd
RR
195 m_penGC = (GdkGC *) NULL;
196 m_brushGC = (GdkGC *) NULL;
197 m_textGC = (GdkGC *) NULL;
198 m_bgGC = (GdkGC *) NULL;
199 m_cmap = (GdkColormap *) NULL;
bbbbe360 200 m_owner = (wxWindow *)NULL;
6db90681 201 m_isMemDC = FALSE;
3b245d60 202 m_font = window->GetFont();
7d5af6fa 203
223d09f6 204 wxASSERT_MSG( window, wxT("DC needs a window") );
7d5af6fa 205
a2053b27 206 GtkWidget *widget = window->m_wxwindow;
7d5af6fa 207
b7f1f77f
VZ
208 // some controls don't have m_wxwindow - like wxStaticBox, but the user
209 // code should still be able to create wxClientDCs for them, so we will
210 // use the parent window here then
211 if ( !widget )
212 {
213 window = window->GetParent();
214 widget = window->m_wxwindow;
215 }
216
223d09f6 217 wxASSERT_MSG( widget, wxT("DC needs a widget") );
7d5af6fa 218
da048e3d
RR
219 GtkPizza *pizza = GTK_PIZZA( widget );
220 m_window = pizza->bin_window;
7d5af6fa 221
1e133b7d
RR
222 /* not realized ? */
223 if (!m_window)
224 {
6db90681 225 /* don't report problems */
7d5af6fa
VZ
226 m_ok = TRUE;
227
228 return;
1e133b7d 229 }
7d5af6fa 230
b7f1f77f 231 m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget );
7d5af6fa 232
265898fd 233 SetUpDC();
bbbbe360
RR
234
235 /* this must be done after SetUpDC, bacause SetUpDC calls the
236 repective SetBrush, SetPen, SetBackground etc functions
237 to set up the DC. SetBackground call m_owner->SetBackground
238 and this might not be desired as the standard dc background
239 is white whereas a window might assume gray to be the
240 standard (as e.g. wxStatusBar) */
7d5af6fa 241
bbbbe360 242 m_owner = window;
903f689b 243}
c801d85f 244
4bc67cc5 245wxWindowDC::~wxWindowDC()
c801d85f 246{
265898fd 247 Destroy();
903f689b 248}
c801d85f 249
72cdf4c9 250void wxWindowDC::DoFloodFill( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
463c1fa1 251 const wxColour &WXUNUSED(col), int WXUNUSED(style) )
c801d85f 252{
223d09f6 253 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
903f689b 254}
c801d85f 255
72cdf4c9 256bool wxWindowDC::DoGetPixel( wxCoord WXUNUSED(x1), wxCoord WXUNUSED(y1), wxColour *WXUNUSED(col) ) const
c801d85f 257{
223d09f6 258 wxFAIL_MSG( wxT("wxWindowDC::DoGetPixel not implemented") );
265898fd 259 return FALSE;
903f689b 260}
c801d85f 261
72cdf4c9 262void wxWindowDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
c801d85f 263{
223d09f6 264 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 265
265898fd
RR
266 if (m_pen.GetStyle() != wxTRANSPARENT)
267 {
6db90681
RR
268 if (m_window)
269 gdk_draw_line( m_window, m_penGC, XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2) );
7d5af6fa 270
ed880dd4
RR
271 CalcBoundingBox(x1, y1);
272 CalcBoundingBox(x2, y2);
265898fd 273 }
903f689b 274}
c801d85f 275
72cdf4c9 276void wxWindowDC::DoCrossHair( wxCoord x, wxCoord y )
c801d85f 277{
223d09f6 278 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 279
265898fd
RR
280 if (m_pen.GetStyle() != wxTRANSPARENT)
281 {
282 int w = 0;
283 int h = 0;
284 GetSize( &w, &h );
72cdf4c9
VZ
285 wxCoord xx = XLOG2DEV(x);
286 wxCoord yy = YLOG2DEV(y);
6db90681 287 if (m_window)
7d5af6fa 288 {
6db90681
RR
289 gdk_draw_line( m_window, m_penGC, 0, yy, XLOG2DEVREL(w), yy );
290 gdk_draw_line( m_window, m_penGC, xx, 0, xx, YLOG2DEVREL(h) );
7d5af6fa 291 }
265898fd 292 }
903f689b 293}
c801d85f 294
72cdf4c9
VZ
295void wxWindowDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2,
296 wxCoord xc, wxCoord yc )
c801d85f 297{
223d09f6 298 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 299
72cdf4c9
VZ
300 wxCoord xx1 = XLOG2DEV(x1);
301 wxCoord yy1 = YLOG2DEV(y1);
302 wxCoord xx2 = XLOG2DEV(x2);
303 wxCoord yy2 = YLOG2DEV(y2);
304 wxCoord xxc = XLOG2DEV(xc);
305 wxCoord yyc = YLOG2DEV(yc);
7d5af6fa 306 double dx = xx1 - xxc;
265898fd 307 double dy = yy1 - yyc;
de87c353 308 double radius = sqrt((double)(dx*dx+dy*dy));
72cdf4c9 309 wxCoord r = (wxCoord)radius;
265898fd
RR
310 double radius1, radius2;
311
7d5af6fa 312 if (xx1 == xx2 && yy1 == yy2)
265898fd
RR
313 {
314 radius1 = 0.0;
315 radius2 = 360.0;
7d5af6fa
VZ
316 }
317 else
318 if (radius == 0.0)
265898fd
RR
319 {
320 radius1 = radius2 = 0.0;
7d5af6fa
VZ
321 }
322 else
265898fd
RR
323 {
324 radius1 = (xx1 - xxc == 0) ?
b0e0d661
VZ
325 (yy1 - yyc < 0) ? 90.0 : -90.0 :
326 -atan2(double(yy1-yyc), double(xx1-xxc)) * RAD2DEG;
265898fd 327 radius2 = (xx2 - xxc == 0) ?
b0e0d661
VZ
328 (yy2 - yyc < 0) ? 90.0 : -90.0 :
329 -atan2(double(yy2-yyc), double(xx2-xxc)) * RAD2DEG;
265898fd 330 }
72cdf4c9
VZ
331 wxCoord alpha1 = wxCoord(radius1 * 64.0);
332 wxCoord alpha2 = wxCoord((radius2 - radius1) * 64.0);
265898fd
RR
333 while (alpha2 <= 0) alpha2 += 360*64;
334 while (alpha1 > 360*64) alpha1 -= 360*64;
335
6db90681
RR
336 if (m_window)
337 {
338 if (m_brush.GetStyle() != wxTRANSPARENT)
339 gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
7d5af6fa 340
6db90681
RR
341 if (m_pen.GetStyle() != wxTRANSPARENT)
342 gdk_draw_arc( m_window, m_penGC, FALSE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
343 }
7d5af6fa 344
265898fd
RR
345 CalcBoundingBox (x1, y1);
346 CalcBoundingBox (x2, y2);
903f689b 347}
c801d85f 348
72cdf4c9 349void wxWindowDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea )
c801d85f 350{
223d09f6 351 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 352
72cdf4c9
VZ
353 wxCoord xx = XLOG2DEV(x);
354 wxCoord yy = YLOG2DEV(y);
355 wxCoord ww = m_signX * XLOG2DEVREL(width);
356 wxCoord hh = m_signY * YLOG2DEVREL(height);
7d5af6fa 357
265898fd
RR
358 // CMB: handle -ve width and/or height
359 if (ww < 0) { ww = -ww; xx = xx - ww; }
360 if (hh < 0) { hh = -hh; yy = yy - hh; }
7d5af6fa 361
6db90681
RR
362 if (m_window)
363 {
72cdf4c9
VZ
364 wxCoord start = wxCoord(sa * 64.0);
365 wxCoord end = wxCoord(ea * 64.0);
7d5af6fa 366
6db90681
RR
367 if (m_brush.GetStyle() != wxTRANSPARENT)
368 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
7d5af6fa 369
6db90681
RR
370 if (m_pen.GetStyle() != wxTRANSPARENT)
371 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, start, end );
372 }
7d5af6fa 373
265898fd
RR
374 CalcBoundingBox (x, y);
375 CalcBoundingBox (x + width, y + height);
903f689b 376}
c801d85f 377
72cdf4c9 378void wxWindowDC::DoDrawPoint( wxCoord x, wxCoord y )
c801d85f 379{
223d09f6 380 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 381
6db90681 382 if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window)
265898fd 383 gdk_draw_point( m_window, m_penGC, XLOG2DEV(x), YLOG2DEV(y) );
7d5af6fa 384
265898fd 385 CalcBoundingBox (x, y);
903f689b 386}
c801d85f 387
72cdf4c9 388void wxWindowDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset )
c801d85f 389{
223d09f6 390 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 391
265898fd
RR
392 if (m_pen.GetStyle() == wxTRANSPARENT) return;
393 if (n <= 0) return;
7d5af6fa 394
265898fd 395 CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset );
7d5af6fa 396
265898fd
RR
397 for (int i = 0; i < n-1; i++)
398 {
72cdf4c9
VZ
399 wxCoord x1 = XLOG2DEV(points[i].x + xoffset);
400 wxCoord x2 = XLOG2DEV(points[i+1].x + xoffset);
401 wxCoord y1 = YLOG2DEV(points[i].y + yoffset); // oh, what a waste
402 wxCoord y2 = YLOG2DEV(points[i+1].y + yoffset);
7d5af6fa
VZ
403
404 if (m_window)
6db90681 405 gdk_draw_line( m_window, m_penGC, x1, y1, x2, y2 );
7d5af6fa 406
265898fd
RR
407 CalcBoundingBox( points[i+1].x + xoffset, points[i+1].y + yoffset );
408 }
903f689b 409}
c801d85f 410
72cdf4c9 411void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle) )
cf7a7e13 412{
223d09f6 413 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 414
4bc67cc5 415 if (n <= 0) return;
7d5af6fa 416
265898fd
RR
417 GdkPoint *gdkpoints = new GdkPoint[n+1];
418 int i;
419 for (i = 0 ; i < n ; i++)
420 {
421 gdkpoints[i].x = XLOG2DEV(points[i].x + xoffset);
422 gdkpoints[i].y = YLOG2DEV(points[i].y + yoffset);
7d5af6fa 423
265898fd
RR
424 CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset );
425 }
7d5af6fa 426
de2d2cdc 427 if (m_window)
72174350
VZ
428 {
429 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
430 gdk_draw_polygon (m_window, m_textGC, TRUE, gdkpoints, n);
431 else
432 {
433 if ((m_brush.GetStyle() != wxTRANSPARENT))
434 gdk_draw_polygon (m_window, m_brushGC, TRUE, gdkpoints, n);
435 }
436 }
7d5af6fa 437
265898fd 438 // To do: Fillstyle
7d5af6fa 439
6db90681
RR
440 if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window)
441 {
265898fd 442 for (i = 0 ; i < n ; i++)
b0e0d661 443 {
7d5af6fa 444 gdk_draw_line( m_window, m_penGC,
b0e0d661
VZ
445 gdkpoints[i%n].x,
446 gdkpoints[i%n].y,
447 gdkpoints[(i+1)%n].x,
448 gdkpoints[(i+1)%n].y);
265898fd 449 }
6db90681 450 }
7d5af6fa 451
265898fd 452 delete[] gdkpoints;
903f689b 453}
c801d85f 454
72cdf4c9 455void wxWindowDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 456{
223d09f6 457 wxCHECK_RET( Ok(), wxT("invalid window dc") );
c801d85f 458
72cdf4c9
VZ
459 wxCoord xx = XLOG2DEV(x);
460 wxCoord yy = YLOG2DEV(y);
461 wxCoord ww = m_signX * XLOG2DEVREL(width);
462 wxCoord hh = m_signY * YLOG2DEVREL(height);
7d5af6fa 463
265898fd
RR
464 // CMB: draw nothing if transformed w or h is 0
465 if (ww == 0 || hh == 0) return;
6f65e337 466
265898fd
RR
467 // CMB: handle -ve width and/or height
468 if (ww < 0) { ww = -ww; xx = xx - ww; }
469 if (hh < 0) { hh = -hh; yy = yy - hh; }
6f65e337 470
6db90681
RR
471 if (m_window)
472 {
72174350
VZ
473 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
474 {
475 gdk_draw_rectangle( m_window, m_textGC, TRUE, xx, yy, ww, hh );
476 gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 );
477 }
478 else
479 {
480 if (m_brush.GetStyle() != wxTRANSPARENT)
481 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
482
483 if (m_pen.GetStyle() != wxTRANSPARENT)
484 gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 );
485 }
6db90681 486 }
7d5af6fa 487
265898fd
RR
488 CalcBoundingBox( x, y );
489 CalcBoundingBox( x + width, y + height );
903f689b 490}
c801d85f 491
72cdf4c9 492void wxWindowDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
c801d85f 493{
223d09f6 494 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 495
265898fd 496 if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
7d5af6fa 497
72cdf4c9
VZ
498 wxCoord xx = XLOG2DEV(x);
499 wxCoord yy = YLOG2DEV(y);
500 wxCoord ww = m_signX * XLOG2DEVREL(width);
501 wxCoord hh = m_signY * YLOG2DEVREL(height);
502 wxCoord rr = XLOG2DEVREL((wxCoord)radius);
265898fd
RR
503
504 // CMB: handle -ve width and/or height
505 if (ww < 0) { ww = -ww; xx = xx - ww; }
506 if (hh < 0) { hh = -hh; yy = yy - hh; }
507
508 // CMB: if radius is zero use DrawRectangle() instead to avoid
509 // X drawing errors with small radii
510 if (rr == 0)
511 {
512 DrawRectangle( x, y, width, height );
513 return;
514 }
515
516 // CMB: draw nothing if transformed w or h is 0
517 if (ww == 0 || hh == 0) return;
518
519 // CMB: adjust size if outline is drawn otherwise the result is
520 // 1 pixel too wide and high
521 if (m_pen.GetStyle() != wxTRANSPARENT)
522 {
523 ww--;
524 hh--;
525 }
526
6db90681 527 if (m_window)
265898fd 528 {
6db90681
RR
529 // CMB: ensure dd is not larger than rectangle otherwise we
530 // get an hour glass shape
72cdf4c9 531 wxCoord dd = 2 * rr;
6db90681
RR
532 if (dd > ww) dd = ww;
533 if (dd > hh) dd = hh;
534 rr = dd / 2;
535
536 if (m_brush.GetStyle() != wxTRANSPARENT)
537 {
538 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
539 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
540 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
541 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
542 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
543 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
544 }
7d5af6fa 545
6db90681 546 if (m_pen.GetStyle() != wxTRANSPARENT)
7d5af6fa 547 {
6db90681
RR
548 gdk_draw_line( m_window, m_penGC, xx+rr, yy, xx+ww-rr, yy );
549 gdk_draw_line( m_window, m_penGC, xx+rr, yy+hh, xx+ww-rr, yy+hh );
550 gdk_draw_line( m_window, m_penGC, xx, yy+rr, xx, yy+hh-rr );
551 gdk_draw_line( m_window, m_penGC, xx+ww, yy+rr, xx+ww, yy+hh-rr );
552 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, dd, dd, 90*64, 90*64 );
553 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
554 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
555 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
7d5af6fa 556 }
265898fd 557 }
7d5af6fa 558
265898fd
RR
559 // this ignores the radius
560 CalcBoundingBox( x, y );
561 CalcBoundingBox( x + width, y + height );
903f689b 562}
c801d85f 563
72cdf4c9 564void wxWindowDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 565{
223d09f6 566 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 567
72cdf4c9
VZ
568 wxCoord xx = XLOG2DEV(x);
569 wxCoord yy = YLOG2DEV(y);
570 wxCoord ww = m_signX * XLOG2DEVREL(width);
571 wxCoord hh = m_signY * YLOG2DEVREL(height);
6f65e337 572
265898fd
RR
573 // CMB: handle -ve width and/or height
574 if (ww < 0) { ww = -ww; xx = xx - ww; }
575 if (hh < 0) { hh = -hh; yy = yy - hh; }
7d5af6fa 576
6db90681
RR
577 if (m_window)
578 {
579 if (m_brush.GetStyle() != wxTRANSPARENT)
580 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
7d5af6fa 581
6db90681
RR
582 if (m_pen.GetStyle() != wxTRANSPARENT)
583 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, 0, 360*64 );
584 }
7d5af6fa 585
ed880dd4 586 CalcBoundingBox( x - width, y - height );
265898fd 587 CalcBoundingBox( x + width, y + height );
903f689b 588}
c801d85f 589
72cdf4c9 590void wxWindowDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
c801d85f 591{
b0e0d661
VZ
592 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
593 DoDrawBitmap( (const wxBitmap&)icon, x, y, (bool)TRUE );
903f689b 594}
c801d85f 595
b0e0d661 596void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap,
72cdf4c9 597 wxCoord x, wxCoord y,
b0e0d661 598 bool useMask )
4bc67cc5 599{
223d09f6 600 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 601
223d09f6 602 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
7d5af6fa 603
cf214c35 604 bool is_mono = (bitmap.GetBitmap() != NULL);
82ea63e6 605
6e13c196 606 /* scale/translate size and position */
265898fd
RR
607 int xx = XLOG2DEV(x);
608 int yy = YLOG2DEV(y);
7d5af6fa 609
4bc67cc5
RR
610 int w = bitmap.GetWidth();
611 int h = bitmap.GetHeight();
7d5af6fa 612
6453876e
RR
613 CalcBoundingBox( x, y );
614 CalcBoundingBox( x + w, y + h );
7d5af6fa 615
6453876e 616 if (!m_window) return;
7d5af6fa 617
4bc67cc5
RR
618 int ww = XLOG2DEVREL(w);
619 int hh = YLOG2DEVREL(h);
7d5af6fa 620
3d2d8da1
RR
621 /* compare to current clipping region */
622 if (!m_currentClippingRegion.IsEmpty())
623 {
624 wxRegion tmp( xx,yy,ww,hh );
625 tmp.Intersect( m_currentClippingRegion );
626 if (tmp.IsEmpty())
627 return;
628 }
629
6e13c196 630 /* scale bitmap if required */
4bc67cc5 631 wxBitmap use_bitmap;
4bc67cc5 632 if ((w != ww) || (h != hh))
265898fd 633 {
4bc67cc5 634 wxImage image( bitmap );
82ea63e6
RR
635 image.Rescale( ww, hh );
636 if (is_mono)
637 use_bitmap = image.ConvertToMonoBitmap(255,255,255);
638 else
639 use_bitmap = image.ConvertToBitmap();
265898fd 640 }
4bc67cc5 641 else
265898fd 642 {
4bc67cc5 643 use_bitmap = bitmap;
265898fd 644 }
7d5af6fa 645
6e13c196 646 /* apply mask if any */
463c1fa1 647 GdkBitmap *mask = (GdkBitmap *) NULL;
4bc67cc5 648 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
7d5af6fa 649
3d2d8da1 650 if (useMask && mask)
82ea63e6 651 {
3d2d8da1
RR
652 GdkBitmap *new_mask = (GdkBitmap*) NULL;
653 if (!m_currentClippingRegion.IsEmpty())
654 {
655 GdkColor col;
656 new_mask = gdk_pixmap_new( wxRootWindow->window, ww, hh, 1 );
657 GdkGC *gc = gdk_gc_new( new_mask );
658 col.pixel = 0;
659 gdk_gc_set_foreground( gc, &col );
660 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh );
661 col.pixel = 0;
662 gdk_gc_set_background( gc, &col );
663 col.pixel = 1;
664 gdk_gc_set_foreground( gc, &col );
665 gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() );
666 gdk_gc_set_clip_origin( gc, -xx, -yy );
667 gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED );
668 gdk_gc_set_stipple( gc, mask );
669 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh );
670 gdk_gc_unref( gc );
671 }
672
673 if (is_mono)
674 {
675 if (new_mask)
676 gdk_gc_set_clip_mask( m_textGC, new_mask );
677 else
678 gdk_gc_set_clip_mask( m_textGC, mask );
679 gdk_gc_set_clip_origin( m_textGC, xx, yy );
680 }
681 else
682 {
683 if (new_mask)
684 gdk_gc_set_clip_mask( m_penGC, new_mask );
685 else
686 gdk_gc_set_clip_mask( m_penGC, mask );
687 gdk_gc_set_clip_origin( m_penGC, xx, yy );
688 }
689 if (new_mask)
690 gdk_bitmap_unref( new_mask );
b0e0d661 691 }
7d5af6fa 692
82ea63e6
RR
693 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
694 drawing a mono-bitmap (XBitmap) we use the current text GC */
695 if (is_mono)
696 gdk_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), 0, 0, xx, yy, -1, -1 );
697 else
698 gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
72174350 699
6e13c196 700 /* remove mask again if any */
7d5af6fa 701 if (useMask && mask)
463c1fa1 702 {
82ea63e6
RR
703 if (is_mono)
704 {
705 gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL );
706 gdk_gc_set_clip_origin( m_textGC, 0, 0 );
3d2d8da1
RR
707 if (!m_currentClippingRegion.IsEmpty())
708 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
82ea63e6
RR
709 }
710 else
711 {
712 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
713 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
3d2d8da1
RR
714 if (!m_currentClippingRegion.IsEmpty())
715 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
82ea63e6 716 }
463c1fa1 717 }
463c1fa1
RR
718}
719
72cdf4c9
VZ
720bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
721 wxDC *source, wxCoord xsrc, wxCoord ysrc,
b0e0d661 722 int logical_func, bool useMask )
c801d85f 723{
6e13c196
RR
724 /* this is the nth try to get this utterly useless function to
725 work. it now completely ignores the scaling or translation
726 of the source dc, but scales correctly on the target dc and
727 knows about possible mask information in a memory dc. */
728
223d09f6 729 wxCHECK_MSG( Ok(), FALSE, wxT("invalid window dc") );
7d5af6fa 730
223d09f6 731 wxCHECK_MSG( source, FALSE, wxT("invalid source dc") );
7d5af6fa 732
6db90681 733 if (!m_window) return FALSE;
7d5af6fa 734
6e13c196
RR
735 wxClientDC *srcDC = (wxClientDC*)source;
736 wxMemoryDC *memDC = (wxMemoryDC*)source;
7d5af6fa 737
6e13c196 738 bool use_bitmap_method = FALSE;
82ea63e6 739 bool is_mono = FALSE;
7d5af6fa 740
6e13c196
RR
741 if (srcDC->m_isMemDC)
742 {
b0e0d661 743 if (!memDC->m_selected.Ok()) return FALSE;
7d5af6fa 744
6e13c196 745 /* we use the "XCopyArea" way to copy a memory dc into
b0e0d661
VZ
746 y different window if the memory dc BOTH
747 a) doesn't have any mask or its mask isn't used
748 b) it is clipped
749 c) is not 1-bit */
7d5af6fa 750
f234c60c 751 if (useMask && (memDC->m_selected.GetMask()))
b0e0d661
VZ
752 {
753 /* we HAVE TO use the direct way for memory dcs
754 that have mask since the XCopyArea doesn't know
755 about masks */
756 use_bitmap_method = TRUE;
757 }
758 else if (memDC->m_selected.GetDepth() == 1)
759 {
760 /* we HAVE TO use the direct way for memory dcs
761 that are bitmaps because XCopyArea doesn't cope
762 with different bit depths */
82ea63e6 763 is_mono = TRUE;
b0e0d661
VZ
764 use_bitmap_method = TRUE;
765 }
766 else if ((xsrc == 0) && (ysrc == 0) &&
767 (width == memDC->m_selected.GetWidth()) &&
768 (height == memDC->m_selected.GetHeight()))
769 {
7d5af6fa
VZ
770 /* we SHOULD use the direct way if all of the bitmap
771 in the memory dc is copied in which case XCopyArea
772 wouldn't be able able to boost performace by reducing
b0e0d661
VZ
773 the area to be scaled */
774 use_bitmap_method = TRUE;
775 }
776 else
777 {
778 use_bitmap_method = FALSE;
779 }
6e13c196 780 }
7d5af6fa 781
265898fd
RR
782 CalcBoundingBox( xdest, ydest );
783 CalcBoundingBox( xdest + width, ydest + height );
7d5af6fa 784
3d2d8da1
RR
785 /* scale/translate size and position */
786 wxCoord xx = XLOG2DEV(xdest);
787 wxCoord yy = YLOG2DEV(ydest);
788
789 wxCoord ww = XLOG2DEVREL(width);
790 wxCoord hh = YLOG2DEVREL(height);
791
792 /* compare to current clipping region */
793 if (!m_currentClippingRegion.IsEmpty())
794 {
795 wxRegion tmp( xx,yy,ww,hh );
796 tmp.Intersect( m_currentClippingRegion );
797 if (tmp.IsEmpty())
798 return TRUE;
799 }
800
4bc67cc5
RR
801 int old_logical_func = m_logicalFunction;
802 SetLogicalFunction( logical_func );
7d5af6fa 803
6e13c196 804 if (use_bitmap_method)
6f65e337 805 {
6e13c196 806 /* scale/translate bitmap size */
72cdf4c9
VZ
807 wxCoord bm_width = memDC->m_selected.GetWidth();
808 wxCoord bm_height = memDC->m_selected.GetHeight();
7d5af6fa 809
72cdf4c9
VZ
810 wxCoord bm_ww = XLOG2DEVREL( bm_width );
811 wxCoord bm_hh = YLOG2DEVREL( bm_height );
7d5af6fa 812
6e13c196 813 /* scale bitmap if required */
6e13c196 814 wxBitmap use_bitmap;
7d5af6fa 815
6e13c196
RR
816 if ((bm_width != bm_ww) || (bm_height != bm_hh))
817 {
818 wxImage image( memDC->m_selected );
b0e0d661 819 image = image.Scale( bm_ww, bm_hh );
7d5af6fa 820
82ea63e6
RR
821 if (is_mono)
822 use_bitmap = image.ConvertToMonoBitmap(255,255,255);
823 else
824 use_bitmap = image.ConvertToBitmap();
6e13c196
RR
825 }
826 else
e23d0e95 827 {
6e13c196
RR
828 use_bitmap = memDC->m_selected;
829 }
7d5af6fa 830
6e13c196 831 /* apply mask if any */
6e13c196
RR
832 GdkBitmap *mask = (GdkBitmap *) NULL;
833 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
7d5af6fa
VZ
834
835 if (useMask && mask)
6e13c196 836 {
3d2d8da1
RR
837 GdkBitmap *new_mask = (GdkBitmap*) NULL;
838 if (!m_currentClippingRegion.IsEmpty())
839 {
840 GdkColor col;
841 new_mask = gdk_pixmap_new( wxRootWindow->window, bm_ww, bm_hh, 1 );
842 GdkGC *gc = gdk_gc_new( new_mask );
843 col.pixel = 0;
844 gdk_gc_set_foreground( gc, &col );
845 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
846 col.pixel = 0;
847 gdk_gc_set_background( gc, &col );
848 col.pixel = 1;
849 gdk_gc_set_foreground( gc, &col );
850 gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() );
851 gdk_gc_set_clip_origin( gc, -xx, -yy );
852 gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED );
853 gdk_gc_set_stipple( gc, mask );
854 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
855 gdk_gc_unref( gc );
856 }
857
82ea63e6
RR
858 if (is_mono)
859 {
3d2d8da1
RR
860 if (new_mask)
861 gdk_gc_set_clip_mask( m_textGC, new_mask );
862 else
863 gdk_gc_set_clip_mask( m_textGC, mask );
82ea63e6
RR
864 gdk_gc_set_clip_origin( m_textGC, xx, yy );
865 }
866 else
6e13c196 867 {
3d2d8da1
RR
868 if (new_mask)
869 gdk_gc_set_clip_mask( m_penGC, new_mask );
870 else
871 gdk_gc_set_clip_mask( m_penGC, mask );
82ea63e6 872 gdk_gc_set_clip_origin( m_penGC, xx, yy );
b0e0d661 873 }
3d2d8da1
RR
874 if (new_mask)
875 gdk_bitmap_unref( new_mask );
6e13c196 876 }
7d5af6fa 877
82ea63e6
RR
878 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
879 drawing a mono-bitmap (XBitmap) we use the current text GC */
880 if (is_mono)
881 gdk_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), xsrc, ysrc, xx, yy, ww, hh );
882 else
883 gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, xx, yy, ww, hh );
884
6e13c196 885 /* remove mask again if any */
7d5af6fa 886 if (useMask && mask)
6e13c196 887 {
82ea63e6
RR
888 if (is_mono)
889 {
890 gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL );
891 gdk_gc_set_clip_origin( m_textGC, 0, 0 );
3d2d8da1
RR
892 if (!m_currentClippingRegion.IsEmpty())
893 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
82ea63e6
RR
894 }
895 else
896 {
897 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
898 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
3d2d8da1
RR
899 if (!m_currentClippingRegion.IsEmpty())
900 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
82ea63e6 901 }
265898fd 902 }
6f65e337 903 }
6e13c196
RR
904 else /* use_bitmap_method */
905 {
6e13c196 906 if ((width != ww) || (height != hh))
b0e0d661
VZ
907 {
908 /* draw source window into a bitmap as we cannot scale
909 a window in contrast to a bitmap. this would actually
910 work with memory dcs as well, but we'd lose the mask
911 information and waste one step in this process since
912 a memory already has a bitmap. all this is slightly
913 inefficient as we could take an XImage directly from
914 an X window, but we'd then also have to care that
915 the window is not outside the screen (in which case
916 we'd get a BadMatch or what not).
917 Is a double XGetImage and combined XGetPixel and
918 XPutPixel really faster? I'm not sure. look at wxXt
919 for a different implementation of the same problem. */
7d5af6fa 920
b0e0d661 921 wxBitmap bitmap( width, height );
7d5af6fa 922 gdk_window_copy_area( bitmap.GetPixmap(), m_penGC, 0, 0,
6e13c196 923 srcDC->GetWindow(),
b0e0d661 924 xsrc, ysrc, width, height );
7d5af6fa 925
b0e0d661 926 /* scale image */
7d5af6fa 927
6e13c196 928 wxImage image( bitmap );
b0e0d661 929 image = image.Scale( ww, hh );
7d5af6fa 930
b0e0d661 931 /* convert to bitmap */
7d5af6fa 932
b0e0d661 933 bitmap = image.ConvertToBitmap();
7d5af6fa 934
b0e0d661 935 /* draw scaled bitmap */
7d5af6fa 936
6e13c196 937 gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
7d5af6fa 938
b0e0d661
VZ
939 }
940 else
941 {
942 /* no scaling and not a memory dc with a mask either */
7d5af6fa 943
6e13c196
RR
944 gdk_window_copy_area( m_window, m_penGC, xx, yy,
945 srcDC->GetWindow(),
946 xsrc, ysrc, width, height );
b0e0d661 947 }
6e13c196 948 }
c801d85f 949
4bc67cc5
RR
950 SetLogicalFunction( old_logical_func );
951 return TRUE;
903f689b 952}
c801d85f 953
72cdf4c9 954void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y )
c801d85f 955{
223d09f6 956 wxCHECK_RET( Ok(), wxT("invalid window dc") );
18a2fa37 957
6db90681 958 if (!m_window) return;
7d5af6fa 959
265898fd 960 GdkFont *font = m_font.GetInternalFont( m_scaleY );
6f65e337 961
a1fffa9f
VZ
962 wxCHECK_RET( font, wxT("invalid font") );
963
265898fd
RR
964 x = XLOG2DEV(x);
965 y = YLOG2DEV(y);
18a2fa37 966
bbbbe360 967 /* CMB 21/5/98: draw text background if mode is wxSOLID */
265898fd
RR
968 if (m_backgroundMode == wxSOLID)
969 {
72cdf4c9
VZ
970 wxCoord width = gdk_string_width( font, text.mbc_str() );
971 wxCoord height = font->ascent + font->descent;
265898fd
RR
972 gdk_gc_set_foreground( m_textGC, m_textBackgroundColour.GetColor() );
973 gdk_draw_rectangle( m_window, m_textGC, TRUE, x, y, width, height );
974 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
975 }
93c5dd39 976 gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text.mbc_str() );
18a2fa37 977
bbbbe360
RR
978 /* CMB 17/7/98: simple underline: ignores scaling and underlying
979 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
980 properties (see wxXt implementation) */
265898fd
RR
981 if (m_font.GetUnderlined())
982 {
13111b2a
VZ
983 wxCoord width = gdk_string_width( font, text.mbc_str() );
984 wxCoord ul_y = y + font->ascent;
265898fd
RR
985 if (font->descent > 0) ul_y++;
986 gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y);
987 }
7d5af6fa 988
13111b2a 989 wxCoord w, h;
265898fd
RR
990 GetTextExtent (text, &w, &h);
991 CalcBoundingBox (x + w, y + h);
992 CalcBoundingBox (x, y);
903f689b 993}
c801d85f 994
95724b1a
VZ
995void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle )
996{
997 if (angle == 0.0)
998 {
999 DrawText(text, x, y);
1000 return;
1001 }
1002
1003 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1004
1005 if (!m_window) return;
1006
1007 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1008
1009 wxCHECK_RET( font, wxT("invalid font") );
1010
9a8c7620 1011 // the size of the text
13111b2a
VZ
1012 wxCoord w = gdk_string_width( font, text.mbc_str() );
1013 wxCoord h = font->ascent + font->descent;
95724b1a 1014
9a8c7620
VZ
1015 // draw the string normally
1016 wxBitmap src(w, h);
95724b1a
VZ
1017 wxMemoryDC dc;
1018 dc.SelectObject(src);
1019 dc.SetFont(GetFont());
1020 dc.SetBackground(*wxWHITE_BRUSH);
1021 dc.SetBrush(*wxBLACK_BRUSH);
1022 dc.Clear();
1023 dc.DrawText(text, 0, 0);
1024 dc.SetFont(wxNullFont);
9a8c7620 1025 dc.SelectObject(wxNullBitmap);
95724b1a
VZ
1026
1027 // Calculate the size of the rotated bounding box.
9a8c7620
VZ
1028 double rad = DegToRad(angle);
1029 double dx = cos(rad),
1030 dy = sin(rad);
1031
1032 // the rectngle vertices are counted clockwise with the first one being at
1033 // (0, 0) (or, rather, at (x, y))
1034 double x2 = w*dx,
1035 y2 = -w*dy; // y axis points to the bottom, hence minus
1036 double x4 = h*dy,
1037 y4 = h*dx;
1038 double x3 = x4 + x2,
1039 y3 = y4 + y2;
1040
72174350 1041 // calc max and min
9a8c7620
VZ
1042 wxCoord maxX = (wxCoord)(dmax(x2, dmax(x3, x4)) + 0.5),
1043 maxY = (wxCoord)(dmax(y2, dmax(y3, y4)) + 0.5),
1044 minX = (wxCoord)(dmin(x2, dmin(x3, x4)) - 0.5),
1045 minY = (wxCoord)(dmin(y2, dmin(y3, y4)) - 0.5);
1046
1047 // prepare to blit-with-rotate the bitmap to the DC
1048 wxImage image(src);
1049
1050 GdkColor *colText = m_textForegroundColour.GetColor(),
1051 *colBack = m_textBackgroundColour.GetColor();
72174350 1052
9a8c7620
VZ
1053 bool textColSet = TRUE;
1054
1055 unsigned char *data = image.GetData();
1056
1057 // paint pixel by pixel
1058 for ( wxCoord srcX = 0; srcX < w; srcX++ )
95724b1a 1059 {
9a8c7620 1060 for ( wxCoord srcY = 0; srcY < h; srcY++ )
95724b1a 1061 {
9a8c7620
VZ
1062 // transform source coords to dest coords
1063 double r = sqrt(srcX*srcX + srcY*srcY);
1064 double angleOrig = atan2(srcY, srcX) - rad;
1065 wxCoord dstX = (wxCoord)(r*cos(angleOrig) + 0.5),
1066 dstY = (wxCoord)(r*sin(angleOrig) + 0.5);
1067
1068 // black pixel?
1069 bool textPixel = data[(srcY*w + srcX)*3] == 0;
1070 if ( textPixel || (m_backgroundMode == wxSOLID) )
95724b1a 1071 {
9a8c7620
VZ
1072 // change colour if needed
1073 if ( textPixel != textColSet )
95724b1a 1074 {
9a8c7620
VZ
1075 gdk_gc_set_foreground( m_textGC, textPixel ? colText
1076 : colBack );
1077
1078 textColSet = textPixel;
95724b1a 1079 }
9a8c7620
VZ
1080
1081 // don't use DrawPoint() because it uses the current pen
1082 // colour, and we don't need it here
1083 gdk_draw_point( m_window, m_textGC,
1084 XLOG2DEV(x + dstX), YLOG2DEV(y + dstY) );
95724b1a
VZ
1085 }
1086 }
1087 }
1088
9a8c7620
VZ
1089 // it would be better to draw with non underlined font and draw the line
1090 // manually here (it would be more straight...)
1091#if 0
1092 if ( m_font.GetUnderlined() )
1093 {
1094 gdk_draw_line( m_window, m_textGC,
1095 XLOG2DEV(x + x4), YLOG2DEV(y + y4 + font->descent),
1096 XLOG2DEV(x + x3), YLOG2DEV(y + y3 + font->descent));
1097 }
1098#endif // 0
1099
1100 // restore the font colour
1101 gdk_gc_set_foreground( m_textGC, colText );
1102
1103 // update the bounding box
1104 CalcBoundingBox(x + minX, y + minY);
1105 CalcBoundingBox(x + maxX, y + maxY);
95724b1a
VZ
1106}
1107
72cdf4c9
VZ
1108void wxWindowDC::DoGetTextExtent(const wxString &string,
1109 wxCoord *width, wxCoord *height,
1110 wxCoord *descent, wxCoord *externalLeading,
1111 wxFont *theFont) const
c801d85f 1112{
265898fd
RR
1113 wxFont fontToUse = m_font;
1114 if (theFont) fontToUse = *theFont;
7d5af6fa 1115
265898fd 1116 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
72cdf4c9
VZ
1117 if (width) (*width) = wxCoord(gdk_string_width( font, string.mbc_str() ) / m_scaleX);
1118 if (height) (*height) = wxCoord((font->ascent + font->descent) / m_scaleY);
1119 if (descent) (*descent) = wxCoord(font->descent / m_scaleY);
265898fd 1120 if (externalLeading) (*externalLeading) = 0; // ??
903f689b 1121}
c801d85f 1122
72cdf4c9 1123wxCoord wxWindowDC::GetCharWidth() const
c801d85f 1124{
265898fd 1125 GdkFont *font = m_font.GetInternalFont( m_scaleY );
58c837a4 1126 wxCHECK_MSG( font, -1, wxT("invalid font") );
7beba2fc 1127
72cdf4c9 1128 return wxCoord(gdk_string_width( font, "H" ) / m_scaleX);
903f689b 1129}
c801d85f 1130
72cdf4c9 1131wxCoord wxWindowDC::GetCharHeight() const
c801d85f 1132{
265898fd 1133 GdkFont *font = m_font.GetInternalFont( m_scaleY );
58c837a4 1134 wxCHECK_MSG( font, -1, wxT("invalid font") );
7beba2fc 1135
72cdf4c9 1136 return wxCoord((font->ascent + font->descent) / m_scaleY);
903f689b 1137}
c801d85f 1138
4bc67cc5 1139void wxWindowDC::Clear()
c801d85f 1140{
223d09f6 1141 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1142
6db90681 1143 if (!m_window) return;
7d5af6fa 1144
f234c60c
RR
1145 /* - we either are a memory dc or have a window as the
1146 owner. anything else shouldn't happen.
1147 - we don't use gdk_window_clear() as we don't set
1148 the window's background colour anymore. it is too
1149 much pain to keep the DC's and the window's back-
1150 ground colour in synch. */
7d5af6fa 1151
f234c60c 1152 if (m_owner)
265898fd 1153 {
f234c60c
RR
1154 int width,height;
1155 m_owner->GetSize( &width, &height );
1156 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
b0e0d661 1157 return;
265898fd 1158 }
f234c60c
RR
1159
1160 if (m_isMemDC)
265898fd
RR
1161 {
1162 int width,height;
1163 GetSize( &width, &height );
1164 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
b0e0d661 1165 return;
265898fd 1166 }
903f689b 1167}
c801d85f 1168
ec758a20 1169void wxWindowDC::SetFont( const wxFont &font )
c801d85f 1170{
265898fd 1171 m_font = font;
903f689b 1172}
c801d85f 1173
ec758a20 1174void wxWindowDC::SetPen( const wxPen &pen )
c801d85f 1175{
223d09f6 1176 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1177
265898fd 1178 if (m_pen == pen) return;
7d5af6fa 1179
265898fd 1180 m_pen = pen;
7d5af6fa 1181
265898fd 1182 if (!m_pen.Ok()) return;
7d5af6fa 1183
6db90681 1184 if (!m_window) return;
7d5af6fa 1185
265898fd 1186 gint width = m_pen.GetWidth();
265898fd
RR
1187 if (width <= 0)
1188 {
112c5086 1189 // CMB: if width is non-zero scale it with the dc
265898fd
RR
1190 width = 1;
1191 }
1192 else
1193 {
1194 // X doesn't allow different width in x and y and so we take
1195 // the average
503f414e
VZ
1196 double w = 0.5 +
1197 ( fabs((double) XLOG2DEVREL(width)) +
1198 fabs((double) YLOG2DEVREL(width)) ) / 2.0;
265898fd
RR
1199 width = (int)w;
1200 }
7d5af6fa
VZ
1201
1202 static const char dotted[] = {1, 1};
1203 static const char short_dashed[] = {2, 2};
72cdf4c9 1204 static const char wxCoord_dashed[] = {2, 4};
7d5af6fa
VZ
1205 static const char dotted_dashed[] = {3, 3, 1, 3};
1206
112c5086
RR
1207 // We express dash pattern in pen width unit, so we are
1208 // independent of zoom factor and so on...
1209 int req_nb_dash;
1210 const char *req_dash;
7d5af6fa 1211
265898fd
RR
1212 GdkLineStyle lineStyle = GDK_LINE_SOLID;
1213 switch (m_pen.GetStyle())
1214 {
112c5086 1215 case wxUSER_DASH:
7d5af6fa
VZ
1216 {
1217 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1218 req_nb_dash = m_pen.GetDashCount();
1219 req_dash = m_pen.GetDash();
1220 break;
7d5af6fa
VZ
1221 }
1222 case wxDOT:
1223 {
1224 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1225 req_nb_dash = 2;
1226 req_dash = dotted;
7d5af6fa
VZ
1227 break;
1228 }
1229 case wxLONG_DASH:
1230 {
1231 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086 1232 req_nb_dash = 2;
72cdf4c9 1233 req_dash = wxCoord_dashed;
7d5af6fa
VZ
1234 break;
1235 }
1236 case wxSHORT_DASH:
1237 {
1238 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1239 req_nb_dash = 2;
1240 req_dash = short_dashed;
7d5af6fa
VZ
1241 break;
1242 }
1243 case wxDOT_DASH:
1244 {
1245// lineStyle = GDK_LINE_DOUBLE_DASH;
1246 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1247 req_nb_dash = 4;
1248 req_dash = dotted_dashed;
7d5af6fa
VZ
1249 break;
1250 }
1251
1252 case wxTRANSPARENT:
72174350 1253 case wxSTIPPLE_MASK_OPAQUE:
7d5af6fa
VZ
1254 case wxSTIPPLE:
1255 case wxSOLID:
1256 default:
1257 {
1258 lineStyle = GDK_LINE_SOLID;
112c5086
RR
1259 req_dash = (wxDash*)NULL;
1260 req_nb_dash = 0;
7d5af6fa
VZ
1261 break;
1262 }
265898fd 1263 }
7d5af6fa 1264
953704c1 1265#if (GTK_MINOR_VERSION > 0)
112c5086
RR
1266 if (req_dash && req_nb_dash)
1267 {
1268 char *real_req_dash = new char[req_nb_dash];
1269 if (real_req_dash)
1270 {
1271 for (int i = 0; i < req_nb_dash; i++)
1272 real_req_dash[i] = req_dash[i] * width;
7d5af6fa 1273 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
112c5086
RR
1274 delete[] real_req_dash;
1275 }
1276 else
1277 {
1278 // No Memory. We use non-scaled dash pattern...
7d5af6fa 1279 gdk_gc_set_dashes( m_penGC, 0, (char*)req_dash, req_nb_dash );
112c5086
RR
1280 }
1281 }
953704c1 1282#endif
7d5af6fa 1283
265898fd
RR
1284 GdkCapStyle capStyle = GDK_CAP_ROUND;
1285 switch (m_pen.GetCap())
1286 {
265898fd
RR
1287 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
1288 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
d4aa3a4b
RR
1289 case wxCAP_ROUND:
1290 default:
72174350 1291 {
d4aa3a4b
RR
1292 if (width <= 1)
1293 {
1294 width = 0;
1295 capStyle = GDK_CAP_NOT_LAST;
1296 }
1297 else
1298 {
1299 capStyle = GDK_CAP_ROUND;
1300 }
72174350 1301 break;
d4aa3a4b 1302 }
265898fd 1303 }
7d5af6fa 1304
265898fd
RR
1305 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
1306 switch (m_pen.GetJoin())
1307 {
1308 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
265898fd 1309 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
d4aa3a4b
RR
1310 case wxJOIN_ROUND:
1311 default: { joinStyle = GDK_JOIN_ROUND; break; }
265898fd 1312 }
7d5af6fa 1313
265898fd 1314 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
7d5af6fa 1315
265898fd
RR
1316 m_pen.GetColour().CalcPixel( m_cmap );
1317 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
903f689b 1318}
c801d85f 1319
ec758a20 1320void wxWindowDC::SetBrush( const wxBrush &brush )
c801d85f 1321{
223d09f6 1322 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1323
265898fd 1324 if (m_brush == brush) return;
7d5af6fa 1325
265898fd 1326 m_brush = brush;
7d5af6fa 1327
265898fd 1328 if (!m_brush.Ok()) return;
7d5af6fa 1329
6db90681 1330 if (!m_window) return;
7d5af6fa 1331
265898fd
RR
1332 m_brush.GetColour().CalcPixel( m_cmap );
1333 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
7d5af6fa 1334
956dbab1 1335 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
7d5af6fa 1336
4fcd73bd 1337 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
265898fd 1338 {
4fcd73bd 1339 if (m_brush.GetStipple()->GetPixmap())
7d5af6fa 1340 {
956dbab1 1341 gdk_gc_set_fill( m_brushGC, GDK_TILED );
cd25b18c 1342 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
7d5af6fa 1343 }
b0e0d661 1344 else
7d5af6fa 1345 {
956dbab1 1346 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
4fcd73bd 1347 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
7d5af6fa 1348 }
265898fd 1349 }
7d5af6fa 1350
de2d2cdc
VZ
1351 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
1352 {
1353 gdk_gc_set_fill( m_textGC, GDK_OPAQUE_STIPPLED);
1354 gdk_gc_set_stipple( m_textGC, m_brush.GetStipple()->GetMask()->GetBitmap() );
1355 }
1356
265898fd
RR
1357 if (IS_HATCH(m_brush.GetStyle()))
1358 {
956dbab1 1359 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
265898fd
RR
1360 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
1361 gdk_gc_set_stipple( m_brushGC, hatches[num] );
1362 }
903f689b 1363}
c801d85f 1364
ec758a20 1365void wxWindowDC::SetBackground( const wxBrush &brush )
46dc76ba 1366{
bbbbe360
RR
1367 /* CMB 21/7/98: Added SetBackground. Sets background brush
1368 * for Clear() and bg colour for shapes filled with cross-hatch brush */
7d5af6fa 1369
223d09f6 1370 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1371
265898fd 1372 if (m_backgroundBrush == brush) return;
7d5af6fa 1373
265898fd 1374 m_backgroundBrush = brush;
7d5af6fa 1375
265898fd 1376 if (!m_backgroundBrush.Ok()) return;
7d5af6fa 1377
6db90681 1378 if (!m_window) return;
7d5af6fa 1379
265898fd
RR
1380 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
1381 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
a802c3a1 1382 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
031b2a7b 1383 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
265898fd 1384 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
3417c2cd
RR
1385
1386 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
7d5af6fa 1387
cd25b18c 1388 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
265898fd 1389 {
fd128b0c 1390 if (m_backgroundBrush.GetStipple()->GetPixmap())
7d5af6fa 1391 {
3417c2cd 1392 gdk_gc_set_fill( m_bgGC, GDK_TILED );
fd128b0c 1393 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
7d5af6fa 1394 }
cd25b18c 1395 else
7d5af6fa 1396 {
3417c2cd 1397 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
fd128b0c 1398 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() );
7d5af6fa 1399 }
265898fd 1400 }
7d5af6fa 1401
265898fd
RR
1402 if (IS_HATCH(m_backgroundBrush.GetStyle()))
1403 {
3417c2cd 1404 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
265898fd
RR
1405 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
1406 gdk_gc_set_stipple( m_bgGC, hatches[num] );
bbbbe360 1407 }
903f689b 1408}
46dc76ba 1409
ec758a20 1410void wxWindowDC::SetLogicalFunction( int function )
c801d85f 1411{
223d09f6 1412 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1413
72174350
VZ
1414 if (m_logicalFunction == function)
1415 return;
1416
1417 // VZ: shouldn't this be a CHECK?
1418 if (!m_window)
1419 return;
01eaf507 1420
265898fd
RR
1421 GdkFunction mode = GDK_COPY;
1422 switch (function)
1423 {
3c679789
RR
1424 case wxXOR: mode = GDK_XOR; break;
1425 case wxINVERT: mode = GDK_INVERT; break;
01eaf507 1426#if (GTK_MINOR_VERSION > 0)
3c679789
RR
1427 case wxOR_REVERSE: mode = GDK_OR_REVERSE; break;
1428 case wxAND_REVERSE: mode = GDK_AND_REVERSE; break;
1429 case wxCLEAR: mode = GDK_CLEAR; break;
1430 case wxSET: mode = GDK_SET; break;
1431 case wxOR_INVERT: mode = GDK_OR_INVERT; break;
1432 case wxAND: mode = GDK_AND; break;
1433 case wxOR: mode = GDK_OR; break;
1434 case wxEQUIV: mode = GDK_EQUIV; break;
1435 case wxNAND: mode = GDK_NAND; break;
1436 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
7d5af6fa
VZ
1437 case wxCOPY: mode = GDK_COPY; break;
1438 case wxNO_OP: mode = GDK_NOOP; break;
1439 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
72174350 1440
2d52841d
RR
1441 // unsupported by GTK
1442 case wxNOR: mode = GDK_COPY; break;
c96faa7c 1443#endif
01eaf507 1444 default:
7d5af6fa 1445 {
223d09f6 1446 wxFAIL_MSG( wxT("unsupported logical function") );
7d5af6fa
VZ
1447 break;
1448 }
265898fd 1449 }
7d5af6fa 1450
265898fd 1451 m_logicalFunction = function;
7d5af6fa 1452
265898fd
RR
1453 gdk_gc_set_function( m_penGC, mode );
1454 gdk_gc_set_function( m_brushGC, mode );
72174350
VZ
1455
1456 // to stay compatible with wxMSW, we don't apply ROPs to the text
3d2d8da1
RR
1457 // operations (i.e. DrawText/DrawRotatedText).
1458 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1459 gdk_gc_set_function( m_textGC, mode );
903f689b 1460}
c801d85f 1461
ec758a20 1462void wxWindowDC::SetTextForeground( const wxColour &col )
c801d85f 1463{
223d09f6 1464 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1465
265898fd 1466 if (m_textForegroundColour == col) return;
7d5af6fa 1467
265898fd
RR
1468 m_textForegroundColour = col;
1469 if (!m_textForegroundColour.Ok()) return;
7d5af6fa 1470
6db90681 1471 if (!m_window) return;
7d5af6fa 1472
265898fd
RR
1473 m_textForegroundColour.CalcPixel( m_cmap );
1474 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
903f689b 1475}
c801d85f 1476
ec758a20 1477void wxWindowDC::SetTextBackground( const wxColour &col )
c801d85f 1478{
223d09f6 1479 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1480
265898fd 1481 if (m_textBackgroundColour == col) return;
7d5af6fa 1482
265898fd
RR
1483 m_textBackgroundColour = col;
1484 if (!m_textBackgroundColour.Ok()) return;
7d5af6fa 1485
6db90681 1486 if (!m_window) return;
7d5af6fa 1487
265898fd
RR
1488 m_textBackgroundColour.CalcPixel( m_cmap );
1489 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
903f689b 1490}
c801d85f 1491
ec758a20 1492void wxWindowDC::SetBackgroundMode( int mode )
c801d85f 1493{
223d09f6 1494 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1495
265898fd 1496 m_backgroundMode = mode;
46dc76ba 1497
6db90681 1498 if (!m_window) return;
7d5af6fa 1499
265898fd
RR
1500 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1501 // transparent/solid background mode
7d5af6fa 1502
265898fd
RR
1503 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
1504 {
1505 gdk_gc_set_fill( m_brushGC,
1506 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
1507 }
903f689b 1508}
c801d85f 1509
ec758a20 1510void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
c801d85f 1511{
223d09f6 1512 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
903f689b 1513}
c801d85f 1514
72cdf4c9 1515void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 1516{
223d09f6 1517 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1518
089e55d6 1519 wxDC::DoSetClippingRegion( x, y, width, height );
7d5af6fa 1520
6db90681 1521 if (!m_window) return;
7d5af6fa 1522
3d2d8da1 1523 wxRect rect;
265898fd
RR
1524 rect.x = XLOG2DEV(x);
1525 rect.y = YLOG2DEV(y);
1526 rect.width = XLOG2DEVREL(width);
1527 rect.height = YLOG2DEVREL(height);
3d2d8da1
RR
1528
1529 m_currentClippingRegion.Clear();
1530 m_currentClippingRegion.Union( rect );
1531 if (!m_paintClippingRegion.IsEmpty())
1532 m_currentClippingRegion.Intersect( m_paintClippingRegion );
1533
1534 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1535 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
1536 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
1537 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
903f689b 1538}
c801d85f 1539
b0e0d661 1540void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
463c1fa1 1541{
223d09f6 1542 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1543
463c1fa1
RR
1544 if (region.Empty())
1545 {
1546 DestroyClippingRegion();
1547 return;
1548 }
7d5af6fa 1549
0bd62129
RL
1550 wxCoord x,y,w,h;
1551 region.GetBox( x, y, w, h );
72174350 1552
0bd62129
RL
1553 wxDC::DoSetClippingRegion( x, y, w, h );
1554
6db90681 1555 if (!m_window) return;
3d2d8da1
RR
1556
1557 m_currentClippingRegion.Clear();
1558 m_currentClippingRegion.Union( region );
1559 if (!m_paintClippingRegion.IsEmpty())
1560 m_currentClippingRegion.Intersect( m_paintClippingRegion );
1561
1562 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1563 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
1564 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
1565 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
463c1fa1
RR
1566}
1567
4bc67cc5 1568void wxWindowDC::DestroyClippingRegion()
c801d85f 1569{
223d09f6 1570 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1571
265898fd 1572 wxDC::DestroyClippingRegion();
7d5af6fa 1573
3d2d8da1
RR
1574 m_currentClippingRegion.Clear();
1575
1576 if (!m_paintClippingRegion.IsEmpty())
1577 m_currentClippingRegion.Union( m_paintClippingRegion );
1578
6db90681 1579 if (!m_window) return;
7d5af6fa 1580
3d2d8da1
RR
1581 if (m_currentClippingRegion.IsEmpty())
1582 {
1583 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
1584 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
1585 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
1586 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
1587 }
1588 else
1589 {
1590 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1591 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
1592 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
1593 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
1594 }
903f689b 1595}
c801d85f 1596
4bc67cc5 1597void wxWindowDC::SetUpDC()
c801d85f 1598{
265898fd 1599 m_ok = TRUE;
3d2d8da1
RR
1600
1601 if (!m_penGC)
1602 {
0e09f76e
RR
1603 m_penGC = wxGetPoolGC( m_window, wxPEN_COLOUR );
1604 m_brushGC = wxGetPoolGC( m_window, wxBRUSH_COLOUR );
1605 m_textGC = wxGetPoolGC( m_window, wxTEXT_COLOUR );
1606 m_bgGC = wxGetPoolGC( m_window, wxBG_COLOUR );
3d2d8da1 1607 }
7d5af6fa 1608
3d2d8da1
RR
1609 /* background colour */
1610 m_backgroundBrush = *wxWHITE_BRUSH;
1611 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
1612 GdkColor *bg_col = m_backgroundBrush.GetColour().GetColor();
1613
1614 /* m_textGC */
1615 m_textForegroundColour.CalcPixel( m_cmap );
1616 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
1617
1618 m_textBackgroundColour.CalcPixel( m_cmap );
1619 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
1620
1621 gdk_gc_set_fill( m_textGC, GDK_SOLID );
3d2d8da1
RR
1622
1623 /* m_penGC */
1624 m_pen.GetColour().CalcPixel( m_cmap );
1625 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
1626 gdk_gc_set_background( m_penGC, bg_col );
1627
3d2d8da1
RR
1628 gdk_gc_set_line_attributes( m_penGC, 0, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_ROUND );
1629
1630
1631 /* m_brushGC */
1632 m_brush.GetColour().CalcPixel( m_cmap );
1633 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
1634 gdk_gc_set_background( m_brushGC, bg_col );
1635
1636 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
3d2d8da1
RR
1637
1638
1639 /* m_bgGC */
1640 gdk_gc_set_background( m_bgGC, bg_col );
1641 gdk_gc_set_foreground( m_bgGC, bg_col );
1642
1643 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
3d2d8da1
RR
1644
1645 /* ROPs */
1646 gdk_gc_set_function( m_textGC, GDK_COPY );
1647 gdk_gc_set_function( m_brushGC, GDK_COPY );
1648 gdk_gc_set_function( m_penGC, GDK_COPY );
3d2d8da1
RR
1649
1650 /* clipping */
1651 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
1652 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
1653 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
1654 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
7d5af6fa
VZ
1655
1656 if (!hatch_bitmap)
265898fd
RR
1657 {
1658 hatch_bitmap = hatches;
1659 hatch_bitmap[0] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, bdiag_bits, bdiag_width, bdiag_height );
1660 hatch_bitmap[1] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cdiag_bits, cdiag_width, cdiag_height );
1661 hatch_bitmap[2] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, fdiag_bits, fdiag_width, fdiag_height );
1662 hatch_bitmap[3] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cross_bits, cross_width, cross_height );
1663 hatch_bitmap[4] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, horiz_bits, horiz_width, horiz_height );
1664 hatch_bitmap[5] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, verti_bits, verti_width, verti_height );
1665 }
903f689b 1666}
c801d85f 1667
4bc67cc5 1668void wxWindowDC::Destroy()
dbf858b5 1669{
3d2d8da1 1670 if (m_penGC) wxFreePoolGC( m_penGC );
265898fd 1671 m_penGC = (GdkGC*) NULL;
3d2d8da1 1672 if (m_brushGC) wxFreePoolGC( m_brushGC );
265898fd 1673 m_brushGC = (GdkGC*) NULL;
3d2d8da1 1674 if (m_textGC) wxFreePoolGC( m_textGC );
265898fd 1675 m_textGC = (GdkGC*) NULL;
3d2d8da1 1676 if (m_bgGC) wxFreePoolGC( m_bgGC );
265898fd 1677 m_bgGC = (GdkGC*) NULL;
dbf858b5
RR
1678}
1679
238d735d
RR
1680void wxWindowDC::ComputeScaleAndOrigin()
1681{
1682 /* CMB: copy scale to see if it changes */
1683 double origScaleX = m_scaleX;
1684 double origScaleY = m_scaleY;
1685
1686 wxDC::ComputeScaleAndOrigin();
1687
1688 /* CMB: if scale has changed call SetPen to recalulate the line width */
1689 if ((m_scaleX != origScaleX || m_scaleY != origScaleY) &&
1690 (m_pen.Ok()))
1691 {
1692 /* this is a bit artificial, but we need to force wxDC to think
1693 the pen has changed */
1694 wxPen pen = m_pen;
1695 m_pen = wxNullPen;
1696 SetPen( pen );
1697 }
1698}
1699
b0e0d661
VZ
1700// Resolution in pixels per logical inch
1701wxSize wxWindowDC::GetPPI() const
1702{
1703 return wxSize(100, 100);
1704}
1705
1706int wxWindowDC::GetDepth() const
c801d85f 1707{
223d09f6 1708 wxFAIL_MSG(wxT("not implemented"));
b0e0d661
VZ
1709
1710 return -1;
903f689b 1711}
c801d85f 1712
d54e4256 1713#if wxUSE_SPLINES
c801d85f
KB
1714// ----------------------------------- spline code ----------------------------------------
1715
1716void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1717 double a3, double b3, double a4, double b4);
4bc67cc5 1718void wx_clear_stack();
c801d85f
KB
1719int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1720 double *y3, double *x4, double *y4);
1721void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1722 double x4, double y4);
1723static bool wx_spline_add_point(double x, double y);
1724static void wx_spline_draw_point_array(wxDC *dc);
1725
1726wxList wx_spline_point_list;
1727
b0e0d661
VZ
1728#define half(z1, z2) ((z1+z2)/2.0)
1729#define THRESHOLD 5
c801d85f
KB
1730
1731/* iterative version */
1732
1733void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1734 double b4)
1735{
1736 register double xmid, ymid;
1737 double x1, y1, x2, y2, x3, y3, x4, y4;
1738
1739 wx_clear_stack();
1740 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1741
1742 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
1743 xmid = (double)half(x2, x3);
1744 ymid = (double)half(y2, y3);
b0e0d661
VZ
1745 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1746 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
c801d85f
KB
1747 wx_spline_add_point( x1, y1 );
1748 wx_spline_add_point( xmid, ymid );
b0e0d661 1749 } else {
c801d85f
KB
1750 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1751 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1752 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1753 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
b0e0d661 1754 }
c801d85f
KB
1755 }
1756}
1757
1758/* utilities used by spline drawing routines */
1759
1760typedef struct wx_spline_stack_struct {
1761 double x1, y1, x2, y2, x3, y3, x4, y4;
1762} Stack;
1763
1764#define SPLINE_STACK_DEPTH 20
1765static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1766static Stack *wx_stack_top;
1767static int wx_stack_count;
1768
4bc67cc5 1769void wx_clear_stack()
c801d85f
KB
1770{
1771 wx_stack_top = wx_spline_stack;
1772 wx_stack_count = 0;
1773}
1774
1775void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1776{
1777 wx_stack_top->x1 = x1;
1778 wx_stack_top->y1 = y1;
1779 wx_stack_top->x2 = x2;
1780 wx_stack_top->y2 = y2;
1781 wx_stack_top->x3 = x3;
1782 wx_stack_top->y3 = y3;
1783 wx_stack_top->x4 = x4;
1784 wx_stack_top->y4 = y4;
1785 wx_stack_top++;
1786 wx_stack_count++;
1787}
1788
1789int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1790 double *x3, double *y3, double *x4, double *y4)
1791{
1792 if (wx_stack_count == 0)
b0e0d661 1793 return (0);
c801d85f
KB
1794 wx_stack_top--;
1795 wx_stack_count--;
1796 *x1 = wx_stack_top->x1;
1797 *y1 = wx_stack_top->y1;
1798 *x2 = wx_stack_top->x2;
1799 *y2 = wx_stack_top->y2;
1800 *x3 = wx_stack_top->x3;
1801 *y3 = wx_stack_top->y3;
1802 *x4 = wx_stack_top->x4;
1803 *y4 = wx_stack_top->y4;
1804 return (1);
1805}
1806
1807static bool wx_spline_add_point(double x, double y)
1808{
1809 wxPoint *point = new wxPoint ;
1810 point->x = (int) x;
1811 point->y = (int) y;
1812 wx_spline_point_list.Append((wxObject*)point);
1813 return TRUE;
1814}
1815
1816static void wx_spline_draw_point_array(wxDC *dc)
1817{
1818 dc->DrawLines(&wx_spline_point_list, 0, 0 );
1819 wxNode *node = wx_spline_point_list.First();
1820 while (node)
1821 {
1822 wxPoint *point = (wxPoint *)node->Data();
1823 delete point;
1824 delete node;
1825 node = wx_spline_point_list.First();
1826 }
1827}
1828
b0e0d661 1829void wxWindowDC::DoDrawSpline( wxList *points )
c801d85f 1830{
223d09f6 1831 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1832
c801d85f
KB
1833 wxPoint *p;
1834 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1835 double x1, y1, x2, y2;
1836
1837 wxNode *node = points->First();
1838 p = (wxPoint *)node->Data();
1839
1840 x1 = p->x;
1841 y1 = p->y;
1842
1843 node = node->Next();
1844 p = (wxPoint *)node->Data();
1845
1846 x2 = p->x;
1847 y2 = p->y;
1848 cx1 = (double)((x1 + x2) / 2);
1849 cy1 = (double)((y1 + y2) / 2);
1850 cx2 = (double)((cx1 + x2) / 2);
1851 cy2 = (double)((cy1 + y2) / 2);
1852
1853 wx_spline_add_point(x1, y1);
1854
1855 while ((node = node->Next()) != NULL)
1856 {
1857 p = (wxPoint *)node->Data();
b0e0d661
VZ
1858 x1 = x2;
1859 y1 = y2;
1860 x2 = p->x;
1861 y2 = p->y;
c801d85f
KB
1862 cx4 = (double)(x1 + x2) / 2;
1863 cy4 = (double)(y1 + y2) / 2;
1864 cx3 = (double)(x1 + cx4) / 2;
1865 cy3 = (double)(y1 + cy4) / 2;
1866
1867 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1868
b0e0d661
VZ
1869 cx1 = cx4;
1870 cy1 = cy4;
c801d85f
KB
1871 cx2 = (double)(cx1 + x2) / 2;
1872 cy2 = (double)(cy1 + y2) / 2;
1873 }
1874
1875 wx_spline_add_point( cx1, cy1 );
1876 wx_spline_add_point( x2, y2 );
1877
1878 wx_spline_draw_point_array( this );
903f689b 1879}
ec758a20 1880
b0e0d661 1881#endif // wxUSE_SPLINE
ec758a20
RR
1882
1883//-----------------------------------------------------------------------------
1884// wxPaintDC
1885//-----------------------------------------------------------------------------
1886
1887IMPLEMENT_DYNAMIC_CLASS(wxPaintDC,wxWindowDC)
1888
4bc67cc5 1889wxPaintDC::wxPaintDC()
ec758a20
RR
1890 : wxWindowDC()
1891{
1892}
1893
1894wxPaintDC::wxPaintDC( wxWindow *win )
1895 : wxWindowDC( win )
1896{
3d2d8da1
RR
1897 if (!win->GetUpdateRegion().IsEmpty())
1898 {
1899 m_paintClippingRegion = win->GetUpdateRegion();
1900 m_currentClippingRegion.Union( m_paintClippingRegion );
1901
1902 gdk_gc_set_clip_region( m_penGC, m_paintClippingRegion.GetRegion() );
1903 gdk_gc_set_clip_region( m_brushGC, m_paintClippingRegion.GetRegion() );
1904 gdk_gc_set_clip_region( m_textGC, m_paintClippingRegion.GetRegion() );
1905 gdk_gc_set_clip_region( m_bgGC, m_paintClippingRegion.GetRegion() );
1906 }
ec758a20
RR
1907}
1908
1909//-----------------------------------------------------------------------------
1910// wxClientDC
1911//-----------------------------------------------------------------------------
1912
1913IMPLEMENT_DYNAMIC_CLASS(wxClientDC,wxWindowDC)
1914
4bc67cc5 1915wxClientDC::wxClientDC()
ec758a20
RR
1916 : wxWindowDC()
1917{
1918}
1919
1920wxClientDC::wxClientDC( wxWindow *win )
1921 : wxWindowDC( win )
1922{
1923}
1924
3d2d8da1
RR
1925// ----------------------------------------------------------------------------
1926// wxDCModule
1927// ----------------------------------------------------------------------------
1928
1929class wxDCModule : public wxModule
1930{
1931public:
1932 bool OnInit();
1933 void OnExit();
1934
1935private:
1936 DECLARE_DYNAMIC_CLASS(wxDCModule)
1937};
1938
1939IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
1940
1941bool wxDCModule::OnInit()
1942{
1943 wxInitGCPool();
1944 return TRUE;
1945}
1946
1947void wxDCModule::OnExit()
1948{
1949 wxCleanUpGCPool();
1950}