]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/listbox.cpp
make the string properly 0 terminated and allow for one char more on the output buffer
[wxWidgets.git] / src / mac / carbon / listbox.cpp
CommitLineData
e9576ca5 1///////////////////////////////////////////////////////////////////////////////
11e62fe6 2// Name: src/mac/carbon/listbox.cpp
e9576ca5 3// Purpose: wxListBox
a31a5f85 4// Author: Stefan Csomor
e9576ca5 5// Modified by:
a31a5f85 6// Created: 1998-01-01
e9576ca5 7// RCS-ID: $Id$
a31a5f85 8// Copyright: (c) Stefan Csomor
65571936 9// Licence: wxWindows licence
e9576ca5
SC
10///////////////////////////////////////////////////////////////////////////////
11
3d1a4878
SC
12#include "wx/wxprec.h"
13
179e085f
RN
14#if wxUSE_LISTBOX
15
03e11df5 16#include "wx/app.h"
e9576ca5 17#include "wx/listbox.h"
b4726a58 18#include "wx/checklst.h"
dc0ace7c 19#include "wx/button.h"
e9576ca5 20#include "wx/settings.h"
422644a3 21#include "wx/toplevel.h"
e9576ca5
SC
22#include "wx/dynarray.h"
23#include "wx/log.h"
24
519cb848 25#include "wx/utils.h"
519cb848 26
b4726a58
SC
27IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl)
28
29BEGIN_EVENT_TABLE(wxListBox, wxControl)
30END_EVENT_TABLE()
31
fdd4e6cc
DS
32#include "wx/mac/uma.h"
33
b4726a58
SC
34// common interface for all implementations
35class wxMacListControl : public wxMacControl
36{
37public :
38 wxMacListControl( wxListBox *peer ) :
39 wxMacControl( peer )
40 {
41 }
42 ~wxMacListControl()
43 {
44
45 }
fdd4e6cc 46
b4726a58
SC
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};
fdd4e6cc 67
b4726a58
SC
68#if 0
69// In case we have to replace data browser ...
70// custom HIView based implementation
fdd4e6cc 71
b4726a58
SC
72class wxMacCustomHIViewListControl : public wxMacListControl
73{
74public :
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
519cb848 92
b4726a58
SC
93// data browser based implementation
94
95class wxMacDataBrowserListControl : public wxMacListControl
96{
97public :
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
143private :
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;
149
150#if TARGET_API_MAC_OSX
151 static pascal void DataBrowserItemNotificationProc(ControlRef browser, DataBrowserItemID itemID,
152 DataBrowserItemNotification message, DataBrowserItemDataRef itemData);
153#else
154 static pascal void DataBrowserItemNotificationProc(ControlRef browser, DataBrowserItemID itemID,
155 DataBrowserItemNotification message);
facd6764 156#endif
b4726a58
SC
157};
158
159// ============================================================================
160// data browser based implementation
161// ============================================================================
e9576ca5 162
b4726a58
SC
163const short kTextColumnId = 1024;
164const short kCheckboxColumnId = 1025;
facd6764 165
b4726a58
SC
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
789ae0cf 171
b4726a58
SC
172DataBrowserItemDataUPP gDataBrowserItemDataUPP = NULL;
173DataBrowserItemNotificationUPP gDataBrowserItemNotificationUPP = NULL;
fdd4e6cc 174
83ce5634 175#if TARGET_API_MAC_OSX
b4726a58 176pascal void wxMacDataBrowserListControl::DataBrowserItemNotificationProc(ControlRef browser, DataBrowserItemID itemID,
83ce5634
SC
177 DataBrowserItemNotification message, DataBrowserItemDataRef itemData)
178#else
b4726a58 179pascal void wxMacDataBrowserListControl::DataBrowserItemNotificationProc(ControlRef browser, DataBrowserItemID itemID,
83ce5634
SC
180 DataBrowserItemNotification message)
181#endif
182{
b4726a58 183 long ref = GetControlReference( browser );
83ce5634
SC
184 if ( ref )
185 {
b4726a58
SC
186 wxListBox* list = wxDynamicCast( (wxObject*) ref , wxListBox );
187 wxMacDataBrowserListControl* peer = (wxMacDataBrowserListControl*) list->GetPeer();
188
189 int i = itemID - 1;
8228b893 190 if (i >= 0 && i < (int)list->GetCount() )
8e0f22c0 191 {
b4726a58 192 bool trigger = false;
fdd4e6cc
DS
193 wxCommandEvent event( wxEVT_COMMAND_LISTBOX_SELECTED, list->GetId() );
194 switch ( message )
83ce5634 195 {
8e0f22c0
SC
196 case kDataBrowserItemDeselected :
197 if ( list->HasMultipleSelection() )
b4726a58
SC
198 trigger = !peer->MacIsSelectionSuppressed();
199 break;
fdd4e6cc 200
8e0f22c0 201 case kDataBrowserItemSelected :
b4726a58
SC
202 trigger = !peer->MacIsSelectionSuppressed();
203 break;
fdd4e6cc 204
8e0f22c0 205 case kDataBrowserItemDoubleClicked :
b4726a58
SC
206 event.SetEventType( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED );
207 trigger = true;
208 break;
fdd4e6cc 209
8e0f22c0 210 default :
b4726a58 211 break;
83ce5634 212 }
fdd4e6cc 213
8e0f22c0
SC
214 if ( trigger )
215 {
216 event.SetEventObject( list );
217 if ( list->HasClientObjectData() )
fdd4e6cc 218 event.SetClientObject( list->GetClientObject( i ) );
8e0f22c0 219 else if ( list->HasClientUntypedData() )
fdd4e6cc
DS
220 event.SetClientData( list->GetClientData( i ) );
221 event.SetString( list->GetString( i ) );
b4726a58 222 event.SetInt( i );
fdd4e6cc 223 event.SetExtraLong( list->HasMultipleSelection() ? message == kDataBrowserItemSelected : true );
b4726a58 224 wxPostEvent( list->GetEventHandler() , event );
8e0f22c0 225 // direct notification is not always having the listbox GetSelection() having in synch with event
b4726a58 226 // list->GetEventHandler()->ProcessEvent(event);
c6179a84 227 }
8e0f22c0 228 }
83ce5634
SC
229 }
230}
231
c6179a84
VZ
232static pascal OSStatus ListBoxGetSetItemData(ControlRef browser,
233 DataBrowserItemID itemID, DataBrowserPropertyID property,
facd6764
SC
234 DataBrowserItemDataRef itemData, Boolean changeValue)
235{
de1b0aeb
VZ
236 OSStatus err = errDataBrowserPropertyNotSupported;
237
b4726a58
SC
238 long ref = GetControlReference( browser );
239
de1b0aeb
VZ
240 if ( ! changeValue )
241 {
b4726a58
SC
242 wxListBox* list = wxDynamicCast( (wxObject*) ref , wxListBox );
243 bool isCheckList = false;
244 if ( list)
245 isCheckList = list->IsKindOf( CLASSINFO(wxCheckListBox));
246
de1b0aeb
VZ
247 switch (property)
248 {
de1b0aeb
VZ
249 case kTextColumnId:
250 {
de1b0aeb
VZ
251 if ( ref )
252 {
b4726a58 253 int i = itemID - 1;
8228b893 254 if (i >= 0 && i < (int)list->GetCount() )
de1b0aeb 255 {
b4726a58
SC
256 wxMacCFStringHolder cf( list->GetString( i ) , list->GetFont().GetEncoding() );
257 verify_noerr( ::SetDataBrowserItemDataText( itemData , cf ) );
258 err = noErr;
de1b0aeb
VZ
259 }
260 }
261 }
fdd4e6cc 262 break;
b4726a58
SC
263
264 case kCheckboxColumnId :
265 {
266 if ( ref )
267 {
268 wxCheckListBox* list = wxDynamicCast( (wxObject*) ref , wxCheckListBox );
269 int i = itemID - 1;
270 if (i >= 0 && (unsigned int) i < list->GetCount() )
271 {
272 verify_noerr( ::SetDataBrowserItemDataButtonValue( itemData , list->IsChecked( i ) ? kThemeButtonOn : kThemeButtonOff ) );
273 err = noErr;
274 }
275 }
276 }
277 break;
278 case kDataBrowserItemIsEditableProperty:
279 {
280 if ( isCheckList )
281 err = ::SetDataBrowserItemDataBooleanValue(itemData, true);
282 }
283 break;
c6179a84 284
de1b0aeb 285 default:
fdd4e6cc 286 break;
de1b0aeb
VZ
287 }
288 }
b4726a58
SC
289 else
290 {
291 switch( property )
292 {
293 case kCheckboxColumnId :
294 {
295 if ( ref )
296 {
297 wxCheckListBox* list = wxDynamicCast( (wxObject*) ref , wxCheckListBox );
298 int i = itemID - 1;
299 if (i >= 0 && (unsigned int)i < list->GetCount() )
300 {
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 ) );
304 err = noErr;
305 list->m_checks[ i ] = newVal;
306
307 wxCommandEvent event(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, list->GetId());
308 event.SetInt(i);
309 event.SetEventObject(list);
310 list->GetEventHandler()->ProcessEvent(event);
311 }
312 }
313
314 }
315 break;
316
317 default :
318 break;
319 }
320 }
c6179a84 321
de1b0aeb 322 return err;
facd6764 323}
fe3dc505 324
b4726a58
SC
325wxMacDataBrowserListControl::wxMacDataBrowserListControl( wxListBox *peer , const wxPoint& pos, const wxSize& size, long style) :
326 wxMacListControl( peer )
327{
328 bool isCheckList = peer->IsKindOf( CLASSINFO(wxCheckListBox));
329
330 m_suppressSelection = false;
331 Rect bounds = wxMacGetBoundsForControl( peer , pos , size );
332 verify_noerr( ::CreateDataBrowserControl( MAC_WXHWND(peer->MacGetTopLevelWindowRef()), &bounds, kDataBrowserListView , &m_controlRef ) );
333
334 DataBrowserSelectionFlags options = kDataBrowserDragSelect;
335 if ( style & wxLB_MULTIPLE )
336 {
337 options += kDataBrowserAlwaysExtendSelection + kDataBrowserCmdTogglesSelection ;
338 }
339 else if ( style & wxLB_EXTENDED )
340 {
341 // default behaviour
342 }
343 else
344 {
345 options += kDataBrowserSelectOnlyOne;
346 }
347 verify_noerr(SetSelectionFlags( options ) );
348
349 if ( gDataBrowserItemDataUPP == NULL ) gDataBrowserItemDataUPP = NewDataBrowserItemDataUPP(ListBoxGetSetItemData);
350 if ( gDataBrowserItemNotificationUPP == NULL )
351 {
352 gDataBrowserItemNotificationUPP =
353#if TARGET_API_MAC_OSX
354 (DataBrowserItemNotificationUPP) NewDataBrowserItemNotificationWithItemUPP(DataBrowserItemNotificationProc);
355#else
356 NewDataBrowserItemNotificationUPP(DataBrowserItemNotificationProc);
357#endif
358 }
359
360 DataBrowserCallbacks callbacks;
361 InitializeDataBrowserCallbacks( &callbacks , kDataBrowserLatestCallbacks );
362
363 callbacks.u.v1.itemDataCallback = gDataBrowserItemDataUPP;
364 callbacks.u.v1.itemNotificationCallback = gDataBrowserItemNotificationUPP;
365 SetCallbacks( &callbacks);
366
367 DataBrowserListViewColumnDesc columnDesc;
368 columnDesc.headerBtnDesc.titleOffset = 0;
369 columnDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
370
371 columnDesc.headerBtnDesc.btnFontStyle.flags =
372 kControlUseFontMask | kControlUseJustMask;
373
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;
379
380 if( isCheckList )
381 {
382 columnDesc.headerBtnDesc.minimumWidth = 30;
383 columnDesc.headerBtnDesc.maximumWidth = 30;
384
385 columnDesc.propertyDesc.propertyID = kCheckboxColumnId;
386 columnDesc.propertyDesc.propertyType = kDataBrowserCheckboxType;
387 columnDesc.propertyDesc.propertyFlags = kDataBrowserPropertyIsMutable | kDataBrowserTableViewSelectionColumn |
388 kDataBrowserDefaultPropertyFlags;
389 verify_noerr(AddListViewColumn( &columnDesc, kDataBrowserListViewAppendColumn) );
390 }
391
392 columnDesc.headerBtnDesc.minimumWidth = 0;
393 columnDesc.headerBtnDesc.maximumWidth = 10000;
394
395
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 |
401#endif
402 kDataBrowserTableViewSelectionColumn;
403
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 ) );
409
410#if 0
411 // shouldn't be necessary anymore under 10.2
412 m_peer->SetData( kControlNoPart, kControlDataBrowserIncludesFrameAndFocusTag, (Boolean) false );
413 m_peer->SetNeedsFocusRect( true );
414#endif
415}
416wxMacDataBrowserListControl::~wxMacDataBrowserListControl()
417{
418
419}
420
421void wxMacDataBrowserListControl::MacDelete( int n )
422{
423 wxArrayInt selectionBefore;
424 MacGetSelections( selectionBefore );
425
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 )
429 {
430 int current = selectionBefore[i];
431 if ( current == n )
432 {
433 // selection was deleted
434 MacSetSelection( current , false );
435 }
436 else if ( current > n )
437 {
438 // something behind the deleted item was selected -> move up
439 MacSetSelection( current - 1 , true );
440 MacSetSelection( current , false );
441 }
442 }
443 // refresh all
444 verify_noerr( UpdateItems( kDataBrowserNoItem , 1 , (UInt32*) kDataBrowserNoItem , kDataBrowserItemNoProperty , kDataBrowserItemNoProperty ) );
445}
446
447void wxMacDataBrowserListControl::MacInsert( int n , const wxString& text)
448{
449 wxArrayInt selectionBefore;
450 MacGetSelections( selectionBefore );
451
452 UInt32 id = GetPeer()->GetCount(); // this has already been increased
453 verify_noerr( AddItems( kDataBrowserNoItem , 1 , (UInt32*) &id , kDataBrowserItemNoProperty ) );
454
455 for ( int i = selectionBefore.GetCount()-1; i >= 0; --i )
456 {
457 int current = selectionBefore[i];
458 if ( current >= n )
459 {
460 MacSetSelection( current + 1 , true );
461 MacSetSelection( current , false );
462 }
463 }
464
465 // refresh all
466 verify_noerr( UpdateItems( kDataBrowserNoItem , 1 , (UInt32*) kDataBrowserNoItem , kDataBrowserItemNoProperty , kDataBrowserItemNoProperty ) );
467}
468
469void wxMacDataBrowserListControl::MacInsert( int n , const wxArrayString& items)
470{
471 wxArrayInt selectionBefore;
472 MacGetSelections( selectionBefore );
473 size_t itemsCount = items.GetCount();
474
475 UInt32 *ids = new UInt32[itemsCount];
476 for ( unsigned int i = 0; i < itemsCount;++i )
477 ids[i] = GetPeer()->GetCount() - itemsCount + i + 1;
478
479 verify_noerr( AddItems( kDataBrowserNoItem , itemsCount , ids , kDataBrowserItemNoProperty ) );
480 delete[] ids;
481
482 for ( int i = selectionBefore.GetCount()-1; i >= 0; --i )
483 {
484 int current = selectionBefore[i];
485 if ( current >= n )
486 {
487 MacSetSelection( current + 1 , true );
488 MacSetSelection( current , false );
489 }
490 }
491
492 // refresh all
493 verify_noerr( UpdateItems( kDataBrowserNoItem , 1 , (UInt32*) kDataBrowserNoItem , kDataBrowserItemNoProperty , kDataBrowserItemNoProperty ) );
494}
495
496void wxMacDataBrowserListControl::MacAppend( const wxString& text)
497{
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
501}
502
503void wxMacDataBrowserListControl::MacClear()
504{
505 verify_noerr( RemoveItems( kDataBrowserNoItem , 0 , NULL , kDataBrowserItemNoProperty ) );
506}
507
508void wxMacDataBrowserListControl::MacDeselectAll()
509{
510 bool former = MacSuppressSelection( true );
511 verify_noerr(SetSelectedItems( 0 , NULL , kDataBrowserItemsRemove ) );
512 MacSuppressSelection( former );
513}
514
515void wxMacDataBrowserListControl::MacSetSelection( int n , bool select )
516{
517 bool former = MacSuppressSelection( true );
518 UInt32 id = n + 1;
519
520 if ( IsItemSelected( id ) != select )
521 {
522 if ( select )
523 verify_noerr(SetSelectedItems( 1 , & id , GetPeer()->HasMultipleSelection() ? kDataBrowserItemsAdd : kDataBrowserItemsAssign ) );
524 else
525 verify_noerr(SetSelectedItems( 1 , & id , kDataBrowserItemsRemove ) );
526 }
527 MacScrollTo( n );
528 MacSuppressSelection( former );
529}
530
531bool wxMacDataBrowserListControl::MacSuppressSelection( bool suppress )
532{
533 bool former = m_suppressSelection;
534 m_suppressSelection = suppress;
535 return former;
536}
537
538bool wxMacDataBrowserListControl::MacIsSelected( int n ) const
539{
540 return IsItemSelected( n + 1 );
541}
542
543int wxMacDataBrowserListControl::MacGetSelection() const
544{
545 for ( unsigned int i = 0; i < GetPeer()->GetCount(); ++i )
546 {
547 if ( IsItemSelected( i + 1 ) )
548 {
549 return i;
550 }
551 }
552 return -1;
553}
554
555int wxMacDataBrowserListControl::MacGetSelections( wxArrayInt& aSelections ) const
556{
557 int no_sel = 0;
558
559 aSelections.Empty();
560
561 UInt32 first , last;
562 GetSelectionAnchor( &first , &last );
563 if ( first != kDataBrowserNoItem )
564 {
565 for ( size_t i = first; i <= last; ++i )
566 {
567 if ( IsItemSelected( i ) )
568 {
569 aSelections.Add( i - 1 );
570 no_sel++;
571 }
572 }
573 }
574 return no_sel;
575}
576
577void wxMacDataBrowserListControl::MacSet( int n , const wxString& text )
578{
579 // as we don't store the strings we only have to issue a redraw
580 UInt32 id = n + 1;
581 verify_noerr( UpdateItems( kDataBrowserNoItem , 1 , &id , kDataBrowserItemNoProperty , kDataBrowserItemNoProperty ) );
582}
583
584void wxMacDataBrowserListControl::MacScrollTo( int n )
585{
586 UInt32 id = n + 1;
587 verify_noerr( RevealItem( id , kTextColumnId , kDataBrowserRevealWithoutSelecting ) );
588}
589
590void wxMacDataBrowserListControl::UpdateLine( int n )
591{
592 UInt32 id = n + 1;
593 verify_noerr( UpdateItems(kDataBrowserNoItem , 1 , &id , kDataBrowserItemNoProperty , kDataBrowserItemNoProperty ) );
594}
595
596//
597// Databrowser
598//
599
600OSStatus wxMacDataBrowserListControl::SetSelectionFlags( DataBrowserSelectionFlags options )
601{
602 return SetDataBrowserSelectionFlags( m_controlRef , options );
603}
604
605OSStatus wxMacDataBrowserListControl::AddListViewColumn( DataBrowserListViewColumnDesc *columnDesc,
606 DataBrowserTableViewColumnIndex position )
607{
608 return AddDataBrowserListViewColumn( m_controlRef , columnDesc, position );
609}
610
611OSStatus wxMacDataBrowserListControl::AutoSizeListViewColumns()
612{
613 return AutoSizeDataBrowserListViewColumns(m_controlRef);
614}
615
616OSStatus wxMacDataBrowserListControl::SetHasScrollBars( bool horiz , bool vert )
617{
618 return SetDataBrowserHasScrollBars( m_controlRef , horiz , vert );
619}
620
621OSStatus wxMacDataBrowserListControl::SetTableViewHiliteStyle( DataBrowserTableViewHiliteStyle hiliteStyle )
622{
623 return SetDataBrowserTableViewHiliteStyle( m_controlRef , hiliteStyle );
624}
625
626OSStatus wxMacDataBrowserListControl::SetListViewHeaderBtnHeight(UInt16 height)
627{
628 return SetDataBrowserListViewHeaderBtnHeight( m_controlRef ,height );
629}
630
631OSStatus wxMacDataBrowserListControl::SetCallbacks(const DataBrowserCallbacks * callbacks)
632{
633 return SetDataBrowserCallbacks( m_controlRef , callbacks );
634}
635
636OSStatus wxMacDataBrowserListControl::UpdateItems( DataBrowserItemID container, UInt32 numItems,
637 const DataBrowserItemID* items,
638 DataBrowserPropertyID preSortProperty,
639 DataBrowserPropertyID propertyID )
640{
641 return UpdateDataBrowserItems( m_controlRef , container, numItems, items, preSortProperty, propertyID );
642}
643
644bool wxMacDataBrowserListControl::IsItemSelected( DataBrowserItemID item ) const
645{
646 return IsDataBrowserItemSelected( m_controlRef , item );
647}
648
649OSStatus wxMacDataBrowserListControl::AddItems( DataBrowserItemID container, UInt32 numItems,
650 const DataBrowserItemID* items,
651 DataBrowserPropertyID preSortProperty )
652{
653 return AddDataBrowserItems( m_controlRef , container, numItems, items, preSortProperty );
654}
655
656OSStatus wxMacDataBrowserListControl::RemoveItems( DataBrowserItemID container, UInt32 numItems,
657 const DataBrowserItemID* items,
658 DataBrowserPropertyID preSortProperty )
659{
660 return RemoveDataBrowserItems( m_controlRef , container, numItems, items, preSortProperty );
661}
662
663OSStatus wxMacDataBrowserListControl::RevealItem( DataBrowserItemID item,
664 DataBrowserPropertyID propertyID,
665 DataBrowserRevealOptions options )
666{
667 return RevealDataBrowserItem( m_controlRef , item , propertyID , options );
668}
669
670OSStatus wxMacDataBrowserListControl::SetSelectedItems(UInt32 numItems,
671 const DataBrowserItemID * items,
672 DataBrowserSetOption operation )
673{
674 return SetDataBrowserSelectedItems( m_controlRef , numItems , items, operation );
675}
676
677OSStatus wxMacDataBrowserListControl::GetSelectionAnchor( DataBrowserItemID * first, DataBrowserItemID * last ) const
678{
679 return GetDataBrowserSelectionAnchor( m_controlRef , first , last );
680}
681
682#if 0
683
684// in case we need that one day
685
686// ============================================================================
687// HIView owner draw based implementation
688// ============================================================================
689
789ae0cf
SC
690static pascal void ListBoxDrawProc( ControlRef browser , DataBrowserItemID item , DataBrowserPropertyID property ,
691 DataBrowserItemState itemState , const Rect *itemRect , SInt16 depth , Boolean isColorDevice )
692{
789ae0cf 693 CFStringRef cfString;
b4726a58 694 ThemeDrawingState themeState;
789ae0cf
SC
695 long systemVersion;
696
b4726a58 697 GetThemeDrawingState( &themeState );
fdd4e6cc 698 cfString = CFStringCreateWithFormat( NULL, NULL, CFSTR("Row %d"), item );
de1b0aeb 699
fdd4e6cc
DS
700 // In this sample we handle the "selected" state; all others fall through to our "active" state
701 if ( itemState == kDataBrowserItemIsSelected )
789ae0cf 702 {
fdd4e6cc
DS
703 ThemeBrush colorBrushID;
704
789ae0cf 705 Gestalt( gestaltSystemVersion, &systemVersion );
fdd4e6cc
DS
706
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;
789ae0cf 711 else
fdd4e6cc 712 colorBrushID = kThemeBrushPrimaryHighlightColor;
789ae0cf 713
fdd4e6cc
DS
714 // First paint the hilite rect, then the text on top
715 SetThemePen( colorBrushID, 32, true );
716 PaintRect( itemRect );
b4726a58 717 SetThemeDrawingState( themeState , false );
789ae0cf 718 }
fdd4e6cc 719
789ae0cf 720 DrawThemeTextBox( cfString, kThemeApplicationFont, kThemeStateActive, true, itemRect, teFlushDefault, NULL );
b4726a58 721 SetThemeDrawingState( themeState , true );
fdd4e6cc 722
de1b0aeb 723 if ( cfString != NULL )
789ae0cf 724 CFRelease( cfString );
789ae0cf 725}
b4726a58
SC
726#endif
727
728
729// ============================================================================
730// list box control implementation
731// ============================================================================
fe3dc505 732
fe3dc505
SC
733wxListBox::wxListBox()
734{
b4726a58 735 m_noItems = 0;
fe3dc505
SC
736}
737
fdd4e6cc
DS
738bool wxListBox::Create(wxWindow *parent,
739 wxWindowID id,
740 const wxPoint& pos,
741 const wxSize& size,
742 const wxArrayString& choices,
743 long style,
744 const wxValidator& validator,
745 const wxString& name)
fe3dc505
SC
746{
747 wxCArrayString chs(choices);
748
749 return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
750 style, validator, name);
751}
752
fdd4e6cc
DS
753bool wxListBox::Create(wxWindow *parent,
754 wxWindowID id,
755 const wxPoint& pos,
756 const wxSize& size,
757 int n,
758 const wxString choices[],
759 long style,
760 const wxValidator& validator,
761 const wxString& name)
facd6764 762{
b4726a58 763 m_macIsUserPane = false;
5e6f42cd
SC
764
765 wxASSERT_MSG( !(style & wxLB_MULTIPLE) || !(style & wxLB_EXTENDED),
766 _T("only one of listbox selection modes can be specified") );
c6179a84 767
facd6764
SC
768 if ( !wxListBoxBase::Create(parent, id, pos, size, style & ~(wxHSCROLL|wxVSCROLL), validator, name) )
769 return false;
770
b4726a58 771 m_noItems = 0; // this will be increased by our append command
789ae0cf 772
b4726a58 773 m_peer = CreateMacListControl(pos , size , style );
de1b0aeb 774
b4726a58 775 MacPostControlCreate(pos,size);
c6179a84 776
b4726a58 777 InsertItems( n , choices , 0 );
facd6764 778
b4726a58 779 SetBestSize(size); // Needed because it is a wxControlWithItems
fdd4e6cc 780
b4726a58 781 return TRUE;
facd6764
SC
782}
783
784wxListBox::~wxListBox()
785{
b4726a58
SC
786 m_peer->SetReference( 0 );
787 FreeData();
788}
fdd4e6cc 789
b4726a58
SC
790wxMacListControl* wxListBox::CreateMacListControl(const wxPoint& pos, const wxSize& size, long style)
791{
792 return new wxMacDataBrowserListControl(this , pos , size , style );
facd6764
SC
793}
794
795void wxListBox::FreeData()
796{
b4726a58
SC
797#if wxUSE_OWNER_DRAWN
798 if ( m_windowStyle & wxLB_OWNERDRAW )
799 {
800 size_t uiCount = m_aItems.Count();
801 while ( uiCount-- != 0 ) {
802 delete m_aItems[uiCount];
803 m_aItems[uiCount] = NULL;
804 }
805
806 m_aItems.Clear();
807 }
808 else
809#endif // wxUSE_OWNER_DRAWN
facd6764
SC
810 if ( HasClientObjectData() )
811 {
aa61d352 812 for ( unsigned int n = 0; n < m_noItems; n++ )
facd6764 813 {
fdd4e6cc 814 delete GetClientObject( n );
facd6764
SC
815 }
816 }
817}
818
819void wxListBox::DoSetSize(int x, int y,
820 int width, int height,
821 int sizeFlags )
822{
b4726a58 823 wxControl::DoSetSize( x , y , width , height , sizeFlags );
facd6764
SC
824}
825
fdd4e6cc 826void wxListBox::DoSetFirstItem(int n)
facd6764 827{
b4726a58 828 GetPeer()->MacScrollTo( n );
facd6764
SC
829}
830
aa61d352 831void wxListBox::Delete(unsigned int n)
facd6764 832{
8228b893 833 wxCHECK_RET( IsValid(n),
facd6764
SC
834 wxT("invalid index in wxListBox::Delete") );
835
b4726a58
SC
836#if wxUSE_OWNER_DRAWN
837 delete m_aItems[n];
838 m_aItems.RemoveAt(n);
839#else // !wxUSE_OWNER_DRAWN
facd6764 840 if ( HasClientObjectData() )
b4726a58
SC
841 {
842 delete GetClientObject(n);
843 }
844#endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
845 m_stringArray.RemoveAt( n );
846 m_dataArray.RemoveAt( n );
847 m_noItems --;
facd6764 848
b4726a58 849 GetPeer()->MacDelete( n );
facd6764
SC
850}
851
852int wxListBox::DoAppend(const wxString& item)
853{
9f884528
RD
854 InvalidateBestSize();
855
b4726a58
SC
856 unsigned int index = m_noItems;
857 m_stringArray.Add( item );
facd6764 858 m_dataArray.Add( NULL );
fdd4e6cc 859 m_noItems++;
b4726a58
SC
860 DoSetItemClientData( index , NULL );
861 GetPeer()->MacAppend( item );
facd6764 862
b4726a58 863 return index;
facd6764
SC
864}
865
866void wxListBox::DoSetItems(const wxArrayString& choices, void** clientData)
867{
b4726a58 868 Clear();
aa61d352 869 unsigned int n = choices.GetCount();
c6179a84 870
b4726a58 871 for ( size_t i = 0; i < n; ++i )
facd6764
SC
872 {
873 if ( clientData )
b4726a58
SC
874 {
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] );
880#endif
881 }
facd6764 882 else
b4726a58 883 Append( choices[i] );
facd6764 884 }
b4726a58
SC
885
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 ) {
891 delete m_aItems[ui];
892 m_aItems[ui] = NULL;
893 }
894 m_aItems.Empty();
895
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);
901 }
902 }
903#endif // wxUSE_OWNER_DRAWN
facd6764
SC
904}
905
11e62fe6 906int wxListBox::FindString(const wxString& s, bool bCase) const
facd6764 907{
b4726a58 908 for ( size_t i = 0; i < m_noItems; ++ i )
facd6764 909 {
429bf230 910 if (s.IsSameAs(GetString(i), bCase))
b4726a58 911 return (int)i;
facd6764 912 }
fdd4e6cc 913
11e62fe6 914 return wxNOT_FOUND;
facd6764
SC
915}
916
917void wxListBox::Clear()
918{
919 FreeData();
920 m_noItems = 0;
b4726a58
SC
921 m_stringArray.Empty();
922 m_dataArray.Empty();
923 GetPeer()->MacClear();
facd6764
SC
924}
925
fdd4e6cc 926void wxListBox::DoSetSelection(int n, bool select)
facd6764 927{
8228b893 928 wxCHECK_RET( n == wxNOT_FOUND || IsValid(n) ,
facd6764 929 wxT("invalid index in wxListBox::SetSelection") );
c6179a84 930
fdd4e6cc 931 if ( n == wxNOT_FOUND )
b4726a58 932 GetPeer()->MacDeselectAll();
fe3dc505 933 else
b4726a58 934 GetPeer()->MacSetSelection( n , select );
facd6764
SC
935}
936
fdd4e6cc 937bool wxListBox::IsSelected(int n) const
facd6764 938{
8228b893 939 wxCHECK_MSG( IsValid(n), false,
facd6764 940 wxT("invalid index in wxListBox::Selected") );
c6179a84 941
b4726a58 942 return GetPeer()->MacIsSelected( n );
facd6764
SC
943}
944
aa61d352 945void *wxListBox::DoGetItemClientData(unsigned int n) const
facd6764 946{
8228b893
WS
947 wxCHECK_MSG( IsValid(n), NULL, wxT("invalid index in wxListBox::GetClientData"));
948
b4726a58 949 wxASSERT_MSG( m_dataArray.GetCount() >= (unsigned int) n , wxT("invalid client_data array") );
c6179a84 950
fdd4e6cc 951 return (void *)m_dataArray[n];
facd6764
SC
952}
953
aa61d352 954wxClientData *wxListBox::DoGetItemClientObject(unsigned int n) const
facd6764 955{
b4726a58 956 return (wxClientData *) DoGetItemClientData( n );
facd6764
SC
957}
958
aa61d352 959void wxListBox::DoSetItemClientData(unsigned int n, void *clientData)
facd6764 960{
8228b893 961 wxCHECK_RET( IsValid(n), wxT("invalid index in wxListBox::SetClientData") );
c6179a84 962
b4726a58
SC
963#if wxUSE_OWNER_DRAWN
964 if ( m_windowStyle & wxLB_OWNERDRAW )
965 {
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"));
969 }
970#endif // wxUSE_OWNER_DRAWN
971 wxASSERT_MSG( m_dataArray.GetCount() >= (unsigned int) n , wxT("invalid client_data array") );
c6179a84 972
aa61d352 973 if ( m_dataArray.GetCount() > (unsigned int) n )
b4726a58 974 m_dataArray[n] = (char*)clientData;
facd6764 975 else
b4726a58 976 m_dataArray.Add( (char*)clientData );
facd6764
SC
977}
978
aa61d352 979void wxListBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
facd6764
SC
980{
981 DoSetItemClientData(n, clientData);
982}
983
984// Return number of selections and an array of selected integers
985int wxListBox::GetSelections(wxArrayInt& aSelections) const
986{
b4726a58 987 return GetPeer()->MacGetSelections( aSelections );
facd6764
SC
988}
989
990// Get single selection, for single choice list items
991int wxListBox::GetSelection() const
992{
b4726a58 993 return GetPeer()->MacGetSelection();
facd6764
SC
994}
995
996// Find string for position
aa61d352 997wxString wxListBox::GetString(unsigned int n) const
facd6764 998{
8228b893 999 wxCHECK_MSG( IsValid(n), wxEmptyString,
55ae2833
RD
1000 wxT("invalid index in wxListBox::GetString") );
1001
b4726a58 1002 return m_stringArray[n] ;
facd6764
SC
1003}
1004
aa61d352 1005void wxListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
facd6764 1006{
8228b893 1007 wxCHECK_RET( IsValidInsert(pos),
facd6764 1008 wxT("invalid index in wxListBox::InsertItems") );
c6179a84 1009
9f884528
RD
1010 InvalidateBestSize();
1011
aa61d352 1012 unsigned int nItems = items.GetCount();
c6179a84 1013
b4726a58
SC
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 );
facd6764
SC
1019}
1020
aa61d352 1021void wxListBox::SetString(unsigned int n, const wxString& s)
facd6764 1022{
b4726a58
SC
1023 m_stringArray[n] = s;
1024 GetPeer()->MacSet( n , s );
facd6764
SC
1025}
1026
1027wxSize wxListBox::DoGetBestSize() const
1028{
1029 int lbWidth = 100; // some defaults
1030 int lbHeight = 110;
1031 int wLine;
1032
1033 {
b4726a58 1034 wxMacPortStateHelper st( UMAGetWindowPort( (WindowRef)MacGetTopLevelWindowRef() ) );
c6179a84 1035
fdd4e6cc 1036 // TODO: clean this up
facd6764
SC
1037 if ( m_font.Ok() )
1038 {
b4726a58
SC
1039 ::TextFont( m_font.MacGetFontNum() );
1040 ::TextSize( m_font.MacGetFontSize() );
1041 ::TextFace( m_font.MacGetFontStyle() );
facd6764
SC
1042 }
1043 else
1044 {
b4726a58 1045 ::TextFont( kFontIDMonaco );
facd6764 1046 ::TextSize( 9 );
b4726a58 1047 ::TextFace( 0 );
facd6764 1048 }
c6179a84 1049
facd6764 1050 // Find the widest line
aa61d352 1051 for (unsigned int i = 0; i < GetCount(); i++)
fdd4e6cc 1052 {
aa61d352 1053 wxString str(GetString(i));
fdd4e6cc
DS
1054
1055#if wxUSE_UNICODE
b4726a58
SC
1056 Point bounds = {0, 0};
1057 SInt16 baseline;
fdd4e6cc
DS
1058
1059 // NB: what if m_font.Ok() == false ???
1060 ::GetThemeTextDimensions(
1061 wxMacCFStringHolder( str , m_font.GetEncoding() ) ,
facd6764
SC
1062 kThemeCurrentPortFont,
1063 kThemeStateActive,
1064 false,
1065 &bounds,
1066 &baseline );
b4726a58 1067 wLine = bounds.h;
fdd4e6cc 1068#else
b4726a58 1069 wLine = ::TextWidth( str.c_str() , 0 , str.length() );
fdd4e6cc
DS
1070#endif
1071
1072 lbWidth = wxMax( lbWidth, wLine );
facd6764 1073 }
c6179a84 1074
facd6764
SC
1075 // Add room for the scrollbar
1076 lbWidth += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
c6179a84 1077
facd6764 1078 // And just a bit more
b4726a58
SC
1079 int cy = 12;
1080 int cx = ::TextWidth( "X" , 0 , 1 );
1081 lbWidth += cx;
c6179a84 1082
fdd4e6cc
DS
1083 // don't make the listbox too tall (limit height to around 10 items)
1084 // but don't make it too small neither
9761ab43 1085 lbHeight = wxMax( (cy + 4) * wxMin( wxMax( GetCount(), 3 ), 10 ), 70 );
facd6764
SC
1086 }
1087
fdd4e6cc 1088 return wxSize( lbWidth, lbHeight );
facd6764
SC
1089}
1090
aa61d352 1091unsigned int wxListBox::GetCount() const
facd6764
SC
1092{
1093 return m_noItems;
1094}
1095
1096void wxListBox::Refresh(bool eraseBack, const wxRect *rect)
1097{
b4726a58 1098 wxControl::Refresh( eraseBack , rect );
facd6764
SC
1099}
1100
b4726a58 1101void wxListBox::MacUpdateLine( int n)
b6a20a20 1102{
b4726a58 1103 GetPeer()->UpdateLine(n);
b6a20a20
RD
1104}
1105
b4726a58 1106#if wxUSE_OWNER_DRAWN
facd6764 1107
b4726a58 1108class wxListBoxItem : public wxOwnerDrawn
facd6764 1109{
b4726a58
SC
1110public:
1111 wxListBoxItem(const wxString& str = "");
1112};
fdd4e6cc 1113
b4726a58 1114wxListBoxItem::wxListBoxItem(const wxString& str) : wxOwnerDrawn(str, FALSE)
facd6764 1115{
b4726a58
SC
1116 // no bitmaps/checkmarks
1117 SetMarginWidth(0);
facd6764
SC
1118}
1119
b4726a58 1120wxOwnerDrawn *wxListBox::CreateItem(size_t n)
facd6764 1121{
b4726a58 1122 return new wxListBoxItem();
facd6764
SC
1123}
1124
b4726a58 1125#endif //USE_OWNER_DRAWN
fdd4e6cc 1126
facd6764 1127
b4726a58
SC
1128// Some custom controls depend on this
1129/* static */ wxVisualAttributes
1130wxListBox::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
facd6764 1131{
b4726a58 1132 wxVisualAttributes attr;
519cb848 1133
b4726a58
SC
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 );
e42e45a9 1137
b4726a58 1138 return attr;
facd6764
SC
1139}
1140
443e2f09
VZ
1141int wxListBox::DoListHitTest(const wxPoint& inpoint) const
1142{
1143 OSErr err;
1144
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
1152
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);
1159
1160 // get column property id (req. for call to itempartbounds)
c00fed0e 1161 DataBrowserTableViewColumnID colId = 0;
443e2f09
VZ
1162 err = GetDataBrowserTableViewColumnProperty(m_peer->GetControlRef(), 0, &colId);
1163 wxCHECK_MSG(err == noErr, wxNOT_FOUND, wxT("Unexpected error from GetDataBrowserTableViewColumnProperty"));
1164
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"));
1173
1174 UInt16 height;
1175 err = GetDataBrowserTableViewRowHeight(m_peer->GetControlRef(), &height);
1176 wxCHECK_MSG(err == noErr, wxNOT_FOUND, wxT("Unexpected error from GetDataBrowserTableViewRowHeight"));
1177
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;
1182
1183
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 )
1188 {
1189 Rect bounds;
1190 err = GetDataBrowserItemPartBounds(m_peer->GetControlRef(), low + 1, colId,
1191 kDataBrowserPropertyEnclosingPart,
1192 &bounds); //note +1 to trans to mac id
1193 if ( err == noErr )
1194 break;
1195
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") );
1200
1201 low++;
1202 }
c00fed0e 1203
443e2f09
VZ
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 )
c00fed0e 1207 {
443e2f09
VZ
1208 int mid = (low + high) / 2;
1209
c00fed0e 1210 Rect bounds;
443e2f09
VZ
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,
1215 wxNOT_FOUND,
1216 wxT("Unexpected error from GetDataBrowserItemPartBounds") );
1217
1218 if ( err == errDataBrowserItemNotFound )
c00fed0e 1219 {
443e2f09
VZ
1220 // item not visible, attempt to find a visible one
1221 high = mid - 1; // search lower
1222 }
1223 else // visible item, do actual hitttest
1224 {
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
1227 // equality)
1228 if( (point.x >= bounds.left && point.x <= bounds.right) &&
1229 (point.y >= bounds.top && point.y <= bounds.bottom) )
1230 {
1231 return mid; // found!
1232 }
1233
1234 if ( point.y < bounds.top )
1235 high = mid - 1; // index(bounds) greater then key(point)
1236 else
1237 low = mid + 1; // index(bounds) less then key(point)
c00fed0e
VZ
1238 }
1239 }
443e2f09 1240
c00fed0e
VZ
1241 return wxNOT_FOUND;
1242}
1243
179e085f 1244#endif