]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcbase.cpp
More border rationalisation. GetDefaultBorder is now mostly defined in base class...
[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"
653752be 31#include "wx/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS
18680f86
WS
32
33#ifndef WX_PRECOMP
34 #include "wx/math.h"
35#endif
dbe94982 36
2970ae54
RR
37
38
39#if wxUSE_NEW_DC
40
41//----------------------------------------------------------------------------
42// wxDCFactory
43//----------------------------------------------------------------------------
44
45wxDCFactory *wxDCFactory::m_factory = NULL;
46
47void wxDCFactory::SetDCFactory( wxDCFactory *factory )
48{
49 if (wxDCFactory::m_factory)
50 delete wxDCFactory::m_factory;
51
52 wxDCFactory::m_factory = factory;
53}
54
55wxDCFactory *wxDCFactory::GetFactory()
56{
57 if (!wxDCFactory::m_factory)
58 wxDCFactory::m_factory = new wxNativeDCFactory;
59
60 return wxDCFactory::m_factory;
61}
62
63//-----------------------------------------------------------------------------
64// wxNativeDCFactory
65//-----------------------------------------------------------------------------
66
ab171e95 67wxImplDC* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner )
2970ae54
RR
68{
69#if defined(__WXMSW__)
ab171e95 70 return new wxWindowsWindowImplDC( owner );
2970ae54 71#elif defined(__WXGTK20__)
ab171e95 72 return new wxGTKWindowImplDC( owner );
2970ae54 73#elif defined(__WXGTK__)
ab171e95 74 return new wxGTKWindowImplDC( owner );
2970ae54 75#elif defined(__WXMAC__)
ab171e95 76 return new wxMacWindowImplDC( owner );
2970ae54 77#elif defined(__WXCOCOA__)
ab171e95 78 return new wxCocoaWindowImplDC( owner );
2970ae54 79#elif defined(__WXMOTIF__)
ab171e95 80 return new wxMotifWindowImplDC( owner );
2970ae54 81#elif defined(__WXX11__)
ab171e95 82 return new wxX11WindowImplDC( owner );
2970ae54 83#elif defined(__WXMGL__)
ab171e95 84 return new wxMGLWindowImplDC( owner );
2970ae54 85#elif defined(__WXDFB__)
ab171e95 86 return new wxDFBWindowImplDC( owner );
2970ae54 87#elif defined(__WXPM__)
ab171e95 88 return new wxPMWindowImplDC( owner );
2970ae54 89#elif defined(__PALMOS__)
ab171e95 90 return new wxPalmWindowImplDC( owner );
2970ae54
RR
91#endif
92}
93
ab171e95 94wxImplDC* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner, wxWindow *window )
2970ae54
RR
95{
96#if defined(__WXMSW__)
ab171e95 97 return new wxWindowsWindowImplDC( owner, window );
2970ae54 98#elif defined(__WXGTK20__)
ab171e95 99 return new wxGTKWindowImplDC( owner, window );
2970ae54 100#elif defined(__WXGTK__)
ab171e95 101 return new wxGTKWindowImplDC( owner, window );
2970ae54 102#elif defined(__WXMAC__)
ab171e95 103 return new wxMacWindowImplDC( owner, window );
2970ae54 104#elif defined(__WXCOCOA__)
ab171e95 105 return new wxCocoaWindowImplDC( owner, window );
2970ae54 106#elif defined(__WXMOTIF__)
ab171e95 107 return new wxMotifWindowImplDC( owner, window );
2970ae54 108#elif defined(__WXX11__)
ab171e95 109 return new wxX11WindowImplDC( owner, window );
2970ae54 110#elif defined(__WXMGL__)
ab171e95 111 return new wxMGLWindowImplDC( owner, window );
2970ae54 112#elif defined(__WXDFB__)
ab171e95 113 return new wxDFBWindowImplDC( owner, window );
2970ae54 114#elif defined(__WXPM__)
ab171e95 115 return new wxPMWindowImplDC( owner, window );
2970ae54 116#elif defined(__PALMOS__)
ab171e95 117 return new wxPalmWindowImplDC( owner, window );
2970ae54
RR
118#endif
119}
120
ab171e95 121wxImplDC* wxNativeDCFactory::CreateClientDC( wxClientDC *owner )
2970ae54
RR
122{
123#if defined(__WXMSW__)
ab171e95 124 return new wxWindowsClientImplDC( owner );
2970ae54 125#elif defined(__WXGTK20__)
ab171e95 126 return new wxGTKClientImplDC( owner );
2970ae54 127#elif defined(__WXGTK__)
ab171e95 128 return new wxGTKClientImplDC( owner );
2970ae54 129#elif defined(__WXMAC__)
ab171e95 130 return new wxMacClientImplDC( owner );
2970ae54 131#elif defined(__WXCOCOA__)
ab171e95 132 return new wxCocoaClientImplDC( owner );
2970ae54 133#elif defined(__WXMOTIF__)
ab171e95 134 return new wxMotifClientImplDC( owner );
2970ae54 135#elif defined(__WXX11__)
ab171e95 136 return new wxX11ClientImplDC( owner );
2970ae54 137#elif defined(__WXMGL__)
ab171e95 138 return new wxMGLClientImplDC( owner );
2970ae54 139#elif defined(__WXDFB__)
ab171e95 140 return new wxDFBClientImplDC( owner );
2970ae54 141#elif defined(__WXPM__)
ab171e95 142 return new wxPMClientImplDC( owner );
2970ae54 143#elif defined(__PALMOS__)
ab171e95 144 return new wxPalmClientImplDC( owner );
2970ae54
RR
145#endif
146}
147
ab171e95 148wxImplDC* wxNativeDCFactory::CreateClientDC( wxClientDC *owner, wxWindow *window )
2970ae54
RR
149{
150#if defined(__WXMSW__)
ab171e95 151 return new wxWindowsClientImplDC( owner, window );
2970ae54 152#elif defined(__WXGTK20__)
ab171e95 153 return new wxGTKClientImplDC( owner, window );
2970ae54 154#elif defined(__WXGTK__)
ab171e95 155 return new wxGTKClientImplDC( owner, window );
2970ae54 156#elif defined(__WXMAC__)
ab171e95 157 return new wxMacClientImplDC( owner, window );
2970ae54 158#elif defined(__WXCOCOA__)
ab171e95 159 return new wxCocoaClientImplDC( owner, window );
2970ae54 160#elif defined(__WXMOTIF__)
ab171e95 161 return new wxMotifClientImplDC( owner, window );
2970ae54 162#elif defined(__WXX11__)
ab171e95 163 return new wxX11ClientImplDC( owner, window );
2970ae54 164#elif defined(__WXMGL__)
ab171e95 165 return new wxMGLClientImplDC( owner, window );
2970ae54 166#elif defined(__WXDFB__)
ab171e95 167 return new wxDFBClientImplDC( owner, window );
2970ae54 168#elif defined(__WXPM__)
ab171e95 169 return new wxPMClientImplDC( owner, window );
2970ae54 170#elif defined(__PALMOS__)
ab171e95 171 return new wxPalmClientImplDC( owner, window );
2970ae54
RR
172#endif
173}
174
ab171e95 175wxImplDC* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner )
2970ae54
RR
176{
177#if defined(__WXMSW__)
ab171e95 178 return new wxWindowsPaintImplDC( owner );
2970ae54 179#elif defined(__WXGTK20__)
ab171e95 180 return new wxGTKPaintImplDC( owner );
2970ae54 181#elif defined(__WXGTK__)
ab171e95 182 return new wxGTKPaintImplDC( owner );
2970ae54 183#elif defined(__WXMAC__)
ab171e95 184 return new wxMacPaintImplDC( owner );
2970ae54 185#elif defined(__WXCOCOA__)
ab171e95 186 return new wxCocoaPaintImplDC( owner );
2970ae54 187#elif defined(__WXMOTIF__)
ab171e95 188 return new wxMotifPaintImplDC( owner );
2970ae54 189#elif defined(__WXX11__)
ab171e95 190 return new wxX11PaintImplDC( owner );
2970ae54 191#elif defined(__WXMGL__)
ab171e95 192 return new wxMGLPaintImplDC( owner );
2970ae54 193#elif defined(__WXDFB__)
ab171e95 194 return new wxDFBPaintImplDC( owner );
2970ae54 195#elif defined(__WXPM__)
ab171e95 196 return new wxPMPaintImplDC( owner );
2970ae54 197#elif defined(__PALMOS__)
ab171e95 198 return new wxPalmPaintImplDC( owner );
2970ae54
RR
199#endif
200}
201
ab171e95 202wxImplDC* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner, wxWindow *window )
2970ae54
RR
203{
204#if defined(__WXMSW__)
ab171e95 205 return new wxWindowsPaintImplDC( owner, window );
2970ae54 206#elif defined(__WXGTK20__)
ab171e95 207 return new wxGTKPaintImplDC( owner, window );
2970ae54 208#elif defined(__WXGTK__)
ab171e95 209 return new wxGTKPaintImplDC( owner, window );
2970ae54 210#elif defined(__WXMAC__)
ab171e95 211 return new wxMacPaintImplDC( owner, window );
2970ae54 212#elif defined(__WXCOCOA__)
ab171e95 213 return new wxCocoaPaintImplDC( owner, window );
2970ae54 214#elif defined(__WXMOTIF__)
ab171e95 215 return new wxMotifPaintImplDC( owner, window );
2970ae54 216#elif defined(__WXX11__)
ab171e95 217 return new wxX11PaintImplDC( owner, window );
2970ae54 218#elif defined(__WXMGL__)
ab171e95 219 return new wxMGLPaintImplDC( owner, window );
2970ae54 220#elif defined(__WXDFB__)
ab171e95 221 return new wxDFBPaintImplDC( owner, window );
2970ae54 222#elif defined(__WXPM__)
ab171e95 223 return new wxPMPaintImplDC( owner, window );
2970ae54 224#elif defined(__PALMOS__)
ab171e95 225 return new wxPalmPaintImplDC( owner, window );
2970ae54
RR
226#endif
227}
228
ab171e95 229wxImplDC* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner )
2970ae54
RR
230{
231#if defined(__WXMSW__)
ab171e95 232 return new wxWindowsMemoryImplDC( owner );
2970ae54 233#elif defined(__WXGTK20__)
ab171e95 234 return new wxGTKMemoryImplDC( owner );
2970ae54 235#elif defined(__WXGTK__)
ab171e95 236 return new wxGTKMemoryImplDC( owner );
2970ae54 237#elif defined(__WXMAC__)
ab171e95 238 return new wxMacMemoryImplDC( owner );
2970ae54 239#elif defined(__WXCOCOA__)
ab171e95 240 return new wxCocoaMemoryImplDC( owner );
2970ae54 241#elif defined(__WXMOTIF__)
ab171e95 242 return new wxMotifMemoryImplDC( owner );
2970ae54 243#elif defined(__WXX11__)
ab171e95 244 return new wxX11MemoryImplDC( owner );
2970ae54 245#elif defined(__WXMGL__)
ab171e95 246 return new wxMGLMemoryImplDC( owner );
2970ae54 247#elif defined(__WXDFB__)
ab171e95 248 return new wxDFBMemoryImplDC( owner );
2970ae54 249#elif defined(__WXPM__)
ab171e95 250 return new wxPMMemoryImplDC( owner );
2970ae54 251#elif defined(__PALMOS__)
ab171e95 252 return new wxPalmMemoryImplDC( owner );
2970ae54
RR
253#endif
254}
255
ab171e95 256wxImplDC* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxBitmap &bitmap )
2970ae54
RR
257{
258#if defined(__WXMSW__)
ab171e95 259 return new wxWindowsMemoryImplDC( owner, bitmap );
2970ae54 260#elif defined(__WXGTK20__)
ab171e95 261 return new wxGTKMemoryImplDC( owner, bitmap );
2970ae54 262#elif defined(__WXGTK__)
ab171e95 263 return new wxGTKMemoryImplDC( owner, bitmap );
2970ae54 264#elif defined(__WXMAC__)
ab171e95 265 return new wxMacMemoryImplDC( owner, bitmap );
2970ae54 266#elif defined(__WXCOCOA__)
ab171e95 267 return new wxCocoaMemoryImplDC( owner, bitmap );
2970ae54 268#elif defined(__WXMOTIF__)
ab171e95 269 return new wxMotifMemoryImplDC( owner, bitmap );
2970ae54 270#elif defined(__WXX11__)
ab171e95 271 return new wxX11MemoryImplDC( owner, bitmap );
2970ae54 272#elif defined(__WXMGL__)
ab171e95 273 return new wxMGLMemoryImplDC( owner, bitmap );
2970ae54 274#elif defined(__WXDFB__)
ab171e95 275 return new wxDFBMemoryImplDC( owner, bitmap );
2970ae54 276#elif defined(__WXPM__)
ab171e95 277 return new wxPMMemoryImplDC( owner, bitmap );
2970ae54 278#elif defined(__PALMOS__)
ab171e95 279 return new wxPalmMemoryImplDC( owner, bitmap );
2970ae54
RR
280#endif
281}
282
ab171e95 283wxImplDC* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxDC *dc )
2970ae54
RR
284{
285#if defined(__WXMSW__)
ab171e95 286 return new wxWindowsMemoryImplDC( owner, dc );
2970ae54 287#elif defined(__WXGTK20__)
ab171e95 288 return new wxGTKMemoryImplDC( owner, dc );
2970ae54 289#elif defined(__WXGTK__)
ab171e95 290 return new wxGTKMemoryImplDC( owner, dc );
2970ae54 291#elif defined(__WXMAC__)
ab171e95 292 return new wxMacMemoryImplDC( owner, dc );
2970ae54 293#elif defined(__WXCOCOA__)
ab171e95 294 return new wxCocoaMemoryImplDC( owner, dc );
2970ae54 295#elif defined(__WXMOTIF__)
ab171e95 296 return new wxMotifMemoryImplDC( owner, dc );
2970ae54 297#elif defined(__WXX11__)
ab171e95 298 return new wxX11MemoryImplDC( owner, dc );
2970ae54 299#elif defined(__WXMGL__)
ab171e95 300 return new wxMGLMemoryImplDC( owner, dc );
2970ae54 301#elif defined(__WXDFB__)
ab171e95 302 return new wxDFBMemoryImplDC( owner, dc );
2970ae54 303#elif defined(__WXPM__)
ab171e95 304 return new wxPMMemoryImplDC( owner, dc );
2970ae54 305#elif defined(__PALMOS__)
ab171e95
RR
306 return new wxPalmMemoryImplDC( owner, dc );
307#endif
308}
309
310wxImplDC* wxNativeDCFactory::CreateScreenDC( wxScreenDC *owner )
311{
312#if defined(__WXMSW__)
313 return new wxWindowsScreenImplDC( owner );
314#elif defined(__WXGTK20__)
315 return new wxGTKScreenImplDC( owner );
316#elif defined(__WXGTK__)
317 return new wxGTKScreenImplDC( owner );
318#elif defined(__WXMAC__)
319 return new wxMacScreenImplDC( owner );
320#elif defined(__WXCOCOA__)
321 return new wxCocoaScreenImplDC( owner );
322#elif defined(__WXMOTIF__)
323 return new wxMotifScreenImplDC( owner );
324#elif defined(__WXX11__)
325 return new wxX11ScreenImplDC( owner );
326#elif defined(__WXMGL__)
327 return new wxMGLScreenImplDC( owner );
328#elif defined(__WXDFB__)
329 return new wxDFBScreenImplDC( owner );
330#elif defined(__WXPM__)
331 return new wxPMScreenImplDC( owner );
332#elif defined(__PALMOS__)
333 return new wxPalmScreenImplDC( owner );
2970ae54
RR
334#endif
335}
336
337//-----------------------------------------------------------------------------
338// wxWindowDC
339//-----------------------------------------------------------------------------
340
341IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
342
ab171e95 343wxWindowDC::wxWindowDC()
2970ae54
RR
344{
345 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 346 m_pimpl = factory->CreateWindowDC( this );
2970ae54
RR
347}
348
ab171e95 349wxWindowDC::wxWindowDC( wxWindow *win )
2970ae54
RR
350{
351 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 352 m_pimpl = factory->CreateWindowDC( this, win );
2970ae54
RR
353}
354
355//-----------------------------------------------------------------------------
356// wxClientDC
357//-----------------------------------------------------------------------------
358
359IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxDC)
360
361wxClientDC::wxClientDC()
362{
363 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 364 m_pimpl = factory->CreateClientDC( this );
2970ae54
RR
365}
366
367wxClientDC::wxClientDC( wxWindow *win )
368{
369 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 370 m_pimpl = factory->CreateClientDC( this, win );
2970ae54
RR
371}
372
373//-----------------------------------------------------------------------------
374// wxMemoryDC
375//-----------------------------------------------------------------------------
376
377IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC)
378
379wxMemoryDC::wxMemoryDC()
380{
381 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 382 m_pimpl = factory->CreateMemoryDC( this );
2970ae54
RR
383}
384
385wxMemoryDC::wxMemoryDC( wxBitmap& bitmap )
386{
387 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 388 m_pimpl = factory->CreateMemoryDC( this, bitmap );
2970ae54
RR
389}
390
391wxMemoryDC::wxMemoryDC( wxDC *dc )
392{
393 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95
RR
394 m_pimpl = factory->CreateMemoryDC( this, dc );
395}
396
397void wxMemoryDC::SelectObject(wxBitmap& bmp)
398{
399 // make sure that the given wxBitmap is not sharing its data with other
400 // wxBitmap instances as its contents will be modified by any drawing
401 // operation done on this DC
402 if (bmp.IsOk())
403 bmp.UnShare();
404
405#ifdef __WXGTK__
406 wxGTKMemoryImplDC *mem_pimpl = wxDynamicCast( m_pimpl, wxGTKMemoryImplDC );
407#else
408 // TODO
409#endif
410 if (mem_pimpl)
411 mem_pimpl->DoSelect(bmp);
412}
413
414void wxMemoryDC::SelectObjectAsSource(const wxBitmap& bmp)
415{
416#ifdef __WXGTK__
417 wxGTKMemoryImplDC *mem_pimpl = wxDynamicCast( m_pimpl, wxGTKMemoryImplDC );
418#else
419 // TODO
420#endif
421 mem_pimpl->DoSelect(bmp);
2970ae54 422}
ab171e95
RR
423
424const wxBitmap& wxMemoryDC::GetSelectedBitmap() const
425{
426#ifdef __WXGTK__
427 wxGTKMemoryImplDC *mem_pimpl = wxDynamicCast( m_pimpl, wxGTKMemoryImplDC );
428#else
429 // TODO
430#endif
431 if (mem_pimpl)
432 return mem_pimpl->DoGetSelectedBitmap();
433
434 return wxNullBitmap;
435}
436
437wxBitmap& wxMemoryDC::GetSelectedBitmap()
438{
439#ifdef __WXGTK__
440 wxGTKMemoryImplDC *mem_pimpl = wxDynamicCast( m_pimpl, wxGTKMemoryImplDC );
441#else
442 // TODO
443#endif
444
445 if (mem_pimpl)
446 return mem_pimpl->DoGetSelectedBitmap();
447
448 return wxNullBitmap;
449}
450
2970ae54
RR
451
452//-----------------------------------------------------------------------------
453// wxPaintDC
454//-----------------------------------------------------------------------------
455
456IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxDC)
457
458wxPaintDC::wxPaintDC()
459{
460 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 461 m_pimpl = factory->CreatePaintDC( this );
2970ae54
RR
462}
463
464wxPaintDC::wxPaintDC( wxWindow *win )
465{
466 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95
RR
467 m_pimpl = factory->CreatePaintDC( this, win );
468}
469
470//-----------------------------------------------------------------------------
471// wxScreenDC
472//-----------------------------------------------------------------------------
473
474IMPLEMENT_DYNAMIC_CLASS(wxScreenDC, wxWindowDC)
475
476wxScreenDC::wxScreenDC()
477{
478 wxDCFactory *factory = wxDCFactory::GetFactory();
479 m_pimpl = factory->CreateScreenDC( this );
2970ae54
RR
480}
481
482//-----------------------------------------------------------------------------
483// wxImplDC
484//-----------------------------------------------------------------------------
485
486IMPLEMENT_ABSTRACT_CLASS(wxImplDC, wxObject)
487
488wxImplDC::wxImplDC( wxDC *owner )
489 : m_colour(wxColourDisplay())
490 , m_ok(true)
491 , m_clipping(false)
492 , m_isInteractive(0)
493 , m_isBBoxValid(false)
494 , m_logicalOriginX(0), m_logicalOriginY(0)
495 , m_deviceOriginX(0), m_deviceOriginY(0)
496 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
497 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
498 , m_userScaleX(1.0), m_userScaleY(1.0)
499 , m_scaleX(1.0), m_scaleY(1.0)
500 , m_signX(1), m_signY(1)
501 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
502 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
503 , m_logicalFunction(wxCOPY)
504 , m_backgroundMode(wxTRANSPARENT)
505 , m_mappingMode(wxMM_TEXT)
506 , m_pen()
507 , m_brush()
508 , m_backgroundBrush(*wxTRANSPARENT_BRUSH)
509 , m_textForegroundColour(*wxBLACK)
510 , m_textBackgroundColour(*wxWHITE)
511 , m_font()
512#if wxUSE_PALETTE
513 , m_palette()
514 , m_hasCustomPalette(false)
515#endif // wxUSE_PALETTE
516{
517 m_owner = owner;
518
519 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
520 (double)wxGetDisplaySizeMM().GetWidth();
521 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
522 (double)wxGetDisplaySizeMM().GetHeight();
523
524 ResetBoundingBox();
525 ResetClipping();
526}
527
528wxImplDC::~wxImplDC()
529{
530}
531
2970ae54
RR
532// ----------------------------------------------------------------------------
533// coordinate conversions and transforms
534// ----------------------------------------------------------------------------
535
536wxCoord wxImplDC::DeviceToLogicalX(wxCoord x) const
537{
538 return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX;
539}
540
541wxCoord wxImplDC::DeviceToLogicalY(wxCoord y) const
542{
543 return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY;
544}
545
546wxCoord wxImplDC::DeviceToLogicalXRel(wxCoord x) const
547{
548 return wxRound((double)(x) / m_scaleX);
549}
550
551wxCoord wxImplDC::DeviceToLogicalYRel(wxCoord y) const
552{
553 return wxRound((double)(y) / m_scaleY);
554}
555
556wxCoord wxImplDC::LogicalToDeviceX(wxCoord x) const
557{
02255e07 558 return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX * m_signY + m_deviceLocalOriginX;
2970ae54
RR
559}
560
561wxCoord wxImplDC::LogicalToDeviceY(wxCoord y) const
562{
02255e07 563 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY * m_signY + m_deviceLocalOriginY;
2970ae54
RR
564}
565
566wxCoord wxImplDC::LogicalToDeviceXRel(wxCoord x) const
567{
568 return wxRound((double)(x) * m_scaleX);
569}
570
571wxCoord wxImplDC::LogicalToDeviceYRel(wxCoord y) const
572{
573 return wxRound((double)(y) * m_scaleY);
574}
575
576void wxImplDC::ComputeScaleAndOrigin()
577{
578 m_scaleX = m_logicalScaleX * m_userScaleX;
579 m_scaleY = m_logicalScaleY * m_userScaleY;
580}
581
582void wxImplDC::SetMapMode( int mode )
583{
584 switch (mode)
585 {
586 case wxMM_TWIPS:
587 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
588 break;
589 case wxMM_POINTS:
590 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
591 break;
592 case wxMM_METRIC:
593 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
594 break;
595 case wxMM_LOMETRIC:
596 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
597 break;
598 default:
599 case wxMM_TEXT:
600 SetLogicalScale( 1.0, 1.0 );
601 break;
602 }
603 m_mappingMode = mode;
604}
605
606void wxImplDC::SetUserScale( double x, double y )
607{
608 // allow negative ? -> no
609 m_userScaleX = x;
610 m_userScaleY = y;
611 ComputeScaleAndOrigin();
612}
613
614void wxImplDC::SetLogicalScale( double x, double y )
615{
616 // allow negative ?
617 m_logicalScaleX = x;
618 m_logicalScaleY = y;
619 ComputeScaleAndOrigin();
620}
621
622void wxImplDC::SetLogicalOrigin( wxCoord x, wxCoord y )
623{
624 m_logicalOriginX = x * m_signX;
625 m_logicalOriginY = y * m_signY;
626 ComputeScaleAndOrigin();
627}
628
629void wxImplDC::SetDeviceOrigin( wxCoord x, wxCoord y )
630{
631 m_deviceOriginX = x;
632 m_deviceOriginY = y;
633 ComputeScaleAndOrigin();
634}
635
636void wxImplDC::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
637{
638 m_deviceLocalOriginX = x;
639 m_deviceLocalOriginY = y;
640 ComputeScaleAndOrigin();
641}
642
643void wxImplDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
644{
645 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
02255e07 646 // wxWidgets 2.9: no longer override it
2970ae54
RR
647 m_signX = (xLeftRight ? 1 : -1);
648 m_signY = (yBottomUp ? -1 : 1);
649 ComputeScaleAndOrigin();
650}
651
652
653// Each element of the widths array will be the width of the string up to and
654// including the corresponding character in text. This is the generic
655// implementation, the port-specific classes should do this with native APIs
656// if available and if faster. Note: pango_layout_index_to_pos is much slower
657// than calling GetTextExtent!!
658
659#define FWC_SIZE 256
660
661class FontWidthCache
662{
663public:
664 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
665 ~FontWidthCache() { delete []m_widths; }
666
667 void Reset()
668 {
669 if (!m_widths)
670 m_widths = new int[FWC_SIZE];
671
672 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
673 }
674
675 wxFont m_font;
676 double m_scaleX;
677 int *m_widths;
678};
679
680static FontWidthCache s_fontWidthCache;
681
682bool wxImplDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
683{
684 int totalWidth = 0;
685
686 const size_t len = text.length();
687 widths.Empty();
688 widths.Add(0, len);
689
690 // reset the cache if font or horizontal scale have changed
691 if ( !s_fontWidthCache.m_widths ||
692 !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) ||
693 (s_fontWidthCache.m_font != GetFont()) )
694 {
695 s_fontWidthCache.Reset();
696 s_fontWidthCache.m_font = GetFont();
697 s_fontWidthCache.m_scaleX = m_scaleX;
698 }
699
700 // Calculate the position of each character based on the widths of
701 // the previous characters
702 int w, h;
703 for ( size_t i = 0; i < len; i++ )
704 {
705 const wxChar c = text[i];
706 unsigned int c_int = (unsigned int)c;
707
708 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
709 {
710 w = s_fontWidthCache.m_widths[c_int];
711 }
712 else
713 {
ab171e95 714 DoGetTextExtent(c, &w, &h);
2970ae54
RR
715 if (c_int < FWC_SIZE)
716 s_fontWidthCache.m_widths[c_int] = w;
717 }
718
719 totalWidth += w;
720 widths[i] = totalWidth;
721 }
722
723 return true;
724}
725
726void wxImplDC::GetMultiLineTextExtent(const wxString& text,
727 wxCoord *x,
728 wxCoord *y,
729 wxCoord *h,
730 const wxFont *font) const
731{
732 wxCoord widthTextMax = 0, widthLine,
733 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
734
735 wxString curLine;
736 for ( const wxChar *pc = text; ; pc++ )
737 {
738 if ( *pc == _T('\n') || *pc == _T('\0') )
739 {
740 if ( curLine.empty() )
741 {
742 // we can't use GetTextExtent - it will return 0 for both width
743 // and height and an empty line should count in height
744 // calculation
745
746 // assume that this line has the same height as the previous
747 // one
748 if ( !heightLineDefault )
749 heightLineDefault = heightLine;
750
751 if ( !heightLineDefault )
752 {
753 // but we don't know it yet - choose something reasonable
754 DoGetTextExtent(_T("W"), NULL, &heightLineDefault,
755 NULL, NULL, font);
756 }
757
758 heightTextTotal += heightLineDefault;
759 }
760 else
761 {
762 DoGetTextExtent(curLine, &widthLine, &heightLine,
763 NULL, NULL, font);
764 if ( widthLine > widthTextMax )
765 widthTextMax = widthLine;
766 heightTextTotal += heightLine;
767 }
768
769 if ( *pc == _T('\n') )
770 {
771 curLine.clear();
772 }
773 else
774 {
775 // the end of string
776 break;
777 }
778 }
779 else
780 {
781 curLine += *pc;
782 }
783 }
784
785 if ( x )
786 *x = widthTextMax;
787 if ( y )
788 *y = heightTextTotal;
789 if ( h )
790 *h = heightLine;
791}
792
793void wxImplDC::DoDrawCheckMark(wxCoord x1, wxCoord y1,
794 wxCoord width, wxCoord height)
795{
ab171e95 796 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
2970ae54
RR
797
798 wxCoord x2 = x1 + width,
799 y2 = y1 + height;
800
801 // the pen width is calibrated to give 3 for width == height == 10
ab171e95 802 wxDCPenChanger pen( *m_owner, wxPen(GetTextForeground(), (width + height + 1)/7));
2970ae54
RR
803
804 // we're drawing a scaled version of wx/generic/tick.xpm here
805 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
806 y3 = y1 + height / 2; // y of the left tick branch
807 DoDrawLine(x1, y3, x3, y2);
808 DoDrawLine(x3, y2, x2, y1);
809
810 CalcBoundingBox(x1, y1);
811 CalcBoundingBox(x2, y2);
812}
813
814bool
815wxImplDC::DoStretchBlit(wxCoord xdest, wxCoord ydest,
816 wxCoord dstWidth, wxCoord dstHeight,
817 wxDC *source,
818 wxCoord xsrc, wxCoord ysrc,
819 wxCoord srcWidth, wxCoord srcHeight,
820 int rop,
821 bool useMask,
822 wxCoord xsrcMask,
823 wxCoord ysrcMask)
824{
825 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
826 _T("invalid blit size") );
827
828 // emulate the stretching by modifying the DC scale
829 double xscale = (double)srcWidth/dstWidth,
830 yscale = (double)srcHeight/dstHeight;
831
832 double xscaleOld, yscaleOld;
833 GetUserScale(&xscaleOld, &yscaleOld);
834 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
835
836 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
837 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
838 source,
839 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
840
841 SetUserScale(xscaleOld, yscaleOld);
842
843 return rc;
844}
845
b0d7707b 846void wxImplDC::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset)
2970ae54
RR
847{
848 int n = list->GetCount();
849 wxPoint *points = new wxPoint[n];
850
851 int i = 0;
b0d7707b 852 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
2970ae54 853 {
b0d7707b 854 wxPoint *point = node->GetData();
2970ae54
RR
855 points[i].x = point->x;
856 points[i].y = point->y;
857 }
858
859 DoDrawLines(n, points, xoffset, yoffset);
860
861 delete [] points;
862}
863
b0d7707b 864void wxImplDC::DrawPolygon(const wxPointList *list,
2970ae54
RR
865 wxCoord xoffset, wxCoord yoffset,
866 int fillStyle)
867{
868 int n = list->GetCount();
869 wxPoint *points = new wxPoint[n];
870
871 int i = 0;
b0d7707b 872 for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
2970ae54 873 {
b0d7707b 874 wxPoint *point = node->GetData();
2970ae54
RR
875 points[i].x = point->x;
876 points[i].y = point->y;
877 }
878
879 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
880
881 delete [] points;
882}
883
884void
885wxImplDC::DoDrawPolyPolygon(int n,
886 int count[],
887 wxPoint points[],
888 wxCoord xoffset, wxCoord yoffset,
889 int fillStyle)
890{
891 if ( n == 1 )
892 {
893 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
894 return;
895 }
896
897 int i, j, lastOfs;
898 wxPoint* pts;
899 wxPen pen;
900
901 for (i = j = lastOfs = 0; i < n; i++)
902 {
903 lastOfs = j;
904 j += count[i];
905 }
906 pts = new wxPoint[j+n-1];
907 for (i = 0; i < j; i++)
908 pts[i] = points[i];
909 for (i = 2; i <= n; i++)
910 {
911 lastOfs -= count[n-i];
912 pts[j++] = pts[lastOfs];
913 }
914
915 pen = GetPen();
916 SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT));
917 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
918 SetPen(pen);
919 for (i = j = 0; i < n; i++)
920 {
921 DoDrawLines(count[i], pts+j, xoffset, yoffset);
922 j += count[i];
923 }
924 delete[] pts;
925}
926
927#if wxUSE_SPLINES
928
ab171e95 929void wxImplDC::DoDrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
2970ae54 930{
b0d7707b 931 wxPointList point_list;
2970ae54
RR
932
933 wxPoint *point1 = new wxPoint;
934 point1->x = x1; point1->y = y1;
b0d7707b 935 point_list.Append( point1 );
2970ae54
RR
936
937 wxPoint *point2 = new wxPoint;
938 point2->x = x2; point2->y = y2;
b0d7707b 939 point_list.Append( point2 );
2970ae54
RR
940
941 wxPoint *point3 = new wxPoint;
942 point3->x = x3; point3->y = y3;
b0d7707b 943 point_list.Append( point3 );
2970ae54 944
ab171e95 945 DoDrawSpline(&point_list);
2970ae54 946
b0d7707b 947 for( wxPointList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
2970ae54 948 {
b0d7707b 949 wxPoint *p = node->GetData();
2970ae54
RR
950 delete p;
951 }
952}
953
ab171e95 954void wxImplDC::DoDrawSpline(int n, wxPoint points[])
2970ae54 955{
b0d7707b 956 wxPointList list;
2970ae54 957 for (int i =0; i < n; i++)
b0d7707b 958 list.Append( &points[i] );
2970ae54 959
ab171e95 960 DoDrawSpline(&list);
2970ae54
RR
961}
962
963// ----------------------------------- spline code ----------------------------------------
964
965void wx_quadratic_spline(double a1, double b1, double a2, double b2,
966 double a3, double b3, double a4, double b4);
967void wx_clear_stack();
968int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
969 double *y3, double *x4, double *y4);
970void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
971 double x4, double y4);
972static bool wx_spline_add_point(double x, double y);
ab171e95 973static void wx_spline_draw_point_array(wxDC *dc);
2970ae54 974
b0d7707b 975wxPointList wx_spline_point_list;
2970ae54
RR
976
977#define half(z1, z2) ((z1+z2)/2.0)
978#define THRESHOLD 5
979
980/* iterative version */
981
982void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
983 double b4)
984{
985 register double xmid, ymid;
986 double x1, y1, x2, y2, x3, y3, x4, y4;
987
988 wx_clear_stack();
989 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
990
991 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
992 xmid = (double)half(x2, x3);
993 ymid = (double)half(y2, y3);
994 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
995 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
996 wx_spline_add_point( x1, y1 );
997 wx_spline_add_point( xmid, ymid );
998 } else {
999 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1000 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1001 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1002 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
1003 }
1004 }
1005}
1006
1007/* utilities used by spline drawing routines */
1008
1009typedef struct wx_spline_stack_struct {
1010 double x1, y1, x2, y2, x3, y3, x4, y4;
1011} Stack;
1012
1013#define SPLINE_STACK_DEPTH 20
1014static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1015static Stack *wx_stack_top;
1016static int wx_stack_count;
1017
1018void wx_clear_stack()
1019{
1020 wx_stack_top = wx_spline_stack;
1021 wx_stack_count = 0;
1022}
1023
1024void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1025{
1026 wx_stack_top->x1 = x1;
1027 wx_stack_top->y1 = y1;
1028 wx_stack_top->x2 = x2;
1029 wx_stack_top->y2 = y2;
1030 wx_stack_top->x3 = x3;
1031 wx_stack_top->y3 = y3;
1032 wx_stack_top->x4 = x4;
1033 wx_stack_top->y4 = y4;
1034 wx_stack_top++;
1035 wx_stack_count++;
1036}
1037
1038int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1039 double *x3, double *y3, double *x4, double *y4)
1040{
1041 if (wx_stack_count == 0)
1042 return (0);
1043 wx_stack_top--;
1044 wx_stack_count--;
1045 *x1 = wx_stack_top->x1;
1046 *y1 = wx_stack_top->y1;
1047 *x2 = wx_stack_top->x2;
1048 *y2 = wx_stack_top->y2;
1049 *x3 = wx_stack_top->x3;
1050 *y3 = wx_stack_top->y3;
1051 *x4 = wx_stack_top->x4;
1052 *y4 = wx_stack_top->y4;
1053 return (1);
1054}
1055
1056static bool wx_spline_add_point(double x, double y)
1057{
b0d7707b
RR
1058 wxPoint *point = new wxPoint( wxRound(x), wxRound(y) );
1059 wx_spline_point_list.Append(point );
1060 return true;
2970ae54
RR
1061}
1062
1063static void wx_spline_draw_point_array(wxDC *dc)
1064{
b0d7707b
RR
1065 wxPointList::compatibility_iterator node = wx_spline_point_list.GetFirst();
1066 while (node)
1067 {
1068 wxPoint *point = node->GetData();
1069 delete point;
1070 wx_spline_point_list.Erase(node);
1071 node = wx_spline_point_list.GetFirst();
1072 }
2970ae54
RR
1073}
1074
b0d7707b 1075void wxImplDC::DoDrawSpline( const wxPointList *points )
2970ae54 1076{
ab171e95 1077 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
2970ae54
RR
1078
1079 wxPoint *p;
1080 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1081 double x1, y1, x2, y2;
1082
b0d7707b 1083 wxPointList::compatibility_iterator node = points->GetFirst();
2970ae54
RR
1084 if (!node)
1085 // empty list
1086 return;
1087
1088 p = (wxPoint *)node->GetData();
1089
1090 x1 = p->x;
1091 y1 = p->y;
1092
1093 node = node->GetNext();
b0d7707b 1094 p = node->GetData();
2970ae54
RR
1095
1096 x2 = p->x;
1097 y2 = p->y;
1098 cx1 = (double)((x1 + x2) / 2);
1099 cy1 = (double)((y1 + y2) / 2);
1100 cx2 = (double)((cx1 + x2) / 2);
1101 cy2 = (double)((cy1 + y2) / 2);
1102
1103 wx_spline_add_point(x1, y1);
1104
1105 while ((node = node->GetNext())
1106#if !wxUSE_STL
1107 != NULL
1108#endif // !wxUSE_STL
1109 )
1110 {
b0d7707b 1111 p = node->GetData();
2970ae54
RR
1112 x1 = x2;
1113 y1 = y2;
1114 x2 = p->x;
1115 y2 = p->y;
1116 cx4 = (double)(x1 + x2) / 2;
1117 cy4 = (double)(y1 + y2) / 2;
1118 cx3 = (double)(x1 + cx4) / 2;
1119 cy3 = (double)(y1 + cy4) / 2;
1120
1121 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1122
1123 cx1 = cx4;
1124 cy1 = cy4;
1125 cx2 = (double)(cx1 + x2) / 2;
1126 cy2 = (double)(cy1 + y2) / 2;
1127 }
1128
1129 wx_spline_add_point( cx1, cy1 );
1130 wx_spline_add_point( x2, y2 );
1131
1132 wx_spline_draw_point_array( m_owner );
1133}
1134
1135#endif // wxUSE_SPLINES
1136
1137
2970ae54
RR
1138
1139void wxImplDC::DoGradientFillLinear(const wxRect& rect,
1140 const wxColour& initialColour,
1141 const wxColour& destColour,
1142 wxDirection nDirection)
1143{
1144 // save old pen
1145 wxPen oldPen = m_pen;
1146 wxBrush oldBrush = m_brush;
1147
1148 wxUint8 nR1 = initialColour.Red();
1149 wxUint8 nG1 = initialColour.Green();
1150 wxUint8 nB1 = initialColour.Blue();
1151 wxUint8 nR2 = destColour.Red();
1152 wxUint8 nG2 = destColour.Green();
1153 wxUint8 nB2 = destColour.Blue();
1154 wxUint8 nR, nG, nB;
1155
1156 if ( nDirection == wxEAST || nDirection == wxWEST )
1157 {
1158 wxInt32 x = rect.GetWidth();
1159 wxInt32 w = x; // width of area to shade
1160 wxInt32 xDelta = w/256; // height of one shade bend
1161 if (xDelta < 1)
1162 xDelta = 1;
1163
1164 while (x >= xDelta)
1165 {
1166 x -= xDelta;
1167 if (nR1 > nR2)
1168 nR = nR1 - (nR1-nR2)*(w-x)/w;
1169 else
1170 nR = nR1 + (nR2-nR1)*(w-x)/w;
1171
1172 if (nG1 > nG2)
1173 nG = nG1 - (nG1-nG2)*(w-x)/w;
1174 else
1175 nG = nG1 + (nG2-nG1)*(w-x)/w;
1176
1177 if (nB1 > nB2)
1178 nB = nB1 - (nB1-nB2)*(w-x)/w;
1179 else
1180 nB = nB1 + (nB2-nB1)*(w-x)/w;
1181
1182 wxColour colour(nR,nG,nB);
1183 SetPen(wxPen(colour, 1, wxSOLID));
1184 SetBrush(wxBrush(colour));
1185 if(nDirection == wxEAST)
5f77ee3b 1186 DoDrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(),
2970ae54
RR
1187 xDelta, rect.GetHeight());
1188 else //nDirection == wxWEST
1189 DoDrawRectangle(rect.GetLeft()+x, rect.GetTop(),
1190 xDelta, rect.GetHeight());
1191 }
1192 }
1193 else // nDirection == wxNORTH || nDirection == wxSOUTH
1194 {
1195 wxInt32 y = rect.GetHeight();
1196 wxInt32 w = y; // height of area to shade
1197 wxInt32 yDelta = w/255; // height of one shade bend
1198 if (yDelta < 1)
1199 yDelta = 1;
1200
1201 while (y > 0)
1202 {
1203 y -= yDelta;
1204 if (nR1 > nR2)
1205 nR = nR1 - (nR1-nR2)*(w-y)/w;
1206 else
1207 nR = nR1 + (nR2-nR1)*(w-y)/w;
1208
1209 if (nG1 > nG2)
1210 nG = nG1 - (nG1-nG2)*(w-y)/w;
1211 else
1212 nG = nG1 + (nG2-nG1)*(w-y)/w;
1213
1214 if (nB1 > nB2)
1215 nB = nB1 - (nB1-nB2)*(w-y)/w;
1216 else
1217 nB = nB1 + (nB2-nB1)*(w-y)/w;
1218
1219 wxColour colour(nR,nG,nB);
1220 SetPen(wxPen(colour, 1, wxSOLID));
1221 SetBrush(wxBrush(colour));
1222 if(nDirection == wxNORTH)
1223 DoDrawRectangle(rect.GetLeft(), rect.GetTop()+y,
1224 rect.GetWidth(), yDelta);
1225 else //nDirection == wxSOUTH
5f77ee3b 1226 DoDrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1,
2970ae54
RR
1227 rect.GetWidth(), yDelta);
1228 }
1229 }
1230
1231 SetPen(oldPen);
1232 SetBrush(oldBrush);
1233}
1234
1235void wxImplDC::DoGradientFillConcentric(const wxRect& rect,
1236 const wxColour& initialColour,
1237 const wxColour& destColour,
1238 const wxPoint& circleCenter)
1239{
1240 //save the old pen color
1241 wxColour oldPenColour = m_pen.GetColour();
1242
1243 wxUint8 nR1 = destColour.Red();
1244 wxUint8 nG1 = destColour.Green();
1245 wxUint8 nB1 = destColour.Blue();
1246 wxUint8 nR2 = initialColour.Red();
1247 wxUint8 nG2 = initialColour.Green();
1248 wxUint8 nB2 = initialColour.Blue();
1249 wxUint8 nR, nG, nB;
1250
1251
1252 //Radius
1253 wxInt32 cx = rect.GetWidth() / 2;
1254 wxInt32 cy = rect.GetHeight() / 2;
1255 wxInt32 nRadius;
1256 if (cx < cy)
1257 nRadius = cx;
1258 else
1259 nRadius = cy;
1260
1261 //Offset of circle
1262 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
1263 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
1264
1265 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
1266 {
1267 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
1268 {
1269 //get color difference
1270 wxInt32 nGradient = ((nRadius -
1271 (wxInt32)sqrt(
1272 pow((double)(x - cx - nCircleOffX), 2) +
1273 pow((double)(y - cy - nCircleOffY), 2)
1274 )) * 100) / nRadius;
1275
1276 //normalize Gradient
1277 if (nGradient < 0 )
1278 nGradient = 0;
1279
1280 //get dest colors
1281 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
1282 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
1283 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
1284
1285 //set the pixel
1286 m_pen.SetColour(wxColour(nR,nG,nB));
ab171e95 1287 DoDrawPoint(x + rect.GetLeft(), y + rect.GetTop());
2970ae54
RR
1288 }
1289 }
1290 //return old pen color
1291 m_pen.SetColour(oldPenColour);
1292}
1293
1294//-----------------------------------------------------------------------------
1295// wxDC
1296//-----------------------------------------------------------------------------
1297
1298IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
1299
ab171e95
RR
1300void wxDC::DrawLabel(const wxString& text,
1301 const wxBitmap& bitmap,
1302 const wxRect& rect,
1303 int alignment,
1304 int indexAccel,
1305 wxRect *rectBounding)
1306{
1307 // find the text position
1308 wxCoord widthText, heightText, heightLine;
1309 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
1310
1311 wxCoord width, height;
1312 if ( bitmap.Ok() )
1313 {
1314 width = widthText + bitmap.GetWidth();
1315 height = bitmap.GetHeight();
1316 }
1317 else // no bitmap
1318 {
1319 width = widthText;
1320 height = heightText;
1321 }
1322
1323 wxCoord x, y;
1324 if ( alignment & wxALIGN_RIGHT )
1325 {
1326 x = rect.GetRight() - width;
1327 }
1328 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1329 {
1330 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
1331 }
1332 else // alignment & wxALIGN_LEFT
1333 {
1334 x = rect.GetLeft();
1335 }
1336
1337 if ( alignment & wxALIGN_BOTTOM )
1338 {
1339 y = rect.GetBottom() - height;
1340 }
1341 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
1342 {
1343 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
1344 }
1345 else // alignment & wxALIGN_TOP
1346 {
1347 y = rect.GetTop();
1348 }
1349
1350 // draw the bitmap first
1351 wxCoord x0 = x,
1352 y0 = y,
1353 width0 = width;
1354 if ( bitmap.Ok() )
1355 {
1356 DrawBitmap(bitmap, x, y, true /* use mask */);
1357
1358 wxCoord offset = bitmap.GetWidth() + 4;
1359 x += offset;
1360 width -= offset;
1361
1362 y += (height - heightText) / 2;
1363 }
1364
1365 // we will draw the underscore under the accel char later
1366 wxCoord startUnderscore = 0,
1367 endUnderscore = 0,
1368 yUnderscore = 0;
1369
1370 // split the string into lines and draw each of them separately
1371 wxString curLine;
1372 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1373 {
1374 if ( *pc == _T('\n') || pc == text.end() )
1375 {
1376 int xRealStart = x; // init it here to avoid compielr warnings
1377
1378 if ( !curLine.empty() )
1379 {
1380 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1381 // wxALIGN_LEFT is 0
1382 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
1383 {
1384 wxCoord widthLine;
1385 GetTextExtent(curLine, &widthLine, NULL);
1386
1387 if ( alignment & wxALIGN_RIGHT )
1388 {
1389 xRealStart += width - widthLine;
1390 }
1391 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1392 {
1393 xRealStart += (width - widthLine) / 2;
1394 }
1395 }
1396 //else: left aligned, nothing to do
1397
1398 DrawText(curLine, xRealStart, y);
1399 }
1400
1401 y += heightLine;
1402
1403 // do we have underscore in this line? we can check yUnderscore
1404 // because it is set below to just y + heightLine if we do
1405 if ( y == yUnderscore )
1406 {
1407 // adjust the horz positions to account for the shift
1408 startUnderscore += xRealStart;
1409 endUnderscore += xRealStart;
1410 }
1411
1412 if ( pc == text.end() )
1413 break;
1414
1415 curLine.clear();
1416 }
1417 else // not end of line
1418 {
1419 if ( pc - text.begin() == indexAccel )
1420 {
1421 // remeber to draw underscore here
1422 GetTextExtent(curLine, &startUnderscore, NULL);
1423 curLine += *pc;
1424 GetTextExtent(curLine, &endUnderscore, NULL);
1425
1426 yUnderscore = y + heightLine;
1427 }
1428 else
1429 {
1430 curLine += *pc;
1431 }
1432 }
1433 }
1434
1435 // draw the underscore if found
1436 if ( startUnderscore != endUnderscore )
1437 {
1438 // it should be of the same colour as text
1439 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
1440
1441 yUnderscore--;
1442
1443 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
1444 }
1445
1446 // return bounding rect if requested
1447 if ( rectBounding )
1448 {
1449 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
1450 }
1451
1452 CalcBoundingBox(x0, y0);
1453 CalcBoundingBox(x0 + width0, y0 + height);
1454}
1455
2970ae54
RR
1456#if WXWIN_COMPATIBILITY_2_8
1457 // for compatibility with the old code when wxCoord was long everywhere
1458void wxDC::GetTextExtent(const wxString& string,
1459 long *x, long *y,
1460 long *descent,
1461 long *externalLeading,
1462 const wxFont *theFont) const
1463 {
1464 wxCoord x2, y2, descent2, externalLeading2;
1465 m_pimpl->DoGetTextExtent(string, &x2, &y2,
1466 &descent2, &externalLeading2,
1467 theFont);
1468 if ( x )
1469 *x = x2;
1470 if ( y )
1471 *y = y2;
1472 if ( descent )
1473 *descent = descent2;
1474 if ( externalLeading )
1475 *externalLeading = externalLeading2;
1476 }
1477
1478void wxDC::GetLogicalOrigin(long *x, long *y) const
1479 {
1480 wxCoord x2, y2;
1481 m_pimpl->DoGetLogicalOrigin(&x2, &y2);
1482 if ( x )
1483 *x = x2;
1484 if ( y )
1485 *y = y2;
1486 }
1487
1488void wxDC::GetDeviceOrigin(long *x, long *y) const
1489 {
1490 wxCoord x2, y2;
1491 m_pimpl->DoGetDeviceOrigin(&x2, &y2);
1492 if ( x )
1493 *x = x2;
1494 if ( y )
1495 *y = y2;
1496 }
1497
1498void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const
1499 {
1500 wxCoord xx,yy,ww,hh;
1501 m_pimpl->DoGetClippingBox(&xx, &yy, &ww, &hh);
1502 if (x) *x = xx;
1503 if (y) *y = yy;
1504 if (w) *w = ww;
1505 if (h) *h = hh;
1506 }
1507
1508#endif // WXWIN_COMPATIBILITY_2_8
1509
1510
1511#else // wxUSE_NEW_DC
1512
1513
68379eaf 1514// bool wxDCBase::sm_cacheing = false;
0cbff120 1515
e7445ff8
PC
1516IMPLEMENT_ABSTRACT_CLASS(wxDCBase, wxObject)
1517
1e6feb95
VZ
1518// ============================================================================
1519// implementation
1520// ============================================================================
1521
653752be
MB
1522IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC, wxMemoryDC)
1523IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC, wxBufferedDC)
1524
04ab8b6d
RR
1525wxDCBase::wxDCBase()
1526 : m_colour(wxColourDisplay())
1527 , m_ok(true)
1528 , m_clipping(false)
1529 , m_isInteractive(0)
1530 , m_isBBoxValid(false)
1531 , m_logicalOriginX(0), m_logicalOriginY(0)
1532 , m_deviceOriginX(0), m_deviceOriginY(0)
1533 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
1534 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
1535 , m_userScaleX(1.0), m_userScaleY(1.0)
1536 , m_scaleX(1.0), m_scaleY(1.0)
1537 , m_signX(1), m_signY(1)
1538 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
1539 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
1540 , m_logicalFunction(wxCOPY)
1541 , m_backgroundMode(wxTRANSPARENT)
1542 , m_mappingMode(wxMM_TEXT)
1543 , m_pen()
1544 , m_brush()
1545 , m_backgroundBrush(*wxTRANSPARENT_BRUSH)
1546 , m_textForegroundColour(*wxBLACK)
1547 , m_textBackgroundColour(*wxWHITE)
1548 , m_font()
1549#if wxUSE_PALETTE
1550 , m_palette()
1551 , m_hasCustomPalette(false)
1552#endif // wxUSE_PALETTE
1553{
1554 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
1555 (double)wxGetDisplaySizeMM().GetWidth();
1556 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
1557 (double)wxGetDisplaySizeMM().GetHeight();
1558
1559 ResetBoundingBox();
1560 ResetClipping();
1561}
1562
1563wxDCBase::~wxDCBase()
1564{
1565}
1566
68df211f
JG
1567#if WXWIN_COMPATIBILITY_2_6
1568void wxDCBase::BeginDrawing()
1569{
1570}
1571
1572void wxDCBase::EndDrawing()
1573{
1574}
1575#endif // WXWIN_COMPATIBILITY_2_6
1576
cfa87e81
RR
1577#if WXWIN_COMPATIBILITY_2_8
1578 // for compatibility with the old code when wxCoord was long everywhere
1579void wxDCBase::GetTextExtent(const wxString& string,
1580 long *x, long *y,
27ee942f
PC
1581 long *descent,
1582 long *externalLeading,
1583 const wxFont *theFont) const
cfa87e81
RR
1584 {
1585 wxCoord x2, y2, descent2, externalLeading2;
1586 DoGetTextExtent(string, &x2, &y2,
1587 &descent2, &externalLeading2,
1588 theFont);
1589 if ( x )
1590 *x = x2;
1591 if ( y )
1592 *y = y2;
1593 if ( descent )
1594 *descent = descent2;
1595 if ( externalLeading )
1596 *externalLeading = externalLeading2;
1597 }
1598
1599void wxDCBase::GetLogicalOrigin(long *x, long *y) const
1600 {
1601 wxCoord x2, y2;
1602 DoGetLogicalOrigin(&x2, &y2);
1603 if ( x )
1604 *x = x2;
1605 if ( y )
1606 *y = y2;
1607 }
1608
1609void wxDCBase::GetDeviceOrigin(long *x, long *y) const
1610 {
1611 wxCoord x2, y2;
1612 DoGetDeviceOrigin(&x2, &y2);
1613 if ( x )
1614 *x = x2;
1615 if ( y )
1616 *y = y2;
1617 }
1618
1619void wxDCBase::GetClippingBox(long *x, long *y, long *w, long *h) const
1620 {
1621 wxCoord xx,yy,ww,hh;
1622 DoGetClippingBox(&xx, &yy, &ww, &hh);
1623 if (x) *x = xx;
1624 if (y) *y = yy;
1625 if (w) *w = ww;
1626 if (h) *h = hh;
1627 }
1628#endif // WXWIN_COMPATIBILITY_2_8
1629
1630
1631
04ab8b6d
RR
1632// ----------------------------------------------------------------------------
1633// coordinate conversions and transforms
1634// ----------------------------------------------------------------------------
1635
1636wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
1637{
1638 return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX;
1639}
1640
1641wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
1642{
1643 return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY;
1644}
1645
1646wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
1647{
1648 return wxRound((double)(x) / m_scaleX);
1649}
1650
1651wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
1652{
1653 return wxRound((double)(y) / m_scaleY);
1654}
1655
1656wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
1657{
1658 return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX + m_deviceLocalOriginX;
1659}
1660
1661wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
1662{
1663 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY + m_deviceLocalOriginY;
1664}
1665
1666wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
1667{
1668 return wxRound((double)(x) * m_scaleX);
1669}
1670
1671wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
1672{
1673 return wxRound((double)(y) * m_scaleY);
1674}
1675
1676void wxDCBase::ComputeScaleAndOrigin()
1677{
1678 m_scaleX = m_logicalScaleX * m_userScaleX;
1679 m_scaleY = m_logicalScaleY * m_userScaleY;
1680}
1681
1682void wxDCBase::SetMapMode( int mode )
1683{
1684 switch (mode)
1685 {
1686 case wxMM_TWIPS:
1687 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
1688 break;
1689 case wxMM_POINTS:
1690 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
1691 break;
1692 case wxMM_METRIC:
1693 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
1694 break;
1695 case wxMM_LOMETRIC:
1696 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
1697 break;
1698 default:
1699 case wxMM_TEXT:
1700 SetLogicalScale( 1.0, 1.0 );
1701 break;
1702 }
1703 m_mappingMode = mode;
1704}
1705
1706void wxDCBase::SetUserScale( double x, double y )
1707{
1708 // allow negative ? -> no
1709 m_userScaleX = x;
1710 m_userScaleY = y;
1711 ComputeScaleAndOrigin();
1712}
1713
1714void wxDCBase::SetLogicalScale( double x, double y )
1715{
1716 // allow negative ?
1717 m_logicalScaleX = x;
1718 m_logicalScaleY = y;
1719 ComputeScaleAndOrigin();
1720}
1721
1722void wxDCBase::SetLogicalOrigin( wxCoord x, wxCoord y )
1723{
1724 m_logicalOriginX = x * m_signX;
1725 m_logicalOriginY = y * m_signY;
1726 ComputeScaleAndOrigin();
1727}
1728
1729void wxDCBase::SetDeviceOrigin( wxCoord x, wxCoord y )
1730{
1731 m_deviceOriginX = x;
1732 m_deviceOriginY = y;
1733 ComputeScaleAndOrigin();
1734}
1735
1736void wxDCBase::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
1737{
1738 m_deviceLocalOriginX = x;
1739 m_deviceLocalOriginY = y;
1740 ComputeScaleAndOrigin();
1741}
1742
1743void wxDCBase::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
1744{
1745 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
02255e07 1746 // wxWidgets 2.9: no longer override it
04ab8b6d
RR
1747 m_signX = (xLeftRight ? 1 : -1);
1748 m_signY = (yBottomUp ? -1 : 1);
1749 ComputeScaleAndOrigin();
1750}
1751
1e6feb95
VZ
1752// ----------------------------------------------------------------------------
1753// special symbols
1754// ----------------------------------------------------------------------------
1755
cd9da200
VZ
1756void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1,
1757 wxCoord width, wxCoord height)
1758{
1759 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1760
1761 wxCoord x2 = x1 + width,
1762 y2 = y1 + height;
1763
860a4018
VZ
1764 // the pen width is calibrated to give 3 for width == height == 10
1765 wxDCPenChanger pen((wxDC&)*this,
1766 wxPen(GetTextForeground(), (width + height + 1)/7));
cd9da200
VZ
1767
1768 // we're drawing a scaled version of wx/generic/tick.xpm here
1769 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
1770 y3 = y1 + height / 2; // y of the left tick branch
1771 DoDrawLine(x1, y3, x3, y2);
1772 DoDrawLine(x3, y2, x2, y1);
1773
1774 CalcBoundingBox(x1, y1);
1775 CalcBoundingBox(x2, y2);
1776}
1777
e3b81044
VZ
1778// ----------------------------------------------------------------------------
1779// stubs for functions not implemented in all ports
1780// ----------------------------------------------------------------------------
1781
1782bool
1783wxDCBase::DoStretchBlit(wxCoord xdest, wxCoord ydest,
1784 wxCoord dstWidth, wxCoord dstHeight,
1785 wxDC *source,
1786 wxCoord xsrc, wxCoord ysrc,
ce2fe5bc 1787 wxCoord srcWidth, wxCoord srcHeight,
e3b81044
VZ
1788 int rop,
1789 bool useMask,
1790 wxCoord xsrcMask,
1791 wxCoord ysrcMask)
1792{
ce2fe5bc
VZ
1793 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
1794 _T("invalid blit size") );
1795
1796 // emulate the stretching by modifying the DC scale
1797 double xscale = (double)srcWidth/dstWidth,
1798 yscale = (double)srcHeight/dstHeight;
1799
1800 double xscaleOld, yscaleOld;
1801 GetUserScale(&xscaleOld, &yscaleOld);
1802 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
1803
1804 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
1805 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
1806 source,
1807 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
1808
1809 SetUserScale(xscaleOld, yscaleOld);
1810
1811 return rc;
e3b81044
VZ
1812}
1813
1e6feb95
VZ
1814// ----------------------------------------------------------------------------
1815// line/polygons
1816// ----------------------------------------------------------------------------
1817
b0d7707b 1818void wxDCBase::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset)
dbe94982 1819{
b0d7707b 1820 unsigned int n = list->GetCount();
dbe94982
BM
1821 wxPoint *points = new wxPoint[n];
1822
b0d7707b
RR
1823 unsigned int i = 0;
1824 wxPointList::compatibility_iterator node;
1825 for ( node = list->GetFirst(); node; node = node->GetNext(), i++ )
dbe94982 1826 {
b0d7707b 1827 wxPoint *point = node->GetData();
dbe94982
BM
1828 points[i].x = point->x;
1829 points[i].y = point->y;
1830 }
1831
1832 DoDrawLines(n, points, xoffset, yoffset);
1833
1834 delete [] points;
1835}
1836
b0d7707b
RR
1837#if WXWIN_COMPATIBILITY_2_8
1838void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset )
1839{
1840 unsigned int n = list->GetCount();
1841 wxPoint *points = new wxPoint[n];
dbe94982 1842
b0d7707b 1843 unsigned int i = 0;
bc2ac5da 1844 wxObjectList::compatibility_iterator node;
b0d7707b
RR
1845 for ( node = list->GetFirst(); node; node = node->GetNext(), i++ )
1846 {
1847 wxPoint *point = (wxPoint*) node->GetData();
1848 points[i].x = point->x;
1849 points[i].y = point->y;
1850 }
1851
1852 DoDrawLines(n, points, xoffset, yoffset);
1853
1854 delete [] points;
1855}
1856#endif // WXWIN_COMPATIBILITY_2_8
1857
1858
1859void wxDCBase::DrawPolygon(const wxPointList *list,
72cdf4c9 1860 wxCoord xoffset, wxCoord yoffset,
dbe94982
BM
1861 int fillStyle)
1862{
b0d7707b 1863 unsigned int n = list->GetCount();
dbe94982
BM
1864 wxPoint *points = new wxPoint[n];
1865
b0d7707b
RR
1866 unsigned int i = 0;
1867 wxPointList::compatibility_iterator node;
1868 for ( node = list->GetFirst(); node; node = node->GetNext(), i++ )
1869 {
1870 wxPoint *point = node->GetData();
1871 points[i].x = point->x;
1872 points[i].y = point->y;
1873 }
1874
1875 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
1876
1877 delete [] points;
1878}
1879
1880
1881#if WXWIN_COMPATIBILITY_2_8
1882void wxDCBase::DrawPolygon(const wxList *list,
1883 wxCoord xoffset, wxCoord yoffset,
1884 int fillStyle )
1885{
1886 unsigned int n = list->GetCount();
1887 wxPoint *points = new wxPoint[n];
1888
1889 unsigned int i = 0;
bc2ac5da 1890 wxObjectList::compatibility_iterator node;
b0d7707b 1891 for ( node = list->GetFirst(); node; node = node->GetNext(), i++ )
dbe94982 1892 {
b0d7707b 1893 wxPoint *point = (wxPoint*) node->GetData();
dbe94982
BM
1894 points[i].x = point->x;
1895 points[i].y = point->y;
1896 }
1897
1898 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
1899
1900 delete [] points;
1901}
b0d7707b 1902#endif // WXWIN_COMPATIBILITY_2_8
dbe94982 1903
63b9e659
VZ
1904void
1905wxDCBase::DoDrawPolyPolygon(int n,
793db755 1906 int count[],
63b9e659
VZ
1907 wxPoint points[],
1908 wxCoord xoffset, wxCoord yoffset,
1909 int fillStyle)
1910{
1911 if ( n == 1 )
1912 {
793db755 1913 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
63b9e659
VZ
1914 return;
1915 }
1916
1917 int i, j, lastOfs;
1918 wxPoint* pts;
1919 wxPen pen;
1920
1921 for (i = j = lastOfs = 0; i < n; i++)
1922 {
1923 lastOfs = j;
793db755 1924 j += count[i];
63b9e659
VZ
1925 }
1926 pts = new wxPoint[j+n-1];
1927 for (i = 0; i < j; i++)
1928 pts[i] = points[i];
1929 for (i = 2; i <= n; i++)
1930 {
793db755 1931 lastOfs -= count[n-i];
63b9e659
VZ
1932 pts[j++] = pts[lastOfs];
1933 }
1934
1935 pen = GetPen();
1936 SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT));
1937 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
1938 SetPen(pen);
1939 for (i = j = 0; i < n; i++)
1940 {
793db755
VZ
1941 DoDrawLines(count[i], pts+j, xoffset, yoffset);
1942 j += count[i];
63b9e659 1943 }
6db1f43b 1944 delete[] pts;
63b9e659
VZ
1945}
1946
1e6feb95
VZ
1947// ----------------------------------------------------------------------------
1948// splines
1949// ----------------------------------------------------------------------------
dbe94982 1950
88ac883a 1951#if wxUSE_SPLINES
dbe94982 1952
72cdf4c9 1953void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
dbe94982 1954{
b0d7707b 1955 wxPointList point_list;
dbe94982
BM
1956
1957 wxPoint *point1 = new wxPoint;
1958 point1->x = x1; point1->y = y1;
b0d7707b 1959 point_list.Append( point1 );
dbe94982
BM
1960
1961 wxPoint *point2 = new wxPoint;
1962 point2->x = x2; point2->y = y2;
b0d7707b 1963 point_list.Append( point2 );
dbe94982
BM
1964
1965 wxPoint *point3 = new wxPoint;
1966 point3->x = x3; point3->y = y3;
b0d7707b 1967 point_list.Append( point3 );
dbe94982
BM
1968
1969 DrawSpline(&point_list);
1970
b0d7707b 1971 for( wxPointList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
dbe94982 1972 {
b0d7707b 1973 wxPoint *p = node->GetData();
dbe94982
BM
1974 delete p;
1975 }
1976}
1977
1978void wxDCBase::DrawSpline(int n, wxPoint points[])
1979{
b0d7707b 1980 wxPointList list;
dbe94982 1981 for (int i =0; i < n; i++)
b0d7707b 1982 list.Append( &points[i] );
dbe94982
BM
1983
1984 DrawSpline(&list);
1985}
1986
fe2e4366
VS
1987// ----------------------------------- spline code ----------------------------------------
1988
1989void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1990 double a3, double b3, double a4, double b4);
1991void wx_clear_stack();
1992int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1993 double *y3, double *x4, double *y4);
1994void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1995 double x4, double y4);
1996static bool wx_spline_add_point(double x, double y);
1997static void wx_spline_draw_point_array(wxDCBase *dc);
1998
b0d7707b 1999wxPointList wx_spline_point_list;
fe2e4366
VS
2000
2001#define half(z1, z2) ((z1+z2)/2.0)
2002#define THRESHOLD 5
2003
2004/* iterative version */
2005
2006void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
2007 double b4)
2008{
2009 register double xmid, ymid;
2010 double x1, y1, x2, y2, x3, y3, x4, y4;
2011
2012 wx_clear_stack();
2013 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
2014
2015 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
2016 xmid = (double)half(x2, x3);
2017 ymid = (double)half(y2, y3);
2018 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
2019 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
2020 wx_spline_add_point( x1, y1 );
2021 wx_spline_add_point( xmid, ymid );
2022 } else {
2023 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
2024 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
2025 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
2026 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
2027 }
2028 }
2029}
2030
2031/* utilities used by spline drawing routines */
2032
2033typedef struct wx_spline_stack_struct {
2034 double x1, y1, x2, y2, x3, y3, x4, y4;
2035} Stack;
2036
2037#define SPLINE_STACK_DEPTH 20
2038static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
2039static Stack *wx_stack_top;
2040static int wx_stack_count;
2041
2042void wx_clear_stack()
2043{
2044 wx_stack_top = wx_spline_stack;
2045 wx_stack_count = 0;
2046}
2047
2048void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
2049{
2050 wx_stack_top->x1 = x1;
2051 wx_stack_top->y1 = y1;
2052 wx_stack_top->x2 = x2;
2053 wx_stack_top->y2 = y2;
2054 wx_stack_top->x3 = x3;
2055 wx_stack_top->y3 = y3;
2056 wx_stack_top->x4 = x4;
2057 wx_stack_top->y4 = y4;
2058 wx_stack_top++;
2059 wx_stack_count++;
2060}
2061
2062int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
2063 double *x3, double *y3, double *x4, double *y4)
2064{
2065 if (wx_stack_count == 0)
2066 return (0);
2067 wx_stack_top--;
2068 wx_stack_count--;
2069 *x1 = wx_stack_top->x1;
2070 *y1 = wx_stack_top->y1;
2071 *x2 = wx_stack_top->x2;
2072 *y2 = wx_stack_top->y2;
2073 *x3 = wx_stack_top->x3;
2074 *y3 = wx_stack_top->y3;
2075 *x4 = wx_stack_top->x4;
2076 *y4 = wx_stack_top->y4;
2077 return (1);
2078}
2079
2080static bool wx_spline_add_point(double x, double y)
2081{
b0d7707b
RR
2082 wxPoint *point = new wxPoint( wxRound(x), wxRound(y) );
2083 wx_spline_point_list.Append( point );
2084 return true;
fe2e4366
VS
2085}
2086
2087static void wx_spline_draw_point_array(wxDCBase *dc)
2088{
b0d7707b
RR
2089 dc->DrawLines(&wx_spline_point_list, 0, 0 );
2090 wxPointList::compatibility_iterator node = wx_spline_point_list.GetFirst();
2091 while (node)
2092 {
2093 wxPoint *point = node->GetData();
2094 delete point;
2095 wx_spline_point_list.Erase(node);
2096 node = wx_spline_point_list.GetFirst();
2097 }
fe2e4366
VS
2098}
2099
b0d7707b
RR
2100#if WXWIN_COMPATIBILITY_2_8
2101void wxDCBase::DrawSpline(const wxList *points)
2102{
2103 wxPointList list;
bc2ac5da 2104 wxObjectList::compatibility_iterator node = points->GetFirst();
b0d7707b
RR
2105 while (node)
2106 {
2107 list.Append( (wxPoint*) node->GetData() );
2108 node = node->GetNext();
2109 }
2110 DoDrawSpline( &list );
2111}
2112#endif // WXWIN_COMPATIBILITY_2_8
2113
2114void wxDCBase::DoDrawSpline( const wxPointList *points )
fe2e4366
VS
2115{
2116 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2117
2118 wxPoint *p;
2119 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
2120 double x1, y1, x2, y2;
2121
b0d7707b 2122 wxPointList::compatibility_iterator node = points->GetFirst();
ef419e3b 2123 if (!node)
410bb8c1
RD
2124 // empty list
2125 return;
e0d31471 2126
b0d7707b 2127 p = node->GetData();
fe2e4366
VS
2128
2129 x1 = p->x;
2130 y1 = p->y;
2131
b1d4dd7a 2132 node = node->GetNext();
b0d7707b 2133 p = node->GetData();
fe2e4366
VS
2134
2135 x2 = p->x;
2136 y2 = p->y;
2137 cx1 = (double)((x1 + x2) / 2);
2138 cy1 = (double)((y1 + y2) / 2);
2139 cx2 = (double)((cx1 + x2) / 2);
2140 cy2 = (double)((cy1 + y2) / 2);
2141
2142 wx_spline_add_point(x1, y1);
2143
28b4db7f
VZ
2144 while ((node = node->GetNext())
2145#if !wxUSE_STL
2146 != NULL
2147#endif // !wxUSE_STL
2148 )
fe2e4366 2149 {
b0d7707b 2150 p = node->GetData();
fe2e4366
VS
2151 x1 = x2;
2152 y1 = y2;
2153 x2 = p->x;
2154 y2 = p->y;
2155 cx4 = (double)(x1 + x2) / 2;
2156 cy4 = (double)(y1 + y2) / 2;
2157 cx3 = (double)(x1 + cx4) / 2;
2158 cy3 = (double)(y1 + cy4) / 2;
2159
2160 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
2161
2162 cx1 = cx4;
2163 cy1 = cy4;
2164 cx2 = (double)(cx1 + x2) / 2;
2165 cy2 = (double)(cy1 + y2) / 2;
2166 }
2167
2168 wx_spline_add_point( cx1, cy1 );
2169 wx_spline_add_point( x2, y2 );
2170
2171 wx_spline_draw_point_array( this );
2172}
2173
88ac883a 2174#endif // wxUSE_SPLINES
1e6feb95 2175
0919e93e
RD
2176// ----------------------------------------------------------------------------
2177// Partial Text Extents
2178// ----------------------------------------------------------------------------
2179
2180
174ee1b3 2181// Each element of the widths array will be the width of the string up to and
3103e8a9 2182// including the corresponding character in text. This is the generic
0919e93e 2183// implementation, the port-specific classes should do this with native APIs
174ee1b3
RD
2184// if available and if faster. Note: pango_layout_index_to_pos is much slower
2185// than calling GetTextExtent!!
2186
06fe86b7 2187#define FWC_SIZE 256
174ee1b3
RD
2188
2189class FontWidthCache
2190{
2191public:
2192 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
2193 ~FontWidthCache() { delete []m_widths; }
2aaa050c
VZ
2194
2195 void Reset()
2196 {
2197 if (!m_widths)
2198 m_widths = new int[FWC_SIZE];
2199
2200 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
2201 }
2202
174ee1b3
RD
2203 wxFont m_font;
2204 double m_scaleX;
2205 int *m_widths;
2206};
2207
2208static FontWidthCache s_fontWidthCache;
0919e93e
RD
2209
2210bool wxDCBase::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
2211{
2212 int totalWidth = 0;
0919e93e 2213
18680f86 2214 const size_t len = text.length();
0919e93e 2215 widths.Empty();
174ee1b3 2216 widths.Add(0, len);
2aaa050c 2217
174ee1b3 2218 // reset the cache if font or horizontal scale have changed
c77a6796
VZ
2219 if ( !s_fontWidthCache.m_widths ||
2220 !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) ||
2221 (s_fontWidthCache.m_font != GetFont()) )
174ee1b3
RD
2222 {
2223 s_fontWidthCache.Reset();
2224 s_fontWidthCache.m_font = GetFont();
2225 s_fontWidthCache.m_scaleX = m_scaleX;
2226 }
2227
0919e93e
RD
2228 // Calculate the position of each character based on the widths of
2229 // the previous characters
c77a6796
VZ
2230 int w, h;
2231 for ( size_t i = 0; i < len; i++ )
174ee1b3
RD
2232 {
2233 const wxChar c = text[i];
2234 unsigned int c_int = (unsigned int)c;
2235
2aaa050c 2236 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
174ee1b3
RD
2237 {
2238 w = s_fontWidthCache.m_widths[c_int];
2239 }
2aaa050c 2240 else
174ee1b3
RD
2241 {
2242 GetTextExtent(c, &w, &h);
2243 if (c_int < FWC_SIZE)
2244 s_fontWidthCache.m_widths[c_int] = w;
2245 }
2246
0919e93e
RD
2247 totalWidth += w;
2248 widths[i] = totalWidth;
2249 }
2aaa050c 2250
0919e93e
RD
2251 return true;
2252}
2253
2254
1e6feb95
VZ
2255// ----------------------------------------------------------------------------
2256// enhanced text drawing
2257// ----------------------------------------------------------------------------
2258
2259void wxDCBase::GetMultiLineTextExtent(const wxString& text,
2260 wxCoord *x,
2261 wxCoord *y,
2262 wxCoord *h,
c94f845b 2263 const wxFont *font) const
1e6feb95 2264{
c7aaa64f
VS
2265 wxCoord widthTextMax = 0, widthLine,
2266 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
1e6feb95
VZ
2267
2268 wxString curLine;
86501081 2269 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1e6feb95 2270 {
86501081 2271 if ( pc == text.end() || *pc == _T('\n') )
1e6feb95
VZ
2272 {
2273 if ( curLine.empty() )
2274 {
2275 // we can't use GetTextExtent - it will return 0 for both width
2276 // and height and an empty line should count in height
2277 // calculation
2278
2279 // assume that this line has the same height as the previous
2280 // one
2281 if ( !heightLineDefault )
2282 heightLineDefault = heightLine;
2283
2284 if ( !heightLineDefault )
2285 {
2286 // but we don't know it yet - choose something reasonable
2287 GetTextExtent(_T("W"), NULL, &heightLineDefault,
2288 NULL, NULL, font);
2289 }
2290
2291 heightTextTotal += heightLineDefault;
2292 }
2293 else
2294 {
2295 GetTextExtent(curLine, &widthLine, &heightLine,
2296 NULL, NULL, font);
2297 if ( widthLine > widthTextMax )
2298 widthTextMax = widthLine;
2299 heightTextTotal += heightLine;
2300 }
2301
86501081 2302 if ( pc == text.end() )
1e6feb95 2303 {
86501081 2304 break;
1e6feb95 2305 }
86501081 2306 else // '\n'
1e6feb95 2307 {
86501081 2308 curLine.clear();
1e6feb95
VZ
2309 }
2310 }
2311 else
2312 {
2313 curLine += *pc;
2314 }
2315 }
2316
2317 if ( x )
2318 *x = widthTextMax;
2319 if ( y )
2320 *y = heightTextTotal;
2321 if ( h )
2322 *h = heightLine;
2323}
2324
2325void wxDCBase::DrawLabel(const wxString& text,
2326 const wxBitmap& bitmap,
2327 const wxRect& rect,
2328 int alignment,
2329 int indexAccel,
2330 wxRect *rectBounding)
2331{
2332 // find the text position
2333 wxCoord widthText, heightText, heightLine;
2334 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
2335
2336 wxCoord width, height;
2337 if ( bitmap.Ok() )
2338 {
2339 width = widthText + bitmap.GetWidth();
2340 height = bitmap.GetHeight();
2341 }
2342 else // no bitmap
2343 {
2344 width = widthText;
2345 height = heightText;
2346 }
2347
2348 wxCoord x, y;
2349 if ( alignment & wxALIGN_RIGHT )
2350 {
2351 x = rect.GetRight() - width;
2352 }
2353 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2354 {
2355 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
2356 }
2357 else // alignment & wxALIGN_LEFT
2358 {
2359 x = rect.GetLeft();
2360 }
2361
2362 if ( alignment & wxALIGN_BOTTOM )
2363 {
2364 y = rect.GetBottom() - height;
2365 }
2366 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
2367 {
2368 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
2369 }
2370 else // alignment & wxALIGN_TOP
2371 {
2372 y = rect.GetTop();
2373 }
2374
2375 // draw the bitmap first
2376 wxCoord x0 = x,
2377 y0 = y,
2378 width0 = width;
2379 if ( bitmap.Ok() )
2380 {
68379eaf 2381 DrawBitmap(bitmap, x, y, true /* use mask */);
1e6feb95
VZ
2382
2383 wxCoord offset = bitmap.GetWidth() + 4;
2384 x += offset;
2385 width -= offset;
2386
2387 y += (height - heightText) / 2;
2388 }
2389
2390 // we will draw the underscore under the accel char later
2391 wxCoord startUnderscore = 0,
2392 endUnderscore = 0,
2393 yUnderscore = 0;
2394
2395 // split the string into lines and draw each of them separately
2396 wxString curLine;
c9f78968 2397 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1e6feb95 2398 {
f5595af6 2399 if ( pc == text.end() || *pc == _T('\n') )
1e6feb95
VZ
2400 {
2401 int xRealStart = x; // init it here to avoid compielr warnings
2402
2403 if ( !curLine.empty() )
2404 {
2405 // NB: can't test for !(alignment & wxALIGN_LEFT) because
2406 // wxALIGN_LEFT is 0
2407 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
2408 {
2409 wxCoord widthLine;
2410 GetTextExtent(curLine, &widthLine, NULL);
2411
2412 if ( alignment & wxALIGN_RIGHT )
2413 {
2414 xRealStart += width - widthLine;
2415 }
2416 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2417 {
2418 xRealStart += (width - widthLine) / 2;
2419 }
2420 }
2421 //else: left aligned, nothing to do
2422
2423 DrawText(curLine, xRealStart, y);
2424 }
2425
2426 y += heightLine;
2427
2428 // do we have underscore in this line? we can check yUnderscore
2429 // because it is set below to just y + heightLine if we do
2430 if ( y == yUnderscore )
2431 {
2432 // adjust the horz positions to account for the shift
2433 startUnderscore += xRealStart;
2434 endUnderscore += xRealStart;
2435 }
2436
c9f78968 2437 if ( pc == text.end() )
1e6feb95
VZ
2438 break;
2439
2440 curLine.clear();
2441 }
2442 else // not end of line
2443 {
9daaea28 2444 if ( pc - text.begin() == indexAccel )
1e6feb95
VZ
2445 {
2446 // remeber to draw underscore here
2447 GetTextExtent(curLine, &startUnderscore, NULL);
2448 curLine += *pc;
2449 GetTextExtent(curLine, &endUnderscore, NULL);
2450
2451 yUnderscore = y + heightLine;
2452 }
2453 else
2454 {
2455 curLine += *pc;
2456 }
2457 }
2458 }
2459
2460 // draw the underscore if found
2461 if ( startUnderscore != endUnderscore )
2462 {
2463 // it should be of the same colour as text
2464 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
2465
2466 yUnderscore--;
2467
2468 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
2469 }
2470
2471 // return bounding rect if requested
2472 if ( rectBounding )
2473 {
2474 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
2475 }
2476
2477 CalcBoundingBox(x0, y0);
2478 CalcBoundingBox(x0 + width0, y0 + height);
2479}
12bdd77c 2480
213ad8e7
VZ
2481
2482void wxDCBase::DoGradientFillLinear(const wxRect& rect,
2483 const wxColour& initialColour,
2484 const wxColour& destColour,
2485 wxDirection nDirection)
2486{
2487 // save old pen
2488 wxPen oldPen = m_pen;
a983a3cf 2489 wxBrush oldBrush = m_brush;
213ad8e7 2490
6dff0e29
BW
2491 wxUint8 nR1 = initialColour.Red();
2492 wxUint8 nG1 = initialColour.Green();
2493 wxUint8 nB1 = initialColour.Blue();
2494 wxUint8 nR2 = destColour.Red();
2495 wxUint8 nG2 = destColour.Green();
2496 wxUint8 nB2 = destColour.Blue();
213ad8e7
VZ
2497 wxUint8 nR, nG, nB;
2498
2499 if ( nDirection == wxEAST || nDirection == wxWEST )
2500 {
2501 wxInt32 x = rect.GetWidth();
2502 wxInt32 w = x; // width of area to shade
2503 wxInt32 xDelta = w/256; // height of one shade bend
2504 if (xDelta < 1)
2505 xDelta = 1;
2506
2507 while (x >= xDelta)
2508 {
2509 x -= xDelta;
2510 if (nR1 > nR2)
2511 nR = nR1 - (nR1-nR2)*(w-x)/w;
2512 else
2513 nR = nR1 + (nR2-nR1)*(w-x)/w;
2514
2515 if (nG1 > nG2)
2516 nG = nG1 - (nG1-nG2)*(w-x)/w;
2517 else
2518 nG = nG1 + (nG2-nG1)*(w-x)/w;
2519
2520 if (nB1 > nB2)
2521 nB = nB1 - (nB1-nB2)*(w-x)/w;
2522 else
2523 nB = nB1 + (nB2-nB1)*(w-x)/w;
2524
e3b81044 2525 wxColour colour(nR,nG,nB);
1dab6da9
BW
2526 SetPen(wxPen(colour, 1, wxSOLID));
2527 SetBrush(wxBrush(colour));
213ad8e7 2528 if(nDirection == wxEAST)
5f77ee3b 2529 DrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(),
213ad8e7
VZ
2530 xDelta, rect.GetHeight());
2531 else //nDirection == wxWEST
1dab6da9 2532 DrawRectangle(rect.GetLeft()+x, rect.GetTop(),
213ad8e7
VZ
2533 xDelta, rect.GetHeight());
2534 }
2535 }
2536 else // nDirection == wxNORTH || nDirection == wxSOUTH
2537 {
2538 wxInt32 y = rect.GetHeight();
2539 wxInt32 w = y; // height of area to shade
2540 wxInt32 yDelta = w/255; // height of one shade bend
2541 if (yDelta < 1)
2542 yDelta = 1;
2543
2544 while (y > 0)
2545 {
2546 y -= yDelta;
2547 if (nR1 > nR2)
2548 nR = nR1 - (nR1-nR2)*(w-y)/w;
2549 else
2550 nR = nR1 + (nR2-nR1)*(w-y)/w;
2551
2552 if (nG1 > nG2)
2553 nG = nG1 - (nG1-nG2)*(w-y)/w;
2554 else
2555 nG = nG1 + (nG2-nG1)*(w-y)/w;
2556
2557 if (nB1 > nB2)
2558 nB = nB1 - (nB1-nB2)*(w-y)/w;
2559 else
2560 nB = nB1 + (nB2-nB1)*(w-y)/w;
2561
e3b81044 2562 wxColour colour(nR,nG,nB);
1dab6da9
BW
2563 SetPen(wxPen(colour, 1, wxSOLID));
2564 SetBrush(wxBrush(colour));
213ad8e7
VZ
2565 if(nDirection == wxNORTH)
2566 DrawRectangle(rect.GetLeft(), rect.GetTop()+y,
2567 rect.GetWidth(), yDelta);
2568 else //nDirection == wxSOUTH
5f77ee3b 2569 DrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1,
213ad8e7
VZ
2570 rect.GetWidth(), yDelta);
2571 }
2572 }
2573
2574 SetPen(oldPen);
a983a3cf 2575 SetBrush(oldBrush);
213ad8e7
VZ
2576}
2577
fb63a242 2578void wxDCBase::DoGradientFillConcentric(const wxRect& rect,
213ad8e7
VZ
2579 const wxColour& initialColour,
2580 const wxColour& destColour,
2581 const wxPoint& circleCenter)
2582{
2583 //save the old pen color
2584 wxColour oldPenColour = m_pen.GetColour();
2585
2586 wxUint8 nR1 = destColour.Red();
2587 wxUint8 nG1 = destColour.Green();
2588 wxUint8 nB1 = destColour.Blue();
2589 wxUint8 nR2 = initialColour.Red();
2590 wxUint8 nG2 = initialColour.Green();
2591 wxUint8 nB2 = initialColour.Blue();
2592 wxUint8 nR, nG, nB;
2593
2594
213ad8e7
VZ
2595 //Radius
2596 wxInt32 cx = rect.GetWidth() / 2;
2597 wxInt32 cy = rect.GetHeight() / 2;
2598 wxInt32 nRadius;
2599 if (cx < cy)
2600 nRadius = cx;
2601 else
2602 nRadius = cy;
2603
2604 //Offset of circle
2605 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
2606 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
2607
e35d07b9 2608 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
213ad8e7 2609 {
e35d07b9 2610 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
213ad8e7
VZ
2611 {
2612 //get color difference
e35d07b9
VZ
2613 wxInt32 nGradient = ((nRadius -
2614 (wxInt32)sqrt(
2615 pow((double)(x - cx - nCircleOffX), 2) +
2616 pow((double)(y - cy - nCircleOffY), 2)
2617 )) * 100) / nRadius;
213ad8e7
VZ
2618
2619 //normalize Gradient
2620 if (nGradient < 0 )
2621 nGradient = 0;
2622
2623 //get dest colors
06052f3f
WS
2624 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
2625 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
2626 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
213ad8e7
VZ
2627
2628 //set the pixel
2629 m_pen.SetColour(wxColour(nR,nG,nB));
2630 DrawPoint(wxPoint(x + rect.GetLeft(), y + rect.GetTop()));
2631 }
2632 }
2633 //return old pen color
2634 m_pen.SetColour(oldPenColour);
2635}
2636
12bdd77c 2637/*
77ffb593 2638Notes for wxWidgets DrawEllipticArcRot(...)
12bdd77c
JS
2639
2640wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
2641It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
2642which are also new.
2643
2644All methods are generic, so they can be implemented in wxDCBase.
2645DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
2646methods like (WinCE) wxDC::DoDrawArc(...).
2647
2648CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2aaa050c 2649of an elliptic arc. The algorithm is pixel-based: In every row (in flat
12bdd77c
JS
2650parts) or every column (in steep parts) only one pixel is calculated.
2651Trigonometric calculation (sin, cos, tan, atan) is only done if the
2aaa050c 2652starting angle is not equal to the ending angle. The calculation of the
12bdd77c
JS
2653pixels is done using simple arithmetic only and should perform not too
2654bad even on devices without floating point processor. I didn't test this yet.
2655
2656Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2aaa050c 2657For instance: an ellipse rotated 180 degrees is drawn
12bdd77c
JS
2658slightly different from the original.
2659
2aaa050c
VZ
2660The points are then moved to an array and used to draw a polyline and/or polygon
2661(with center added, the pie).
12bdd77c
JS
2662The result looks quite similar to the native ellipse, only e few pixels differ.
2663
2664The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
2665slower as DrawEllipse(...), which calls the native API.
2666An rotated ellipse outside the clipping region takes nearly the same time,
2667while an native ellipse outside takes nearly no time to draw.
2668
2aaa050c 2669If you draw an arc with this new method, you will see the starting and ending angles
12bdd77c
JS
2670are calculated properly.
2671If you use DrawEllipticArc(...), you will see they are only correct for circles
2672and not properly calculated for ellipses.
2673
2674Peter Lenhard
2675p.lenhard@t-online.de
2676*/
2677
2678#ifdef __WXWINCE__
2aaa050c
VZ
2679void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y,
2680 wxCoord w, wxCoord h,
12bdd77c
JS
2681 double sa, double ea, double angle )
2682{
b0d7707b 2683 wxPointList list;
12bdd77c
JS
2684
2685 CalculateEllipticPoints( &list, x, y, w, h, sa, ea );
2686 Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) );
2687
2688 // Add center (for polygon/pie)
b0d7707b 2689 list.Append( new wxPoint( x+w/2, y+h/2 ) );
12bdd77c
JS
2690
2691 // copy list into array and delete list elements
2c3ebf8b 2692 int n = list.GetCount();
12bdd77c
JS
2693 wxPoint *points = new wxPoint[n];
2694 int i = 0;
b0d7707b 2695 wxPointList::compatibility_iterator node;
2c3ebf8b 2696 for ( node = list.GetFirst(); node; node = node->GetNext(), i++ )
12bdd77c 2697 {
b0d7707b 2698 wxPoint *point = node->GetData();
12bdd77c
JS
2699 points[i].x = point->x;
2700 points[i].y = point->y;
2701 delete point;
2702 }
2703
2704 // first draw the pie without pen, if necessary
63b9e659 2705 if( GetBrush() != *wxTRANSPARENT_BRUSH )
12bdd77c
JS
2706 {
2707 wxPen tempPen( GetPen() );
2708 SetPen( *wxTRANSPARENT_PEN );
2709 DoDrawPolygon( n, points, 0, 0 );
2710 SetPen( tempPen );
2711 }
2712
2713 // then draw the arc without brush, if necessary
63b9e659 2714 if( GetPen() != *wxTRANSPARENT_PEN )
12bdd77c
JS
2715 {
2716 // without center
2717 DoDrawLines( n-1, points, 0, 0 );
2718 }
2719
2720 delete [] points;
2721
2722} // DrawEllipticArcRot
2723
b0d7707b 2724void wxDCBase::Rotate( wxPointList* points, double angle, wxPoint center )
12bdd77c
JS
2725{
2726 if( angle != 0.0 )
2727 {
e0d31471 2728 double pi(M_PI);
12bdd77c
JS
2729 double dSinA = -sin(angle*2.0*pi/360.0);
2730 double dCosA = cos(angle*2.0*pi/360.0);
b0d7707b
RR
2731 wxPointList::compatibility_iterator node;
2732 for ( node = points->GetFirst(); node; node = node->GetNext() )
12bdd77c 2733 {
b0d7707b 2734 wxPoint* point = node->GetData();
2aaa050c 2735
12bdd77c
JS
2736 // transform coordinates, if necessary
2737 if( center.x ) point->x -= center.x;
2738 if( center.y ) point->y -= center.y;
2739
2740 // calculate rotation, rounding simply by implicit cast to integer
2741 int xTemp = point->x * dCosA - point->y * dSinA;
2742 point->y = point->x * dSinA + point->y * dCosA;
2743 point->x = xTemp;
2744
2745 // back transform coordinates, if necessary
2746 if( center.x ) point->x += center.x;
2747 if( center.y ) point->y += center.y;
2748 }
2749 }
2750}
2751
b0d7707b 2752void wxDCBase::CalculateEllipticPoints( wxPointList* points,
2aaa050c
VZ
2753 wxCoord xStart, wxCoord yStart,
2754 wxCoord w, wxCoord h,
12bdd77c
JS
2755 double sa, double ea )
2756{
e0d31471 2757 double pi = M_PI;
12bdd77c
JS
2758 double sar = 0;
2759 double ear = 0;
2760 int xsa = 0;
2761 int ysa = 0;
2762 int xea = 0;
2763 int yea = 0;
2764 int sq = 0;
2765 int eq = 0;
2766 bool bUseAngles = false;
2767 if( w<0 ) w = -w;
2768 if( h<0 ) h = -h;
2769 // half-axes
2770 wxCoord a = w/2;
2771 wxCoord b = h/2;
2772 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
2773 int decrX = 0;
2aaa050c 2774 if( 2*a == w ) decrX = 1;
12bdd77c 2775 int decrY = 0;
2aaa050c 2776 if( 2*b == h ) decrY = 1;
12bdd77c
JS
2777 // center
2778 wxCoord xCenter = xStart + a;
2779 wxCoord yCenter = yStart + b;
2780 // calculate data for start and end, if necessary
2781 if( sa != ea )
2782 {
2783 bUseAngles = true;
2784 // normalisation of angles
2785 while( sa<0 ) sa += 360;
2786 while( ea<0 ) ea += 360;
2787 while( sa>=360 ) sa -= 360;
2788 while( ea>=360 ) ea -= 360;
2789 // calculate quadrant numbers
2790 if( sa > 270 ) sq = 3;
2791 else if( sa > 180 ) sq = 2;
2792 else if( sa > 90 ) sq = 1;
2793 if( ea > 270 ) eq = 3;
2794 else if( ea > 180 ) eq = 2;
2795 else if( ea > 90 ) eq = 1;
2796 sar = sa * pi / 180.0;
2797 ear = ea * pi / 180.0;
2798 // correct angle circle -> ellipse
2799 sar = atan( -a/(double)b * tan( sar ) );
2aaa050c 2800 if ( sq == 1 || sq == 2 ) sar += pi;
12bdd77c
JS
2801 ear = atan( -a/(double)b * tan( ear ) );
2802 if ( eq == 1 || eq == 2 ) ear += pi;
2803 // coordinates of points
2804 xsa = xCenter + a * cos( sar );
2805 if( sq == 0 || sq == 3 ) xsa -= decrX;
2806 ysa = yCenter + b * sin( sar );
2807 if( sq == 2 || sq == 3 ) ysa -= decrY;
2808 xea = xCenter + a * cos( ear );
2809 if( eq == 0 || eq == 3 ) xea -= decrX;
2810 yea = yCenter + b * sin( ear );
2811 if( eq == 2 || eq == 3 ) yea -= decrY;
2812 } // if iUseAngles
2813 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
2814 double c1 = b * b;
2815 double c2 = 2.0 / w;
2816 c2 *= c2;
2817 c2 *= c1;
2818 wxCoord x = 0;
2819 wxCoord y = b;
2820 long x2 = 1;
2821 long y2 = y*y;
2822 long y2_old = 0;
2823 long y_old = 0;
2824 // Lists for quadrant 1 to 4
b0d7707b 2825 wxPointList pointsarray[4];
12bdd77c
JS
2826 // Calculate points for first quadrant and set in all quadrants
2827 for( x = 0; x <= a; ++x )
2828 {
2829 x2 = x2+x+x-1;
2830 y2_old = y2;
2831 y_old = y;
2832 bool bNewPoint = false;
2833 while( y2 > c1 - c2 * x2 && y > 0 )
2834 {
2835 bNewPoint = true;
2836 y2 = y2-y-y+1;
2837 --y;
2838 }
2aaa050c 2839 // old y now to big: set point with old y, old x
12bdd77c
JS
2840 if( bNewPoint && x>1)
2841 {
2842 int x1 = x - 1;
2843 // remove points on the same line
b0d7707b
RR
2844 pointsarray[0].Insert( new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) );
2845 pointsarray[1].Append( new wxPoint( xCenter - x1, yCenter - y_old ) );
2846 pointsarray[2].Insert( new wxPoint( xCenter - x1, yCenter + y_old - decrY ) );
2847 pointsarray[3].Append( new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) );
12bdd77c
JS
2848 } // set point
2849 } // calculate point
2aaa050c 2850
12bdd77c 2851 // Starting and/or ending points for the quadrants, first quadrant gets both.
b0d7707b
RR
2852 pointsarray[0].Insert( new wxPoint( xCenter + a - decrX, yCenter ) );
2853 pointsarray[0].Append( new wxPoint( xCenter, yCenter - b ) );
2854 pointsarray[1].Append( new wxPoint( xCenter - a, yCenter ) );
2855 pointsarray[2].Append( new wxPoint( xCenter, yCenter + b - decrY ) );
2856 pointsarray[3].Append( new wxPoint( xCenter + a - decrX, yCenter ) );
12bdd77c
JS
2857
2858 // copy quadrants in original list
2859 if( bUseAngles )
2860 {
2861 // Copy the right part of the points in the lists
2862 // and delete the wxPoints, because they do not leave this method.
b0d7707b 2863 points->Append( new wxPoint( xsa, ysa ) );
12bdd77c
JS
2864 int q = sq;
2865 bool bStarted = false;
2866 bool bReady = false;
2867 bool bForceTurn = ( sq == eq && sa > ea );
2868 while( !bReady )
2869 {
b0d7707b
RR
2870 wxPointList::compatibility_iterator node;
2871 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
12bdd77c
JS
2872 {
2873 // once: go to starting point in start quadrant
2874 if( !bStarted &&
2aaa050c 2875 (
b0d7707b 2876 node->GetData()->x < xsa+1 && q <= 1
2aaa050c 2877 ||
b0d7707b 2878 node->GetData()->x > xsa-1 && q >= 2
12bdd77c 2879 )
2aaa050c 2880 )
12bdd77c
JS
2881 {
2882 bStarted = true;
2883 }
2884
2885 // copy point, if not at ending point
2886 if( bStarted )
2887 {
2888 if( q != eq || bForceTurn
2889 ||
2c3ebf8b 2890 ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1
2aaa050c 2891 ||
2c3ebf8b 2892 ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2
12bdd77c
JS
2893 )
2894 {
2895 // copy point
b0d7707b
RR
2896 wxPoint* pPoint = new wxPoint( *(node->GetData()) );
2897 points->Append( pPoint );
12bdd77c 2898 }
b0d7707b 2899 else if( q == eq && !bForceTurn || node->GetData()->x == xea)
12bdd77c 2900 {
2aaa050c 2901 bReady = true;
12bdd77c
JS
2902 }
2903 }
2904 } // for node
2905 ++q;
2906 if( q > 3 ) q = 0;
2907 bForceTurn = false;
2908 bStarted = true;
2909 } // while not bReady
b0d7707b 2910 points->Append( new wxPoint( xea, yea ) );
12bdd77c
JS
2911
2912 // delete points
2913 for( q = 0; q < 4; ++q )
2914 {
b0d7707b
RR
2915 wxPointList::compatibility_iterator node;
2916 for( node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
12bdd77c 2917 {
b0d7707b 2918 wxPoint *p = node->GetData();
12bdd77c
JS
2919 delete p;
2920 }
2aaa050c 2921 }
12bdd77c
JS
2922 }
2923 else
2924 {
b0d7707b 2925 wxPointList::compatibility_iterator node;
12bdd77c 2926 // copy whole ellipse, wxPoints will be deleted outside
2c3ebf8b 2927 for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() )
12bdd77c 2928 {
b0d7707b 2929 wxPoint *p = node->GetData();
12bdd77c
JS
2930 points->Append( p );
2931 }
2c3ebf8b 2932 for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() )
12bdd77c 2933 {
b0d7707b 2934 wxPoint *p = node->GetData();
12bdd77c
JS
2935 points->Append( p );
2936 }
2c3ebf8b 2937 for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() )
12bdd77c 2938 {
b0d7707b 2939 wxPoint *p = node->GetData();
12bdd77c
JS
2940 points->Append( p );
2941 }
2c3ebf8b 2942 for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() )
12bdd77c 2943 {
b0d7707b 2944 wxPoint *p = node->GetData();
12bdd77c
JS
2945 points->Append( p );
2946 }
2947 } // not iUseAngles
2948} // CalculateEllipticPoints
2949
e3b81044 2950#endif // __WXWINCE__
2970ae54
RR
2951
2952#endif // wxUSE_NEW_DC