]> git.saurik.com Git - wxWidgets.git/blame - src/mac/checklst.cpp
A little clarification
[wxWidgets.git] / src / mac / checklst.cpp
CommitLineData
e9576ca5
SC
1///////////////////////////////////////////////////////////////////////////////
2// Name: checklst.cpp
3// Purpose: implementation of wxCheckListBox class
a31a5f85 4// Author: Stefan Csomor
e9576ca5 5// Modified by:
a31a5f85 6// Created: 1998-01-01
e9576ca5 7// RCS-ID: $Id$
a31a5f85 8// Copyright: (c) Stefan Csomor
e9576ca5
SC
9// Licence: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// headers & declarations
14// ============================================================================
15
16#ifdef __GNUG__
17#pragma implementation "checklst.h"
18#endif
19
b698c8e9 20#include "wx/defs.h"
e9576ca5 21
55d60746
GD
22#if wxUSE_CHECKLISTBOX
23
b698c8e9
GD
24#include "wx/checklst.h"
25
dbfc5b97
SC
26#include "wx/mac/uma.h"
27#include "Appearance.h"
28
1169a919
JS
29// ============================================================================
30// implementation of wxCheckListBoxBase
31// ============================================================================
32
33wxCheckListBoxBase::wxCheckListBoxBase()
34{
35}
36
e9576ca5 37// ============================================================================
dbfc5b97 38// implementation of wxCheckListBox
e9576ca5
SC
39// ============================================================================
40
dbfc5b97
SC
41IMPLEMENT_DYNAMIC_CLASS(wxCheckListBox, wxListBox)
42
43const short kwxMacListWithVerticalScrollbar = 128 ;
44const short kwxMacListItemHeight = 14 ;
45const short kwxMacListCheckboxWidth = 14 ;
46
573ac9dc
SC
47#if PRAGMA_STRUCT_ALIGN
48 #pragma options align=mac68k
49#elif PRAGMA_STRUCT_PACKPUSH
50 #pragma pack(push, 2)
51#elif PRAGMA_STRUCT_PACK
52 #pragma pack(2)
53#endif
54
dbfc5b97
SC
55typedef struct {
56 unsigned short instruction;
57 void (*function)();
58} ldefRec, *ldefPtr, **ldefHandle;
59
573ac9dc
SC
60#if PRAGMA_STRUCT_ALIGN
61 #pragma options align=reset
62#elif PRAGMA_STRUCT_PACKPUSH
63 #pragma pack(pop)
64#elif PRAGMA_STRUCT_PACK
65 #pragma pack()
66#endif
67
dbfc5b97
SC
68extern "C"
69{
70static pascal void wxMacCheckListDefinition( short message, Boolean isSelected, Rect *drawRect,
71 Cell cell, short dataOffset, short dataLength,
72 ListHandle listHandle ) ;
73}
74
75static pascal void wxMacCheckListDefinition( short message, Boolean isSelected, Rect *drawRect,
76 Cell cell, short dataOffset, short dataLength,
77 ListHandle listHandle )
78{
dbfc5b97
SC
79 GrafPtr savePort;
80 GrafPtr grafPtr;
81 RgnHandle savedClipRegion;
82 SInt32 savedPenMode;
83 wxCheckListBox* list;
e40298d5
JS
84 GetPort(&savePort);
85 SetPort((**listHandle).port);
86 grafPtr = (**listHandle).port ;
dbfc5b97
SC
87 // typecast our refCon
88 list = (wxCheckListBox*) GetControlReference( (ControlHandle) GetListRefCon(listHandle) );
89
90 // Calculate the cell rect.
91
92 switch( message ) {
93 case lInitMsg:
94 break;
95
96 case lCloseMsg:
97 break;
98
99 case lDrawMsg:
100 {
101 const wxString text = list->m_stringArray[cell.v] ;
102 int checked = list->m_checks[cell.v] ;
103
104 // Save the current clip region, and set the clip region to the area we are about
105 // to draw.
106
107 savedClipRegion = NewRgn();
108 GetClip( savedClipRegion );
109
110 ClipRect( drawRect );
111 EraseRect( drawRect );
112
fcb35beb
VZ
113 const wxFont& font = list->GetFont();
114 if ( font.Ok() )
e40298d5 115 {
fcb35beb
VZ
116 ::TextFont( font.GetMacFontNum() ) ;
117 ::TextSize( font.GetMacFontSize()) ;
118 ::TextFace( font.GetMacFontStyle() ) ;
50b30d83
SC
119 }
120
dbfc5b97
SC
121 ThemeButtonDrawInfo info ;
122 info.state = kThemeStateActive ;
123 info.value = checked ? kThemeButtonOn : kThemeButtonOff ;
124 info.adornment = kThemeAdornmentNone ;
125 Rect checkRect = *drawRect ;
50b30d83
SC
126
127
dbfc5b97 128 checkRect.left +=0 ;
50b30d83
SC
129 checkRect.top +=0 ;
130 checkRect.right = checkRect.left + list->m_checkBoxWidth ;
131 checkRect.bottom = checkRect.top + list->m_checkBoxHeight ;
dbfc5b97 132 DrawThemeButton(&checkRect,kThemeCheckBox,
e40298d5
JS
133 &info,NULL,NULL, NULL,0);
134
135 MoveTo(drawRect->left + 2 + list->m_checkBoxWidth+2, drawRect->top + list->m_TextBaseLineOffset );
136
137 DrawText(text, 0 , text.Length());
dbfc5b97
SC
138 // If the cell is hilited, do the hilite now. Paint the cell contents with the
139 // appropriate QuickDraw transform mode.
140
141 if( isSelected ) {
76a5e5d2
SC
142 savedPenMode = GetPortPenMode( (CGrafPtr) grafPtr );
143 SetPortPenMode( (CGrafPtr) grafPtr, hilitetransfermode );
dbfc5b97 144 PaintRect( drawRect );
76a5e5d2 145 SetPortPenMode( (CGrafPtr) grafPtr, savedPenMode );
dbfc5b97
SC
146 }
147
148 // Restore the saved clip region.
149
150 SetClip( savedClipRegion );
151 DisposeRgn( savedClipRegion );
e40298d5
JS
152 }
153 break;
dbfc5b97
SC
154 case lHiliteMsg:
155
156 // Hilite or unhilite the cell. Paint the cell contents with the
157 // appropriate QuickDraw transform mode.
158
159 GetPort( &grafPtr );
76a5e5d2
SC
160 savedPenMode = GetPortPenMode( (CGrafPtr) grafPtr );
161 SetPortPenMode( (CGrafPtr) grafPtr, hilitetransfermode );
dbfc5b97 162 PaintRect( drawRect );
76a5e5d2 163 SetPortPenMode( (CGrafPtr) grafPtr, savedPenMode );
dbfc5b97
SC
164 break;
165 default :
166 break ;
167 }
168 SetPort(savePort);
169}
170
171extern "C" void MacDrawStringCell(Rect *cellRect, Cell lCell, ListHandle theList, long refCon) ;
172
173static ListDefUPP macCheckListDefUPP = NULL ;
174
175// ----------------------------------------------------------------------------
176// creation
177// ----------------------------------------------------------------------------
178
179void wxCheckListBox::Init()
180{
181}
182
183bool wxCheckListBox::Create(wxWindow *parent,
184 wxWindowID id,
185 const wxPoint &pos,
186 const wxSize &size,
187 int n,
188 const wxString choices[],
189 long style,
190 const wxValidator& validator,
191 const wxString &name)
192{
b45ed7a2
VZ
193 if ( !wxCheckListBoxBase::Create(parent, id, pos, size,
194 n, choices, style, validator, name) )
195 return false;
196
dbfc5b97
SC
197 m_noItems = 0 ; // this will be increased by our append command
198 m_selected = 0;
199
50b30d83
SC
200 m_checkBoxWidth = 12;
201 m_checkBoxHeight= 10;
202
203 long h = m_checkBoxHeight ;
204#if TARGET_CARBON
205 GetThemeMetric(kThemeMetricCheckBoxWidth,(long *)&m_checkBoxWidth);
206 GetThemeMetric(kThemeMetricCheckBoxHeight,&h);
207#endif
fcb35beb
VZ
208
209 const wxFont& font = GetFont();
50b30d83
SC
210
211 FontInfo finfo;
fcb35beb 212 FetchFontInfo(font.GetMacFontNum(),font.GetMacFontSize(),font.GetMacFontStyle(),&finfo);
50b30d83
SC
213
214 m_TextBaseLineOffset= finfo.leading+finfo.ascent;
215 m_checkBoxHeight= finfo.leading+finfo.ascent+finfo.descent;
216
e40298d5
JS
217 if (m_checkBoxHeight<h)
218 {
219 m_TextBaseLineOffset+= (h-m_checkBoxHeight)/2;
220 m_checkBoxHeight= h;
221 }
222
dbfc5b97
SC
223 Rect bounds ;
224 Str255 title ;
225
427ff662 226 MacPreControlCreate( parent , id , wxEmptyString , pos , size ,style, validator , name , &bounds , title ) ;
dbfc5b97
SC
227
228 ListDefSpec listDef;
229 listDef.defType = kListDefUserProcType;
230 if ( macCheckListDefUPP == NULL )
231 {
232 macCheckListDefUPP = NewListDefUPP( wxMacCheckListDefinition );
233 }
234 listDef.u.userProc = macCheckListDefUPP ;
235
236#if TARGET_CARBON
237 Size asize;
238
239
962cbf2e 240 CreateListBoxControl( MAC_WXHWND(parent->MacGetRootWindow()), &bounds, false, 0, 1, false, true,
50b30d83 241 m_checkBoxHeight+2, 14, false, &listDef, (ControlRef *)&m_macControl );
dbfc5b97 242
76a5e5d2 243 GetControlData( (ControlHandle) m_macControl, kControlNoPart, kControlListBoxListHandleTag,
dbfc5b97
SC
244 sizeof(ListHandle), (Ptr) &m_macList, &asize);
245
76a5e5d2
SC
246 SetControlReference( (ControlHandle) m_macControl, (long) this);
247 SetControlVisibility( (ControlHandle) m_macControl, false, false);
dbfc5b97
SC
248
249#else
250
251 long result ;
252
fe3fcb05 253 wxStAppResource resload ;
76a5e5d2 254 m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , title , false ,
dbfc5b97
SC
255 kwxMacListWithVerticalScrollbar , 0 , 0,
256 kControlListBoxProc , (long) this ) ;
76a5e5d2 257 ::GetControlData( (ControlHandle) m_macControl , kControlNoPart , kControlListBoxListHandleTag ,
dbfc5b97
SC
258 sizeof( ListHandle ) , (char*) &m_macList , &result ) ;
259
260 HLock( (Handle) m_macList ) ;
261 ldefHandle ldef ;
262 ldef = (ldefHandle) NewHandle( sizeof(ldefRec) ) ;
76a5e5d2 263 if ( (**(ListHandle)m_macList).listDefProc != NULL )
dbfc5b97
SC
264 {
265 (**ldef).instruction = 0x4EF9; /* JMP instruction */
266 (**ldef).function = (void(*)()) listDef.u.userProc;
76a5e5d2 267 (**(ListHandle)m_macList).listDefProc = (Handle) ldef ;
dbfc5b97
SC
268 }
269
76a5e5d2 270 Point pt = (**(ListHandle)m_macList).cellSize ;
dbfc5b97 271 pt.v = 14 ;
76a5e5d2
SC
272 LCellSize( pt , (ListHandle)m_macList ) ;
273 LAddColumn( 1 , 0 , (ListHandle)m_macList ) ;
2f1ae414 274#endif
dbfc5b97
SC
275 OptionBits options = 0;
276 if ( style & wxLB_MULTIPLE )
277 {
278 options += lNoExtend ;
279 }
280 else if ( style & wxLB_EXTENDED )
281 {
282 options += lExtendDrag ;
283 }
284 else
285 {
2b5f62a0 286 options = (OptionBits) lOnlyOne ;
dbfc5b97 287 }
76a5e5d2 288 SetListSelectionFlags((ListHandle)m_macList, options);
dbfc5b97
SC
289
290 MacPostControlCreate() ;
291
292 for ( int i = 0 ; i < n ; i++ )
293 {
294 Append( choices[i] ) ;
295 }
296
76a5e5d2 297 LSetDrawingMode( true , (ListHandle) m_macList ) ;
dbfc5b97
SC
298
299 return TRUE;
300}
e9576ca5
SC
301
302// ----------------------------------------------------------------------------
dbfc5b97 303// wxCheckListBox functions
e9576ca5
SC
304// ----------------------------------------------------------------------------
305
dbfc5b97
SC
306bool wxCheckListBox::IsChecked(size_t item) const
307{
308 wxCHECK_MSG( item < m_checks.GetCount(), FALSE,
309 _T("invalid index in wxCheckListBox::IsChecked") );
310
311 return m_checks[item] != 0;
312}
313
314void wxCheckListBox::Check(size_t item, bool check)
315{
316 wxCHECK_RET( item < m_checks.GetCount(),
317 _T("invalid index in wxCheckListBox::Check") );
318
319 // intermediate var is needed to avoid compiler warning with VC++
320 bool isChecked = m_checks[item] != 0;
321 if ( check != isChecked )
322 {
323 m_checks[item] = check;
324
325 MacRedrawControl() ;
326 }
327}
328
329// ----------------------------------------------------------------------------
330// methods forwarded to wxListBox
331// ----------------------------------------------------------------------------
332
333void wxCheckListBox::Delete(int n)
334{
335 wxCHECK_RET( n < GetCount(), _T("invalid index in wxListBox::Delete") );
e9576ca5 336
dbfc5b97 337 wxListBox::Delete(n);
e9576ca5 338
dbfc5b97
SC
339 m_checks.RemoveAt(n);
340}
341
342int wxCheckListBox::DoAppend(const wxString& item)
e9576ca5 343{
50b30d83 344 LSetDrawingMode( false , (ListHandle) m_macList ) ;
dbfc5b97
SC
345 int pos = wxListBox::DoAppend(item);
346
347 // the item is initially unchecked
348 m_checks.Insert(FALSE, pos);
50b30d83 349 LSetDrawingMode( true , (ListHandle) m_macList ) ;
dbfc5b97
SC
350
351 return pos;
e9576ca5
SC
352}
353
dbfc5b97 354void wxCheckListBox::DoInsertItems(const wxArrayString& items, int pos)
e9576ca5 355{
dbfc5b97
SC
356 wxListBox::DoInsertItems(items, pos);
357
358 size_t count = items.GetCount();
359 for ( size_t n = 0; n < count; n++ )
360 {
361 m_checks.Insert(FALSE, pos + n);
362 }
e9576ca5
SC
363}
364
dbfc5b97
SC
365void wxCheckListBox::DoSetItems(const wxArrayString& items, void **clientData)
366{
367 // call it first as it does DoClear()
368 wxListBox::DoSetItems(items, clientData);
369
370 size_t count = items.GetCount();
371 for ( size_t n = 0; n < count; n++ )
372 {
373 m_checks.Add(FALSE);
374 }
375}
e9576ca5 376
dbfc5b97 377void wxCheckListBox::DoClear()
e9576ca5 378{
dbfc5b97 379 m_checks.Empty();
e9576ca5
SC
380}
381
dbfc5b97
SC
382BEGIN_EVENT_TABLE(wxCheckListBox, wxListBox)
383 EVT_CHAR(wxCheckListBox::OnChar)
384 EVT_LEFT_DOWN(wxCheckListBox::OnLeftClick)
385END_EVENT_TABLE()
386
387// this will only work as soon as
388
389void wxCheckListBox::OnChar(wxKeyEvent& event)
e9576ca5 390{
e40298d5 391 if ( event.GetKeyCode() == WXK_SPACE )
dbfc5b97 392 {
e40298d5
JS
393 int index = GetSelection() ;
394 if ( index >= 0 )
395 {
396 Check(index, !IsChecked(index) ) ;
397 wxCommandEvent event(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, GetId());
398 event.SetInt(index);
399 event.SetEventObject(this);
400 GetEventHandler()->ProcessEvent(event);
401 }
dbfc5b97 402 }
e40298d5
JS
403 else
404 event.Skip();
e9576ca5
SC
405}
406
dbfc5b97
SC
407void wxCheckListBox::OnLeftClick(wxMouseEvent& event)
408{
e40298d5
JS
409 // clicking on the item selects it, clicking on the checkmark toggles
410 if ( event.GetX() <= 20 /*check width*/ ) {
411 int lineheight ;
412 int topcell ;
dbfc5b97 413#if TARGET_CARBON
e40298d5
JS
414 Point pt ;
415 GetListCellSize( (ListHandle)m_macList , &pt ) ;
416 lineheight = pt.v ;
417 ListBounds visible ;
418 GetListVisibleCells( (ListHandle)m_macList , &visible ) ;
419 topcell = visible.top ;
dbfc5b97 420#else
e40298d5
JS
421 lineheight = (**(ListHandle)m_macList).cellSize.v ;
422 topcell = (**(ListHandle)m_macList).visible.top ;
dbfc5b97 423#endif
e40298d5
JS
424 size_t nItem = ((size_t)event.GetY()) / lineheight + topcell ;
425
426 if ( nItem < (size_t)m_noItems )
427 {
428 Check(nItem, !IsChecked(nItem) ) ;
429 wxCommandEvent event(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, GetId());
430 event.SetInt(nItem);
431 event.SetEventObject(this);
432 GetEventHandler()->ProcessEvent(event);
433 }
434 //else: it's not an error, just click outside of client zone
435 }
436 else {
437 // implement default behaviour: clicking on the item selects it
438 event.Skip();
dbfc5b97 439 }
dbfc5b97 440}
e9576ca5 441
dbfc5b97 442#endif // wxUSE_CHECKLISTBOX