#include "wx/listctrl.h"
-#if (!defined(__WXMSW__) || defined(__WXUNIVERSAL__)) && !defined(__WXMAC__)
+#if ((!defined(__WXMSW__) && !defined(__WXMAC__)) || defined(__WXUNIVERSAL__))
// if we have a native version, its implementation file does all this
IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject)
IMPLEMENT_DYNAMIC_CLASS(wxListView, wxListCtrl)
#include "wx/dcclient.h"
#include "wx/dcscreen.h"
#include "wx/math.h"
+ #include "wx/settings.h"
#endif
#include "wx/imaglist.h"
#include "wx/renderer.h"
#ifdef __WXMAC__
- #include "wx/mac/private.h"
+ #include "wx/osx/private.h"
#endif
static const int EXTRA_BORDER_Y = 2;
// offset for the header window
-static const int HEADER_OFFSET_X = 1;
-static const int HEADER_OFFSET_Y = 1;
+static const int HEADER_OFFSET_X = 0;
+static const int HEADER_OFFSET_Y = 0;
// margin between rows of icons in [small] icon view
static const int MARGIN_BETWEEN_ROWS = 6;
// the space between the image and the text in the report mode
static const int IMAGE_MARGIN_IN_REPORT_MODE = 5;
+// the space between the image and the text in the report mode in header
+static const int HEADER_IMAGE_MARGIN_IN_REPORT_MODE = 2;
+
// ============================================================================
// private classes
// ============================================================================
// wxListLineData (internal)
//-----------------------------------------------------------------------------
-WX_DECLARE_EXPORTED_LIST(wxListItemData, wxListItemDataList);
+WX_DECLARE_LIST(wxListItemData, wxListItemDataList);
#include "wx/listimpl.cpp"
WX_DEFINE_LIST(wxListItemDataList)
int width);
};
-WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData, wxListLineDataArray);
+WX_DECLARE_OBJARRAY(wxListLineData, wxListLineDataArray);
#include "wx/arrimpl.cpp"
WX_DEFINE_OBJARRAY(wxListLineDataArray)
// it wasn't vetoed, i.e. if we should proceed
bool SendListEvent(wxEventType type, const wxPoint& pos);
- DECLARE_DYNAMIC_CLASS(wxListHeaderWindow)
DECLARE_EVENT_TABLE()
};
wxTextCtrl *GetText() const { return m_text; }
- void AcceptChangesAndFinish();
+ void EndEdit( bool discardChanges );
protected:
void OnChar( wxKeyEvent &event );
void OnKillFocus( wxFocusEvent &event );
bool AcceptChanges();
- void Finish();
+ void Finish( bool setfocus );
private:
wxListMainWindow *m_owner;
wxTextCtrl *m_text;
wxString m_startValue;
size_t m_itemEdited;
- bool m_finished;
bool m_aboutToFinish;
DECLARE_EVENT_TABLE()
// wxListMainWindow (internal)
//-----------------------------------------------------------------------------
-WX_DECLARE_EXPORTED_LIST(wxListHeaderData, wxListHeaderDataList);
+WX_DECLARE_LIST(wxListHeaderData, wxListHeaderDataList);
#include "wx/listimpl.cpp"
WX_DEFINE_LIST(wxListHeaderDataList)
-class wxListMainWindow : public wxScrolledWindow
+class wxListMainWindow : public wxScrolledCanvas
{
public:
wxListMainWindow();
// bring the selected item into view, scrolling to it if necessary
void MoveToItem(size_t item);
+ bool ScrollList( int WXUNUSED(dx), int dy );
+
// bring the current item into view
void MoveToFocus() { MoveToItem(m_current); }
return m_textctrlWrapper ? m_textctrlWrapper->GetText() : NULL;
}
- void FinishEditing(wxTextCtrl *text)
+ void ResetTextControl(wxTextCtrl *text)
{
delete text;
m_textctrlWrapper = NULL;
- SetFocusIgnoringChildren();
}
- // suspend/resume redrawing the control
- void Freeze();
- void Thaw();
-
void OnRenameTimer();
bool OnRenameAccept(size_t itemEdit, const wxString& value);
void OnRenameCancelled(size_t itemEdit);
void OnPaint( wxPaintEvent &event );
+ void OnChildFocus(wxChildFocusEvent& event);
+
void DrawImage( int index, wxDC *dc, int x, int y );
void GetImageSize( int index, int &width, int &height ) const;
int GetTextLength( const wxString &s ) const;
void SetItemState( long item, long state, long stateMask );
void SetItemStateAll( long state, long stateMask );
int GetItemState( long item, long stateMask ) const;
- void GetItemRect( long index, wxRect &rect ) const;
+ bool GetItemRect( long item, wxRect &rect ) const
+ {
+ return GetSubItemRect(item, wxLIST_GETSUBITEMRECT_WHOLEITEM, rect);
+ }
+ bool GetSubItemRect( long item, long subItem, wxRect& rect ) const;
wxRect GetViewRect() const;
bool GetItemPosition( long item, wxPoint& pos ) const;
int GetSelectedItemCount() const;
// send out a wxListEvent
void SendNotify( size_t line,
- wxEventType command,
+ wxEventType command,
const wxPoint& point = wxDefaultPosition );
// override base class virtual to reset m_lineHeight when the font changes
virtual bool SetFont(const wxFont& font)
{
- if ( !wxScrolledWindow::SetFont(font) )
+ if ( !wxScrolledCanvas::SetFont(font) )
return false;
m_lineHeight = 0;
{
return m_hasFocus ? m_highlightBrush : m_highlightUnfocusedBrush;
}
-
+
bool HasFocus() const
{
return m_hasFocus;
wxBrush *m_highlightBrush,
*m_highlightUnfocusedBrush;
- // if this is > 0, the control is frozen and doesn't redraw itself
- size_t m_freezeCount;
-
// wrapper around the text control currently used for in place editing or
// NULL if no item is being edited
wxListTextCtrlWrapper *m_textctrlWrapper;
- DECLARE_DYNAMIC_CLASS(wxListMainWindow)
DECLARE_EVENT_TABLE()
friend class wxGenericListCtrl;
if ( m_mask & wxLIST_MASK_WIDTH )
SetWidth(item.m_width);
-
+
if ( m_mask & wxLIST_MASK_STATE )
SetState(item.m_state);
}
if ( highlighted )
#ifdef __WXMAC__
{
- if (m_owner->HasFocus())
+ if (m_owner->HasFocus()
+#if !defined(__WXUNIVERSAL__)
+ && IsControlActive( (ControlRef)m_owner->GetHandle() )
+#endif
+ )
colText = *wxWHITE;
else
colText = *wxBLACK;
if ( highlighted )
dc->SetBrush( *m_owner->GetHighlightBrush() );
else
- dc->SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID));
+ dc->SetBrush(wxBrush(attr->GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
dc->SetPen( *wxTRANSPARENT_PEN );
if (highlighted)
{
int flags = wxCONTROL_SELECTED;
- if (m_owner->HasFocus())
+ if (m_owner->HasFocus()
+#if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__)
+ && IsControlActive( (ControlRef)m_owner->GetHandle() )
+#endif
+ )
flags |= wxCONTROL_FOCUSED;
wxRendererNative::Get().DrawItemSelectionRect( m_owner, *dc, m_gi->m_rectHighlight, flags );
-
+
}
else
{
int xOld = x;
x += width;
+ const int wText = width - 8;
+ wxDCClipper clipper(*dc, xOld, rect.y, wText, rect.height);
+
if ( item->HasImage() )
{
int ix, iy;
}
if ( item->HasText() )
- DrawTextFormatted(dc, item->GetText(), col, xOld, yMid, width - 8);
+ DrawTextFormatted(dc, item->GetText(), col, xOld, yMid, wText);
}
}
void wxListLineData::DrawTextFormatted(wxDC *dc,
- const wxString &text,
+ const wxString& textOrig,
int col,
int x,
int yMid,
int width)
{
+ // we don't support displaying multiple lines currently (and neither does
+ // wxMSW FWIW) so just merge all the lines
+ wxString text(textOrig);
+ text.Replace(_T("\n"), _T(" "));
+
wxCoord w, h;
dc->GetTextExtent(text, &w, &h);
// wxListHeaderWindow
//-----------------------------------------------------------------------------
-IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow,wxWindow)
-
BEGIN_EVENT_TABLE(wxListHeaderWindow,wxWindow)
EVT_PAINT (wxListHeaderWindow::OnPaint)
EVT_MOUSE_EVENTS (wxListHeaderWindow::OnMouse)
GetClientSize( &w, &h );
m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
- dc.SetBackgroundMode(wxTRANSPARENT);
+ dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
dc.SetTextForeground(GetForegroundColour());
int x = HEADER_OFFSET_X;
m_owner->GetColumn( i, item );
int wCol = item.m_width;
- // the width of the rect to draw: make it smaller to fit entirely
- // inside the column rect
-#ifdef __WXMAC__
int cw = wCol;
int ch = h;
-#else
- int cw = wCol - 2;
- int ch = h - 2;
-#endif
int flags = 0;
if (!m_parent->IsEnabled())
flags |= wxCONTROL_DISABLED;
-// NB: The code below is not really Mac-specific, but since we are close
+// 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
// other platforms, please go ahead and revise or remove the #ifdef.
#ifdef __WXMAC__
- if ( !m_owner->IsVirtual() && (item.m_mask & wxLIST_MASK_STATE) &&
+ if ( !m_owner->IsVirtual() && (item.m_mask & wxLIST_MASK_STATE) &&
(item.m_state & wxLIST_STATE_SELECTED) )
flags |= wxCONTROL_SELECTED;
#endif
wLabel += 2 * EXTRA_WIDTH;
// and the width of the icon, if any
- static const int MARGIN_BETWEEN_TEXT_AND_ICON = 2;
int ix = 0, iy = 0; // init them just to suppress the compiler warnings
const int image = item.m_image;
wxImageList *imageList;
if ( imageList )
{
imageList->GetSize(image, ix, iy);
- wLabel += ix + MARGIN_BETWEEN_TEXT_AND_ICON;
+ wLabel += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE;
}
}
else
break;
}
+ // draw the text and image clipping them so that they
+ // don't overwrite the column boundary
+ wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 );
+
// if we have an image, draw it on the right of the label
if ( imageList )
{
(
image,
dc,
- xAligned + wLabel - ix - MARGIN_BETWEEN_TEXT_AND_ICON,
+ xAligned + wLabel - ix - HEADER_IMAGE_MARGIN_IN_REPORT_MODE,
HEADER_OFFSET_Y + (h - 4 - iy)/2,
wxIMAGELIST_DRAW_TRANSPARENT
);
-
- cw -= ix + MARGIN_BETWEEN_TEXT_AND_ICON;
}
- // draw the text clipping it so that it doesn't overwrite the column
- // boundary
- wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 );
-
dc.DrawText( item.GetText(),
xAligned + EXTRA_WIDTH, h / 2 - hLabel / 2 ); //HEADER_OFFSET_Y + EXTRA_HEIGHT );
x += wCol;
}
+
+ // Fill in what's missing to the right of the columns, otherwise we will
+ // leave an unpainted area when columns are removed (and it looks better)
+ if ( x < w )
+ {
+ wxRendererNative::Get().DrawHeaderButton
+ (
+ this,
+ dc,
+ wxRect(x, HEADER_OFFSET_Y, w - x, h),
+ 0
+ );
+ }
}
void wxListHeaderWindow::DrawCurrent()
{
+#if 1
+ m_owner->SetColumnWidth( m_column, m_currentX - m_minX );
+#else
int x1 = m_currentX;
int y1 = 0;
m_owner->ClientToScreen( &x1, &y1 );
dc.SetPen( wxNullPen );
dc.SetBrush( wxNullBrush );
+#endif
}
void wxListHeaderWindow::OnMouse( wxMouseEvent &event )
{
wxListItem colItem;
m_owner->GetColumn(i, colItem);
- long state = colItem.GetState();
+ long state = colItem.GetState();
if (i == m_column)
colItem.SetState(state | wxLIST_STATE_SELECTED);
else
m_owner->SetColumn(i, colItem);
}
}
-
+
SendListEvent( event.LeftDown()
? wxEVT_COMMAND_LIST_COL_CLICK
: wxEVT_COMMAND_LIST_COL_RIGHT_CLICK,
{
m_owner = owner;
m_text = text;
- m_finished = false;
m_aboutToFinish = false;
wxRect rectLabel = owner->GetLineLabelRect(itemEdit);
m_text->PushEventHandler(this);
}
-void wxListTextCtrlWrapper::Finish()
+void wxListTextCtrlWrapper::EndEdit(bool discardChanges)
{
- if ( !m_finished )
+ m_aboutToFinish = true;
+
+ if ( discardChanges )
{
- m_finished = true;
+ m_owner->OnRenameCancelled(m_itemEdited);
- m_text->RemoveEventHandler(this);
- m_owner->FinishEditing(m_text);
+ Finish( true );
+ }
+ else
+ {
+ // Notify the owner about the changes
+ AcceptChanges();
- wxPendingDelete.Append( this );
+ // Even if vetoed, close the control (consistent with MSW)
+ Finish( true );
}
}
+void wxListTextCtrlWrapper::Finish( bool setfocus )
+{
+ m_text->RemoveEventHandler(this);
+ m_owner->ResetTextControl( m_text );
+
+ wxPendingDelete.Append( this );
+
+ if (setfocus)
+ m_owner->SetFocus();
+}
+
bool wxListTextCtrlWrapper::AcceptChanges()
{
const wxString value = m_text->GetValue();
- if ( value == m_startValue )
- // nothing changed, always accept
- return true;
-
+ // notice that we should always call OnRenameAccept() to generate the "end
+ // label editing" event, even if the user hasn't really changed anything
if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
+ {
// vetoed by the user
return false;
+ }
- // accepted, do rename the item
- m_owner->SetItemText(m_itemEdited, value);
+ // accepted, do rename the item (unless nothing changed)
+ if ( value != m_startValue )
+ m_owner->SetItemText(m_itemEdited, value);
return true;
}
-void wxListTextCtrlWrapper::AcceptChangesAndFinish()
-{
- m_aboutToFinish = true;
-
- // Notify the owner about the changes
- AcceptChanges();
-
- // Even if vetoed, close the control (consistent with MSW)
- Finish();
-}
-
void wxListTextCtrlWrapper::OnChar( wxKeyEvent &event )
{
switch ( event.m_keyCode )
{
case WXK_RETURN:
- AcceptChangesAndFinish();
+ EndEdit( false );
break;
case WXK_ESCAPE:
- m_owner->OnRenameCancelled( m_itemEdited );
- Finish();
+ EndEdit( true );
break;
default:
void wxListTextCtrlWrapper::OnKeyUp( wxKeyEvent &event )
{
- if (m_finished)
+ if (m_aboutToFinish)
{
- event.Skip();
- return;
+ // auto-grow the textctrl:
+ wxSize parentSize = m_owner->GetSize();
+ wxPoint myPos = m_text->GetPosition();
+ wxSize mySize = m_text->GetSize();
+ int sx, sy;
+ m_text->GetTextExtent(m_text->GetValue() + _T("MM"), &sx, &sy);
+ if (myPos.x + sx > parentSize.x)
+ sx = parentSize.x - myPos.x;
+ if (mySize.x > sx)
+ sx = mySize.x;
+ m_text->SetSize(sx, wxDefaultCoord);
}
- // auto-grow the textctrl:
- wxSize parentSize = m_owner->GetSize();
- wxPoint myPos = m_text->GetPosition();
- wxSize mySize = m_text->GetSize();
- int sx, sy;
- m_text->GetTextExtent(m_text->GetValue() + _T("MM"), &sx, &sy);
- if (myPos.x + sx > parentSize.x)
- sx = parentSize.x - myPos.x;
- if (mySize.x > sx)
- sx = mySize.x;
- m_text->SetSize(sx, wxDefaultCoord);
-
event.Skip();
}
void wxListTextCtrlWrapper::OnKillFocus( wxFocusEvent &event )
{
- if ( !m_finished && !m_aboutToFinish )
+ if ( !m_aboutToFinish )
{
if ( !AcceptChanges() )
m_owner->OnRenameCancelled( m_itemEdited );
- Finish();
+ Finish( false );
}
// We must let the native text control handle focus
// wxListMainWindow
//-----------------------------------------------------------------------------
-IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow,wxScrolledWindow)
-
-BEGIN_EVENT_TABLE(wxListMainWindow,wxScrolledWindow)
+BEGIN_EVENT_TABLE(wxListMainWindow,wxScrolledCanvas)
EVT_PAINT (wxListMainWindow::OnPaint)
EVT_MOUSE_EVENTS (wxListMainWindow::OnMouse)
EVT_CHAR (wxListMainWindow::OnChar)
EVT_KEY_DOWN (wxListMainWindow::OnKeyDown)
- EVT_KEY_UP (wxListMainWindow::OnKeyUp)
+ EVT_KEY_UP (wxListMainWindow::OnKeyUp)
EVT_SET_FOCUS (wxListMainWindow::OnSetFocus)
EVT_KILL_FOCUS (wxListMainWindow::OnKillFocus)
EVT_SCROLLWIN (wxListMainWindow::OnScroll)
+ EVT_CHILD_FOCUS (wxListMainWindow::OnChildFocus)
END_EVENT_TABLE()
void wxListMainWindow::Init()
m_lineLastClicked =
m_lineSelectSingleOnUp =
m_lineBeforeLastClicked = (size_t)-1;
-
- m_freezeCount = 0;
}
wxListMainWindow::wxListMainWindow()
const wxSize& size,
long style,
const wxString &name )
- : wxScrolledWindow( parent, id, pos, size,
+ : wxScrolledCanvas( parent, id, pos, size,
style | wxHSCROLL | wxVSCROLL, name )
{
Init();
(
wxSYS_COLOUR_HIGHLIGHT
),
- wxSOLID
+ wxBRUSHSTYLE_SOLID
);
-
+
m_highlightUnfocusedBrush = new wxBrush
(
wxSystemSettings::GetColour
(
wxSYS_COLOUR_BTNSHADOW
),
- wxSOLID
+ wxBRUSHSTYLE_SOLID
);
SetScrollbars( 0, 0, 0, 0, 0, 0 );
if ( !InReportView() )
return GetLine(line)->m_gi->m_rectLabel;
+ int image_x = 0;
+ wxListLineData *data = GetLine(line);
+ wxListItemDataList::compatibility_iterator node = data->m_items.GetFirst();
+ if (node)
+ {
+ wxListItemData *item = node->GetData();
+ if ( item->HasImage() )
+ {
+ int ix, iy;
+ GetImageSize( item->GetImage(), ix, iy );
+ image_x = 3 + ix + IMAGE_MARGIN_IN_REPORT_MODE;
+ }
+ }
+
wxRect rect;
- rect.x = HEADER_OFFSET_X;
+ rect.x = image_x + HEADER_OFFSET_X;
rect.y = GetLineY(line);
- rect.width = GetColumnWidth(0);
+ rect.width = GetColumnWidth(0) - image_x;
rect.height = GetLineHeight();
return rect;
}
}
-void wxListMainWindow::Freeze()
-{
- m_freezeCount++;
-}
-
-void wxListMainWindow::Thaw()
-{
- wxCHECK_RET( m_freezeCount > 0, _T("thawing unfrozen list control?") );
-
- if ( --m_freezeCount == 0 )
- Refresh();
-}
-
void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
{
// Note: a wxPaintDC must be constructed even if no drawing is
// done (a Windows requirement).
wxPaintDC dc( this );
- if ( IsEmpty() || m_freezeCount )
+ if ( IsEmpty() )
+ {
// nothing to draw or not the moment to draw it
return;
+ }
if ( m_dirty )
+ {
// delay the repainting until we calculate all the items positions
return;
+ }
PrepareDC( dc );
wxRect rectLine;
int xOrig = dc.LogicalToDeviceX( 0 );
int yOrig = dc.LogicalToDeviceY( 0 );
-
+
// tell the caller cache to cache the data
if ( IsVirtual() )
{
if ( HasFlag(wxLC_HRULES) )
{
- wxPen pen(GetRuleColour(), 1, wxSOLID);
+ wxPen pen(GetRuleColour(), 1, wxPENSTYLE_SOLID);
wxSize clientSize = GetClientSize();
- // Don't draw the first one
- for ( size_t i = visibleFrom + 1; i <= visibleTo; i++ )
+ size_t i = visibleFrom;
+ if (i == 0) i = 1; // Don't draw the first one
+ for ( ; i <= visibleTo; i++ )
{
dc.SetPen(pen);
dc.SetBrush( *wxTRANSPARENT_BRUSH );
// Draw vertical rules if required
if ( HasFlag(wxLC_VRULES) && !IsEmpty() )
{
- wxPen pen(GetRuleColour(), 1, wxSOLID);
+ wxPen pen(GetRuleColour(), 1, wxPENSTYLE_SOLID);
wxRect firstItemRect, lastItemRect;
GetItemRect(visibleFrom, firstItemRect);
{
int colWidth = GetColumnWidth(col);
x += colWidth;
- dc.DrawLine(x - dev_x - 2, firstItemRect.GetY() - 1 - dev_y,
- x - dev_x - 2, lastItemRect.GetBottom() + 1 - dev_y);
+ int x_pos = x - dev_x;
+ if (col < GetColumnCount()-1) x_pos -= 2;
+ dc.DrawLine(x_pos, firstItemRect.GetY() - 1 - dev_y,
+ x_pos, lastItemRect.GetBottom() + 1 - dev_y);
}
}
}
dc.DrawRectangle( rect );
#else
wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, wxCONTROL_CURRENT|wxCONTROL_FOCUSED );
-
+
#endif
}
}
RefreshLine(m_current);
}
}
- else // multi sel
+ else // multi selection
{
- HighlightLines(0, GetItemCount() - 1, on);
+ if ( !IsEmpty() )
+ HighlightLines(0, GetItemCount() - 1, on);
}
}
+void wxListMainWindow::OnChildFocus(wxChildFocusEvent& WXUNUSED(event))
+{
+ // Do nothing here. This prevents the default handler in wxScrolledWindow
+ // from needlessly scrolling the window when the edit control is
+ // dismissed. See ticket #9563.
+}
+
void wxListMainWindow::SendNotify( size_t line,
wxEventType command,
const wxPoint& point )
{
wxListEvent le( command, GetParent()->GetId() );
le.SetEventObject( GetParent() );
-
+
le.m_itemIndex = line;
// set only for events which have position
{
m_current = current;
+ // as the current item changed, we shouldn't start editing it when the
+ // "slow click" timer expires as the click happened on another item
+ if ( m_renameTimer->IsRunning() )
+ m_renameTimer->Stop();
+
SendNotify(current, wxEVT_COMMAND_LIST_ITEM_FOCUSED);
}
// We have to call this here because the label in question might just have
// been added and no screen update taken place.
if ( m_dirty )
+ {
wxSafeYield();
+ // Pending events dispatched by wxSafeYield might have changed the item
+ // count
+ if ( (size_t)item >= GetItemCount() )
+ return NULL;
+ }
+
wxTextCtrl * const text = (wxTextCtrl *)textControlClass->CreateObject();
m_textctrlWrapper = new wxListTextCtrlWrapper(this, text, item);
return m_textctrlWrapper->GetText();
// 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->AcceptChangesAndFinish();
+ m_textctrlWrapper->EndEdit( false );
#endif // __WXMAC__
+ if ( event.LeftDown() )
+ SetFocus();
+
event.SetEventObject( GetParent() );
if ( GetParent()->GetEventHandler()->ProcessEvent( event) )
return;
if (event.RightDown())
{
SendNotify( (size_t)-1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition() );
- // Allow generation of context menu event
- event.Skip();
+
+ wxContextMenuEvent evtCtx(
+ wxEVT_CONTEXT_MENU,
+ GetParent()->GetId(),
+ ClientToScreen(event.GetPosition()));
+ evtCtx.SetEventObject(GetParent());
+ GetParent()->GetEventHandler()->ProcessEvent(evtCtx);
}
return;
}
if (event.RightDown())
{
SendNotify( (size_t) -1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition() );
- // Allow generation of context menu event
- event.Skip();
+
+ wxContextMenuEvent evtCtx(
+ wxEVT_CONTEXT_MENU,
+ GetParent()->GetId(),
+ ClientToScreen(event.GetPosition()));
+ evtCtx.SetEventObject(GetParent());
+ GetParent()->GetEventHandler()->ProcessEvent(evtCtx);
}
else
{
bool forceClick = false;
if (event.ButtonDClick())
{
- m_renameTimer->Stop();
+ if ( m_renameTimer->IsRunning() )
+ m_renameTimer->Stop();
+
m_lastOnSame = false;
if ( current == m_lineLastClicked )
(hitResult == wxLIST_HITTEST_ONITEMLABEL) &&
HasFlag(wxLC_EDIT_LABELS) )
{
- m_renameTimer->Start( 100, true );
+ if ( !InReportView() ||
+ GetLineLabelRect(current).Contains(x, y) )
+ {
+ int dclick = wxSystemSettings::GetMetric(wxSYS_DCLICK_MSEC);
+ m_renameTimer->Start(dclick > 0 ? dclick : 250, true);
+ }
}
}
Scroll( -1, rect.y / hLine );
if (rect.y + rect.height + 5 > view_y + client_h)
Scroll( -1, (rect.y + rect.height - client_h + hLine) / hLine );
+
+#ifdef __WXMAC__
+ // At least on Mac the visible lines value will get reset inside of
+ // Scroll *before* it actually scrolls the window because of the
+ // Update() that happens there, so it will still have the wrong value.
+ // So let's reset it again and wait for it to be recalculated in the
+ // next paint event. I would expect this problem to show up in wxGTK
+ // too but couldn't duplicate it there. Perhaps the order of events
+ // is different... --Robin
+ ResetVisibleLinesRange();
+#endif
}
else // !report
{
+ int sx = -1,
+ sy = -1;
+
if (rect.x-view_x < 5)
- Scroll( (rect.x - 5) / SCROLL_UNIT_X, -1 );
+ sx = (rect.x - 5) / SCROLL_UNIT_X;
if (rect.x + rect.width - 5 > view_x + client_w)
- Scroll( (rect.x + rect.width - client_w + SCROLL_UNIT_X) / SCROLL_UNIT_X, -1 );
+ sx = (rect.x + rect.width - client_w + SCROLL_UNIT_X) / SCROLL_UNIT_X;
+
+ if (rect.y-view_y < 5)
+ sy = (rect.y - 5) / hLine;
+ if (rect.y + rect.height - 5 > view_y + client_h)
+ sy = (rect.y + rect.height - client_h + hLine) / hLine;
+
+ Scroll(sx, sy);
}
}
+bool wxListMainWindow::ScrollList(int WXUNUSED(dx), int dy)
+{
+ if ( !InReportView() )
+ {
+ // TODO: this should work in all views but is not implemented now
+ return false;
+ }
+
+ size_t top, bottom;
+ GetVisibleLinesRange(&top, &bottom);
+
+ if ( bottom == (size_t)-1 )
+ return 0;
+
+ ResetVisibleLinesRange();
+
+ int hLine = GetLineHeight();
+
+ Scroll(-1, top + dy / hLine);
+
+#ifdef __WXMAC__
+ // see comment in MoveToItem() for why we do this
+ ResetVisibleLinesRange();
+#endif
+
+ return true;
+}
+
// ----------------------------------------------------------------------------
// keyboard handling
// ----------------------------------------------------------------------------
else // !shift
{
// all previously selected items are unselected unless ctrl is held
- if ( !event.ControlDown() )
+ // in a multiselection control
+ if ( !event.ControlDown() || IsSingleSel() )
HighlightAll(false);
ChangeCurrent(newCurrent);
// refresh the old focus to remove it
RefreshLine( oldCurrent );
- if ( !event.ControlDown() )
- {
+ // in single selection mode we must always have a selected item
+ if ( !event.ControlDown() || IsSingleSel() )
HighlightLine( m_current, true );
- }
}
RefreshLine( m_current );
wxWindow *parent = GetParent();
// propagate the key event upwards
- wxKeyEvent ke( wxEVT_KEY_DOWN );
- ke.m_shiftDown = event.m_shiftDown;
- ke.m_controlDown = event.m_controlDown;
- ke.m_altDown = event.m_altDown;
- ke.m_metaDown = event.m_metaDown;
- ke.m_keyCode = event.m_keyCode;
- ke.m_x = event.m_x;
- ke.m_y = event.m_y;
+ wxKeyEvent ke(event);
ke.SetEventObject( parent );
- if (parent->GetEventHandler()->ProcessEvent( ke )) return;
+ if (parent->GetEventHandler()->ProcessEvent( ke ))
+ return;
event.Skip();
}
wxWindow *parent = GetParent();
// propagate the key event upwards
- wxKeyEvent ke( wxEVT_KEY_UP );
- ke.m_shiftDown = event.m_shiftDown;
- ke.m_controlDown = event.m_controlDown;
- ke.m_altDown = event.m_altDown;
- ke.m_metaDown = event.m_metaDown;
- ke.m_keyCode = event.m_keyCode;
- ke.m_x = event.m_x;
- ke.m_y = event.m_y;
- ke.SetEventObject( parent );
- if (parent->GetEventHandler()->ProcessEvent( ke )) return;
+ wxKeyEvent ke(event);
+ if (parent->GetEventHandler()->ProcessEvent( ke ))
+ return;
event.Skip();
}
}
// propagate the char event upwards
- wxKeyEvent ke( wxEVT_CHAR );
- ke.m_shiftDown = event.m_shiftDown;
- ke.m_controlDown = event.m_controlDown;
- ke.m_altDown = event.m_altDown;
- ke.m_metaDown = event.m_metaDown;
- ke.m_keyCode = event.m_keyCode;
- ke.m_x = event.m_x;
- ke.m_y = event.m_y;
+ wxKeyEvent ke(event);
ke.SetEventObject( parent );
- if (parent->GetEventHandler()->ProcessEvent( ke )) return;
+ if (parent->GetEventHandler()->ProcessEvent( ke ))
+ return;
- if (event.GetKeyCode() == WXK_TAB)
- {
- wxNavigationKeyEvent nevent;
- nevent.SetWindowChange( event.ControlDown() );
- nevent.SetDirection( !event.ShiftDown() );
- nevent.SetEventObject( GetParent()->GetParent() );
- nevent.SetCurrentFocus( m_parent );
- if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent ))
- return;
- }
+ if ( HandleAsNavigationKey(event) )
+ return;
// no item -> nothing to do
if (!HasCurrent())
case WXK_SPACE:
if ( IsSingleSel() )
{
- SendNotify( m_current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
-
- if ( IsHighlighted(m_current) )
+ if ( event.ControlDown() )
+ {
+ ReverseHighlight(m_current);
+ }
+ else // normal space press
{
- // don't unselect the item in single selection mode
- break;
+ SendNotify( m_current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
}
- //else: select it in ReverseHighlight() below if unselected
}
-
- ReverseHighlight(m_current);
+ else // multiple selection
+ {
+ ReverseHighlight(m_current);
+ }
break;
case WXK_RETURN:
if (width == wxLIST_AUTOSIZE_USEHEADER)
{
width = GetTextLength(column->GetText());
+ width += 2*EXTRA_WIDTH;
+
+ // check for column header's image availability
+ const int image = column->GetImage();
+ if ( image != -1 )
+ {
+ if ( m_small_image_list )
+ {
+ int ix = 0, iy = 0;
+ m_small_image_list->GetSize(image, ix, iy);
+ width += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE;
+ }
+ }
}
else if ( width == wxLIST_AUTOSIZE )
{
wxRect wxListMainWindow::GetViewRect() const
{
- wxASSERT_MSG( !HasFlag(wxLC_REPORT | wxLC_LIST),
- _T("wxListCtrl::GetViewRect() only works in icon mode") );
+ wxASSERT_MSG( !HasFlag(wxLC_LIST), "not implemented for list view" );
// we need to find the longest/tallest label
wxCoord xMax = 0, yMax = 0;
{
for ( int i = 0; i < count; i++ )
{
- wxRect r;
- GetItemRect(i, r);
+ // we need logical, not physical, coordinates here, so use
+ // GetLineRect() instead of GetItemRect()
+ wxRect r = GetLineRect(i);
wxCoord x = r.GetRight(),
y = r.GetBottom();
return wxRect(0, 0, xMax, yMax);
}
-void wxListMainWindow::GetItemRect( long index, wxRect &rect ) const
+bool
+wxListMainWindow::GetSubItemRect(long item, long subItem, wxRect& rect) const
{
- wxCHECK_RET( index >= 0 && (size_t)index < GetItemCount(),
- _T("invalid index in GetItemRect") );
+ wxCHECK_MSG( subItem == wxLIST_GETSUBITEMRECT_WHOLEITEM || InReportView(),
+ false,
+ _T("GetSubItemRect only meaningful in report view") );
+ wxCHECK_MSG( item >= 0 && (size_t)item < GetItemCount(), false,
+ _T("invalid item in GetSubItemRect") );
// ensure that we're laid out, otherwise we could return nonsense
if ( m_dirty )
RecalculatePositions(true /* no refresh */);
}
- rect = GetLineRect((size_t)index);
+ rect = GetLineRect((size_t)item);
+
+ // Adjust rect to specified column
+ if ( subItem != wxLIST_GETSUBITEMRECT_WHOLEITEM )
+ {
+ wxCHECK_MSG( subItem >= 0 && subItem < GetColumnCount(), false,
+ _T("invalid subItem in GetSubItemRect") );
+
+ for (int i = 0; i < subItem; i++)
+ {
+ rect.x += GetColumnWidth(i);
+ }
+ rect.width = GetColumnWidth(subItem);
+ }
CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y);
+
+ return true;
}
bool wxListMainWindow::GetItemPosition(long item, wxPoint& pos) const
const size_t count = GetItemCount();
int iconSpacing;
- if ( HasFlag(wxLC_ICON) )
+ if ( HasFlag(wxLC_ICON) && m_normal_image_list )
iconSpacing = m_normal_spacing;
- else if ( HasFlag(wxLC_SMALL_ICON) )
+ else if ( HasFlag(wxLC_SMALL_ICON) && m_small_image_list )
iconSpacing = m_small_spacing;
else
iconSpacing = 0;
if ( m_current != index || m_current == count - 1 )
m_current--;
}
-
+
if ( InReportView() )
{
// mark the Column Max Width cache as dirty if the items in the line
{
if (str.empty())
return wxNOT_FOUND;
-
+
long pos = start;
wxString str_upper = str.Upper();
if (pos < 0)
void wxListMainWindow::SortItems( wxListCtrlCompare fn, long data )
{
+ // selections won't make sense any more after sorting the items so reset
+ // them
+ HighlightAll(false);
+ ResetCurrent();
+
list_ctrl_compare_func_2 = fn;
list_ctrl_compare_data = data;
m_lines.Sort( list_ctrl_compare_func_1 );
void wxListMainWindow::OnScroll(wxScrollWinEvent& event)
{
- // update our idea of which lines are shown when we redraw the window the
- // next time
- ResetVisibleLinesRange();
-
// FIXME
#if ( defined(__WXGTK__) || defined(__WXMAC__) ) && !defined(__WXUNIVERSAL__)
- wxScrolledWindow::OnScroll(event);
+ wxScrolledCanvas::OnScroll(event);
#else
HandleOnScroll( event );
#endif
+ // update our idea of which lines are shown when we redraw the window the
+ // next time
+ ResetVisibleLinesRange();
+
if ( event.GetOrientation() == wxHORIZONTAL && HasHeader() )
{
wxGenericListCtrl* lc = GetListCtrl();
{
if ( m_headerWin )
{
-#ifdef __WXMAC__
+#if defined( __WXMAC__ ) && wxOSX_USE_COCOA_OR_CARBON
SInt32 h;
GetThemeMetric( kThemeMetricListHeaderHeight, &h );
#else
if ( !wxControl::Create( parent, id, pos, size, style, validator, name ) )
return false;
+ // this window itself shouldn't get the focus, only m_mainWin should
+ SetCanFocus(false);
+
// don't create the inner window with the border
style &= ~wxBORDER_MASK;
m_mainWin = new wxListMainWindow( this, wxID_ANY, wxPoint(0, 0), size, style );
-#ifdef __WXMAC_CARBON__
+#if defined( __WXMAC__ ) && wxOSX_USE_COCOA_OR_CARBON
// Human Interface Guidelines ask us for a special font in this case
if ( GetWindowVariant() == wxWINDOW_VARIANT_NORMAL )
{
wxFont font;
- font.MacCreateThemeFont( kThemeViewsFont );
+ font.MacCreateFromThemeFont( kThemeViewsFont );
SetFont( font );
}
#endif
{
CreateHeaderWindow();
-#ifdef __WXMAC_CARBON__
+#if defined( __WXMAC__ ) && wxOSX_USE_COCOA_OR_CARBON
if (m_headerWin)
{
wxFont font;
- font.MacCreateThemeFont( kThemeSmallSystemFont );
+ font.MacCreateFromThemeFont( kThemeSmallSystemFont );
m_headerWin->SetFont( font );
CalculateAndSetHeaderHeight();
}
else
flag &= ~style;
- SetWindowStyleFlag( flag );
+ // some styles can be set without recreating everything (as happens in
+ // SetWindowStyleFlag() which calls wxListMainWindow::DeleteEverything())
+ if ( !(style & ~(wxLC_HRULES | wxLC_VRULES)) )
+ {
+ Refresh();
+ wxWindow::SetWindowStyleFlag(flag);
+ }
+ else
+ {
+ SetWindowStyleFlag( flag );
+ }
}
void wxGenericListCtrl::SetWindowStyleFlag( long flag )
return info.m_data;
}
-bool wxGenericListCtrl::SetItemData( long item, long data )
+bool wxGenericListCtrl::SetItemPtrData( long item, wxUIntPtr data )
{
wxListItem info;
info.m_mask = wxLIST_MASK_DATA;
return m_mainWin->GetViewRect();
}
-bool wxGenericListCtrl::GetItemRect( long item, wxRect &rect, int WXUNUSED(code) ) const
+bool wxGenericListCtrl::GetItemRect(long item, wxRect& rect, int code) const
{
- m_mainWin->GetItemRect( item, rect );
+ return GetSubItemRect(item, wxLIST_GETSUBITEMRECT_WHOLEITEM, rect, code);
+}
+
+bool wxGenericListCtrl::GetSubItemRect(long item,
+ long subItem,
+ wxRect& rect,
+ int WXUNUSED(code)) const
+{
+ if ( !m_mainWin->GetSubItemRect( item, subItem, rect ) )
+ return false;
+
if ( m_mainWin->HasHeader() )
rect.y += m_headerHeight + 1;
+
return true;
}
bool wxGenericListCtrl::SetItemPosition( long WXUNUSED(item), const wxPoint& WXUNUSED(pos) )
{
- return 0;
+ return false;
}
int wxGenericListCtrl::GetItemCount() const
return info.GetBackgroundColour();
}
+int wxGenericListCtrl::GetScrollPos( int orient ) const
+{
+ return m_mainWin->GetScrollPos( orient );
+}
+
+void wxGenericListCtrl::SetScrollPos( int orient, int pos, bool refresh )
+{
+ m_mainWin->SetScrollPos( orient, pos, refresh );
+}
+
void wxGenericListCtrl::SetItemFont( long item, const wxFont &f )
{
wxListItem info;
return InsertColumn( col, item );
}
-bool wxGenericListCtrl::ScrollList( int WXUNUSED(dx), int WXUNUSED(dy) )
+bool wxGenericListCtrl::ScrollList( int dx, int dy )
{
- return 0;
+ return m_mainWin->ScrollList(dx, dy);
}
// Sort items.
}
}
-void wxGenericListCtrl::Freeze()
-{
- m_mainWin->Freeze();
-}
-
-void wxGenericListCtrl::Thaw()
-{
- m_mainWin->Thaw();
-}
-
#endif // wxUSE_LISTCTRL