]> git.saurik.com Git - wxWidgets.git/blame - src/os2/ownerdrw.cpp
Applied patch [ 1281902 ] fix for wxJoystick under Linux
[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
65571936 9// Licence: wxWindows licence
63415778
DW
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"
2b5f62a0 21 #include "wx/os2/private.h"
63415778
DW
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
50528a1d 31#include "wx/settings.h"
63415778
DW
32#include "wx/ownerdrw.h"
33#include "wx/menuitem.h"
34
35
36// ============================================================================
37// implementation of wxOwnerDrawn class
38// ============================================================================
39
402e2f7c 40//
63415778
DW
41// ctor
42// ----
402e2f7c 43//
6670f564
WS
44wxOwnerDrawn::wxOwnerDrawn( const wxString& rsStr,
45 bool bCheckable,
46 bool WXUNUSED(bMenuItem) )
402e2f7c 47: m_strName(rsStr)
63415778 48{
402e2f7c
DW
49 m_bCheckable = bCheckable;
50 m_bOwnerDrawn = FALSE;
51 m_nHeight = 0;
52 m_nMarginWidth = ms_nLastMarginWidth;
53 if (wxNORMAL_FONT)
54 m_font = *wxNORMAL_FONT;
55} // end of wxOwnerDrawn::wxOwnerDrawn
63415778 56
490120b4
SN
57wxOwnerDrawn::~wxOwnerDrawn() { }
58
402e2f7c 59size_t wxOwnerDrawn::ms_nDefaultMarginWidth = 15;
63415778
DW
60
61size_t wxOwnerDrawn::ms_nLastMarginWidth = ms_nDefaultMarginWidth;
62
402e2f7c
DW
63//
64// Drawing
63415778 65// -------
402e2f7c 66//
63415778 67
6670f564
WS
68bool wxOwnerDrawn::OnMeasureItem( size_t* pWidth,
69 size_t* pHeight )
63415778 70{
6670f564 71 wxMemoryDC vDC;
402e2f7c 72
6670f564 73 wxString sStr = wxStripMenuCodes(m_strName);
402e2f7c 74
57ff8a87
DW
75 //
76 // If we have a valid accel string, then pad out
d6922577
JS
77 // the menu string so that the menu and accel string are not
78 // placed on top of each other.
57ff8a87
DW
79 if (!m_strAccel.empty() )
80 {
81 sStr.Pad(sStr.Length()%8);
82 sStr += m_strAccel;
83 }
84 vDC.SetFont(GetFont());
402e2f7c
DW
85 vDC.GetTextExtent( sStr
86 ,(long *)pWidth
87 ,(long *)pHeight
88 );
6670f564 89 if (!m_strAccel.empty())
57ff8a87
DW
90 {
91 //
d6922577 92 // Measure the accelerator string, and add its width to
57ff8a87
DW
93 // the total item width, plus 16 (Accelerators are right justified,
94 // with the right edge of the text rectangle 16 pixels left of
95 // the right edge of the menu)
96 //
97 int nAccelWidth;
98 int nAccelHeight;
99
100 vDC.GetTextExtent( m_strAccel
101 ,&nAccelWidth
102 ,&nAccelHeight
103 );
104 *pWidth += nAccelWidth;
105 }
106
107 //
d6922577
JS
108 // Add space at the end of the menu for the submenu expansion arrow.
109 // This will also allow offsetting the accel string from the right edge
57ff8a87 110 //
9923c37d 111 *pWidth = (size_t)(*pWidth + GetDefaultMarginWidth() * 1.5);
57ff8a87
DW
112
113 //
114 // JACS: items still look too tightly packed, so adding 5 pixels.
115 //
116 (*pHeight) += 5;
402e2f7c 117
57ff8a87
DW
118 //
119 // Ray Gilbert's changes - Corrects the problem of a BMP
120 // being placed next to text in a menu item, and the BMP does
121 // not match the size expected by the system. This will
122 // resize the space so the BMP will fit. Without this, BMPs
123 // must be no larger or smaller than 16x16.
124 //
125 if (m_bmpChecked.Ok())
126 {
127 //
128 // Is BMP height larger then text height?
129 //
130 size_t nAdjustedHeight = m_bmpChecked.GetHeight() +
131 wxSystemSettings::GetMetric(wxSYS_EDGE_Y);
132 if (*pHeight < nAdjustedHeight)
133 *pHeight = nAdjustedHeight;
134
135 //
136 // Does BMP encroach on default check menu position?
137 //
138 size_t nAdjustedWidth = m_bmpChecked.GetWidth() +
139 (wxSystemSettings::GetMetric(wxSYS_EDGE_X) * 2);
140
141 //
142 // Do we need to widen margin to fit BMP?
143 //
144 if ((size_t)GetMarginWidth() < nAdjustedWidth)
145 SetMarginWidth(nAdjustedWidth);
146
147 //
148 // Add the size of the bitmap to our total size...
149 //
150 *pWidth += GetMarginWidth();
151 }
152
153 //
154 // Add the size of the bitmap to our total size - even if we don't have
155 // a bitmap we leave room for one...
156 //
157 *pWidth += GetMarginWidth();
158
159 //
160 // Make sure that this item is at least as
161 // tall as the user's system settings specify
162 //
163 if (*pHeight < m_nMinHeight)
164 *pHeight = m_nMinHeight;
165 m_nHeight = *pHeight; // remember height for use in OnDrawItem
6670f564 166 return true;
402e2f7c 167} // end of wxOwnerDrawn::OnMeasureItem
63415778 168
63415778 169// draw the item
6670f564
WS
170bool wxOwnerDrawn::OnDrawItem( wxDC& rDC,
171 const wxRect& rRect,
172 wxODAction eAction,
173 wxODStatus eStatus )
63415778 174{
402e2f7c 175 //
23122f8c 176 // We do nothing on focus change
7172b423 177 //
23122f8c 178 if (eAction == wxODFocusChanged )
6670f564 179 return true;
7172b423 180
402e2f7c 181 //
7172b423
DW
182 // Select the font and draw the text
183 // ---------------------------------
402e2f7c 184 //
402e2f7c 185
7172b423 186 CHARBUNDLE vCbnd;
402e2f7c 187 HPS hPS= rDC.GetHPS();
7172b423
DW
188 wxColour vColBack;
189 wxColour vColText;
190 COLORREF vRef;
5afb9458 191 RECTL vRect = {rRect.x + 4, rRect.y + 1, rRect.x + (rRect.width - 2), rRect.y + rRect.height};
402e2f7c 192
ad7f3189
DW
193 memset(&vCbnd, 0, sizeof(CHARBUNDLE));
194
7172b423
DW
195 //
196 // Use default font if no font set
197 //
198 if (m_font.Ok())
199 {
200 m_font.RealizeResource();
201 }
202 else
203 {
204 ::GpiSetCharSet(hPS, LCID_DEFAULT);
205 }
5afb9458
DW
206
207 //
d6922577 208 // Based on the status of the menu item, pick the right colors
5afb9458 209 //
402e2f7c
DW
210 if (eStatus & wxODSelected)
211 {
0fba44b4 212 wxColour vCol2(wxT("WHITE"));
5afb9458
DW
213 vColBack.Set( (unsigned char)0
214 ,(unsigned char)0
215 ,(unsigned char)160
216 ); // no dark blue in color table
217 vColText = vCol2;
402e2f7c
DW
218 }
219 else if (eStatus & wxODDisabled)
220 {
7172b423
DW
221 vRef = (ULONG)::WinQuerySysColor( HWND_DESKTOP
222 ,SYSCLR_MENU // Light gray
223 ,0L
224 );
225 vColBack.Set( GetRValue(vRef)
226 ,GetGValue(vRef)
227 ,GetBValue(vRef)
228 );
229 vRef = (ULONG)::WinQuerySysColor( HWND_DESKTOP
230 ,SYSCLR_MENUDISABLEDTEXT // dark gray
231 ,0L
232 );
233 vColText.Set( GetRValue(vRef)
234 ,GetGValue(vRef)
235 ,GetBValue(vRef)
236 );
402e2f7c
DW
237 }
238 else
239 {
240 //
241 // Fall back to default colors if none explicitly specified
242 //
7172b423 243 vRef = ::WinQuerySysColor( HWND_DESKTOP
77ffb593 244 ,SYSCLR_MENU // we are using gray for all our window backgrounds in wxWidgets
7172b423
DW
245 ,0L
246 );
247 vColBack.Set( GetRValue(vRef)
248 ,GetGValue(vRef)
249 ,GetBValue(vRef)
250 );
251 vRef = ::WinQuerySysColor( HWND_DESKTOP
252 ,SYSCLR_WINDOWTEXT // Black
253 ,0L
254 );
255 vColText.Set( GetRValue(vRef)
256 ,GetGValue(vRef)
257 ,GetBValue(vRef)
258 );
402e2f7c 259 }
ad7f3189 260
5afb9458
DW
261 rDC.SetTextBackground(vColBack);
262 rDC.SetTextForeground(vColText);
263 rDC.SetBackgroundMode(wxTRANSPARENT);
ad7f3189
DW
264 vCbnd.lColor = vColText.GetPixel();
265 vCbnd.lBackColor = vColBack.GetPixel();
266 ::GpiSetAttrs( hPS
267 ,PRIM_CHAR
268 ,CBB_BACK_COLOR | CBB_COLOR
269 ,0
270 ,&vCbnd
271 );
272 ::GpiSetBackMix( hPS
273 ,BM_LEAVEALONE
274 );
7172b423 275
5afb9458
DW
276 //
277 // Paint the background
278 //
279 ::WinFillRect(hPS, &vRect, vColBack.GetPixel());
402e2f7c 280
402e2f7c
DW
281 //
282 // Determine where to draw and leave space for a check-mark.
283 //
284 int nX = rRect.x + GetMarginWidth();
285
402e2f7c
DW
286 //
287 // Unfortunately, unlike Win32, PM has no owner drawn specific text
288 // drawing methods like ::DrawState that can cleanly handle accel
d6922577 289 // mnemonics and deal, automatically, with various states, so we have
402e2f7c 290 // to handle them ourselves. Notice Win32 can't handle \t in ownerdrawn
d6922577
JS
291 // strings either. We cannot handle mnemonics either. We display
292 // them, though, in the hope we can figure them out some day.
5afb9458 293 //
402e2f7c 294
23122f8c 295 //
d6922577 296 // Display main text and accel text separately to align better
23122f8c 297 //
6670f564
WS
298 wxString sTgt = wxT("\t");
299 wxString sFullString = m_strName; // need to save the original text
300 wxString sAccel;
301 int nIndex;
302 size_t nWidth;
303 size_t nCharWidth;
304 size_t nHeight;
305 bool bFoundMnemonic = false;
306 bool bFoundAccel = false;
23122f8c 307
5afb9458
DW
308 //
309 // Deal with the tab, extracting the Accel text
310 //
311 nIndex = sFullString.Find(sTgt.c_str());
23122f8c 312 if (nIndex != -1)
5afb9458 313 {
6670f564 314 bFoundAccel = true;
5afb9458
DW
315 sAccel = sFullString.Mid(nIndex + 1);
316 sFullString.Remove(nIndex);
317 }
318
319 //
d6922577 320 // Deal with the mnemonic character
5afb9458 321 //
0fba44b4 322 sTgt = wxT("~");
5afb9458 323 nIndex = sFullString.Find(sTgt.c_str());
23122f8c 324 if (nIndex != -1)
5afb9458 325 {
6670f564 326 wxString sTmp = sFullString;
5afb9458 327
6670f564 328 bFoundMnemonic = true;
5afb9458
DW
329 sTmp.Remove(nIndex);
330 rDC.GetTextExtent( sTmp
331 ,(long *)&nWidth
332 ,(long *)&nHeight
333 );
9923c37d 334 sTmp = sFullString[(size_t)(nIndex + 1)];
5afb9458
DW
335 rDC.GetTextExtent( sTmp
336 ,(long *)&nCharWidth
337 ,(long *)&nHeight
338 );
6670f564 339 sFullString.Replace(sTgt.c_str(), wxEmptyString, true);
5afb9458
DW
340 }
341
342 //
343 // Draw the main item text sans the accel text
ad7f3189
DW
344 //
345 POINTL vPntStart = {nX, rRect.y + 4};
346 ::GpiCharStringAt( rDC.GetHPS()
347 ,&vPntStart
348 ,sFullString.length()
349 ,(PCH)sFullString.c_str()
350 );
d6922577 351 if (bFoundMnemonic)
5afb9458
DW
352 {
353 //
d6922577 354 // Underline the mnemonic -- still won't work, but at least it "looks" right
5afb9458
DW
355 //
356 wxPen vPen;
5afb9458
DW
357 POINTL vPntEnd = {nX + nWidth + nCharWidth - 3, rRect.y + 2}; //CharWidth is bit wide
358
ad7f3189
DW
359 vPntStart.x = nX + nWidth - 1;
360 vPntStart.y = rRect.y + 2; // Make it look pretty!
5afb9458
DW
361 vPen = wxPen(vColText, 1, wxSOLID); // Assuming we are always black
362 rDC.SetPen(vPen);
363 ::GpiMove(hPS, &vPntStart);
364 ::GpiLine(hPS, &vPntEnd);
365 }
23122f8c 366
5afb9458
DW
367 //
368 // Now draw the accel text
369 //
370 if (bFoundAccel)
371 {
372 size_t nWidth;
373 size_t nHeight;
7172b423 374
5afb9458
DW
375 rDC.GetTextExtent( sAccel
376 ,(long *)&nWidth
377 ,(long *)&nHeight
378 );
379 //
380 // Back off the starting position from the right edge
381 //
ad7f3189
DW
382 vPntStart.x = rRect.width - (nWidth + 7);
383 vPntStart.y = rRect.y + 4;
384 ::GpiCharStringAt( rDC.GetHPS()
385 ,&vPntStart
386 ,sAccel.length()
387 ,(PCH)sAccel.c_str()
388 );
5afb9458 389 }
402e2f7c
DW
390
391 //
392 // Draw the bitmap
393 // ---------------
394 //
395 if (IsCheckable() && !m_bmpChecked.Ok())
396 {
397 if (eStatus & wxODChecked)
398 {
399 RECTL vRect;
400 HBITMAP hBmpCheck = ::WinGetSysBitmap(HWND_DESKTOP, SBMP_MENUCHECK);
401
402 vRect.xLeft = rRect.x;
403 vRect.xRight = rRect.x + GetMarginWidth();
404 vRect.yBottom = rRect.y;
1159a76f 405 vRect.yTop = rRect.y + m_nHeight - 3;
402e2f7c
DW
406
407 ::WinDrawBitmap( hPS // PS for this menuitem
408 ,hBmpCheck // system checkmark
409 ,NULL // draw the whole bitmap
410 ,(PPOINTL)&vRect // destination -- bottom left corner of the menuitem area
411 ,0L // ignored
412 ,0L // draw a bitmap
413 ,DBM_NORMAL // draw normal size
414 );
415 }
63415778 416 }
402e2f7c
DW
417 else
418 {
419 //
420 // For uncheckable item we use only the 'checked' bitmap
421 //
6670f564 422 wxBitmap vBmp(GetBitmap(IsCheckable() ? ((eStatus & wxODChecked) != 0) : TRUE));
402e2f7c
DW
423
424 if (vBmp.Ok())
425 {
ad7f3189 426
402e2f7c 427 wxMemoryDC vDCMem(&rDC);
ad7f3189 428 wxMemoryDC* pOldDC = (wxMemoryDC*)vBmp.GetSelectedInto();
402e2f7c 429
ad7f3189
DW
430 if(pOldDC != NULL)
431 {
432 vBmp.SetSelectedInto(NULL);
433 }
402e2f7c
DW
434 vDCMem.SelectObject(vBmp);
435
436 //
437 // Center bitmap
438 //
439 int nBmpWidth = vBmp.GetWidth();
440 int nBmpHeight = vBmp.GetHeight();
441
442 //
443 // There should be enough space!
444 //
445 wxASSERT((nBmpWidth <= rRect.width) && (nBmpHeight <= rRect.height));
446
b63b737d
DW
447 int nHeightDiff = m_nHeight - nBmpHeight;
448
402e2f7c 449 rDC.Blit( rRect.x + (GetMarginWidth() - nBmpWidth) / 2
b63b737d 450 ,rRect.y + nHeightDiff / 2
402e2f7c
DW
451 ,nBmpWidth
452 ,nBmpHeight
453 ,&vDCMem
454 ,0
455 ,0
456 ,wxCOPY
6670f564 457 ,true
402e2f7c
DW
458 );
459
460 if (eStatus & wxODSelected)
461 {
2b7cd532 462 POINTL vPnt1 = {rRect.x + 1, rRect.y + 3}; // Leave a little background border
1159a76f 463 POINTL vPnt2 = {rRect.x + GetMarginWidth(), rRect.y + m_nHeight - 3};
2b7cd532 464
402e2f7c
DW
465 LINEBUNDLE vLine;
466
5afb9458 467 vLine.lColor = vColBack.GetPixel();
402e2f7c
DW
468 ::GpiSetAttrs( hPS
469 ,PRIM_LINE
470 ,LBB_COLOR
471 ,0
472 ,&vLine
473 );
1159a76f 474 ::GpiMove(hPS, &vPnt1);
402e2f7c
DW
475 ::GpiBox( hPS
476 ,DRO_OUTLINE
1159a76f 477 ,&vPnt2
402e2f7c
DW
478 ,0L
479 ,0L
480 );
481 }
ad7f3189 482 vBmp.SetSelectedInto(NULL);
402e2f7c 483 }
63415778 484 }
6670f564 485 return true;
23122f8c 486} // end of wxOwnerDrawn::OnDrawItem
63415778 487
7e99520b 488#endif //wxUSE_OWNER_DRAWN