1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/carbon/listbox.cpp
4 // Author: Stefan Csomor
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.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"
27 IMPLEMENT_DYNAMIC_CLASS(wxListBox
, wxControl
)
29 BEGIN_EVENT_TABLE(wxListBox
, wxControl
)
32 #include "wx/mac/uma.h"
34 // common interface for all implementations
35 class wxMacListControl
: public wxMacControl
38 wxMacListControl( wxListBox
*peer
) :
47 virtual void UpdateLine( int n
) = 0;
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;
62 wxListBox
* GetPeer() const
64 return (wxListBox
*) m_peer
;
69 // In case we have to replace data browser ...
70 // custom HIView based implementation
72 class wxMacCustomHIViewListControl
: public wxMacListControl
75 wxMacCustomHIViewListControl( wxListBox
*peer
, const wxPoint
& pos
, const wxSize
& size
, long style
);
76 ~wxMacCustomHIViewListControl();
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
);
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
);
93 // data browser based implementation
95 class wxMacDataBrowserListControl
: public wxMacListControl
98 wxMacDataBrowserListControl( wxListBox
*peer
, const wxPoint
& pos
, const wxSize
& size
, long style
);
99 ~wxMacDataBrowserListControl();
101 void UpdateLine( int n
);
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
);
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
);
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
);
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 bool m_suppressSelection
;
150 #if TARGET_API_MAC_OSX
151 static pascal void DataBrowserItemNotificationProc(ControlRef browser
, DataBrowserItemID itemID
,
152 DataBrowserItemNotification message
, DataBrowserItemDataRef itemData
);
154 static pascal void DataBrowserItemNotificationProc(ControlRef browser
, DataBrowserItemID itemID
,
155 DataBrowserItemNotification message
);
159 // ============================================================================
160 // data browser based implementation
161 // ============================================================================
163 const short kTextColumnId
= 1024;
164 const short kCheckboxColumnId
= 1025;
166 // new databrowserbased version
167 // because of the limited insert
168 // functionality of DataBrowser,
169 // we just introduce id s corresponding
170 // to the line number
172 DataBrowserItemDataUPP gDataBrowserItemDataUPP
= NULL
;
173 DataBrowserItemNotificationUPP gDataBrowserItemNotificationUPP
= NULL
;
175 #if TARGET_API_MAC_OSX
176 pascal void wxMacDataBrowserListControl
::DataBrowserItemNotificationProc(ControlRef browser
, DataBrowserItemID itemID
,
177 DataBrowserItemNotification message
, DataBrowserItemDataRef itemData
)
179 pascal void wxMacDataBrowserListControl
::DataBrowserItemNotificationProc(ControlRef browser
, DataBrowserItemID itemID
,
180 DataBrowserItemNotification message
)
183 long ref
= GetControlReference( browser
);
186 wxListBox
* list
= wxDynamicCast( (wxObject
*) ref
, wxListBox
);
187 wxMacDataBrowserListControl
* peer
= (wxMacDataBrowserListControl
*) list
->GetPeer();
190 if (i
>= 0 && i
< (int)list
->GetCount() )
192 bool trigger
= false;
193 wxCommandEvent
event( wxEVT_COMMAND_LISTBOX_SELECTED
, list
->GetId() );
196 case kDataBrowserItemDeselected
:
197 if ( list
->HasMultipleSelection() )
198 trigger
= !peer
->MacIsSelectionSuppressed();
201 case kDataBrowserItemSelected
:
202 trigger
= !peer
->MacIsSelectionSuppressed();
205 case kDataBrowserItemDoubleClicked
:
206 event
.SetEventType( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
);
216 event
.SetEventObject( list
);
217 if ( list
->HasClientObjectData() )
218 event
.SetClientObject( list
->GetClientObject( i
) );
219 else if ( list
->HasClientUntypedData() )
220 event
.SetClientData( list
->GetClientData( i
) );
221 event
.SetString( list
->GetString( i
) );
223 event
.SetExtraLong( list
->HasMultipleSelection() ? message
== kDataBrowserItemSelected
: true );
224 wxPostEvent( list
->GetEventHandler() , event
);
225 // direct notification is not always having the listbox GetSelection() having in synch with event
226 // list->GetEventHandler()->ProcessEvent(event);
232 static pascal OSStatus
ListBoxGetSetItemData(ControlRef browser
,
233 DataBrowserItemID itemID
, DataBrowserPropertyID property
,
234 DataBrowserItemDataRef itemData
, Boolean changeValue
)
236 OSStatus err
= errDataBrowserPropertyNotSupported
;
238 long ref
= GetControlReference( browser
);
242 wxListBox
* list
= wxDynamicCast( (wxObject
*) ref
, wxListBox
);
243 bool isCheckList
= false;
245 isCheckList
= list
->IsKindOf( CLASSINFO(wxCheckListBox
));
254 if (i
>= 0 && i
< (int)list
->GetCount() )
256 wxMacCFStringHolder
cf( list
->GetString( i
) , list
->GetFont().GetEncoding() );
257 verify_noerr( ::SetDataBrowserItemDataText( itemData
, cf
) );
264 case kCheckboxColumnId
:
268 wxCheckListBox
* list
= wxDynamicCast( (wxObject
*) ref
, wxCheckListBox
);
270 if (i
>= 0 && (unsigned int) i
< list
->GetCount() )
272 verify_noerr( ::SetDataBrowserItemDataButtonValue( itemData
, list
->IsChecked( i
) ? kThemeButtonOn
: kThemeButtonOff
) );
278 case kDataBrowserItemIsEditableProperty
:
281 err
= ::SetDataBrowserItemDataBooleanValue(itemData
, true);
293 case kCheckboxColumnId
:
297 wxCheckListBox
* list
= wxDynamicCast( (wxObject
*) ref
, wxCheckListBox
);
299 if (i
>= 0 && (unsigned int)i
< list
->GetCount() )
301 // we have to change this behind the back, since Check() would be triggering another update round
302 bool newVal
= !list
->IsChecked( i
);
303 verify_noerr( ::SetDataBrowserItemDataButtonValue( itemData
, newVal ? kThemeButtonOn
: kThemeButtonOff
) );
305 list
->m_checks
[ i
] = newVal
;
307 wxCommandEvent
event(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED
, list
->GetId());
309 event
.SetEventObject(list
);
310 list
->GetEventHandler()->ProcessEvent(event
);
325 wxMacDataBrowserListControl
::wxMacDataBrowserListControl( wxListBox
*peer
, const wxPoint
& pos
, const wxSize
& size
, long style
) :
326 wxMacListControl( peer
)
328 bool isCheckList
= peer
->IsKindOf( CLASSINFO(wxCheckListBox
));
330 m_suppressSelection
= false;
331 Rect bounds
= wxMacGetBoundsForControl( peer
, pos
, size
);
332 verify_noerr( ::CreateDataBrowserControl( MAC_WXHWND(peer
->MacGetTopLevelWindowRef()), &bounds
, kDataBrowserListView
, &m_controlRef
) );
334 DataBrowserSelectionFlags options
= kDataBrowserDragSelect
;
335 if ( style
& wxLB_MULTIPLE
)
337 options
+= kDataBrowserAlwaysExtendSelection
+ kDataBrowserCmdTogglesSelection
;
339 else if ( style
& wxLB_EXTENDED
)
345 options
+= kDataBrowserSelectOnlyOne
;
347 verify_noerr(SetSelectionFlags( options
) );
349 if ( gDataBrowserItemDataUPP
== NULL
) gDataBrowserItemDataUPP
= NewDataBrowserItemDataUPP(ListBoxGetSetItemData
);
350 if ( gDataBrowserItemNotificationUPP
== NULL
)
352 gDataBrowserItemNotificationUPP
=
353 #if TARGET_API_MAC_OSX
354 (DataBrowserItemNotificationUPP
) NewDataBrowserItemNotificationWithItemUPP(DataBrowserItemNotificationProc
);
356 NewDataBrowserItemNotificationUPP(DataBrowserItemNotificationProc
);
360 DataBrowserCallbacks callbacks
;
361 InitializeDataBrowserCallbacks( &callbacks
, kDataBrowserLatestCallbacks
);
363 callbacks
.u
.v1
.itemDataCallback
= gDataBrowserItemDataUPP
;
364 callbacks
.u
.v1
.itemNotificationCallback
= gDataBrowserItemNotificationUPP
;
365 SetCallbacks( &callbacks
);
367 DataBrowserListViewColumnDesc columnDesc
;
368 columnDesc
.headerBtnDesc
.titleOffset
= 0;
369 columnDesc
.headerBtnDesc
.version
= kDataBrowserListViewLatestHeaderDesc
;
371 columnDesc
.headerBtnDesc
.btnFontStyle
.flags
=
372 kControlUseFontMask
| kControlUseJustMask
;
374 columnDesc
.headerBtnDesc
.btnContentInfo
.contentType
= kControlNoContent
;
375 columnDesc
.headerBtnDesc
.btnFontStyle
.just
= teFlushDefault
;
376 columnDesc
.headerBtnDesc
.btnFontStyle
.font
= kControlFontViewSystemFont
;
377 columnDesc
.headerBtnDesc
.btnFontStyle
.style
= normal
;
378 columnDesc
.headerBtnDesc
.titleString
= NULL
;
382 columnDesc
.headerBtnDesc
.minimumWidth
= 30;
383 columnDesc
.headerBtnDesc
.maximumWidth
= 30;
385 columnDesc
.propertyDesc
.propertyID
= kCheckboxColumnId
;
386 columnDesc
.propertyDesc
.propertyType
= kDataBrowserCheckboxType
;
387 columnDesc
.propertyDesc
.propertyFlags
= kDataBrowserPropertyIsMutable
| kDataBrowserTableViewSelectionColumn
|
388 kDataBrowserDefaultPropertyFlags
;
389 verify_noerr(AddListViewColumn( &columnDesc
, kDataBrowserListViewAppendColumn
) );
392 columnDesc
.headerBtnDesc
.minimumWidth
= 0;
393 columnDesc
.headerBtnDesc
.maximumWidth
= 10000;
396 columnDesc
.propertyDesc
.propertyID
= kTextColumnId
;
397 columnDesc
.propertyDesc
.propertyType
= kDataBrowserTextType
;
398 columnDesc
.propertyDesc
.propertyFlags
=
399 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
400 kDataBrowserListViewTypeSelectColumn
|
402 kDataBrowserTableViewSelectionColumn
;
404 verify_noerr(AddListViewColumn( &columnDesc
, kDataBrowserListViewAppendColumn
) );
405 verify_noerr(AutoSizeListViewColumns() );
406 verify_noerr(SetHasScrollBars(false , true ) );
407 verify_noerr(SetTableViewHiliteStyle(kDataBrowserTableViewFillHilite
) );
408 verify_noerr(SetListViewHeaderBtnHeight( 0 ) );
411 // shouldn't be necessary anymore under 10.2
412 m_peer
->SetData( kControlNoPart
, kControlDataBrowserIncludesFrameAndFocusTag
, (Boolean
) false );
413 m_peer
->SetNeedsFocusRect( true );
416 wxMacDataBrowserListControl
::~wxMacDataBrowserListControl()
421 void wxMacDataBrowserListControl
::MacDelete( int n
)
423 wxArrayInt selectionBefore
;
424 MacGetSelections( selectionBefore
);
426 UInt32 id
= GetPeer()->GetCount()+1;
427 verify_noerr( RemoveItems( kDataBrowserNoItem
, 1 , (UInt32
*) &id
, kDataBrowserItemNoProperty
) );
428 for ( size_t i
= 0; i
< selectionBefore
.GetCount(); ++i
)
430 int current
= selectionBefore
[i
];
433 // selection was deleted
434 MacSetSelection( current
, false );
436 else if ( current
> n
)
438 // something behind the deleted item was selected -> move up
439 MacSetSelection( current
- 1 , true );
440 MacSetSelection( current
, false );
444 verify_noerr( UpdateItems( kDataBrowserNoItem
, 1 , (UInt32
*) kDataBrowserNoItem
, kDataBrowserItemNoProperty
, kDataBrowserItemNoProperty
) );
447 void wxMacDataBrowserListControl
::MacInsert( int n
, const wxString
& text
)
449 wxArrayInt selectionBefore
;
450 MacGetSelections( selectionBefore
);
452 UInt32 id
= GetPeer()->GetCount(); // this has already been increased
453 verify_noerr( AddItems( kDataBrowserNoItem
, 1 , (UInt32
*) &id
, kDataBrowserItemNoProperty
) );
455 for ( int i
= selectionBefore
.GetCount()-1; i
>= 0; --i
)
457 int current
= selectionBefore
[i
];
460 MacSetSelection( current
+ 1 , true );
461 MacSetSelection( current
, false );
466 verify_noerr( UpdateItems( kDataBrowserNoItem
, 1 , (UInt32
*) kDataBrowserNoItem
, kDataBrowserItemNoProperty
, kDataBrowserItemNoProperty
) );
469 void wxMacDataBrowserListControl
::MacInsert( int n
, const wxArrayString
& items
)
471 wxArrayInt selectionBefore
;
472 MacGetSelections( selectionBefore
);
473 size_t itemsCount
= items
.GetCount();
475 UInt32
*ids
= new UInt32
[itemsCount
];
476 for ( unsigned int i
= 0; i
< itemsCount
;++i
)
477 ids
[i
] = GetPeer()->GetCount() - itemsCount
+ i
+ 1;
479 verify_noerr( AddItems( kDataBrowserNoItem
, itemsCount
, ids
, kDataBrowserItemNoProperty
) );
482 for ( int i
= selectionBefore
.GetCount()-1; i
>= 0; --i
)
484 int current
= selectionBefore
[i
];
487 MacSetSelection( current
+ 1 , true );
488 MacSetSelection( current
, false );
493 verify_noerr( UpdateItems( kDataBrowserNoItem
, 1 , (UInt32
*) kDataBrowserNoItem
, kDataBrowserItemNoProperty
, kDataBrowserItemNoProperty
) );
496 void wxMacDataBrowserListControl
::MacAppend( const wxString
& text
)
498 UInt32 id
= GetPeer()->GetCount(); // this has already been increased
499 verify_noerr( AddItems( kDataBrowserNoItem
, 1 , (UInt32
*) &id
, kDataBrowserItemNoProperty
) );
500 // no need to deal with selections nor refreshed, as we have appended
503 void wxMacDataBrowserListControl
::MacClear()
505 verify_noerr( RemoveItems( kDataBrowserNoItem
, 0 , NULL
, kDataBrowserItemNoProperty
) );
508 void wxMacDataBrowserListControl
::MacDeselectAll()
510 bool former
= MacSuppressSelection( true );
511 verify_noerr(SetSelectedItems( 0 , NULL
, kDataBrowserItemsRemove
) );
512 MacSuppressSelection( former
);
515 void wxMacDataBrowserListControl
::MacSetSelection( int n
, bool select
)
517 bool former
= MacSuppressSelection( true );
520 if ( IsItemSelected( id
) != select
)
523 verify_noerr(SetSelectedItems( 1 , & id
, GetPeer()->HasMultipleSelection() ? kDataBrowserItemsAdd
: kDataBrowserItemsAssign
) );
525 verify_noerr(SetSelectedItems( 1 , & id
, kDataBrowserItemsRemove
) );
528 MacSuppressSelection( former
);
531 bool wxMacDataBrowserListControl
::MacSuppressSelection( bool suppress
)
533 bool former
= m_suppressSelection
;
534 m_suppressSelection
= suppress
;
538 bool wxMacDataBrowserListControl
::MacIsSelected( int n
) const
540 return IsItemSelected( n
+ 1 );
543 int wxMacDataBrowserListControl
::MacGetSelection() const
545 for ( unsigned int i
= 0; i
< GetPeer()->GetCount(); ++i
)
547 if ( IsItemSelected( i
+ 1 ) )
555 int wxMacDataBrowserListControl
::MacGetSelections( wxArrayInt
& aSelections
) const
562 GetSelectionAnchor( &first
, &last
);
563 if ( first
!= kDataBrowserNoItem
)
565 for ( size_t i
= first
; i
<= last
; ++i
)
567 if ( IsItemSelected( i
) )
569 aSelections
.Add( i
- 1 );
577 void wxMacDataBrowserListControl
::MacSet( int n
, const wxString
& text
)
579 // as we don't store the strings we only have to issue a redraw
581 verify_noerr( UpdateItems( kDataBrowserNoItem
, 1 , &id
, kDataBrowserItemNoProperty
, kDataBrowserItemNoProperty
) );
584 void wxMacDataBrowserListControl
::MacScrollTo( int n
)
587 verify_noerr( RevealItem( id
, kTextColumnId
, kDataBrowserRevealWithoutSelecting
) );
590 void wxMacDataBrowserListControl
::UpdateLine( int n
)
593 verify_noerr( UpdateItems(kDataBrowserNoItem
, 1 , &id
, kDataBrowserItemNoProperty
, kDataBrowserItemNoProperty
) );
600 OSStatus wxMacDataBrowserListControl
::SetSelectionFlags( DataBrowserSelectionFlags options
)
602 return SetDataBrowserSelectionFlags( m_controlRef
, options
);
605 OSStatus wxMacDataBrowserListControl
::AddListViewColumn( DataBrowserListViewColumnDesc
*columnDesc
,
606 DataBrowserTableViewColumnIndex position
)
608 return AddDataBrowserListViewColumn( m_controlRef
, columnDesc
, position
);
611 OSStatus wxMacDataBrowserListControl
::AutoSizeListViewColumns()
613 return AutoSizeDataBrowserListViewColumns(m_controlRef
);
616 OSStatus wxMacDataBrowserListControl
::SetHasScrollBars( bool horiz
, bool vert
)
618 return SetDataBrowserHasScrollBars( m_controlRef
, horiz
, vert
);
621 OSStatus wxMacDataBrowserListControl
::SetTableViewHiliteStyle( DataBrowserTableViewHiliteStyle hiliteStyle
)
623 return SetDataBrowserTableViewHiliteStyle( m_controlRef
, hiliteStyle
);
626 OSStatus wxMacDataBrowserListControl
::SetListViewHeaderBtnHeight(UInt16 height
)
628 return SetDataBrowserListViewHeaderBtnHeight( m_controlRef
,height
);
631 OSStatus wxMacDataBrowserListControl
::SetCallbacks(const DataBrowserCallbacks
* callbacks
)
633 return SetDataBrowserCallbacks( m_controlRef
, callbacks
);
636 OSStatus wxMacDataBrowserListControl
::UpdateItems( DataBrowserItemID container
, UInt32 numItems
,
637 const DataBrowserItemID
* items
,
638 DataBrowserPropertyID preSortProperty
,
639 DataBrowserPropertyID propertyID
)
641 return UpdateDataBrowserItems( m_controlRef
, container
, numItems
, items
, preSortProperty
, propertyID
);
644 bool wxMacDataBrowserListControl
::IsItemSelected( DataBrowserItemID item
) const
646 return IsDataBrowserItemSelected( m_controlRef
, item
);
649 OSStatus wxMacDataBrowserListControl
::AddItems( DataBrowserItemID container
, UInt32 numItems
,
650 const DataBrowserItemID
* items
,
651 DataBrowserPropertyID preSortProperty
)
653 return AddDataBrowserItems( m_controlRef
, container
, numItems
, items
, preSortProperty
);
656 OSStatus wxMacDataBrowserListControl
::RemoveItems( DataBrowserItemID container
, UInt32 numItems
,
657 const DataBrowserItemID
* items
,
658 DataBrowserPropertyID preSortProperty
)
660 return RemoveDataBrowserItems( m_controlRef
, container
, numItems
, items
, preSortProperty
);
663 OSStatus wxMacDataBrowserListControl
::RevealItem( DataBrowserItemID item
,
664 DataBrowserPropertyID propertyID
,
665 DataBrowserRevealOptions options
)
667 return RevealDataBrowserItem( m_controlRef
, item
, propertyID
, options
);
670 OSStatus wxMacDataBrowserListControl
::SetSelectedItems(UInt32 numItems
,
671 const DataBrowserItemID
* items
,
672 DataBrowserSetOption operation
)
674 return SetDataBrowserSelectedItems( m_controlRef
, numItems
, items
, operation
);
677 OSStatus wxMacDataBrowserListControl
::GetSelectionAnchor( DataBrowserItemID
* first
, DataBrowserItemID
* last
) const
679 return GetDataBrowserSelectionAnchor( m_controlRef
, first
, last
);
684 // in case we need that one day
686 // ============================================================================
687 // HIView owner draw based implementation
688 // ============================================================================
690 static pascal void ListBoxDrawProc( ControlRef browser
, DataBrowserItemID item
, DataBrowserPropertyID property
,
691 DataBrowserItemState itemState
, const Rect
*itemRect
, SInt16 depth
, Boolean isColorDevice
)
693 CFStringRef cfString
;
694 ThemeDrawingState themeState
;
697 GetThemeDrawingState( &themeState
);
698 cfString
= CFStringCreateWithFormat( NULL
, NULL
, CFSTR("Row %d"), item
);
700 // In this sample we handle the "selected" state; all others fall through to our "active" state
701 if ( itemState
== kDataBrowserItemIsSelected
)
703 ThemeBrush colorBrushID
;
705 Gestalt( gestaltSystemVersion
, &systemVersion
);
707 // TODO: switch over to wxSystemSettingsNative::GetColour() when kThemeBrushSecondaryHighlightColor is incorporated
708 // Panther DB starts using kThemeBrushSecondaryHighlightColor for inactive browser hilighting
709 if ( (systemVersion
>= 0x00001030) && !IsControlActive( browser
) )
710 colorBrushID
= kThemeBrushSecondaryHighlightColor
;
712 colorBrushID
= kThemeBrushPrimaryHighlightColor
;
714 // First paint the hilite rect, then the text on top
715 SetThemePen( colorBrushID
, 32, true );
716 PaintRect( itemRect
);
717 SetThemeDrawingState( themeState
, false );
720 DrawThemeTextBox( cfString
, kThemeApplicationFont
, kThemeStateActive
, true, itemRect
, teFlushDefault
, NULL
);
721 SetThemeDrawingState( themeState
, true );
723 if ( cfString
!= NULL
)
724 CFRelease( cfString
);
729 // ============================================================================
730 // list box control implementation
731 // ============================================================================
733 wxListBox
::wxListBox()
738 bool wxListBox
::Create(wxWindow
*parent
,
742 const wxArrayString
& choices
,
744 const wxValidator
& validator
,
745 const wxString
& name
)
747 wxCArrayString
chs(choices
);
749 return Create(parent
, id
, pos
, size
, chs
.GetCount(), chs
.GetStrings(),
750 style
, validator
, name
);
753 bool wxListBox
::Create(wxWindow
*parent
,
758 const wxString choices
[],
760 const wxValidator
& validator
,
761 const wxString
& name
)
763 m_macIsUserPane
= false;
765 wxASSERT_MSG( !(style
& wxLB_MULTIPLE
) || !(style
& wxLB_EXTENDED
),
766 _T("only one of listbox selection modes can be specified") );
768 if ( !wxListBoxBase
::Create(parent
, id
, pos
, size
, style
& ~(wxHSCROLL
|wxVSCROLL
), validator
, name
) )
771 m_noItems
= 0; // this will be increased by our append command
773 m_peer
= CreateMacListControl(pos
, size
, style
);
775 MacPostControlCreate(pos
,size
);
777 InsertItems( n
, choices
, 0 );
779 SetBestSize(size
); // Needed because it is a wxControlWithItems
784 wxListBox
::~wxListBox()
786 m_peer
->SetReference( 0 );
790 wxMacListControl
* wxListBox
::CreateMacListControl(const wxPoint
& pos
, const wxSize
& size
, long style
)
792 return new wxMacDataBrowserListControl(this , pos
, size
, style
);
795 void wxListBox
::FreeData()
797 #if wxUSE_OWNER_DRAWN
798 if ( m_windowStyle
& wxLB_OWNERDRAW
)
800 size_t uiCount
= m_aItems
.Count();
801 while ( uiCount
-- != 0 ) {
802 delete m_aItems
[uiCount
];
803 m_aItems
[uiCount
] = NULL
;
809 #endif // wxUSE_OWNER_DRAWN
810 if ( HasClientObjectData() )
812 for ( unsigned int n
= 0; n
< m_noItems
; n
++ )
814 delete GetClientObject( n
);
819 void wxListBox
::DoSetSize(int x
, int y
,
820 int width
, int height
,
823 wxControl
::DoSetSize( x
, y
, width
, height
, sizeFlags
);
826 void wxListBox
::DoSetFirstItem(int n
)
828 GetPeer()->MacScrollTo( n
);
831 void wxListBox
::Delete(unsigned int n
)
833 wxCHECK_RET( IsValid(n
),
834 wxT("invalid index in wxListBox::Delete") );
836 #if wxUSE_OWNER_DRAWN
838 m_aItems
.RemoveAt(n
);
839 #else // !wxUSE_OWNER_DRAWN
840 if ( HasClientObjectData() )
842 delete GetClientObject(n
);
844 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
845 m_stringArray
.RemoveAt( n
);
846 m_dataArray
.RemoveAt( n
);
849 GetPeer()->MacDelete( n
);
852 int wxListBox
::DoAppend(const wxString
& item
)
854 InvalidateBestSize();
856 unsigned int index
= m_noItems
;
857 m_stringArray
.Add( item
);
858 m_dataArray
.Add( NULL
);
860 DoSetItemClientData( index
, NULL
);
861 GetPeer()->MacAppend( item
);
866 void wxListBox
::DoSetItems(const wxArrayString
& choices
, void** clientData
)
869 unsigned int n
= choices
.GetCount();
871 for ( size_t i
= 0; i
< n
; ++i
)
875 #if wxUSE_OWNER_DRAWN
876 wxASSERT_MSG(clientData
[i
] == NULL
,
877 wxT("Can't use client data with owner-drawn listboxes"));
878 #else // !wxUSE_OWNER_DRAWN
879 Append( choices
[i
] , clientData
[i
] );
883 Append( choices
[i
] );
886 #if wxUSE_OWNER_DRAWN
887 if ( m_windowStyle
& wxLB_OWNERDRAW
) {
888 // first delete old items
889 size_t ui
= m_aItems
.Count();
890 while ( ui
-- != 0 ) {
896 // then create new ones
897 for ( ui
= 0; ui
< (size_t)m_noItems
; ui
++ ) {
898 wxOwnerDrawn
*pNewItem
= CreateItem(ui
);
899 pNewItem
->SetName(choices
[ui
]);
900 m_aItems
.Add(pNewItem
);
903 #endif // wxUSE_OWNER_DRAWN
906 int wxListBox
::FindString(const wxString
& s
, bool bCase
) const
908 for ( size_t i
= 0; i
< m_noItems
; ++ i
)
910 if (s
.IsSameAs(GetString(i
), bCase
))
917 void wxListBox
::Clear()
921 m_stringArray
.Empty();
923 GetPeer()->MacClear();
926 void wxListBox
::DoSetSelection(int n
, bool select
)
928 wxCHECK_RET( n
== wxNOT_FOUND
|| IsValid(n
) ,
929 wxT("invalid index in wxListBox::SetSelection") );
931 if ( n
== wxNOT_FOUND
)
932 GetPeer()->MacDeselectAll();
934 GetPeer()->MacSetSelection( n
, select
);
937 bool wxListBox
::IsSelected(int n
) const
939 wxCHECK_MSG( IsValid(n
), false,
940 wxT("invalid index in wxListBox::Selected") );
942 return GetPeer()->MacIsSelected( n
);
945 void *wxListBox
::DoGetItemClientData(unsigned int n
) const
947 wxCHECK_MSG( IsValid(n
), NULL
, wxT("invalid index in wxListBox::GetClientData"));
949 wxASSERT_MSG( m_dataArray
.GetCount() >= (unsigned int) n
, wxT("invalid client_data array") );
951 return (void *)m_dataArray
[n
];
954 wxClientData
*wxListBox
::DoGetItemClientObject(unsigned int n
) const
956 return (wxClientData
*) DoGetItemClientData( n
);
959 void wxListBox
::DoSetItemClientData(unsigned int n
, void *clientData
)
961 wxCHECK_RET( IsValid(n
), wxT("invalid index in wxListBox::SetClientData") );
963 #if wxUSE_OWNER_DRAWN
964 if ( m_windowStyle
& wxLB_OWNERDRAW
)
966 // client data must be pointer to wxOwnerDrawn, otherwise we would crash
967 // in OnMeasure/OnDraw.
968 wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes"));
970 #endif // wxUSE_OWNER_DRAWN
971 wxASSERT_MSG( m_dataArray
.GetCount() >= (unsigned int) n
, wxT("invalid client_data array") );
973 if ( m_dataArray
.GetCount() > (unsigned int) n
)
974 m_dataArray
[n
] = (char*)clientData
;
976 m_dataArray
.Add( (char*)clientData
);
979 void wxListBox
::DoSetItemClientObject(unsigned int n
, wxClientData
* clientData
)
981 DoSetItemClientData(n
, clientData
);
984 // Return number of selections and an array of selected integers
985 int wxListBox
::GetSelections(wxArrayInt
& aSelections
) const
987 return GetPeer()->MacGetSelections( aSelections
);
990 // Get single selection, for single choice list items
991 int wxListBox
::GetSelection() const
993 return GetPeer()->MacGetSelection();
996 // Find string for position
997 wxString wxListBox
::GetString(unsigned int n
) const
999 wxCHECK_MSG( IsValid(n
), wxEmptyString
,
1000 wxT("invalid index in wxListBox::GetString") );
1002 return m_stringArray
[n
] ;
1005 void wxListBox
::DoInsertItems(const wxArrayString
& items
, unsigned int pos
)
1007 wxCHECK_RET( IsValidInsert(pos
),
1008 wxT("invalid index in wxListBox::InsertItems") );
1010 InvalidateBestSize();
1012 unsigned int nItems
= items
.GetCount();
1014 for ( unsigned int i
= 0; i
< nItems
; i
++ )
1015 m_stringArray
.Insert( items
[i
] , pos
+i
);
1016 m_dataArray
.Insert( NULL
, pos
, nItems
);
1017 m_noItems
+= nItems
;
1018 GetPeer()->MacInsert( pos
, items
);
1021 void wxListBox
::SetString(unsigned int n
, const wxString
& s
)
1023 m_stringArray
[n
] = s
;
1024 GetPeer()->MacSet( n
, s
);
1027 wxSize wxListBox
::DoGetBestSize() const
1029 int lbWidth
= 100; // some defaults
1034 wxMacPortStateHelper
st( UMAGetWindowPort( (WindowRef
)MacGetTopLevelWindowRef() ) );
1036 // TODO: clean this up
1039 ::TextFont( m_font
.MacGetFontNum() );
1040 ::TextSize( m_font
.MacGetFontSize() );
1041 ::TextFace( m_font
.MacGetFontStyle() );
1045 ::TextFont( kFontIDMonaco
);
1050 // Find the widest line
1051 for (unsigned int i
= 0; i
< GetCount(); i
++)
1053 wxString
str(GetString(i
));
1056 Point bounds
= {0, 0};
1059 // NB: what if m_font.Ok() == false ???
1060 ::GetThemeTextDimensions(
1061 wxMacCFStringHolder( str
, m_font
.GetEncoding() ) ,
1062 kThemeCurrentPortFont
,
1069 wLine
= ::TextWidth( str
.c_str() , 0 , str
.length() );
1072 lbWidth
= wxMax( lbWidth
, wLine
);
1075 // Add room for the scrollbar
1076 lbWidth
+= wxSystemSettings
::GetMetric(wxSYS_VSCROLL_X
);
1078 // And just a bit more
1080 int cx
= ::TextWidth( "X" , 0 , 1 );
1083 // don't make the listbox too tall (limit height to around 10 items)
1084 // but don't make it too small neither
1085 lbHeight
= wxMax( (cy
+ 4) * wxMin( wxMax( GetCount(), 3 ), 10 ), 70 );
1088 return wxSize( lbWidth
, lbHeight
);
1091 unsigned int wxListBox
::GetCount() const
1096 void wxListBox
::Refresh(bool eraseBack
, const wxRect
*rect
)
1098 wxControl
::Refresh( eraseBack
, rect
);
1101 void wxListBox
::MacUpdateLine( int n
)
1103 GetPeer()->UpdateLine(n
);
1106 #if wxUSE_OWNER_DRAWN
1108 class wxListBoxItem
: public wxOwnerDrawn
1111 wxListBoxItem(const wxString
& str
= "");
1114 wxListBoxItem
::wxListBoxItem(const wxString
& str
) : wxOwnerDrawn(str
, FALSE
)
1116 // no bitmaps/checkmarks
1120 wxOwnerDrawn
*wxListBox
::CreateItem(size_t n
)
1122 return new wxListBoxItem();
1125 #endif //USE_OWNER_DRAWN
1128 // Some custom controls depend on this
1129 /* static */ wxVisualAttributes
1130 wxListBox
::GetClassDefaultAttributes(wxWindowVariant
WXUNUSED(variant
))
1132 wxVisualAttributes attr
;
1134 attr
.colFg
= wxSystemSettings
::GetColour( wxSYS_COLOUR_WINDOWTEXT
);
1135 attr
.colBg
= wxSystemSettings
::GetColour( wxSYS_COLOUR_LISTBOX
);
1136 attr
.font
= wxSystemSettings
::GetFont( wxSYS_DEFAULT_GUI_FONT
);
1141 int wxListBox
::DoListHitTest(const wxPoint
& inpoint
) const
1145 // There are few reasons why this is complicated:
1146 // 1) There is no native hittest function for mac
1147 // 2) GetDataBrowserItemPartBounds only works on visible items
1148 // 3) We can't do it through GetDataBrowserTableView[Item]RowHeight
1149 // because what it returns is basically inaccurate in the context
1150 // of the coordinates we want here, but we use this as a guess
1151 // for where the first visible item lies
1153 wxPoint point
= inpoint
;
1154 // interestingly enough 10.2 (and below?) have GetDataBrowserItemPartBounds
1155 // giving root window coordinates but 10.3 and above give client coordinates
1156 // so we only compare using root window coordinates on 10.3 and up
1157 if ( UMAGetSystemVersion() < 0x1030 )
1158 MacClientToRootWindow(&point
.x
, &point
.y
);
1160 // get column property id (req. for call to itempartbounds)
1161 DataBrowserTableViewColumnID colId
= 0;
1162 err
= GetDataBrowserTableViewColumnProperty(m_peer
->GetControlRef(), 0, &colId
);
1163 wxCHECK_MSG(err
== noErr
, wxNOT_FOUND
, wxT("Unexpected error from GetDataBrowserTableViewColumnProperty"));
1165 // OK, first we need to find the first visible item we have -
1166 // this will be the "low" for our binary search. There is no real
1167 // easy way around this, as we will need to do a SLOW linear search
1168 // until we find a visible item, but we can do a cheap calculation
1169 // via the row height to speed things up a bit
1170 UInt32 scrollx
, scrolly
;
1171 err
= GetDataBrowserScrollPosition(m_peer
->GetControlRef(), &scrollx
, &scrolly
);
1172 wxCHECK_MSG(err
== noErr
, wxNOT_FOUND
, wxT("Unexpected error from GetDataBrowserScrollPosition"));
1175 err
= GetDataBrowserTableViewRowHeight(m_peer
->GetControlRef(), &height
);
1176 wxCHECK_MSG(err
== noErr
, wxNOT_FOUND
, wxT("Unexpected error from GetDataBrowserTableViewRowHeight"));
1178 // these indices are 0-based, as usual, so we need to add 1 to them when
1179 // passing them to data browser functions which use 1-based indices
1180 int low
= scrolly
/ height
,
1181 high
= GetCount() - 1;
1184 // search for the first visible item (note that the scroll guess above
1185 // is the low bounds of where the item might lie so we only use that as a
1186 // starting point - we should reach it within 1 or 2 iterations of the loop)
1187 while ( low
<= high
)
1190 err
= GetDataBrowserItemPartBounds(m_peer
->GetControlRef(), low
+ 1, colId
,
1191 kDataBrowserPropertyEnclosingPart
,
1192 &bounds
); //note +1 to trans to mac id
1196 // errDataBrowserItemNotFound is expected as it simply means that the
1197 // item is not currently visible -- but other errors are not
1198 wxCHECK_MSG( err
== errDataBrowserItemNotFound
, wxNOT_FOUND
,
1199 wxT("Unexpected error from GetDataBrowserItemPartBounds") );
1204 // NOW do a binary search for where the item lies, searching low again if
1205 // we hit an item that isn't visible
1206 while ( low
<= high
)
1208 int mid
= (low
+ high
) / 2;
1211 err
= GetDataBrowserItemPartBounds(m_peer
->GetControlRef(), mid
+ 1, colId
,
1212 kDataBrowserPropertyEnclosingPart
,
1213 &bounds
); //note +1 to trans to mac id
1214 wxCHECK_MSG( err
== noErr
|| err
== errDataBrowserItemNotFound
,
1216 wxT("Unexpected error from GetDataBrowserItemPartBounds") );
1218 if ( err
== errDataBrowserItemNotFound
)
1220 // item not visible, attempt to find a visible one
1221 high
= mid
- 1; // search lower
1223 else // visible item, do actual hitttest
1225 // if point is within the bounds, return this item (since we assume
1226 // all x coords of items are equal we only test the x coord in
1228 if( (point
.x
>= bounds
.left
&& point
.x
<= bounds
.right
) &&
1229 (point
.y
>= bounds
.top
&& point
.y
<= bounds
.bottom
) )
1231 return mid
; // found!
1234 if ( point
.y
< bounds
.top
)
1235 high
= mid
- 1; // index(bounds) greater then key(point)
1237 low
= mid
+ 1; // index(bounds) less then key(point)