1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/pen.cpp
4 // Author: Julian Smart
5 // Modified by: Vadim Zeitlin: refactored wxPen code to wxPenRefData
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
30 #include "wx/bitmap.h"
34 #include "wx/msw/private.h"
36 #define M_PENDATA ((wxPenRefData*)m_refData)
38 // Win32 has ExtCreatePen() but WinCE doesn't
39 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
40 #define wxHAVE_EXT_CREATE_PEN
43 // ----------------------------------------------------------------------------
44 // wxPenRefData: contains information about an HPEN and its handle
45 // ----------------------------------------------------------------------------
47 class WXDLLEXPORT wxPenRefData
: public wxGDIRefData
54 wxPenRefData(const wxPenRefData
& data
);
55 wxPenRefData(const wxColour
& col
, int width
, wxPenStyle style
);
56 wxPenRefData(const wxBitmap
& stipple
, int width
);
57 virtual ~wxPenRefData();
59 bool operator==(const wxPenRefData
& data
) const
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
&&
67 (m_style
!= wxPENSTYLE_STIPPLE
|| m_stipple
.IsSameAs(data
.m_stipple
)) &&
68 (m_style
!= wxPENSTYLE_USER_DASH
||
69 (m_nbDash
== data
.m_nbDash
&&
70 memcmp(m_dash
, data
.m_dash
, m_nbDash
*sizeof(wxDash
)) == 0));
74 // accessors and setters
75 // ---------------------
77 wxColour
& GetColour() const { return const_cast<wxColour
&>(m_colour
); }
78 int GetWidth() const { return m_width
; }
79 wxPenStyle
GetStyle() const { return m_style
; }
80 wxPenJoin
GetJoin() const { return m_join
; }
81 wxPenCap
GetCap() const { return m_cap
; }
82 wxDash
* GetDash() const { return m_dash
; }
83 int GetDashCount() const { return m_nbDash
; }
84 wxBitmap
* GetStipple() const { return const_cast<wxBitmap
*>(&m_stipple
); }
86 void SetColour(const wxColour
& col
) { Free(); m_colour
= col
; }
87 void SetWidth(int width
) { Free(); m_width
= width
; }
88 void SetStyle(wxPenStyle style
) { Free(); m_style
= style
; }
89 void SetStipple(const wxBitmap
& stipple
)
93 m_style
= wxPENSTYLE_STIPPLE
;
97 void SetDashes(int nb_dashes
, const wxDash
*dash
)
101 m_nbDash
= nb_dashes
;
102 m_dash
= const_cast<wxDash
*>(dash
);
105 void SetJoin(wxPenJoin join
) { Free(); m_join
= join
; }
106 void SetCap(wxPenCap cap
) { Free(); m_cap
= cap
; }
112 // create the HPEN if we don't have it yet
115 // get the HPEN creating it on demand
116 WXHPEN
GetHPEN() const;
118 // return true if we have a valid HPEN
119 bool HasHPEN() const { return m_hPen
!= 0; }
121 // return true if we had a valid handle before, false otherwise
125 // initialize the fields which have reasonable default values
127 // doesn't initialize m_width and m_style which must be initialize in ctor
130 m_join
= wxJOIN_ROUND
;
147 wxDECLARE_NO_ASSIGN_CLASS(wxPenRefData
);
150 // ============================================================================
152 // ============================================================================
154 // ----------------------------------------------------------------------------
155 // wxPenRefData ctors/dtor
156 // ----------------------------------------------------------------------------
158 wxPenRefData::wxPenRefData()
162 m_style
= wxPENSTYLE_SOLID
;
166 wxPenRefData::wxPenRefData(const wxPenRefData
& data
)
169 m_style
= data
.m_style
;
170 m_width
= data
.m_width
;
171 m_join
= data
.m_join
;
173 m_nbDash
= data
.m_nbDash
;
174 m_dash
= data
.m_dash
;
175 m_colour
= data
.m_colour
;
179 wxPenRefData::wxPenRefData(const wxColour
& col
, int width
, wxPenStyle style
)
189 wxPenRefData::wxPenRefData(const wxBitmap
& stipple
, int width
)
193 m_style
= wxPENSTYLE_STIPPLE
;
199 wxPenRefData::~wxPenRefData()
202 ::DeleteObject(m_hPen
);
205 // ----------------------------------------------------------------------------
206 // wxPenRefData HPEN management
207 // ----------------------------------------------------------------------------
209 static int ConvertPenStyle(wxPenStyle style
)
213 case wxPENSTYLE_SHORT_DASH
:
214 case wxPENSTYLE_LONG_DASH
:
217 case wxPENSTYLE_TRANSPARENT
:
221 wxFAIL_MSG( wxT("unknown pen style") );
224 #ifdef wxHAVE_EXT_CREATE_PEN
228 case wxPENSTYLE_DOT_DASH
:
231 case wxPENSTYLE_USER_DASH
:
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
:
242 #endif // wxHAVE_EXT_CREATE_PEN
248 #ifdef wxHAVE_EXT_CREATE_PEN
250 static int ConvertJoinStyle(wxPenJoin join
)
255 return PS_JOIN_BEVEL
;
258 return PS_JOIN_MITER
;
261 wxFAIL_MSG( wxT("unknown pen join style") );
265 return PS_JOIN_ROUND
;
269 static int ConvertCapStyle(wxPenCap cap
)
273 case wxCAP_PROJECTING
:
274 return PS_ENDCAP_SQUARE
;
277 return PS_ENDCAP_FLAT
;
280 wxFAIL_MSG( wxT("unknown pen cap style") );
284 return PS_ENDCAP_ROUND
;
288 #endif // wxHAVE_EXT_CREATE_PEN
290 bool wxPenRefData::Alloc()
295 if ( m_style
== wxPENSTYLE_TRANSPARENT
)
297 m_hPen
= (HPEN
)::GetStockObject(NULL_PEN
);
301 const COLORREF col
= m_colour
.GetPixel();
303 #ifdef wxHAVE_EXT_CREATE_PEN
304 // Only NT can display dashed or dotted lines with width > 1
305 static const int os
= wxGetOsVersion();
306 if ( os
!= wxOS_WINDOWS_NT
&&
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
) &&
317 // check if it's a standard kind of pen which can be created with just
319 if ( m_join
== wxJOIN_ROUND
&&
320 m_cap
== wxCAP_ROUND
&&
321 m_style
!= wxPENSTYLE_USER_DASH
&&
322 m_style
!= wxPENSTYLE_STIPPLE
&&
323 (m_width
<= 1 || m_style
== wxPENSTYLE_SOLID
) )
324 #endif // !wxHAVE_EXT_CREATE_PEN
326 m_hPen
= ::CreatePen(ConvertPenStyle(m_style
), m_width
, col
);
328 #ifdef wxHAVE_EXT_CREATE_PEN
329 else // need to use ExtCreatePen()
331 DWORD styleMSW
= PS_GEOMETRIC
|
332 ConvertPenStyle(m_style
) |
333 ConvertJoinStyle(m_join
) |
334 ConvertCapStyle(m_cap
);
339 case wxPENSTYLE_STIPPLE
:
340 lb
.lbStyle
= BS_PATTERN
;
341 lb
.lbHatch
= wxPtrToUInt(m_stipple
.GetHBITMAP());
344 case wxPENSTYLE_BDIAGONAL_HATCH
:
345 lb
.lbStyle
= BS_HATCHED
;
346 lb
.lbHatch
= HS_BDIAGONAL
;
349 case wxPENSTYLE_CROSSDIAG_HATCH
:
350 lb
.lbStyle
= BS_HATCHED
;
351 lb
.lbHatch
= HS_DIAGCROSS
;
354 case wxPENSTYLE_FDIAGONAL_HATCH
:
355 lb
.lbStyle
= BS_HATCHED
;
356 lb
.lbHatch
= HS_FDIAGONAL
;
359 case wxPENSTYLE_CROSS_HATCH
:
360 lb
.lbStyle
= BS_HATCHED
;
361 lb
.lbHatch
= HS_CROSS
;
364 case wxPENSTYLE_HORIZONTAL_HATCH
:
365 lb
.lbStyle
= BS_HATCHED
;
366 lb
.lbHatch
= HS_HORIZONTAL
;
369 case wxPENSTYLE_VERTICAL_HATCH
:
370 lb
.lbStyle
= BS_HATCHED
;
371 lb
.lbHatch
= HS_VERTICAL
;
375 lb
.lbStyle
= BS_SOLID
;
376 // this should be unnecessary (it's unused) but suppresses the
377 // Purify messages about uninitialized memory read
385 if ( m_style
== wxPENSTYLE_USER_DASH
&& m_nbDash
&& m_dash
)
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
;
397 m_hPen
= ::ExtCreatePen(styleMSW
, m_width
, &lb
, m_nbDash
, (LPDWORD
)dash
);
401 #endif // wxHAVE_EXT_CREATE_PEN
406 bool wxPenRefData::Free()
411 ::DeleteObject(m_hPen
);
417 WXHPEN
wxPenRefData::GetHPEN() const
420 const_cast<wxPenRefData
*>(this)->Alloc();
422 return (WXHPEN
)m_hPen
;
425 // ----------------------------------------------------------------------------
427 // ----------------------------------------------------------------------------
429 IMPLEMENT_DYNAMIC_CLASS(wxPen
, wxGDIObject
)
431 wxPen::wxPen(const wxColour
& col
, int width
, wxPenStyle style
)
433 m_refData
= new wxPenRefData(col
, width
, style
);
436 #if FUTURE_WXWIN_COMPATIBILITY_3_0
437 wxPen::wxPen(const wxColour
& colour
, int width
, int style
)
439 m_refData
= new wxPenRefData(colour
, width
, (wxPenStyle
)style
);
443 wxPen::wxPen(const wxBitmap
& stipple
, int width
)
445 m_refData
= new wxPenRefData(stipple
, width
);
448 bool wxPen::operator==(const wxPen
& pen
) const
451 penData
= static_cast<const wxPenRefData
*>(pen
.m_refData
);
453 // an invalid pen is only equal to another invalid pen
454 return m_refData
? penData
&& *M_PENDATA
== *penData
: !penData
;
457 bool wxPen::RealizeResource()
459 return M_PENDATA
&& M_PENDATA
->Alloc();
462 WXHANDLE
wxPen::GetResourceHandle() const
464 return M_PENDATA
? M_PENDATA
->GetHPEN() : 0;
467 bool wxPen::FreeResource(bool WXUNUSED(force
))
469 return M_PENDATA
&& M_PENDATA
->Free();
472 bool wxPen::IsFree() const
474 return M_PENDATA
&& !M_PENDATA
->HasHPEN();
477 wxGDIRefData
* wxPen::CreateGDIRefData() const
479 return new wxPenRefData
;
482 wxGDIRefData
* wxPen::CloneGDIRefData(const wxGDIRefData
* data
) const
484 return new wxPenRefData(*static_cast<const wxPenRefData
*>(data
));
487 void wxPen::SetColour(const wxColour
& col
)
491 M_PENDATA
->SetColour(col
);
494 void wxPen::SetColour(unsigned char r
, unsigned char g
, unsigned char b
)
496 SetColour(wxColour(r
, g
, b
));
499 void wxPen::SetWidth(int width
)
503 M_PENDATA
->SetWidth(width
);
506 void wxPen::SetStyle(wxPenStyle style
)
510 M_PENDATA
->SetStyle(style
);
513 void wxPen::SetStipple(const wxBitmap
& stipple
)
517 M_PENDATA
->SetStipple(stipple
);
520 void wxPen::SetDashes(int nb_dashes
, const wxDash
*dash
)
524 M_PENDATA
->SetDashes(nb_dashes
, dash
);
527 void wxPen::SetJoin(wxPenJoin join
)
531 M_PENDATA
->SetJoin(join
);
534 void wxPen::SetCap(wxPenCap cap
)
538 M_PENDATA
->SetCap(cap
);
541 wxColour
wxPen::GetColour() const
543 wxCHECK_MSG( IsOk(), wxNullColour
, wxT("invalid pen") );
545 return M_PENDATA
->GetColour();
548 int wxPen::GetWidth() const
550 wxCHECK_MSG( IsOk(), -1, wxT("invalid pen") );
552 return M_PENDATA
->GetWidth();
555 wxPenStyle
wxPen::GetStyle() const
557 wxCHECK_MSG( IsOk(), wxPENSTYLE_INVALID
, wxT("invalid pen") );
559 return M_PENDATA
->GetStyle();
562 wxPenJoin
wxPen::GetJoin() const
564 wxCHECK_MSG( IsOk(), wxJOIN_INVALID
, wxT("invalid pen") );
566 return M_PENDATA
->GetJoin();
569 wxPenCap
wxPen::GetCap() const
571 wxCHECK_MSG( IsOk(), wxCAP_INVALID
, wxT("invalid pen") );
573 return M_PENDATA
->GetCap();
576 int wxPen::GetDashes(wxDash
** ptr
) const
578 wxCHECK_MSG( IsOk(), -1, wxT("invalid pen") );
580 *ptr
= M_PENDATA
->GetDash();
581 return M_PENDATA
->GetDashCount();
584 wxDash
* wxPen::GetDash() const
586 wxCHECK_MSG( IsOk(), NULL
, wxT("invalid pen") );
588 return m_refData
? M_PENDATA
->GetDash() : NULL
;
591 int wxPen::GetDashCount() const
593 wxCHECK_MSG( IsOk(), -1, wxT("invalid pen") );
595 return m_refData
? M_PENDATA
->GetDashCount() : 0;
598 wxBitmap
* wxPen::GetStipple() const
600 wxCHECK_MSG( IsOk(), NULL
, wxT("invalid pen") );
602 return m_refData
? M_PENDATA
->GetStipple() : NULL
;