]> git.saurik.com Git - wxWidgets.git/blob - src/mac/listbox.cpp
wxMac completed so far, generic listctrl extension
[wxWidgets.git] / src / mac / listbox.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: listbox.cpp
3 // Purpose: wxListBox
4 // Author: AUTHOR
5 // Modified by:
6 // Created: ??/??/98
7 // RCS-ID: $Id$
8 // Copyright: (c) AUTHOR
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "listbox.h"
14 #endif
15
16 #include "wx/listbox.h"
17 #include "wx/settings.h"
18 #include "wx/dynarray.h"
19 #include "wx/log.h"
20
21 #include "wx/utils.h"
22 #include "extldef.h"
23
24 #if !USE_SHARED_LIBRARY
25 IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl)
26
27 BEGIN_EVENT_TABLE(wxListBox, wxControl)
28 EVT_SIZE( wxListBox::OnSize )
29 END_EVENT_TABLE()
30 #endif
31
32 #include <wx/mac/uma.h>
33
34 extern "C" void MacDrawStringCell(Rect *cellRect, Cell lCell, ListHandle theList, long refCon) ;
35 const short kwxMacListWithVerticalScrollbar = 128 ;
36
37 // ============================================================================
38 // list box control implementation
39 // ============================================================================
40
41 // Listbox item
42 wxListBox::wxListBox()
43 {
44 m_noItems = 0;
45 m_selected = 0;
46 }
47
48 bool wxListBox::Create(wxWindow *parent, wxWindowID id,
49 const wxPoint& pos,
50 const wxSize& size,
51 int n, const wxString choices[],
52 long style,
53 const wxValidator& validator,
54 const wxString& name)
55 {
56 m_noItems = 0 ; // this will be increased by our append command
57 m_selected = 0;
58
59 Rect bounds ;
60 Str255 title ;
61 m_macHorizontalBorder = 5 ; // additional pixels around the real control
62 m_macVerticalBorder = 5 ;
63
64 MacPreControlCreate( parent , id , "" , pos , size ,style, validator , name , &bounds , title ) ;
65
66 m_macControl = UMANewControl( parent->GetMacRootWindow() , &bounds , title , true , kwxMacListWithVerticalScrollbar , 0 , 0,
67 kControlListBoxProc , (long) this ) ;
68
69 long result ;
70 UMAGetControlData( m_macControl , kControlNoPart , kControlListBoxListHandleTag , sizeof( ListHandle ) , (char*) &m_macList , &result ) ;
71
72 NewExtLDEFInfo( m_macList , MacDrawStringCell , (long) this ) ;
73 (**m_macList).selFlags = lOnlyOne ;
74 if ( style & wxLB_MULTIPLE )
75 {
76 (**m_macList).selFlags += lNoExtend ;
77 }
78 else if ( style & wxLB_EXTENDED )
79 {
80 (**m_macList).selFlags += lExtendDrag ;
81 }
82 Point pt = (**m_macList).cellSize ;
83 pt.v = 14 ;
84 LCellSize( pt , m_macList ) ;
85
86 LAddColumn( 1 , 0 , m_macList ) ;
87
88 MacPostControlCreate() ;
89
90 ControlFontStyleRec controlstyle ;
91 controlstyle.flags = kControlUseFontMask + kControlUseSizeMask ;
92 //controlstyle.font = kControlFontSmallSystemFont ;
93 controlstyle.font = kFontIDMonaco ;
94 controlstyle.size = 9 ;
95 ::UMASetControlFontStyle( m_macControl , &controlstyle ) ;
96
97 for ( int i = 0 ; i < n ; i++ )
98 {
99 Append( choices[i] ) ;
100 }
101
102 LSetDrawingMode( true , m_macList ) ;
103
104 return TRUE;
105 }
106
107 wxListBox::~wxListBox()
108 {
109 Free() ;
110 DisposeExtLDEFInfo( m_macList ) ;
111 }
112
113 void wxListBox::Free()
114 {
115 #if wxUSE_OWNER_DRAWN
116 if ( m_windowStyle & wxLB_OWNERDRAW )
117 {
118 size_t uiCount = m_aItems.Count();
119 while ( uiCount-- != 0 ) {
120 delete m_aItems[uiCount];
121 }
122
123 m_aItems.Clear();
124 }
125 else
126 #endif // wxUSE_OWNER_DRAWN
127 if ( HasClientObjectData() )
128 {
129 for ( size_t n = 0; n < (size_t)m_noItems; n++ )
130 {
131 delete GetClientObject(n);
132 }
133 }
134 }
135
136 void wxListBox::DoSetFirstItem(int N)
137 {
138 MacScrollTo( N ) ;
139 }
140
141 void wxListBox::Delete(int N)
142 {
143 wxCHECK_RET( N >= 0 && N < m_noItems,
144 wxT("invalid index in wxListBox::Delete") );
145
146 #if wxUSE_OWNER_DRAWN
147 delete m_aItems[N];
148 m_aItems.Remove(N);
149 #else // !wxUSE_OWNER_DRAWN
150 if ( HasClientObjectData() )
151 {
152 delete GetClientObject(N);
153 }
154 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
155 m_stringArray.Remove( N ) ;
156 m_noItems --;
157
158 MacDelete( N ) ;
159 }
160
161 int wxListBox::DoAppend(const wxString& item)
162 {
163 int index = m_noItems ;
164 if( wxApp::s_macDefaultEncodingIsPC )
165 {
166 m_stringArray.Add( wxMacMakeMacStringFromPC( item ) ) ;
167 }
168 else
169 m_stringArray.Add( item ) ;
170 m_noItems ++;
171 MacAppend( item ) ;
172
173 return index ;
174 }
175
176 void wxListBox::DoSetItems(const wxArrayString& choices, void** clientData)
177 {
178 MacSetRedraw( false ) ;
179 Clear() ;
180 int n = choices.GetCount();
181
182 for( int i = 0 ; i < n ; ++i )
183 {
184 if ( clientData )
185 {
186 #if wxUSE_OWNER_DRAWN
187 wxASSERT_MSG(clientData[i] == NULL,
188 wxT("Can't use client data with owner-drawn listboxes"));
189 #else // !wxUSE_OWNER_DRAWN
190 Append( choices[i] , clientData[0] ) ;
191 #endif
192 }
193 else
194 Append( choices[i] ) ;
195 }
196
197 #if wxUSE_OWNER_DRAWN
198 if ( m_windowStyle & wxLB_OWNERDRAW ) {
199 // first delete old items
200 size_t ui = m_aItems.Count();
201 while ( ui-- != 0 ) {
202 delete m_aItems[ui];
203 }
204 m_aItems.Empty();
205
206 // then create new ones
207 for ( ui = 0; ui < (size_t)m_noItems; ui++ ) {
208 wxOwnerDrawn *pNewItem = CreateItem(ui);
209 pNewItem->SetName(choices[ui]);
210 m_aItems.Add(pNewItem);
211 }
212 }
213 #endif // wxUSE_OWNER_DRAWN
214 MacSetRedraw( true ) ;
215 }
216
217 bool wxListBox::HasMultipleSelection() const
218 {
219 return (m_windowStyle & wxLB_MULTIPLE) || (m_windowStyle & wxLB_EXTENDED);
220 }
221
222 int wxListBox::FindString(const wxString& st) const
223 {
224 wxString s ;
225 if( wxApp::s_macDefaultEncodingIsPC )
226 {
227 s = wxMacMakeMacStringFromPC( st ) ;
228 }
229 else
230 s = st ;
231
232 if ( s.Right(1) == "*" )
233 {
234 wxString search = s.Left( s.Length() - 1 ) ;
235 int len = search.Length() ;
236 for ( int i = 0 ; i < m_noItems ; ++ i )
237 {
238 if ( equalstring( m_stringArray[i].Left( len ) , search , false , false ) )
239 return i ;
240 }
241 }
242 else
243 {
244 for ( int i = 0 ; i < m_noItems ; ++ i )
245 {
246 if ( equalstring( m_stringArray[i] , s , false , false ) )
247 return i ;
248 }
249 }
250 return -1;
251 }
252
253 void wxListBox::Clear()
254 {
255 Free();
256 m_noItems = 0;
257 m_stringArray.Empty() ;
258 m_dataArray.Empty() ;
259 MacClear() ;
260 }
261
262 void wxListBox::SetSelection(int N, bool select)
263 {
264 wxCHECK_RET( N >= 0 && N < m_noItems,
265 "invalid index in wxListBox::SetSelection" );
266 MacSetSelection( N , select ) ;
267 }
268
269 bool wxListBox::IsSelected(int N) const
270 {
271 wxCHECK_MSG( N >= 0 && N < m_noItems, FALSE,
272 "invalid index in wxListBox::Selected" );
273
274 return MacIsSelected( N ) ;
275 }
276
277 void *wxListBox::DoGetItemClientData(int N) const
278 {
279 wxCHECK_MSG( N >= 0 && N < m_noItems, NULL,
280 "invalid index in wxListBox::GetClientData" );
281
282 return (void *)m_dataArray[N];
283 }
284
285 wxClientData *wxListBox::DoGetItemClientObject(int N) const
286 {
287 return (wxClientData *) DoGetItemClientData( N ) ;
288 }
289
290 void wxListBox::DoSetItemClientData(int N, void *Client_data)
291 {
292 wxCHECK_RET( N >= 0 && N < m_noItems,
293 "invalid index in wxListBox::SetClientData" );
294
295 #if wxUSE_OWNER_DRAWN
296 if ( m_windowStyle & wxLB_OWNERDRAW )
297 {
298 // client data must be pointer to wxOwnerDrawn, otherwise we would crash
299 // in OnMeasure/OnDraw.
300 wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes"));
301 }
302 #endif // wxUSE_OWNER_DRAWN
303 m_dataArray[N] = (char*) Client_data ;
304 }
305
306 void wxListBox::DoSetItemClientObject(int n, wxClientData* clientData)
307 {
308 DoSetItemClientData(n, clientData);
309 }
310
311 // Return number of selections and an array of selected integers
312 int wxListBox::GetSelections(wxArrayInt& aSelections) const
313 {
314 return MacGetSelections( aSelections ) ;
315
316 /* TODO
317 if ((m_windowStyle & wxLB_MULTIMacE) || (m_windowStyle & wxLB_EXTENDED))
318 {
319 int no_sel = ??
320 for ( int n = 0; n < no_sel; n++ )
321 aSelections.Add(??);
322
323 return no_sel;
324 }
325 else // single-selection listbox
326 {
327 aSelections.Add(??);
328
329 return 1;
330 }
331 */
332 }
333
334 // Get single selection, for single choice list items
335 int wxListBox::GetSelection() const
336 {
337 return MacGetSelection() ;
338 }
339
340 // Find string for position
341 wxString wxListBox::GetString(int N) const
342 {
343 if( wxApp::s_macDefaultEncodingIsPC )
344 {
345 return wxMacMakePCStringFromMac( m_stringArray[N] ) ;
346 }
347 else
348 return m_stringArray[N] ;
349 }
350
351 void wxListBox::DoInsertItems(const wxArrayString& items, int pos)
352 {
353 wxCHECK_RET( pos >= 0 && pos <= m_noItems,
354 wxT("invalid index in wxListBox::InsertItems") );
355
356 int nItems = items.GetCount();
357
358 for ( int i = 0 ; i < nItems ; i++ )
359 {
360 m_stringArray.Insert( items[i] , pos + i ) ;
361 m_dataArray.Insert( NULL , pos + i ) ;
362 MacInsert( pos + i , items[i] ) ;
363 }
364
365 m_noItems += nItems;
366 }
367
368 void wxListBox::SetString(int N, const wxString& s)
369 {
370 m_stringArray[N] = s ;
371 MacSet( N , s ) ;
372 }
373
374 wxSize wxListBox::DoGetBestSize()
375 {
376 return wxSize(100, 100);
377 }
378
379 int wxListBox::GetCount() const
380 {
381 return m_noItems;
382 }
383
384 void wxListBox::SetupColours()
385 {
386 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
387 SetForegroundColour(GetParent()->GetForegroundColour());
388 }
389
390 #if wxUSE_OWNER_DRAWN
391
392 class wxListBoxItem : public wxOwnerDrawn
393 {
394 public:
395 wxListBoxItem(const wxString& str = "");
396 };
397
398 wxListBoxItem::wxListBoxItem(const wxString& str) : wxOwnerDrawn(str, FALSE)
399 {
400 // no bitmaps/checkmarks
401 SetMarginWidth(0);
402 }
403
404 wxOwnerDrawn *wxListBox::CreateItem(size_t n)
405 {
406 return new wxListBoxItem();
407 }
408
409 #endif //USE_OWNER_DRAWN
410
411 // ============================================================================
412 // list box control implementation
413 // ============================================================================
414
415 void MacDrawStringCell(Rect *cellRect, Cell lCell, ListHandle theList, long refCon)
416 {
417 wxListBox* list;
418 // typecast our refCon
419 list = (wxListBox*)refCon;
420
421 MoveTo(cellRect->left + 4 , cellRect->top + 10 );
422 const wxString text = list->m_stringArray[lCell.v] ;
423 ::TextFont( kFontIDMonaco ) ;
424 ::TextSize( 9 );
425 ::TextFace( 0 ) ;
426 DrawText(text, 0 , text.Length());
427
428 }
429
430 void wxListBox::MacDelete( int N )
431 {
432 ListHandle list ;
433 long result ;
434 Cell cell = { 0 , 0 } ;
435 UMAGetControlData( m_macControl , kControlNoPart , kControlListBoxListHandleTag , sizeof( ListHandle ) , (char*) &list , &result ) ;
436 LDelRow( 1 , N , list ) ;
437 }
438
439 void wxListBox::MacInsert( int n , const char * text)
440 {
441 Cell cell ;
442
443 cell.h = 0 ;
444 cell.v = n ;
445
446 LAddRow( 1 , cell.v , m_macList ) ;
447 }
448
449 void wxListBox::MacAppend( const char * text)
450 {
451 Cell cell = { 0 , 0 } ;
452 cell.v = (**m_macList).dataBounds.bottom ;
453 LAddRow( 1 , cell.v , m_macList ) ;
454 }
455
456 void wxListBox::MacClear()
457 {
458 LDelRow( (**m_macList).dataBounds.bottom , 0 , m_macList ) ;
459 }
460
461 void wxListBox::MacSetSelection( int n , bool select )
462 {
463 Cell cell = { 0 , 0 } ;
464 if ( LGetSelect( TRUE , &cell , m_macList ) )
465 {
466 LSetSelect( false , cell , m_macList ) ;
467 }
468
469 cell.v = n ;
470 LSetSelect( select , cell , m_macList ) ;
471 LAutoScroll( m_macList ) ;
472 }
473
474 bool wxListBox::MacIsSelected( int n ) const
475 {
476 Cell cell = { 0 , 0 } ;
477 cell.v = n ;
478 return LGetSelect( false , &cell , m_macList ) ;
479 }
480
481 void wxListBox::MacDestroy()
482 {
483 // DisposeExtLDEFInfo( m_macList ) ;
484 }
485
486 int wxListBox::MacGetSelection() const
487 {
488 Cell cell = { 0 , 0 } ;
489 if ( LGetSelect( true , &cell , m_macList ) )
490 return cell.v ;
491 else
492 return -1 ;
493 }
494
495 int wxListBox::MacGetSelections( wxArrayInt& aSelections ) const
496 {
497 int no_sel = 0 ;
498
499 aSelections.Empty();
500
501 Cell cell = { 0 , 0 } ;
502 cell.v = 0 ;
503
504 while ( LGetSelect( true , &cell , m_macList ) )
505 {
506 aSelections.Add( cell.v ) ;
507 no_sel++ ;
508 cell.v++ ;
509 }
510 return no_sel ;
511 }
512
513 void wxListBox::MacSet( int n , const char * text )
514 {
515 // our implementation does not store anything in the list
516 // so we just have to redraw
517 Cell cell = { 0 , 0 } ;
518 cell.v = n ;
519 LDraw( cell , m_macList ) ;
520 }
521
522 void wxListBox::MacScrollTo( int n )
523 {
524 // TODO implement scrolling
525 }
526
527 void wxListBox::OnSize( const wxSizeEvent &event)
528 {
529 Point pt = (**m_macList).cellSize ;
530 pt.h = m_width - 15 /* scrollbar */ - m_macHorizontalBorder * 2 ;
531 LCellSize( pt , m_macList ) ;
532 }
533
534 void wxListBox::MacHandleControlClick( ControlHandle control , SInt16 controlpart )
535 {
536 Boolean wasDoubleClick = false ;
537 long result ;
538
539 UMAGetControlData( m_macControl , kControlNoPart , kControlListBoxDoubleClickTag , sizeof( wasDoubleClick ) , (char*) &wasDoubleClick , &result ) ;
540 if ( !wasDoubleClick )
541 {
542 MacDoClick() ;
543 }
544 else
545 {
546 MacDoDoubleClick() ;
547 }
548 }
549
550 void wxListBox::MacSetRedraw( bool doDraw )
551 {
552 LSetDrawingMode( doDraw , m_macList ) ;
553
554 }
555
556 void wxListBox::MacDoClick()
557 {
558 wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, m_windowId);
559 event.SetEventObject( this );
560
561 wxArrayInt aSelections;
562 int n, count = GetSelections(aSelections);
563 if ( count > 0 )
564 {
565 n = aSelections[0];
566 if ( HasClientObjectData() )
567 event.SetClientObject( GetClientObject(n) );
568 else if ( HasClientUntypedData() )
569 event.SetClientData( GetClientData(n) );
570 event.SetString( GetString(n) );
571 }
572 else
573 {
574 n = -1;
575 }
576
577 event.m_commandInt = n;
578
579 GetEventHandler()->ProcessEvent(event);
580 }
581
582 void wxListBox::MacDoDoubleClick()
583 {
584 wxCommandEvent event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, m_windowId);
585 event.SetEventObject( this );
586 GetEventHandler()->ProcessEvent(event) ;
587 }