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