#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() )
int xOld = x;
x += width;
- const int wText = width - 8;
+ width -= 8;
+ const int wText = width;
wxDCClipper clipper(*dc, xOld, rect.y, wText, rect.height);
if ( item->HasImage() )
}
if ( item->HasText() )
- DrawTextFormatted(dc, item->GetText(), col, xOld, yMid, wText);
+ DrawTextFormatted(dc, item->GetText(), col, xOld, yMid, width);
}
}
// 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) &&
m_text->PushEventHandler(this);
}
-void wxListTextCtrlWrapper::EndEdit(bool discardChanges)
+void wxListTextCtrlWrapper::EndEdit(EndReason reason)
{
m_aboutToFinish = true;
- if ( discardChanges )
+ switch ( reason )
{
- m_owner->OnRenameCancelled(m_itemEdited);
+ case End_Accept:
+ // Notify the owner about the changes
+ AcceptChanges();
- Finish( true );
- }
- else
- {
- // Notify the owner about the changes
- AcceptChanges();
+ // Even if vetoed, close the control (consistent with MSW)
+ Finish( true );
+ break;
+
+ case End_Discard:
+ m_owner->OnRenameCancelled(m_itemEdited);
+
+ Finish( true );
+ break;
- // Even if vetoed, close the control (consistent with MSW)
- Finish( true );
+ case End_Destroy:
+ // Don't generate any notifications for the control being destroyed
+ // and don't set focus to it neither.
+ Finish(false);
+ break;
}
}
}
void wxListTextCtrlWrapper::OnChar( wxKeyEvent &event )
+{
+ if ( !CheckForEndEditKey(event) )
+ event.Skip();
+}
+
+bool wxListTextCtrlWrapper::CheckForEndEditKey(const wxKeyEvent& event)
{
switch ( event.m_keyCode )
{
case WXK_RETURN:
- EndEdit( false );
+ EndEdit( End_Accept );
break;
case WXK_ESCAPE:
- EndEdit( true );
+ EndEdit( End_Discard );
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)
wxListMainWindow::~wxListMainWindow()
{
+ if ( m_textctrlWrapper )
+ m_textctrlWrapper->EndEdit(wxListTextCtrlWrapper::End_Destroy);
+
DoDeleteAllItems();
WX_CLEAR_LIST(wxListHeaderDataList, m_columns);
WX_CLEAR_ARRAY(m_aColWidths);
// listctrl because the order of events is different (or something like
// that), so explicitly end the edit if it is active.
if ( event.LeftDown() && m_textctrlWrapper )
- m_textctrlWrapper->EndEdit( false );
+ m_textctrlWrapper->EndEdit(wxListTextCtrlWrapper::End_Accept);
#endif // __WXMAC__
if ( event.LeftDown() )
if (parent->GetEventHandler()->ProcessEvent( ke ))
return;
+ // send a list event
+ wxListEvent le( wxEVT_COMMAND_LIST_KEY_DOWN, parent->GetId() );
+ le.m_itemIndex = m_current;
+ if (HasCurrent())
+ GetLine(m_current)->GetItem( 0, le.m_item );
+ le.m_code = event.GetKeyCode();
+ le.SetEventObject( parent );
+ if (parent->GetEventHandler()->ProcessEvent( le ))
+ return;
+
event.Skip();
}
event.Skip();
}
-void wxListMainWindow::OnChar( wxKeyEvent &event )
+void wxListMainWindow::OnCharHook( wxKeyEvent &event )
{
- wxWindow *parent = GetParent();
-
- // send a list_key event up
- if ( HasCurrent() )
+ if ( m_textctrlWrapper )
{
- wxListEvent le( wxEVT_COMMAND_LIST_KEY_DOWN, GetParent()->GetId() );
- le.m_itemIndex = m_current;
- GetLine(m_current)->GetItem( 0, le.m_item );
- le.m_code = event.GetKeyCode();
- le.SetEventObject( parent );
- parent->GetEventHandler()->ProcessEvent( le );
+ // 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();
+
// propagate the char event upwards
wxKeyEvent ke(event);
ke.SetEventObject( parent );
}
}
- // 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()