Updated brush/pen implementation for OS/2 to current implementation style.
[wxWidgets.git] / src / os2 / pen.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/os2/pen.cpp
3 // Purpose: wxPen
4 // Author: David Webster
5 // Modified by:
6 // Created: 10/10/99
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #include "wx/pen.h"
16
17 #ifndef WX_PRECOMP
18 #include <stdio.h>
19 #include "wx/list.h"
20 #include "wx/utils.h"
21 #include "wx/app.h"
22 #include "wx/log.h"
23 #endif
24
25 #include "wx/os2/private.h"
26
27 class WXDLLIMPEXP_FWD_CORE wxPen;
28
29 // ----------------------------------------------------------------------------
30 // wxPenRefData: contains information about an HPEN and its handle
31 // ----------------------------------------------------------------------------
32
33 class WXDLLEXPORT wxPenRefData: public wxGDIRefData
34 {
35 friend class WXDLLIMPEXP_FWD_CORE wxPen;
36 public:
37 wxPenRefData();
38 wxPenRefData(const wxPenRefData& rData);
39 wxPenRefData(const wxColour& col, int width, wxPenStyle style);
40 wxPenRefData(const wxBitmap& stipple, int width);
41 virtual ~wxPenRefData();
42
43 bool operator==(const wxPenRefData& data) const
44 {
45 // we intentionally don't compare m_hPen fields here
46 return m_nStyle == data.m_nStyle &&
47 m_nWidth == data.m_nWidth &&
48 m_nJoin == data.m_nJoin &&
49 m_nCap == data.m_nCap &&
50 m_vColour == data.m_vColour &&
51 (m_nStyle != wxPENSTYLE_STIPPLE || m_vStipple.IsSameAs(data.m_vStipple)) &&
52 (m_nStyle != wxPENSTYLE_USER_DASH ||
53 (m_dash == data.m_dash &&
54 memcmp(m_dash, data.m_dash, m_nbDash*sizeof(wxDash)) == 0));
55 }
56
57 private:
58 // initialize the fields which have reasonable default values
59 //
60 // doesn't initialize m_width and m_style which must be initialize in ctor
61 void Init()
62 {
63 m_nJoin = wxJOIN_ROUND;
64 m_nCap = wxCAP_ROUND;
65 m_nbDash = 0;
66 m_dash = NULL;
67 m_hPen = 0;
68 }
69
70 int m_nWidth;
71 wxPenStyle m_nStyle;
72 wxPenJoin m_nJoin;
73 wxPenCap m_nCap;
74 wxBitmap m_vStipple;
75 int m_nbDash;
76 wxDash * m_dash;
77 wxColour m_vColour;
78 WXHPEN m_hPen;// in OS/2 GPI this will be the PS the pen is associated with
79
80 DECLARE_NO_ASSIGN_CLASS(wxPenRefData)
81 };
82
83 #define M_PENDATA ((wxPenRefData *)m_refData)
84
85 // ----------------------------------------------------------------------------
86 // wxPenRefData ctors/dtor
87 // ----------------------------------------------------------------------------
88
89 wxPenRefData::wxPenRefData()
90 {
91 Init();
92
93 m_nStyle = wxPENSTYLE_SOLID;
94 m_nWidth = 1;
95 } // end of wxPenRefData::wxPenRefData
96
97 wxPenRefData::wxPenRefData(
98 const wxPenRefData& rData
99 )
100 {
101 m_nStyle = rData.m_nStyle;
102 m_nWidth = rData.m_nWidth;
103 m_nJoin = rData.m_nJoin;
104 m_nCap = rData.m_nCap;
105 m_nbDash = rData.m_nbDash;
106 m_dash = rData.m_dash;
107 m_vColour = rData.m_vColour;
108 m_hPen = 0L;
109 } // end of wxPenRefData::wxPenRefData
110
111 wxPenRefData::wxPenRefData(const wxColour& col, int width, wxPenStyle style)
112 {
113 Init();
114
115 m_nStyle = style;
116 m_nWidth = width;
117
118 m_vColour = col;
119 }
120
121 wxPenRefData::wxPenRefData(const wxBitmap& stipple, int width)
122 {
123 Init();
124
125 m_nStyle = wxPENSTYLE_STIPPLE;
126 m_nWidth = width;
127
128 m_vStipple = stipple;
129 }
130
131 wxPenRefData::~wxPenRefData()
132 {
133 } // end of wxPenRefData::~wxPenRefData
134
135 // ----------------------------------------------------------------------------
136 // wxPen
137 // ----------------------------------------------------------------------------
138
139 IMPLEMENT_DYNAMIC_CLASS(wxPen, wxGDIObject)
140
141 wxPen::wxPen(
142 const wxColour& rColour
143 , int nWidth
144 , wxPenStyle nStyle
145 )
146 {
147 m_refData = new wxPenRefData(rColour, nWidth, nStyle);
148
149 RealizeResource();
150 } // end of wxPen::wxPen
151
152 #if FUTURE_WXWIN_COMPATIBILITY_3_0
153 wxPen::wxPen(const wxColour& colour, int width, int style)
154 {
155 m_refData = new wxPenRefData(colour, width, (wxPenStyle)style);
156
157 RealizeResource();
158 }
159 #endif
160
161 wxPen::wxPen(
162 const wxBitmap& rStipple
163 , int nWidth
164 )
165 {
166 m_refData = new wxPenRefData (rStipple, nWidth);
167
168 RealizeResource();
169 } // end of wxPen::wxPen
170
171 int wx2os2PenStyle(
172 wxPenStyle nWxStyle
173 );
174
175 bool wxPen::RealizeResource()
176 {
177 BOOL bOk;
178 ERRORID vError;
179 wxString sError;
180
181 if (M_PENDATA && M_PENDATA->m_hPen == 0L)
182 {
183 SIZEL vSize = {0, 0};
184 DEVOPENSTRUC vDop = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
185 HDC hDC = ::DevOpenDC( vHabmain
186 ,OD_MEMORY
187 ,"*"
188 ,5L
189 ,(PDEVOPENDATA)&vDop
190 ,NULLHANDLE
191 );
192 M_PENDATA->m_hPen = (WXHPEN)::GpiCreatePS( vHabmain
193 ,hDC
194 ,&vSize
195 ,PU_PELS | GPIT_MICRO | GPIA_ASSOC
196 );
197 }
198 if (M_PENDATA)
199 {
200 //
201 // Set the color table to RGB mode
202 //
203 if (!::GpiCreateLogColorTable( (HPS)M_PENDATA->m_hPen
204 ,0L
205 ,LCOLF_RGB
206 ,0L
207 ,0L
208 ,NULL
209 ))
210 {
211 vError = ::WinGetLastError(vHabmain);
212 sError = wxPMErrorToStr(vError);
213 wxLogError(_T("Unable to set current color table to RGB mode. Error: %s\n"), sError.c_str());
214 return false;
215 }
216 if (M_PENDATA->m_nStyle == wxPENSTYLE_TRANSPARENT)
217 {
218 return true;
219 }
220
221 COLORREF vPmColour = 0L;
222 USHORT uLineType = (USHORT)wx2os2PenStyle(M_PENDATA->m_nStyle);
223
224 vPmColour = M_PENDATA->m_vColour.GetPixel();
225
226 USHORT uJoin = 0L;
227
228 switch(M_PENDATA->m_nJoin)
229 {
230 case wxJOIN_BEVEL:
231 uJoin = LINEJOIN_BEVEL;
232 break;
233
234 case wxJOIN_MITER:
235 uJoin = LINEJOIN_MITRE;
236 break;
237
238 case wxJOIN_ROUND:
239 uJoin = LINEJOIN_ROUND;
240 break;
241 }
242
243 USHORT uCap = 0L;
244
245 switch(M_PENDATA->m_nCap)
246 {
247 case wxCAP_PROJECTING:
248 uCap = LINEEND_SQUARE;
249 break;
250
251 case wxCAP_BUTT:
252 uCap = LINEEND_FLAT;
253 break;
254
255 case wxCAP_ROUND:
256 uCap = LINEEND_ROUND;
257 break;
258 }
259 m_vLineBundle.lColor = (LONG)vPmColour;
260 m_vLineBundle.usMixMode = FM_OVERPAINT;
261 if (M_PENDATA->m_nWidth < 1)
262 M_PENDATA->m_nWidth = 1;
263 m_vLineBundle.fxWidth = M_PENDATA->m_nWidth;
264 m_vLineBundle.lGeomWidth = M_PENDATA->m_nWidth;
265 m_vLineBundle.usType = uLineType;
266 m_vLineBundle.usEnd = uCap;
267 m_vLineBundle.usJoin = uJoin;
268
269 bOk = ::GpiSetAttrs( M_PENDATA->m_hPen
270 ,PRIM_LINE
271 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE | LBB_END | LBB_JOIN
272 ,0L
273 ,&m_vLineBundle
274 );
275 if (!bOk)
276 {
277 vError = ::WinGetLastError(vHabmain);
278 sError = wxPMErrorToStr(vError);
279 wxLogError(_T("Can't set Gpi attributes for a LINEBUNDLE. Error: %s\n"), sError.c_str());
280 return false;
281 }
282
283 ULONG flAttrMask = 0L;
284 ULONG flDefMask = 0L;
285 switch(M_PENDATA->m_nStyle)
286 {
287 case wxPENSTYLE_STIPPLE:
288 ::GpiSetBitmapId( M_PENDATA->m_hPen
289 ,(USHORT)M_PENDATA->m_vStipple.GetHBITMAP()
290 ,(USHORT)M_PENDATA->m_vStipple.GetId()
291 );
292 ::GpiSetPatternSet( M_PENDATA->m_hPen
293 ,(USHORT)M_PENDATA->m_vStipple.GetId()
294 );
295 flAttrMask = ABB_COLOR | ABB_BACK_COLOR | ABB_MIX_MODE | ABB_BACK_MIX_MODE | ABB_SET | ABB_SYMBOL;
296 flDefMask = ABB_REF_POINT;
297 break;
298
299 case wxPENSTYLE_BDIAGONAL_HATCH:
300 m_vAreaBundle.usSymbol = PATSYM_DIAG3;
301 m_vAreaBundle.usSet = LCID_DEFAULT;
302 flAttrMask = ABB_COLOR | ABB_BACK_COLOR | ABB_MIX_MODE | ABB_BACK_MIX_MODE | ABB_SYMBOL;
303 flDefMask = ABB_SET | ABB_REF_POINT;
304 break;
305
306 case wxPENSTYLE_CROSSDIAG_HATCH:
307 m_vAreaBundle.usSymbol = PATSYM_DIAGHATCH;
308 m_vAreaBundle.usSet = LCID_DEFAULT;
309 flAttrMask = ABB_COLOR | ABB_BACK_COLOR | ABB_MIX_MODE | ABB_BACK_MIX_MODE | ABB_SYMBOL;
310 flDefMask = ABB_SET | ABB_REF_POINT;
311 break;
312
313 case wxPENSTYLE_FDIAGONAL_HATCH:
314 m_vAreaBundle.usSymbol = PATSYM_DIAG1;
315 m_vAreaBundle.usSet = LCID_DEFAULT;
316 flAttrMask = ABB_COLOR | ABB_BACK_COLOR | ABB_MIX_MODE | ABB_BACK_MIX_MODE | ABB_SYMBOL;
317 flDefMask = ABB_SET | ABB_REF_POINT;
318 break;
319
320 case wxPENSTYLE_CROSS_HATCH:
321 m_vAreaBundle.usSymbol = PATSYM_HATCH;
322 m_vAreaBundle.usSet = LCID_DEFAULT;
323 flAttrMask = ABB_COLOR | ABB_BACK_COLOR | ABB_MIX_MODE | ABB_BACK_MIX_MODE | ABB_SYMBOL;
324 flDefMask = ABB_SET | ABB_REF_POINT;
325 break;
326
327 case wxPENSTYLE_HORIZONTAL_HATCH:
328 m_vAreaBundle.usSymbol = PATSYM_HORIZ;
329 m_vAreaBundle.usSet = LCID_DEFAULT;
330 flAttrMask = ABB_COLOR | ABB_BACK_COLOR | ABB_MIX_MODE | ABB_BACK_MIX_MODE | ABB_SYMBOL;
331 flDefMask = ABB_SET | ABB_REF_POINT;
332 break;
333
334 case wxPENSTYLE_VERTICAL_HATCH:
335 m_vAreaBundle.usSymbol = PATSYM_VERT;
336 m_vAreaBundle.usSet = LCID_DEFAULT;
337 flAttrMask = ABB_COLOR | ABB_BACK_COLOR | ABB_MIX_MODE | ABB_BACK_MIX_MODE | ABB_SYMBOL;
338 flDefMask = ABB_SET | ABB_REF_POINT;
339 break;
340
341 default:
342 m_vAreaBundle.usSymbol = PATSYM_SOLID;
343 m_vAreaBundle.usSet = LCID_DEFAULT;
344 flAttrMask = ABB_COLOR | ABB_BACK_COLOR | ABB_MIX_MODE | ABB_BACK_MIX_MODE | ABB_SYMBOL;
345 flDefMask = ABB_SET | ABB_REF_POINT;
346 break;
347 }
348
349 m_vAreaBundle.lColor = vPmColour;
350 m_vAreaBundle.lBackColor = RGB_WHITE;
351 m_vAreaBundle.usMixMode = FM_OVERPAINT;
352 m_vAreaBundle.usBackMixMode = BM_OVERPAINT;
353
354 bOk = ::GpiSetAttrs( M_PENDATA->m_hPen
355 ,PRIM_AREA
356 ,flAttrMask
357 ,flDefMask
358 ,&m_vAreaBundle
359 );
360 if (!bOk)
361 {
362 vError = ::WinGetLastError(vHabmain);
363 sError = wxPMErrorToStr(vError);
364 wxLogError(_T("Can't set Gpi attributes for an AREABUNDLE. Error: %s\n"), sError.c_str());
365 }
366
367 return (bool)bOk;
368 }
369 return false;
370 } // end of wxPen::RealizeResource
371
372 WXHANDLE wxPen::GetResourceHandle() const
373 {
374 if (!M_PENDATA)
375 return 0;
376 else
377 return (WXHANDLE)M_PENDATA->m_hPen;
378 } // end of wxPen::GetResourceHandle
379
380 bool wxPen::FreeResource( bool WXUNUSED(bForce) )
381 {
382 if (M_PENDATA && (M_PENDATA->m_hPen != 0))
383 {
384 M_PENDATA->m_hPen = 0;
385 return true;
386 }
387 else return false;
388 } // end of wxPen::FreeResource
389
390 bool wxPen::IsFree() const
391 {
392 return (M_PENDATA && M_PENDATA->m_hPen == 0);
393 }
394
395 wxGDIRefData* wxPen::CreateGDIRefData() const
396 {
397 return new wxPenRefData;
398 }
399
400 wxGDIRefData* wxPen::CloneGDIRefData(const wxGDIRefData* data) const
401 {
402 return new wxPenRefData(*wx_static_cast(const wxPenRefData*, data));
403 }
404
405 void wxPen::SetColour( const wxColour& rColour )
406 {
407 AllocExclusive();
408 M_PENDATA->m_vColour = rColour;
409 RealizeResource();
410 } // end of wxPen::SetColour
411
412 void wxPen::SetColour( unsigned char cRed, unsigned char cGreen, unsigned char cBlue)
413 {
414 AllocExclusive();
415 M_PENDATA->m_vColour.Set(cRed, cGreen, cBlue);
416 RealizeResource();
417 } // end of wxPen::SetColour
418
419 void wxPen::SetPS( HPS hPS )
420 {
421 AllocExclusive();
422 if (M_PENDATA->m_hPen)
423 ::GpiDestroyPS(M_PENDATA->m_hPen);
424 M_PENDATA->m_hPen = hPS;
425 RealizeResource();
426 } // end of WxWinGdi_CPen::SetPS
427
428 void wxPen::SetWidth(
429 int nWidth
430 )
431 {
432 AllocExclusive();
433 M_PENDATA->m_nWidth = nWidth;
434 RealizeResource();
435 } // end of wxPen::SetWidth
436
437 void wxPen::SetStyle(
438 wxPenStyle nStyle
439 )
440 {
441 AllocExclusive();
442 M_PENDATA->m_nStyle = nStyle;
443 RealizeResource();
444 } // end of wxPen::SetStyle
445
446 void wxPen::SetStipple(
447 const wxBitmap& rStipple
448 )
449 {
450 AllocExclusive();
451 M_PENDATA->m_vStipple = rStipple;
452 M_PENDATA->m_nStyle = wxPENSTYLE_STIPPLE;
453 RealizeResource();
454 } // end of wxPen::SetStipple
455
456 void wxPen::SetDashes( int WXUNUSED(nNbDashes),
457 const wxDash* WXUNUSED(pDash) )
458 {
459 //
460 // Does nothing under OS/2
461 //
462 } // end of wxPen::SetDashes
463
464 void wxPen::SetJoin(
465 wxPenJoin nJoin
466 )
467 {
468 AllocExclusive();
469 M_PENDATA->m_nJoin = nJoin;
470 RealizeResource();
471 } // end of wxPen::SetJoin
472
473 void wxPen::SetCap(
474 wxPenCap nCap
475 )
476 {
477 AllocExclusive();
478 M_PENDATA->m_nCap = nCap;
479 RealizeResource();
480 } // end of wxPen::SetCap
481
482 wxColour& wxPen::GetColour() const
483 {
484 wxCHECK_MSG( Ok(), wxNullColour, wxT("invalid pen") );
485
486 return M_PENDATA->m_vColour;
487 }
488
489 int wxPen::GetWidth() const
490 {
491 wxCHECK_MSG( Ok(), -1, wxT("invalid pen") );
492
493 return M_PENDATA->m_nWidth;
494 }
495
496 wxPenStyle wxPen::GetStyle() const
497 {
498 wxCHECK_MSG( Ok(), wxPENSTYLE_INVALID, wxT("invalid pen") );
499
500 return M_PENDATA->m_nStyle;
501 }
502
503 wxPenJoin wxPen::GetJoin() const
504 {
505 wxCHECK_MSG( Ok(), wxJOIN_INVALID, wxT("invalid pen") );
506
507 return M_PENDATA->m_nJoin;
508 }
509
510 wxPenCap wxPen::GetCap() const
511 {
512 wxCHECK_MSG( Ok(), wxCAP_INVALID, wxT("invalid pen") );
513
514 return M_PENDATA->m_nCap;
515 }
516
517 int wxPen::GetPS() const
518 {
519 wxCHECK_MSG( Ok(), 0, wxT("invalid pen") );
520
521 return M_PENDATA->m_hPen;
522 }
523
524 int wxPen::GetDashes(wxDash** ptr) const
525 {
526 wxCHECK_MSG( Ok(), -1, wxT("invalid pen") );
527
528 *ptr = M_PENDATA->m_dash;
529 return M_PENDATA->m_nbDash;
530 }
531
532 wxDash* wxPen::GetDash() const
533 {
534 wxCHECK_MSG( Ok(), NULL, wxT("invalid pen") );
535
536 return M_PENDATA->m_dash;
537 }
538
539 int wxPen::GetDashCount() const
540 {
541 wxCHECK_MSG( Ok(), -1, wxT("invalid pen") );
542
543 return M_PENDATA->m_nbDash;
544 }
545
546 wxBitmap* wxPen::GetStipple() const
547 {
548 wxCHECK_MSG( Ok(), NULL, wxT("invalid pen") );
549
550 return &(M_PENDATA->m_vStipple);
551 }
552
553 int wx2os2PenStyle(
554 wxPenStyle nWxStyle
555 )
556 {
557 int nPMStyle = 0;
558
559 switch (nWxStyle)
560 {
561 case wxPENSTYLE_DOT:
562 nPMStyle = LINETYPE_DOT;
563 break;
564
565 case wxPENSTYLE_DOT_DASH:
566 nPMStyle = LINETYPE_DASHDOT;
567 break;
568
569 case wxPENSTYLE_SHORT_DASH:
570 nPMStyle = LINETYPE_SHORTDASH;
571 break;
572
573 case wxPENSTYLE_LONG_DASH:
574 nPMStyle = LINETYPE_LONGDASH;
575 break;
576
577 case wxPENSTYLE_TRANSPARENT:
578 nPMStyle = LINETYPE_INVISIBLE;
579 break;
580
581 case wxPENSTYLE_USER_DASH:
582 nPMStyle = LINETYPE_DASHDOUBLEDOT; // We must make a choice... This is mine!
583 break;
584
585 case wxPENSTYLE_SOLID:
586 default:
587 nPMStyle = LINETYPE_SOLID;
588 break;
589 }
590 return nPMStyle;
591 } // end of wx2os2PenStyle