]>
Commit | Line | Data |
---|---|---|
e9576ca5 | 1 | /////////////////////////////////////////////////////////////////////////////// |
11e62fe6 | 2 | // Name: src/mac/carbon/listbox.cpp |
e9576ca5 | 3 | // Purpose: wxListBox |
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 |
65571936 | 9 | // Licence: wxWindows licence |
e9576ca5 SC |
10 | /////////////////////////////////////////////////////////////////////////////// |
11 | ||
3d1a4878 SC |
12 | #include "wx/wxprec.h" |
13 | ||
179e085f RN |
14 | #if wxUSE_LISTBOX |
15 | ||
03e11df5 | 16 | #include "wx/app.h" |
e9576ca5 | 17 | #include "wx/listbox.h" |
dc0ace7c | 18 | #include "wx/button.h" |
e9576ca5 | 19 | #include "wx/settings.h" |
422644a3 | 20 | #include "wx/toplevel.h" |
e9576ca5 SC |
21 | #include "wx/dynarray.h" |
22 | #include "wx/log.h" | |
23 | ||
519cb848 | 24 | #include "wx/utils.h" |
519cb848 | 25 | |
fdd4e6cc DS |
26 | #include "wx/mac/uma.h" |
27 | ||
28 | const short kTextColumnId = 1024 ; | |
29 | ||
30 | // new DataBrowser-based version: | |
31 | // because of the limited insert functionality of DataBrowser, | |
32 | // we just introduce IDs corresponding to the line number | |
33 | ||
34 | ||
e40298d5 | 35 | IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl) |
519cb848 SC |
36 | |
37 | BEGIN_EVENT_TABLE(wxListBox, wxControl) | |
684e0b31 | 38 | #ifndef __WXMAC_OSX__ |
393b27ad | 39 | // EVT_SIZE( wxListBox::OnSize ) |
e40298d5 | 40 | EVT_CHAR( wxListBox::OnChar ) |
facd6764 | 41 | #endif |
519cb848 | 42 | END_EVENT_TABLE() |
e9576ca5 | 43 | |
facd6764 | 44 | |
789ae0cf SC |
45 | DataBrowserItemDataUPP gDataBrowserItemDataUPP = NULL ; |
46 | DataBrowserItemNotificationUPP gDataBrowserItemNotificationUPP = NULL ; | |
47 | DataBrowserDrawItemUPP gDataBrowserDrawItemUPP = NULL ; | |
48 | ||
fdd4e6cc | 49 | |
83ce5634 | 50 | #if TARGET_API_MAC_OSX |
c6179a84 | 51 | static pascal void DataBrowserItemNotificationProc(ControlRef browser, DataBrowserItemID itemID, |
83ce5634 SC |
52 | DataBrowserItemNotification message, DataBrowserItemDataRef itemData) |
53 | #else | |
fdd4e6cc | 54 | static pascal void DataBrowserItemNotificationProc(ControlRef browser, DataBrowserItemID itemID, |
83ce5634 SC |
55 | DataBrowserItemNotification message) |
56 | #endif | |
57 | { | |
58 | long ref = GetControlReference( browser ) ; | |
59 | if ( ref ) | |
60 | { | |
469d8d5d | 61 | wxListBox* list = wxDynamicCast( (wxObject*) ref , wxListBox ) ; |
45285a62 | 62 | int i = itemID - 1 ; |
8e0f22c0 SC |
63 | if (i >= 0 && i < list->GetCount() ) |
64 | { | |
65 | bool trigger = false ; | |
fdd4e6cc DS |
66 | wxCommandEvent event( wxEVT_COMMAND_LISTBOX_SELECTED, list->GetId() ); |
67 | switch ( message ) | |
83ce5634 | 68 | { |
8e0f22c0 SC |
69 | case kDataBrowserItemDeselected : |
70 | if ( list->HasMultipleSelection() ) | |
fe3dc505 | 71 | trigger = !list->MacIsSelectionSuppressed() ; |
8e0f22c0 | 72 | break ; |
fdd4e6cc | 73 | |
8e0f22c0 | 74 | case kDataBrowserItemSelected : |
fe3dc505 | 75 | trigger = !list->MacIsSelectionSuppressed() ; |
8e0f22c0 | 76 | break ; |
fdd4e6cc | 77 | |
8e0f22c0 | 78 | case kDataBrowserItemDoubleClicked : |
fdd4e6cc | 79 | event.SetEventType( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED ) ; |
8e0f22c0 SC |
80 | trigger = true ; |
81 | break ; | |
fdd4e6cc | 82 | |
8e0f22c0 SC |
83 | default : |
84 | break ; | |
83ce5634 | 85 | } |
fdd4e6cc | 86 | |
8e0f22c0 SC |
87 | if ( trigger ) |
88 | { | |
89 | event.SetEventObject( list ); | |
90 | if ( list->HasClientObjectData() ) | |
fdd4e6cc | 91 | event.SetClientObject( list->GetClientObject( i ) ); |
8e0f22c0 | 92 | else if ( list->HasClientUntypedData() ) |
fdd4e6cc DS |
93 | event.SetClientData( list->GetClientData( i ) ); |
94 | event.SetString( list->GetString( i ) ); | |
95 | event.SetInt( i ) ; | |
96 | event.SetExtraLong( list->HasMultipleSelection() ? message == kDataBrowserItemSelected : true ); | |
8e0f22c0 SC |
97 | wxPostEvent( list->GetEventHandler() , event ) ; |
98 | // direct notification is not always having the listbox GetSelection() having in synch with event | |
c6179a84 VZ |
99 | // list->GetEventHandler()->ProcessEvent(event) ; |
100 | } | |
8e0f22c0 | 101 | } |
83ce5634 SC |
102 | } |
103 | } | |
104 | ||
c6179a84 VZ |
105 | static pascal OSStatus ListBoxGetSetItemData(ControlRef browser, |
106 | DataBrowserItemID itemID, DataBrowserPropertyID property, | |
facd6764 SC |
107 | DataBrowserItemDataRef itemData, Boolean changeValue) |
108 | { | |
de1b0aeb VZ |
109 | OSStatus err = errDataBrowserPropertyNotSupported; |
110 | ||
111 | if ( ! changeValue ) | |
112 | { | |
113 | switch (property) | |
114 | { | |
de1b0aeb VZ |
115 | case kTextColumnId: |
116 | { | |
117 | long ref = GetControlReference( browser ) ; | |
118 | if ( ref ) | |
119 | { | |
120 | wxListBox* list = wxDynamicCast( (wxObject*) ref , wxListBox ) ; | |
45285a62 | 121 | int i = itemID - 1 ; |
8e0f22c0 | 122 | if (i >= 0 && i < list->GetCount() ) |
de1b0aeb | 123 | { |
fdd4e6cc | 124 | wxMacCFStringHolder cf( list->GetString( i ) , list->GetFont().GetEncoding() ) ; |
de1b0aeb VZ |
125 | verify_noerr( ::SetDataBrowserItemDataText( itemData , cf ) ) ; |
126 | err = noErr ; | |
127 | } | |
128 | } | |
129 | } | |
fdd4e6cc | 130 | break; |
c6179a84 | 131 | |
de1b0aeb | 132 | default: |
fdd4e6cc | 133 | break; |
de1b0aeb VZ |
134 | } |
135 | } | |
c6179a84 | 136 | |
de1b0aeb | 137 | return err; |
facd6764 | 138 | } |
fe3dc505 | 139 | |
789ae0cf SC |
140 | static pascal void ListBoxDrawProc( ControlRef browser , DataBrowserItemID item , DataBrowserPropertyID property , |
141 | DataBrowserItemState itemState , const Rect *itemRect , SInt16 depth , Boolean isColorDevice ) | |
142 | { | |
789ae0cf | 143 | CFStringRef cfString; |
fdd4e6cc | 144 | ThemeDrawingState themeState ; |
789ae0cf SC |
145 | long systemVersion; |
146 | ||
789ae0cf | 147 | GetThemeDrawingState( &themeState ) ; |
fdd4e6cc | 148 | cfString = CFStringCreateWithFormat( NULL, NULL, CFSTR("Row %d"), item ); |
de1b0aeb | 149 | |
fdd4e6cc DS |
150 | // In this sample we handle the "selected" state; all others fall through to our "active" state |
151 | if ( itemState == kDataBrowserItemIsSelected ) | |
789ae0cf | 152 | { |
fdd4e6cc DS |
153 | ThemeBrush colorBrushID; |
154 | ||
789ae0cf | 155 | Gestalt( gestaltSystemVersion, &systemVersion ); |
fdd4e6cc DS |
156 | |
157 | // TODO: switch over to wxSystemSettingsNative::GetColour() when kThemeBrushSecondaryHighlightColor is incorporated | |
158 | // Panther DB starts using kThemeBrushSecondaryHighlightColor for inactive browser hilighting | |
159 | if ( (systemVersion >= 0x00001030) && !IsControlActive( browser ) ) | |
160 | colorBrushID = kThemeBrushSecondaryHighlightColor; | |
789ae0cf | 161 | else |
fdd4e6cc | 162 | colorBrushID = kThemeBrushPrimaryHighlightColor; |
789ae0cf | 163 | |
fdd4e6cc DS |
164 | // First paint the hilite rect, then the text on top |
165 | SetThemePen( colorBrushID, 32, true ); | |
166 | PaintRect( itemRect ); | |
789ae0cf SC |
167 | SetThemeDrawingState( themeState , false ) ; |
168 | } | |
fdd4e6cc | 169 | |
789ae0cf | 170 | DrawThemeTextBox( cfString, kThemeApplicationFont, kThemeStateActive, true, itemRect, teFlushDefault, NULL ); |
fdd4e6cc DS |
171 | SetThemeDrawingState( themeState , true ) ; |
172 | ||
de1b0aeb | 173 | if ( cfString != NULL ) |
789ae0cf | 174 | CFRelease( cfString ); |
789ae0cf | 175 | } |
fe3dc505 SC |
176 | |
177 | // Listbox item | |
178 | wxListBox::wxListBox() | |
179 | { | |
fdd4e6cc DS |
180 | m_noItems = 0; |
181 | m_selected = 0; | |
182 | m_macList = NULL ; | |
183 | m_suppressSelection = false ; | |
fe3dc505 SC |
184 | } |
185 | ||
fdd4e6cc DS |
186 | bool wxListBox::Create(wxWindow *parent, |
187 | wxWindowID id, | |
188 | const wxPoint& pos, | |
189 | const wxSize& size, | |
190 | const wxArrayString& choices, | |
191 | long style, | |
192 | const wxValidator& validator, | |
193 | const wxString& name) | |
fe3dc505 SC |
194 | { |
195 | wxCArrayString chs(choices); | |
196 | ||
197 | return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(), | |
198 | style, validator, name); | |
199 | } | |
200 | ||
fdd4e6cc DS |
201 | bool wxListBox::Create(wxWindow *parent, |
202 | wxWindowID id, | |
203 | const wxPoint& pos, | |
204 | const wxSize& size, | |
205 | int n, | |
206 | const wxString choices[], | |
207 | long style, | |
208 | const wxValidator& validator, | |
209 | const wxString& name) | |
facd6764 | 210 | { |
fdd4e6cc | 211 | m_macIsUserPane = false ; |
5e6f42cd SC |
212 | |
213 | wxASSERT_MSG( !(style & wxLB_MULTIPLE) || !(style & wxLB_EXTENDED), | |
214 | _T("only one of listbox selection modes can be specified") ); | |
c6179a84 | 215 | |
facd6764 SC |
216 | if ( !wxListBoxBase::Create(parent, id, pos, size, style & ~(wxHSCROLL|wxVSCROLL), validator, name) ) |
217 | return false; | |
218 | ||
219 | m_noItems = 0 ; // this will be increased by our append command | |
220 | m_selected = 0; | |
facd6764 SC |
221 | |
222 | Rect bounds = wxMacGetBoundsForControl( this , pos , size ) ; | |
facd6764 | 223 | |
fdd4e6cc DS |
224 | m_peer = new wxMacControl( this ) ; |
225 | verify_noerr( | |
226 | ::CreateDataBrowserControl( | |
227 | MAC_WXHWND(parent->MacGetTopLevelWindowRef()), &bounds, | |
228 | kDataBrowserListView, m_peer->GetControlRefAddr() ) ); | |
facd6764 SC |
229 | |
230 | DataBrowserSelectionFlags options = kDataBrowserDragSelect ; | |
231 | if ( style & wxLB_MULTIPLE ) | |
fdd4e6cc | 232 | options |= kDataBrowserAlwaysExtendSelection | kDataBrowserCmdTogglesSelection ; |
facd6764 | 233 | else if ( style & wxLB_EXTENDED ) |
fdd4e6cc | 234 | ; // default behaviour |
facd6764 | 235 | else |
fdd4e6cc DS |
236 | options |= kDataBrowserSelectOnlyOne ; |
237 | ||
238 | verify_noerr( m_peer->SetSelectionFlags( options ) ); | |
de1b0aeb | 239 | |
fdd4e6cc DS |
240 | if ( gDataBrowserItemDataUPP == NULL ) |
241 | gDataBrowserItemDataUPP = NewDataBrowserItemDataUPP(ListBoxGetSetItemData) ; | |
789ae0cf | 242 | if ( gDataBrowserItemNotificationUPP == NULL ) |
de1b0aeb VZ |
243 | { |
244 | gDataBrowserItemNotificationUPP = | |
789ae0cf | 245 | #if TARGET_API_MAC_OSX |
de1b0aeb | 246 | (DataBrowserItemNotificationUPP) NewDataBrowserItemNotificationWithItemUPP(DataBrowserItemNotificationProc) ; |
789ae0cf | 247 | #else |
de1b0aeb | 248 | NewDataBrowserItemNotificationUPP(DataBrowserItemNotificationProc) ; |
789ae0cf | 249 | #endif |
de1b0aeb | 250 | } |
fdd4e6cc DS |
251 | |
252 | if ( gDataBrowserDrawItemUPP == NULL ) | |
253 | gDataBrowserDrawItemUPP = NewDataBrowserDrawItemUPP(ListBoxDrawProc) ; | |
789ae0cf SC |
254 | |
255 | DataBrowserCallbacks callbacks ; | |
256 | InitializeDataBrowserCallbacks( &callbacks , kDataBrowserLatestCallbacks ) ; | |
facd6764 | 257 | |
789ae0cf | 258 | callbacks.u.v1.itemDataCallback = gDataBrowserItemDataUPP; |
de1b0aeb | 259 | callbacks.u.v1.itemNotificationCallback = gDataBrowserItemNotificationUPP; |
789ae0cf SC |
260 | m_peer->SetCallbacks( &callbacks); |
261 | ||
262 | DataBrowserCustomCallbacks customCallbacks ; | |
de1b0aeb VZ |
263 | InitializeDataBrowserCustomCallbacks( &customCallbacks , kDataBrowserLatestCustomCallbacks ) ; |
264 | ||
789ae0cf | 265 | customCallbacks.u.v1.drawItemCallback = gDataBrowserDrawItemUPP ; |
de1b0aeb VZ |
266 | |
267 | SetDataBrowserCustomCallbacks( m_peer->GetControlRef() , &customCallbacks ) ; | |
268 | ||
facd6764 SC |
269 | DataBrowserListViewColumnDesc columnDesc ; |
270 | columnDesc.headerBtnDesc.titleOffset = 0; | |
de1b0aeb | 271 | columnDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc; |
fdd4e6cc | 272 | columnDesc.headerBtnDesc.btnFontStyle.flags = kControlUseFontMask | kControlUseJustMask; |
de1b0aeb VZ |
273 | columnDesc.headerBtnDesc.btnContentInfo.contentType = kControlNoContent; |
274 | columnDesc.headerBtnDesc.btnFontStyle.just = teFlushDefault; | |
275 | columnDesc.headerBtnDesc.minimumWidth = 0; | |
276 | columnDesc.headerBtnDesc.maximumWidth = 10000; | |
c6179a84 | 277 | |
de1b0aeb VZ |
278 | columnDesc.headerBtnDesc.btnFontStyle.font = kControlFontViewSystemFont; |
279 | columnDesc.headerBtnDesc.btnFontStyle.style = normal; | |
280 | columnDesc.headerBtnDesc.titleString = NULL ; // CFSTR( "" ); | |
facd6764 | 281 | |
de1b0aeb VZ |
282 | columnDesc.propertyDesc.propertyID = kTextColumnId; |
283 | columnDesc.propertyDesc.propertyType = kDataBrowserTextType ; // kDataBrowserCustomType; | |
fdd4e6cc DS |
284 | columnDesc.propertyDesc.propertyFlags = kDataBrowserTableViewSelectionColumn; |
285 | ||
9bd2d050 | 286 | #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2 |
fdd4e6cc | 287 | columnDesc.propertyDesc.propertyFlags |= kDataBrowserListViewTypeSelectColumn; |
c2697b87 | 288 | #endif |
facd6764 | 289 | |
fdd4e6cc DS |
290 | verify_noerr( m_peer->AddListViewColumn( &columnDesc, kDataBrowserListViewAppendColumn ) ) ; |
291 | verify_noerr( m_peer->AutoSizeListViewColumns() ) ; | |
292 | verify_noerr( m_peer->SetHasScrollBars( false, true ) ) ; | |
293 | verify_noerr( m_peer->SetTableViewHiliteStyle( kDataBrowserTableViewFillHilite ) ) ; | |
294 | verify_noerr( m_peer->SetListViewHeaderBtnHeight( 0 ) ) ; | |
c6179a84 | 295 | |
789ae0cf SC |
296 | #if 0 |
297 | // shouldn't be necessary anymore under 10.2 | |
298 | m_peer->SetData( kControlNoPart, kControlDataBrowserIncludesFrameAndFocusTag, (Boolean) false ) ; | |
299 | m_peer->SetNeedsFocusRect( true ) ; | |
83ce5634 | 300 | #endif |
facd6764 | 301 | |
fdd4e6cc | 302 | MacPostControlCreate( pos, size ) ; |
facd6764 SC |
303 | |
304 | for ( int i = 0 ; i < n ; i++ ) | |
305 | { | |
306 | Append( choices[i] ) ; | |
307 | } | |
308 | ||
fdd4e6cc DS |
309 | // Needed because it is a wxControlWithItems |
310 | SetBestSize(size); | |
c6179a84 | 311 | |
fdd4e6cc | 312 | return true; |
facd6764 SC |
313 | } |
314 | ||
315 | wxListBox::~wxListBox() | |
316 | { | |
77eddfb7 | 317 | m_peer->SetReference( 0 ) ; |
facd6764 | 318 | FreeData() ; |
fdd4e6cc | 319 | |
facd6764 SC |
320 | // avoid access during destruction |
321 | if ( m_macList ) | |
facd6764 | 322 | m_macList = NULL ; |
facd6764 SC |
323 | } |
324 | ||
325 | void wxListBox::FreeData() | |
326 | { | |
facd6764 SC |
327 | if ( HasClientObjectData() ) |
328 | { | |
329 | for ( size_t n = 0; n < (size_t)m_noItems; n++ ) | |
330 | { | |
fdd4e6cc | 331 | delete GetClientObject( n ); |
facd6764 SC |
332 | } |
333 | } | |
334 | } | |
335 | ||
336 | void wxListBox::DoSetSize(int x, int y, | |
337 | int width, int height, | |
338 | int sizeFlags ) | |
339 | { | |
340 | wxControl::DoSetSize( x , y , width , height , sizeFlags ) ; | |
341 | } | |
342 | ||
fdd4e6cc | 343 | void wxListBox::DoSetFirstItem(int n) |
facd6764 | 344 | { |
fdd4e6cc | 345 | MacScrollTo( n ) ; |
facd6764 SC |
346 | } |
347 | ||
fdd4e6cc | 348 | void wxListBox::Delete(int n) |
facd6764 | 349 | { |
fdd4e6cc | 350 | wxCHECK_RET( n >= 0 && n < m_noItems, |
facd6764 SC |
351 | wxT("invalid index in wxListBox::Delete") ); |
352 | ||
facd6764 | 353 | if ( HasClientObjectData() ) |
fdd4e6cc DS |
354 | delete GetClientObject( n ); |
355 | ||
356 | m_stringArray.RemoveAt( n ) ; | |
357 | m_dataArray.RemoveAt( n ) ; | |
358 | m_noItems--; | |
facd6764 | 359 | |
fdd4e6cc | 360 | MacDelete( n ) ; |
facd6764 SC |
361 | } |
362 | ||
363 | int wxListBox::DoAppend(const wxString& item) | |
364 | { | |
9f884528 RD |
365 | InvalidateBestSize(); |
366 | ||
facd6764 SC |
367 | int index = m_noItems ; |
368 | m_stringArray.Add( item ) ; | |
369 | m_dataArray.Add( NULL ); | |
fdd4e6cc | 370 | m_noItems++; |
facd6764 SC |
371 | DoSetItemClientData( index , NULL ) ; |
372 | MacAppend( item ) ; | |
373 | ||
374 | return index ; | |
375 | } | |
376 | ||
377 | void wxListBox::DoSetItems(const wxArrayString& choices, void** clientData) | |
378 | { | |
379 | Clear() ; | |
380 | int n = choices.GetCount(); | |
c6179a84 | 381 | |
fdd4e6cc | 382 | for ( int i = 0 ; i < n ; ++i ) |
facd6764 SC |
383 | { |
384 | if ( clientData ) | |
facd6764 | 385 | Append( choices[i] , clientData[i] ) ; |
facd6764 SC |
386 | else |
387 | Append( choices[i] ) ; | |
388 | } | |
facd6764 SC |
389 | } |
390 | ||
11e62fe6 | 391 | int wxListBox::FindString(const wxString& s, bool bCase) const |
facd6764 | 392 | { |
facd6764 SC |
393 | if ( s.Right(1) == wxT("*") ) |
394 | { | |
395 | wxString search = s.Left( s.Length() - 1 ) ; | |
396 | int len = search.Length() ; | |
397 | Str255 s1 , s2 ; | |
398 | wxMacStringToPascal( search , s2 ) ; | |
c6179a84 | 399 | |
facd6764 SC |
400 | for ( int i = 0 ; i < m_noItems ; ++ i ) |
401 | { | |
de1b0aeb | 402 | wxMacStringToPascal( m_stringArray[i].Left( len ) , s1 ) ; |
facd6764 | 403 | |
11e62fe6 | 404 | if ( EqualString( s1 , s2 , bCase , false ) ) |
facd6764 SC |
405 | return i ; |
406 | } | |
fdd4e6cc | 407 | |
facd6764 SC |
408 | if ( s.Left(1) == wxT("*") && s.Length() > 1 ) |
409 | { | |
410 | wxString st = s ; | |
411 | st.MakeLower() ; | |
fdd4e6cc | 412 | |
facd6764 SC |
413 | for ( int i = 0 ; i < m_noItems ; ++i ) |
414 | { | |
fdd4e6cc | 415 | if ( GetString( i ).Lower().Matches(st) ) |
facd6764 SC |
416 | return i ; |
417 | } | |
418 | } | |
facd6764 SC |
419 | } |
420 | else | |
421 | { | |
422 | Str255 s1 , s2 ; | |
c6179a84 | 423 | |
facd6764 | 424 | wxMacStringToPascal( s , s2 ) ; |
c6179a84 | 425 | |
facd6764 SC |
426 | for ( int i = 0 ; i < m_noItems ; ++ i ) |
427 | { | |
de1b0aeb | 428 | wxMacStringToPascal( m_stringArray[i] , s1 ) ; |
facd6764 | 429 | |
11e62fe6 | 430 | if ( EqualString( s1 , s2 , bCase , false ) ) |
facd6764 SC |
431 | return i ; |
432 | } | |
433 | } | |
fdd4e6cc | 434 | |
11e62fe6 | 435 | return wxNOT_FOUND; |
facd6764 SC |
436 | } |
437 | ||
438 | void wxListBox::Clear() | |
439 | { | |
440 | FreeData(); | |
441 | m_noItems = 0; | |
442 | m_stringArray.Empty() ; | |
443 | m_dataArray.Empty() ; | |
444 | MacClear() ; | |
445 | } | |
446 | ||
fdd4e6cc | 447 | void wxListBox::DoSetSelection(int n, bool select) |
facd6764 | 448 | { |
fdd4e6cc | 449 | wxCHECK_RET( n == wxNOT_FOUND || (n >= 0 && n < m_noItems) , |
facd6764 | 450 | wxT("invalid index in wxListBox::SetSelection") ); |
c6179a84 | 451 | |
fdd4e6cc | 452 | if ( n == wxNOT_FOUND ) |
fe3dc505 SC |
453 | MacDeselectAll() ; |
454 | else | |
fdd4e6cc | 455 | MacSetSelection( n , select ) ; |
facd6764 SC |
456 | } |
457 | ||
fdd4e6cc | 458 | bool wxListBox::IsSelected(int n) const |
facd6764 | 459 | { |
fdd4e6cc | 460 | wxCHECK_MSG( n >= 0 && n < m_noItems, false, |
facd6764 | 461 | wxT("invalid index in wxListBox::Selected") ); |
c6179a84 | 462 | |
fdd4e6cc | 463 | return MacIsSelected( n ) ; |
facd6764 SC |
464 | } |
465 | ||
fdd4e6cc | 466 | void *wxListBox::DoGetItemClientData(int n) const |
facd6764 | 467 | { |
fdd4e6cc | 468 | wxCHECK_MSG( n >= 0 && n < m_noItems, NULL, |
facd6764 | 469 | wxT("invalid index in wxListBox::GetClientData")); |
c6179a84 | 470 | |
fdd4e6cc | 471 | return (void *)m_dataArray[n]; |
facd6764 SC |
472 | } |
473 | ||
fdd4e6cc | 474 | wxClientData *wxListBox::DoGetItemClientObject(int n) const |
facd6764 | 475 | { |
fdd4e6cc | 476 | return (wxClientData *) DoGetItemClientData( n ) ; |
facd6764 SC |
477 | } |
478 | ||
fdd4e6cc | 479 | void wxListBox::DoSetItemClientData(int n, void *clientData) |
facd6764 | 480 | { |
fdd4e6cc | 481 | wxCHECK_RET( n >= 0 && n < m_noItems, |
facd6764 | 482 | wxT("invalid index in wxListBox::SetClientData") ); |
c6179a84 | 483 | |
fdd4e6cc | 484 | wxASSERT_MSG( m_dataArray.GetCount() >= (size_t) n , wxT("invalid client_data array") ) ; |
c6179a84 | 485 | |
fdd4e6cc DS |
486 | if ( m_dataArray.GetCount() > (size_t) n ) |
487 | m_dataArray[n] = (char*)clientData ; | |
facd6764 | 488 | else |
fdd4e6cc | 489 | m_dataArray.Add( (char*)clientData ) ; |
facd6764 SC |
490 | } |
491 | ||
492 | void wxListBox::DoSetItemClientObject(int n, wxClientData* clientData) | |
493 | { | |
494 | DoSetItemClientData(n, clientData); | |
495 | } | |
496 | ||
497 | // Return number of selections and an array of selected integers | |
498 | int wxListBox::GetSelections(wxArrayInt& aSelections) const | |
499 | { | |
500 | return MacGetSelections( aSelections ) ; | |
501 | } | |
502 | ||
503 | // Get single selection, for single choice list items | |
504 | int wxListBox::GetSelection() const | |
505 | { | |
506 | return MacGetSelection() ; | |
507 | } | |
508 | ||
509 | // Find string for position | |
fdd4e6cc | 510 | wxString wxListBox::GetString(int n) const |
facd6764 | 511 | { |
fdd4e6cc | 512 | wxCHECK_MSG( n >= 0 && n < m_noItems, wxEmptyString, |
55ae2833 RD |
513 | wxT("invalid index in wxListBox::GetString") ); |
514 | ||
fdd4e6cc | 515 | return m_stringArray[n] ; |
facd6764 SC |
516 | } |
517 | ||
518 | void wxListBox::DoInsertItems(const wxArrayString& items, int pos) | |
519 | { | |
520 | wxCHECK_RET( pos >= 0 && pos <= m_noItems, | |
521 | wxT("invalid index in wxListBox::InsertItems") ); | |
c6179a84 | 522 | |
9f884528 RD |
523 | InvalidateBestSize(); |
524 | ||
facd6764 | 525 | int nItems = items.GetCount(); |
c6179a84 | 526 | |
facd6764 SC |
527 | for ( int i = 0 ; i < nItems ; i++ ) |
528 | { | |
529 | m_stringArray.Insert( items[i] , pos + i ) ; | |
530 | m_dataArray.Insert( NULL , pos + i ) ; | |
8e0f22c0 | 531 | m_noItems++ ; |
facd6764 SC |
532 | MacInsert( pos + i , items[i] ) ; |
533 | } | |
facd6764 SC |
534 | } |
535 | ||
fdd4e6cc | 536 | void wxListBox::SetString(int n, const wxString& s) |
facd6764 | 537 | { |
fdd4e6cc DS |
538 | m_stringArray[n] = s ; |
539 | MacSet( n , s ) ; | |
facd6764 SC |
540 | } |
541 | ||
542 | wxSize wxListBox::DoGetBestSize() const | |
543 | { | |
544 | int lbWidth = 100; // some defaults | |
545 | int lbHeight = 110; | |
546 | int wLine; | |
547 | ||
548 | { | |
fdd4e6cc | 549 | wxMacPortStateHelper st( UMAGetWindowPort( (WindowRef)MacGetTopLevelWindowRef() ) ) ; |
c6179a84 | 550 | |
fdd4e6cc | 551 | // TODO: clean this up |
facd6764 SC |
552 | if ( m_font.Ok() ) |
553 | { | |
554 | ::TextFont( m_font.MacGetFontNum() ) ; | |
555 | ::TextSize( m_font.MacGetFontSize() ) ; | |
556 | ::TextFace( m_font.MacGetFontStyle() ) ; | |
557 | } | |
558 | else | |
559 | { | |
560 | ::TextFont( kFontIDMonaco ) ; | |
561 | ::TextSize( 9 ); | |
562 | ::TextFace( 0 ) ; | |
563 | } | |
c6179a84 | 564 | |
facd6764 | 565 | // Find the widest line |
fdd4e6cc DS |
566 | for (int i = 0; i < GetCount(); i++) |
567 | { | |
568 | wxString str( GetString( i ) ); | |
569 | ||
570 | #if wxUSE_UNICODE | |
571 | Point bounds = {0, 0} ; | |
facd6764 | 572 | SInt16 baseline ; |
fdd4e6cc DS |
573 | |
574 | // NB: what if m_font.Ok() == false ??? | |
575 | ::GetThemeTextDimensions( | |
576 | wxMacCFStringHolder( str , m_font.GetEncoding() ) , | |
facd6764 SC |
577 | kThemeCurrentPortFont, |
578 | kThemeStateActive, | |
579 | false, | |
580 | &bounds, | |
581 | &baseline ); | |
582 | wLine = bounds.h ; | |
fdd4e6cc | 583 | #else |
facd6764 | 584 | wLine = ::TextWidth( str.c_str() , 0 , str.Length() ) ; |
fdd4e6cc DS |
585 | #endif |
586 | ||
587 | lbWidth = wxMax( lbWidth, wLine ); | |
facd6764 | 588 | } |
c6179a84 | 589 | |
facd6764 SC |
590 | // Add room for the scrollbar |
591 | lbWidth += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); | |
c6179a84 | 592 | |
facd6764 SC |
593 | // And just a bit more |
594 | int cy = 12 ; | |
595 | int cx = ::TextWidth( "X" , 0 , 1 ) ; | |
596 | lbWidth += cx ; | |
c6179a84 | 597 | |
fdd4e6cc DS |
598 | // don't make the listbox too tall (limit height to around 10 items) |
599 | // but don't make it too small neither | |
9761ab43 | 600 | lbHeight = wxMax( (cy + 4) * wxMin( wxMax( GetCount(), 3 ), 10 ), 70 ); |
facd6764 SC |
601 | } |
602 | ||
fdd4e6cc | 603 | return wxSize( lbWidth, lbHeight ); |
facd6764 SC |
604 | } |
605 | ||
606 | int wxListBox::GetCount() const | |
607 | { | |
608 | return m_noItems; | |
609 | } | |
610 | ||
611 | void wxListBox::Refresh(bool eraseBack, const wxRect *rect) | |
612 | { | |
613 | wxControl::Refresh( eraseBack , rect ) ; | |
facd6764 SC |
614 | } |
615 | ||
b6a20a20 RD |
616 | // Some custom controls depend on this |
617 | /* static */ wxVisualAttributes | |
618 | wxListBox::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) | |
619 | { | |
620 | wxVisualAttributes attr; | |
fdd4e6cc DS |
621 | |
622 | attr.colFg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ); | |
623 | attr.colBg = wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX ); | |
624 | attr.font = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ); | |
625 | ||
b6a20a20 RD |
626 | return attr; |
627 | } | |
628 | ||
facd6764 SC |
629 | // ============================================================================ |
630 | // list box control implementation | |
631 | // ============================================================================ | |
632 | ||
fe3dc505 | 633 | void wxListBox::MacDelete( int n ) |
facd6764 | 634 | { |
fe3dc505 SC |
635 | wxArrayInt selectionBefore ; |
636 | MacGetSelections( selectionBefore ) ; | |
637 | ||
fdd4e6cc DS |
638 | UInt32 id = m_noItems + 1 ; |
639 | ||
5ca0d812 | 640 | verify_noerr( m_peer->RemoveItems( kDataBrowserNoItem , 1 , (UInt32*) &id , kDataBrowserItemNoProperty ) ) ; |
0b9cd93c | 641 | for ( size_t i = 0 ; i < selectionBefore.GetCount() ; ++i ) |
fe3dc505 SC |
642 | { |
643 | int current = selectionBefore[i] ; | |
644 | if ( current == n ) | |
645 | { | |
646 | // selection was deleted | |
647 | MacSetSelection( current , false ) ; | |
648 | } | |
649 | else if ( current > n ) | |
650 | { | |
651 | // something behind the deleted item was selected -> move up | |
c6179a84 | 652 | MacSetSelection( current - 1 , true ) ; |
fe3dc505 SC |
653 | MacSetSelection( current , false ) ; |
654 | } | |
655 | } | |
fdd4e6cc | 656 | |
fe3dc505 | 657 | // refresh all |
fdd4e6cc DS |
658 | verify_noerr( |
659 | m_peer->UpdateItems( | |
660 | kDataBrowserNoItem, 1, (UInt32*)kDataBrowserNoItem, | |
661 | kDataBrowserItemNoProperty, kDataBrowserItemNoProperty ) ) ; | |
facd6764 SC |
662 | } |
663 | ||
fdd4e6cc | 664 | void wxListBox::MacInsert( int n , const wxString& text ) |
facd6764 | 665 | { |
fe3dc505 SC |
666 | wxArrayInt selectionBefore ; |
667 | MacGetSelections( selectionBefore ) ; | |
668 | ||
fdd4e6cc DS |
669 | // this has already been increased |
670 | UInt32 id = m_noItems ; | |
671 | verify_noerr( m_peer->AddItems( kDataBrowserNoItem , 1 , (UInt32*) &id , kDataBrowserItemNoProperty ) ) ; | |
fe3dc505 SC |
672 | |
673 | for ( int i = selectionBefore.GetCount()-1 ; i >= 0 ; --i ) | |
674 | { | |
675 | int current = selectionBefore[i] ; | |
676 | if ( current >= n ) | |
677 | { | |
c6179a84 | 678 | MacSetSelection( current + 1 , true ) ; |
fe3dc505 SC |
679 | MacSetSelection( current , false ) ; |
680 | } | |
681 | } | |
682 | ||
683 | // refresh all | |
fdd4e6cc DS |
684 | verify_noerr( |
685 | m_peer->UpdateItems( | |
686 | kDataBrowserNoItem, 1, (UInt32*)kDataBrowserNoItem, | |
687 | kDataBrowserItemNoProperty, kDataBrowserItemNoProperty ) ) ; | |
facd6764 SC |
688 | } |
689 | ||
fdd4e6cc | 690 | void wxListBox::MacAppend( const wxString& text ) |
facd6764 | 691 | { |
8e0f22c0 | 692 | UInt32 id = m_noItems ; // this has already been increased |
fdd4e6cc | 693 | verify_noerr( m_peer->AddItems( kDataBrowserNoItem , 1 , (UInt32*) &id , kDataBrowserItemNoProperty ) ) ; |
fe3dc505 | 694 | // no need to deal with selections nor refreshed, as we have appended |
facd6764 SC |
695 | } |
696 | ||
697 | void wxListBox::MacClear() | |
698 | { | |
5ca0d812 | 699 | verify_noerr( m_peer->RemoveItems( kDataBrowserNoItem , 0 , NULL , kDataBrowserItemNoProperty ) ) ; |
facd6764 SC |
700 | } |
701 | ||
c6179a84 | 702 | void wxListBox::MacDeselectAll() |
fe3dc505 SC |
703 | { |
704 | bool former = MacSuppressSelection( true ) ; | |
705 | verify_noerr(m_peer->SetSelectedItems( 0 , NULL , kDataBrowserItemsRemove ) ) ; | |
706 | MacSuppressSelection( former ) ; | |
707 | } | |
708 | ||
facd6764 SC |
709 | void wxListBox::MacSetSelection( int n , bool select ) |
710 | { | |
fe3dc505 | 711 | bool former = MacSuppressSelection( true ) ; |
8e0f22c0 | 712 | UInt32 id = n + 1 ; |
fe3dc505 | 713 | |
5ca0d812 | 714 | if ( m_peer->IsItemSelected( id ) != select ) |
facd6764 | 715 | { |
fe3dc505 | 716 | if ( select ) |
fdd4e6cc | 717 | verify_noerr( m_peer->SetSelectedItems( 1 , & id , HasMultipleSelection() ? kDataBrowserItemsAdd : kDataBrowserItemsAssign ) ) ; |
fe3dc505 | 718 | else |
fdd4e6cc | 719 | verify_noerr( m_peer->SetSelectedItems( 1 , & id , kDataBrowserItemsRemove ) ) ; |
facd6764 | 720 | } |
fdd4e6cc | 721 | |
facd6764 | 722 | MacScrollTo( n ) ; |
fe3dc505 SC |
723 | MacSuppressSelection( former ) ; |
724 | } | |
725 | ||
fdd4e6cc | 726 | bool wxListBox::MacSuppressSelection( bool suppress ) |
fe3dc505 | 727 | { |
de1b0aeb VZ |
728 | bool former = m_suppressSelection ; |
729 | m_suppressSelection = suppress ; | |
730 | return former ; | |
facd6764 SC |
731 | } |
732 | ||
733 | bool wxListBox::MacIsSelected( int n ) const | |
734 | { | |
8e0f22c0 | 735 | return m_peer->IsItemSelected( n + 1 ) ; |
facd6764 SC |
736 | } |
737 | ||
738 | int wxListBox::MacGetSelection() const | |
739 | { | |
45285a62 | 740 | for ( int i = 0 ; i < GetCount() ; ++i ) |
facd6764 | 741 | { |
8e0f22c0 | 742 | if ( m_peer->IsItemSelected( i + 1 ) ) |
facd6764 | 743 | return i ; |
facd6764 | 744 | } |
fdd4e6cc | 745 | |
fe3dc505 | 746 | return -1 ; |
facd6764 SC |
747 | } |
748 | ||
749 | int wxListBox::MacGetSelections( wxArrayInt& aSelections ) const | |
750 | { | |
751 | int no_sel = 0 ; | |
c6179a84 | 752 | |
facd6764 | 753 | aSelections.Empty(); |
c6179a84 | 754 | |
fe3dc505 SC |
755 | UInt32 first , last ; |
756 | m_peer->GetSelectionAnchor( &first , &last ) ; | |
757 | if ( first != kDataBrowserNoItem ) | |
facd6764 | 758 | { |
0b9cd93c | 759 | for ( size_t i = first ; i <= last ; ++i ) |
facd6764 | 760 | { |
fe3dc505 SC |
761 | if ( m_peer->IsItemSelected( i ) ) |
762 | { | |
763 | aSelections.Add( i - 1 ) ; | |
764 | no_sel++ ; | |
765 | } | |
facd6764 SC |
766 | } |
767 | } | |
fdd4e6cc | 768 | |
facd6764 SC |
769 | return no_sel ; |
770 | } | |
519cb848 | 771 | |
facd6764 SC |
772 | void wxListBox::MacSet( int n , const wxString& text ) |
773 | { | |
774 | // as we don't store the strings we only have to issue a redraw | |
8e0f22c0 | 775 | UInt32 id = n + 1 ; |
5ca0d812 | 776 | verify_noerr( m_peer->UpdateItems( kDataBrowserNoItem , 1 , &id , kDataBrowserItemNoProperty , kDataBrowserItemNoProperty ) ) ; |
facd6764 | 777 | } |
e42e45a9 | 778 | |
facd6764 SC |
779 | void wxListBox::MacScrollTo( int n ) |
780 | { | |
8e0f22c0 | 781 | UInt32 id = n + 1 ; |
fdd4e6cc | 782 | verify_noerr( m_peer->RevealItem( id , kTextColumnId , kDataBrowserRevealWithoutSelecting ) ) ; |
facd6764 SC |
783 | } |
784 | ||
5ecae0b7 SC |
785 | #if !TARGET_API_MAC_OSX |
786 | ||
facd6764 SC |
787 | void wxListBox::OnChar(wxKeyEvent& event) |
788 | { | |
fdd4e6cc | 789 | // TODO: trigger proper events here |
facd6764 SC |
790 | event.Skip() ; |
791 | return ; | |
c6179a84 | 792 | |
facd6764 SC |
793 | if ( event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER) |
794 | { | |
795 | wxWindow* parent = GetParent() ; | |
fdd4e6cc DS |
796 | |
797 | while ( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) | |
facd6764 | 798 | parent = parent->GetParent() ; |
c6179a84 | 799 | |
facd6764 SC |
800 | if ( parent && parent->GetDefaultItem() ) |
801 | { | |
fdd4e6cc | 802 | wxButton *def = wxDynamicCast(parent->GetDefaultItem(), wxButton); |
facd6764 SC |
803 | if ( def && def->IsEnabled() ) |
804 | { | |
fdd4e6cc DS |
805 | wxCommandEvent event( wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() ); |
806 | event.SetEventObject( def ); | |
807 | def->Command( event ); | |
808 | ||
facd6764 SC |
809 | return ; |
810 | } | |
811 | } | |
fdd4e6cc | 812 | |
facd6764 SC |
813 | event.Skip() ; |
814 | } | |
fdd4e6cc | 815 | |
facd6764 SC |
816 | /* generate wxID_CANCEL if command-. or <esc> has been pressed (typically in dialogs) */ |
817 | else if (event.GetKeyCode() == WXK_ESCAPE || (event.GetKeyCode() == '.' && event.MetaDown() ) ) | |
818 | { | |
de1b0aeb | 819 | // FIXME: look in ancestors, not just parent. |
facd6764 SC |
820 | wxWindow* win = GetParent()->FindWindow( wxID_CANCEL ) ; |
821 | if (win) | |
822 | { | |
de1b0aeb VZ |
823 | wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL); |
824 | new_event.SetEventObject( win ); | |
825 | win->GetEventHandler()->ProcessEvent( new_event ); | |
826 | } | |
facd6764 SC |
827 | } |
828 | else if ( event.GetKeyCode() == WXK_TAB ) | |
829 | { | |
830 | wxNavigationKeyEvent new_event; | |
831 | new_event.SetEventObject( this ); | |
832 | new_event.SetDirection( !event.ShiftDown() ); | |
833 | /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */ | |
834 | new_event.SetWindowChange( event.ControlDown() ); | |
835 | new_event.SetCurrentFocus( this ); | |
836 | if ( !GetEventHandler()->ProcessEvent( new_event ) ) | |
837 | event.Skip() ; | |
838 | } | |
839 | else if ( event.GetKeyCode() == WXK_DOWN || event.GetKeyCode() == WXK_UP ) | |
840 | { | |
841 | // perform the default key handling first | |
842 | wxControl::OnKeyDown( event ) ; | |
c6179a84 | 843 | |
fdd4e6cc | 844 | wxCommandEvent event( wxEVT_COMMAND_LISTBOX_SELECTED, m_windowId ); |
facd6764 | 845 | event.SetEventObject( this ); |
c6179a84 | 846 | |
facd6764 SC |
847 | wxArrayInt aSelections; |
848 | int n, count = GetSelections(aSelections); | |
849 | if ( count > 0 ) | |
850 | { | |
851 | n = aSelections[0]; | |
852 | if ( HasClientObjectData() ) | |
fdd4e6cc | 853 | event.SetClientObject( GetClientObject( n ) ); |
facd6764 | 854 | else if ( HasClientUntypedData() ) |
fdd4e6cc DS |
855 | event.SetClientData( GetClientData( n ) ); |
856 | event.SetString( GetString( n ) ); | |
facd6764 SC |
857 | } |
858 | else | |
859 | { | |
860 | n = -1; | |
861 | } | |
c6179a84 | 862 | |
fdd4e6cc | 863 | event.SetInt( n ); |
c6179a84 | 864 | |
facd6764 SC |
865 | GetEventHandler()->ProcessEvent(event); |
866 | } | |
867 | else | |
868 | { | |
869 | if ( event.GetTimestamp() > m_lastTypeIn + 60 ) | |
facd6764 | 870 | m_typeIn = wxEmptyString ; |
fdd4e6cc | 871 | |
facd6764 SC |
872 | m_lastTypeIn = event.GetTimestamp() ; |
873 | m_typeIn += (char) event.GetKeyCode() ; | |
fdd4e6cc | 874 | int line = FindString( wxT("*") + m_typeIn + wxT("*") ) ; |
facd6764 SC |
875 | if ( line >= 0 ) |
876 | { | |
877 | if ( GetSelection() != line ) | |
878 | { | |
fdd4e6cc DS |
879 | SetSelection( line ) ; |
880 | ||
881 | wxCommandEvent event( wxEVT_COMMAND_LISTBOX_SELECTED, m_windowId ); | |
facd6764 | 882 | event.SetEventObject( this ); |
c6179a84 | 883 | |
facd6764 SC |
884 | if ( HasClientObjectData() ) |
885 | event.SetClientObject( GetClientObject( line ) ); | |
886 | else if ( HasClientUntypedData() ) | |
fdd4e6cc DS |
887 | event.SetClientData( GetClientData( line ) ); |
888 | event.SetString( GetString( line ) ); | |
889 | event.SetInt( line ); | |
c6179a84 | 890 | |
facd6764 SC |
891 | GetEventHandler()->ProcessEvent(event); |
892 | } | |
893 | } | |
894 | } | |
895 | } | |
573ac9dc | 896 | |
c6179a84 | 897 | #endif // !TARGET_API_MAC_OSX |
5ecae0b7 | 898 | |
179e085f | 899 | #endif |