]> git.saurik.com Git - wxWidgets.git/blame - src/msw/pen.cpp
Forward port 2.8 fix.
[wxWidgets.git] / src / msw / pen.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
46562151 2// Name: src/msw/pen.cpp
2bda0e17
KB
3// Purpose: wxPen
4// Author: Julian Smart
8c583381 5// Modified by: Vadim Zeitlin: refactored wxPen code to wxPenRefData
2bda0e17
KB
6// Created: 04/01/98
7// RCS-ID: $Id$
6c9a19aa 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
8c583381
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
2bda0e17
KB
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
8ecff181 24 #pragma hdrstop
2bda0e17
KB
25#endif
26
f5590243
WS
27#include "wx/pen.h"
28
2bda0e17 29#ifndef WX_PRECOMP
ce3b4b90 30 #include "wx/bitmap.h"
8ecff181 31 #include "wx/utils.h"
2bda0e17
KB
32#endif
33
34#include "wx/msw/private.h"
2bda0e17 35
8c583381 36#define M_PENDATA ((wxPenRefData*)m_refData)
ce3b4b90 37
8c583381
VZ
38// Win32 has ExtCreatePen() but WinCE doesn't
39#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
40 #define wxHAVE_EXT_CREATE_PEN
41#endif
ef59847c 42
8c583381
VZ
43// ----------------------------------------------------------------------------
44// wxPenRefData: contains information about an HPEN and its handle
45// ----------------------------------------------------------------------------
ce3b4b90
PC
46
47class WXDLLEXPORT wxPenRefData : public wxGDIRefData
48{
49public:
8c583381
VZ
50 // ctors and dtor
51 // --------------
52
ce3b4b90
PC
53 wxPenRefData();
54 wxPenRefData(const wxPenRefData& data);
82cddbd9 55 wxPenRefData(const wxColour& col, int width, wxPenStyle style);
8c583381 56 wxPenRefData(const wxBitmap& stipple, int width);
ce3b4b90
PC
57 virtual ~wxPenRefData();
58
59 bool operator==(const wxPenRefData& data) const
60 {
61 // we intentionally don't compare m_hPen fields here
62 return m_style == data.m_style &&
63 m_width == data.m_width &&
64 m_join == data.m_join &&
65 m_cap == data.m_cap &&
66 m_colour == data.m_colour &&
ed7ec76d
FM
67 (m_style != wxPENSTYLE_STIPPLE || m_stipple.IsSameAs(data.m_stipple)) &&
68 (m_style != wxPENSTYLE_USER_DASH ||
ce3b4b90
PC
69 (m_nbDash == data.m_nbDash &&
70 memcmp(m_dash, data.m_dash, m_nbDash*sizeof(wxDash)) == 0));
71 }
72
8c583381
VZ
73
74 // accessors and setters
75 // ---------------------
76
5c33522f 77 wxColour& GetColour() const { return const_cast<wxColour&>(m_colour); }
8c583381 78 int GetWidth() const { return m_width; }
82cddbd9
FM
79 wxPenStyle GetStyle() const { return m_style; }
80 wxPenJoin GetJoin() const { return m_join; }
81 wxPenCap GetCap() const { return m_cap; }
8c583381
VZ
82 wxDash* GetDash() const { return m_dash; }
83 int GetDashCount() const { return m_nbDash; }
5c33522f 84 wxBitmap* GetStipple() const { return const_cast<wxBitmap *>(&m_stipple); }
8c583381
VZ
85
86 void SetColour(const wxColour& col) { Free(); m_colour = col; }
87 void SetWidth(int width) { Free(); m_width = width; }
82cddbd9 88 void SetStyle(wxPenStyle style) { Free(); m_style = style; }
8c583381
VZ
89 void SetStipple(const wxBitmap& stipple)
90 {
91 Free();
92
777819af 93 m_style = wxPENSTYLE_STIPPLE;
8c583381
VZ
94 m_stipple = stipple;
95 }
96
97 void SetDashes(int nb_dashes, const wxDash *dash)
98 {
99 Free();
100
101 m_nbDash = nb_dashes;
5c33522f 102 m_dash = const_cast<wxDash *>(dash);
8c583381
VZ
103 }
104
82cddbd9
FM
105 void SetJoin(wxPenJoin join) { Free(); m_join = join; }
106 void SetCap(wxPenCap cap) { Free(); m_cap = cap; }
8c583381
VZ
107
108
109 // HPEN management
110 // ---------------
111
112 // create the HPEN if we don't have it yet
113 bool Alloc();
114
115 // get the HPEN creating it on demand
116 WXHPEN GetHPEN() const;
117
118 // return true if we have a valid HPEN
119 bool HasHPEN() const { return m_hPen != 0; }
120
121 // return true if we had a valid handle before, false otherwise
122 bool Free();
123
124private:
125 // initialize the fields which have reasonable default values
126 //
127 // doesn't initialize m_width and m_style which must be initialize in ctor
128 void Init()
129 {
130 m_join = wxJOIN_ROUND;
131 m_cap = wxCAP_ROUND;
132 m_nbDash = 0;
133 m_dash = NULL;
134 m_hPen = 0;
135 }
136
ce3b4b90 137 int m_width;
82cddbd9
FM
138 wxPenStyle m_style;
139 wxPenJoin m_join;
140 wxPenCap m_cap;
ce3b4b90
PC
141 wxBitmap m_stipple;
142 int m_nbDash;
143 wxDash * m_dash;
144 wxColour m_colour;
8c583381 145 HPEN m_hPen;
ce3b4b90 146
c0c133e1 147 wxDECLARE_NO_ASSIGN_CLASS(wxPenRefData);
ce3b4b90 148};
2bda0e17 149
8c583381
VZ
150// ============================================================================
151// implementation
152// ============================================================================
153
154// ----------------------------------------------------------------------------
155// wxPenRefData ctors/dtor
156// ----------------------------------------------------------------------------
157
e4a81a2e 158wxPenRefData::wxPenRefData()
2bda0e17 159{
8c583381
VZ
160 Init();
161
777819af 162 m_style = wxPENSTYLE_SOLID;
8c583381 163 m_width = 1;
2bda0e17
KB
164}
165
b823f5a1 166wxPenRefData::wxPenRefData(const wxPenRefData& data)
04a18b0d 167 :wxGDIRefData()
b823f5a1
JS
168{
169 m_style = data.m_style;
170 m_width = data.m_width;
171 m_join = data.m_join;
172 m_cap = data.m_cap;
173 m_nbDash = data.m_nbDash;
174 m_dash = data.m_dash;
175 m_colour = data.m_colour;
176 m_hPen = 0;
177}
178
82cddbd9 179wxPenRefData::wxPenRefData(const wxColour& col, int width, wxPenStyle style)
2bda0e17 180{
8c583381 181 Init();
2bda0e17 182
8c583381
VZ
183 m_style = style;
184 m_width = width;
2bda0e17 185
8c583381
VZ
186 m_colour = col;
187}
ce3b4b90 188
8c583381 189wxPenRefData::wxPenRefData(const wxBitmap& stipple, int width)
2bda0e17 190{
8c583381
VZ
191 Init();
192
777819af 193 m_style = wxPENSTYLE_STIPPLE;
8c583381
VZ
194 m_width = width;
195
196 m_stipple = stipple;
2bda0e17
KB
197}
198
8c583381 199wxPenRefData::~wxPenRefData()
2bda0e17 200{
8c583381
VZ
201 if ( m_hPen )
202 ::DeleteObject(m_hPen);
2bda0e17
KB
203}
204
8c583381
VZ
205// ----------------------------------------------------------------------------
206// wxPenRefData HPEN management
207// ----------------------------------------------------------------------------
208
82cddbd9 209static int ConvertPenStyle(wxPenStyle style)
2bda0e17 210{
8c583381
VZ
211 switch ( style )
212 {
777819af
FM
213 case wxPENSTYLE_SHORT_DASH:
214 case wxPENSTYLE_LONG_DASH:
8c583381
VZ
215 return PS_DASH;
216
777819af 217 case wxPENSTYLE_TRANSPARENT:
8c583381 218 return PS_NULL;
2bda0e17 219
8c583381 220 default:
9a83f860 221 wxFAIL_MSG( wxT("unknown pen style") );
8c583381
VZ
222 // fall through
223
d6f2a891 224#ifdef wxHAVE_EXT_CREATE_PEN
777819af 225 case wxPENSTYLE_DOT:
d6f2a891
VZ
226 return PS_DOT;
227
777819af 228 case wxPENSTYLE_DOT_DASH:
d6f2a891
VZ
229 return PS_DASHDOT;
230
777819af 231 case wxPENSTYLE_USER_DASH:
d6f2a891
VZ
232 return PS_USERSTYLE;
233
777819af
FM
234 case wxPENSTYLE_STIPPLE:
235 case wxPENSTYLE_BDIAGONAL_HATCH:
236 case wxPENSTYLE_CROSSDIAG_HATCH:
237 case wxPENSTYLE_FDIAGONAL_HATCH:
238 case wxPENSTYLE_CROSS_HATCH:
239 case wxPENSTYLE_HORIZONTAL_HATCH:
240 case wxPENSTYLE_VERTICAL_HATCH:
241 case wxPENSTYLE_SOLID:
d6f2a891
VZ
242#endif // wxHAVE_EXT_CREATE_PEN
243
8c583381
VZ
244 return PS_SOLID;
245 }
2bda0e17
KB
246}
247
d6f2a891
VZ
248#ifdef wxHAVE_EXT_CREATE_PEN
249
82cddbd9 250static int ConvertJoinStyle(wxPenJoin join)
2bda0e17 251{
8c583381
VZ
252 switch( join )
253 {
254 case wxJOIN_BEVEL:
255 return PS_JOIN_BEVEL;
2bda0e17 256
8c583381
VZ
257 case wxJOIN_MITER:
258 return PS_JOIN_MITER;
2bda0e17 259
8c583381 260 default:
9a83f860 261 wxFAIL_MSG( wxT("unknown pen join style") );
8c583381
VZ
262 // fall through
263
264 case wxJOIN_ROUND:
265 return PS_JOIN_ROUND;
266 }
2bda0e17
KB
267}
268
82cddbd9 269static int ConvertCapStyle(wxPenCap cap)
ce3b4b90 270{
8c583381
VZ
271 switch ( cap )
272 {
273 case wxCAP_PROJECTING:
274 return PS_ENDCAP_SQUARE;
ce3b4b90 275
8c583381
VZ
276 case wxCAP_BUTT:
277 return PS_ENDCAP_FLAT;
278
279 default:
9a83f860 280 wxFAIL_MSG( wxT("unknown pen cap style") );
8c583381
VZ
281 // fall through
282
283 case wxCAP_ROUND:
284 return PS_ENDCAP_ROUND;
285 }
ce3b4b90
PC
286}
287
8c583381
VZ
288#endif // wxHAVE_EXT_CREATE_PEN
289
290bool wxPenRefData::Alloc()
2bda0e17 291{
8c583381 292 if ( m_hPen )
8b0975a3
VZ
293 return false;
294
777819af 295 if ( m_style == wxPENSTYLE_TRANSPARENT )
c45a644e 296 {
8c583381 297 m_hPen = (HPEN)::GetStockObject(NULL_PEN);
8b0975a3
VZ
298 return true;
299 }
300
8c583381 301 const COLORREF col = m_colour.GetPixel();
8b0975a3 302
8c583381 303#ifdef wxHAVE_EXT_CREATE_PEN
8b0975a3 304 // Only NT can display dashed or dotted lines with width > 1
8c583381 305 static const int os = wxGetOsVersion();
406d283a 306 if ( os != wxOS_WINDOWS_NT &&
ed7ec76d
FM
307 (m_style == wxPENSTYLE_DOT ||
308 m_style == wxPENSTYLE_LONG_DASH ||
309 m_style == wxPENSTYLE_SHORT_DASH ||
310 m_style == wxPENSTYLE_DOT_DASH ||
311 m_style == wxPENSTYLE_USER_DASH) &&
8c583381 312 m_width > 1 )
8b0975a3 313 {
8c583381 314 m_width = 1;
8b0975a3
VZ
315 }
316
8c583381
VZ
317 // check if it's a standard kind of pen which can be created with just
318 // CreatePen()
319 if ( m_join == wxJOIN_ROUND &&
320 m_cap == wxCAP_ROUND &&
ed7ec76d
FM
321 m_style != wxPENSTYLE_USER_DASH &&
322 m_style != wxPENSTYLE_STIPPLE &&
323 (m_width <= 1 || m_style == wxPENSTYLE_SOLID) )
8c583381 324#endif // !wxHAVE_EXT_CREATE_PEN
8b0975a3 325 {
8c583381 326 m_hPen = ::CreatePen(ConvertPenStyle(m_style), m_width, col);
8b0975a3 327 }
8c583381
VZ
328#ifdef wxHAVE_EXT_CREATE_PEN
329 else // need to use ExtCreatePen()
8b0975a3 330 {
8c583381
VZ
331 DWORD styleMSW = PS_GEOMETRIC |
332 ConvertPenStyle(m_style) |
333 ConvertJoinStyle(m_join) |
334 ConvertCapStyle(m_cap);
8b0975a3 335
8c583381
VZ
336 LOGBRUSH lb;
337 switch( m_style )
c45a644e 338 {
777819af 339 case wxPENSTYLE_STIPPLE:
8c583381 340 lb.lbStyle = BS_PATTERN;
dca0f651 341 lb.lbHatch = wxPtrToUInt(m_stipple.GetHBITMAP());
8b0975a3 342 break;
8c583381 343
777819af 344 case wxPENSTYLE_BDIAGONAL_HATCH:
8c583381
VZ
345 lb.lbStyle = BS_HATCHED;
346 lb.lbHatch = HS_BDIAGONAL;
8b0975a3 347 break;
8c583381 348
777819af 349 case wxPENSTYLE_CROSSDIAG_HATCH:
8c583381
VZ
350 lb.lbStyle = BS_HATCHED;
351 lb.lbHatch = HS_DIAGCROSS;
8b0975a3 352 break;
8c583381 353
777819af 354 case wxPENSTYLE_FDIAGONAL_HATCH:
8c583381
VZ
355 lb.lbStyle = BS_HATCHED;
356 lb.lbHatch = HS_FDIAGONAL;
8b0975a3 357 break;
8c583381 358
777819af 359 case wxPENSTYLE_CROSS_HATCH:
8c583381
VZ
360 lb.lbStyle = BS_HATCHED;
361 lb.lbHatch = HS_CROSS;
8b0975a3 362 break;
8c583381 363
777819af 364 case wxPENSTYLE_HORIZONTAL_HATCH:
8c583381
VZ
365 lb.lbStyle = BS_HATCHED;
366 lb.lbHatch = HS_HORIZONTAL;
8b0975a3 367 break;
8c583381 368
777819af 369 case wxPENSTYLE_VERTICAL_HATCH:
8c583381
VZ
370 lb.lbStyle = BS_HATCHED;
371 lb.lbHatch = HS_VERTICAL;
8b0975a3 372 break;
8c583381 373
8b0975a3 374 default:
8c583381 375 lb.lbStyle = BS_SOLID;
8c583381
VZ
376 // this should be unnecessary (it's unused) but suppresses the
377 // Purify messages about uninitialized memory read
378 lb.lbHatch = 0;
8b0975a3 379 break;
c45a644e 380 }
8b0975a3 381
8c583381 382 lb.lbColor = col;
8b0975a3 383
8c583381 384 DWORD *dash;
777819af 385 if ( m_style == wxPENSTYLE_USER_DASH && m_nbDash && m_dash )
8b0975a3 386 {
8c583381
VZ
387 dash = new DWORD[m_nbDash];
388 int rw = m_width > 1 ? m_width : 1;
389 for ( int i = 0; i < m_nbDash; i++ )
390 dash[i] = m_dash[i] * rw;
8b0975a3
VZ
391 }
392 else
393 {
8c583381 394 dash = NULL;
8b0975a3
VZ
395 }
396
8c583381 397 m_hPen = ::ExtCreatePen(styleMSW, m_width, &lb, m_nbDash, (LPDWORD)dash);
8b0975a3 398
8c583381 399 delete [] dash;
8b0975a3 400 }
8c583381
VZ
401#endif // wxHAVE_EXT_CREATE_PEN
402
403 return m_hPen != 0;
404}
405
406bool wxPenRefData::Free()
407{
408 if ( !m_hPen )
409 return false;
410
411 ::DeleteObject(m_hPen);
412 m_hPen = 0;
413
414 return true;
415}
416
417WXHPEN wxPenRefData::GetHPEN() const
418{
419 if ( !m_hPen )
5c33522f 420 const_cast<wxPenRefData *>(this)->Alloc();
8c583381
VZ
421
422 return (WXHPEN)m_hPen;
423}
424
425// ----------------------------------------------------------------------------
426// wxPen
427// ----------------------------------------------------------------------------
428
429IMPLEMENT_DYNAMIC_CLASS(wxPen, wxGDIObject)
430
777819af 431wxPen::wxPen(const wxColour& col, int width, wxPenStyle style)
8c583381
VZ
432{
433 m_refData = new wxPenRefData(col, width, style);
434}
435
ac3688c0
FM
436#if FUTURE_WXWIN_COMPATIBILITY_3_0
437wxPen::wxPen(const wxColour& colour, int width, int style)
82cddbd9 438{
777819af 439 m_refData = new wxPenRefData(colour, width, (wxPenStyle)style);
82cddbd9 440}
ac3688c0 441#endif
82cddbd9 442
8c583381
VZ
443wxPen::wxPen(const wxBitmap& stipple, int width)
444{
445 m_refData = new wxPenRefData(stipple, width);
446}
447
448bool wxPen::operator==(const wxPen& pen) const
449{
450 const wxPenRefData *
5c33522f 451 penData = static_cast<const wxPenRefData *>(pen.m_refData);
8c583381
VZ
452
453 // an invalid pen is only equal to another invalid pen
454 return m_refData ? penData && *M_PENDATA == *penData : !penData;
455}
8b0975a3 456
8c583381
VZ
457bool wxPen::RealizeResource()
458{
459 return M_PENDATA && M_PENDATA->Alloc();
2bda0e17
KB
460}
461
2b5f62a0 462WXHANDLE wxPen::GetResourceHandle() const
2bda0e17 463{
8c583381 464 return M_PENDATA ? M_PENDATA->GetHPEN() : 0;
2bda0e17
KB
465}
466
33ac7e6f 467bool wxPen::FreeResource(bool WXUNUSED(force))
2bda0e17 468{
8c583381 469 return M_PENDATA && M_PENDATA->Free();
2bda0e17
KB
470}
471
e4a81a2e 472bool wxPen::IsFree() const
2bda0e17 473{
8c583381 474 return M_PENDATA && !M_PENDATA->HasHPEN();
2bda0e17 475}
2bda0e17 476
8f884a0d 477wxGDIRefData* wxPen::CreateGDIRefData() const
2bda0e17 478{
385fa875 479 return new wxPenRefData;
7c310bc8
PC
480}
481
8f884a0d 482wxGDIRefData* wxPen::CloneGDIRefData(const wxGDIRefData* data) const
7c310bc8 483{
5c33522f 484 return new wxPenRefData(*static_cast<const wxPenRefData*>(data));
2bda0e17
KB
485}
486
487void wxPen::SetColour(const wxColour& col)
488{
7c310bc8 489 AllocExclusive();
2bda0e17 490
8c583381 491 M_PENDATA->SetColour(col);
2bda0e17
KB
492}
493
1a1498c0 494void wxPen::SetColour(unsigned char r, unsigned char g, unsigned char b)
2bda0e17 495{
8c583381 496 SetColour(wxColour(r, g, b));
2bda0e17
KB
497}
498
8c583381 499void wxPen::SetWidth(int width)
2bda0e17 500{
7c310bc8 501 AllocExclusive();
2bda0e17 502
8c583381 503 M_PENDATA->SetWidth(width);
2bda0e17
KB
504}
505
82cddbd9 506void wxPen::SetStyle(wxPenStyle style)
2bda0e17 507{
7c310bc8 508 AllocExclusive();
2bda0e17 509
8c583381 510 M_PENDATA->SetStyle(style);
2bda0e17
KB
511}
512
8c583381 513void wxPen::SetStipple(const wxBitmap& stipple)
2bda0e17 514{
7c310bc8 515 AllocExclusive();
2bda0e17 516
8c583381 517 M_PENDATA->SetStipple(stipple);
2bda0e17
KB
518}
519
8c583381 520void wxPen::SetDashes(int nb_dashes, const wxDash *dash)
2bda0e17 521{
7c310bc8 522 AllocExclusive();
2bda0e17 523
8c583381 524 M_PENDATA->SetDashes(nb_dashes, dash);
2bda0e17
KB
525}
526
82cddbd9 527void wxPen::SetJoin(wxPenJoin join)
2bda0e17 528{
7c310bc8 529 AllocExclusive();
2bda0e17 530
8c583381 531 M_PENDATA->SetJoin(join);
2bda0e17
KB
532}
533
82cddbd9 534void wxPen::SetCap(wxPenCap cap)
2bda0e17 535{
7c310bc8 536 AllocExclusive();
2bda0e17 537
8c583381 538 M_PENDATA->SetCap(cap);
2bda0e17
KB
539}
540
231b9591 541wxColour wxPen::GetColour() const
ce3b4b90 542{
ac3688c0
FM
543 wxCHECK_MSG( Ok(), wxNullColour, wxT("invalid pen") );
544
545 return M_PENDATA->GetColour();
ce3b4b90
PC
546}
547
548int wxPen::GetWidth() const
549{
ac3688c0
FM
550 wxCHECK_MSG( Ok(), -1, wxT("invalid pen") );
551
552 return M_PENDATA->GetWidth();
ce3b4b90
PC
553}
554
82cddbd9 555wxPenStyle wxPen::GetStyle() const
ce3b4b90 556{
ac3688c0
FM
557 wxCHECK_MSG( Ok(), wxPENSTYLE_INVALID, wxT("invalid pen") );
558
559 return M_PENDATA->GetStyle();
ce3b4b90
PC
560}
561
82cddbd9 562wxPenJoin wxPen::GetJoin() const
ce3b4b90 563{
ac3688c0
FM
564 wxCHECK_MSG( Ok(), wxJOIN_INVALID, wxT("invalid pen") );
565
566 return M_PENDATA->GetJoin();
ce3b4b90
PC
567}
568
82cddbd9 569wxPenCap wxPen::GetCap() const
ce3b4b90 570{
ac3688c0
FM
571 wxCHECK_MSG( Ok(), wxCAP_INVALID, wxT("invalid pen") );
572
573 return M_PENDATA->GetCap();
ce3b4b90
PC
574}
575
576int wxPen::GetDashes(wxDash** ptr) const
577{
ac3688c0 578 wxCHECK_MSG( Ok(), -1, wxT("invalid pen") );
8c583381
VZ
579
580 *ptr = M_PENDATA->GetDash();
581 return M_PENDATA->GetDashCount();
ce3b4b90
PC
582}
583
584wxDash* wxPen::GetDash() const
585{
ac3688c0
FM
586 wxCHECK_MSG( Ok(), NULL, wxT("invalid pen") );
587
8c583381 588 return m_refData ? M_PENDATA->GetDash() : NULL;
ce3b4b90
PC
589}
590
591int wxPen::GetDashCount() const
592{
ac3688c0
FM
593 wxCHECK_MSG( Ok(), -1, wxT("invalid pen") );
594
8c583381 595 return m_refData ? M_PENDATA->GetDashCount() : 0;
ce3b4b90
PC
596}
597
598wxBitmap* wxPen::GetStipple() const
599{
ac3688c0
FM
600 wxCHECK_MSG( Ok(), NULL, wxT("invalid pen") );
601
8c583381 602 return m_refData ? M_PENDATA->GetStipple() : NULL;
2bda0e17 603}