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