X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/99ab3e3f56ab43fe1127eb565cad1a619cad0499..68f64b40bfdffd1fc4967dc422a7d89b42545d82:/src/motif/listbox.cpp diff --git a/src/motif/listbox.cpp b/src/motif/listbox.cpp index 1b2a48a223..b0ab1011ab 100644 --- a/src/motif/listbox.cpp +++ b/src/motif/listbox.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Name: listbox.cpp +// Name: src/motif/listbox.cpp // Purpose: wxListBox // Author: Julian Smart // Modified by: @@ -9,20 +9,20 @@ // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ - #pragma implementation "listbox.h" -#endif +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" -#ifdef __VMS -#define XtParent XTPARENT -#define XtDisplay XTDISPLAY -#endif +#if wxUSE_LISTBOX -# include "wx/listbox.h" -#include "wx/settings.h" -#include "wx/dynarray.h" -#include "wx/log.h" -#include "wx/utils.h" +#include "wx/listbox.h" + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/log.h" + #include "wx/utils.h" + #include "wx/settings.h" + #include "wx/arrstr.h" +#endif #ifdef __VMS__ #pragma message disable nosimpint @@ -33,8 +33,6 @@ #endif #include "wx/motif/private.h" - IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl) - static void wxListBoxCallback(Widget w, XtPointer clientData, XmListCallbackStruct * cbs); @@ -47,21 +45,23 @@ static void wxListBoxCallback(Widget w, class wxSizeKeeper { int m_x, m_y; - wxWindow* m_w; + int m_w, m_h; + wxWindow* m_wnd; public: wxSizeKeeper( wxWindow* w ) - : m_w( w ) + : m_wnd( w ) { - m_w->GetSize( &m_x, &m_y ); + m_wnd->GetSize( &m_w, &m_h ); + m_wnd->GetPosition( &m_x, &m_y ); } void Restore() { int x, y; - m_w->GetSize( &x, &y ); + m_wnd->GetSize( &x, &y ); if( x != m_x || y != m_y ) - m_w->SetSize( -1, -1, m_x, m_y ); + m_wnd->SetSize( m_x, m_y, m_w, m_h ); } }; @@ -85,29 +85,37 @@ bool wxListBox::Create(wxWindow *parent, wxWindowID id, { if( !wxControl::CreateControl( parent, id, pos, size, style, validator, name ) ) - return FALSE; + return false; + PreCreation(); - m_noItems = n; - m_backgroundColour = * wxWHITE; + m_noItems = (unsigned int)n; Widget parentWidget = (Widget) parent->GetClientWidget(); + Display* dpy = XtDisplay(parentWidget); - Arg args[3]; + Arg args[4]; int count = 0; - XtSetArg( args[0], XmNlistSizePolicy, XmCONSTANT ); ++count; - XtSetArg( args[1], XmNselectionPolicy, + XtSetArg( args[count], XmNlistSizePolicy, XmCONSTANT ); ++count; + XtSetArg( args[count], XmNselectionPolicy, ( m_windowStyle & wxLB_MULTIPLE ) ? XmMULTIPLE_SELECT : ( m_windowStyle & wxLB_EXTENDED ) ? XmEXTENDED_SELECT : XmBROWSE_SELECT ); ++count; + if( m_font.Ok() ) + { + XtSetArg( args[count], + (String)wxFont::GetFontTag(), m_font.GetFontTypeC(dpy) ); + ++count; + } if( m_windowStyle & wxLB_ALWAYS_SB ) { - XtSetArg( args[2], XmNscrollBarDisplayPolicy, XmSTATIC ); + XtSetArg( args[count], XmNscrollBarDisplayPolicy, XmSTATIC ); ++count; } - Widget listWidget = XmCreateScrolledList(parentWidget, - (char*)name.c_str(), args, count); + Widget listWidget = + XmCreateScrolledList(parentWidget, + name.char_str(), args, count); m_mainWidget = (WXWidget) listWidget; @@ -115,12 +123,9 @@ bool wxListBox::Create(wxWindow *parent, wxWindowID id, XtManageChild (listWidget); - long width = size.x; - long height = size.y; - if (width == -1) - width = 150; - if (height == -1) - height = 80; + wxSize best = GetBestSize(); + if( size.x != -1 ) best.x = size.x; + if( size.y != -1 ) best.y = size.y; XtAddCallback (listWidget, XmNbrowseSelectionCallback, @@ -139,21 +144,24 @@ bool wxListBox::Create(wxWindow *parent, wxWindowID id, (XtCallbackProc) wxListBoxCallback, (XtPointer) this); - ChangeFont(FALSE); - - SetCanAddEventHandler(TRUE); + PostCreation(); AttachWidget (parent, m_mainWidget, (WXWidget) NULL, - pos.x, pos.y, width, height); + pos.x, pos.y, best.x, best.y); - ChangeBackgroundColour(); - - return TRUE; + return true; } -wxListBox::~wxListBox() +bool wxListBox::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, + const wxSize& size, + const wxArrayString& choices, + long style, + const wxValidator& validator, + const wxString& name) { - if( HasClientObjectData() ) - m_clientDataDict.DestroyData(); + wxCArrayString chs(choices); + return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(), + style, validator, name); } void wxListBox::SetSelectionPolicy() @@ -175,8 +183,9 @@ void wxListBox::DoSetFirstItem( int N ) { int count, length; - if (N < 0) + if (!IsValid(N)) return; + XtVaGetValues ((Widget) m_mainWidget, XmNvisibleItemCount, &count, XmNitemCount, &length, @@ -186,131 +195,60 @@ void wxListBox::DoSetFirstItem( int N ) XmListSetPos ((Widget) m_mainWidget, N + 1); } -void wxListBox::Delete(int N) +void wxListBox::DoDeleteOneItem(unsigned int n) { - wxSizeKeeper sk( this ); Widget listBox = (Widget) m_mainWidget; - bool managed = XtIsManaged(listBox); - - if (managed) - XtUnmanageChild (listBox); + XmListDeletePos (listBox, n + 1); - XmListDeletePos (listBox, N + 1); - - if (managed) - XtManageChild (listBox); - - sk.Restore(); - m_clientDataDict.Delete(N, HasClientObjectData()); + wxListBoxBase::DoDeleteOneItem(n); m_noItems --; } -int wxListBox::DoAppend(const wxString& item) -{ - wxSizeKeeper sk( this ); - Widget listBox = (Widget) m_mainWidget; - - bool managed = XtIsManaged(listBox); - - if (managed) - XtUnmanageChild (listBox); - int n; - XtVaGetValues (listBox, XmNitemCount, &n, NULL); - wxXmString text( item ); - // XmListAddItem(listBox, text, n + 1); - XmListAddItemUnselected (listBox, text(), 0); - - // It seems that if the list is cleared, we must re-ask for - // selection policy!! - SetSelectionPolicy(); - - if (managed) - XtManageChild (listBox); - - sk.Restore(); - m_noItems ++; - - return GetCount() - 1; -} - -void wxListBox::DoSetItems(const wxArrayString& items, void** clientData) -{ - wxSizeKeeper sk( this ); - Widget listBox = (Widget) m_mainWidget; - - if( HasClientObjectData() ) - m_clientDataDict.DestroyData(); - - bool managed = XtIsManaged(listBox); - - if (managed) - XtUnmanageChild (listBox); - XmString *text = new XmString[items.GetCount()]; - size_t i; - for (i = 0; i < items.GetCount(); ++i) - text[i] = XmStringCreateSimple ((char*)items[i].c_str()); - - if ( clientData ) - for (i = 0; i < items.GetCount(); ++i) - m_clientDataDict.Set(i, (wxClientData*)clientData[i], FALSE); - - XmListAddItems (listBox, text, items.GetCount(), 0); - for (i = 0; i < items.GetCount(); i++) - XmStringFree (text[i]); - delete[] text; - - // It seems that if the list is cleared, we must re-ask for - // selection policy!! - SetSelectionPolicy(); - - if (managed) - XtManageChild (listBox); - - sk.Restore(); - - m_noItems = items.GetCount(); -} - -int wxListBox::FindString(const wxString& s) const +int wxDoFindStringInList(Widget w, const wxString& s) { wxXmString str( s ); int *positions = NULL; int no_positions = 0; - bool success = XmListGetMatchPos ((Widget) m_mainWidget, str(), + bool success = XmListGetMatchPos (w, str(), &positions, &no_positions); - if (success) + if (success && positions) { int pos = positions[0]; - if (positions) - XtFree ((char *) positions); + XtFree ((char *) positions); return pos - 1; } else return -1; } -void wxListBox::Clear() +int wxListBox::FindString(const wxString& s, bool WXUNUSED(bCase)) const { - if (m_noItems <= 0) + // FIXME: back to base class for not supported value of bCase + + return wxDoFindStringInList( (Widget)m_mainWidget, s ); +} + +void wxListBox::DoClear() +{ + if (!m_noItems) return; wxSizeKeeper sk( this ); Widget listBox = (Widget) m_mainWidget; XmListDeleteAllItems (listBox); - if( HasClientObjectData() ) - m_clientDataDict.DestroyData(); sk.Restore(); + wxListBoxBase::DoClear(); m_noItems = 0; } -void wxListBox::SetSelection(int N, bool select) +void wxListBox::DoSetSelection(int N, bool select) { - m_inSetValue = TRUE; + m_inSetValue = true; if (select) { #if 0 @@ -329,9 +267,9 @@ void wxListBox::SetSelection(int N, bool select) int i; for (i = 0; i < n; i++) XmListSelectPos ((Widget) m_mainWidget, - selections[i] + 1, FALSE); + selections[i] + 1, False); - XmListSelectPos ((Widget) m_mainWidget, N + 1, FALSE); + XmListSelectPos ((Widget) m_mainWidget, N + 1, False); XtVaSetValues ((Widget) m_mainWidget, XmNselectionPolicy, XmEXTENDED_SELECT, @@ -339,13 +277,13 @@ void wxListBox::SetSelection(int N, bool select) } else #endif // 0 - XmListSelectPos ((Widget) m_mainWidget, N + 1, FALSE); + XmListSelectPos ((Widget) m_mainWidget, N + 1, False); } else XmListDeselectPos ((Widget) m_mainWidget, N + 1); - m_inSetValue = FALSE; + m_inSetValue = false; } bool wxListBox::IsSelected(int N) const @@ -354,35 +292,15 @@ bool wxListBox::IsSelected(int N) const wxArrayInt theSelections; int count = GetSelections (theSelections); if (count == 0) - return FALSE; + return false; else { int j; for (j = 0; j < count; j++) if (theSelections[j] == N) - return TRUE; + return true; } - return FALSE; -} - -void wxListBox::DoSetItemClientObject(int n, wxClientData* clientData) -{ - m_clientDataDict.Set(n, clientData, FALSE); -} - -wxClientData* wxListBox::DoGetItemClientObject(int n) const -{ - return m_clientDataDict.Get(n); -} - -void *wxListBox::DoGetItemClientData(int N) const -{ - return (void*)m_clientDataDict.Get(N); -} - -void wxListBox::DoSetItemClientData(int N, void *Client_data) -{ - m_clientDataDict.Set(N, (wxClientData*)Client_data, FALSE); + return false; } // Return number of selections and an array of selected integers @@ -415,9 +333,8 @@ int wxListBox::GetSelections(wxArrayInt& aSelections) const } // Get single selection, for single choice list items -int wxListBox::GetSelection() const +int wxDoGetSelectionInList(Widget listBox) { - Widget listBox = (Widget) m_mainWidget; int *posList = NULL; int posCnt = 0; bool flag = XmListGetSelectedPos (listBox, &posList, &posCnt); @@ -433,73 +350,71 @@ int wxListBox::GetSelection() const return -1; } +int wxListBox::GetSelection() const +{ + return wxDoGetSelectionInList((Widget) m_mainWidget); +} + // Find string for position -wxString wxListBox::GetString(int N) const +wxString wxDoGetStringInList( Widget listBox, int n ) { - Widget listBox = (Widget) m_mainWidget; XmString *strlist; - int n; - XtVaGetValues (listBox, XmNitemCount, &n, XmNitems, &strlist, NULL); - if (N <= n && N >= 0) - { - char *txt; - if (XmStringGetLtoR (strlist[N], XmSTRING_DEFAULT_CHARSET, &txt)) - { - wxString str(txt); - XtFree (txt); - return str; - } - else - return wxEmptyString; - } + int count; + XtVaGetValues( listBox, + XmNitemCount, &count, + XmNitems, &strlist, + NULL ); + if( n < count && n >= 0 ) + return wxXmStringToString( strlist[n] ); else return wxEmptyString; } -void wxListBox::DoInsertItems(const wxArrayString& items, int pos) +wxString wxListBox::GetString(unsigned int n) const { - wxSizeKeeper sk( this ); - Widget listBox = (Widget) m_mainWidget; + return wxDoGetStringInList( (Widget)m_mainWidget, n ); +} - bool managed = XtIsManaged(listBox); +int wxListBox::DoInsertItems(const wxArrayStringsAdapter & items, + unsigned int pos, + void **clientData, wxClientDataType type) +{ + Widget listBox = (Widget) m_mainWidget; - if (managed) - XtUnmanageChild(listBox); + const unsigned int numItems = items.GetCount(); - XmString *text = new XmString[items.GetCount()]; - size_t i; - // Steve Hammes: Motif 1.1 compatibility - // #if XmVersion > 1100 - // Corrected by Sergey Krasnov from Steve Hammes' code + XmString *text = new XmString[numItems]; + unsigned int i; #if XmVersion > 1001 - for (i = 0; i < items.GetCount(); i++) - text[i] = XmStringCreateSimple((char*)items[i].c_str()); - XmListAddItemsUnselected(listBox, text, items.GetCount(), pos+1); + for (i = 0; i < numItems; i++) + { + text[i] = wxStringToXmString(items[i]); + } + XmListAddItemsUnselected(listBox, text, numItems, GetMotifPosition(pos)); + InsertNewItemsClientData(pos, numItems, clientData, type); #else - for (i = 0; i < items.GetCount(); i++) + AllocClientData(numItems); + + unsigned int idx = pos; + for ( i = 0; i < numItems; i++, idx++ ) { - text[i] = XmStringCreateSimple((char*)items[i].c_str()); - // Another Sergey correction - XmListAddItemUnselected(listBox, text[i], pos+i+1); + text[i] = wxStringToXmString(items[i]); + XmListAddItemUnselected(listBox, text[i], GetMotifPosition(idx)); + InsertNewItemClientData(idx, clientData, i, type); } #endif - for (i = 0; i < items.GetCount(); i++) + for (i = 0; i < numItems; i++) XmStringFree(text[i]); delete[] text; - // It seems that if the list is cleared, we must re-ask for - // selection policy!! - SetSelectionPolicy(); - - if (managed) - XtManageChild(listBox); + m_noItems += numItems; - sk.Restore(); + SetSelectionPolicy(); - m_noItems += items.GetCount(); + return pos + numItems - 1; } -void wxListBox::SetString(int N, const wxString& s) +void wxListBox::SetString(unsigned int n, const wxString& s) { wxSizeKeeper sk( this ); Widget listBox = (Widget) m_mainWidget; @@ -508,19 +423,19 @@ void wxListBox::SetString(int N, const wxString& s) // delete the item and add it again. // FIXME isn't there a way to change it in place? - XmListDeletePos (listBox, N+1); - XmListAddItem (listBox, text(), N+1); + XmListDeletePos (listBox, n+1); + XmListAddItem (listBox, text(), n+1); sk.Restore(); } void wxListBox::Command (wxCommandEvent & event) { - if (event.m_extraLong) - SetSelection (event.m_commandInt); + if (event.GetExtraLong()) + SetSelection (event.GetInt()); else { - Deselect (event.m_commandInt); + Deselect (event.GetInt()); return; } ProcessCommand (event); @@ -547,8 +462,8 @@ void wxListBoxCallback (Widget WXUNUSED(w), XtPointer clientData, event.SetClientObject( item->GetClientObject(n) ); else if ( item->HasClientUntypedData() ) event.SetClientData( item->GetClientData(n) ); - event.m_commandInt = n; - event.m_extraLong = TRUE; + event.SetInt(n); + event.SetExtraLong(true); event.SetEventObject(item); event.SetString( item->GetString( n ) ); @@ -568,7 +483,7 @@ void wxListBoxCallback (Widget WXUNUSED(w), XtPointer clientData, item->DoToggleItem( n, x ); #endif case XmCR_DEFAULT_ACTION: - item->GetEventHandler()->ProcessEvent(event); + item->HandleWindowEvent(event); break; case XmCR_EXTENDED_SELECT: switch (cbs->selection_type) @@ -577,7 +492,7 @@ void wxListBoxCallback (Widget WXUNUSED(w), XtPointer clientData, case XmADDITION: case XmMODIFICATION: item->DoToggleItem( n, x ); - item->GetEventHandler()->ProcessEvent(event); + item->HandleWindowEvent(event); break; } break; @@ -605,8 +520,8 @@ void wxListBox::ChangeBackgroundColour() * function to change them (by default, taken from wxSystemSettings) */ wxColour backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE); - DoChangeBackgroundColour((WXWidget) hsb, backgroundColour, TRUE); - DoChangeBackgroundColour((WXWidget) vsb, backgroundColour, TRUE); + wxDoChangeBackgroundColour((WXWidget) hsb, backgroundColour, true); + wxDoChangeBackgroundColour((WXWidget) vsb, backgroundColour, true); XtVaSetValues (hsb, XmNtroughColor, backgroundColour.AllocColour(XtDisplay(hsb)), @@ -615,7 +530,8 @@ void wxListBox::ChangeBackgroundColour() XmNtroughColor, backgroundColour.AllocColour(XtDisplay(vsb)), NULL); - DoChangeBackgroundColour((WXWidget) parent, m_backgroundColour, TRUE); + // MBN: why change parent's background? It looks really ugly. + // wxDoChangeBackgroundColour((WXWidget) parent, m_backgroundColour, true); } void wxListBox::ChangeForegroundColour() @@ -633,13 +549,62 @@ void wxListBox::ChangeForegroundColour() /* TODO: should scrollbars be affected? Should probably have separate function to change them (by default, taken from wxSystemSettings) - DoChangeForegroundColour((WXWidget) hsb, m_foregroundColour); - DoChangeForegroundColour((WXWidget) vsb, m_foregroundColour); - DoChangeForegroundColour((WXWidget) parent, m_foregroundColour); + wxDoChangeForegroundColour((WXWidget) hsb, m_foregroundColour); + wxDoChangeForegroundColour((WXWidget) vsb, m_foregroundColour); + wxDoChangeForegroundColour((WXWidget) parent, m_foregroundColour); */ } -int wxListBox::GetCount() const +unsigned int wxListBox::GetCount() const { return m_noItems; } + +#define LIST_SCROLL_SPACING 6 + +wxSize wxDoGetListBoxBestSize( Widget listWidget, const wxWindow* window ) +{ + int max; + Dimension spacing, highlight, xmargin, ymargin, shadow; + int width = 0; + int x, y; + + XtVaGetValues( listWidget, + XmNitemCount, &max, + XmNlistSpacing, &spacing, + XmNhighlightThickness, &highlight, + XmNlistMarginWidth, &xmargin, + XmNlistMarginHeight, &ymargin, + XmNshadowThickness, &shadow, + NULL ); + + for( size_t i = 0; i < (size_t)max; ++i ) + { + window->GetTextExtent( wxDoGetStringInList( listWidget, i ), &x, &y ); + width = wxMax( width, x ); + } + + // use some arbitrary value if there are no strings + if( width == 0 ) + width = 100; + + // get my + window->GetTextExtent( "v", &x, &y ); + + // make it a little larger than widest string, plus the scrollbar + width += wxSystemSettings::GetMetric( wxSYS_VSCROLL_X ) + + 2 * highlight + LIST_SCROLL_SPACING + 2 * xmargin + 2 * shadow; + + // at least 3 items, at most 10 + int height = wxMax( 3, wxMin( 10, max ) ) * + ( y + spacing + 2 * highlight ) + 2 * ymargin + 2 * shadow; + + return wxSize( width, height ); +} + +wxSize wxListBox::DoGetBestSize() const +{ + return wxDoGetListBoxBestSize( (Widget)m_mainWidget, this ); +} + +#endif // wxUSE_LISTBOX