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