]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcbase.cpp
Add support for wxDC_ROW_LINES for GTK+ and OS X
[wxWidgets.git] / src / common / dcbase.cpp
CommitLineData
dbe94982 1/////////////////////////////////////////////////////////////////////////////
06052f3f 2// Name: src/common/dcbase.cpp
1e6feb95
VZ
3// Purpose: generic methods of the wxDC Class
4// Author: Vadim Zeitlin
dbe94982
BM
5// Modified by:
6// Created: 05/25/99
7// RCS-ID: $Id$
77ffb593 8// Copyright: (c) wxWidgets team
65571936 9// Licence: wxWindows licence
dbe94982
BM
10/////////////////////////////////////////////////////////////////////////////
11
1e6feb95
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
1e6feb95
VZ
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
dbe94982
BM
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
bd1e9c12 24 #pragma hdrstop
dbe94982
BM
25#endif
26
dbe94982 27#include "wx/dc.h"
ab171e95
RR
28#include "wx/dcclient.h"
29#include "wx/dcmemory.h"
30#include "wx/dcscreen.h"
4f37154e 31#include "wx/dcprint.h"
4f37154e 32#include "wx/prntbase.h"
18680f86
WS
33
34#ifndef WX_PRECOMP
35 #include "wx/math.h"
f2498c4e 36 #include "wx/module.h"
18680f86 37#endif
dbe94982 38
888dde65 39#ifdef __WXMSW__
f2498c4e
VZ
40 #include "wx/msw/dcclient.h"
41 #include "wx/msw/dcmemory.h"
42 #include "wx/msw/dcscreen.h"
888dde65 43#endif
2970ae54 44
888dde65 45#ifdef __WXGTK__
f2498c4e
VZ
46 #include "wx/gtk/dcclient.h"
47 #include "wx/gtk/dcmemory.h"
48 #include "wx/gtk/dcscreen.h"
888dde65
RR
49#endif
50
51#ifdef __WXMAC__
f2498c4e
VZ
52 #include "wx/mac/dcclient.h"
53 #include "wx/mac/dcmemory.h"
54 #include "wx/mac/dcscreen.h"
888dde65 55#endif
2970ae54 56
e6514d0e 57#ifdef __WXX11__
f2498c4e
VZ
58 #include "wx/x11/dcclient.h"
59 #include "wx/x11/dcmemory.h"
60 #include "wx/x11/dcscreen.h"
e6514d0e
RR
61#endif
62
2970ae54
RR
63//----------------------------------------------------------------------------
64// wxDCFactory
65//----------------------------------------------------------------------------
66
67wxDCFactory *wxDCFactory::m_factory = NULL;
68
f2498c4e 69void wxDCFactory::Set(wxDCFactory *factory)
2970ae54 70{
f2498c4e 71 delete m_factory;
2970ae54 72
f2498c4e 73 m_factory = factory;
2970ae54
RR
74}
75
f0875501 76wxDCFactory *wxDCFactory::Get()
2970ae54 77{
f2498c4e
VZ
78 if ( !m_factory )
79 m_factory = new wxNativeDCFactory;
2970ae54 80
f2498c4e 81 return m_factory;
2970ae54
RR
82}
83
f2498c4e
VZ
84class wxDCFactoryCleanupModule : public wxModule
85{
86public:
87 virtual bool OnInit() { return true; }
88 virtual void OnExit() { wxDCFactory::Set(NULL); }
89
90private:
91 DECLARE_DYNAMIC_CLASS(wxDCFactoryCleanupModule)
92};
93
94IMPLEMENT_DYNAMIC_CLASS(wxDCFactoryCleanupModule, wxModule)
95
2970ae54
RR
96//-----------------------------------------------------------------------------
97// wxNativeDCFactory
98//-----------------------------------------------------------------------------
99
888dde65 100wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner )
f0875501 101{
888dde65 102 return new wxWindowDCImpl( owner );
2970ae54
RR
103}
104
888dde65 105wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner, wxWindow *window )
f0875501 106{
888dde65 107 return new wxWindowDCImpl( owner, window );
2970ae54
RR
108}
109
888dde65
RR
110wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner )
111{
112 return new wxClientDCImpl( owner );
2970ae54
RR
113}
114
888dde65
RR
115wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner, wxWindow *window )
116{
117 return new wxClientDCImpl( owner, window );
2970ae54
RR
118}
119
888dde65
RR
120wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner )
121{
122 return new wxPaintDCImpl( owner );
2970ae54
RR
123}
124
888dde65
RR
125wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner, wxWindow *window )
126{
127 return new wxPaintDCImpl( owner, window );
2970ae54
RR
128}
129
888dde65
RR
130wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner )
131{
132 return new wxMemoryDCImpl( owner );
2970ae54
RR
133}
134
888dde65
RR
135wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxBitmap &bitmap )
136{
137 return new wxMemoryDCImpl( owner, bitmap );
2970ae54
RR
138}
139
888dde65
RR
140wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxDC *dc )
141{
142 return new wxMemoryDCImpl( owner, dc );
ab171e95
RR
143}
144
888dde65
RR
145wxDCImpl* wxNativeDCFactory::CreateScreenDC( wxScreenDC *owner )
146{
147 return new wxScreenDCImpl( owner );
2970ae54
RR
148}
149
6b4f4d47 150#if wxUSE_PRINTING_ARCHITECTURE
888dde65 151wxDCImpl *wxNativeDCFactory::CreatePrinterDC( wxPrinterDC *owner, const wxPrintData &data )
c8ddadff 152{
4f37154e 153 wxPrintFactory *factory = wxPrintFactory::GetFactory();
888dde65 154 return factory->CreatePrinterDCImpl( owner, data );
c8ddadff 155}
6b4f4d47 156#endif
c8ddadff 157
2970ae54
RR
158//-----------------------------------------------------------------------------
159// wxWindowDC
160//-----------------------------------------------------------------------------
161
f0875501 162IMPLEMENT_ABSTRACT_CLASS(wxWindowDC, wxDC)
2970ae54 163
f0875501
VZ
164wxWindowDC::wxWindowDC(wxWindow *win)
165 : wxDC(wxDCFactory::Get()->CreateWindowDC(this, win))
2970ae54 166{
2970ae54
RR
167}
168
169//-----------------------------------------------------------------------------
170// wxClientDC
171//-----------------------------------------------------------------------------
172
f0875501 173IMPLEMENT_ABSTRACT_CLASS(wxClientDC, wxWindowDC)
2970ae54 174
f0875501
VZ
175wxClientDC::wxClientDC(wxWindow *win)
176 : wxWindowDC(wxDCFactory::Get()->CreateClientDC(this, win))
2970ae54 177{
2970ae54
RR
178}
179
2970ae54
RR
180//-----------------------------------------------------------------------------
181// wxMemoryDC
182//-----------------------------------------------------------------------------
183
184IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC)
185
186wxMemoryDC::wxMemoryDC()
f0875501 187 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this))
2970ae54 188{
2970ae54
RR
189}
190
f0875501
VZ
191wxMemoryDC::wxMemoryDC(wxBitmap& bitmap)
192 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, bitmap))
2970ae54 193{
2970ae54
RR
194}
195
f0875501
VZ
196wxMemoryDC::wxMemoryDC(wxDC *dc)
197 : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, dc))
2970ae54 198{
ab171e95
RR
199}
200
201void wxMemoryDC::SelectObject(wxBitmap& bmp)
202{
203 // make sure that the given wxBitmap is not sharing its data with other
204 // wxBitmap instances as its contents will be modified by any drawing
205 // operation done on this DC
206 if (bmp.IsOk())
207 bmp.UnShare();
208
4f37154e 209 GetImpl()->DoSelect(bmp);
ab171e95
RR
210}
211
212void wxMemoryDC::SelectObjectAsSource(const wxBitmap& bmp)
213{
4f37154e 214 GetImpl()->DoSelect(bmp);
2970ae54 215}
ab171e95
RR
216
217const wxBitmap& wxMemoryDC::GetSelectedBitmap() const
218{
4f37154e 219 return GetImpl()->GetSelectedBitmap();
ab171e95
RR
220}
221
222wxBitmap& wxMemoryDC::GetSelectedBitmap()
223{
4f37154e 224 return GetImpl()->GetSelectedBitmap();
ab171e95
RR
225}
226
f0875501 227
2970ae54
RR
228//-----------------------------------------------------------------------------
229// wxPaintDC
230//-----------------------------------------------------------------------------
231
f0875501 232IMPLEMENT_ABSTRACT_CLASS(wxPaintDC, wxClientDC)
2970ae54 233
f0875501
VZ
234wxPaintDC::wxPaintDC(wxWindow *win)
235 : wxClientDC(wxDCFactory::Get()->CreatePaintDC(this, win))
2970ae54 236{
2970ae54
RR
237}
238
ab171e95
RR
239//-----------------------------------------------------------------------------
240// wxScreenDC
241//-----------------------------------------------------------------------------
242
243IMPLEMENT_DYNAMIC_CLASS(wxScreenDC, wxWindowDC)
244
245wxScreenDC::wxScreenDC()
f0875501 246 : wxDC(wxDCFactory::Get()->CreateScreenDC(this))
ab171e95 247{
2970ae54
RR
248}
249
4f37154e
RR
250//-----------------------------------------------------------------------------
251// wxPrinterDC
252//-----------------------------------------------------------------------------
253
6b4f4d47
RR
254#if wxUSE_PRINTING_ARCHITECTURE
255
4f37154e
RR
256IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC, wxDC)
257
258wxPrinterDC::wxPrinterDC()
f0875501 259 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, wxPrintData()))
4f37154e 260{
4f37154e
RR
261}
262
f0875501
VZ
263wxPrinterDC::wxPrinterDC(const wxPrintData& data)
264 : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, data))
38dd8ed4
RR
265{
266}
267
268wxRect wxPrinterDC::GetPaperRect()
269{
270 return GetImpl()->GetPaperRect();
271}
272
273int wxPrinterDC::GetResolution()
274{
275 return GetImpl()->GetResolution();
276}
277
f0875501 278#endif // wxUSE_PRINTING_ARCHITECTURE
38dd8ed4 279
2970ae54 280//-----------------------------------------------------------------------------
888dde65 281// wxDCImpl
2970ae54
RR
282//-----------------------------------------------------------------------------
283
888dde65 284IMPLEMENT_ABSTRACT_CLASS(wxDCImpl, wxObject)
2970ae54 285
888dde65
RR
286wxDCImpl::wxDCImpl( wxDC *owner )
287 : m_window(NULL)
288 , m_colour(wxColourDisplay())
2970ae54
RR
289 , m_ok(true)
290 , m_clipping(false)
291 , m_isInteractive(0)
292 , m_isBBoxValid(false)
293 , m_logicalOriginX(0), m_logicalOriginY(0)
294 , m_deviceOriginX(0), m_deviceOriginY(0)
295 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
296 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
297 , m_userScaleX(1.0), m_userScaleY(1.0)
298 , m_scaleX(1.0), m_scaleY(1.0)
299 , m_signX(1), m_signY(1)
300 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
301 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
302 , m_logicalFunction(wxCOPY)
303 , m_backgroundMode(wxTRANSPARENT)
304 , m_mappingMode(wxMM_TEXT)
305 , m_pen()
306 , m_brush()
307 , m_backgroundBrush(*wxTRANSPARENT_BRUSH)
308 , m_textForegroundColour(*wxBLACK)
309 , m_textBackgroundColour(*wxWHITE)
310 , m_font()
311#if wxUSE_PALETTE
312 , m_palette()
313 , m_hasCustomPalette(false)
314#endif // wxUSE_PALETTE
315{
316 m_owner = owner;
317
318 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
319 (double)wxGetDisplaySizeMM().GetWidth();
320 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
321 (double)wxGetDisplaySizeMM().GetHeight();
f0875501 322
2970ae54
RR
323 ResetBoundingBox();
324 ResetClipping();
325}
326
888dde65 327wxDCImpl::~wxDCImpl()
2970ae54
RR
328{
329}
330
2970ae54
RR
331// ----------------------------------------------------------------------------
332// coordinate conversions and transforms
333// ----------------------------------------------------------------------------
334
888dde65 335wxCoord wxDCImpl::DeviceToLogicalX(wxCoord x) const
2970ae54
RR
336{
337 return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX;
338}
339
888dde65 340wxCoord wxDCImpl::DeviceToLogicalY(wxCoord y) const
2970ae54
RR
341{
342 return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY;
343}
344
888dde65 345wxCoord wxDCImpl::DeviceToLogicalXRel(wxCoord x) const
2970ae54
RR
346{
347 return wxRound((double)(x) / m_scaleX);
348}
349
888dde65 350wxCoord wxDCImpl::DeviceToLogicalYRel(wxCoord y) const
2970ae54
RR
351{
352 return wxRound((double)(y) / m_scaleY);
353}
354
888dde65 355wxCoord wxDCImpl::LogicalToDeviceX(wxCoord x) const
2970ae54 356{
02255e07 357 return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX * m_signY + m_deviceLocalOriginX;
2970ae54
RR
358}
359
888dde65 360wxCoord wxDCImpl::LogicalToDeviceY(wxCoord y) const
2970ae54 361{
02255e07 362 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY * m_signY + m_deviceLocalOriginY;
2970ae54
RR
363}
364
888dde65 365wxCoord wxDCImpl::LogicalToDeviceXRel(wxCoord x) const
2970ae54
RR
366{
367 return wxRound((double)(x) * m_scaleX);
368}
369
888dde65 370wxCoord wxDCImpl::LogicalToDeviceYRel(wxCoord y) const
2970ae54
RR
371{
372 return wxRound((double)(y) * m_scaleY);
373}
374
888dde65 375void wxDCImpl::ComputeScaleAndOrigin()
2970ae54
RR
376{
377 m_scaleX = m_logicalScaleX * m_userScaleX;
378 m_scaleY = m_logicalScaleY * m_userScaleY;
379}
380
888dde65 381void wxDCImpl::SetMapMode( int mode )
2970ae54
RR
382{
383 switch (mode)
384 {
385 case wxMM_TWIPS:
386 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
387 break;
388 case wxMM_POINTS:
389 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
390 break;
391 case wxMM_METRIC:
392 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
393 break;
394 case wxMM_LOMETRIC:
395 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
396 break;
397 default:
398 case wxMM_TEXT:
399 SetLogicalScale( 1.0, 1.0 );
400 break;
401 }
402 m_mappingMode = mode;
403}
404
888dde65 405void wxDCImpl::SetUserScale( double x, double y )
2970ae54
RR
406{
407 // allow negative ? -> no
408 m_userScaleX = x;
409 m_userScaleY = y;
410 ComputeScaleAndOrigin();
411}
412
888dde65 413void wxDCImpl::SetLogicalScale( double x, double y )
2970ae54
RR
414{
415 // allow negative ?
416 m_logicalScaleX = x;
417 m_logicalScaleY = y;
418 ComputeScaleAndOrigin();
419}
420
888dde65 421void wxDCImpl::SetLogicalOrigin( wxCoord x, wxCoord y )
2970ae54
RR
422{
423 m_logicalOriginX = x * m_signX;
424 m_logicalOriginY = y * m_signY;
425 ComputeScaleAndOrigin();
426}
427
888dde65 428void wxDCImpl::SetDeviceOrigin( wxCoord x, wxCoord y )
2970ae54
RR
429{
430 m_deviceOriginX = x;
431 m_deviceOriginY = y;
432 ComputeScaleAndOrigin();
433}
434
888dde65 435void wxDCImpl::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
2970ae54
RR
436{
437 m_deviceLocalOriginX = x;
438 m_deviceLocalOriginY = y;
439 ComputeScaleAndOrigin();
440}
441
888dde65 442void wxDCImpl::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
2970ae54
RR
443{
444 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
02255e07 445 // wxWidgets 2.9: no longer override it
2970ae54
RR
446 m_signX = (xLeftRight ? 1 : -1);
447 m_signY = (yBottomUp ? -1 : 1);
448 ComputeScaleAndOrigin();
449}
450
451
452// Each element of the widths array will be the width of the string up to and
453// including the corresponding character in text. This is the generic
454// implementation, the port-specific classes should do this with native APIs
455// if available and if faster. Note: pango_layout_index_to_pos is much slower
456// than calling GetTextExtent!!
457
458#define FWC_SIZE 256
459
460class FontWidthCache
461{
462public:
463 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
464 ~FontWidthCache() { delete []m_widths; }
465
466 void Reset()
467 {
468 if (!m_widths)
469 m_widths = new int[FWC_SIZE];
470
471 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
472 }
473
474 wxFont m_font;
475 double m_scaleX;
476 int *m_widths;
477};
478
479static FontWidthCache s_fontWidthCache;
480
888dde65 481bool wxDCImpl::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
2970ae54
RR
482{
483 int totalWidth = 0;
484
485 const size_t len = text.length();
486 widths.Empty();
487 widths.Add(0, len);
488
489 // reset the cache if font or horizontal scale have changed
490 if ( !s_fontWidthCache.m_widths ||
491 !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) ||
492 (s_fontWidthCache.m_font != GetFont()) )
493 {
494 s_fontWidthCache.Reset();
495 s_fontWidthCache.m_font = GetFont();
496 s_fontWidthCache.m_scaleX = m_scaleX;
497 }
498
499 // Calculate the position of each character based on the widths of
500 // the previous characters
501 int w, h;
502 for ( size_t i = 0; i < len; i++ )
503 {
504 const wxChar c = text[i];
505 unsigned int c_int = (unsigned int)c;
506
507 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
508 {
509 w = s_fontWidthCache.m_widths[c_int];
510 }
511 else
512 {
ab171e95 513 DoGetTextExtent(c, &w, &h);
2970ae54
RR
514 if (c_int < FWC_SIZE)
515 s_fontWidthCache.m_widths[c_int] = w;
516 }
517
518 totalWidth += w;
519 widths[i] = totalWidth;
520 }
521
522 return true;
523}
524
888dde65 525void wxDCImpl::GetMultiLineTextExtent(const wxString& text,
2970ae54
RR
526 wxCoord *x,
527 wxCoord *y,
528 wxCoord *h,
529 const wxFont *font) const
530{
531 wxCoord widthTextMax = 0, widthLine,
532 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
533
534 wxString curLine;
4f37154e 535 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
2970ae54 536 {
4f37154e 537 if ( pc == text.end() || *pc == _T('\n') )
2970ae54
RR
538 {
539 if ( curLine.empty() )
540 {
541 // we can't use GetTextExtent - it will return 0 for both width
542 // and height and an empty line should count in height
543 // calculation
544
545 // assume that this line has the same height as the previous
546 // one
547 if ( !heightLineDefault )
548 heightLineDefault = heightLine;
549
550 if ( !heightLineDefault )
551 {
552 // but we don't know it yet - choose something reasonable
553 DoGetTextExtent(_T("W"), NULL, &heightLineDefault,
554 NULL, NULL, font);
555 }
556
557 heightTextTotal += heightLineDefault;
558 }
559 else
560 {
561 DoGetTextExtent(curLine, &widthLine, &heightLine,
562 NULL, NULL, font);
563 if ( widthLine > widthTextMax )
564 widthTextMax = widthLine;
565 heightTextTotal += heightLine;
566 }
567
4f37154e 568 if ( pc == text.end() )
2970ae54 569 {
4f37154e 570 break;
2970ae54 571 }
4f37154e 572 else // '\n'
2970ae54 573 {
4f37154e 574 curLine.clear();
2970ae54
RR
575 }
576 }
577 else
578 {
579 curLine += *pc;
580 }
581 }
582
583 if ( x )
584 *x = widthTextMax;
585 if ( y )
586 *y = heightTextTotal;
587 if ( h )
588 *h = heightLine;
589}
590
888dde65 591void wxDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1,
2970ae54
RR
592 wxCoord width, wxCoord height)
593{
ab171e95 594 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
2970ae54
RR
595
596 wxCoord x2 = x1 + width,
597 y2 = y1 + height;
598
599 // the pen width is calibrated to give 3 for width == height == 10
ab171e95 600 wxDCPenChanger pen( *m_owner, wxPen(GetTextForeground(), (width + height + 1)/7));
2970ae54
RR
601
602 // we're drawing a scaled version of wx/generic/tick.xpm here
603 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
604 y3 = y1 + height / 2; // y of the left tick branch
605 DoDrawLine(x1, y3, x3, y2);
606 DoDrawLine(x3, y2, x2, y1);
607
608 CalcBoundingBox(x1, y1);
609 CalcBoundingBox(x2, y2);
610}
611
612bool
888dde65 613wxDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest,
2970ae54
RR
614 wxCoord dstWidth, wxCoord dstHeight,
615 wxDC *source,
616 wxCoord xsrc, wxCoord ysrc,
617 wxCoord srcWidth, wxCoord srcHeight,
618 int rop,
619 bool useMask,
620 wxCoord xsrcMask,
621 wxCoord ysrcMask)
622{
623 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
624 _T("invalid blit size") );
625
626 // emulate the stretching by modifying the DC scale
627 double xscale = (double)srcWidth/dstWidth,
628 yscale = (double)srcHeight/dstHeight;
629
630 double xscaleOld, yscaleOld;
631 GetUserScale(&xscaleOld, &yscaleOld);
632 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
633
634 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
635 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
636 source,
637 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
638
639 SetUserScale(xscaleOld, yscaleOld);
640
641 return rc;
642}
643
888dde65 644void wxDCImpl::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset)
2970ae54
RR
645{
646 int n = list->GetCount();
647 wxPoint *points = new wxPoint[n];
648
649 int i = 0;
b0d7707b 650 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
2970ae54 651 {
b0d7707b 652 wxPoint *point = node->GetData();
2970ae54
RR
653 points[i].x = point->x;
654 points[i].y = point->y;
655 }
656
657 DoDrawLines(n, points, xoffset, yoffset);
658
659 delete [] points;
660}
661
888dde65 662void wxDCImpl::DrawPolygon(const wxPointList *list,
2970ae54
RR
663 wxCoord xoffset, wxCoord yoffset,
664 int fillStyle)
665{
666 int n = list->GetCount();
667 wxPoint *points = new wxPoint[n];
668
669 int i = 0;
b0d7707b 670 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
2970ae54 671 {
b0d7707b 672 wxPoint *point = node->GetData();
2970ae54
RR
673 points[i].x = point->x;
674 points[i].y = point->y;
675 }
676
677 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
678
679 delete [] points;
680}
681
682void
888dde65 683wxDCImpl::DoDrawPolyPolygon(int n,
2970ae54
RR
684 int count[],
685 wxPoint points[],
686 wxCoord xoffset, wxCoord yoffset,
687 int fillStyle)
688{
689 if ( n == 1 )
690 {
691 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
692 return;
693 }
694
695 int i, j, lastOfs;
696 wxPoint* pts;
697 wxPen pen;
698
699 for (i = j = lastOfs = 0; i < n; i++)
700 {
701 lastOfs = j;
702 j += count[i];
703 }
704 pts = new wxPoint[j+n-1];
705 for (i = 0; i < j; i++)
706 pts[i] = points[i];
707 for (i = 2; i <= n; i++)
708 {
709 lastOfs -= count[n-i];
710 pts[j++] = pts[lastOfs];
711 }
712
713 pen = GetPen();
714 SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT));
715 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
716 SetPen(pen);
717 for (i = j = 0; i < n; i++)
718 {
719 DoDrawLines(count[i], pts+j, xoffset, yoffset);
720 j += count[i];
721 }
722 delete[] pts;
723}
724
725#if wxUSE_SPLINES
726
888dde65 727void wxDCImpl::DoDrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
2970ae54 728{
b0d7707b 729 wxPointList point_list;
2970ae54
RR
730
731 wxPoint *point1 = new wxPoint;
732 point1->x = x1; point1->y = y1;
b0d7707b 733 point_list.Append( point1 );
2970ae54
RR
734
735 wxPoint *point2 = new wxPoint;
736 point2->x = x2; point2->y = y2;
b0d7707b 737 point_list.Append( point2 );
2970ae54
RR
738
739 wxPoint *point3 = new wxPoint;
740 point3->x = x3; point3->y = y3;
b0d7707b 741 point_list.Append( point3 );
2970ae54 742
ab171e95 743 DoDrawSpline(&point_list);
2970ae54 744
b0d7707b 745 for( wxPointList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
2970ae54 746 {
b0d7707b 747 wxPoint *p = node->GetData();
2970ae54
RR
748 delete p;
749 }
750}
751
888dde65 752void wxDCImpl::DoDrawSpline(int n, wxPoint points[])
2970ae54 753{
b0d7707b 754 wxPointList list;
2970ae54 755 for (int i =0; i < n; i++)
b0d7707b 756 list.Append( &points[i] );
2970ae54 757
ab171e95 758 DoDrawSpline(&list);
2970ae54
RR
759}
760
761// ----------------------------------- spline code ----------------------------------------
762
763void wx_quadratic_spline(double a1, double b1, double a2, double b2,
764 double a3, double b3, double a4, double b4);
765void wx_clear_stack();
766int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
767 double *y3, double *x4, double *y4);
768void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
769 double x4, double y4);
770static bool wx_spline_add_point(double x, double y);
ab171e95 771static void wx_spline_draw_point_array(wxDC *dc);
2970ae54 772
b0d7707b 773wxPointList wx_spline_point_list;
2970ae54
RR
774
775#define half(z1, z2) ((z1+z2)/2.0)
776#define THRESHOLD 5
777
778/* iterative version */
779
780void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
781 double b4)
782{
783 register double xmid, ymid;
784 double x1, y1, x2, y2, x3, y3, x4, y4;
785
786 wx_clear_stack();
787 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
788
789 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
790 xmid = (double)half(x2, x3);
791 ymid = (double)half(y2, y3);
792 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
793 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
794 wx_spline_add_point( x1, y1 );
795 wx_spline_add_point( xmid, ymid );
796 } else {
797 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
798 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
799 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
800 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
801 }
802 }
803}
804
805/* utilities used by spline drawing routines */
806
807typedef struct wx_spline_stack_struct {
808 double x1, y1, x2, y2, x3, y3, x4, y4;
809} Stack;
810
811#define SPLINE_STACK_DEPTH 20
812static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
813static Stack *wx_stack_top;
814static int wx_stack_count;
815
816void wx_clear_stack()
817{
818 wx_stack_top = wx_spline_stack;
819 wx_stack_count = 0;
820}
821
822void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
823{
824 wx_stack_top->x1 = x1;
825 wx_stack_top->y1 = y1;
826 wx_stack_top->x2 = x2;
827 wx_stack_top->y2 = y2;
828 wx_stack_top->x3 = x3;
829 wx_stack_top->y3 = y3;
830 wx_stack_top->x4 = x4;
831 wx_stack_top->y4 = y4;
832 wx_stack_top++;
833 wx_stack_count++;
834}
835
836int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
837 double *x3, double *y3, double *x4, double *y4)
838{
839 if (wx_stack_count == 0)
840 return (0);
841 wx_stack_top--;
842 wx_stack_count--;
843 *x1 = wx_stack_top->x1;
844 *y1 = wx_stack_top->y1;
845 *x2 = wx_stack_top->x2;
846 *y2 = wx_stack_top->y2;
847 *x3 = wx_stack_top->x3;
848 *y3 = wx_stack_top->y3;
849 *x4 = wx_stack_top->x4;
850 *y4 = wx_stack_top->y4;
851 return (1);
852}
853
854static bool wx_spline_add_point(double x, double y)
855{
b0d7707b
RR
856 wxPoint *point = new wxPoint( wxRound(x), wxRound(y) );
857 wx_spline_point_list.Append(point );
858 return true;
2970ae54
RR
859}
860
861static void wx_spline_draw_point_array(wxDC *dc)
862{
4f37154e 863 dc->DrawLines(&wx_spline_point_list, 0, 0 );
b0d7707b
RR
864 wxPointList::compatibility_iterator node = wx_spline_point_list.GetFirst();
865 while (node)
866 {
867 wxPoint *point = node->GetData();
868 delete point;
869 wx_spline_point_list.Erase(node);
870 node = wx_spline_point_list.GetFirst();
871 }
2970ae54
RR
872}
873
888dde65 874void wxDCImpl::DoDrawSpline( const wxPointList *points )
2970ae54 875{
ab171e95 876 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
2970ae54
RR
877
878 wxPoint *p;
879 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
880 double x1, y1, x2, y2;
881
b0d7707b 882 wxPointList::compatibility_iterator node = points->GetFirst();
2970ae54
RR
883 if (!node)
884 // empty list
885 return;
886
887 p = (wxPoint *)node->GetData();
888
889 x1 = p->x;
890 y1 = p->y;
891
892 node = node->GetNext();
b0d7707b 893 p = node->GetData();
2970ae54
RR
894
895 x2 = p->x;
896 y2 = p->y;
897 cx1 = (double)((x1 + x2) / 2);
898 cy1 = (double)((y1 + y2) / 2);
899 cx2 = (double)((cx1 + x2) / 2);
900 cy2 = (double)((cy1 + y2) / 2);
901
902 wx_spline_add_point(x1, y1);
903
904 while ((node = node->GetNext())
905#if !wxUSE_STL
906 != NULL
907#endif // !wxUSE_STL
908 )
909 {
b0d7707b 910 p = node->GetData();
2970ae54
RR
911 x1 = x2;
912 y1 = y2;
913 x2 = p->x;
914 y2 = p->y;
915 cx4 = (double)(x1 + x2) / 2;
916 cy4 = (double)(y1 + y2) / 2;
917 cx3 = (double)(x1 + cx4) / 2;
918 cy3 = (double)(y1 + cy4) / 2;
919
920 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
921
922 cx1 = cx4;
923 cy1 = cy4;
924 cx2 = (double)(cx1 + x2) / 2;
925 cy2 = (double)(cy1 + y2) / 2;
926 }
927
928 wx_spline_add_point( cx1, cy1 );
929 wx_spline_add_point( x2, y2 );
930
931 wx_spline_draw_point_array( m_owner );
932}
933
934#endif // wxUSE_SPLINES
935
936
2970ae54 937
888dde65 938void wxDCImpl::DoGradientFillLinear(const wxRect& rect,
2970ae54
RR
939 const wxColour& initialColour,
940 const wxColour& destColour,
941 wxDirection nDirection)
942{
943 // save old pen
944 wxPen oldPen = m_pen;
945 wxBrush oldBrush = m_brush;
946
947 wxUint8 nR1 = initialColour.Red();
948 wxUint8 nG1 = initialColour.Green();
949 wxUint8 nB1 = initialColour.Blue();
950 wxUint8 nR2 = destColour.Red();
951 wxUint8 nG2 = destColour.Green();
952 wxUint8 nB2 = destColour.Blue();
953 wxUint8 nR, nG, nB;
954
955 if ( nDirection == wxEAST || nDirection == wxWEST )
956 {
957 wxInt32 x = rect.GetWidth();
958 wxInt32 w = x; // width of area to shade
959 wxInt32 xDelta = w/256; // height of one shade bend
960 if (xDelta < 1)
961 xDelta = 1;
962
963 while (x >= xDelta)
964 {
965 x -= xDelta;
966 if (nR1 > nR2)
967 nR = nR1 - (nR1-nR2)*(w-x)/w;
968 else
969 nR = nR1 + (nR2-nR1)*(w-x)/w;
970
971 if (nG1 > nG2)
972 nG = nG1 - (nG1-nG2)*(w-x)/w;
973 else
974 nG = nG1 + (nG2-nG1)*(w-x)/w;
975
976 if (nB1 > nB2)
977 nB = nB1 - (nB1-nB2)*(w-x)/w;
978 else
979 nB = nB1 + (nB2-nB1)*(w-x)/w;
980
981 wxColour colour(nR,nG,nB);
982 SetPen(wxPen(colour, 1, wxSOLID));
983 SetBrush(wxBrush(colour));
984 if(nDirection == wxEAST)
5f77ee3b 985 DoDrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(),
2970ae54
RR
986 xDelta, rect.GetHeight());
987 else //nDirection == wxWEST
988 DoDrawRectangle(rect.GetLeft()+x, rect.GetTop(),
989 xDelta, rect.GetHeight());
990 }
991 }
992 else // nDirection == wxNORTH || nDirection == wxSOUTH
993 {
994 wxInt32 y = rect.GetHeight();
995 wxInt32 w = y; // height of area to shade
996 wxInt32 yDelta = w/255; // height of one shade bend
997 if (yDelta < 1)
998 yDelta = 1;
999
1000 while (y > 0)
1001 {
1002 y -= yDelta;
1003 if (nR1 > nR2)
1004 nR = nR1 - (nR1-nR2)*(w-y)/w;
1005 else
1006 nR = nR1 + (nR2-nR1)*(w-y)/w;
1007
1008 if (nG1 > nG2)
1009 nG = nG1 - (nG1-nG2)*(w-y)/w;
1010 else
1011 nG = nG1 + (nG2-nG1)*(w-y)/w;
1012
1013 if (nB1 > nB2)
1014 nB = nB1 - (nB1-nB2)*(w-y)/w;
1015 else
1016 nB = nB1 + (nB2-nB1)*(w-y)/w;
1017
1018 wxColour colour(nR,nG,nB);
1019 SetPen(wxPen(colour, 1, wxSOLID));
1020 SetBrush(wxBrush(colour));
1021 if(nDirection == wxNORTH)
1022 DoDrawRectangle(rect.GetLeft(), rect.GetTop()+y,
1023 rect.GetWidth(), yDelta);
1024 else //nDirection == wxSOUTH
5f77ee3b 1025 DoDrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1,
2970ae54
RR
1026 rect.GetWidth(), yDelta);
1027 }
1028 }
1029
1030 SetPen(oldPen);
1031 SetBrush(oldBrush);
1032}
1033
888dde65 1034void wxDCImpl::DoGradientFillConcentric(const wxRect& rect,
2970ae54
RR
1035 const wxColour& initialColour,
1036 const wxColour& destColour,
1037 const wxPoint& circleCenter)
1038{
1039 //save the old pen color
1040 wxColour oldPenColour = m_pen.GetColour();
1041
1042 wxUint8 nR1 = destColour.Red();
1043 wxUint8 nG1 = destColour.Green();
1044 wxUint8 nB1 = destColour.Blue();
1045 wxUint8 nR2 = initialColour.Red();
1046 wxUint8 nG2 = initialColour.Green();
1047 wxUint8 nB2 = initialColour.Blue();
1048 wxUint8 nR, nG, nB;
1049
1050
1051 //Radius
1052 wxInt32 cx = rect.GetWidth() / 2;
1053 wxInt32 cy = rect.GetHeight() / 2;
1054 wxInt32 nRadius;
1055 if (cx < cy)
1056 nRadius = cx;
1057 else
1058 nRadius = cy;
1059
1060 //Offset of circle
1061 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
1062 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
1063
1064 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
1065 {
1066 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
1067 {
1068 //get color difference
1069 wxInt32 nGradient = ((nRadius -
1070 (wxInt32)sqrt(
1071 pow((double)(x - cx - nCircleOffX), 2) +
1072 pow((double)(y - cy - nCircleOffY), 2)
1073 )) * 100) / nRadius;
1074
1075 //normalize Gradient
1076 if (nGradient < 0 )
1077 nGradient = 0;
1078
1079 //get dest colors
1080 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
1081 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
1082 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
1083
1084 //set the pixel
1085 m_pen.SetColour(wxColour(nR,nG,nB));
ab171e95 1086 DoDrawPoint(x + rect.GetLeft(), y + rect.GetTop());
2970ae54
RR
1087 }
1088 }
1089 //return old pen color
1090 m_pen.SetColour(oldPenColour);
1091}
1092
1093//-----------------------------------------------------------------------------
1094// wxDC
1095//-----------------------------------------------------------------------------
1096
1097IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
1098
ab171e95
RR
1099void wxDC::DrawLabel(const wxString& text,
1100 const wxBitmap& bitmap,
1101 const wxRect& rect,
1102 int alignment,
1103 int indexAccel,
1104 wxRect *rectBounding)
1105{
1106 // find the text position
1107 wxCoord widthText, heightText, heightLine;
1108 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
1109
1110 wxCoord width, height;
1111 if ( bitmap.Ok() )
1112 {
1113 width = widthText + bitmap.GetWidth();
1114 height = bitmap.GetHeight();
1115 }
1116 else // no bitmap
1117 {
1118 width = widthText;
1119 height = heightText;
1120 }
1121
1122 wxCoord x, y;
1123 if ( alignment & wxALIGN_RIGHT )
1124 {
1125 x = rect.GetRight() - width;
1126 }
1127 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1128 {
1129 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
1130 }
1131 else // alignment & wxALIGN_LEFT
1132 {
1133 x = rect.GetLeft();
1134 }
1135
1136 if ( alignment & wxALIGN_BOTTOM )
1137 {
1138 y = rect.GetBottom() - height;
1139 }
1140 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
1141 {
1142 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
1143 }
1144 else // alignment & wxALIGN_TOP
1145 {
1146 y = rect.GetTop();
1147 }
1148
1149 // draw the bitmap first
1150 wxCoord x0 = x,
1151 y0 = y,
1152 width0 = width;
1153 if ( bitmap.Ok() )
1154 {
1155 DrawBitmap(bitmap, x, y, true /* use mask */);
1156
1157 wxCoord offset = bitmap.GetWidth() + 4;
1158 x += offset;
1159 width -= offset;
1160
1161 y += (height - heightText) / 2;
1162 }
1163
1164 // we will draw the underscore under the accel char later
1165 wxCoord startUnderscore = 0,
1166 endUnderscore = 0,
1167 yUnderscore = 0;
1168
1169 // split the string into lines and draw each of them separately
1170 wxString curLine;
1171 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1172 {
1173 if ( *pc == _T('\n') || pc == text.end() )
1174 {
1175 int xRealStart = x; // init it here to avoid compielr warnings
1176
1177 if ( !curLine.empty() )
1178 {
1179 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1180 // wxALIGN_LEFT is 0
1181 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
1182 {
1183 wxCoord widthLine;
1184 GetTextExtent(curLine, &widthLine, NULL);
1185
1186 if ( alignment & wxALIGN_RIGHT )
1187 {
1188 xRealStart += width - widthLine;
1189 }
1190 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1191 {
1192 xRealStart += (width - widthLine) / 2;
1193 }
1194 }
1195 //else: left aligned, nothing to do
1196
1197 DrawText(curLine, xRealStart, y);
1198 }
1199
1200 y += heightLine;
1201
1202 // do we have underscore in this line? we can check yUnderscore
1203 // because it is set below to just y + heightLine if we do
1204 if ( y == yUnderscore )
1205 {
1206 // adjust the horz positions to account for the shift
1207 startUnderscore += xRealStart;
1208 endUnderscore += xRealStart;
1209 }
1210
1211 if ( pc == text.end() )
1212 break;
1213
1214 curLine.clear();
1215 }
1216 else // not end of line
1217 {
1218 if ( pc - text.begin() == indexAccel )
1219 {
1220 // remeber to draw underscore here
1221 GetTextExtent(curLine, &startUnderscore, NULL);
1222 curLine += *pc;
1223 GetTextExtent(curLine, &endUnderscore, NULL);
1224
1225 yUnderscore = y + heightLine;
1226 }
1227 else
1228 {
1229 curLine += *pc;
1230 }
1231 }
1232 }
1233
1234 // draw the underscore if found
1235 if ( startUnderscore != endUnderscore )
1236 {
1237 // it should be of the same colour as text
1238 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
1239
1240 yUnderscore--;
1241
1242 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
1243 }
1244
1245 // return bounding rect if requested
1246 if ( rectBounding )
1247 {
1248 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
1249 }
1250
1251 CalcBoundingBox(x0, y0);
1252 CalcBoundingBox(x0 + width0, y0 + height);
1253}
1254
2970ae54
RR
1255#if WXWIN_COMPATIBILITY_2_8
1256 // for compatibility with the old code when wxCoord was long everywhere
1257void wxDC::GetTextExtent(const wxString& string,
1258 long *x, long *y,
1259 long *descent,
1260 long *externalLeading,
1261 const wxFont *theFont) const
1262 {
1263 wxCoord x2, y2, descent2, externalLeading2;
1264 m_pimpl->DoGetTextExtent(string, &x2, &y2,
1265 &descent2, &externalLeading2,
1266 theFont);
1267 if ( x )
1268 *x = x2;
1269 if ( y )
1270 *y = y2;
1271 if ( descent )
1272 *descent = descent2;
1273 if ( externalLeading )
1274 *externalLeading = externalLeading2;
1275 }
1276
f0875501 1277void wxDC::GetLogicalOrigin(long *x, long *y) const
2970ae54
RR
1278 {
1279 wxCoord x2, y2;
1280 m_pimpl->DoGetLogicalOrigin(&x2, &y2);
1281 if ( x )
1282 *x = x2;
1283 if ( y )
1284 *y = y2;
1285 }
1286
f0875501 1287void wxDC::GetDeviceOrigin(long *x, long *y) const
2970ae54
RR
1288 {
1289 wxCoord x2, y2;
1290 m_pimpl->DoGetDeviceOrigin(&x2, &y2);
1291 if ( x )
1292 *x = x2;
1293 if ( y )
1294 *y = y2;
f0875501
VZ
1295 }
1296
1297void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const
2970ae54
RR
1298 {
1299 wxCoord xx,yy,ww,hh;
1300 m_pimpl->DoGetClippingBox(&xx, &yy, &ww, &hh);
1301 if (x) *x = xx;
1302 if (y) *y = yy;
1303 if (w) *w = ww;
1304 if (h) *h = hh;
f0875501
VZ
1305 }
1306
2970ae54 1307#endif // WXWIN_COMPATIBILITY_2_8