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