Ownerdrawn updates
[wxWidgets.git] / src / os2 / ownerdrw.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: msw/ownerdrw.cpp
3 // Purpose: implementation of wxOwnerDrawn class
4 // Author: David Webster
5 // Modified by:
6 // Created: 10/12/99
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
9 // Licence: wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifndef WX_PRECOMP
20 #include "wx/window.h"
21 #include "wx/msw/private.h"
22 #include "wx/font.h"
23 #include "wx/bitmap.h"
24 #include "wx/dcmemory.h"
25 #include "wx/menu.h"
26 #include "wx/utils.h"
27 #endif
28
29 #if wxUSE_OWNER_DRAWN
30
31 #include "wx/ownerdrw.h"
32 #include "wx/menuitem.h"
33
34
35 // ============================================================================
36 // implementation of wxOwnerDrawn class
37 // ============================================================================
38
39 //
40 // ctor
41 // ----
42 //
43 wxOwnerDrawn::wxOwnerDrawn(
44 const wxString& rsStr
45 , bool bCheckable
46 , bool bMenuItem
47 )
48 : m_strName(rsStr)
49 {
50 m_bCheckable = bCheckable;
51 m_bOwnerDrawn = FALSE;
52 m_nHeight = 0;
53 m_nMarginWidth = ms_nLastMarginWidth;
54 if (wxNORMAL_FONT)
55 m_font = *wxNORMAL_FONT;
56 } // end of wxOwnerDrawn::wxOwnerDrawn
57
58 size_t wxOwnerDrawn::ms_nDefaultMarginWidth = 15;
59
60 size_t wxOwnerDrawn::ms_nLastMarginWidth = ms_nDefaultMarginWidth;
61
62 //
63 // Drawing
64 // -------
65 //
66
67 bool wxOwnerDrawn::OnMeasureItem(
68 size_t* pWidth
69 , size_t* pHeight
70 )
71 {
72 wxMemoryDC vDC;
73
74 vDC.SetFont(GetFont());
75
76 wxString sStr = wxStripMenuCodes(m_strName);
77
78 vDC.GetTextExtent( sStr
79 ,(long *)pWidth
80 ,(long *)pHeight
81 );
82
83 (*pHeight) = (*pHeight) + 2;
84 m_nHeight = *pHeight; // remember height for use in OnDrawItem
85 return TRUE;
86 } // end of wxOwnerDrawn::OnMeasureItem
87
88 // draw the item
89 bool wxOwnerDrawn::OnDrawItem(
90 wxDC& rDC
91 , const wxRect& rRect
92 , wxODAction eAction
93 , wxODStatus eStatus
94 )
95 {
96 //
97 // We do nothing on focus change
98 //
99 if (eAction == wxODFocusChanged )
100 return TRUE;
101
102 //
103 // Select the font and draw the text
104 // ---------------------------------
105 //
106
107 CHARBUNDLE vCbnd;
108 HPS hPS= rDC.GetHPS();
109 wxColour vColBack;
110 wxColour vColText;
111 COLORREF vRef;
112 RECTL vRect = {rRect.x + 4, rRect.y + 1, rRect.x + (rRect.width - 2), rRect.y + rRect.height};
113
114 //
115 // Use default font if no font set
116 //
117 if (m_font.Ok())
118 {
119 m_font.RealizeResource();
120 }
121 else
122 {
123 ::GpiSetCharSet(hPS, LCID_DEFAULT);
124 }
125
126 //
127 // Base on the status of the menu item pick the right colors
128 //
129 if (eStatus & wxODSelected)
130 {
131 wxColour vCol2("WHITE");
132 vColBack.Set( (unsigned char)0
133 ,(unsigned char)0
134 ,(unsigned char)160
135 ); // no dark blue in color table
136 vColText = vCol2;
137 }
138 else if (eStatus & wxODDisabled)
139 {
140 vRef = (ULONG)::WinQuerySysColor( HWND_DESKTOP
141 ,SYSCLR_MENU // Light gray
142 ,0L
143 );
144 vColBack.Set( GetRValue(vRef)
145 ,GetGValue(vRef)
146 ,GetBValue(vRef)
147 );
148 vRef = (ULONG)::WinQuerySysColor( HWND_DESKTOP
149 ,SYSCLR_MENUDISABLEDTEXT // dark gray
150 ,0L
151 );
152 vColText.Set( GetRValue(vRef)
153 ,GetGValue(vRef)
154 ,GetBValue(vRef)
155 );
156 }
157 else
158 {
159 //
160 // Fall back to default colors if none explicitly specified
161 //
162 vRef = ::WinQuerySysColor( HWND_DESKTOP
163 ,SYSCLR_MENU // we are using gray for all our window backgrounds in wxWindows
164 ,0L
165 );
166 vColBack.Set( GetRValue(vRef)
167 ,GetGValue(vRef)
168 ,GetBValue(vRef)
169 );
170 vRef = ::WinQuerySysColor( HWND_DESKTOP
171 ,SYSCLR_WINDOWTEXT // Black
172 ,0L
173 );
174 vColText.Set( GetRValue(vRef)
175 ,GetGValue(vRef)
176 ,GetBValue(vRef)
177 );
178 }
179 rDC.SetTextBackground(vColBack);
180 rDC.SetTextForeground(vColText);
181 rDC.SetBackgroundMode(wxTRANSPARENT);
182
183 //
184 // Paint the background
185 //
186 ::WinFillRect(hPS, &vRect, vColBack.GetPixel());
187
188 //
189 // Determine where to draw and leave space for a check-mark.
190 //
191 int nX = rRect.x + GetMarginWidth();
192
193 //
194 // Unfortunately, unlike Win32, PM has no owner drawn specific text
195 // drawing methods like ::DrawState that can cleanly handle accel
196 // pneumonics and deal, automatically, with various states, so we have
197 // to handle them ourselves. Notice Win32 can't handle \t in ownerdrawn
198 // strings either. We cannot handle mneumonics either. We display
199 // it, though, in hopes we can figure it out some day.
200 //
201
202 //
203 // Display main text and accel text separately to allign better
204 //
205 wxString sTgt = "\t";
206 wxString sFullString = m_strName; // need to save the original text
207 wxString sAccel;
208 size_t nIndex;
209 size_t nWidth;
210 size_t nCharWidth;
211 size_t nHeight;
212 bool bFoundMneumonic = FALSE;
213 bool bFoundAccel = FALSE;
214
215 //
216 // Deal with the tab, extracting the Accel text
217 //
218 nIndex = sFullString.Find(sTgt.c_str());
219 if (nIndex != -1)
220 {
221 bFoundAccel = TRUE;
222 sAccel = sFullString.Mid(nIndex + 1);
223 sFullString.Remove(nIndex);
224 }
225
226 //
227 // Deal with the mneumonic character
228 //
229 sTgt = "~";
230 nIndex = sFullString.Find(sTgt.c_str());
231 if (nIndex != -1)
232 {
233 wxString sTmp = sFullString;
234
235 bFoundMneumonic = TRUE;
236 sTmp.Remove(nIndex);
237 rDC.GetTextExtent( sTmp
238 ,(long *)&nWidth
239 ,(long *)&nHeight
240 );
241 sTmp = sFullString[nIndex + 1];
242 rDC.GetTextExtent( sTmp
243 ,(long *)&nCharWidth
244 ,(long *)&nHeight
245 );
246 sFullString.Replace(sTgt.c_str(), "", TRUE);
247 }
248
249 //
250 // Draw the main item text sans the accel text
251 rDC.DrawText( sFullString
252 ,nX
253 ,rRect.y + 4
254 );
255 if (bFoundMneumonic)
256 {
257 //
258 // Underline the mneumonic -- still won't work, but at least it "looks" right
259 //
260 wxPen vPen;
261 POINTL vPntStart = {nX + nWidth - 1, rRect.y + 2}; // Make it look pretty!
262 POINTL vPntEnd = {nX + nWidth + nCharWidth - 3, rRect.y + 2}; //CharWidth is bit wide
263
264 vPen = wxPen(vColText, 1, wxSOLID); // Assuming we are always black
265 rDC.SetPen(vPen);
266 ::GpiMove(hPS, &vPntStart);
267 ::GpiLine(hPS, &vPntEnd);
268 }
269
270 //
271 // Now draw the accel text
272 //
273 if (bFoundAccel)
274 {
275 size_t nWidth;
276 size_t nHeight;
277
278 rDC.GetTextExtent( sAccel
279 ,(long *)&nWidth
280 ,(long *)&nHeight
281 );
282 //
283 // Back off the starting position from the right edge
284 //
285 rDC.DrawText( sAccel
286 ,rRect.width - (nWidth + 7) // this seems to mimic the default OS/2 positioning
287 ,rRect.y + 4
288 );
289 }
290
291 //
292 // Draw the bitmap
293 // ---------------
294 //
295 if (IsCheckable() && !m_bmpChecked.Ok())
296 {
297 if (eStatus & wxODChecked)
298 {
299 RECTL vRect;
300 HBITMAP hBmpCheck = ::WinGetSysBitmap(HWND_DESKTOP, SBMP_MENUCHECK);
301
302 vRect.xLeft = rRect.x;
303 vRect.xRight = rRect.x + GetMarginWidth();
304 vRect.yBottom = rRect.y;
305 vRect.yTop = rRect.y + m_nHeight - 3;
306
307 ::WinDrawBitmap( hPS // PS for this menuitem
308 ,hBmpCheck // system checkmark
309 ,NULL // draw the whole bitmap
310 ,(PPOINTL)&vRect // destination -- bottom left corner of the menuitem area
311 ,0L // ignored
312 ,0L // draw a bitmap
313 ,DBM_NORMAL // draw normal size
314 );
315 }
316 }
317 else
318 {
319 //
320 // For uncheckable item we use only the 'checked' bitmap
321 //
322 wxBitmap vBmp(GetBitmap(IsCheckable() ? ((eStatus & wxODChecked) != 0) : TRUE));
323
324 if (vBmp.Ok())
325 {
326 wxMemoryDC vDCMem(&rDC);
327
328 vDCMem.SelectObject(vBmp);
329
330 //
331 // Center bitmap
332 //
333 int nBmpWidth = vBmp.GetWidth();
334 int nBmpHeight = vBmp.GetHeight();
335
336 //
337 // There should be enough space!
338 //
339 wxASSERT((nBmpWidth <= rRect.width) && (nBmpHeight <= rRect.height));
340
341 //
342 //MT: blit with mask enabled.
343 //
344 rDC.Blit( rRect.x + (GetMarginWidth() - nBmpWidth) / 2
345 ,rRect.y + (m_nHeight - nBmpHeight) /2
346 ,nBmpWidth
347 ,nBmpHeight
348 ,&vDCMem
349 ,0
350 ,0
351 ,wxCOPY
352 ,TRUE
353 );
354
355 if (eStatus & wxODSelected)
356 {
357 RECT vRectBmp = { rRect.x
358 ,rRect.y
359 ,rRect.x + GetMarginWidth()
360 ,rRect.y + m_nHeight
361 };
362 POINTL vPnt1 = {2, 4}; // Leave a little background border
363 POINTL vPnt2 = {rRect.x + GetMarginWidth(), rRect.y + m_nHeight - 3};
364 LINEBUNDLE vLine;
365
366 vLine.lColor = vColBack.GetPixel();
367 ::GpiSetAttrs( hPS
368 ,PRIM_LINE
369 ,LBB_COLOR
370 ,0
371 ,&vLine
372 );
373 ::GpiMove(hPS, &vPnt1);
374 ::GpiBox( hPS
375 ,DRO_OUTLINE
376 ,&vPnt2
377 ,0L
378 ,0L
379 );
380 }
381 }
382 }
383 return TRUE;
384 } // end of wxOwnerDrawn::OnDrawItem
385
386 #endif //wxUSE_OWNER_DRAWN