More Ownerdraw menu 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 //
79 // # without this menu items look too tightly packed (at least under Windows)
80 //
81 sStr += wxT('W'); // 'W' is typically the widest letter
82 vDC.GetTextExtent( sStr
83 ,(long *)pWidth
84 ,(long *)pHeight
85 );
86 // DEBUG
87 char zMsg[128];
88 sprintf(zMsg, "GetTextExtent for %s: Width: %ld, Height: %ld", m_strName.c_str(), *pWidth, *pHeight);
89 (void)wxMessageBox( "wxWindows Menu sample"
90 ,zMsg
91 ,wxICON_INFORMATION
92 );
93 // end DEBUG
94
95 //
96 // JACS: items still look too tightly packed, so adding 2 pixels.
97 //
98 (*pHeight) = (*pHeight) + 2;
99 m_nHeight = *pHeight; // remember height for use in OnDrawItem
100 return TRUE;
101 } // end of wxOwnerDrawn::OnMeasureItem
102
103 // searching for this macro you'll find all the code where I'm using the native
104 // Win32 GDI functions and not wxWindows ones. Might help to whoever decides to
105 // port this code to X. (VZ)
106
107 // JACS: TODO. Why does a disabled but highlighted item still
108 // get drawn embossed? How can we tell DrawState that we don't want the
109 // embossing?
110
111 // draw the item
112 bool wxOwnerDrawn::OnDrawItem(
113 wxDC& rDC
114 , const wxRect& rRect
115 , wxODAction eAction
116 , wxODStatus eStatus
117 )
118 {
119 //
120 // For now we let PM deal with highlighting and framing and such in a
121 // default manner. So we leave fsAttribute and fsOldAttribute ( or
122 // fsState and fsOldState ) the same and pass it on. We may want to add
123 // code later to draw theseattributes in a more custom manner.
124 //
125
126 //
127 // WxWinGdi_CColour <-> RGB
128 //
129 #define ToRGB(col) OS2RGB(col.Red(), col.Green(), col.Blue())
130 #define UnRGB(col) GetRValue(col), GetGValue(col), GetBValue(col)
131
132 CHARBUNDLE vCbndText;
133 CHARBUNDLE vCbndBack;
134 HPS hPS= rDC.GetHPS();
135 ULONG lColBack;
136 ULONG lColText;
137
138 if (eStatus & wxODSelected)
139 {
140 lColBack = (DWORD)::WinQuerySysColor( HWND_DESKTOP
141 ,SYSCLR_MENUHILITEBGND // Light gray
142 ,0L
143 );
144 lColText = (DWORD)::WinQuerySysColor( HWND_DESKTOP
145 ,SYSCLR_MENUTEXT // Black
146 ,0L
147 );
148 }
149 else if (eStatus & wxODDisabled)
150 {
151 lColBack = (DWORD)::WinQuerySysColor( HWND_DESKTOP
152 ,SYSCLR_MENU // Light gray
153 ,0L
154 );
155 lColText = (DWORD)::WinQuerySysColor( HWND_DESKTOP
156 ,SYSCLR_MENUDISABLEDTEXT // dark gray
157 ,0L
158 );
159 }
160 else
161 {
162 //
163 // Fall back to default colors if none explicitly specified
164 //
165 lColBack = m_colBack.Ok() ? ToRGB(m_colBack) : ::WinQuerySysColor( HWND_DESKTOP
166 ,SYSCLR_MENU // we are using gray for all our window backgrounds in wxWindows
167 ,0L
168 );
169 lColText = m_colText.Ok() ? ToRGB(m_colText) : ::WinQuerySysColor( HWND_DESKTOP
170 ,SYSCLR_WINDOWTEXT // Black
171 ,0L
172 );
173 }
174 vCbndText.lColor = (LONG)lColText;
175 vCbndBack.lColor = (LONG)lColBack;
176
177 ::GpiSetAttrs( hPS
178 ,PRIM_CHAR
179 ,CBB_BACK_COLOR
180 ,0
181 ,&vCbndBack
182 );
183 ::GpiSetAttrs( hPS
184 ,PRIM_CHAR
185 ,CBB_COLOR
186 ,0
187 ,&vCbndText
188 );
189
190
191 //
192 // Determine where to draw and leave space for a check-mark.
193 //
194 int nX = rRect.x + GetMarginWidth();
195
196 //
197 // Select the font and draw the text
198 // ---------------------------------
199 //
200
201 //
202 // Use default font if no font set
203 //
204 if (m_font.Ok())
205 {
206 m_font.RealizeResource();
207 }
208 else
209 {
210 ::GpiSetCharSet(hPS, LCID_DEFAULT);
211 }
212
213 //
214 // Unfortunately, unlike Win32, PM has no owner drawn specific text
215 // drawing methods like ::DrawState that can cleanly handle accel
216 // pneumonics and deal, automatically, with various states, so we have
217 // to handle them ourselves. Notice Win32 can't handle \t in ownerdrawn
218 // strings either.
219
220 rDC.DrawText( m_strName
221 ,nX
222 ,rRect.y
223 );
224
225 //
226 // Draw the bitmap
227 // ---------------
228 //
229 if (IsCheckable() && !m_bmpChecked.Ok())
230 {
231 if (eStatus & wxODChecked)
232 {
233 RECTL vRect;
234 HBITMAP hBmpCheck = ::WinGetSysBitmap(HWND_DESKTOP, SBMP_MENUCHECK);
235
236 vRect.xLeft = rRect.x;
237 vRect.xRight = rRect.x + GetMarginWidth();
238 vRect.yBottom = rRect.y;
239 vRect.yTop = rRect.y + m_nHeight;
240
241 ::WinDrawBitmap( hPS // PS for this menuitem
242 ,hBmpCheck // system checkmark
243 ,NULL // draw the whole bitmap
244 ,(PPOINTL)&vRect // destination -- bottom left corner of the menuitem area
245 ,0L // ignored
246 ,0L // draw a bitmap
247 ,DBM_NORMAL // draw normal size
248 );
249 }
250 }
251 else
252 {
253 //
254 // For uncheckable item we use only the 'checked' bitmap
255 //
256 wxBitmap vBmp(GetBitmap(IsCheckable() ? ((eStatus & wxODChecked) != 0) : TRUE));
257
258 if (vBmp.Ok())
259 {
260 wxMemoryDC vDCMem(&rDC);
261
262 vDCMem.SelectObject(vBmp);
263
264 //
265 // Center bitmap
266 //
267 int nBmpWidth = vBmp.GetWidth();
268 int nBmpHeight = vBmp.GetHeight();
269
270 //
271 // There should be enough space!
272 //
273 wxASSERT((nBmpWidth <= rRect.width) && (nBmpHeight <= rRect.height));
274
275 //
276 //MT: blit with mask enabled.
277 //
278 rDC.Blit( rRect.x + (GetMarginWidth() - nBmpWidth) / 2
279 ,rRect.y + (m_nHeight - nBmpHeight) /2
280 ,nBmpWidth
281 ,nBmpHeight
282 ,&vDCMem
283 ,0
284 ,0
285 ,wxCOPY
286 ,TRUE
287 );
288
289 if (eStatus & wxODSelected)
290 {
291 RECT vRectBmp = { rRect.x
292 ,rRect.y
293 ,rRect.x + GetMarginWidth()
294 ,rRect.y + m_nHeight
295 };
296 LINEBUNDLE vLine;
297
298 vLine.lColor = lColBack;
299 ::GpiSetAttrs( hPS
300 ,PRIM_LINE
301 ,LBB_COLOR
302 ,0
303 ,&vLine
304 );
305 ::GpiBox( hPS
306 ,DRO_OUTLINE
307 ,(PPOINTL)&vRectBmp
308 ,0L
309 ,0L
310 );
311 }
312 }
313 }
314
315 return TRUE;
316 }
317
318 #endif //wxUSE_OWNER_DRAWN