variables/functions from wxWindow; used wxTranslateMouseEvent instead of duplicating its functionality. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@20217 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
708 lines
18 KiB
C++
708 lines
18 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Name: listbox.cpp
|
|
// Purpose: wxListBox
|
|
// Author: Julian Smart
|
|
// Modified by:
|
|
// Created: 17/09/98
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) Julian Smart
|
|
// Licence: wxWindows licence
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef __GNUG__
|
|
#pragma implementation "listbox.h"
|
|
#endif
|
|
|
|
#ifdef __VMS
|
|
#define XtParent XTPARENT
|
|
#define XtDisplay XTDISPLAY
|
|
#endif
|
|
|
|
# include "wx/listbox.h"
|
|
#include "wx/settings.h"
|
|
#include "wx/dynarray.h"
|
|
#include "wx/log.h"
|
|
#include "wx/utils.h"
|
|
|
|
#ifdef __VMS__
|
|
#pragma message disable nosimpint
|
|
#endif
|
|
#include <Xm/List.h>
|
|
#ifdef __VMS__
|
|
#pragma message enable nosimpint
|
|
#endif
|
|
#include "wx/motif/private.h"
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl)
|
|
|
|
static void wxListBoxCallback(Widget w,
|
|
XtPointer clientData,
|
|
XmListCallbackStruct * cbs);
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxSizeKeeper
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// helper class to reduce code duplication
|
|
class wxSizeKeeper
|
|
{
|
|
int m_x, m_y;
|
|
wxWindow* m_w;
|
|
public:
|
|
wxSizeKeeper( wxWindow* w )
|
|
: m_w( w )
|
|
{
|
|
m_w->GetSize( &m_x, &m_y );
|
|
}
|
|
|
|
void Restore()
|
|
{
|
|
int x, y;
|
|
|
|
m_w->GetSize( &x, &y );
|
|
if( x != m_x || y != m_y )
|
|
m_w->SetSize( -1, -1, m_x, m_y );
|
|
}
|
|
};
|
|
|
|
// ============================================================================
|
|
// list box control implementation
|
|
// ============================================================================
|
|
|
|
// Listbox item
|
|
wxListBox::wxListBox()
|
|
{
|
|
m_noItems = 0;
|
|
}
|
|
|
|
bool wxListBox::Create(wxWindow *parent, wxWindowID id,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
int n, const wxString choices[],
|
|
long style,
|
|
const wxValidator& validator,
|
|
const wxString& name)
|
|
{
|
|
if( !wxControl::CreateControl( parent, id, pos, size, style,
|
|
validator, name ) )
|
|
return FALSE;
|
|
|
|
m_noItems = n;
|
|
m_backgroundColour = * wxWHITE;
|
|
|
|
Widget parentWidget = (Widget) parent->GetClientWidget();
|
|
|
|
WXFontType fontType = (WXFontType)NULL;
|
|
|
|
if( m_font.Ok() )
|
|
{
|
|
fontType = m_font.GetFontType(XtDisplay(parentWidget));
|
|
}
|
|
|
|
Arg args[4];
|
|
int count = 0;
|
|
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( fontType )
|
|
{
|
|
XtSetArg( args[count], (String)wxFont::GetFontTag(), fontType );
|
|
++count;
|
|
}
|
|
if( m_windowStyle & wxLB_ALWAYS_SB )
|
|
{
|
|
XtSetArg( args[count], XmNscrollBarDisplayPolicy, XmSTATIC );
|
|
++count;
|
|
}
|
|
|
|
Widget listWidget =
|
|
XmCreateScrolledList(parentWidget,
|
|
wxConstCast(name.c_str(), char), args, count);
|
|
|
|
m_mainWidget = (WXWidget) listWidget;
|
|
|
|
Set(n, choices);
|
|
|
|
XtManageChild (listWidget);
|
|
|
|
wxSize best = GetBestSize();
|
|
if( size.x != -1 ) best.x = size.x;
|
|
if( size.y != -1 ) best.y = size.y;
|
|
|
|
XtAddCallback (listWidget,
|
|
XmNbrowseSelectionCallback,
|
|
(XtCallbackProc) wxListBoxCallback,
|
|
(XtPointer) this);
|
|
XtAddCallback (listWidget,
|
|
XmNextendedSelectionCallback,
|
|
(XtCallbackProc) wxListBoxCallback,
|
|
(XtPointer) this);
|
|
XtAddCallback (listWidget,
|
|
XmNmultipleSelectionCallback,
|
|
(XtCallbackProc) wxListBoxCallback,
|
|
(XtPointer) this);
|
|
XtAddCallback (listWidget,
|
|
XmNdefaultActionCallback,
|
|
(XtCallbackProc) wxListBoxCallback,
|
|
(XtPointer) this);
|
|
|
|
AttachWidget (parent, m_mainWidget, (WXWidget) NULL,
|
|
pos.x, pos.y, best.x, best.y);
|
|
|
|
ChangeBackgroundColour();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
wxListBox::~wxListBox()
|
|
{
|
|
if( HasClientObjectData() )
|
|
m_clientDataDict.DestroyData();
|
|
}
|
|
|
|
void wxListBox::SetSelectionPolicy()
|
|
{
|
|
Widget listBox = (Widget)m_mainWidget;
|
|
Arg args[3];
|
|
|
|
XtSetArg( args[0], XmNlistSizePolicy, XmCONSTANT );
|
|
|
|
XtSetArg( args[1], XmNselectionPolicy,
|
|
( m_windowStyle & wxLB_MULTIPLE ) ? XmMULTIPLE_SELECT :
|
|
( m_windowStyle & wxLB_EXTENDED ) ? XmEXTENDED_SELECT :
|
|
XmBROWSE_SELECT );
|
|
|
|
XtSetValues( listBox, args, 2 );
|
|
}
|
|
|
|
void wxListBox::DoSetFirstItem( int N )
|
|
{
|
|
int count, length;
|
|
|
|
if (N < 0)
|
|
return;
|
|
XtVaGetValues ((Widget) m_mainWidget,
|
|
XmNvisibleItemCount, &count,
|
|
XmNitemCount, &length,
|
|
NULL);
|
|
if ((N + count) >= length)
|
|
N = length - count;
|
|
XmListSetPos ((Widget) m_mainWidget, N + 1);
|
|
}
|
|
|
|
void wxListBox::Delete(int N)
|
|
{
|
|
wxSizeKeeper sk( this );
|
|
Widget listBox = (Widget) m_mainWidget;
|
|
|
|
bool managed = XtIsManaged(listBox);
|
|
|
|
if (managed)
|
|
XtUnmanageChild (listBox);
|
|
|
|
XmListDeletePos (listBox, N + 1);
|
|
|
|
if (managed)
|
|
XtManageChild (listBox);
|
|
|
|
sk.Restore();
|
|
m_clientDataDict.Delete(N, HasClientObjectData());
|
|
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] = wxStringToXmString (items[i]);
|
|
|
|
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 wxDoFindStringInList(Widget w, const wxString& s)
|
|
{
|
|
wxXmString str( s );
|
|
int *positions = NULL;
|
|
int no_positions = 0;
|
|
bool success = XmListGetMatchPos (w, str(),
|
|
&positions, &no_positions);
|
|
|
|
if (success)
|
|
{
|
|
int pos = positions[0];
|
|
if (positions)
|
|
XtFree ((char *) positions);
|
|
return pos - 1;
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
int wxListBox::FindString(const wxString& s) const
|
|
{
|
|
return wxDoFindStringInList( (Widget)m_mainWidget, s );
|
|
}
|
|
|
|
void wxListBox::Clear()
|
|
{
|
|
if (m_noItems <= 0)
|
|
return;
|
|
|
|
wxSizeKeeper sk( this );
|
|
Widget listBox = (Widget) m_mainWidget;
|
|
|
|
XmListDeleteAllItems (listBox);
|
|
if( HasClientObjectData() )
|
|
m_clientDataDict.DestroyData();
|
|
|
|
sk.Restore();
|
|
|
|
m_noItems = 0;
|
|
}
|
|
|
|
void wxListBox::SetSelection(int N, bool select)
|
|
{
|
|
m_inSetValue = TRUE;
|
|
if (select)
|
|
{
|
|
#if 0
|
|
if (m_windowStyle & wxLB_MULTIPLE)
|
|
{
|
|
int *selections = NULL;
|
|
int n = GetSelections (&selections);
|
|
|
|
// This hack is supposed to work, to make it possible
|
|
// to select more than one item, but it DOESN'T under Motif 1.1.
|
|
|
|
XtVaSetValues ((Widget) m_mainWidget,
|
|
XmNselectionPolicy, XmMULTIPLE_SELECT,
|
|
NULL);
|
|
|
|
int i;
|
|
for (i = 0; i < n; i++)
|
|
XmListSelectPos ((Widget) m_mainWidget,
|
|
selections[i] + 1, FALSE);
|
|
|
|
XmListSelectPos ((Widget) m_mainWidget, N + 1, FALSE);
|
|
|
|
XtVaSetValues ((Widget) m_mainWidget,
|
|
XmNselectionPolicy, XmEXTENDED_SELECT,
|
|
NULL);
|
|
}
|
|
else
|
|
#endif // 0
|
|
XmListSelectPos ((Widget) m_mainWidget, N + 1, FALSE);
|
|
|
|
}
|
|
else
|
|
XmListDeselectPos ((Widget) m_mainWidget, N + 1);
|
|
|
|
m_inSetValue = FALSE;
|
|
}
|
|
|
|
bool wxListBox::IsSelected(int N) const
|
|
{
|
|
// In Motif, no simple way to determine if the item is selected.
|
|
wxArrayInt theSelections;
|
|
int count = GetSelections (theSelections);
|
|
if (count == 0)
|
|
return FALSE;
|
|
else
|
|
{
|
|
int j;
|
|
for (j = 0; j < count; j++)
|
|
if (theSelections[j] == N)
|
|
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 number of selections and an array of selected integers
|
|
int wxListBox::GetSelections(wxArrayInt& aSelections) const
|
|
{
|
|
aSelections.Empty();
|
|
|
|
Widget listBox = (Widget) m_mainWidget;
|
|
int *posList = NULL;
|
|
int posCnt = 0;
|
|
bool flag = XmListGetSelectedPos (listBox, &posList, &posCnt);
|
|
if (flag)
|
|
{
|
|
if (posCnt > 0)
|
|
{
|
|
aSelections.Alloc(posCnt);
|
|
|
|
int i;
|
|
for (i = 0; i < posCnt; i++)
|
|
aSelections.Add(posList[i] - 1);
|
|
|
|
XtFree ((char *) posList);
|
|
return posCnt;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
// Get single selection, for single choice list items
|
|
int wxDoGetSelectionInList(Widget listBox)
|
|
{
|
|
int *posList = NULL;
|
|
int posCnt = 0;
|
|
bool flag = XmListGetSelectedPos (listBox, &posList, &posCnt);
|
|
if (flag)
|
|
{
|
|
int id = -1;
|
|
if (posCnt > 0)
|
|
id = posList[0] - 1;
|
|
XtFree ((char *) posList);
|
|
return id;
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
int wxListBox::GetSelection() const
|
|
{
|
|
return wxDoGetSelectionInList((Widget) m_mainWidget);
|
|
}
|
|
|
|
// Find string for position
|
|
wxString wxDoGetStringInList( Widget listBox, int n )
|
|
{
|
|
XmString *strlist;
|
|
int count;
|
|
XtVaGetValues( listBox,
|
|
XmNitemCount, &count,
|
|
XmNitems, &strlist,
|
|
NULL );
|
|
if( n < count && n >= 0 )
|
|
return wxXmStringToString( strlist[n] );
|
|
else
|
|
return wxEmptyString;
|
|
}
|
|
|
|
wxString wxListBox::GetString( int n ) const
|
|
{
|
|
return wxDoGetStringInList( (Widget)m_mainWidget, n );
|
|
}
|
|
|
|
void wxListBox::DoInsertItems(const wxArrayString& items, int pos)
|
|
{
|
|
wxSizeKeeper sk( this );
|
|
Widget listBox = (Widget) m_mainWidget;
|
|
|
|
bool managed = XtIsManaged(listBox);
|
|
|
|
if (managed)
|
|
XtUnmanageChild(listBox);
|
|
|
|
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
|
|
#if XmVersion > 1001
|
|
for (i = 0; i < items.GetCount(); i++)
|
|
text[i] = wxStringToXmString(items[i]);
|
|
XmListAddItemsUnselected(listBox, text, items.GetCount(), pos+1);
|
|
#else
|
|
for (i = 0; i < items.GetCount(); i++)
|
|
{
|
|
text[i] = wxStringToXmString(items[i]);
|
|
// Another Sergey correction
|
|
XmListAddItemUnselected(listBox, text[i], pos+i+1);
|
|
}
|
|
#endif
|
|
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();
|
|
}
|
|
|
|
void wxListBox::SetString(int N, const wxString& s)
|
|
{
|
|
wxSizeKeeper sk( this );
|
|
Widget listBox = (Widget) m_mainWidget;
|
|
|
|
wxXmString text( 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);
|
|
|
|
sk.Restore();
|
|
}
|
|
|
|
void wxListBox::Command (wxCommandEvent & event)
|
|
{
|
|
if (event.m_extraLong)
|
|
SetSelection (event.m_commandInt);
|
|
else
|
|
{
|
|
Deselect (event.m_commandInt);
|
|
return;
|
|
}
|
|
ProcessCommand (event);
|
|
}
|
|
|
|
void wxListBoxCallback (Widget WXUNUSED(w), XtPointer clientData,
|
|
XmListCallbackStruct * cbs)
|
|
{
|
|
wxListBox *item = (wxListBox *) clientData;
|
|
|
|
if (item->InSetValue())
|
|
return;
|
|
|
|
wxEventType evtType;
|
|
|
|
if( cbs->reason == XmCR_DEFAULT_ACTION )
|
|
evtType = wxEVT_COMMAND_LISTBOX_DOUBLECLICKED;
|
|
else
|
|
evtType = wxEVT_COMMAND_LISTBOX_SELECTED;
|
|
|
|
int n = cbs->item_position - 1;
|
|
wxCommandEvent event (evtType, item->GetId());
|
|
if ( item->HasClientObjectData() )
|
|
event.SetClientObject( item->GetClientObject(n) );
|
|
else if ( item->HasClientUntypedData() )
|
|
event.SetClientData( item->GetClientData(n) );
|
|
event.m_commandInt = n;
|
|
event.m_extraLong = TRUE;
|
|
event.SetEventObject(item);
|
|
event.SetString( item->GetString( n ) );
|
|
|
|
int x = -1;
|
|
if( NULL != cbs->event && cbs->event->type == ButtonRelease )
|
|
{
|
|
XButtonEvent* evt = (XButtonEvent*)cbs->event;
|
|
|
|
x = evt->x;
|
|
}
|
|
|
|
switch (cbs->reason)
|
|
{
|
|
case XmCR_MULTIPLE_SELECT:
|
|
case XmCR_BROWSE_SELECT:
|
|
#if wxUSE_CHECKLISTBOX
|
|
item->DoToggleItem( n, x );
|
|
#endif
|
|
case XmCR_DEFAULT_ACTION:
|
|
item->GetEventHandler()->ProcessEvent(event);
|
|
break;
|
|
case XmCR_EXTENDED_SELECT:
|
|
switch (cbs->selection_type)
|
|
{
|
|
case XmINITIAL:
|
|
case XmADDITION:
|
|
case XmMODIFICATION:
|
|
item->DoToggleItem( n, x );
|
|
item->GetEventHandler()->ProcessEvent(event);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
WXWidget wxListBox::GetTopWidget() const
|
|
{
|
|
return (WXWidget) XtParent( (Widget) m_mainWidget );
|
|
}
|
|
|
|
void wxListBox::ChangeBackgroundColour()
|
|
{
|
|
wxWindow::ChangeBackgroundColour();
|
|
|
|
Widget parent = XtParent ((Widget) m_mainWidget);
|
|
Widget hsb, vsb;
|
|
|
|
XtVaGetValues (parent,
|
|
XmNhorizontalScrollBar, &hsb,
|
|
XmNverticalScrollBar, &vsb,
|
|
NULL);
|
|
|
|
/* TODO: should scrollbars be affected? Should probably have separate
|
|
* function to change them (by default, taken from wxSystemSettings)
|
|
*/
|
|
wxColour backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
|
|
wxDoChangeBackgroundColour((WXWidget) hsb, backgroundColour, TRUE);
|
|
wxDoChangeBackgroundColour((WXWidget) vsb, backgroundColour, TRUE);
|
|
|
|
XtVaSetValues (hsb,
|
|
XmNtroughColor, backgroundColour.AllocColour(XtDisplay(hsb)),
|
|
NULL);
|
|
XtVaSetValues (vsb,
|
|
XmNtroughColor, backgroundColour.AllocColour(XtDisplay(vsb)),
|
|
NULL);
|
|
|
|
// MBN: why change parent's background? It looks really ugly.
|
|
// wxDoChangeBackgroundColour((WXWidget) parent, m_backgroundColour, TRUE);
|
|
}
|
|
|
|
void wxListBox::ChangeForegroundColour()
|
|
{
|
|
wxWindow::ChangeForegroundColour();
|
|
|
|
Widget parent = XtParent ((Widget) m_mainWidget);
|
|
Widget hsb, vsb;
|
|
|
|
XtVaGetValues(parent,
|
|
XmNhorizontalScrollBar, &hsb,
|
|
XmNverticalScrollBar, &vsb,
|
|
NULL);
|
|
|
|
/* TODO: should scrollbars be affected? Should probably have separate
|
|
function to change them (by default, taken from wxSystemSettings)
|
|
|
|
wxDoChangeForegroundColour((WXWidget) hsb, m_foregroundColour);
|
|
wxDoChangeForegroundColour((WXWidget) vsb, m_foregroundColour);
|
|
wxDoChangeForegroundColour((WXWidget) parent, m_foregroundColour);
|
|
*/
|
|
}
|
|
|
|
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 );
|
|
}
|
|
|