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