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