More OS/2 update to fix some owner drawn things
[wxWidgets.git] / src / os2 / checklst.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: checklst.cpp
3 // Purpose: implementation of wxCheckListBox class
4 // Author: David Webster
5 // Modified by:
6 // Created: 10/13/99
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // headers & declarations
14 // ============================================================================
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #if wxUSE_OWNER_DRAWN
20
21 #include "wx/object.h"
22 #include "wx/colour.h"
23 #include "wx/font.h"
24 #include "wx/bitmap.h"
25 #include "wx/window.h"
26 #include "wx/listbox.h"
27 #include "wx/ownerdrw.h"
28 #include "wx/settings.h"
29 #include "wx/dcmemory.h"
30 #include "wx/os2/checklst.h"
31 #include "wx/log.h"
32
33 #define INCL_PM
34 #include <os2.h>
35
36 // ----------------------------------------------------------------------------
37 // private functions
38 // ----------------------------------------------------------------------------
39
40 // get item (converted to right type)
41 #define GetItem(n) ((wxCheckListBoxItem *)(GetItem(n)))
42
43 // ============================================================================
44 // implementation
45 // ============================================================================
46
47 IMPLEMENT_DYNAMIC_CLASS(wxCheckListBox, wxListBox)
48
49 // ----------------------------------------------------------------------------
50 // declaration and implementation of wxCheckListBoxItem class
51 // ----------------------------------------------------------------------------
52
53 class wxCheckListBoxItem : public wxOwnerDrawn
54 {
55 friend class wxCheckListBox;
56 public:
57 //
58 // ctor
59 //
60 wxCheckListBoxItem( wxCheckListBox* pParent
61 ,size_t nIndex
62 );
63
64 //
65 // Drawing functions
66 //
67 virtual bool OnDrawItem( wxDC& rDc
68 ,const wxRect& rRect
69 ,wxODAction eAct
70 ,wxODStatus eStat
71 );
72
73 //
74 // Simple accessors
75 //
76 bool IsChecked(void) const { return m_bChecked; }
77 void Check(bool bCheck);
78 void Toggle(void) { Check(!IsChecked()); }
79
80 private:
81 bool m_bChecked;
82 wxCheckListBox* m_pParent;
83 size_t m_nIndex;
84 }; // end of CLASS wxCheckListBoxItem
85
86 wxCheckListBoxItem::wxCheckListBoxItem (
87 wxCheckListBox* pParent
88 , size_t nIndex
89 )
90 : wxOwnerDrawn( ""
91 ,TRUE // checkable
92 )
93 {
94 m_bChecked = FALSE;
95 m_pParent = pParent;
96 m_nIndex = nIndex;
97
98 //
99 // We don't initialize m_nCheckHeight/Width vars because it's
100 // done in OnMeasure while they are used only in OnDraw and we
101 // know that there will always be OnMeasure before OnDraw
102 //
103 SetMarginWidth(GetDefaultMarginWidth());
104 } // end of wxCheckListBoxItem::wxCheckListBoxItem
105
106 bool wxCheckListBoxItem::OnDrawItem (
107 wxDC& rDc
108 , const wxRect& rRect
109 , wxODAction eAct
110 , wxODStatus eStat
111 )
112 {
113 wxRect vRect = rRect;
114
115 ::WinQueryWindowRect( m_pParent->GetHWND()
116 ,&rDc.m_vRclPaint
117 );
118 if (IsChecked())
119 eStat = (wxOwnerDrawn::wxODStatus)(eStat | wxOwnerDrawn::wxODChecked);
120
121 //
122 // Unfortunately PM doesn't quite get the text position exact. We need to alter
123 // it down and to the right, just a little bit. The coords in rRect are OS/2
124 // coords not wxWindows coords.
125 //
126 vRect.x += 5;
127 vRect.y -= 3;
128 if (wxOwnerDrawn::OnDrawItem( rDc
129 ,vRect
130 ,eAct
131 ,eStat))
132 {
133 size_t nCheckWidth = GetDefaultMarginWidth();
134 size_t nCheckHeight = m_pParent->GetItemHeight();
135 int nParentHeight;
136 int nX = rRect.GetX();
137 int nY = rRect.GetY();
138 int nOldY = nY;
139 wxColour vColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
140 wxPen vPenBack;
141 wxPen vPenGray;
142 wxPen vPenPrev;
143
144 m_pParent->GetSize( NULL
145 ,&nParentHeight
146 );
147
148 nY = nParentHeight - nY - nCheckHeight;
149 vPenBack = wxPen(vColour, 1, wxSOLID);
150 vPenGray = wxPen(wxColour(127, 127, 127), 1, wxSOLID);
151
152 //
153 // Erase the 1-pixel border
154 //
155 rDc.SetPen(vPenBack);
156 rDc.DrawRectangle( nX
157 ,nY
158 ,nCheckWidth
159 ,nCheckHeight
160 );
161
162 //
163 // Now we draw the smaller rectangle
164 //
165 nY++;
166 nCheckWidth -= 2;
167 nCheckHeight -= 2;
168
169 //
170 // Draw hollow gray rectangle
171 //
172 rDc.SetPen(vPenGray);
173 rDc.DrawRectangle( nX
174 ,nY
175 ,nCheckWidth
176 ,nCheckHeight
177 );
178
179 nX++;
180 if (IsChecked())
181 {
182 //
183 // Draw the check by loading the sys standard bitmap and drawing it
184 //
185 HBITMAP hChkBmp = ::WinGetSysBitmap( HWND_DESKTOP
186 ,SBMP_MENUCHECK
187 );
188 POINTL vPoint = {nX, nOldY + 3};
189
190 ::WinDrawBitmap( rDc.GetHPS()
191 ,hChkBmp
192 ,NULL
193 ,&vPoint
194 ,NULL
195 ,NULL
196 ,DBM_NORMAL
197 );
198 }
199 return TRUE;
200 }
201 return FALSE;
202 } // end of wxCheckListBoxItem::OnDrawItem
203
204 //
205 // Change the state of the item and redraw it
206 //
207 void wxCheckListBoxItem::Check (
208 bool bCheck
209 )
210 {
211 m_bChecked = bCheck;
212
213 //
214 // Index may be chanegd because new items were added/deleted
215 //
216 if (m_pParent->GetItemIndex(this) != (int)m_nIndex)
217 {
218 //
219 // Update it
220 //
221 int nIndex = m_pParent->GetItemIndex(this);
222
223 wxASSERT_MSG(nIndex != wxNOT_FOUND, wxT("what does this item do here?"));
224
225 m_nIndex = (size_t)nIndex;
226 }
227
228 HWND hWndListbox = (HWND)m_pParent->GetHWND();
229 RECTL rUpdate;
230 MRESULT mRc;
231
232 wxCommandEvent vEvent( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED
233 ,m_pParent->GetId()
234 );
235
236 vEvent.SetInt(m_nIndex);
237 vEvent.SetEventObject(m_pParent);
238 m_pParent->ProcessCommand(vEvent);
239 } // end of wxCheckListBoxItem::Check
240
241 // ----------------------------------------------------------------------------
242 // implementation of wxCheckListBox class
243 // ----------------------------------------------------------------------------
244
245 // define event table
246 // ------------------
247 BEGIN_EVENT_TABLE(wxCheckListBox, wxListBox)
248 EVT_CHAR(wxCheckListBox::OnChar)
249 EVT_LEFT_DOWN(wxCheckListBox::OnLeftClick)
250 END_EVENT_TABLE()
251
252 //
253 // Control creation
254 // ----------------
255 //
256
257 //
258 // Default ctor: use Create() to really create the control
259 //
260 wxCheckListBox::wxCheckListBox()
261 : wxListBox()
262 {
263 } // end of wxCheckListBox::wxCheckListBox
264
265 //
266 // Ctor which creates the associated control
267 //
268 wxCheckListBox::wxCheckListBox (
269 wxWindow* pParent
270 , wxWindowID vId
271 , const wxPoint& rPos
272 , const wxSize& rSize
273 , int nStrings
274 , const wxString asChoices[]
275 , long lStyle
276 #if wxUSE_VALIDATORS
277 , const wxValidator& rVal
278 #endif
279 , const wxString& rsName
280 )
281 : wxListBox()
282 {
283 Create( pParent
284 ,vId
285 ,rPos
286 ,rSize
287 ,nStrings
288 ,asChoices
289 ,lStyle | wxLB_OWNERDRAW
290 #if wxUSE_VALIDATORS
291 ,rVal
292 #endif
293 ,rsName
294 );
295 } // end of wxCheckListBox::wxCheckListBox
296
297 void wxCheckListBox::Delete(
298 int N
299 )
300 {
301 wxCHECK_RET( N >= 0 && N < m_nNumItems,
302 wxT("invalid index in wxListBox::Delete") );
303 wxListBox::Delete(N);
304
305 //
306 // Free memory
307 //
308 delete m_aItems[N];
309 m_aItems.RemoveAt(N);
310 } // end of wxCheckListBox::Delete
311
312 void wxCheckListBox::InsertItems (
313 int nItems
314 , const wxString asItems[]
315 , int nPos
316 )
317 {
318 int i;
319
320 wxCHECK_RET( nPos >= 0 && nPos <= m_nNumItems,
321 wxT("invalid index in wxCheckListBox::InsertItems") );
322
323 wxListBox::InsertItems( nItems
324 ,asItems
325 ,nPos
326 );
327 for (i = 0; i < nItems; i++)
328 {
329 wxOwnerDrawn* pNewItem = CreateItem((size_t)(nPos + i));
330
331 pNewItem->SetName(asItems[i]);
332 m_aItems.Insert(pNewItem, (size_t)(nPos + i));
333 ::WinSendMsg( (HWND)GetHWND()
334 ,LM_SETITEMHANDLE
335 ,(MPARAM)(i + nPos)
336 ,MPFROMP(pNewItem)
337 );
338 }
339 } // end of wxCheckListBox::InsertItems
340
341 bool wxCheckListBox::SetFont (
342 const wxFont& rFont
343 )
344 {
345 size_t i;
346
347 for (i = 0; i < m_aItems.GetCount(); i++)
348 m_aItems[i]->SetFont(rFont);
349 wxListBox::SetFont(rFont);
350 return TRUE;
351 } // end of wxCheckListBox::SetFont
352
353 //
354 // Create/retrieve item
355 // --------------------
356 //
357
358 //
359 // Create a check list box item
360 //
361 wxOwnerDrawn* wxCheckListBox::CreateItem (
362 size_t nIndex
363 )
364 {
365 wxCheckListBoxItem* pItem = new wxCheckListBoxItem( this
366 ,nIndex
367 );
368 return pItem;
369 } // end of wxCheckListBox::CreateItem
370
371 //
372 // Return item size
373 // ----------------
374 //
375 long wxCheckListBox::OS2OnMeasure (
376 WXMEASUREITEMSTRUCT* pItem
377 )
378 {
379 if (!pItem)
380 pItem = (WXMEASUREITEMSTRUCT*)new OWNERITEM;
381 if (wxListBox::OS2OnMeasure(pItem) )
382 {
383 POWNERITEM pStruct = (POWNERITEM)pItem;
384
385 //
386 // Save item height
387 //
388 m_nItemHeight = pStruct->rclItem.yTop - pStruct->rclItem.yBottom;
389
390 //
391 // Add place for the check mark
392 //
393 pStruct->rclItem.xRight += wxOwnerDrawn::GetDefaultMarginWidth();
394 return long(MRFROM2SHORT((USHORT)m_nItemHeight, (USHORT)(pStruct->rclItem.xRight - pStruct->rclItem.xLeft)));
395 }
396 return 0L;
397 } // end of wxCheckListBox::CreateItem
398
399 //
400 // Check items
401 // -----------
402 //
403 bool wxCheckListBox::IsChecked (
404 size_t uiIndex
405 ) const
406 {
407 return GetItem(uiIndex)->IsChecked();
408 } // end of wxCheckListBox::IsChecked
409
410 void wxCheckListBox::Check (
411 size_t uiIndex
412 , bool bCheck
413 )
414 {
415 GetItem(uiIndex)->Check(bCheck);
416 } // end of wxCheckListBox::Check
417
418 //
419 // Process events
420 // --------------
421 //
422 void wxCheckListBox::OnChar (
423 wxKeyEvent& rEvent
424 )
425 {
426 if (rEvent.KeyCode() == WXK_SPACE)
427 GetItem(GetSelection())->Toggle();
428 else
429 rEvent.Skip();
430 } // end of wxCheckListBox::OnChar
431
432 void wxCheckListBox::OnLeftClick (
433 wxMouseEvent& rEvent
434 )
435 {
436 //
437 // Clicking on the item selects it, clicking on the checkmark toggles
438 //
439 if (rEvent.GetX() <= wxOwnerDrawn::GetDefaultMarginWidth())
440 {
441 int nParentHeight;
442 wxScreenDC vDc;
443 wxCoord vHeight;
444
445 GetSize( NULL
446 ,&nParentHeight
447 );
448 vDc.SetFont(GetFont());
449 vHeight = vDc.GetCharHeight() * 2.5;
450
451 //
452 // This, of course, will not work if the LB is scrolled
453 //
454 int nY = rEvent.GetY();
455
456 nY = nParentHeight - (nY + vHeight);
457
458 size_t nItem = (size_t)(nY / vHeight);
459
460 if (nItem < (size_t)m_nNumItems)
461 GetItem(nItem)->Toggle();
462 //
463 // else: it's not an error, just click outside of client zone
464 //
465 }
466 else
467 {
468 //
469 // Implement default behaviour: clicking on the item selects it
470 //
471 rEvent.Skip();
472 }
473 } // end of wxCheckListBox::OnLeftClick
474
475 #endif
476