#include "wx/listctrl.h"
-#if ((!defined(__WXMSW__) && !(defined(__WXMAC__) && wxOSX_USE_CARBON)) || defined(__WXUNIVERSAL__))
- // if we have a native version, its implementation file does all this
- IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject)
- IMPLEMENT_DYNAMIC_CLASS(wxListView, wxListCtrl)
- IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent)
-
- IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxGenericListCtrl)
-#endif
-
#ifndef WX_PRECOMP
#include "wx/scrolwin.h"
#include "wx/timer.h"
else
colText = *wxBLACK;
#else
- colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+ if ( hasFocus )
+ colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+ else
+ colText = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT);
#endif
}
else if ( attr && attr->HasTextColour() )
// NB: The code below is not really Mac-specific, but since we are close
// to 2.8 release and I don't have time to test on other platforms, I
-// defined this only for wxMac. If this behavior is desired on
+// defined this only for wxMac. If this behaviour is desired on
// other platforms, please go ahead and revise or remove the #ifdef.
#ifdef __WXMAC__
if ( !m_owner->IsVirtual() && (item.m_mask & wxLIST_MASK_STATE) &&
}
void wxListTextCtrlWrapper::OnChar( wxKeyEvent &event )
+{
+ if ( !CheckForEndEditKey(event) )
+ event.Skip();
+}
+
+bool wxListTextCtrlWrapper::CheckForEndEditKey(const wxKeyEvent& event)
{
switch ( event.m_keyCode )
{
break;
default:
- event.Skip();
+ return false;
}
+
+ return true;
}
void wxListTextCtrlWrapper::OnKeyUp( wxKeyEvent &event )
BEGIN_EVENT_TABLE(wxListMainWindow, wxWindow)
EVT_PAINT (wxListMainWindow::OnPaint)
EVT_MOUSE_EVENTS (wxListMainWindow::OnMouse)
+ EVT_CHAR_HOOK (wxListMainWindow::OnCharHook)
EVT_CHAR (wxListMainWindow::OnChar)
EVT_KEY_DOWN (wxListMainWindow::OnKeyDown)
EVT_KEY_UP (wxListMainWindow::OnKeyUp)
GetParent()->GetId());
evCache.SetEventObject( GetParent() );
evCache.m_oldItemIndex = visibleFrom;
+ evCache.m_item.m_itemId =
evCache.m_itemIndex = visibleTo;
GetParent()->GetEventHandler()->ProcessEvent( evCache );
}
wxListEvent le( command, GetParent()->GetId() );
le.SetEventObject( GetParent() );
+ le.m_item.m_itemId =
le.m_itemIndex = line;
// set only for events which have position
wxListEvent le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, GetParent()->GetId() );
le.SetEventObject( GetParent() );
+ le.m_item.m_itemId =
le.m_itemIndex = item;
wxListLineData *data = GetLine(itemEdit);
wxCHECK_MSG( data, NULL, wxT("invalid index in EditLabel()") );
{
wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() );
le.SetEventObject( GetParent() );
+ le.m_item.m_itemId =
le.m_itemIndex = itemEdit;
wxListLineData *data = GetLine(itemEdit);
le.SetEditCanceled(true);
le.SetEventObject( GetParent() );
+ le.m_item.m_itemId =
le.m_itemIndex = itemEdit;
wxListLineData *data = GetLine(itemEdit);
wxListEvent le( command, GetParent()->GetId() );
le.SetEventObject( GetParent() );
+ le.m_item.m_itemId =
le.m_itemIndex = m_lineLastClicked;
le.m_pointDrag = m_dragStart;
GetParent()->GetEventHandler()->ProcessEvent( le );
// send a list event
wxListEvent le( wxEVT_COMMAND_LIST_KEY_DOWN, parent->GetId() );
+ le.m_item.m_itemId =
le.m_itemIndex = m_current;
if (HasCurrent())
GetLine(m_current)->GetItem( 0, le.m_item );
event.Skip();
}
+void wxListMainWindow::OnCharHook( wxKeyEvent &event )
+{
+ if ( m_textctrlWrapper )
+ {
+ // When an in-place editor is active we should ensure that it always
+ // gets the key events that are special to it.
+ if ( m_textctrlWrapper->CheckForEndEditKey(event) )
+ {
+ // Skip the call to wxEvent::Skip() below.
+ return;
+ }
+ }
+
+ event.Skip();
+}
+
void wxListMainWindow::OnChar( wxKeyEvent &event )
{
wxWindow *parent = GetParent();
}
}
- // update the item on screen
- wxRect rectItem;
- GetItemRect(id, rectItem);
- RefreshRect(rectItem);
+ // update the item on screen unless we're going to update everything soon
+ // anyhow
+ if ( !m_dirty )
+ {
+ wxRect rectItem;
+ GetItemRect(id, rectItem);
+ RefreshRect(rectItem);
+ }
}
void wxListMainWindow::SetItemStateAll(long state, long stateMask)
int x = EXTRA_BORDER_X;
int y = EXTRA_BORDER_Y;
+
+ // Note that "row" here is vertical, i.e. what is called
+ // "column" in many other places in wxWidgets.
int maxWidthInThisRow = 0;
m_linesPerPage = 0;
if (currentlyVisibleLines > m_linesPerPage)
m_linesPerPage = currentlyVisibleLines;
- if ( y + sizeLine.y >= clientHeight )
+ // Have we reached the end of the row either because no
+ // more items would fit or because there are simply no more
+ // items?
+ if ( y + sizeLine.y >= clientHeight
+ || i == count - 1)
{
+ // Adjust all items in this row to have the same
+ // width to ensure that they all align horizontally in
+ // icon view.
+ if ( HasFlag(wxLC_ICON) || HasFlag(wxLC_SMALL_ICON) )
+ {
+ size_t firstRowLine = i - currentlyVisibleLines + 1;
+ for (size_t j = firstRowLine; j <= i; j++)
+ {
+ GetLine(j)->m_gi->ExtendWidth(maxWidthInThisRow);
+ }
+ }
+
currentlyVisibleLines = 0;
y = EXTRA_BORDER_Y;
maxWidthInThisRow += MARGIN_BETWEEN_ROWS;
maxWidthInThisRow = 0;
}
- // We have reached the last item.
- if ( i == count - 1 )
- entireWidth += maxWidthInThisRow;
-
if ( (tries == 0) &&
(entireWidth + SCROLL_UNIT_X > clientWidth) )
{
for ( size_t i = 0; i < m_lines.GetCount(); i++ )
{
wxListLineData * const line = GetLine(i);
+
+ // In the following atypical but possible scenario it can be
+ // legal to call DeleteColumn() but the items may not have any
+ // values for it:
+ // 1. In report view, insert a second column.
+ // 2. Still in report view, add an item with 2 values.
+ // 3. Switch to an icon (or list) view.
+ // 4. Add an item -- necessarily with 1 value only.
+ // 5. Switch back to report view.
+ // 6. Call DeleteColumn().
+ // So we need to check for this as otherwise we would simply crash
+ // if this happens.
+ if ( line->m_items.GetCount() <= static_cast<unsigned>(col) )
+ continue;
+
wxListItemDataList::compatibility_iterator n = line->m_items.Item( col );
delete n->GetData();
line->m_items.Erase(n);
wxListLineData *line = new wxListLineData(this);
line->SetItem( item.m_col, item );
+ if ( item.m_mask & wxLIST_MASK_IMAGE )
+ {
+ // Reset the buffered height if it's not big enough for the new image.
+ int image = item.GetImage();
+ if ( m_small_image_list && image != -1 && InReportView() )
+ {
+ int imageWidth, imageHeight;
+ m_small_image_list->GetSize(image, imageWidth, imageHeight);
+
+ if ( imageHeight > m_lineHeight )
+ m_lineHeight = 0;
+ }
+ }
m_lines.Insert( line, id );
// if we don't have the header any longer, we need to relayout the window
// if ( !GetColumnCount() )
+
+ // Ensure that the non-existent columns are really removed from display.
+ Refresh();
+
return true;
}
wxListItem info;
info.m_text = label;
info.m_image = imageIndex;
- info.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_IMAGE;
+ info.m_mask = wxLIST_MASK_TEXT;
+ if (imageIndex > -1)
+ info.m_mask |= wxLIST_MASK_IMAGE;
info.m_itemId = index;
return InsertItem( info );
}
void wxGenericListCtrl::DoClientToScreen( int *x, int *y ) const
{
- m_mainWin->DoClientToScreen(x, y);
+ // It's not clear whether this can be called before m_mainWin is created
+ // but it seems better to be on the safe side and check.
+ if ( m_mainWin )
+ m_mainWin->DoClientToScreen(x, y);
+ else
+ wxControl::DoClientToScreen(x, y);
}
void wxGenericListCtrl::DoScreenToClient( int *x, int *y ) const
{
- m_mainWin->DoScreenToClient(x, y);
+ // At least in wxGTK/Univ build this method can be called before m_mainWin
+ // is created so avoid crashes in this case.
+ if ( m_mainWin )
+ m_mainWin->DoScreenToClient(x, y);
+ else
+ wxControl::DoScreenToClient(x, y);
}
void wxGenericListCtrl::SetFocus()