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