]>
Commit | Line | Data |
---|---|---|
1 | /////////////////////////////////////////////////////////////////////////////// | |
2 | // Name: src/mac/carbon/listbox.cpp | |
3 | // Purpose: wxListBox | |
4 | // Author: Stefan Csomor | |
5 | // Modified by: | |
6 | // Created: 1998-01-01 | |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) Stefan Csomor | |
9 | // Licence: wxWindows licence | |
10 | /////////////////////////////////////////////////////////////////////////////// | |
11 | ||
12 | #include "wx/wxprec.h" | |
13 | ||
14 | #if wxUSE_LISTBOX | |
15 | ||
16 | #include "wx/app.h" | |
17 | #include "wx/listbox.h" | |
18 | #include "wx/checklst.h" | |
19 | #include "wx/button.h" | |
20 | #include "wx/settings.h" | |
21 | #include "wx/toplevel.h" | |
22 | #include "wx/dynarray.h" | |
23 | #include "wx/log.h" | |
24 | ||
25 | #include "wx/utils.h" | |
26 | ||
27 | IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl) | |
28 | ||
29 | BEGIN_EVENT_TABLE(wxListBox, wxControl) | |
30 | END_EVENT_TABLE() | |
31 | ||
32 | #include "wx/mac/uma.h" | |
33 | ||
34 | // common interface for all implementations | |
35 | class wxMacListControl : public wxMacControl | |
36 | { | |
37 | public: | |
38 | wxMacListControl( wxListBox *peer ) | |
39 | : wxMacControl( peer ) | |
40 | { | |
41 | } | |
42 | ||
43 | ~wxMacListControl() | |
44 | { | |
45 | } | |
46 | ||
47 | virtual void UpdateLine( int n ) = 0; | |
48 | ||
49 | virtual void MacDelete( int n ) = 0; | |
50 | virtual void MacInsert( int n, const wxString& item ) = 0; | |
51 | virtual void MacInsert( int n, const wxArrayString& items ) = 0; | |
52 | virtual void MacAppend( const wxString& item ) = 0; | |
53 | virtual void MacSet( int n, const wxString& item ) = 0; | |
54 | virtual void MacClear() = 0; | |
55 | virtual void MacDeselectAll() = 0; | |
56 | virtual void MacSetSelection( int n, bool select ) = 0; | |
57 | virtual int MacGetSelection() const = 0; | |
58 | virtual int MacGetSelections( wxArrayInt& aSelections ) const = 0; | |
59 | virtual bool MacIsSelected( int n ) const = 0; | |
60 | virtual void MacScrollTo( int n ) = 0; | |
61 | ||
62 | wxListBox * GetPeer() const | |
63 | { return (wxListBox*)m_peer; } | |
64 | }; | |
65 | ||
66 | #if 0 | |
67 | // In case we have to replace data browser ... | |
68 | // custom HIView-based implementation | |
69 | ||
70 | class wxMacCustomHIViewListControl : public wxMacListControl | |
71 | { | |
72 | public: | |
73 | wxMacCustomHIViewListControl( wxListBox *peer, const wxPoint& pos, const wxSize& size, long style ); | |
74 | ~wxMacCustomHIViewListControl(); | |
75 | ||
76 | void MacDelete( int n ); | |
77 | void MacInsert( int n, const wxString& item ); | |
78 | void MacInsert( int n, const wxArrayString& items ); | |
79 | void MacAppend( const wxString& item ); | |
80 | void MacSet( int n, const wxString& item ); | |
81 | void MacClear(); | |
82 | void MacDeselectAll(); | |
83 | void MacSetSelection( int n, bool select ); | |
84 | int MacGetSelection() const; | |
85 | int MacGetSelections( wxArrayInt& aSelections ) const; | |
86 | bool MacIsSelected( int n ) const; | |
87 | void MacScrollTo( int n ); | |
88 | }; | |
89 | #endif | |
90 | ||
91 | // DataBrowser-based implementation | |
92 | ||
93 | class wxMacDataBrowserListControl : public wxMacListControl | |
94 | { | |
95 | public: | |
96 | wxMacDataBrowserListControl( wxListBox *peer, const wxPoint& pos, const wxSize& size, long style ); | |
97 | ~wxMacDataBrowserListControl(); | |
98 | ||
99 | void UpdateLine( int n ); | |
100 | ||
101 | void MacDelete( int n ); | |
102 | void MacInsert( int n, const wxString& item ); | |
103 | void MacInsert( int n, const wxArrayString& items ); | |
104 | void MacAppend( const wxString& item ); | |
105 | void MacSet( int n, const wxString& item ); | |
106 | void MacClear(); | |
107 | void MacDeselectAll(); | |
108 | void MacSetSelection( int n, bool select ); | |
109 | int MacGetSelection() const; | |
110 | int MacGetSelections( wxArrayInt& aSelections ) const; | |
111 | bool MacIsSelected( int n ) const; | |
112 | void MacScrollTo( int n ); | |
113 | ||
114 | virtual OSStatus SetSelectionFlags( DataBrowserSelectionFlags ); | |
115 | virtual OSStatus AddListViewColumn( DataBrowserListViewColumnDesc *columnDesc, | |
116 | DataBrowserTableViewColumnIndex position ); | |
117 | virtual OSStatus AutoSizeListViewColumns(); | |
118 | virtual OSStatus SetHasScrollBars( bool horiz, bool vert ); | |
119 | virtual OSStatus SetTableViewHiliteStyle( DataBrowserTableViewHiliteStyle hiliteStyle ); | |
120 | virtual OSStatus SetListViewHeaderBtnHeight( UInt16 height ); | |
121 | virtual OSStatus SetCallbacks( const DataBrowserCallbacks *callbacks ); | |
122 | virtual OSStatus UpdateItems( DataBrowserItemID container, UInt32 numItems, | |
123 | const DataBrowserItemID *items, | |
124 | DataBrowserPropertyID preSortProperty, | |
125 | DataBrowserPropertyID propertyID ); | |
126 | virtual OSStatus AddItems( DataBrowserItemID container, UInt32 numItems, | |
127 | const DataBrowserItemID *items, | |
128 | DataBrowserPropertyID preSortProperty ); | |
129 | virtual OSStatus RemoveItems( DataBrowserItemID container, UInt32 numItems, | |
130 | const DataBrowserItemID *items, | |
131 | DataBrowserPropertyID preSortProperty ); | |
132 | virtual OSStatus RevealItem( DataBrowserItemID item, | |
133 | DataBrowserPropertyID propertyID, | |
134 | DataBrowserRevealOptions options ); | |
135 | virtual OSStatus GetSelectionAnchor( DataBrowserItemID *first, DataBrowserItemID *last ) const; | |
136 | virtual bool IsItemSelected( DataBrowserItemID item ) const; | |
137 | virtual OSStatus SetSelectedItems( UInt32 numItems, | |
138 | const DataBrowserItemID *items, | |
139 | DataBrowserSetOption operation ); | |
140 | ||
141 | private: | |
142 | // as we are getting the same events for human and API selection we have to suppress | |
143 | // events in the latter case | |
144 | bool MacSuppressSelection( bool suppress ); | |
145 | bool MacIsSelectionSuppressed() const { return m_suppressSelection; } | |
146 | ||
147 | bool m_suppressSelection; | |
148 | ||
149 | #if TARGET_API_MAC_OSX | |
150 | static pascal void DataBrowserItemNotificationProc( | |
151 | ControlRef browser, | |
152 | DataBrowserItemID itemID, | |
153 | DataBrowserItemNotification message, | |
154 | DataBrowserItemDataRef itemData ); | |
155 | #else | |
156 | static pascal void DataBrowserItemNotificationProc( | |
157 | ControlRef browser, | |
158 | DataBrowserItemID itemID, | |
159 | DataBrowserItemNotification message ); | |
160 | #endif | |
161 | }; | |
162 | ||
163 | // ============================================================================ | |
164 | // data browser based implementation | |
165 | // ============================================================================ | |
166 | ||
167 | const short kTextColumnId = 1024; | |
168 | const short kCheckboxColumnId = 1025; | |
169 | ||
170 | // new DataBrowser-based version | |
171 | // because of the limited insert | |
172 | // functionality of DataBrowser, | |
173 | // we just introduce IDs corresponding | |
174 | // to the line number | |
175 | ||
176 | DataBrowserItemDataUPP gDataBrowserItemDataUPP = NULL; | |
177 | DataBrowserItemNotificationUPP gDataBrowserItemNotificationUPP = NULL; | |
178 | ||
179 | #if TARGET_API_MAC_OSX | |
180 | pascal void wxMacDataBrowserListControl::DataBrowserItemNotificationProc( | |
181 | ControlRef browser, | |
182 | DataBrowserItemID itemID, | |
183 | DataBrowserItemNotification message, | |
184 | DataBrowserItemDataRef itemData ) | |
185 | #else | |
186 | pascal void wxMacDataBrowserListControl::DataBrowserItemNotificationProc( | |
187 | ControlRef browser, | |
188 | DataBrowserItemID itemID, | |
189 | DataBrowserItemNotification message ) | |
190 | #endif | |
191 | { | |
192 | long ref = GetControlReference( browser ); | |
193 | if ( ref != 0 ) | |
194 | { | |
195 | wxListBox *list = wxDynamicCast( (wxObject*)ref, wxListBox ); | |
196 | wxMacDataBrowserListControl *peer = (wxMacDataBrowserListControl*) list->GetPeer(); | |
197 | ||
198 | int i = itemID - 1; | |
199 | if (i >= 0 && i < (int)list->GetCount()) | |
200 | { | |
201 | bool trigger = false; | |
202 | wxCommandEvent event( wxEVT_COMMAND_LISTBOX_SELECTED, list->GetId() ); | |
203 | switch (message) | |
204 | { | |
205 | case kDataBrowserItemDeselected: | |
206 | if ( list->HasMultipleSelection() ) | |
207 | trigger = !peer->MacIsSelectionSuppressed(); | |
208 | break; | |
209 | ||
210 | case kDataBrowserItemSelected: | |
211 | trigger = !peer->MacIsSelectionSuppressed(); | |
212 | break; | |
213 | ||
214 | case kDataBrowserItemDoubleClicked: | |
215 | event.SetEventType( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED ); | |
216 | trigger = true; | |
217 | break; | |
218 | ||
219 | default: | |
220 | break; | |
221 | } | |
222 | ||
223 | if ( trigger ) | |
224 | { | |
225 | event.SetEventObject( list ); | |
226 | if ( list->HasClientObjectData() ) | |
227 | event.SetClientObject( list->GetClientObject( i ) ); | |
228 | else if ( list->HasClientUntypedData() ) | |
229 | event.SetClientData( list->GetClientData( i ) ); | |
230 | event.SetString( list->GetString( i ) ); | |
231 | event.SetInt( i ); | |
232 | event.SetExtraLong( list->HasMultipleSelection() ? message == kDataBrowserItemSelected : true ); | |
233 | wxPostEvent( list->GetEventHandler(), event ); | |
234 | ||
235 | // direct notification is not always having the listbox GetSelection() having in synch with event | |
236 | // list->GetEventHandler()->ProcessEvent(event); | |
237 | } | |
238 | } | |
239 | } | |
240 | } | |
241 | ||
242 | static pascal OSStatus ListBoxGetSetItemData( | |
243 | ControlRef browser, | |
244 | DataBrowserItemID itemID, | |
245 | DataBrowserPropertyID property, | |
246 | DataBrowserItemDataRef itemData, | |
247 | Boolean changeValue ) | |
248 | { | |
249 | OSStatus err = errDataBrowserPropertyNotSupported; | |
250 | ||
251 | long ref = GetControlReference( browser ); | |
252 | ||
253 | if ( !changeValue ) | |
254 | { | |
255 | wxListBox *list = wxDynamicCast( (wxObject*)ref, wxListBox ); | |
256 | bool isCheckList = false; | |
257 | if (list) | |
258 | isCheckList = list->IsKindOf( CLASSINFO(wxCheckListBox) ); | |
259 | ||
260 | switch (property) | |
261 | { | |
262 | case kTextColumnId: | |
263 | if ( ref != 0 ) | |
264 | { | |
265 | int i = itemID - 1; | |
266 | if (i >= 0 && i < (int)list->GetCount()) | |
267 | { | |
268 | wxMacCFStringHolder cf( list->GetString( i ), list->GetFont().GetEncoding() ); | |
269 | err = ::SetDataBrowserItemDataText( itemData, cf ); | |
270 | verify_noerr( err ); | |
271 | err = noErr; | |
272 | } | |
273 | } | |
274 | break; | |
275 | ||
276 | case kCheckboxColumnId: | |
277 | if ( ref != 0 ) | |
278 | { | |
279 | wxCheckListBox *list = wxDynamicCast( (wxObject*)ref, wxCheckListBox ); | |
280 | int i = itemID - 1; | |
281 | if (i >= 0 && (unsigned int) i < list->GetCount()) | |
282 | { | |
283 | err = ::SetDataBrowserItemDataButtonValue( itemData, list->IsChecked( i ) ? kThemeButtonOn : kThemeButtonOff ); | |
284 | verify_noerr( err ); | |
285 | err = noErr; | |
286 | } | |
287 | } | |
288 | break; | |
289 | ||
290 | case kDataBrowserItemIsEditableProperty: | |
291 | if ( isCheckList ) | |
292 | err = ::SetDataBrowserItemDataBooleanValue( itemData, true ); | |
293 | break; | |
294 | ||
295 | default: | |
296 | break; | |
297 | } | |
298 | } | |
299 | else | |
300 | { | |
301 | switch (property) | |
302 | { | |
303 | case kCheckboxColumnId: | |
304 | if ( ref != 0 ) | |
305 | { | |
306 | wxCheckListBox *list = wxDynamicCast( (wxObject*)ref, wxCheckListBox ); | |
307 | int i = itemID - 1; | |
308 | if (i >= 0 && (unsigned int)i < list->GetCount()) | |
309 | { | |
310 | // we have to change this behind the back, since Check() would be triggering another update round | |
311 | bool newVal = !list->IsChecked( i ); | |
312 | err = ::SetDataBrowserItemDataButtonValue( itemData, newVal ? kThemeButtonOn : kThemeButtonOff ); | |
313 | verify_noerr( err ); | |
314 | err = noErr; | |
315 | list->m_checks[i] = newVal; | |
316 | ||
317 | wxCommandEvent event( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, list->GetId() ); | |
318 | event.SetInt( i ); | |
319 | event.SetEventObject( list ); | |
320 | list->GetEventHandler()->ProcessEvent( event ); | |
321 | } | |
322 | } | |
323 | break; | |
324 | ||
325 | default: | |
326 | break; | |
327 | } | |
328 | } | |
329 | ||
330 | return err; | |
331 | } | |
332 | ||
333 | wxMacDataBrowserListControl::wxMacDataBrowserListControl( wxListBox *peer, const wxPoint& pos, const wxSize& size, long style) | |
334 | : wxMacListControl( peer ) | |
335 | { | |
336 | bool isCheckList = peer->IsKindOf( CLASSINFO(wxCheckListBox)); | |
337 | ||
338 | m_suppressSelection = false; | |
339 | Rect bounds = wxMacGetBoundsForControl( peer, pos, size ); | |
340 | OSStatus err = ::CreateDataBrowserControl( | |
341 | MAC_WXHWND(peer->MacGetTopLevelWindowRef()), | |
342 | &bounds, kDataBrowserListView, &m_controlRef ); | |
343 | verify_noerr( err ); | |
344 | ||
345 | DataBrowserSelectionFlags options = kDataBrowserDragSelect; | |
346 | if ( style & wxLB_MULTIPLE ) | |
347 | { | |
348 | options |= kDataBrowserAlwaysExtendSelection | kDataBrowserCmdTogglesSelection; | |
349 | } | |
350 | else if ( style & wxLB_EXTENDED ) | |
351 | { | |
352 | // default behaviour | |
353 | } | |
354 | else | |
355 | { | |
356 | options |= kDataBrowserSelectOnlyOne; | |
357 | } | |
358 | err = SetSelectionFlags( options ); | |
359 | verify_noerr( err ); | |
360 | ||
361 | if ( gDataBrowserItemDataUPP == NULL ) | |
362 | gDataBrowserItemDataUPP = NewDataBrowserItemDataUPP(ListBoxGetSetItemData); | |
363 | if ( gDataBrowserItemNotificationUPP == NULL ) | |
364 | { | |
365 | gDataBrowserItemNotificationUPP = | |
366 | #if TARGET_API_MAC_OSX | |
367 | (DataBrowserItemNotificationUPP) NewDataBrowserItemNotificationWithItemUPP(DataBrowserItemNotificationProc); | |
368 | #else | |
369 | NewDataBrowserItemNotificationUPP(DataBrowserItemNotificationProc); | |
370 | #endif | |
371 | } | |
372 | ||
373 | DataBrowserCallbacks callbacks; | |
374 | InitializeDataBrowserCallbacks( &callbacks, kDataBrowserLatestCallbacks ); | |
375 | ||
376 | callbacks.u.v1.itemDataCallback = gDataBrowserItemDataUPP; | |
377 | callbacks.u.v1.itemNotificationCallback = gDataBrowserItemNotificationUPP; | |
378 | SetCallbacks( &callbacks ); | |
379 | ||
380 | DataBrowserListViewColumnDesc columnDesc; | |
381 | columnDesc.headerBtnDesc.titleOffset = 0; | |
382 | columnDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc; | |
383 | ||
384 | columnDesc.headerBtnDesc.btnFontStyle.flags = | |
385 | kControlUseFontMask | kControlUseJustMask; | |
386 | ||
387 | columnDesc.headerBtnDesc.btnContentInfo.contentType = kControlNoContent; | |
388 | columnDesc.headerBtnDesc.btnFontStyle.just = teFlushDefault; | |
389 | columnDesc.headerBtnDesc.btnFontStyle.font = kControlFontViewSystemFont; | |
390 | columnDesc.headerBtnDesc.btnFontStyle.style = normal; | |
391 | columnDesc.headerBtnDesc.titleString = NULL; | |
392 | ||
393 | if ( isCheckList ) | |
394 | { | |
395 | columnDesc.headerBtnDesc.minimumWidth = 30; | |
396 | columnDesc.headerBtnDesc.maximumWidth = 30; | |
397 | ||
398 | columnDesc.propertyDesc.propertyID = kCheckboxColumnId; | |
399 | columnDesc.propertyDesc.propertyType = kDataBrowserCheckboxType; | |
400 | columnDesc.propertyDesc.propertyFlags = | |
401 | kDataBrowserPropertyIsMutable | |
402 | | kDataBrowserTableViewSelectionColumn | |
403 | | kDataBrowserDefaultPropertyFlags; | |
404 | err = AddListViewColumn( &columnDesc, kDataBrowserListViewAppendColumn ); | |
405 | verify_noerr( err ); | |
406 | } | |
407 | ||
408 | columnDesc.headerBtnDesc.minimumWidth = 0; | |
409 | columnDesc.headerBtnDesc.maximumWidth = 10000; | |
410 | ||
411 | columnDesc.propertyDesc.propertyID = kTextColumnId; | |
412 | columnDesc.propertyDesc.propertyType = kDataBrowserTextType; | |
413 | columnDesc.propertyDesc.propertyFlags = kDataBrowserTableViewSelectionColumn; | |
414 | #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2 | |
415 | columnDesc.propertyDesc.propertyFlags |= kDataBrowserListViewTypeSelectColumn; | |
416 | #endif | |
417 | ||
418 | verify_noerr( AddListViewColumn( &columnDesc, kDataBrowserListViewAppendColumn ) ); | |
419 | verify_noerr( AutoSizeListViewColumns() ); | |
420 | verify_noerr( SetHasScrollBars( false, true ) ); | |
421 | verify_noerr( SetTableViewHiliteStyle(kDataBrowserTableViewFillHilite ) ); | |
422 | verify_noerr( SetListViewHeaderBtnHeight( 0 ) ); | |
423 | ||
424 | #if 0 | |
425 | // shouldn't be necessary anymore under 10.2 | |
426 | m_peer->SetData( kControlNoPart, kControlDataBrowserIncludesFrameAndFocusTag, (Boolean)false ); | |
427 | m_peer->SetNeedsFocusRect( true ); | |
428 | #endif | |
429 | } | |
430 | ||
431 | wxMacDataBrowserListControl::~wxMacDataBrowserListControl() | |
432 | { | |
433 | } | |
434 | ||
435 | void wxMacDataBrowserListControl::MacDelete( int n ) | |
436 | { | |
437 | wxArrayInt selectionBefore; | |
438 | MacGetSelections( selectionBefore ); | |
439 | ||
440 | UInt32 id = GetPeer()->GetCount() + 1; | |
441 | ||
442 | OSStatus err = RemoveItems( kDataBrowserNoItem, 1, (UInt32*) &id, kDataBrowserItemNoProperty ); | |
443 | verify_noerr( err ); | |
444 | ||
445 | for ( size_t i = 0; i < selectionBefore.GetCount(); ++i ) | |
446 | { | |
447 | int current = selectionBefore[i]; | |
448 | if ( current == n ) | |
449 | { | |
450 | // selection was deleted | |
451 | MacSetSelection( current, false ); | |
452 | } | |
453 | else if ( current > n ) | |
454 | { | |
455 | // something behind the deleted item was selected -> move up | |
456 | MacSetSelection( current - 1, true ); | |
457 | MacSetSelection( current, false ); | |
458 | } | |
459 | } | |
460 | ||
461 | // refresh all | |
462 | err = UpdateItems( | |
463 | kDataBrowserNoItem, 1, (UInt32*)kDataBrowserNoItem, | |
464 | kDataBrowserItemNoProperty, kDataBrowserItemNoProperty ); | |
465 | verify_noerr( err ); | |
466 | } | |
467 | ||
468 | void wxMacDataBrowserListControl::MacInsert( int n, const wxString& text) | |
469 | { | |
470 | wxArrayInt selectionBefore; | |
471 | MacGetSelections( selectionBefore ); | |
472 | ||
473 | UInt32 id = GetPeer()->GetCount(); // this has already been increased | |
474 | OSStatus err = AddItems( kDataBrowserNoItem, 1, (UInt32*) &id, kDataBrowserItemNoProperty ); | |
475 | verify_noerr( err ); | |
476 | ||
477 | for ( int i = selectionBefore.GetCount() - 1; i >= 0; --i ) | |
478 | { | |
479 | int current = selectionBefore[i]; | |
480 | if ( current >= n ) | |
481 | { | |
482 | MacSetSelection( current + 1, true ); | |
483 | MacSetSelection( current, false ); | |
484 | } | |
485 | } | |
486 | ||
487 | // refresh all | |
488 | err = UpdateItems( | |
489 | kDataBrowserNoItem, 1, (UInt32*)kDataBrowserNoItem, | |
490 | kDataBrowserItemNoProperty, kDataBrowserItemNoProperty ); | |
491 | verify_noerr( err ); | |
492 | } | |
493 | ||
494 | void wxMacDataBrowserListControl::MacInsert( int n, const wxArrayString& items) | |
495 | { | |
496 | wxArrayInt selectionBefore; | |
497 | MacGetSelections( selectionBefore ); | |
498 | size_t itemsCount = items.GetCount(); | |
499 | ||
500 | UInt32 *ids = new UInt32[itemsCount]; | |
501 | for ( unsigned int i = 0; i < itemsCount; ++i ) | |
502 | ids[i] = GetPeer()->GetCount() - itemsCount + i + 1; | |
503 | ||
504 | OSStatus err = AddItems( kDataBrowserNoItem, itemsCount, ids, kDataBrowserItemNoProperty ); | |
505 | verify_noerr( err ); | |
506 | delete [] ids; | |
507 | ||
508 | for ( int i = selectionBefore.GetCount() - 1; i >= 0; --i ) | |
509 | { | |
510 | int current = selectionBefore[i]; | |
511 | if ( current >= n ) | |
512 | { | |
513 | MacSetSelection( current + 1, true ); | |
514 | MacSetSelection( current, false ); | |
515 | } | |
516 | } | |
517 | ||
518 | // refresh all | |
519 | err = UpdateItems( | |
520 | kDataBrowserNoItem, 1, (UInt32*)kDataBrowserNoItem, | |
521 | kDataBrowserItemNoProperty, kDataBrowserItemNoProperty ); | |
522 | verify_noerr( err ); | |
523 | } | |
524 | ||
525 | void wxMacDataBrowserListControl::MacAppend( const wxString& text) | |
526 | { | |
527 | UInt32 id = GetPeer()->GetCount(); // this has already been increased | |
528 | verify_noerr( AddItems( kDataBrowserNoItem, 1, (UInt32*) &id, kDataBrowserItemNoProperty ) ); | |
529 | // no need to deal with selections nor refreshed, as we have appended | |
530 | } | |
531 | ||
532 | void wxMacDataBrowserListControl::MacClear() | |
533 | { | |
534 | verify_noerr( RemoveItems( kDataBrowserNoItem, 0, NULL, kDataBrowserItemNoProperty ) ); | |
535 | } | |
536 | ||
537 | void wxMacDataBrowserListControl::MacDeselectAll() | |
538 | { | |
539 | bool former = MacSuppressSelection( true ); | |
540 | verify_noerr(SetSelectedItems( 0, NULL, kDataBrowserItemsRemove ) ); | |
541 | MacSuppressSelection( former ); | |
542 | } | |
543 | ||
544 | void wxMacDataBrowserListControl::MacSetSelection( int n, bool select ) | |
545 | { | |
546 | UInt32 id = n + 1; | |
547 | bool former = MacSuppressSelection( true ); | |
548 | ||
549 | if ( IsItemSelected( id ) != select ) | |
550 | { | |
551 | OSStatus err; | |
552 | ||
553 | if ( select ) | |
554 | err = SetSelectedItems( 1, &id, GetPeer()->HasMultipleSelection() ? kDataBrowserItemsAdd : kDataBrowserItemsAssign ); | |
555 | else | |
556 | err = SetSelectedItems( 1, &id, kDataBrowserItemsRemove ); | |
557 | ||
558 | verify_noerr( err ); | |
559 | } | |
560 | ||
561 | MacScrollTo( n ); | |
562 | MacSuppressSelection( former ); | |
563 | } | |
564 | ||
565 | bool wxMacDataBrowserListControl::MacSuppressSelection( bool suppress ) | |
566 | { | |
567 | bool former = m_suppressSelection; | |
568 | m_suppressSelection = suppress; | |
569 | ||
570 | return former; | |
571 | } | |
572 | ||
573 | bool wxMacDataBrowserListControl::MacIsSelected( int n ) const | |
574 | { | |
575 | return IsItemSelected( n + 1 ); | |
576 | } | |
577 | ||
578 | int wxMacDataBrowserListControl::MacGetSelection() const | |
579 | { | |
580 | for ( unsigned int i = 0; i < GetPeer()->GetCount(); ++i ) | |
581 | { | |
582 | if ( IsItemSelected( i + 1 ) ) | |
583 | { | |
584 | return i; | |
585 | } | |
586 | } | |
587 | ||
588 | return -1; | |
589 | } | |
590 | ||
591 | int wxMacDataBrowserListControl::MacGetSelections( wxArrayInt& aSelections ) const | |
592 | { | |
593 | int no_sel = 0; | |
594 | ||
595 | aSelections.Empty(); | |
596 | ||
597 | UInt32 first, last; | |
598 | GetSelectionAnchor( &first, &last ); | |
599 | if ( first != kDataBrowserNoItem ) | |
600 | { | |
601 | for ( size_t i = first; i <= last; ++i ) | |
602 | { | |
603 | if ( IsItemSelected( i ) ) | |
604 | { | |
605 | aSelections.Add( i - 1 ); | |
606 | no_sel++; | |
607 | } | |
608 | } | |
609 | } | |
610 | ||
611 | return no_sel; | |
612 | } | |
613 | ||
614 | void wxMacDataBrowserListControl::MacSet( int n, const wxString& text ) | |
615 | { | |
616 | // as we don't store the strings we only have to issue a redraw | |
617 | UInt32 id = n + 1; | |
618 | verify_noerr( UpdateItems( kDataBrowserNoItem, 1, &id, kDataBrowserItemNoProperty, kDataBrowserItemNoProperty ) ); | |
619 | } | |
620 | ||
621 | void wxMacDataBrowserListControl::MacScrollTo( int n ) | |
622 | { | |
623 | UInt32 id = n + 1; | |
624 | verify_noerr( RevealItem( id, kTextColumnId, kDataBrowserRevealWithoutSelecting ) ); | |
625 | } | |
626 | ||
627 | void wxMacDataBrowserListControl::UpdateLine( int n ) | |
628 | { | |
629 | UInt32 id = n + 1; | |
630 | verify_noerr( UpdateItems(kDataBrowserNoItem, 1, &id, kDataBrowserItemNoProperty, kDataBrowserItemNoProperty ) ); | |
631 | } | |
632 | ||
633 | // | |
634 | // Databrowser | |
635 | // | |
636 | ||
637 | OSStatus wxMacDataBrowserListControl::SetSelectionFlags( DataBrowserSelectionFlags options ) | |
638 | { | |
639 | return SetDataBrowserSelectionFlags( m_controlRef, options ); | |
640 | } | |
641 | ||
642 | OSStatus wxMacDataBrowserListControl::AddListViewColumn( DataBrowserListViewColumnDesc *columnDesc, | |
643 | DataBrowserTableViewColumnIndex position ) | |
644 | { | |
645 | return AddDataBrowserListViewColumn( m_controlRef, columnDesc, position ); | |
646 | } | |
647 | ||
648 | OSStatus wxMacDataBrowserListControl::AutoSizeListViewColumns() | |
649 | { | |
650 | return AutoSizeDataBrowserListViewColumns(m_controlRef); | |
651 | } | |
652 | ||
653 | OSStatus wxMacDataBrowserListControl::SetHasScrollBars( bool horiz, bool vert ) | |
654 | { | |
655 | return SetDataBrowserHasScrollBars( m_controlRef, horiz, vert ); | |
656 | } | |
657 | ||
658 | OSStatus wxMacDataBrowserListControl::SetTableViewHiliteStyle( DataBrowserTableViewHiliteStyle hiliteStyle ) | |
659 | { | |
660 | return SetDataBrowserTableViewHiliteStyle( m_controlRef, hiliteStyle ); | |
661 | } | |
662 | ||
663 | OSStatus wxMacDataBrowserListControl::SetListViewHeaderBtnHeight(UInt16 height) | |
664 | { | |
665 | return SetDataBrowserListViewHeaderBtnHeight( m_controlRef, height ); | |
666 | } | |
667 | ||
668 | OSStatus wxMacDataBrowserListControl::SetCallbacks(const DataBrowserCallbacks *callbacks) | |
669 | { | |
670 | return SetDataBrowserCallbacks( m_controlRef, callbacks ); | |
671 | } | |
672 | ||
673 | OSStatus wxMacDataBrowserListControl::UpdateItems( | |
674 | DataBrowserItemID container, | |
675 | UInt32 numItems, | |
676 | const DataBrowserItemID *items, | |
677 | DataBrowserPropertyID preSortProperty, | |
678 | DataBrowserPropertyID propertyID ) | |
679 | { | |
680 | return UpdateDataBrowserItems( m_controlRef, container, numItems, items, preSortProperty, propertyID ); | |
681 | } | |
682 | ||
683 | bool wxMacDataBrowserListControl::IsItemSelected( DataBrowserItemID item ) const | |
684 | { | |
685 | return IsDataBrowserItemSelected( m_controlRef, item ); | |
686 | } | |
687 | ||
688 | OSStatus wxMacDataBrowserListControl::AddItems( | |
689 | DataBrowserItemID container, | |
690 | UInt32 numItems, | |
691 | const DataBrowserItemID *items, | |
692 | DataBrowserPropertyID preSortProperty ) | |
693 | { | |
694 | return AddDataBrowserItems( m_controlRef, container, numItems, items, preSortProperty ); | |
695 | } | |
696 | ||
697 | OSStatus wxMacDataBrowserListControl::RemoveItems( | |
698 | DataBrowserItemID container, | |
699 | UInt32 numItems, | |
700 | const DataBrowserItemID *items, | |
701 | DataBrowserPropertyID preSortProperty ) | |
702 | { | |
703 | return RemoveDataBrowserItems( m_controlRef, container, numItems, items, preSortProperty ); | |
704 | } | |
705 | ||
706 | OSStatus wxMacDataBrowserListControl::RevealItem( | |
707 | DataBrowserItemID item, | |
708 | DataBrowserPropertyID propertyID, | |
709 | DataBrowserRevealOptions options ) | |
710 | { | |
711 | return RevealDataBrowserItem( m_controlRef, item, propertyID, options ); | |
712 | } | |
713 | ||
714 | OSStatus wxMacDataBrowserListControl::SetSelectedItems( | |
715 | UInt32 numItems, | |
716 | const DataBrowserItemID *items, | |
717 | DataBrowserSetOption operation ) | |
718 | { | |
719 | return SetDataBrowserSelectedItems( m_controlRef, numItems, items, operation ); | |
720 | } | |
721 | ||
722 | OSStatus wxMacDataBrowserListControl::GetSelectionAnchor( DataBrowserItemID *first, DataBrowserItemID *last ) const | |
723 | { | |
724 | return GetDataBrowserSelectionAnchor( m_controlRef, first, last ); | |
725 | } | |
726 | ||
727 | #if 0 | |
728 | ||
729 | // in case we need that one day | |
730 | ||
731 | // ============================================================================ | |
732 | // HIView owner-draw-based implementation | |
733 | // ============================================================================ | |
734 | ||
735 | static pascal void ListBoxDrawProc( | |
736 | ControlRef browser, DataBrowserItemID item, DataBrowserPropertyID property, | |
737 | DataBrowserItemState itemState, const Rect *itemRect, SInt16 depth, Boolean isColorDevice ) | |
738 | { | |
739 | CFStringRef cfString; | |
740 | ThemeDrawingState themeState; | |
741 | long systemVersion; | |
742 | ||
743 | GetThemeDrawingState( &themeState ); | |
744 | cfString = CFStringCreateWithFormat( NULL, NULL, CFSTR("Row %d"), item ); | |
745 | ||
746 | // In this sample we handle the "selected" state; all others fall through to our "active" state | |
747 | if ( itemState == kDataBrowserItemIsSelected ) | |
748 | { | |
749 | ThemeBrush colorBrushID; | |
750 | ||
751 | // TODO: switch over to wxSystemSettingsNative::GetColour() when kThemeBrushSecondaryHighlightColor | |
752 | // is incorporated Panther DB starts using kThemeBrushSecondaryHighlightColor | |
753 | // for inactive browser highlighting | |
754 | Gestalt( gestaltSystemVersion, &systemVersion ); | |
755 | if ( (systemVersion >= 0x00001030) && !IsControlActive( browser ) ) | |
756 | colorBrushID = kThemeBrushSecondaryHighlightColor; | |
757 | else | |
758 | colorBrushID = kThemeBrushPrimaryHighlightColor; | |
759 | ||
760 | // First paint the hilite rect, then the text on top | |
761 | SetThemePen( colorBrushID, 32, true ); | |
762 | PaintRect( itemRect ); | |
763 | SetThemeDrawingState( themeState, false ); | |
764 | } | |
765 | ||
766 | DrawThemeTextBox( cfString, kThemeApplicationFont, kThemeStateActive, true, itemRect, teFlushDefault, NULL ); | |
767 | SetThemeDrawingState( themeState, true ); | |
768 | ||
769 | if ( cfString != NULL ) | |
770 | CFRelease( cfString ); | |
771 | } | |
772 | #endif | |
773 | ||
774 | // ============================================================================ | |
775 | // list box control implementation | |
776 | // ============================================================================ | |
777 | ||
778 | wxListBox::wxListBox() | |
779 | { | |
780 | m_noItems = 0; | |
781 | } | |
782 | ||
783 | bool wxListBox::Create( | |
784 | wxWindow *parent, | |
785 | wxWindowID id, | |
786 | const wxPoint& pos, | |
787 | const wxSize& size, | |
788 | const wxArrayString& choices, | |
789 | long style, | |
790 | const wxValidator& validator, | |
791 | const wxString& name ) | |
792 | { | |
793 | wxCArrayString chs(choices); | |
794 | ||
795 | return Create( | |
796 | parent, id, pos, size, chs.GetCount(), chs.GetStrings(), | |
797 | style, validator, name ); | |
798 | } | |
799 | ||
800 | bool wxListBox::Create( | |
801 | wxWindow *parent, | |
802 | wxWindowID id, | |
803 | const wxPoint& pos, | |
804 | const wxSize& size, | |
805 | int n, | |
806 | const wxString choices[], | |
807 | long style, | |
808 | const wxValidator& validator, | |
809 | const wxString& name ) | |
810 | { | |
811 | m_macIsUserPane = false; | |
812 | ||
813 | wxASSERT_MSG( !(style & wxLB_MULTIPLE) || !(style & wxLB_EXTENDED), | |
814 | wxT("only a single listbox selection mode can be specified") ); | |
815 | ||
816 | if ( !wxListBoxBase::Create( parent, id, pos, size, style & ~(wxHSCROLL | wxVSCROLL), validator, name ) ) | |
817 | return false; | |
818 | ||
819 | // this will be increased by our append command | |
820 | m_noItems = 0; | |
821 | ||
822 | m_peer = CreateMacListControl( pos, size, style ); | |
823 | ||
824 | MacPostControlCreate( pos, size ); | |
825 | ||
826 | InsertItems( n, choices, 0 ); | |
827 | ||
828 | // Needed because it is a wxControlWithItems | |
829 | SetBestSize( size ); | |
830 | ||
831 | return true; | |
832 | } | |
833 | ||
834 | wxListBox::~wxListBox() | |
835 | { | |
836 | m_peer->SetReference( 0 ); | |
837 | FreeData(); | |
838 | } | |
839 | ||
840 | wxMacListControl * wxListBox::CreateMacListControl(const wxPoint& pos, const wxSize& size, long style) | |
841 | { | |
842 | return new wxMacDataBrowserListControl( this, pos, size, style ); | |
843 | } | |
844 | ||
845 | void wxListBox::FreeData() | |
846 | { | |
847 | #if wxUSE_OWNER_DRAWN | |
848 | if ( m_windowStyle & wxLB_OWNERDRAW ) | |
849 | { | |
850 | size_t uiCount = m_aItems.Count(); | |
851 | while ( uiCount != 0 ) | |
852 | { | |
853 | uiCount--; | |
854 | delete m_aItems[uiCount]; | |
855 | m_aItems[uiCount] = NULL; | |
856 | } | |
857 | ||
858 | m_aItems.Clear(); | |
859 | } | |
860 | else | |
861 | #endif | |
862 | if ( HasClientObjectData() ) | |
863 | { | |
864 | for ( unsigned int n = 0; n < m_noItems; n++ ) | |
865 | { | |
866 | delete GetClientObject( n ); | |
867 | } | |
868 | } | |
869 | } | |
870 | ||
871 | void wxListBox::DoSetSize(int x, int y, | |
872 | int width, int height, | |
873 | int sizeFlags ) | |
874 | { | |
875 | wxControl::DoSetSize( x, y, width, height, sizeFlags ); | |
876 | } | |
877 | ||
878 | void wxListBox::DoSetFirstItem(int n) | |
879 | { | |
880 | GetPeer()->MacScrollTo( n ); | |
881 | } | |
882 | ||
883 | void wxListBox::Delete(unsigned int n) | |
884 | { | |
885 | wxCHECK_RET( IsValid(n), wxT("invalid index in wxListBox::Delete") ); | |
886 | ||
887 | #if wxUSE_OWNER_DRAWN | |
888 | delete m_aItems[n]; | |
889 | m_aItems.RemoveAt(n); | |
890 | #else | |
891 | if ( HasClientObjectData() ) | |
892 | { | |
893 | delete GetClientObject(n); | |
894 | } | |
895 | #endif | |
896 | ||
897 | m_stringArray.RemoveAt( n ); | |
898 | m_dataArray.RemoveAt( n ); | |
899 | m_noItems--; | |
900 | ||
901 | GetPeer()->MacDelete( n ); | |
902 | } | |
903 | ||
904 | int wxListBox::DoAppend(const wxString& item) | |
905 | { | |
906 | InvalidateBestSize(); | |
907 | ||
908 | unsigned int index = m_noItems; | |
909 | m_stringArray.Add( item ); | |
910 | m_dataArray.Add( NULL ); | |
911 | m_noItems++; | |
912 | DoSetItemClientData( index, NULL ); | |
913 | GetPeer()->MacAppend( item ); | |
914 | ||
915 | return index; | |
916 | } | |
917 | ||
918 | void wxListBox::DoSetItems(const wxArrayString& choices, void** clientData) | |
919 | { | |
920 | Clear(); | |
921 | unsigned int n = choices.GetCount(); | |
922 | ||
923 | for ( size_t i = 0; i < n; ++i ) | |
924 | { | |
925 | if ( clientData ) | |
926 | { | |
927 | #if wxUSE_OWNER_DRAWN | |
928 | wxASSERT_MSG(clientData[i] == NULL, | |
929 | wxT("Cannot use client data with owner-drawn listboxes")); | |
930 | #else | |
931 | Append( choices[i], clientData[i] ); | |
932 | #endif | |
933 | } | |
934 | else | |
935 | Append( choices[i] ); | |
936 | } | |
937 | ||
938 | #if wxUSE_OWNER_DRAWN | |
939 | if ( m_windowStyle & wxLB_OWNERDRAW ) | |
940 | { | |
941 | // first delete old items | |
942 | size_t ui = m_aItems.Count(); | |
943 | while ( ui != 0 ) | |
944 | { | |
945 | ui--; | |
946 | delete m_aItems[ui]; | |
947 | m_aItems[ui] = NULL; | |
948 | } | |
949 | ||
950 | m_aItems.Empty(); | |
951 | ||
952 | // then create new ones | |
953 | for ( ui = 0; ui < (size_t)m_noItems; ui++ ) | |
954 | { | |
955 | wxOwnerDrawn *pNewItem = CreateItem(ui); | |
956 | pNewItem->SetName(choices[ui]); | |
957 | m_aItems.Add(pNewItem); | |
958 | } | |
959 | } | |
960 | #endif | |
961 | } | |
962 | ||
963 | int wxListBox::FindString(const wxString& s, bool bCase) const | |
964 | { | |
965 | for ( size_t i = 0; i < m_noItems; ++ i ) | |
966 | { | |
967 | if (s.IsSameAs( GetString( i ), bCase) ) | |
968 | return (int)i; | |
969 | } | |
970 | ||
971 | return wxNOT_FOUND; | |
972 | } | |
973 | ||
974 | void wxListBox::Clear() | |
975 | { | |
976 | FreeData(); | |
977 | m_noItems = 0; | |
978 | m_stringArray.Empty(); | |
979 | m_dataArray.Empty(); | |
980 | GetPeer()->MacClear(); | |
981 | } | |
982 | ||
983 | void wxListBox::DoSetSelection(int n, bool select) | |
984 | { | |
985 | wxCHECK_RET( n == wxNOT_FOUND || IsValid(n), | |
986 | wxT("invalid index in wxListBox::SetSelection") ); | |
987 | ||
988 | if ( n == wxNOT_FOUND ) | |
989 | GetPeer()->MacDeselectAll(); | |
990 | else | |
991 | GetPeer()->MacSetSelection( n, select ); | |
992 | } | |
993 | ||
994 | bool wxListBox::IsSelected(int n) const | |
995 | { | |
996 | wxCHECK_MSG( IsValid(n), false, wxT("invalid index in wxListBox::Selected") ); | |
997 | ||
998 | return GetPeer()->MacIsSelected( n ); | |
999 | } | |
1000 | ||
1001 | void *wxListBox::DoGetItemClientData(unsigned int n) const | |
1002 | { | |
1003 | wxCHECK_MSG( IsValid(n), NULL, wxT("invalid index in wxListBox::GetClientData")); | |
1004 | ||
1005 | wxASSERT_MSG( m_dataArray.GetCount() >= (unsigned int)n, wxT("invalid client_data array") ); | |
1006 | ||
1007 | return (void*)m_dataArray[n]; | |
1008 | } | |
1009 | ||
1010 | wxClientData *wxListBox::DoGetItemClientObject(unsigned int n) const | |
1011 | { | |
1012 | return (wxClientData*)DoGetItemClientData( n ); | |
1013 | } | |
1014 | ||
1015 | void wxListBox::DoSetItemClientData(unsigned int n, void *clientData) | |
1016 | { | |
1017 | wxCHECK_RET( IsValid(n), wxT("invalid index in wxListBox::SetClientData") ); | |
1018 | ||
1019 | #if wxUSE_OWNER_DRAWN | |
1020 | if ( m_windowStyle & wxLB_OWNERDRAW ) | |
1021 | { | |
1022 | // client data must be pointer to wxOwnerDrawn, otherwise we would crash | |
1023 | // in OnMeasure/OnDraw. | |
1024 | wxFAIL_MSG(wxT("Cannot use client data with owner-drawn listboxes")); | |
1025 | } | |
1026 | #endif | |
1027 | ||
1028 | wxASSERT_MSG( m_dataArray.GetCount() >= (unsigned int)n, wxT("invalid client_data array") ); | |
1029 | ||
1030 | if ( m_dataArray.GetCount() > (unsigned int)n ) | |
1031 | m_dataArray[n] = (char*)clientData; | |
1032 | else | |
1033 | m_dataArray.Add( (char*)clientData ); | |
1034 | } | |
1035 | ||
1036 | void wxListBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData) | |
1037 | { | |
1038 | DoSetItemClientData(n, clientData); | |
1039 | } | |
1040 | ||
1041 | // Return number of selections and an array of selected integers | |
1042 | int wxListBox::GetSelections(wxArrayInt& aSelections) const | |
1043 | { | |
1044 | return GetPeer()->MacGetSelections( aSelections ); | |
1045 | } | |
1046 | ||
1047 | // Get single selection, for single choice list items | |
1048 | int wxListBox::GetSelection() const | |
1049 | { | |
1050 | return GetPeer()->MacGetSelection(); | |
1051 | } | |
1052 | ||
1053 | // Find string for position | |
1054 | wxString wxListBox::GetString(unsigned int n) const | |
1055 | { | |
1056 | wxCHECK_MSG( IsValid(n), wxEmptyString, wxT("invalid index in wxListBox::GetString") ); | |
1057 | ||
1058 | return m_stringArray[n]; | |
1059 | } | |
1060 | ||
1061 | void wxListBox::DoInsertItems(const wxArrayString& items, unsigned int pos) | |
1062 | { | |
1063 | wxCHECK_RET( IsValidInsert(pos), wxT("invalid index in wxListBox::InsertItems") ); | |
1064 | ||
1065 | InvalidateBestSize(); | |
1066 | ||
1067 | unsigned int nItems = items.GetCount(); | |
1068 | ||
1069 | for ( unsigned int i = 0; i < nItems; i++ ) | |
1070 | m_stringArray.Insert( items[i], pos + i ); | |
1071 | m_dataArray.Insert( NULL, pos, nItems ); | |
1072 | m_noItems += nItems; | |
1073 | GetPeer()->MacInsert( pos, items ); | |
1074 | } | |
1075 | ||
1076 | void wxListBox::SetString(unsigned int n, const wxString& s) | |
1077 | { | |
1078 | m_stringArray[n] = s; | |
1079 | GetPeer()->MacSet( n, s ); | |
1080 | } | |
1081 | ||
1082 | wxSize wxListBox::DoGetBestSize() const | |
1083 | { | |
1084 | int lbWidth = 100; // some defaults | |
1085 | int lbHeight = 110; | |
1086 | int wLine; | |
1087 | ||
1088 | { | |
1089 | wxMacPortStateHelper st( UMAGetWindowPort( (WindowRef)MacGetTopLevelWindowRef() ) ); | |
1090 | ||
1091 | // TODO: clean this up | |
1092 | if ( m_font.Ok() ) | |
1093 | { | |
1094 | ::TextFont( m_font.MacGetFontNum() ); | |
1095 | ::TextSize( m_font.MacGetFontSize() ); | |
1096 | ::TextFace( m_font.MacGetFontStyle() ); | |
1097 | } | |
1098 | else | |
1099 | { | |
1100 | ::TextFont( kFontIDMonaco ); | |
1101 | ::TextSize( 9 ); | |
1102 | ::TextFace( 0 ); | |
1103 | } | |
1104 | ||
1105 | // Find the widest line | |
1106 | for (unsigned int i = 0; i < GetCount(); i++) | |
1107 | { | |
1108 | wxString str( GetString( i ) ); | |
1109 | ||
1110 | #if wxUSE_UNICODE | |
1111 | Point bounds = {0, 0}; | |
1112 | SInt16 baseline; | |
1113 | ||
1114 | // NB: what if m_font.Ok() == false ??? | |
1115 | ::GetThemeTextDimensions( | |
1116 | wxMacCFStringHolder( str, m_font.GetEncoding() ), | |
1117 | kThemeCurrentPortFont, | |
1118 | kThemeStateActive, | |
1119 | false, | |
1120 | &bounds, | |
1121 | &baseline ); | |
1122 | wLine = bounds.h; | |
1123 | #else | |
1124 | wLine = ::TextWidth( str.c_str(), 0, str.length() ); | |
1125 | #endif | |
1126 | ||
1127 | lbWidth = wxMax( lbWidth, wLine ); | |
1128 | } | |
1129 | ||
1130 | // Add room for the scrollbar | |
1131 | lbWidth += wxSystemSettings::GetMetric( wxSYS_VSCROLL_X ); | |
1132 | ||
1133 | // And just a bit more | |
1134 | int cy = 12; | |
1135 | int cx = ::TextWidth( "X", 0, 1 ); | |
1136 | lbWidth += cx; | |
1137 | ||
1138 | // don't make the listbox too tall (limit height to around 10 items) | |
1139 | // but don't make it too small neither | |
1140 | lbHeight = wxMax( (cy + 4) * wxMin( wxMax( GetCount(), 3 ), 10 ), 70 ); | |
1141 | } | |
1142 | ||
1143 | return wxSize( lbWidth, lbHeight ); | |
1144 | } | |
1145 | ||
1146 | unsigned int wxListBox::GetCount() const | |
1147 | { | |
1148 | return m_noItems; | |
1149 | } | |
1150 | ||
1151 | void wxListBox::Refresh(bool eraseBack, const wxRect *rect) | |
1152 | { | |
1153 | wxControl::Refresh( eraseBack, rect ); | |
1154 | } | |
1155 | ||
1156 | void wxListBox::MacUpdateLine(int n) | |
1157 | { | |
1158 | GetPeer()->UpdateLine(n); | |
1159 | } | |
1160 | ||
1161 | #if wxUSE_OWNER_DRAWN | |
1162 | ||
1163 | class wxListBoxItem : public wxOwnerDrawn | |
1164 | { | |
1165 | public: | |
1166 | wxListBoxItem(const wxString& str = ""); | |
1167 | }; | |
1168 | ||
1169 | wxListBoxItem::wxListBoxItem(const wxString& str) | |
1170 | : wxOwnerDrawn(str, false) | |
1171 | { | |
1172 | // no bitmaps/checkmarks | |
1173 | SetMarginWidth( 0 ); | |
1174 | } | |
1175 | ||
1176 | wxOwnerDrawn *wxListBox::CreateItem(size_t n) | |
1177 | { | |
1178 | return new wxListBoxItem(); | |
1179 | } | |
1180 | ||
1181 | #endif // USE_OWNER_DRAWN | |
1182 | ||
1183 | ||
1184 | // Some custom controls depend on this | |
1185 | /* static */ wxVisualAttributes | |
1186 | wxListBox::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) | |
1187 | { | |
1188 | wxVisualAttributes attr; | |
1189 | ||
1190 | attr.colFg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ); | |
1191 | attr.colBg = wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX ); | |
1192 | attr.font = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ); | |
1193 | ||
1194 | return attr; | |
1195 | } | |
1196 | ||
1197 | int wxListBox::DoListHitTest(const wxPoint& inpoint) const | |
1198 | { | |
1199 | OSStatus err; | |
1200 | ||
1201 | // There are few reasons why this is complicated: | |
1202 | // 1) There is no native HitTest function for Mac | |
1203 | // 2) GetDataBrowserItemPartBounds only works on visible items | |
1204 | // 3) We can't do it through GetDataBrowserTableView[Item]RowHeight | |
1205 | // because what it returns is basically inaccurate in the context | |
1206 | // of the coordinates we want here, but we use this as a guess | |
1207 | // for where the first visible item lies | |
1208 | ||
1209 | wxPoint point = inpoint; | |
1210 | ||
1211 | // interestingly enough 10.2 (and below?) have GetDataBrowserItemPartBounds | |
1212 | // giving root window coordinates but 10.3 and above give client coordinates | |
1213 | // so we only compare using root window coordinates on 10.3 and up | |
1214 | if ( UMAGetSystemVersion() < 0x1030 ) | |
1215 | MacClientToRootWindow(&point.x, &point.y); | |
1216 | ||
1217 | // get column property ID (req. for call to itempartbounds) | |
1218 | DataBrowserTableViewColumnID colId = 0; | |
1219 | err = GetDataBrowserTableViewColumnProperty(m_peer->GetControlRef(), 0, &colId); | |
1220 | wxCHECK_MSG(err == noErr, wxNOT_FOUND, wxT("Unexpected error from GetDataBrowserTableViewColumnProperty")); | |
1221 | ||
1222 | // OK, first we need to find the first visible item we have - | |
1223 | // this will be the "low" for our binary search. There is no real | |
1224 | // easy way around this, as we will need to do a SLOW linear search | |
1225 | // until we find a visible item, but we can do a cheap calculation | |
1226 | // via the row height to speed things up a bit | |
1227 | UInt32 scrollx, scrolly; | |
1228 | err = GetDataBrowserScrollPosition(m_peer->GetControlRef(), &scrollx, &scrolly); | |
1229 | wxCHECK_MSG(err == noErr, wxNOT_FOUND, wxT("Unexpected error from GetDataBrowserScrollPosition")); | |
1230 | ||
1231 | UInt16 height; | |
1232 | err = GetDataBrowserTableViewRowHeight(m_peer->GetControlRef(), &height); | |
1233 | wxCHECK_MSG(err == noErr, wxNOT_FOUND, wxT("Unexpected error from GetDataBrowserTableViewRowHeight")); | |
1234 | ||
1235 | // these indices are 0-based, as usual, so we need to add 1 to them when | |
1236 | // passing them to data browser functions which use 1-based indices | |
1237 | int low = scrolly / height, | |
1238 | high = GetCount() - 1; | |
1239 | ||
1240 | // search for the first visible item (note that the scroll guess above | |
1241 | // is the low bounds of where the item might lie so we only use that as a | |
1242 | // starting point - we should reach it within 1 or 2 iterations of the loop) | |
1243 | while ( low <= high ) | |
1244 | { | |
1245 | Rect bounds; | |
1246 | err = GetDataBrowserItemPartBounds( | |
1247 | m_peer->GetControlRef(), low + 1, colId, | |
1248 | kDataBrowserPropertyEnclosingPart, | |
1249 | &bounds); // note +1 to translate to Mac ID | |
1250 | if ( err == noErr ) | |
1251 | break; | |
1252 | ||
1253 | // errDataBrowserItemNotFound is expected as it simply means that the | |
1254 | // item is not currently visible -- but other errors are not | |
1255 | wxCHECK_MSG( err == errDataBrowserItemNotFound, wxNOT_FOUND, | |
1256 | wxT("Unexpected error from GetDataBrowserItemPartBounds") ); | |
1257 | ||
1258 | low++; | |
1259 | } | |
1260 | ||
1261 | // NOW do a binary search for where the item lies, searching low again if | |
1262 | // we hit an item that isn't visible | |
1263 | while ( low <= high ) | |
1264 | { | |
1265 | int mid = (low + high) / 2; | |
1266 | ||
1267 | Rect bounds; | |
1268 | err = GetDataBrowserItemPartBounds( | |
1269 | m_peer->GetControlRef(), mid + 1, colId, | |
1270 | kDataBrowserPropertyEnclosingPart, | |
1271 | &bounds); //note +1 to trans to mac id | |
1272 | wxCHECK_MSG( err == noErr || err == errDataBrowserItemNotFound, | |
1273 | wxNOT_FOUND, | |
1274 | wxT("Unexpected error from GetDataBrowserItemPartBounds") ); | |
1275 | ||
1276 | if ( err == errDataBrowserItemNotFound ) | |
1277 | { | |
1278 | // item not visible, attempt to find a visible one | |
1279 | // search lower | |
1280 | high = mid - 1; | |
1281 | } | |
1282 | else // visible item, do actual hitttest | |
1283 | { | |
1284 | // if point is within the bounds, return this item (since we assume | |
1285 | // all x coords of items are equal we only test the x coord in | |
1286 | // equality) | |
1287 | if ((point.x >= bounds.left && point.x <= bounds.right) && | |
1288 | (point.y >= bounds.top && point.y <= bounds.bottom) ) | |
1289 | { | |
1290 | // found! | |
1291 | return mid; | |
1292 | } | |
1293 | ||
1294 | if ( point.y < bounds.top ) | |
1295 | // index(bounds) greater then key(point) | |
1296 | high = mid - 1; | |
1297 | else | |
1298 | // index(bounds) less then key(point) | |
1299 | low = mid + 1; | |
1300 | } | |
1301 | } | |
1302 | ||
1303 | return wxNOT_FOUND; | |
1304 | } | |
1305 | ||
1306 | #endif |