X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/065e208ec09e3d08d51d9604497f92f53c210f93..9c20523110b6601abd001eb6316c563ff1b53af0:/src/cocoa/combobox.mm diff --git a/src/cocoa/combobox.mm b/src/cocoa/combobox.mm index e016e89205..c65d6b5a70 100644 --- a/src/cocoa/combobox.mm +++ b/src/cocoa/combobox.mm @@ -1,31 +1,178 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: cocoa/combobox.mm +// Name: src/cocoa/combobox.mm // Purpose: wxComboBox -// Author: David Elliott +// Author: Ryan Norton // Modified by: -// Created: 2003/07/14 +// Created: 2005/02/16 // RCS-ID: $Id$ // Copyright: (c) 2003 David Elliott -// Licence: wxWidgets licence +// Licence: wxWidgets licence ///////////////////////////////////////////////////////////////////////////// +// +// Impl notes: +// There is no custom data source because doing so unnecessarily sacrifices +// some native autocompletion behavior (we would have to make our own - +// the SimpleComboBox sample does so in the developer folder that +// comes with OSX). One reason you might want this would be to have +// only one array or be able to display numbers returned by an NSNumber +// from the methods. +// +// One problem though is that wxCB_SORT isn't implemented... +// +// Also, not sure if it is correctly getting text field events since +// I'm using SetNSComboBox instead of SetNSTextField +// +// doWxEvent is really hackish... but since there's only one event... +// +// Ideas for future improvement - other notes: +// Combox w/o wxCB_DROPDOWN doesn't seem to be implementable +//wxCB_READONLY Same as wxCB_DROPDOWN but only the strings specified as the combobox choices can be selected, it is impossible to select (even from a program) a string which is not in the choices list. +//wxCB_SORT is possible with data source +// +// setIntercellSpacing:/setItemHeight: to autoadjust to number of inserted items? +// +/* + //example of autocompletion from SimpleComboBox Example + // ========================================================== +// Combo box data source methods +// ========================================================== + +- (int)numberOfItemsInComboBox:(NSComboBox *)aComboBox { + return [genres count]; +} +- (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(int)index { + return [genres objectAtIndex:index]; +} +- (unsigned int)comboBox:(NSComboBox *)aComboBox indexOfItemWithStringValue:(NSString *)string { + return [genres indexOfObject: string]; +} + +- (NSString *) firstGenreMatchingPrefix:(NSString *)prefix { + NSString *string = nil; + NSString *lowercasePrefix = [prefix lowercaseString]; + NSEnumerator *stringEnum = [genres objectEnumerator]; + while ((string = [stringEnum nextObject])) { + if ([[string lowercaseString] hasPrefix: lowercasePrefix]) return string; + } + return nil; +} + +- (NSString *)comboBox:(NSComboBox *)aComboBox completedString:(NSString *)inputString { + // This method is received after each character typed by the user, because we have checked the "completes" flag for genreComboBox in IB. + // Given the inputString the user has typed, see if we can find a genre with the prefix, and return it as the suggested complete string. + NSString *candidate = [self firstGenreMatchingPrefix: inputString]; + return (candidate ? candidate : inputString); +} +*/ + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + #include "wx/wxprec.h" #if wxUSE_COMBOBOX -#include "wx/app.h" #include "wx/combobox.h" -#include "wx/log.h" + +#include "wx/cocoa/objc/objc_uniquifying.h" + +#ifndef WX_PRECOMP + #include "wx/window.h" + #include "wx/log.h" + #include "wx/app.h" +#endif // WX_PRECOMP + +#import +#import +#import + +// ---------------------------------------------------------------------------- +// globals +// ---------------------------------------------------------------------------- +WX_IMPLEMENT_OBJC_INTERFACE_HASHMAP(NSComboBox) + +void wxCocoaNSComboBox::AssociateNSComboBox(WX_NSComboBox cocoaNSComboBox) +{ + if(cocoaNSComboBox) + { + sm_cocoaHash.insert(wxCocoaNSComboBoxHash::value_type(cocoaNSComboBox,this)); + + [[NSNotificationCenter defaultCenter] addObserver:(id)cocoaNSComboBox selector:@selector(comboBoxSelectionDidChange:) name:@"NSComboBoxSelectionDidChangeNotification" object:cocoaNSComboBox]; + [[NSNotificationCenter defaultCenter] addObserver:(id)cocoaNSComboBox selector:@selector(comboBoxSelectionDidChange:) name:@"NSComboBoxSelectionIsChangingNotification" object:cocoaNSComboBox]; + [[NSNotificationCenter defaultCenter] addObserver:(id)cocoaNSComboBox selector:@selector(comboBoxSelectionDidChange:) name:@"NSComboBoxWillDismissNotification" object:cocoaNSComboBox]; + [[NSNotificationCenter defaultCenter] addObserver:(id)cocoaNSComboBox selector:@selector(comboBoxSelectionDidChange:) name:@"NSComboBoxWillPopUpNotification" object:cocoaNSComboBox]; + } +} + +void wxCocoaNSComboBox::DisassociateNSComboBox(WX_NSComboBox cocoaNSComboBox) +{ + if(cocoaNSComboBox) + { + sm_cocoaHash.erase(cocoaNSComboBox); + [[NSNotificationCenter defaultCenter] removeObserver:(id)cocoaNSComboBox name:@"NSComboBoxSelectionDidChangeNotification" object:cocoaNSComboBox]; + [[NSNotificationCenter defaultCenter] removeObserver:(id)cocoaNSComboBox name:@"NSComboBoxSelectionIsChangingNotification" object:cocoaNSComboBox]; + [[NSNotificationCenter defaultCenter] removeObserver:(id)cocoaNSComboBox name:@"NSComboBoxWillDismissNotification" object:cocoaNSComboBox]; + [[NSNotificationCenter defaultCenter] removeObserver:(id)cocoaNSComboBox name:@"NSComboBoxWillPopUpNotification" object:cocoaNSComboBox]; + } +} + +// ============================================================================ +// @class wxPoserNSComboBox +// ============================================================================ +@interface wxPoserNSComboBox : NSComboBox +{ +} + +- (void)comboBoxSelectionDidChange:(NSNotification *)notification; +- (void)comboBoxSelectionIsChanging:(NSNotification *)notification; +- (void)comboBoxWillDismiss:(NSNotification *)notification; +- (void)comboBoxWillPopUp:(NSNotification *)notification; +@end // wxPoserNSComboBox +WX_DECLARE_GET_OBJC_CLASS(wxPoserNSComboBox,NSComboBox) + +//WX_IMPLEMENT_POSER(wxPoserNSComboBox); +@implementation wxPoserNSComboBox : NSComboBox + +- (void)comboBoxSelectionDidChange:(NSNotification *)notification +{ + wxCocoaNSComboBox *win = wxCocoaNSComboBox::GetFromCocoa(self); + win->doWxEvent(wxEVT_COMMAND_COMBOBOX_SELECTED); +} + +- (void)comboBoxSelectionIsChanging:(NSNotification *)notification +{ + //... +} + +- (void)comboBoxWillDismiss:(NSNotification *)notification +{ + //... +} + +- (void)comboBoxWillPopUp:(NSNotification *)notification +{ + //... +} + +@end // implementation wxPoserNSComboBox +WX_IMPLEMENT_GET_OBJC_CLASS(wxPoserNSComboBox,NSComboBox) #include "wx/cocoa/autorelease.h" #include "wx/cocoa/string.h" #import -IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxTextCtrl) -BEGIN_EVENT_TABLE(wxComboBox, wxTextCtrl) +IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl) +BEGIN_EVENT_TABLE(wxComboBox, wxControl) END_EVENT_TABLE() -// WX_IMPLEMENT_COCOA_OWNER(wxComboBox,NSComboBox,NSTextField,NSView) +WX_IMPLEMENT_COCOA_OWNER(wxComboBox,NSComboBox,NSTextField,NSView) +WX_IMPLEMENT_COCOA_OWNER(wxComboBox,NSTextField,NSControl,NSView) bool wxComboBox::Create(wxWindow *parent, wxWindowID winid, const wxString& value, @@ -56,7 +203,7 @@ bool wxComboBox::Create(wxWindow *parent, wxWindowID winid, return false; m_cocoaNSView = NULL; - SetNSTextField([[NSComboBox alloc] initWithFrame:MakeDefaultNSRect(size)]); + SetNSComboBox([[WX_GET_OBJC_CLASS(wxPoserNSComboBox) alloc] initWithFrame:MakeDefaultNSRect(size)]); [m_cocoaNSView release]; [GetNSTextField() setStringValue:wxNSStringWithWxString(value.c_str())]; [GetNSControl() sizeToFit]; @@ -64,84 +211,200 @@ bool wxComboBox::Create(wxWindow *parent, wxWindowID winid, m_parent->CocoaAddChild(this); SetInitialFrameRect(pos,size); + wxComboBox::Append(n, choices); + + [GetNSComboBox() setCompletes:true]; //autocomplete :) + return true; } wxComboBox::~wxComboBox() { + DisassociateNSComboBox(GetNSComboBox()); } -void wxComboBox::SetSelection(int) +void wxComboBox::doWxEvent(int nEvent) { + wxCommandEvent event2(wxEVT_COMMAND_COMBOBOX_SELECTED, GetId() ); + event2.SetInt(GetSelection()); + event2.SetEventObject(this); + event2.SetString(GetStringSelection()); + HandleWindowEvent(event2); + + // For consistency with MSW and GTK, also send a text updated event + // After all, the text is updated when a selection is made + wxCommandEvent TextEvent( wxEVT_COMMAND_TEXT_UPDATED, GetId() ); + TextEvent.SetString( GetStringSelection() ); + TextEvent.SetEventObject( this ); + HandleWindowEvent( TextEvent ); } -wxString wxComboBox::GetStringSelection() + +void wxComboBox::SetSelection(int nSelection) { - return wxEmptyString; + [GetNSComboBox() selectItemAtIndex:nSelection]; } -void wxComboBox::SetStringSelection(const wxString& selection) +wxString wxComboBox::GetStringSelection() { + return wxStringWithNSString([GetNSComboBox() objectValueOfSelectedItem]); } -void wxComboBox::Clear() +void wxComboBox::DoClear() { + [GetNSComboBox() removeAllItems]; + m_Datas.Clear(); } -void wxComboBox::Delete(int) +void wxComboBox::DoDeleteOneItem(unsigned int n) { + [GetNSComboBox() removeItemAtIndex:n]; + m_Datas.RemoveAt(n); } -int wxComboBox::GetCount() const +unsigned int wxComboBox::GetCount() const { - return 0; + return (unsigned int)[GetNSComboBox() numberOfItems]; } -wxString wxComboBox::GetString(int) const +wxString wxComboBox::GetString(unsigned int nIndex) const { - return wxEmptyString; + return wxStringWithNSString([GetNSComboBox() itemObjectValueAtIndex:nIndex]); } -void wxComboBox::SetString(int, const wxString&) +void wxComboBox::SetString(unsigned int nIndex, const wxString& szString) { + wxAutoNSAutoreleasePool pool; + //FIXME: There appears to be no "set item data" method - maybe + //an assignment would work? + [GetNSComboBox() removeItemAtIndex:nIndex]; + [GetNSComboBox() insertItemWithObjectValue:wxNSStringWithWxString(szString) atIndex:nIndex]; } -int wxComboBox::FindString(const wxString&) const +int wxComboBox::FindString(const wxString& szItem, bool bCase) const { - return 0; + // FIXME: use wxItemContainerImmutable::FindString for bCase parameter + return [GetNSComboBox() indexOfItemWithObjectValue:wxNSStringWithWxString(szItem)]; } int wxComboBox::GetSelection() const { - return 0; + return [GetNSComboBox() indexOfSelectedItem]; } -int wxComboBox::DoAppend(const wxString&) +int wxComboBox::DoInsertItems(const wxArrayStringsAdapter& items, + unsigned int pos, + void **clientData, + wxClientDataType type) +{ + wxAutoNSAutoreleasePool pool; + const unsigned int numITems = items.GetCount(); + for ( unsigned int i = 0; i < numITems; ++i, ++pos ) + { + [GetNSComboBox() insertItemWithObjectValue:wxNSStringWithWxString(items[i]) atIndex:(pos)]; + m_Datas.Insert(NULL, pos); + AssignNewItemClientData(pos, clientData, i, type); + } + return pos - 1; +} + +void wxComboBox::DoSetItemClientData(unsigned int nIndex, void* pData) +{ + m_Datas[nIndex] = pData; +} + +void* wxComboBox::DoGetItemClientData(unsigned int nIndex) const +{ + return m_Datas[nIndex]; +} + +///////////////////////////////////////////////////////////////////////////// +// wxTextEntry virtual implementations: + +void wxComboBox::WriteText(wxString const&) +{ +} + +wxString wxComboBox::GetValue() const +{ + wxAutoNSAutoreleasePool pool; + return wxStringWithNSString([GetNSTextField() stringValue]); +} + +void wxComboBox::Remove(long, long) +{ +} + +void wxComboBox::Cut() +{ +} + +void wxComboBox::Copy() { - return 0; } -int wxComboBox::DoInsert(const wxString&, int) +void wxComboBox::Paste() +{ +} + +void wxComboBox::Undo() +{ +} + +void wxComboBox::Redo() +{ +} + +bool wxComboBox::CanUndo() const +{ + return false; +} + +bool wxComboBox::CanRedo() const +{ + return false; +} + +void wxComboBox::SetInsertionPoint(long) +{ +} + +long wxComboBox::GetInsertionPoint() const { return 0; } -void wxComboBox::DoSetItemClientData(int, void*) +wxTextPos wxComboBox::GetLastPosition() const +{ + // working - returns the size of the wxString + return (long)(GetValue().Len()); +} + +void wxComboBox::SetSelection(long, long) { } -void* wxComboBox::DoGetItemClientData(int) const +void wxComboBox::GetSelection(long*, long*) const { - return NULL; } -void wxComboBox::DoSetItemClientObject(int, wxClientData*) +bool wxComboBox::IsEditable() const { + return [GetNSTextField() isEditable]; } -wxClientData* wxComboBox::DoGetItemClientObject(int) const +void wxComboBox::SetEditable(bool editable) { - return NULL; + // first ensure that the current value is stored (in case the user had not finished editing + // before SetEditable(FALSE) was called) + DoSetValue(GetValue(),1); + + [GetNSTextField() setEditable: editable]; + + // forces the focus on the textctrl to be lost - while focus is still maintained + // after SetEditable(FALSE) the user may still edit the control + // (might not the best way to do this..) + [GetNSTextField() abortEditing]; } -#endif //wxUSE_COMBOBOX +#endif // wxUSE_COMBOBOX