]> git.saurik.com Git - wxWidgets.git/blob - src/mgl/dc.cpp
wxPopupWindow for wxMGL
[wxWidgets.git] / src / mgl / dc.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dc.cpp
3 // Purpose: wxDC class
4 // Author: Vaclav Slavik
5 // Created: 2001/03/09
6 // RCS-ID: $Id$
7 // Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ===========================================================================
12 // declarations
13 // ===========================================================================
14
15 // ---------------------------------------------------------------------------
16 // headers
17 // ---------------------------------------------------------------------------
18
19 #ifdef __GNUG__
20 #pragma implementation "dc.h"
21 #endif
22
23 // For compilers that support precompilation, includes "wx.h".
24 #include "wx/wxprec.h"
25
26 #ifdef __BORLANDC__
27 #pragma hdrstop
28 #endif
29
30 #ifndef WX_PRECOMP
31 #include "wx/dc.h"
32 #include "wx/dcmemory.h"
33 #endif
34
35 #include "wx/fontutil.h"
36 #include "wx/fontmap.h"
37 #include "wx/mgl/private.h"
38 #include "wx/log.h"
39
40 #include <string.h>
41 #include <math.h>
42 #include <mgraph.hpp>
43
44
45
46 //-----------------------------------------------------------------------------
47 // constants
48 //-----------------------------------------------------------------------------
49
50 const double mm2inches = 0.0393700787402;
51 const double inches2mm = 25.4;
52 const double mm2twips = 56.6929133859;
53 const double twips2mm = 0.0176388888889;
54 const double mm2pt = 2.83464566929;
55 const double pt2mm = 0.352777777778;
56 const double RAD2DEG = 180.0 / M_PI;
57
58
59 //-----------------------------------------------------------------------------
60 // pens data:
61 //-----------------------------------------------------------------------------
62
63 const ushort STIPPLE_wxDOT = 0x5555/* - - - - - - - -*/;
64 const ushort STIPPLE_wxLONG_DASH = 0xF0F0/* ---- ----*/;
65 const ushort STIPPLE_wxSHORT_DASH = 0xCCCC/*-- -- -- -- */;
66 const ushort STIPPLE_wxDOT_DASH = 0x3939/* --- - --- -*/;
67 const ushort STIPPLE_wxSOLID = 0xFFFF/*----------------*/;
68
69 #define PATTERN_ROW(b7,b6,b5,b4,b3,b2,b1,b0) \
70 ((b7 << 7) | (b6 << 6) | (b5 << 5) | (b4 << 4) | \
71 (b3 << 3) | (b2 << 2) | (b1 << 1) | b0)
72
73 static pattern_t PATTERN_wxFDIAGONAL_HATCH = {{
74 PATTERN_ROW(1,0,0,0,0,0,0,0),
75 PATTERN_ROW(0,1,0,0,0,0,0,0),
76 PATTERN_ROW(0,0,1,0,0,0,0,0),
77 PATTERN_ROW(0,0,0,1,0,0,0,0),
78 PATTERN_ROW(0,0,0,0,1,0,0,0),
79 PATTERN_ROW(0,0,0,0,0,1,0,0),
80 PATTERN_ROW(0,0,0,0,0,0,1,0),
81 PATTERN_ROW(0,0,0,0,0,0,0,1),
82 }};
83
84 static pattern_t PATTERN_wxCROSSDIAG_HATCH = {{
85 PATTERN_ROW(1,0,0,0,0,0,0,1),
86 PATTERN_ROW(0,1,0,0,0,0,1,0),
87 PATTERN_ROW(0,0,1,0,0,1,0,0),
88 PATTERN_ROW(0,0,0,1,1,0,0,0),
89 PATTERN_ROW(0,0,0,1,1,0,0,0),
90 PATTERN_ROW(0,0,1,0,0,1,0,0),
91 PATTERN_ROW(0,1,0,0,0,0,1,0),
92 PATTERN_ROW(1,0,0,0,0,0,0,1),
93 }};
94
95 static pattern_t PATTERN_wxBDIAGONAL_HATCH = {{
96 PATTERN_ROW(0,0,0,0,0,0,0,1),
97 PATTERN_ROW(0,0,0,0,0,0,1,0),
98 PATTERN_ROW(0,0,0,0,0,1,0,0),
99 PATTERN_ROW(0,0,0,0,1,0,0,0),
100 PATTERN_ROW(0,0,0,1,0,0,0,0),
101 PATTERN_ROW(0,0,1,0,0,0,0,0),
102 PATTERN_ROW(0,1,0,0,0,0,0,0),
103 PATTERN_ROW(1,0,0,0,0,0,0,0),
104 }};
105
106 static pattern_t PATTERN_wxCROSS_HATCH = {{
107 PATTERN_ROW(0,0,0,1,0,0,0,0),
108 PATTERN_ROW(0,0,0,1,0,0,0,0),
109 PATTERN_ROW(0,0,0,1,0,0,0,0),
110 PATTERN_ROW(1,1,1,1,1,1,1,1),
111 PATTERN_ROW(0,0,0,1,0,0,0,0),
112 PATTERN_ROW(0,0,0,1,0,0,0,0),
113 PATTERN_ROW(0,0,0,1,0,0,0,0),
114 PATTERN_ROW(0,0,0,1,0,0,0,0),
115 }};
116
117 static pattern_t PATTERN_wxHORIZONTAL_HATCH = {{
118 PATTERN_ROW(0,0,0,0,0,0,0,0),
119 PATTERN_ROW(0,0,0,0,0,0,0,0),
120 PATTERN_ROW(0,0,0,0,0,0,0,0),
121 PATTERN_ROW(1,1,1,1,1,1,1,1),
122 PATTERN_ROW(0,0,0,0,0,0,0,0),
123 PATTERN_ROW(0,0,0,0,0,0,0,0),
124 PATTERN_ROW(0,0,0,0,0,0,0,0),
125 PATTERN_ROW(0,0,0,0,0,0,0,0),
126 }};
127
128 static pattern_t PATTERN_wxVERTICAL_HATCH = {{
129 PATTERN_ROW(0,0,0,1,0,0,0,0),
130 PATTERN_ROW(0,0,0,1,0,0,0,0),
131 PATTERN_ROW(0,0,0,1,0,0,0,0),
132 PATTERN_ROW(0,0,0,1,0,0,0,0),
133 PATTERN_ROW(0,0,0,1,0,0,0,0),
134 PATTERN_ROW(0,0,0,1,0,0,0,0),
135 PATTERN_ROW(0,0,0,1,0,0,0,0),
136 PATTERN_ROW(0,0,0,1,0,0,0,0),
137 }};
138
139 #undef PATTERN_ROW
140
141 //-----------------------------------------------------------------------------
142 // wxDC
143 //-----------------------------------------------------------------------------
144
145 IMPLEMENT_ABSTRACT_CLASS(wxDC, wxDCBase)
146
147 // Default constructor
148 wxDC::wxDC()
149 {
150 m_isMemDC = FALSE;
151 m_MGLDC = NULL;
152 m_OwnsMGLDC = FALSE;
153 m_ok = FALSE; // must call SetMGLDevCtx() before using it
154
155 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
156 (double)wxGetDisplaySizeMM().GetWidth();
157 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
158 (double)wxGetDisplaySizeMM().GetHeight();
159
160 m_pen = *wxBLACK_PEN;
161 m_font = *wxNORMAL_FONT;
162 m_brush = *wxWHITE_BRUSH;
163 m_penOfsX = m_penOfsY = 0;
164
165 m_penSelected = m_brushSelected = FALSE;
166 m_downloadedPatterns[0] = m_downloadedPatterns[1] = FALSE;
167
168 m_mglFont = NULL;
169 }
170
171
172 wxDC::~wxDC()
173 {
174 if (m_OwnsMGLDC)
175 delete m_MGLDC;
176 }
177
178 void wxDC::SetMGLDC(MGLDevCtx *mgldc, bool OwnsMGLDC)
179 {
180 if ( m_OwnsMGLDC && m_MGLDC )
181 delete m_MGLDC;
182 m_MGLDC = mgldc;
183 m_OwnsMGLDC = OwnsMGLDC;
184 m_ok = TRUE;
185
186 if ( mgldc->getDC()->a.clipRegion )
187 {
188 MGLRegion clip;
189 mgldc->getClipRegion(clip);
190 m_globalClippingRegion = wxRegion(clip);
191 // FIXME_MGL -- reuse wxWindows::m_updateRegion ?
192 m_currentClippingRegion = m_globalClippingRegion;
193 m_clipping = TRUE;
194 }
195
196 InitializeMGLDC();
197 }
198
199 void wxDC::InitializeMGLDC()
200 {
201 if ( GetDepth() > 8 )
202 {
203 wxCurrentDCSwitcher switcher(m_MGLDC); // will go away with MGL6
204 m_MGLDC->setFontBlendMode(MGL_AA_RGBBLEND);
205 }
206 }
207
208
209 // ---------------------------------------------------------------------------
210 // clipping
211 // ---------------------------------------------------------------------------
212
213
214 #define DO_SET_CLIPPING_BOX(rg) \
215 { \
216 wxRect rect = rg.GetBox(); \
217 m_clipX1 = (wxCoord) XDEV2LOG(rect.GetLeft()); \
218 m_clipY1 = (wxCoord) YDEV2LOG(rect.GetTop()); \
219 m_clipX2 = (wxCoord) XDEV2LOG(rect.GetRight()); \
220 m_clipY2 = (wxCoord) YDEV2LOG(rect.GetBottom()); \
221 }
222
223 void wxDC::DoSetClippingRegion(wxCoord cx, wxCoord cy, wxCoord cw, wxCoord ch)
224 {
225 wxCHECK_RET( Ok(), wxT("invalid dc") );
226
227 wxRect rect(XLOG2DEV(cx), YLOG2DEV(cy), XLOG2DEVREL(cw), YLOG2DEVREL(ch));
228
229 if ( !m_currentClippingRegion.IsNull() )
230 m_currentClippingRegion.Intersect(rect);
231 else
232 m_currentClippingRegion.Union(rect);
233
234 m_MGLDC->setClipRegion(m_currentClippingRegion.GetMGLRegion());
235
236 m_clipping = TRUE;
237 DO_SET_CLIPPING_BOX(m_currentClippingRegion)
238 }
239
240 void wxDC::DoSetClippingRegionAsRegion(const wxRegion& region)
241 {
242 wxCHECK_RET( Ok(), wxT("invalid dc") );
243
244 if ( region.IsEmpty() )
245 {
246 DestroyClippingRegion();
247 return;
248 }
249
250 wxRegion rg(region);
251
252 // check if the DC is scaled or moved, and if yes, then
253 // convert rg to device coordinates:
254 if ( m_deviceOriginX != 0 || m_deviceOriginY != 0 ||
255 XLOG2DEVREL(500) != 500 || YLOG2DEVREL(500) != 500 )
256 {
257 region_t *mrg = rg.GetMGLRegion().rgnPointer();
258 span_t *s;
259 segment_t *p;
260 for (s = mrg->spans; s; s = s->next)
261 {
262 s->y = YLOG2DEV(s->y);
263 for (p = s->seg; p; p = p->next)
264 p->x = XLOG2DEV(p->x);
265 }
266 }
267
268 if ( !m_currentClippingRegion.IsNull() )
269 m_currentClippingRegion.Intersect(rg);
270 else
271 m_currentClippingRegion.Union(rg);
272
273 m_MGLDC->setClipRegion(m_currentClippingRegion.GetMGLRegion());
274
275 m_clipping = TRUE;
276 DO_SET_CLIPPING_BOX(m_currentClippingRegion)
277 }
278
279 void wxDC::DestroyClippingRegion()
280 {
281 wxCHECK_RET( Ok(), wxT("invalid dc") );
282
283 if ( !m_globalClippingRegion.IsNull() )
284 {
285 m_MGLDC->setClipRegion(m_globalClippingRegion.GetMGLRegion());
286 m_currentClippingRegion = m_globalClippingRegion;
287 m_clipping = TRUE;
288 }
289 else
290 {
291 m_MGLDC->setClipRect(MGLRect(0, 0, m_MGLDC->sizex(), m_MGLDC->sizey()));
292 m_clipping = FALSE;
293 m_currentClippingRegion.Clear();
294 }
295 }
296
297 // ---------------------------------------------------------------------------
298 // query capabilities
299 // ---------------------------------------------------------------------------
300
301 bool wxDC::CanDrawBitmap() const
302 {
303 return TRUE;
304 }
305
306 bool wxDC::CanGetTextExtent() const
307 {
308 return TRUE;
309 }
310
311 int wxDC::GetDepth() const
312 {
313 return m_MGLDC->getBitsPerPixel();
314 }
315
316 // ---------------------------------------------------------------------------
317 // drawing
318 // ---------------------------------------------------------------------------
319
320 void wxDC::Clear()
321 {
322 wxCHECK_RET( Ok(), wxT("invalid dc") );
323
324 m_MGLDC->makeCurrent(); // will go away with MGL6.0
325 if ( m_backgroundBrush.GetStyle() != wxTRANSPARENT )
326 {
327 int w, h;
328 wxBrush oldb = m_brush;
329 SetBrush(m_backgroundBrush);
330 SelectBrush();
331 GetSize(&w, &h);
332 m_MGLDC->fillRect(0, 0, w-1, h-1);
333 SetBrush(oldb);
334 }
335 }
336
337 void wxDC::DoFloodFill(wxCoord x, wxCoord y, const wxColour& col, int style)
338 {
339 wxFAIL_MSG( wxT("wxDC::DoFloodFill not implemented") );
340 }
341
342 bool wxDC::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const
343 {
344 wxCHECK_MSG( col, FALSE, _T("NULL colour parameter in wxDC::GetPixel"));
345
346 uchar r, g, b;
347 m_MGLDC->unpackColorFast(m_MGLDC->getPixel(XLOG2DEV(x), XLOG2DEV(y)),
348 r, g, b);
349 col->Set(r, g, b);
350 return TRUE;
351 }
352
353 void wxDC::DoCrossHair(wxCoord x, wxCoord y)
354 {
355 wxCHECK_RET( Ok(), wxT("invalid dc") );
356
357 if ( m_pen.GetStyle() != wxTRANSPARENT )
358 {
359 int w = 0;
360 int h = 0;
361 GetSize(&w, &h);
362 m_MGLDC->makeCurrent(); // will go away with MGL6.0
363 if ( !m_penSelected )
364 SelectPen();
365 wxCoord xx = XLOG2DEV(x);
366 wxCoord yy = YLOG2DEV(y);
367 m_MGLDC->line(m_penOfsX, yy + m_penOfsY, w-1 + m_penOfsX, yy + m_penOfsY);
368 m_MGLDC->line(xx + m_penOfsX, m_penOfsY, x + m_penOfsX, h-1 + m_penOfsY);
369 CalcBoundingBox(0, 0);
370 CalcBoundingBox(w, h);
371 }
372 }
373
374 void wxDC::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
375 {
376 wxCHECK_RET( Ok(), wxT("invalid dc") );
377
378 if ( m_pen.GetStyle() != wxTRANSPARENT )
379 {
380 m_MGLDC->makeCurrent(); // will go away with MGL6.0
381 if ( !m_penSelected )
382 SelectPen();
383 m_MGLDC->line(XLOG2DEV(x1) + m_penOfsX, XLOG2DEV(y1) + m_penOfsY,
384 XLOG2DEV(x2) + m_penOfsX, XLOG2DEV(y2) + m_penOfsY);
385 CalcBoundingBox(x1, y1);
386 CalcBoundingBox(x2, y2);
387 }
388 }
389
390 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
391 // and ending at (x2, y2)
392 void wxDC::DoDrawArc(wxCoord x1, wxCoord y1,
393 wxCoord x2, wxCoord y2,
394 wxCoord xc, wxCoord yc)
395 {
396 wxCHECK_RET( Ok(), wxT("invalid dc") );
397
398 wxCoord xx1 = XLOG2DEV(x1);
399 wxCoord yy1 = YLOG2DEV(y1);
400 wxCoord xx2 = XLOG2DEV(x2);
401 wxCoord yy2 = YLOG2DEV(y2);
402 wxCoord xxc = XLOG2DEV(xc);
403 wxCoord yyc = YLOG2DEV(yc);
404 double dx = xx1 - xxc;
405 double dy = yy1 - yyc;
406 double radius = sqrt((double)(dx*dx+dy*dy));
407 wxCoord r = (wxCoord)radius;
408 double radius1, radius2;
409
410
411 if (xx1 == xx2 && yy1 == yy2)
412 {
413 radius1 = 0.0;
414 radius2 = 360.0;
415 }
416 else if (radius == 0.0)
417 {
418 radius1 = radius2 = 0.0;
419 }
420 else
421 {
422 radius1 = (xx1 - xxc == 0) ?
423 (yy1 - yyc < 0) ? 90.0 : -90.0 :
424 -atan2(double(yy1-yyc), double(xx1-xxc)) * RAD2DEG;
425 radius2 = (xx2 - xxc == 0) ?
426 (yy2 - yyc < 0) ? 90.0 : -90.0 :
427 -atan2(double(yy2-yyc), double(xx2-xxc)) * RAD2DEG;
428 }
429 wxCoord alpha1 = wxCoord(radius1);
430 wxCoord alpha2 = alpha1 + wxCoord(radius2 - radius1);
431 while (alpha2 <= 0) alpha2 += 360;
432 while (alpha1 > 360) alpha1 -= 360;
433
434 m_MGLDC->makeCurrent(); // will go away with MGL6.0
435 if ( m_brush.GetStyle() != wxTRANSPARENT )
436 {
437 if ( !m_brushSelected )
438 SelectBrush();
439 m_MGLDC->fillEllipseArc(xxc, yyc, r, r, alpha1, alpha2);
440 }
441
442 if ( m_pen.GetStyle() != wxTRANSPARENT )
443 {
444 if ( !m_penSelected )
445 SelectPen();
446 m_MGLDC->ellipseArc(xxc + m_penOfsX, yyc + m_penOfsY, r, r, alpha1, alpha2);
447 }
448
449 CalcBoundingBox(xc - r, yc - r);
450 CalcBoundingBox(xc + r, yc + r);
451 }
452
453 void wxDC::DoDrawPoint(wxCoord x, wxCoord y)
454 {
455 wxCHECK_RET( Ok(), wxT("invalid dc") );
456
457 if ( m_pen.GetStyle() != wxTRANSPARENT )
458 {
459 m_MGLDC->makeCurrent(); // will go away with MGL6.0
460 if ( !m_penSelected )
461 SelectPen();
462 m_MGLDC->pixel(XLOG2DEV(x), YLOG2DEV(y));
463 CalcBoundingBox(x, y);
464 }
465 }
466
467 void wxDC::DoDrawPolygon(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset,int fillStyle)
468 {
469 wxCHECK_RET( Ok(), wxT("invalid dc") );
470
471 wxCoord xxoffset = XLOG2DEVREL(xoffset),
472 yyoffset = YLOG2DEVREL(yoffset);
473 MGLPoint *cpoints = new MGLPoint[n+1];
474 for (int i = 0; i < n; i++)
475 {
476 CalcBoundingBox(points[i].x + xoffset, points[i].y + yoffset);
477 cpoints[i].x = (int)(XLOG2DEV(points[i].x));
478 cpoints[i].y = (int)(YLOG2DEV(points[i].y));
479 }
480 cpoints[n] = cpoints[0];
481
482 m_MGLDC->makeCurrent(); // will go away with MGL6.0
483 if ( m_brush.GetStyle() != wxTRANSPARENT )
484 {
485 if ( !m_brushSelected )
486 SelectBrush();
487 m_MGLDC->fillPolygon(n, cpoints, xxoffset, yyoffset);
488 }
489
490 if ( m_pen.GetStyle() != wxTRANSPARENT )
491 {
492 if ( !m_penSelected )
493 SelectPen();
494 if (m_penOfsX != 0 || m_penOfsY != 0)
495 {
496 for (int i = 0; i <= n; i++)
497 {
498 cpoints[i].x += m_penOfsX;
499 cpoints[i].y += m_penOfsY;
500 }
501 }
502 m_MGLDC->polyLine(n+1, cpoints);
503 }
504
505 delete[] cpoints;
506 }
507
508 void wxDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset)
509 {
510 wxCHECK_RET( Ok(), wxT("invalid dc") );
511
512 if ( m_pen.GetStyle() != wxTRANSPARENT )
513 {
514 MGLPoint *cpoints = new MGLPoint[n];
515 m_MGLDC->makeCurrent(); // will go away with MGL6.0
516 if ( !m_penSelected )
517 SelectPen();
518 for (int i = 0; i < n; i++)
519 {
520 CalcBoundingBox(points[i].x + xoffset, points[i].y + yoffset);
521 cpoints[i].x = (int)(XLOG2DEV(points[i].x + xoffset) /*+ m_penOfsX*/);
522 cpoints[i].y = (int)(YLOG2DEV(points[i].y + yoffset) /*+ m_penOfsY*/);
523 }
524 m_MGLDC->polyLine(n, cpoints);
525 delete[] cpoints;
526 }
527 }
528
529 void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
530 {
531 wxCHECK_RET( Ok(), wxT("invalid dc") );
532
533 wxCoord xx = XLOG2DEV(x);
534 wxCoord yy = YLOG2DEV(y);
535 wxCoord ww = m_signX * XLOG2DEVREL(width);
536 wxCoord hh = m_signY * YLOG2DEVREL(height);
537
538 if ( ww == 0 || hh == 0 ) return;
539
540 if ( ww < 0 )
541 {
542 ww = -ww;
543 xx = xx - ww;
544 }
545 if ( hh < 0 )
546 {
547 hh = -hh;
548 yy = yy - hh;
549 }
550
551 m_MGLDC->makeCurrent(); // will go away with MGL6.0
552 if ( m_brush.GetStyle() != wxTRANSPARENT )
553 {
554 if ( !m_brushSelected )
555 SelectBrush();
556 m_MGLDC->fillRect(xx, yy, xx + ww, yy + hh);
557 }
558
559 if ( m_pen.GetStyle() != wxTRANSPARENT )
560 {
561 if ( !m_penSelected )
562 SelectPen();
563 m_MGLDC->rect(xx + m_penOfsX, yy + m_penOfsY,
564 xx + ww + m_penOfsX, yy + hh + m_penOfsY);
565 }
566
567 CalcBoundingBox(x, y);
568 CalcBoundingBox(x + width, y + height);
569 }
570
571 void wxDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius)
572 {
573 wxCHECK_RET( Ok(), wxT("invalid dc") );
574
575 if ( radius < 0.0 )
576 radius = -radius * ((width < height) ? width : height);
577
578 wxCoord xx = XLOG2DEV(x);
579 wxCoord yy = YLOG2DEV(y);
580 wxCoord ww = m_signX * XLOG2DEVREL(width);
581 wxCoord hh = m_signY * YLOG2DEVREL(height);
582 wxCoord rr = XLOG2DEVREL((wxCoord)radius);
583
584 // CMB: handle -ve width and/or height
585 if ( ww < 0 )
586 {
587 ww = -ww;
588 xx = xx - ww;
589 }
590 if ( hh < 0 )
591 {
592 hh = -hh;
593 yy = yy - hh;
594 }
595
596 // CMB: if radius is zero use DrawRectangle() instead to avoid
597 // X drawing errors with small radii
598 if ( rr == 0 )
599 {
600 DrawRectangle(x, y, width, height);
601 return;
602 }
603
604 // CMB: draw nothing if transformed w or h is 0
605 if ( ww == 0 || hh == 0 ) return;
606
607 // CMB: ensure dd is not larger than rectangle otherwise we
608 // get an hour glass shape
609 wxCoord dd = 2 * rr;
610 if ( dd > ww ) dd = ww;
611 if ( dd > hh ) dd = hh;
612 rr = dd / 2;
613
614 m_MGLDC->makeCurrent(); // will go away with MGL6.0
615 if ( m_brush.GetStyle() != wxTRANSPARENT )
616 {
617 if (!m_brushSelected)
618 SelectBrush();
619 m_MGLDC->fillRect(xx+rr, yy, xx+ww-rr, yy+hh);
620 m_MGLDC->fillRect(xx, yy+rr, xx+ww, yy+hh-rr);
621 m_MGLDC->fillEllipseArc(xx+rr, yy+rr, rr, rr, 90, 180);
622 m_MGLDC->fillEllipseArc(xx+ww-rr, yy+rr, rr, rr, 0, 90);
623 m_MGLDC->fillEllipseArc(xx+rr, yy+hh-rr, rr, rr, 180, 270);
624 m_MGLDC->fillEllipseArc(xx+ww-rr, yy+hh-rr, rr, rr, 270, 0);
625 }
626
627 if ( m_pen.GetStyle() != wxTRANSPARENT )
628 {
629 if ( !m_penSelected )
630 SelectPen();
631 xx += m_penOfsX;
632 yy += m_penOfsY;
633 m_MGLDC->line(xx+rr+1, yy, xx+ww-rr, yy);
634 m_MGLDC->ellipseArc(xx+ww-rr, yy+rr, rr, rr, 0, 90);
635 m_MGLDC->line(xx+ww, yy+rr+1, xx+ww, yy+hh-rr);
636 m_MGLDC->ellipseArc(xx+ww-rr, yy+hh-rr, rr, rr, 270, 0);
637 m_MGLDC->line(xx+ww-rr, yy+hh, xx+rr+1, yy+hh);
638 m_MGLDC->ellipseArc(xx+rr, yy+hh-rr, rr, rr, 180, 270);
639 m_MGLDC->line(xx, yy+hh-rr, xx, yy+rr+1);
640 m_MGLDC->ellipseArc(xx+rr, yy+rr, rr, rr, 90, 180);
641 }
642
643 CalcBoundingBox(x, y);
644 CalcBoundingBox(x + width, y + height);
645 }
646
647 void wxDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
648 {
649 wxCHECK_RET( Ok(), wxT("invalid dc") );
650
651 wxCoord x2 = (x+width);
652 wxCoord y2 = (y+height);
653
654 m_MGLDC->makeCurrent(); // will go away with MGL6.0
655 if ( m_brush.GetStyle() != wxTRANSPARENT )
656 {
657 if ( !m_brushSelected )
658 SelectBrush();
659 MGLRect rect(XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2));
660 m_MGLDC->fillEllipse(rect);
661 }
662
663 if ( m_pen.GetStyle() != wxTRANSPARENT )
664 {
665 if ( !m_penSelected )
666 SelectPen();
667 MGLRect rect(XLOG2DEV(x) + m_penOfsX, YLOG2DEV(y) + m_penOfsY,
668 XLOG2DEV(x2) + m_penOfsX, YLOG2DEV(y2) + m_penOfsY);
669 m_MGLDC->ellipse(rect);
670 }
671
672 CalcBoundingBox(x, y);
673 CalcBoundingBox(x2, y2);
674 }
675
676 void wxDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
677 {
678 wxCHECK_RET( Ok(), wxT("invalid dc") );
679
680 wxCoord x2 = (x+w);
681 wxCoord y2 = (y+h);
682
683 m_MGLDC->makeCurrent(); // will go away with MGL6.0
684 if ( m_brush.GetStyle() != wxTRANSPARENT )
685 {
686 if (!m_brushSelected) SelectBrush();
687 MGLRect rect(XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2));
688 m_MGLDC->fillEllipseArc(rect, (int)sa, (int)ea);
689 }
690
691 if ( m_pen.GetStyle() != wxTRANSPARENT )
692 {
693 if ( !m_penSelected )
694 SelectPen();
695 MGLRect rect(XLOG2DEV(x) + m_penOfsX, YLOG2DEV(y) + m_penOfsY,
696 XLOG2DEV(x2) + m_penOfsX, YLOG2DEV(y2) + m_penOfsY);
697 m_MGLDC->ellipseArc(rect, (int)sa, (int)ea);
698 }
699
700 CalcBoundingBox(x, y);
701 CalcBoundingBox(x2, y2);
702 }
703
704 void wxDC::DoDrawText(const wxString& text, wxCoord x, wxCoord y)
705 {
706 m_MGLDC->makeCurrent(); // will go away with MGL6.0
707 DrawAnyText(text, x, y);
708
709 // update the bounding box
710 wxCoord w, h;
711 CalcBoundingBox(x, y);
712 GetTextExtent(text, &w, &h);
713 CalcBoundingBox(x + w, y + h);
714 }
715
716 bool wxDC::SelectMGLFont()
717 {
718 if ( m_mglFont == NULL )
719 {
720 float scale = m_scaleY;
721 bool antialiased = (GetDepth() > 8);
722
723 m_mglFont = m_font.GetMGLfont_t(scale, antialiased);
724 wxCHECK_MSG( m_mglFont, FALSE, wxT("invalid font") );
725
726 m_MGLDC->useFont(m_mglFont);
727 wxLogTrace("mgl_font", "useFont(%p)", m_mglFont);
728
729 #if !wxUSE_UNICODE
730 wxNativeEncodingInfo nativeEnc;
731 wxFontEncoding encoding = m_font.GetEncoding();
732 if ( !wxGetNativeFontEncoding(encoding, &nativeEnc) ||
733 !wxTestFontEncoding(nativeEnc) )
734 {
735 #if wxUSE_FONTMAP
736 if ( !wxTheFontMapper->GetAltForEncoding(encoding, &nativeEnc) )
737 #endif
738 {
739 nativeEnc.mglEncoding = MGL_ENCODING_ASCII;
740 }
741 }
742 m_MGLDC->setTextEncoding(nativeEnc.mglEncoding);
743 #endif
744 }
745 return TRUE;
746 }
747
748 void wxDC::DrawAnyText(const wxString& text, wxCoord x, wxCoord y)
749 {
750 wxCHECK_RET( Ok(), wxT("invalid dc") );
751
752 SelectMGLFont();
753
754 m_MGLDC->setColor(m_MGLDC->packColorFast(m_textForegroundColour.Red(),
755 m_textForegroundColour.Green(), m_textForegroundColour.Blue()));
756 m_MGLDC->setBackColor(m_MGLDC->packColorFast(m_textBackgroundColour.Red(),
757 m_textBackgroundColour.Green(), m_textBackgroundColour.Blue()));
758
759 // Render the text:
760 wxCoord xx = XLOG2DEV(x);
761 wxCoord yy = YLOG2DEV(y);
762
763 m_MGLDC->setLineStyle(MGL_LINE_STIPPLE);
764 m_MGLDC->setLineStipple(0xFFFF);
765 m_MGLDC->setPenSize(1, 1);
766 m_MGLDC->setPenStyle(MGL_BITMAP_SOLID);
767
768 #if wxUSE_UNICODE
769 const wchar_t *c_text = text.c_str();
770 #else
771 const char *c_text = text.c_str();
772 #endif
773 m_MGLDC->drawStr(xx, yy, c_text);
774
775 // Render underline:
776 if ( m_font.GetUnderlined() )
777 {
778 int x1 = xx, y1 = yy;
779 int x2 = 0 , y2 = 0;
780 int w = m_MGLDC->textWidth(c_text);
781 m_MGLDC->underScoreLocation(x1, y1, c_text);
782 switch (m_MGLDC->getTextDirection())
783 {
784 case MGL_RIGHT_DIR: x2 = x1 + w, y2 = y1; break;
785 case MGL_LEFT_DIR: x2 = x1 - w, y2 = y1; break;
786 case MGL_UP_DIR: x2 = x1, y2 = y1 - w; break;
787 case MGL_DOWN_DIR: x2 = x1, y2 = y1 + w; break;
788 }
789 m_MGLDC->line(x1, y1, x2, y2);
790 }
791
792 m_penSelected = m_brushSelected = FALSE;
793 }
794
795 void wxDC::DoDrawRotatedText(const wxString& text,
796 wxCoord x, wxCoord y,
797 double angle)
798 {
799 m_MGLDC->makeCurrent(); // will go away with MGL6.0
800
801 if ( angle == 0 )
802 {
803 DoDrawText(text, x, y);
804 return;
805 }
806 else if ( angle == 90.0 )
807 m_MGLDC->setTextDirection(MGL_UP_DIR);
808 else if ( angle == 180.0 )
809 m_MGLDC->setTextDirection(MGL_LEFT_DIR);
810 else if ( angle == 270.0 )
811 m_MGLDC->setTextDirection(MGL_DOWN_DIR);
812 else
813 {
814 // FIXME_MGL -- implement once MGL supports it
815 wxFAIL_MSG(wxT("wxMGL only supports rotated text with angle 0,90,180 or 270"));
816 return;
817 }
818
819 DrawAnyText(text, x, y);
820
821 // Restore default:
822 m_MGLDC->setTextDirection(MGL_RIGHT_DIR);
823 }
824
825 // ---------------------------------------------------------------------------
826 // set GDI objects
827 // ---------------------------------------------------------------------------
828
829 void wxDC::SelectMGLStipplePen(int style)
830 {
831 ushort stipple;
832
833 switch (style)
834 {
835 case wxDOT: stipple = STIPPLE_wxDOT; break;
836 case wxLONG_DASH: stipple = STIPPLE_wxLONG_DASH; break;
837 case wxSHORT_DASH: stipple = STIPPLE_wxSHORT_DASH; break;
838 case wxDOT_DASH: stipple = STIPPLE_wxDOT_DASH; break;
839 default: stipple = STIPPLE_wxSOLID; break;
840 }
841
842 m_MGLDC->setLineStyle(MGL_LINE_STIPPLE);
843 m_MGLDC->setLineStipple(stipple);
844 m_MGLDC->setPenSize(1, 1);
845 m_MGLDC->setPenStyle(MGL_BITMAP_SOLID);
846 m_penOfsY = m_penOfsX = 0;
847 }
848
849 // Accepted valus of SelectMGLFatPen's 2nd argument
850 enum {
851 wxMGL_SELECT_FROM_PEN,
852 wxMGL_SELECT_FROM_BRUSH
853 };
854
855 void wxDC::SelectMGLFatPen(int style, int flag)
856 {
857 MGL_penStyleType penstyle;
858 const pattern_t *pattern = NULL;
859 pixpattern24_t *pixPattern = NULL;
860 int wx, wy;
861 int slot;
862
863 // Since MGL pens may be created from wxBrush or wxPen and we often
864 // switch between pens and brushes, we take advantage of MGL's ability
865 // to have multiple (pix)pattern_t's loaded. We always download pen
866 // to 0th slot and brush to 1st slot.
867 if ( flag == wxMGL_SELECT_FROM_PEN )
868 slot = 0;
869 else
870 slot = 1;
871
872 // compute pen's width:
873 if ( m_pen.GetWidth() <= 1 )
874 {
875 wx = wy = 1;
876 m_penOfsX = m_penOfsY = 0;
877 }
878 else
879 {
880 wx = (int)(0.5 + fabs((double) XLOG2DEVREL(m_pen.GetWidth())));
881 wy = (int)(0.5 + fabs((double) YLOG2DEVREL(m_pen.GetWidth())));
882 m_penOfsX = -wx/2;
883 m_penOfsY = -wy/2;
884 }
885
886 // find pen's type:
887 penstyle = MGL_BITMAP_TRANSPARENT;
888 switch (style)
889 {
890 case wxBDIAGONAL_HATCH: pattern = &PATTERN_wxBDIAGONAL_HATCH;
891 penstyle = MGL_BITMAP_TRANSPARENT;
892 break;
893 case wxCROSSDIAG_HATCH: pattern = &PATTERN_wxCROSSDIAG_HATCH;
894 penstyle = MGL_BITMAP_TRANSPARENT;
895 break;
896 case wxFDIAGONAL_HATCH: pattern = &PATTERN_wxFDIAGONAL_HATCH;
897 penstyle = MGL_BITMAP_TRANSPARENT;
898 break;
899 case wxCROSS_HATCH: pattern = &PATTERN_wxCROSS_HATCH;
900 penstyle = MGL_BITMAP_TRANSPARENT;
901 break;
902 case wxHORIZONTAL_HATCH: pattern = &PATTERN_wxHORIZONTAL_HATCH;
903 penstyle = MGL_BITMAP_TRANSPARENT;
904 break;
905 case wxVERTICAL_HATCH: pattern = &PATTERN_wxVERTICAL_HATCH;
906 penstyle = MGL_BITMAP_TRANSPARENT;
907 break;
908
909 case wxSTIPPLE:
910 if ( flag == wxMGL_SELECT_FROM_PEN )
911 pixPattern = (pixpattern24_t*) m_pen.GetPixPattern();
912 else
913 pixPattern = (pixpattern24_t*) m_brush.GetPixPattern();
914 penstyle = MGL_PIXMAP;
915 break;
916
917 case wxSTIPPLE_MASK_OPAQUE:
918 pattern = (pattern_t*) m_brush.GetMaskPattern();
919 penstyle = MGL_BITMAP_OPAQUE;
920 break;
921
922 case wxSOLID:
923 default:
924 penstyle = MGL_BITMAP_SOLID; break;
925 }
926
927 // ...and finally, pass the pen to MGL:
928
929 if ( pattern )
930 {
931 if ( !m_downloadedPatterns[slot] )
932 {
933 m_MGLDC->setPenBitmapPattern(slot, pattern);
934 m_downloadedPatterns[slot] = TRUE;
935 }
936 m_MGLDC->usePenBitmapPattern(slot);
937 }
938
939 if ( pixPattern )
940 {
941 if ( !m_downloadedPatterns[slot] )
942 {
943 pixpattern_t pix;
944 int x, y, c;
945
946 switch (GetDepth())
947 {
948 case 8:
949 for (y = 0; y < 8; y++)
950 for (x = 0; x < 8; x++)
951 pix.b8.p[x][y] = m_MGLDC->packColorFast(
952 pixPattern->p[x][y][0],
953 pixPattern->p[x][y][1],
954 pixPattern->p[x][y][2]);
955 break;
956 case 15:
957 case 16:
958 for (y = 0; y < 8; y++)
959 for (x = 0; x < 8; x++)
960 pix.b16.p[x][y] = m_MGLDC->packColorFast(
961 pixPattern->p[x][y][0],
962 pixPattern->p[x][y][1],
963 pixPattern->p[x][y][2]);
964 break;
965 case 24:
966 for (y = 0; y < 8; y++)
967 for (x = 0; x < 8; x++)
968 for (c = 0; c < 3; c++)
969 pix.b24.p[x][y][c] = pixPattern->p[x][y][c];
970 break;
971 case 32:
972 for (y = 0; y < 8; y++)
973 for (x = 0; x < 8; x++)
974 pix.b32.p[x][y] = m_MGLDC->packColorFast(
975 pixPattern->p[x][y][0],
976 pixPattern->p[x][y][1],
977 pixPattern->p[x][y][2]);
978 break;
979 default:
980 wxFAIL_MSG(_T("invalid DC depth"));
981 break;
982 }
983 m_MGLDC->setPenPixmapPattern(slot, &pix);
984 m_downloadedPatterns[slot] = TRUE;
985 }
986 m_MGLDC->usePenPixmapPattern(slot);
987 }
988
989 m_MGLDC->setLineStyle(MGL_LINE_PENSTYLE);
990 m_MGLDC->setPenStyle(penstyle);
991 m_MGLDC->setPenSize(wy, wx);
992 }
993
994 void wxDC::SelectPen()
995 {
996 wxCHECK_RET( Ok(), wxT("invalid dc") );
997
998 wxColour& clr = m_pen.GetColour();
999 m_MGLDC->makeCurrent(); // will go away with MGL6.0
1000 m_MGLDC->setColorRGB(clr.Red(), clr.Green(), clr.Blue());
1001
1002 switch (m_pen.GetStyle())
1003 {
1004 case wxTRANSPARENT:
1005 break;
1006
1007 case wxDOT:
1008 case wxLONG_DASH:
1009 case wxSHORT_DASH:
1010 case wxDOT_DASH:
1011 SelectMGLStipplePen(m_pen.GetStyle());
1012 break;
1013
1014 case wxBDIAGONAL_HATCH:
1015 case wxCROSSDIAG_HATCH:
1016 case wxFDIAGONAL_HATCH:
1017 case wxCROSS_HATCH:
1018 case wxHORIZONTAL_HATCH:
1019 case wxVERTICAL_HATCH:
1020 SelectMGLFatPen(m_pen.GetStyle(), wxMGL_SELECT_FROM_PEN);
1021 break;
1022
1023 case wxSTIPPLE:
1024 SelectMGLFatPen(m_pen.GetStyle(), wxMGL_SELECT_FROM_PEN);
1025 break;
1026
1027 case wxSOLID:
1028 case wxUSER_DASH:
1029 default:
1030 if ( m_pen.GetWidth() <= 1 )
1031 SelectMGLStipplePen(wxSOLID);
1032 else
1033 SelectMGLFatPen(wxSOLID, wxMGL_SELECT_FROM_PEN);
1034 break;
1035 }
1036 m_penSelected = TRUE;
1037 m_brushSelected = FALSE;
1038 }
1039
1040 void wxDC::SelectBrush()
1041 {
1042 wxCHECK_RET( Ok(), wxT("invalid dc") );
1043
1044 wxColour fg, bg;
1045 m_MGLDC->makeCurrent(); // will go away with MGL6.0
1046
1047 if ( m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE )
1048 {
1049 fg = m_textForegroundColour;
1050 bg = m_textBackgroundColour;
1051 }
1052 else
1053 {
1054 fg = m_brush.GetColour();
1055 bg = m_backgroundBrush.GetColour();
1056 }
1057
1058 m_MGLDC->setColorRGB(fg.Red(), fg.Green(), fg.Blue());
1059 m_MGLDC->setBackColor(m_MGLDC->packColorFast(bg.Red(), bg.Green(), bg.Blue()));
1060 m_penSelected = FALSE;
1061 m_brushSelected = TRUE;
1062
1063 SelectMGLFatPen(m_brush.GetStyle(), wxMGL_SELECT_FROM_BRUSH);
1064 }
1065
1066 void wxDC::SetPen(const wxPen& pen)
1067 {
1068 if ( !pen.Ok() ) return;
1069 if ( m_pen == pen ) return;
1070 m_pen = pen;
1071 m_penSelected = FALSE;
1072 m_downloadedPatterns[0] = FALSE;
1073 }
1074
1075 void wxDC::SetBrush(const wxBrush& brush)
1076 {
1077 if ( !brush.Ok() ) return;
1078 if ( m_brush == brush ) return;
1079 m_brush = brush;
1080 m_brushSelected = FALSE;
1081 m_downloadedPatterns[1] = FALSE;
1082 }
1083
1084 void wxDC::SetPalette(const wxPalette& palette)
1085 {
1086 wxCHECK_RET( Ok(), wxT("invalid dc") );
1087
1088 if ( palette == wxNullPalette )
1089 {
1090 SetPalette(m_oldPalette);
1091 return;
1092 }
1093
1094 if ( !palette.Ok() ) return;
1095 if ( m_palette == palette ) return;
1096 m_oldPalette = m_palette;
1097 m_palette = palette;
1098
1099 int cnt = m_palette.GetColoursCount();
1100 palette_t *pal = m_palette.GetMGLpalette_t();
1101 m_MGLDC->setPalette(pal, cnt, 0);
1102 m_MGLDC->realizePalette(cnt, 0, TRUE);
1103 }
1104
1105 void wxDC::SetFont(const wxFont& font)
1106 {
1107 wxCHECK_RET( font.Ok(), wxT("invalid font") );
1108 m_font = font;
1109 m_mglFont = NULL;
1110 }
1111
1112 void wxDC::SetBackground(const wxBrush& brush)
1113 {
1114 wxCHECK_RET( Ok(), wxT("invalid dc") );
1115
1116 if (!m_backgroundBrush.Ok()) return;
1117
1118 m_backgroundBrush = brush;
1119 wxColour &clr = m_backgroundBrush.GetColour();
1120 m_MGLDC->makeCurrent(); // will go away with MGL6.0
1121 m_MGLDC->setBackColor(
1122 m_MGLDC->packColorFast(clr.Red(), clr.Green(), clr.Blue()));
1123 }
1124
1125 void wxDC::SetBackgroundMode(int mode)
1126 {
1127 m_backgroundMode = mode;
1128 if ( mode == wxSOLID )
1129 m_MGLDC->setBackMode(MGL_OPAQUE_BACKGROUND);
1130 else
1131 m_MGLDC->setBackMode(MGL_TRANSPARENT_BACKGROUND);
1132 }
1133
1134 void wxDC::SetLogicalFunction(int function)
1135 {
1136 wxCHECK_RET( Ok(), wxT("invalid dc") );
1137
1138 m_logicalFunction = function;
1139
1140 m_MGLDC->makeCurrent(); // will go away with MGL6.0
1141 m_MGLDC->setWriteMode(LogicalFunctionToMGLRop(m_logicalFunction));
1142 }
1143
1144 int wxDC::LogicalFunctionToMGLRop(int logFunc) const
1145 {
1146 MGL_writeModeType rop;
1147
1148 switch (logFunc)
1149 {
1150 case wxCLEAR: rop = MGL_R2_BLACK; break;
1151 case wxXOR: rop = MGL_R2_XORSRC; break;
1152 case wxINVERT: rop = MGL_R2_NOT; break;
1153 case wxOR_REVERSE: rop = MGL_R2_MERGESRCNOT; break;
1154 case wxAND_REVERSE: rop = MGL_R2_MASKSRCNOT; break;
1155 case wxCOPY: rop = MGL_R2_COPYSRC; break;
1156 case wxAND: rop = MGL_R2_MASKSRC; break;
1157 case wxAND_INVERT: rop = MGL_R2_MASKNOTSRC; break;
1158 case wxNO_OP: rop = MGL_R2_NOP; break;
1159 case wxNOR: rop = MGL_R2_NOTMERGESRC; break;
1160 case wxEQUIV: rop = MGL_R2_NOTXORSRC; break;
1161 case wxSRC_INVERT: rop = MGL_R2_NOTCOPYSRC; break;
1162 case wxOR_INVERT: rop = MGL_R2_MERGENOTSRC; break;
1163 case wxNAND: rop = MGL_R2_NOTMASKSRC; break;
1164 case wxOR: rop = MGL_R2_MERGESRC; break;
1165 case wxSET: rop = MGL_R2_WHITE; break;
1166 default:
1167 wxFAIL_MSG( wxT("unsupported logical function") );
1168 return MGL_REPLACE_MODE;
1169 }
1170 return (int)rop;
1171 }
1172
1173 bool wxDC::StartDoc(const wxString& message)
1174 {
1175 // We might be previewing, so return TRUE to let it continue.
1176 return TRUE;
1177 }
1178
1179 void wxDC::EndDoc()
1180 {
1181 }
1182
1183 void wxDC::StartPage()
1184 {
1185 }
1186
1187 void wxDC::EndPage()
1188 {
1189 }
1190
1191 // ---------------------------------------------------------------------------
1192 // text metrics
1193 // ---------------------------------------------------------------------------
1194
1195 wxCoord wxDC::GetCharHeight() const
1196 {
1197 wxCurrentDCSwitcher switcher(m_MGLDC);
1198 if ( !wxConstCast(this, wxDC)->SelectMGLFont() ) return -1;
1199 return YDEV2LOGREL(m_mglFont->fontHeight);
1200 }
1201
1202 wxCoord wxDC::GetCharWidth() const
1203 {
1204 wxCurrentDCSwitcher switcher(m_MGLDC);
1205 if ( !wxConstCast(this, wxDC)->SelectMGLFont() ) return -1;
1206 // VS: wxT() is intentional, charWidth() has both char and wchar_t version
1207 // VS: YDEV is corrent, it should *not* be XDEV, because font's are only
1208 // scaled according to m_scaleY
1209 return YDEV2LOGREL(m_mglFont->fontWidth);
1210 }
1211
1212 void wxDC::DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y,
1213 wxCoord *descent, wxCoord *externalLeading,
1214 wxFont *theFont) const
1215 {
1216 wxFont oldFont;
1217
1218 if ( theFont != NULL )
1219 {
1220 oldFont = m_font;
1221 wxConstCast(this, wxDC)->SetFont(*theFont);
1222 }
1223
1224 wxCurrentDCSwitcher switcher(m_MGLDC);
1225 if ( !wxConstCast(this, wxDC)->SelectMGLFont() ) return;
1226
1227 if ( x )
1228 // VS: YDEV is corrent, it should *not* be XDEV, because font's are
1229 // only scaled according to m_scaleY
1230 *x = YDEV2LOGREL(m_MGLDC->textWidth(string.c_str()));
1231 if ( y )
1232 *y = YDEV2LOGREL(m_MGLDC->textHeight());
1233 if ( descent )
1234 *descent = YDEV2LOGREL(m_mglFont->descent);
1235 if ( externalLeading )
1236 *externalLeading = YDEV2LOGREL(m_mglFont->leading);
1237
1238 if ( theFont != NULL )
1239 wxConstCast(this, wxDC)->SetFont(oldFont);
1240 }
1241
1242
1243
1244 // ---------------------------------------------------------------------------
1245 // mapping modes
1246 // ---------------------------------------------------------------------------
1247
1248 void wxDC::ComputeScaleAndOrigin()
1249 {
1250 double newX = m_logicalScaleX * m_userScaleX;
1251 double newY = m_logicalScaleY * m_userScaleY;
1252
1253 // make sure font will be reloaded before drawing:
1254 if ( newY != m_scaleY )
1255 m_mglFont = NULL;
1256 // make sure m_penOfs{X,Y} will be reevaluated before drawing:
1257 if ( newY != m_scaleY || newX != m_scaleX )
1258 m_penSelected = FALSE;
1259
1260 m_scaleX = newX, m_scaleY = newY;
1261 }
1262
1263 void wxDC::SetMapMode(int mode)
1264 {
1265 switch (mode)
1266 {
1267 case wxMM_TWIPS:
1268 SetLogicalScale(twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y);
1269 break;
1270 case wxMM_POINTS:
1271 SetLogicalScale(pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y);
1272 break;
1273 case wxMM_METRIC:
1274 SetLogicalScale(m_mm_to_pix_x, m_mm_to_pix_y);
1275 break;
1276 case wxMM_LOMETRIC:
1277 SetLogicalScale(m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0);
1278 break;
1279 default:
1280 case wxMM_TEXT:
1281 SetLogicalScale(1.0, 1.0);
1282 break;
1283 }
1284 m_mappingMode = mode;
1285 }
1286
1287 void wxDC::SetUserScale( double x, double y )
1288 {
1289 // allow negative ? -> no
1290 m_userScaleX = x;
1291 m_userScaleY = y;
1292 ComputeScaleAndOrigin();
1293 }
1294
1295 void wxDC::SetLogicalScale( double x, double y )
1296 {
1297 // allow negative ?
1298 m_logicalScaleX = x;
1299 m_logicalScaleY = y;
1300 ComputeScaleAndOrigin();
1301 }
1302
1303 void wxDC::SetLogicalOrigin( wxCoord x, wxCoord y )
1304 {
1305 m_logicalOriginX = x * m_signX; // is this still correct ?
1306 m_logicalOriginY = y * m_signY;
1307 ComputeScaleAndOrigin();
1308 }
1309
1310 void wxDC::SetDeviceOrigin( wxCoord x, wxCoord y )
1311 {
1312 // only wxPostScripDC has m_signX = -1, we override SetDeviceOrigin there
1313 m_deviceOriginX = x;
1314 m_deviceOriginY = y;
1315 ComputeScaleAndOrigin();
1316 }
1317
1318 void wxDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
1319 {
1320 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
1321 m_signX = (xLeftRight ? 1 : -1);
1322 m_signY = (yBottomUp ? -1 : 1);
1323 ComputeScaleAndOrigin();
1324 }
1325
1326 // ---------------------------------------------------------------------------
1327 // coordinates transformations
1328 // ---------------------------------------------------------------------------
1329
1330 wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
1331 {
1332 return ((wxDC *)this)->XDEV2LOG(x);
1333 }
1334
1335 wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
1336 {
1337 return ((wxDC *)this)->YDEV2LOG(y);
1338 }
1339
1340 wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
1341 {
1342 return ((wxDC *)this)->XDEV2LOGREL(x);
1343 }
1344
1345 wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
1346 {
1347 return ((wxDC *)this)->YDEV2LOGREL(y);
1348 }
1349
1350 wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
1351 {
1352 return ((wxDC *)this)->XLOG2DEV(x);
1353 }
1354
1355 wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
1356 {
1357 return ((wxDC *)this)->YLOG2DEV(y);
1358 }
1359
1360 wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
1361 {
1362 return ((wxDC *)this)->XLOG2DEVREL(x);
1363 }
1364
1365 wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
1366 {
1367 return ((wxDC *)this)->YLOG2DEVREL(y);
1368 }
1369
1370
1371 void wxDC::DoGetSize(int *w, int *h) const
1372 {
1373 if (w) *w = m_MGLDC->sizex();
1374 if (h) *h = m_MGLDC->sizey();
1375 }
1376
1377 void wxDC::DoGetSizeMM(int *width, int *height) const
1378 {
1379 int w = 0;
1380 int h = 0;
1381 GetSize(&w, &h);
1382 if ( width ) *width = int(double(w) / (m_userScaleX*m_mm_to_pix_x));
1383 if ( height ) *height = int(double(h) / (m_userScaleY*m_mm_to_pix_y));
1384 }
1385
1386 wxSize wxDC::GetPPI() const
1387 {
1388 return wxSize(int(double(m_mm_to_pix_x) * inches2mm),
1389 int(double(m_mm_to_pix_y) * inches2mm));
1390 }
1391
1392
1393 // ---------------------------------------------------------------------------
1394 // Blitting
1395 // ---------------------------------------------------------------------------
1396
1397 bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest,
1398 wxCoord width, wxCoord height,
1399 wxDC *source, wxCoord xsrc, wxCoord ysrc,
1400 int rop, bool useMask,
1401 wxCoord xsrcMask, wxCoord ysrcMask)
1402 {
1403 wxCHECK_MSG( Ok(), FALSE, wxT("invalid dc") );
1404 wxCHECK_MSG( source, FALSE, wxT("invalid source dc") );
1405
1406 // transform the source DC coords to the device ones
1407 xsrc = source->LogicalToDeviceX(xsrc);
1408 ysrc = source->LogicalToDeviceY(ysrc);
1409
1410 /* FIXME_MGL: use the mask origin when drawing transparently */
1411 if (xsrcMask == -1 && ysrcMask == -1)
1412 {
1413 xsrcMask = xsrc; ysrcMask = ysrc;
1414 }
1415 else
1416 {
1417 xsrcMask = source->LogicalToDeviceX(xsrcMask);
1418 ysrcMask = source->LogicalToDeviceY(ysrcMask);
1419 }
1420
1421 CalcBoundingBox(xdest, ydest);
1422 CalcBoundingBox(xdest + width, ydest + height);
1423
1424 /* scale/translate size and position */
1425 wxCoord xx = XLOG2DEV(xdest);
1426 wxCoord yy = YLOG2DEV(ydest);
1427 wxCoord ww = XLOG2DEVREL(width);
1428 wxCoord hh = YLOG2DEVREL(height);
1429
1430 if ( source->m_isMemDC )
1431 {
1432 wxMemoryDC *memDC = (wxMemoryDC*) source;
1433 DoDrawSubBitmap(memDC->GetSelectedObject(), xsrc, ysrc, ww, hh,
1434 xdest, ydest, rop, useMask);
1435 }
1436 else
1437 {
1438 m_MGLDC->makeCurrent(); // will go away with MGL6.0
1439 m_MGLDC->bitBlt(*source->GetMGLDC(),
1440 xsrc, ysrc, xsrc + ww, ysrc + hh,
1441 xx, yy, LogicalFunctionToMGLRop(rop));
1442 }
1443
1444 return TRUE;
1445 }
1446
1447 void wxDC::DoDrawBitmap(const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask)
1448 {
1449 wxCHECK_RET( Ok(), wxT("invalid dc") );
1450 wxCHECK_RET( bmp.Ok(), wxT("invalid bitmap") );
1451
1452 wxCoord w = bmp.GetWidth();
1453 wxCoord h = bmp.GetHeight();
1454
1455 DoDrawSubBitmap(bmp, 0, 0, w, h, x, y, m_logicalFunction, useMask);
1456 }
1457
1458 void wxDC::DoDrawIcon(const wxIcon& icon, wxCoord x, wxCoord y)
1459 {
1460 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
1461 DoDrawBitmap((const wxBitmap&)icon, x, y, (bool)TRUE);
1462 }
1463
1464
1465 static inline void DoBitBlt(const wxBitmap& src, MGLDevCtx *dst,
1466 int sx, int sy, int sw, int sh,
1467 int dx, int dy, int dw, int dh,
1468 int rop, bool useStretching, bool putSection)
1469 {
1470 bitmap_t *bmp = src.GetMGLbitmap_t();
1471 if (!useStretching)
1472 {
1473 if (!putSection)
1474 dst->putBitmap(dx, dy, bmp, rop);
1475 else
1476 dst->putBitmapSection(sx, sy, sx + sw, sy + sh, dx, dy, bmp, rop);
1477 }
1478 else
1479 {
1480 if (!putSection)
1481 dst->stretchBitmap(dx, dy, dx + dw, dy + dh, bmp, rop);
1482 else
1483 dst->stretchBitmapSection(sx, sy, sx + sw, sy + sh,
1484 dx, dy, dx + dw, dy + dh, bmp, rop);
1485 }
1486 }
1487
1488 void wxDC::DoDrawSubBitmap(const wxBitmap &bmp,
1489 wxCoord x, wxCoord y, wxCoord w, wxCoord h,
1490 wxCoord destx, wxCoord desty, int rop, bool useMask)
1491 {
1492 wxCHECK_RET( Ok(), wxT("invalid dc") );
1493 wxCHECK_RET( bmp.Ok(), wxT("invalid bitmap") );
1494
1495 CalcBoundingBox(x, y);
1496 CalcBoundingBox(x + w, y + h);
1497
1498 wxCoord dx = XLOG2DEV(destx);
1499 wxCoord dy = YLOG2DEV(desty);
1500 wxCoord dw = XLOG2DEVREL(w);
1501 wxCoord dh = YLOG2DEVREL(h);
1502
1503 m_MGLDC->makeCurrent(); // will go away with MGL6.0
1504
1505 bool useStretching = ((w != dw) || (h != dh));
1506 bool putSection = (w != bmp.GetWidth() || h != bmp.GetHeight());
1507 MGL_writeModeType mglRop = (MGL_writeModeType)LogicalFunctionToMGLRop(rop);
1508
1509 if ( bmp.GetDepth() == 1 )
1510 {
1511 // Mono bitmaps are handled in special way -- all 1s are drawn in
1512 // foreground colours, all 0s in background colour.
1513
1514 ((wxBitmap&)bmp).SetMonoPalette(m_textForegroundColour, m_textBackgroundColour);
1515 }
1516
1517 if ( useMask && bmp.GetMask() )
1518 {
1519 // Since MGL does not support masks directly (in MGL, mask is handled
1520 // in same way as in wxImage, i.e. there is one "key" color), we
1521 // simulate masked bitblt in 6 steps (same as in MSW):
1522 //
1523 // 1. Create a temporary bitmap and copy the destination area into it.
1524 // 2. Copy the source area into the temporary bitmap using the
1525 // specified logical function.
1526 // 3. Set the masked area in the temporary bitmap to BLACK by ANDing
1527 // the mask bitmap with the temp bitmap with the foreground colour
1528 // set to WHITE and the bg colour set to BLACK.
1529 // 4. Set the unmasked area in the destination area to BLACK by
1530 // ANDing the mask bitmap with the destination area with the
1531 // foreground colour set to BLACK and the background colour set
1532 // to WHITE.
1533 // 5. OR the temporary bitmap with the destination area.
1534 // 6. Delete the temporary bitmap.
1535 //
1536 // This sequence of operations ensures that the source's transparent
1537 // area need not be black, and logical functions are supported.
1538
1539 wxBitmap *mask = bmp.GetMask()->GetBitmap();
1540
1541 MGLMemoryDC *temp;
1542
1543 if ( GetDepth() <= 8 )
1544 {
1545 temp = new MGLMemoryDC(dw, dh, GetDepth(), NULL);
1546 wxDC tempdc;
1547 tempdc.SetMGLDC(temp, FALSE);
1548 tempdc.SetPalette(m_palette);
1549 }
1550 else
1551 {
1552 pixel_format_t pf;
1553 m_MGLDC->getPixelFormat(pf);
1554 temp = new MGLMemoryDC(dw, dh, GetDepth(), &pf);
1555 }
1556
1557 wxCHECK_RET( temp->isValid(), wxT("cannot create temporary dc") );
1558
1559 temp->bitBlt(*m_MGLDC, dx, dy, dx + dw, dy + dh, 0, 0, MGL_REPLACE_MODE);
1560
1561 DoBitBlt(bmp, temp, x, y, w, h, 0, 0, dw, dh, mglRop,
1562 useStretching, putSection);
1563
1564 mask->SetMonoPalette(wxColour(0,0,0), wxColour(255,255,255));
1565 DoBitBlt(*mask, temp, x, y, w, h, 0, 0, dw, dh, MGL_R2_MASKSRC,
1566 useStretching, putSection);
1567 DoBitBlt(*mask, m_MGLDC, x, y, w, h, dx, dy, dw, dh, MGL_R2_MASKNOTSRC,
1568 useStretching, putSection);
1569
1570 m_MGLDC->bitBlt(*temp, 0, 0, dw, dh, dx, dy, MGL_OR_MODE);
1571
1572 delete temp;
1573 }
1574
1575 else
1576 {
1577 DoBitBlt(bmp, m_MGLDC, x, y, w, h, dx, dy, dw, dh, mglRop,
1578 useStretching, putSection);
1579 }
1580 }