1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/pen.cpp
4 // Author: Julian Smart
5 // Modified by: Vadim Zeitlin: refactored wxPen code to wxPenRefData
7 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
29 #include "wx/bitmap.h"
33 #include "wx/msw/private.h"
35 #define M_PENDATA ((wxPenRefData*)m_refData)
37 // Win32 has ExtCreatePen() but WinCE doesn't
38 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
39 #define wxHAVE_EXT_CREATE_PEN
42 // ----------------------------------------------------------------------------
43 // wxPenRefData: contains information about an HPEN and its handle
44 // ----------------------------------------------------------------------------
46 class WXDLLEXPORT wxPenRefData
: public wxGDIRefData
53 wxPenRefData(const wxPenRefData
& data
);
54 wxPenRefData(const wxColour
& col
, int width
, wxPenStyle style
);
55 wxPenRefData(const wxBitmap
& stipple
, int width
);
56 virtual ~wxPenRefData();
58 bool operator==(const wxPenRefData
& data
) const
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
&&
66 (m_style
!= wxPENSTYLE_STIPPLE
|| m_stipple
.IsSameAs(data
.m_stipple
)) &&
67 (m_style
!= wxPENSTYLE_USER_DASH
||
68 (m_nbDash
== data
.m_nbDash
&&
69 memcmp(m_dash
, data
.m_dash
, m_nbDash
*sizeof(wxDash
)) == 0));
73 // accessors and setters
74 // ---------------------
76 wxColour
& GetColour() const { return const_cast<wxColour
&>(m_colour
); }
77 int GetWidth() const { return m_width
; }
78 wxPenStyle
GetStyle() const { return m_style
; }
79 wxPenJoin
GetJoin() const { return m_join
; }
80 wxPenCap
GetCap() const { return m_cap
; }
81 wxDash
* GetDash() const { return m_dash
; }
82 int GetDashCount() const { return m_nbDash
; }
83 wxBitmap
* GetStipple() const { return const_cast<wxBitmap
*>(&m_stipple
); }
85 void SetColour(const wxColour
& col
) { Free(); m_colour
= col
; }
86 void SetWidth(int width
) { Free(); m_width
= width
; }
87 void SetStyle(wxPenStyle style
) { Free(); m_style
= style
; }
88 void SetStipple(const wxBitmap
& stipple
)
92 m_style
= wxPENSTYLE_STIPPLE
;
96 void SetDashes(int nb_dashes
, const wxDash
*dash
)
100 m_nbDash
= nb_dashes
;
101 m_dash
= const_cast<wxDash
*>(dash
);
104 void SetJoin(wxPenJoin join
) { Free(); m_join
= join
; }
105 void SetCap(wxPenCap cap
) { Free(); m_cap
= cap
; }
111 // create the HPEN if we don't have it yet
114 // get the HPEN creating it on demand
115 WXHPEN
GetHPEN() const;
117 // return true if we have a valid HPEN
118 bool HasHPEN() const { return m_hPen
!= 0; }
120 // return true if we had a valid handle before, false otherwise
124 // initialize the fields which have reasonable default values
126 // doesn't initialize m_width and m_style which must be initialize in ctor
129 m_join
= wxJOIN_ROUND
;
146 wxDECLARE_NO_ASSIGN_CLASS(wxPenRefData
);
149 // ============================================================================
151 // ============================================================================
153 // ----------------------------------------------------------------------------
154 // wxPenRefData ctors/dtor
155 // ----------------------------------------------------------------------------
157 wxPenRefData::wxPenRefData()
161 m_style
= wxPENSTYLE_SOLID
;
165 wxPenRefData::wxPenRefData(const wxPenRefData
& data
)
168 m_style
= data
.m_style
;
169 m_width
= data
.m_width
;
170 m_join
= data
.m_join
;
172 m_nbDash
= data
.m_nbDash
;
173 m_dash
= data
.m_dash
;
174 m_colour
= data
.m_colour
;
178 wxPenRefData::wxPenRefData(const wxColour
& col
, int width
, wxPenStyle style
)
188 wxPenRefData::wxPenRefData(const wxBitmap
& stipple
, int width
)
192 m_style
= wxPENSTYLE_STIPPLE
;
198 wxPenRefData::~wxPenRefData()
201 ::DeleteObject(m_hPen
);
204 // ----------------------------------------------------------------------------
205 // wxPenRefData HPEN management
206 // ----------------------------------------------------------------------------
208 static int ConvertPenStyle(wxPenStyle style
)
212 case wxPENSTYLE_SHORT_DASH
:
213 case wxPENSTYLE_LONG_DASH
:
216 case wxPENSTYLE_TRANSPARENT
:
220 wxFAIL_MSG( wxT("unknown pen style") );
223 #ifdef wxHAVE_EXT_CREATE_PEN
227 case wxPENSTYLE_DOT_DASH
:
230 case wxPENSTYLE_USER_DASH
:
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
:
241 #endif // wxHAVE_EXT_CREATE_PEN
247 #ifdef wxHAVE_EXT_CREATE_PEN
249 static int ConvertJoinStyle(wxPenJoin join
)
254 return PS_JOIN_BEVEL
;
257 return PS_JOIN_MITER
;
260 wxFAIL_MSG( wxT("unknown pen join style") );
264 return PS_JOIN_ROUND
;
268 static int ConvertCapStyle(wxPenCap cap
)
272 case wxCAP_PROJECTING
:
273 return PS_ENDCAP_SQUARE
;
276 return PS_ENDCAP_FLAT
;
279 wxFAIL_MSG( wxT("unknown pen cap style") );
283 return PS_ENDCAP_ROUND
;
287 #endif // wxHAVE_EXT_CREATE_PEN
289 bool wxPenRefData::Alloc()
294 if ( m_style
== wxPENSTYLE_TRANSPARENT
)
296 m_hPen
= (HPEN
)::GetStockObject(NULL_PEN
);
300 const COLORREF col
= m_colour
.GetPixel();
302 #ifdef wxHAVE_EXT_CREATE_PEN
303 // Only NT can display dashed or dotted lines with width > 1
304 static const int os
= wxGetOsVersion();
305 if ( os
!= wxOS_WINDOWS_NT
&&
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
) &&
316 // check if it's a standard kind of pen which can be created with just
318 if ( m_join
== wxJOIN_ROUND
&&
319 m_cap
== wxCAP_ROUND
&&
320 m_style
!= wxPENSTYLE_USER_DASH
&&
321 m_style
!= wxPENSTYLE_STIPPLE
&&
322 (m_width
<= 1 || m_style
== wxPENSTYLE_SOLID
) )
323 #endif // !wxHAVE_EXT_CREATE_PEN
325 m_hPen
= ::CreatePen(ConvertPenStyle(m_style
), m_width
, col
);
327 #ifdef wxHAVE_EXT_CREATE_PEN
328 else // need to use ExtCreatePen()
330 DWORD styleMSW
= PS_GEOMETRIC
|
331 ConvertPenStyle(m_style
) |
332 ConvertJoinStyle(m_join
) |
333 ConvertCapStyle(m_cap
);
338 case wxPENSTYLE_STIPPLE
:
339 lb
.lbStyle
= BS_PATTERN
;
340 lb
.lbHatch
= wxPtrToUInt(m_stipple
.GetHBITMAP());
343 case wxPENSTYLE_BDIAGONAL_HATCH
:
344 lb
.lbStyle
= BS_HATCHED
;
345 lb
.lbHatch
= HS_BDIAGONAL
;
348 case wxPENSTYLE_CROSSDIAG_HATCH
:
349 lb
.lbStyle
= BS_HATCHED
;
350 lb
.lbHatch
= HS_DIAGCROSS
;
353 case wxPENSTYLE_FDIAGONAL_HATCH
:
354 lb
.lbStyle
= BS_HATCHED
;
355 lb
.lbHatch
= HS_FDIAGONAL
;
358 case wxPENSTYLE_CROSS_HATCH
:
359 lb
.lbStyle
= BS_HATCHED
;
360 lb
.lbHatch
= HS_CROSS
;
363 case wxPENSTYLE_HORIZONTAL_HATCH
:
364 lb
.lbStyle
= BS_HATCHED
;
365 lb
.lbHatch
= HS_HORIZONTAL
;
368 case wxPENSTYLE_VERTICAL_HATCH
:
369 lb
.lbStyle
= BS_HATCHED
;
370 lb
.lbHatch
= HS_VERTICAL
;
374 lb
.lbStyle
= BS_SOLID
;
375 // this should be unnecessary (it's unused) but suppresses the
376 // Purify messages about uninitialized memory read
384 if ( m_style
== wxPENSTYLE_USER_DASH
&& m_nbDash
&& m_dash
)
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
;
396 m_hPen
= ::ExtCreatePen(styleMSW
, m_width
, &lb
, m_nbDash
, (LPDWORD
)dash
);
400 #endif // wxHAVE_EXT_CREATE_PEN
405 bool wxPenRefData::Free()
410 ::DeleteObject(m_hPen
);
416 WXHPEN
wxPenRefData::GetHPEN() const
419 const_cast<wxPenRefData
*>(this)->Alloc();
421 return (WXHPEN
)m_hPen
;
424 // ----------------------------------------------------------------------------
426 // ----------------------------------------------------------------------------
428 IMPLEMENT_DYNAMIC_CLASS(wxPen
, wxGDIObject
)
430 wxPen::wxPen(const wxColour
& col
, int width
, wxPenStyle style
)
432 m_refData
= new wxPenRefData(col
, width
, style
);
435 #if FUTURE_WXWIN_COMPATIBILITY_3_0
436 wxPen::wxPen(const wxColour
& colour
, int width
, int style
)
438 m_refData
= new wxPenRefData(colour
, width
, (wxPenStyle
)style
);
442 wxPen::wxPen(const wxBitmap
& stipple
, int width
)
444 m_refData
= new wxPenRefData(stipple
, width
);
447 bool wxPen::operator==(const wxPen
& pen
) const
450 penData
= static_cast<const wxPenRefData
*>(pen
.m_refData
);
452 // an invalid pen is only equal to another invalid pen
453 return m_refData
? penData
&& *M_PENDATA
== *penData
: !penData
;
456 bool wxPen::RealizeResource()
458 return M_PENDATA
&& M_PENDATA
->Alloc();
461 WXHANDLE
wxPen::GetResourceHandle() const
463 return M_PENDATA
? M_PENDATA
->GetHPEN() : 0;
466 bool wxPen::FreeResource(bool WXUNUSED(force
))
468 return M_PENDATA
&& M_PENDATA
->Free();
471 bool wxPen::IsFree() const
473 return M_PENDATA
&& !M_PENDATA
->HasHPEN();
476 wxGDIRefData
* wxPen::CreateGDIRefData() const
478 return new wxPenRefData
;
481 wxGDIRefData
* wxPen::CloneGDIRefData(const wxGDIRefData
* data
) const
483 return new wxPenRefData(*static_cast<const wxPenRefData
*>(data
));
486 void wxPen::SetColour(const wxColour
& col
)
490 M_PENDATA
->SetColour(col
);
493 void wxPen::SetColour(unsigned char r
, unsigned char g
, unsigned char b
)
495 SetColour(wxColour(r
, g
, b
));
498 void wxPen::SetWidth(int width
)
502 M_PENDATA
->SetWidth(width
);
505 void wxPen::SetStyle(wxPenStyle style
)
509 M_PENDATA
->SetStyle(style
);
512 void wxPen::SetStipple(const wxBitmap
& stipple
)
516 M_PENDATA
->SetStipple(stipple
);
519 void wxPen::SetDashes(int nb_dashes
, const wxDash
*dash
)
523 M_PENDATA
->SetDashes(nb_dashes
, dash
);
526 void wxPen::SetJoin(wxPenJoin join
)
530 M_PENDATA
->SetJoin(join
);
533 void wxPen::SetCap(wxPenCap cap
)
537 M_PENDATA
->SetCap(cap
);
540 wxColour
wxPen::GetColour() const
542 wxCHECK_MSG( IsOk(), wxNullColour
, wxT("invalid pen") );
544 return M_PENDATA
->GetColour();
547 int wxPen::GetWidth() const
549 wxCHECK_MSG( IsOk(), -1, wxT("invalid pen") );
551 return M_PENDATA
->GetWidth();
554 wxPenStyle
wxPen::GetStyle() const
556 wxCHECK_MSG( IsOk(), wxPENSTYLE_INVALID
, wxT("invalid pen") );
558 return M_PENDATA
->GetStyle();
561 wxPenJoin
wxPen::GetJoin() const
563 wxCHECK_MSG( IsOk(), wxJOIN_INVALID
, wxT("invalid pen") );
565 return M_PENDATA
->GetJoin();
568 wxPenCap
wxPen::GetCap() const
570 wxCHECK_MSG( IsOk(), wxCAP_INVALID
, wxT("invalid pen") );
572 return M_PENDATA
->GetCap();
575 int wxPen::GetDashes(wxDash
** ptr
) const
577 wxCHECK_MSG( IsOk(), -1, wxT("invalid pen") );
579 *ptr
= M_PENDATA
->GetDash();
580 return M_PENDATA
->GetDashCount();
583 wxDash
* wxPen::GetDash() const
585 wxCHECK_MSG( IsOk(), NULL
, wxT("invalid pen") );
587 return m_refData
? M_PENDATA
->GetDash() : NULL
;
590 int wxPen::GetDashCount() const
592 wxCHECK_MSG( IsOk(), -1, wxT("invalid pen") );
594 return m_refData
? M_PENDATA
->GetDashCount() : 0;
597 wxBitmap
* wxPen::GetStipple() const
599 wxCHECK_MSG( IsOk(), NULL
, wxT("invalid pen") );
601 return m_refData
? M_PENDATA
->GetStipple() : NULL
;