More Motif stuff
[wxWidgets.git] / src / motif / dcclient.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dcclient.cpp
3 // Purpose: wxClientDC class
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "dcclient.h"
14 #endif
15
16 #include "wx/dcclient.h"
17 #include "wx/dcmemory.h"
18 #include "wx/window.h"
19 #include <math.h>
20
21 #include <Xm/Xm.h>
22
23 #include "wx/motif/private.h"
24
25 //-----------------------------------------------------------------------------
26 // constants
27 //-----------------------------------------------------------------------------
28
29 #define RAD2DEG 57.2957795131
30
31 //-----------------------------------------------------------------------------
32 // wxWindowDC
33 //-----------------------------------------------------------------------------
34
35 #if !USE_SHARED_LIBRARY
36 //IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxDC)
37 //IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
38 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
39 #endif
40
41
42 wxWindowDC::wxWindowDC(void)
43 {
44 m_gc = (WXGC) 0;
45 m_gcBacking = (WXGC) 0;
46 m_window = NULL;
47 m_backgroundPixel = -1;
48 m_currentPenWidth = 1;
49 m_currentPenJoin = -1;
50 m_currentPenDashCount = -1;
51 m_currentPenDash = (char*) NULL;
52 m_currentStyle = -1;
53 m_currentFill = -1;
54 m_currentBkMode = wxTRANSPARENT;
55 m_colour = wxColourDisplay();
56 m_display = (WXDisplay*) NULL;
57 m_clippingRegion = (WXRegion) 0;
58 };
59
60 wxWindowDC::wxWindowDC( wxWindow *window )
61 {
62 m_window = window;
63 m_gc = (WXGC) 0;
64 m_gcBacking = (WXGC) 0;
65 m_window = NULL;
66 m_backgroundPixel = -1;
67 m_currentPenWidth = 1;
68 m_currentPenJoin = -1;
69 m_currentPenDashCount = -1;
70 m_currentPenDash = (char*) NULL;
71 m_currentStyle = -1;
72 m_currentFill = -1;
73 m_currentBkMode = wxTRANSPARENT;
74 m_colour = wxColourDisplay();
75 m_display = window->GetXDisplay();
76 m_clippingRegion = (WXRegion) 0;
77 m_ok = TRUE;
78 };
79
80 wxWindowDC::~wxWindowDC(void)
81 {
82 if (m_gc)
83 XFreeGC ((Display*) m_display, (GC) m_gc);
84 m_gc = (WXGC) 0;
85
86 if (m_gcBacking)
87 XFreeGC ((Display*) m_display, (GC) m_gcBacking);
88 m_gcBacking = (WXGC) 0;
89
90 if (m_clippingRegion)
91 XDestroyRegion ((Region) m_clippingRegion);
92 m_clippingRegion = (WXRegion) 0;
93 };
94
95 void wxWindowDC::FloodFill( long WXUNUSED(x1), long WXUNUSED(y1),
96 wxColour* WXUNUSED(col), int WXUNUSED(style) )
97 {
98 };
99
100 bool wxWindowDC::GetPixel( long WXUNUSED(x1), long WXUNUSED(y1), wxColour *WXUNUSED(col) ) const
101 {
102 return FALSE;
103 };
104
105 void wxWindowDC::DrawLine( long x1, long y1, long x2, long y2 )
106 {
107 if (!Ok()) return;
108 #if 0
109 int x1d, y1d, x2d, y2d;
110
111 /* MATTHEW: [7] Implement GetPixel */
112 FreeGetPixelCache();
113
114 x1d = XLOG2DEV(x1);
115 y1d = YLOG2DEV(y1);
116 x2d = XLOG2DEV(x2);
117 y2d = YLOG2DEV(y2);
118
119 if (current_pen && autoSetting)
120 SetPen (current_pen);
121 XDrawLine (display, pixmap, gc, x1d, y1d, x2d, y2d);
122
123 if (canvas && canvas->is_retained)
124 XDrawLine (display, canvas->backingPixmap, gcBacking,
125 XLOG2DEV_2(x1), YLOG2DEV_2(y1),
126 XLOG2DEV_2(x2), YLOG2DEV_2(y2));
127
128 CalcBoundingBox(x1, y1);
129 CalcBoundingBox(x2, y2);
130 #endif
131 };
132
133 void wxWindowDC::CrossHair( long x, long y )
134 {
135 if (!Ok()) return;
136
137 };
138
139 void wxWindowDC::DrawArc( long x1, long y1, long x2, long y2, long xc, long yc )
140 {
141 if (!Ok()) return;
142
143 long xx1 = XLOG2DEV(x1);
144 long yy1 = YLOG2DEV(y1);
145 long xx2 = XLOG2DEV(x2);
146 long yy2 = YLOG2DEV(y2);
147 long xxc = XLOG2DEV((long)xc);
148 long yyc = YLOG2DEV((long)yc);
149 double dx = xx1 - xxc;
150 double dy = yy1 - yyc;
151 double radius = sqrt(dx*dx+dy*dy);
152 long r = (long)radius;
153 double radius1, radius2;
154
155 if (xx1 == xx2 && yy1 == yy2)
156 {
157 radius1 = 0.0;
158 radius2 = 360.0;
159 }
160 else
161 if (radius == 0.0)
162 {
163 radius1 = radius2 = 0.0;
164 }
165 else
166 {
167 radius1 = (xx1 - xxc == 0) ?
168 (yy1 - yyc < 0) ? 90.0 : -90.0 :
169 -atan2(double(yy1-yyc), double(xx1-xxc)) * RAD2DEG;
170 radius2 = (xx2 - xxc == 0) ?
171 (yy2 - yyc < 0) ? 90.0 : -90.0 :
172 -atan2(double(yy2-yyc), double(xx2-xxc)) * RAD2DEG;
173 };
174 long alpha1 = long(radius1 * 64.0);
175 long alpha2 = long((radius2 - radius1) * 64.0);
176 while (alpha2 <= 0) alpha2 += 360*64;
177 while (alpha1 > 360*64) alpha1 -= 360*64;
178
179 if (m_brush.GetStyle() != wxTRANSPARENT) {};
180
181 if (m_pen.GetStyle() != wxTRANSPARENT) {};
182
183 };
184
185 void wxWindowDC::DrawEllipticArc( long x, long y, long width, long height, double sa, double ea )
186 {
187 if (!Ok()) return;
188
189 long xx = XLOG2DEV(x);
190 long yy = YLOG2DEV(y);
191 long ww = m_signX * XLOG2DEVREL(width);
192 long hh = m_signY * YLOG2DEVREL(height);
193
194 // CMB: handle -ve width and/or height
195 if (ww < 0) { ww = -ww; xx = xx - ww; }
196 if (hh < 0) { hh = -hh; yy = yy - hh; }
197
198 long start = long(sa * 64.0);
199 long end = long(ea * 64.0);
200 if (m_brush.GetStyle() != wxTRANSPARENT) {};
201
202 if (m_pen.GetStyle() != wxTRANSPARENT) {};
203 };
204
205 void wxWindowDC::DrawPoint( long x, long y )
206 {
207 if (!Ok()) return;
208
209 if (m_pen.GetStyle() != wxTRANSPARENT) {};
210 };
211
212 void wxWindowDC::DrawLines( int n, wxPoint points[], long xoffset, long yoffset )
213 {
214 if (!Ok()) return;
215
216 if (m_pen.GetStyle() == wxTRANSPARENT) return;
217
218 for (int i = 0; i < n-1; i++)
219 {
220 long x1 = XLOG2DEV(points[i].x + xoffset);
221 long x2 = XLOG2DEV(points[i+1].x + xoffset);
222 long y1 = YLOG2DEV(points[i].y + yoffset); // oh, what a waste
223 long y2 = YLOG2DEV(points[i+1].y + yoffset);
224 };
225 };
226
227 void wxWindowDC::DrawLines( wxList *points, long xoffset, long yoffset )
228 {
229 if (!Ok()) return;
230
231 if (m_pen.GetStyle() == wxTRANSPARENT) return;
232
233 wxNode *node = points->First();
234 while (node->Next())
235 {
236 wxPoint *point = (wxPoint*)node->Data();
237 wxPoint *npoint = (wxPoint*)node->Next()->Data();
238 long x1 = XLOG2DEV(point->x + xoffset);
239 long x2 = XLOG2DEV(npoint->x + xoffset);
240 long y1 = YLOG2DEV(point->y + yoffset); // and again...
241 long y2 = YLOG2DEV(npoint->y + yoffset);
242 node = node->Next();
243 };
244 };
245
246 void wxWindowDC::DrawPolygon( int WXUNUSED(n), wxPoint WXUNUSED(points)[],
247 long WXUNUSED(xoffset), long WXUNUSED(yoffset), int WXUNUSED(fillStyle) )
248 {
249 if (!Ok()) return;
250 };
251
252 void wxWindowDC::DrawPolygon( wxList *WXUNUSED(lines), long WXUNUSED(xoffset),
253 long WXUNUSED(yoffset), int WXUNUSED(fillStyle) )
254 {
255 if (!Ok()) return;
256 };
257
258 void wxWindowDC::DrawRectangle( long x, long y, long width, long height )
259 {
260 if (!Ok()) return;
261
262 long xx = XLOG2DEV(x);
263 long yy = YLOG2DEV(y);
264 long ww = m_signX * XLOG2DEVREL(width);
265 long hh = m_signY * YLOG2DEVREL(height);
266
267 // CMB: draw nothing if transformed w or h is 0
268 if (ww == 0 || hh == 0) return;
269
270 // CMB: handle -ve width and/or height
271 if (ww < 0) { ww = -ww; xx = xx - ww; }
272 if (hh < 0) { hh = -hh; yy = yy - hh; }
273
274 if (m_brush.GetStyle() != wxTRANSPARENT) {};
275
276 if (m_pen.GetStyle() != wxTRANSPARENT) {};
277 };
278
279 void wxWindowDC::DrawRoundedRectangle( long x, long y, long width, long height, double radius )
280 {
281 if (!Ok()) return;
282
283 if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
284
285 long xx = XLOG2DEV(x);
286 long yy = YLOG2DEV(y);
287 long ww = m_signX * XLOG2DEVREL(width);
288 long hh = m_signY * YLOG2DEVREL(height);
289 long rr = XLOG2DEVREL((long)radius);
290
291 // CMB: handle -ve width and/or height
292 if (ww < 0) { ww = -ww; xx = xx - ww; }
293 if (hh < 0) { hh = -hh; yy = yy - hh; }
294
295 // CMB: if radius is zero use DrawRectangle() instead to avoid
296 // X drawing errors with small radii
297 if (rr == 0)
298 {
299 DrawRectangle( x, y, width, height );
300 return;
301 }
302
303 // CMB: draw nothing if transformed w or h is 0
304 if (ww == 0 || hh == 0) return;
305
306 // CMB: adjust size if outline is drawn otherwise the result is
307 // 1 pixel too wide and high
308 if (m_pen.GetStyle() != wxTRANSPARENT)
309 {
310 ww--;
311 hh--;
312 }
313
314 // CMB: ensure dd is not larger than rectangle otherwise we
315 // get an hour glass shape
316 long dd = 2 * rr;
317 if (dd > ww) dd = ww;
318 if (dd > hh) dd = hh;
319 rr = dd / 2;
320
321 if (m_brush.GetStyle() != wxTRANSPARENT)
322 {
323 };
324
325 if (m_pen.GetStyle() != wxTRANSPARENT)
326 {
327 };
328 };
329
330 void wxWindowDC::DrawEllipse( long x, long y, long width, long height )
331 {
332 if (!Ok()) return;
333
334 long xx = XLOG2DEV(x);
335 long yy = YLOG2DEV(y);
336 long ww = m_signX * XLOG2DEVREL(width);
337 long hh = m_signY * YLOG2DEVREL(height);
338
339 // CMB: handle -ve width and/or height
340 if (ww < 0) { ww = -ww; xx = xx - ww; }
341 if (hh < 0) { hh = -hh; yy = yy - hh; }
342
343 if (m_brush.GetStyle() != wxTRANSPARENT) {};
344
345 if (m_pen.GetStyle() != wxTRANSPARENT) {};
346 };
347
348 bool wxWindowDC::CanDrawBitmap(void) const
349 {
350 return TRUE;
351 };
352
353 void wxWindowDC::DrawIcon( const wxIcon &icon, long x, long y, bool useMask )
354 {
355 if (!Ok()) return;
356
357 if (!icon.Ok()) return;
358
359 int xx = XLOG2DEV(x);
360 int yy = YLOG2DEV(y);
361
362 };
363
364 bool wxWindowDC::Blit( long xdest, long ydest, long width, long height,
365 wxDC *source, long xsrc, long ysrc, int WXUNUSED(logical_func), bool WXUNUSED(useMask) )
366 {
367 if (!Ok()) return FALSE;
368
369 // CMB 20/5/98: add blitting of bitmaps
370 if (source->IsKindOf(CLASSINFO(wxMemoryDC)))
371 {
372 wxMemoryDC* srcDC = (wxMemoryDC*)source;
373 /*
374 GdkBitmap* bmap = srcDC->m_selected.GetBitmap();
375 if (bmap)
376 {
377 gdk_draw_bitmap (
378 m_window,
379 m_textGC,
380 bmap,
381 source->DeviceToLogicalX(xsrc), source->DeviceToLogicalY(ysrc),
382 XLOG2DEV(xdest), YLOG2DEV(ydest),
383 source->DeviceToLogicalXRel(width), source->DeviceToLogicalYRel(height)
384 );
385 return TRUE;
386 }
387 */
388 }
389
390 return TRUE;
391 };
392
393 void wxWindowDC::DrawText( const wxString &text, long x, long y, bool
394 WXUNUSED(use16) )
395 {
396 if (!Ok()) return;
397
398 };
399
400
401
402 bool wxWindowDC::CanGetTextExtent(void) const
403 {
404 return TRUE;
405 };
406
407 void wxWindowDC::GetTextExtent( const wxString &string, long *width, long *height,
408 long *WXUNUSED(descent), long *WXUNUSED(externalLeading),
409 wxFont *WXUNUSED(theFont), bool WXUNUSED(use16) )
410 {
411 if (!Ok()) return;
412
413 };
414
415 long wxWindowDC::GetCharWidth(void)
416 {
417 if (!Ok()) return 0;
418 return 0;
419 };
420
421 long wxWindowDC::GetCharHeight(void)
422 {
423 if (!Ok()) return 0;
424 return 0;
425 };
426
427 void wxWindowDC::Clear(void)
428 {
429 if (!Ok()) return;
430
431 };
432
433 void wxWindowDC::SetFont( const wxFont &font )
434 {
435 if (!Ok()) return;
436
437 m_font = font;
438 };
439
440 void wxWindowDC::SetPen( const wxPen &pen )
441 {
442 if (!Ok()) return;
443
444 if (m_pen == pen) return;
445
446 m_pen = pen;
447
448 if (!m_pen.Ok()) return;
449 };
450
451 void wxWindowDC::SetBrush( const wxBrush &brush )
452 {
453 if (!Ok()) return;
454
455 if (m_brush == brush) return;
456
457 m_brush = brush;
458
459 if (!m_brush.Ok()) return;
460
461 };
462
463 void wxWindowDC::SetBackground( const wxBrush &brush )
464 {
465 if (!Ok()) return;
466
467 if (m_backgroundBrush == brush) return;
468
469 m_backgroundBrush = brush;
470
471 if (!m_backgroundBrush.Ok()) return;
472
473 };
474
475 void wxWindowDC::SetLogicalFunction( int function )
476 {
477 if (m_logicalFunction == function) return;
478 };
479
480 void wxWindowDC::SetTextForeground( const wxColour &col )
481 {
482 if (!Ok()) return;
483
484 if (m_textForegroundColour == col) return;
485
486 m_textForegroundColour = col;
487 if (!m_textForegroundColour.Ok()) return;
488 };
489
490 void wxWindowDC::SetTextBackground( const wxColour &col )
491 {
492 if (!Ok()) return;
493
494 if (m_textBackgroundColour == col) return;
495
496 m_textBackgroundColour = col;
497 if (!m_textBackgroundColour.Ok()) return;
498 };
499
500 void wxWindowDC::SetBackgroundMode( int mode )
501 {
502 m_backgroundMode = mode;
503
504 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
505 {
506 }
507 };
508
509 void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
510 {
511 };
512
513 void wxWindowDC::SetClippingRegion( long x, long y, long width, long height )
514 {
515 wxDC::SetClippingRegion( x, y, width, height );
516
517 };
518
519 void wxWindowDC::DestroyClippingRegion(void)
520 {
521 wxDC::DestroyClippingRegion();
522
523 };
524
525 // ----------------------------------- spline code ----------------------------------------
526
527 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
528 double a3, double b3, double a4, double b4);
529 void wx_clear_stack(void);
530 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
531 double *y3, double *x4, double *y4);
532 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
533 double x4, double y4);
534 static bool wx_spline_add_point(double x, double y);
535 static void wx_spline_draw_point_array(wxDC *dc);
536
537 wxList wx_spline_point_list;
538
539 #define half(z1, z2) ((z1+z2)/2.0)
540 #define THRESHOLD 5
541
542 /* iterative version */
543
544 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
545 double b4)
546 {
547 register double xmid, ymid;
548 double x1, y1, x2, y2, x3, y3, x4, y4;
549
550 wx_clear_stack();
551 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
552
553 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
554 xmid = (double)half(x2, x3);
555 ymid = (double)half(y2, y3);
556 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
557 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
558 wx_spline_add_point( x1, y1 );
559 wx_spline_add_point( xmid, ymid );
560 } else {
561 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
562 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
563 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
564 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
565 }
566 }
567 }
568
569 /* utilities used by spline drawing routines */
570
571 typedef struct wx_spline_stack_struct {
572 double x1, y1, x2, y2, x3, y3, x4, y4;
573 } Stack;
574
575 #define SPLINE_STACK_DEPTH 20
576 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
577 static Stack *wx_stack_top;
578 static int wx_stack_count;
579
580 void wx_clear_stack(void)
581 {
582 wx_stack_top = wx_spline_stack;
583 wx_stack_count = 0;
584 }
585
586 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
587 {
588 wx_stack_top->x1 = x1;
589 wx_stack_top->y1 = y1;
590 wx_stack_top->x2 = x2;
591 wx_stack_top->y2 = y2;
592 wx_stack_top->x3 = x3;
593 wx_stack_top->y3 = y3;
594 wx_stack_top->x4 = x4;
595 wx_stack_top->y4 = y4;
596 wx_stack_top++;
597 wx_stack_count++;
598 }
599
600 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
601 double *x3, double *y3, double *x4, double *y4)
602 {
603 if (wx_stack_count == 0)
604 return (0);
605 wx_stack_top--;
606 wx_stack_count--;
607 *x1 = wx_stack_top->x1;
608 *y1 = wx_stack_top->y1;
609 *x2 = wx_stack_top->x2;
610 *y2 = wx_stack_top->y2;
611 *x3 = wx_stack_top->x3;
612 *y3 = wx_stack_top->y3;
613 *x4 = wx_stack_top->x4;
614 *y4 = wx_stack_top->y4;
615 return (1);
616 }
617
618 static bool wx_spline_add_point(double x, double y)
619 {
620 wxPoint *point = new wxPoint ;
621 point->x = (int) x;
622 point->y = (int) y;
623 wx_spline_point_list.Append((wxObject*)point);
624 return TRUE;
625 }
626
627 static void wx_spline_draw_point_array(wxDC *dc)
628 {
629 dc->DrawLines(&wx_spline_point_list, 0, 0 );
630 wxNode *node = wx_spline_point_list.First();
631 while (node)
632 {
633 wxPoint *point = (wxPoint *)node->Data();
634 delete point;
635 delete node;
636 node = wx_spline_point_list.First();
637 }
638 }
639
640 void wxWindowDC::DrawOpenSpline( wxList *points )
641 {
642 wxPoint *p;
643 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
644 double x1, y1, x2, y2;
645
646 wxNode *node = points->First();
647 p = (wxPoint *)node->Data();
648
649 x1 = p->x;
650 y1 = p->y;
651
652 node = node->Next();
653 p = (wxPoint *)node->Data();
654
655 x2 = p->x;
656 y2 = p->y;
657 cx1 = (double)((x1 + x2) / 2);
658 cy1 = (double)((y1 + y2) / 2);
659 cx2 = (double)((cx1 + x2) / 2);
660 cy2 = (double)((cy1 + y2) / 2);
661
662 wx_spline_add_point(x1, y1);
663
664 while ((node = node->Next()) != NULL)
665 {
666 p = (wxPoint *)node->Data();
667 x1 = x2;
668 y1 = y2;
669 x2 = p->x;
670 y2 = p->y;
671 cx4 = (double)(x1 + x2) / 2;
672 cy4 = (double)(y1 + y2) / 2;
673 cx3 = (double)(x1 + cx4) / 2;
674 cy3 = (double)(y1 + cy4) / 2;
675
676 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
677
678 cx1 = cx4;
679 cy1 = cy4;
680 cx2 = (double)(cx1 + x2) / 2;
681 cy2 = (double)(cy1 + y2) / 2;
682 }
683
684 wx_spline_add_point( cx1, cy1 );
685 wx_spline_add_point( x2, y2 );
686
687 wx_spline_draw_point_array( this );
688 };