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