Files
wxWidgets/src/osx/listbox_osx.cpp
Vadim Zeitlin f58438058b Show the first, not the last, inserted item in wxListBox in wxOSX.
The listbox showed its last, not first, item after creation in wxOSX which was
inconsistent with the other ports and generally inconvenient.

Fix this by ensuring that the first item being inserted is shown, and not the
last one as was (implicitly) the case before. A better fix would be to avoid
scrolling entirely but I don't know how to do this with NSClipView.

Closes #12365.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@66038 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2010-11-05 21:42:49 +00:00

421 lines
11 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: src/osx/carbon/listbox.cpp
// Purpose: wxListBox
// Author: Stefan Csomor
// Modified by:
// Created: 1998-01-01
// RCS-ID: $Id$
// Copyright: (c) Stefan Csomor
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#if wxUSE_LISTBOX
#include "wx/listbox.h"
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/intl.h"
#include "wx/utils.h"
#include "wx/settings.h"
#include "wx/arrstr.h"
#include "wx/dcclient.h"
#endif
IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControlWithItems)
BEGIN_EVENT_TABLE(wxListBox, wxControl)
END_EVENT_TABLE()
#include "wx/osx/private.h"
// ============================================================================
// list box control implementation
// ============================================================================
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 )
{
wxCArrayString chs(choices);
return Create(
parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
style, validator, name );
}
wxListWidgetImpl* wxListBox::GetListPeer() const
{
wxListWidgetImpl* impl = dynamic_cast<wxListWidgetImpl*> ( GetPeer() );
return impl;
}
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 )
{
m_blockEvents = false;
m_macIsUserPane = false;
wxASSERT_MSG( !(style & wxLB_MULTIPLE) || !(style & wxLB_EXTENDED),
wxT("only a single listbox selection mode can be specified") );
if ( !wxListBoxBase::Create( parent, id, pos, size, style & ~(wxHSCROLL | wxVSCROLL), validator, name ) )
return false;
if ( IsSorted() )
m_strings.sorted = new wxSortedArrayString;
else
m_strings.unsorted = new wxArrayString;
m_peer = wxWidgetImpl::CreateListBox( this, parent, id, pos, size, style, GetExtraStyle() );
MacPostControlCreate( pos, size );
m_textColumn = GetListPeer()->InsertTextColumn(0,wxEmptyString);
Append(n, choices);
// Needed because it is a wxControlWithItems
SetInitialSize( size );
return true;
}
wxListBox::~wxListBox()
{
m_blockEvents = true;
FreeData();
m_blockEvents = false;
// make sure no native events get sent to a object in destruction
wxDELETE(m_peer);
if ( IsSorted() )
delete m_strings.sorted;
else
delete m_strings.unsorted;
m_strings.sorted = NULL;
}
void wxListBox::FreeData()
{
if ( IsSorted() )
m_strings.sorted->Clear();
else
m_strings.unsorted->Clear();
m_itemsClientData.Clear();
GetListPeer()->ListClear();
}
void wxListBox::DoSetFirstItem(int n)
{
GetListPeer()->ListScrollTo( n );
}
void wxListBox::EnsureVisible(int n)
{
GetListPeer()->ListScrollTo( n );
}
void wxListBox::DoDeleteOneItem(unsigned int n)
{
wxCHECK_RET( IsValid(n), wxT("invalid index in wxListBox::Delete") );
m_blockEvents = true;
if ( IsSorted() )
m_strings.sorted->RemoveAt(n);
else
m_strings.unsorted->RemoveAt(n);
m_itemsClientData.RemoveAt(n);
GetListPeer()->ListDelete( n );
m_blockEvents = false;
UpdateOldSelections();
}
void wxListBox::DoClear()
{
m_blockEvents = true;
FreeData();
m_blockEvents = false;
UpdateOldSelections();
}
// ----------------------------------------------------------------------------
// selection
// ----------------------------------------------------------------------------
void wxListBox::DoSetSelection(int n, bool select)
{
wxCHECK_RET( n == wxNOT_FOUND || IsValid(n),
wxT("invalid index in wxListBox::SetSelection") );
m_blockEvents = true;
if ( n == wxNOT_FOUND )
GetListPeer()->ListDeselectAll();
else
GetListPeer()->ListSetSelection( n, select, HasMultipleSelection() );
m_blockEvents = false;
UpdateOldSelections();
}
bool wxListBox::IsSelected(int n) const
{
wxCHECK_MSG( IsValid(n), false, wxT("invalid index in wxListBox::Selected") );
return GetListPeer()->ListIsSelected( n );
}
// Return number of selections and an array of selected integers
int wxListBox::GetSelections(wxArrayInt& aSelections) const
{
return GetListPeer()->ListGetSelections( aSelections );
}
// Get single selection, for single choice list items
int wxListBox::GetSelection() const
{
return GetListPeer()->ListGetSelection();
}
int wxListBox::DoListHitTest(const wxPoint& inpoint) const
{
return GetListPeer()->DoListHitTest( inpoint );
}
// ----------------------------------------------------------------------------
// display
// ----------------------------------------------------------------------------
void wxListBox::GetValueCallback( unsigned int n, wxListWidgetColumn* col , wxListWidgetCellValue& value )
{
if ( col == m_textColumn )
value.Set( GetString( n ) );
}
void wxListBox::SetValueCallback( unsigned int WXUNUSED(n), wxListWidgetColumn* WXUNUSED(col) , wxListWidgetCellValue& WXUNUSED(value) )
{
}
wxSize wxListBox::DoGetBestSize() const
{
int lbWidth = 100; // some defaults
int lbHeight;
int wLine;
{
wxClientDC dc(const_cast<wxListBox*>(this));
dc.SetFont(GetFont());
// Find the widest line
for (unsigned int i = 0; i < GetCount(); i++)
{
wxString str( GetString( i ) );
wxCoord width, height ;
dc.GetTextExtent( str , &width, &height);
wLine = width ;
lbWidth = wxMax( lbWidth, wLine );
}
// Add room for the scrollbar
lbWidth += wxSystemSettings::GetMetric( wxSYS_VSCROLL_X );
// And just a bit more
int cy = 12;
wxCoord width, height ;
dc.GetTextExtent( wxT("XX") , &width, &height);
int cx = width ;
lbWidth += cx;
// don't make the listbox too tall (limit height to around 10 items)
// but don't make it too small neither
lbHeight = wxMax( (cy + 4) * wxMin( wxMax( GetCount(), 3 ), 10 ), 70 );
}
return wxSize( lbWidth, lbHeight );
}
void wxListBox::Refresh(bool eraseBack, const wxRect *rect)
{
wxControl::Refresh( eraseBack, rect );
}
// Some custom controls depend on this
/* static */ wxVisualAttributes
wxListBox::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
{
wxVisualAttributes attr;
attr.colFg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
attr.colBg = wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX );
static wxFont font = wxFont(wxOSX_SYSTEM_FONT_VIEWS);
attr.font = font;
return attr;
}
// below is all code copied from univ
// ----------------------------------------------------------------------------
// client data handling
// ----------------------------------------------------------------------------
void wxListBox::DoSetItemClientData(unsigned int n, void* clientData)
{
m_itemsClientData[n] = clientData;
}
void *wxListBox::DoGetItemClientData(unsigned int n) const
{
return m_itemsClientData[n];
}
// ----------------------------------------------------------------------------
// accessing strings
// ----------------------------------------------------------------------------
unsigned int wxListBox::GetCount() const
{
return IsSorted() ? m_strings.sorted->size()
: m_strings.unsorted->size();
}
wxString wxListBox::GetString(unsigned int n) const
{
return IsSorted() ? m_strings.sorted->Item(n)
: m_strings.unsorted->Item(n);
}
int wxListBox::FindString(const wxString& s, bool bCase) const
{
return IsSorted() ? m_strings.sorted->Index(s, bCase)
: m_strings.unsorted->Index(s, bCase);
}
// ----------------------------------------------------------------------------
// adding/inserting strings
// ----------------------------------------------------------------------------
void wxListBox::OnItemInserted(unsigned int WXUNUSED(pos))
{
}
int wxListBox::DoInsertItems(const wxArrayStringsAdapter& items,
unsigned int pos,
void **clientData,
wxClientDataType type)
{
int idx = wxNOT_FOUND;
unsigned int startpos = pos;
const unsigned int numItems = items.GetCount();
for ( unsigned int i = 0; i < numItems; ++i )
{
const wxString& item = items[i];
idx = IsSorted() ? m_strings.sorted->Add(item)
: (m_strings.unsorted->Insert(item, pos), pos++);
m_itemsClientData.Insert(NULL, idx);
AssignNewItemClientData(idx, clientData, i, type);
GetListPeer()->ListInsert(startpos+i);
OnItemInserted(idx);
}
GetListPeer()->UpdateLineToEnd(startpos);
// Inserting the items may scroll the listbox down to show the last
// selected one but we don't want to do it as it could result in e.g. the
// first items of a listbox be hidden immediately after its creation so
// show the first selected item instead. Ideal would probably be to
// preserve the old selection unchanged, in fact, but I don't know how to
// get the first visible item so for now do at least this.
SetFirstItem(startpos);
UpdateOldSelections();
return idx;
}
void wxListBox::SetString(unsigned int n, const wxString& s)
{
wxCHECK_RET( !IsSorted(), wxT("can't set string in sorted listbox") );
if ( IsSorted() )
(*m_strings.sorted)[n] = s;
else
(*m_strings.unsorted)[n] = s;
GetListPeer()->UpdateLine(n);
}
//
// common event handling
//
void wxListBox::HandleLineEvent( unsigned int n, bool doubleClick )
{
wxCommandEvent event( doubleClick ? wxEVT_COMMAND_LISTBOX_DOUBLECLICKED :
wxEVT_COMMAND_LISTBOX_SELECTED, GetId() );
event.SetEventObject( this );
if ( HasClientObjectData() )
event.SetClientObject( GetClientObject(n) );
else if ( HasClientUntypedData() )
event.SetClientData( GetClientData(n) );
event.SetString( GetString(n) );
event.SetInt( n );
event.SetExtraLong( 1 );
HandleWindowEvent(event);
}
//
// common list cell value operations
//
void wxListWidgetCellValue::Check( bool check )
{
Set( check ? 1 : 0 );
}
bool wxListWidgetCellValue::IsChecked() const
{
return GetIntValue() != 0;
}
#endif // wxUSE_LISTBOX