#if wxUSE_LISTCTRL
-#include "wx/dcscreen.h"
-#include "wx/app.h"
-#include "wx/listctrl.h"
+#ifndef WX_PRECOMP
+ #include "wx/app.h"
+
+ #include "wx/dynarray.h"
+
+ #include "wx/dcscreen.h"
+
+ #include "wx/textctrl.h"
+#endif
+
#include "wx/imaglist.h"
-#include "wx/dynarray.h"
+#include "wx/listctrl.h"
-#ifdef __WXGTK__
-#include <gtk/gtk.h>
-#include "wx/gtk/win_gtk.h"
+#if defined(__WXGTK__)
+ #include <gtk/gtk.h>
+ #include "wx/gtk/win_gtk.h"
#endif
// ----------------------------------------------------------------------------
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_FOCUSED)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT)
// ----------------------------------------------------------------------------
wxString *m_res;
wxListMainWindow *m_owner;
wxString m_startValue;
+ bool m_finished;
public:
wxListTextCtrl() {}
// bring the current item into view
void MoveToFocus() { MoveToItem(m_current); }
+ // start editing the label of the given item
void EditLabel( long item );
+
+ // suspend/resume redrawing the control
+ void Freeze();
+ void Thaw();
+
void OnRenameTimer();
void OnRenameAccept();
bool IsEmpty() const { return GetItemCount() == 0; }
void SetItemCount(long count);
- void ResetCurrent() { m_current = (size_t)-1; }
+ // change the current (== focused) item, send a notification event
+ void ChangeCurrent(size_t current);
+ void ResetCurrent() { ChangeCurrent((size_t)-1); }
bool HasCurrent() const { return m_current != (size_t)-1; }
// send out a wxListEvent
#ifdef __WXMAC__
return *wxWHITE;
#else
- return wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT);
+ return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT);
#endif
}
// delete all items but don't refresh: called from dtor
void DoDeleteAllItems();
- // called when an item is [un]focuded, i.e. becomes [not] current
- //
- // currently unused
- void OnFocusLine( size_t line );
- void OnUnfocusLine( size_t line );
-
// the height of one line using the current font
wxCoord m_lineHeight;
wxBrush *m_highlightBrush,
*m_highlightUnfocusedBrush;
+ // if this is > 0, the control is frozen and doesn't redraw itself
+ size_t m_freezeCount;
+
DECLARE_DYNAMIC_CLASS(wxListMainWindow);
DECLARE_EVENT_TABLE()
};
// stop counting (see comment below)
itemsChanged = NULL;
}
-
- itemsChanged->Add(m_itemsSel[i]);
+ else
+ {
+ itemsChanged->Add(m_itemsSel[i]);
+ }
}
m_itemsSel.RemoveAt(i);
wxColour colText;
if ( highlighted )
{
- colText = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+ colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
}
else
{
m_owner = owner;
m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE );
- SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE ) );
+ SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
}
wxListHeaderWindow::~wxListHeaderWindow()
void wxListHeaderWindow::DoDrawRect( wxDC *dc, int x, int y, int w, int h )
{
-#ifdef __WXGTK__
+#if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
GtkStateType state = m_parent->IsEnabled() ? GTK_STATE_NORMAL
: GTK_STATE_INSENSITIVE;
gtk_paint_box (m_wxwindow->style, GTK_PIZZA(m_wxwindow)->bin_window,
state, GTK_SHADOW_OUT,
- (GdkRectangle*) NULL, m_wxwindow, "button",
+ (GdkRectangle*) NULL, m_wxwindow,
+ (char *)"button", // const_cast
x-1, y-1, w+2, h+2);
#elif defined( __WXMAC__ )
const int m_corner = 1;
dc->SetBrush( *wxTRANSPARENT_BRUSH );
- dc->SetPen( wxPen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW ) , 1 , wxSOLID ) );
+ dc->SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNSHADOW ) , 1 , wxSOLID ) );
dc->DrawLine( x+w-m_corner+1, y, x+w, y+h ); // right (outer)
dc->DrawRectangle( x, y+h, w+1, 1 ); // bottom (outer)
dc->DrawLine( x+w-m_corner+1, y, x+w, y+h ); // right (outer)
dc->DrawRectangle( x, y+h, w+1, 1 ); // bottom (outer)
- wxPen pen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID );
+ wxPen pen( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID );
dc->SetPen( pen );
dc->DrawLine( x+w-m_corner, y, x+w-1, y+h ); // right (inner)
void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
{
-#ifdef __WXGTK__
+#if defined(__WXGTK__)
wxClientDC dc( this );
#else
wxPaintDC dc( this );
int numColumns = m_owner->GetColumnCount();
wxListItem item;
- for (int i = 0; i < numColumns; i++)
+ for ( int i = 0; i < numColumns && x < w; i++ )
{
m_owner->GetColumn( i, item );
int wCol = item.m_width;
dc.DrawText( item.GetText(),
x + EXTRA_WIDTH, HEADER_OFFSET_Y + EXTRA_HEIGHT );
- if ( x > w - wCol + 5 )
- break;
-
x += wCol;
}
+
dc.EndDrawing();
}
{
int x1 = m_currentX;
int y1 = 0;
- ClientToScreen( &x1, &y1 );
+ m_owner->ClientToScreen( &x1, &y1 );
- int x2 = m_currentX-1;
+ int x2 = m_currentX;
int y2 = 0;
m_owner->GetClientSize( NULL, &y2 );
m_owner->ClientToScreen( &x2, &y2 );
(*m_accept) = FALSE;
(*m_res) = "";
m_startValue = value;
+ m_finished = FALSE;
}
void wxListTextCtrl::OnChar( wxKeyEvent &event )
if (!wxPendingDelete.Member(this))
wxPendingDelete.Append(this);
- if ((*m_accept) && ((*m_res) != m_startValue))
+ if ((*m_res) != m_startValue)
m_owner->OnRenameAccept();
+ m_finished = TRUE;
+ m_owner->SetFocus(); // This doesn't work. TODO.
+
return;
}
if (event.m_keyCode == WXK_ESCAPE)
if (!wxPendingDelete.Member(this))
wxPendingDelete.Append(this);
+ m_finished = TRUE;
+ m_owner->SetFocus(); // This doesn't work. TODO.
+
return;
}
void wxListTextCtrl::OnKeyUp( wxKeyEvent &event )
{
+ if (m_finished)
+ {
+ event.Skip();
+ return;
+ }
+
// auto-grow the textctrl:
wxSize parentSize = m_owner->GetSize();
wxPoint myPos = GetPosition();
wxSize mySize = GetSize();
int sx, sy;
- GetTextExtent(GetValue() + _T("MM"), &sx, &sy); // FIXME: MM??
+ GetTextExtent(GetValue() + _T("M"), &sx, &sy); // FIXME: MM??
if (myPos.x + sx > parentSize.x)
sx = parentSize.x - myPos.x;
if (mySize.x > sx)
event.Skip();
}
-void wxListTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
+void wxListTextCtrl::OnKillFocus( wxFocusEvent &event )
{
+ if (m_finished)
+ {
+ event.Skip();
+ return;
+ }
+
if (!wxPendingDelete.Member(this))
wxPendingDelete.Append(this);
- if ((*m_accept) && ((*m_res) != m_startValue))
+ (*m_accept) = TRUE;
+ (*m_res) = GetValue();
+
+ if ((*m_res) != m_startValue)
m_owner->OnRenameAccept();
}
m_currentEdit =
m_lineLastClicked =
m_lineBeforeLastClicked = (size_t)-1;
+
+ m_freezeCount = 0;
}
void wxListMainWindow::InitScrolling()
m_highlightBrush = new wxBrush
(
- wxSystemSettings::GetSystemColour
+ wxSystemSettings::GetColour
(
wxSYS_COLOUR_HIGHLIGHT
),
m_highlightUnfocusedBrush = new wxBrush
(
- wxSystemSettings::GetSystemColour
+ wxSystemSettings::GetColour
(
wxSYS_COLOUR_BTNSHADOW
),
InitScrolling();
SetScrollbars( m_xScroll, m_yScroll, 0, 0, 0, 0 );
- SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX ) );
+ SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX ) );
}
wxListMainWindow::~wxListMainWindow()
for ( size_t line = from; line <= to; line++ )
{
- if ( IsHighlighted(line) )
+ if ( IsHighlighted(line) || (line == m_current) )
{
if ( line < selMin )
selMin = line;
#endif // !__WXGTK__/__WXGTK__
}
+void wxListMainWindow::Freeze()
+{
+ m_freezeCount++;
+}
+
+void wxListMainWindow::Thaw()
+{
+ wxCHECK_RET( m_freezeCount > 0, _T("thawing unfrozen list control?") );
+
+ if ( !--m_freezeCount )
+ {
+ 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() )
+ if ( IsEmpty() || m_freezeCount )
{
- // empty control. nothing to draw
+ // nothing to draw or not the moment to draw it
return;
}
// what we're trying to avoid
if ( !IsVirtual() && (command != wxEVT_COMMAND_LIST_DELETE_ITEM) )
{
- GetLine(line)->GetItem( 0, le.m_item );
+ if ( line != (size_t)-1 )
+ {
+ GetLine(line)->GetItem( 0, le.m_item );
+ }
+ //else: this happens for wxEVT_COMMAND_LIST_ITEM_FOCUSED event
}
//else: there may be no more such item
GetParent()->GetEventHandler()->ProcessEvent( le );
}
-void wxListMainWindow::OnFocusLine( size_t WXUNUSED(line) )
+void wxListMainWindow::ChangeCurrent(size_t current)
{
-// SendNotify( line, wxEVT_COMMAND_LIST_ITEM_FOCUSSED );
-}
+ m_current = current;
-void wxListMainWindow::OnUnfocusLine( size_t WXUNUSED(line) )
-{
-// SendNotify( line, wxEVT_COMMAND_LIST_ITEM_UNFOCUSSED );
+ SendNotify(current, wxEVT_COMMAND_LIST_ITEM_FOCUSED);
}
void wxListMainWindow::EditLabel( long item )
if ( IsSingleSel() || !(event.ControlDown() || event.ShiftDown()) )
{
HighlightAll( FALSE );
- m_current = current;
+
+ ChangeCurrent(current);
ReverseHighlight(m_current);
}
{
if (event.ControlDown())
{
- m_current = current;
+ ChangeCurrent(current);
ReverseHighlight(m_current);
}
else if (event.ShiftDown())
{
- m_current = current;
+ ChangeCurrent(current);
size_t lineFrom = oldCurrent,
lineTo = current;
if (m_current != oldCurrent)
{
RefreshLine( oldCurrent );
- OnUnfocusLine( oldCurrent );
- OnFocusLine( m_current );
}
// forceClick is only set if the previous click was on another item
// items anyhow
if ( event.ShiftDown() && !IsSingleSel() )
{
- m_current = newCurrent;
+ ChangeCurrent(newCurrent);
// select all the items between the old and the new one
if ( oldCurrent > newCurrent )
if ( !event.ControlDown() )
HighlightAll(FALSE);
- m_current = newCurrent;
+ ChangeCurrent(newCurrent);
HighlightLine( oldCurrent, FALSE );
RefreshLine( oldCurrent );
}
}
- OnUnfocusLine( oldCurrent );
- OnFocusLine( m_current );
RefreshLine( m_current );
MoveToFocus();
nevent.SetDirection( !event.ShiftDown() );
nevent.SetEventObject( GetParent()->GetParent() );
nevent.SetCurrentFocus( m_parent );
- if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent )) return;
+ if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent ))
+ return;
}
/* no item -> nothing to do */
case WXK_SPACE:
if ( IsSingleSel() )
{
- wxListEvent le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED,
- GetParent()->GetId() );
- le.SetEventObject( GetParent() );
- le.m_itemIndex = m_current;
- GetLine(m_current)->GetItem( 0, le.m_item );
- GetParent()->GetEventHandler()->ProcessEvent( le );
+ SendNotify( m_current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
if ( IsHighlighted(m_current) )
{
case WXK_RETURN:
case WXK_EXECUTE:
- {
- wxListEvent le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED,
- GetParent()->GetId() );
- le.SetEventObject( GetParent() );
- le.m_itemIndex = m_current;
- GetLine(m_current)->GetItem( 0, le.m_item );
- GetParent()->GetEventHandler()->ProcessEvent( le );
- }
+ SendNotify( m_current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
break;
default:
// EVT_KILL_FOCUS before which means that we finish by redrawing the items
// which are already drawn correctly resulting in horrible flicker - avoid
// it
- if ( m_hasFocus )
- return;
+ if ( !m_hasFocus )
+ {
+ m_hasFocus = TRUE;
- m_hasFocus = TRUE;
+ RefreshSelected();
+ }
- if (!GetParent())
+ if ( !GetParent() )
return;
- RefreshSelected();
-
#ifdef __WXGTK__
g_focusWindow = GetParent();
#endif
// don't do anything if this item is already focused
if ( item != m_current )
{
- OnUnfocusLine( m_current );
- m_current = item;
- OnFocusLine( m_current );
+ ChangeCurrent(item);
if ( oldCurrent != (size_t)-1 )
{
// don't do anything if this item is not focused
if ( item == m_current )
{
- OnUnfocusLine( m_current );
- m_current = (size_t)-1;
+ ResetCurrent();
RefreshLine( oldCurrent );
}
// single sel mode
if ( m_current != item )
{
- OnUnfocusLine( m_current );
- m_current = item;
- OnFocusLine( m_current );
+ ChangeCurrent(item);
if ( oldCurrent != (size_t)-1 )
{
else
iconSpacing = 0;
+ // Note that we do not call GetClientSize() here but
+ // GetSize() and substract the border size for sunken
+ // borders manually. This is technically incorrect,
+ // but we need to know the client area's size WITHOUT
+ // scrollbars here. Since we don't know if there are
+ // any scrollbars, we use GetSize() instead. Another
+ // solution would be to call SetScrollbars() here to
+ // remove the scrollbars and call GetClientSize() then,
+ // but this might result in flicker and - worse - will
+ // reset the scrollbars to 0 which is not good at all
+ // if you resize a dialog/window, but don't want to
+ // reset the window scrolling. RR.
+ // Furthermore, we actually do NOT subtract the border
+ // width as 2 pixels is just the extra space which we
+ // need around the actual content in the window. Other-
+ // wise the text would e.g. touch the upper border. RR.
int clientWidth,
clientHeight;
- GetClientSize( &clientWidth, &clientHeight );
-
+ GetSize( &clientWidth, &clientHeight );
+
if ( HasFlag(wxLC_REPORT) )
{
// all lines have the same height
// fit into the window, we recalculate after subtracting an
// approximated 15 pt for the horizontal scrollbar
- clientHeight -= 4; // sunken frame
-
int entireWidth = 0;
for (int tries = 0; tries < 2; tries++)
{
- entireWidth = 0;
+ // We start with 4 for the border around all items
+ entireWidth = 4;
+
+ if (tries == 1)
+ {
+ // Now we have decided that the items do not fit into the
+ // client area. Unfortunately, wxWindows sometimes thinks
+ // that it does fit and therefore NO horizontal scrollbar
+ // is inserted. This looks ugly, so we fudge here and make
+ // the calculated width bigger than was actually has been
+ // calculated. This ensures that wxScrolledWindows puts
+ // a scrollbar at the bottom of its client area.
+ entireWidth += SCROLL_UNIT_X;
+ }
+
+ // Start at 2,2 so the text does not touch the border
int x = 2;
int y = 2;
int maxWidth = 0;
currentlyVisibleLines++;
wxListLineData *line = GetLine(i);
line->CalculateSize( &dc, iconSpacing );
- line->SetPosition( x, y, clientWidth, iconSpacing );
+ line->SetPosition( x, y, clientWidth, iconSpacing ); // Why clientWidth? (FIXME)
wxSize sizeLine = GetLineSize(i);
if (currentlyVisibleLines > m_linesPerPage)
m_linesPerPage = currentlyVisibleLines;
- // assume that the size of the next one is the same... (FIXME)
- if ( y + sizeLine.y - 6 >= clientHeight )
+ // Assume that the size of the next one is the same... (FIXME)
+ if ( y + sizeLine.y >= clientHeight )
{
currentlyVisibleLines = 0;
y = 2;
entireWidth += maxWidth+6;
maxWidth = 0;
}
+
+ // We have reached the last item.
if ( i == count - 1 )
entireWidth += maxWidth;
- if ((tries == 0) && (entireWidth > clientWidth))
+
+ if ( (tries == 0) && (entireWidth+SCROLL_UNIT_X > clientWidth) )
{
- clientHeight -= 15; // scrollbar height
+ clientHeight -= 15; // We guess the scrollbar height. (FIXME)
m_linesPerPage = 0;
currentlyVisibleLines = 0;
break;
}
+
if ( i == count - 1 )
- tries = 1; // everything fits, no second try required
+ tries = 1; // Everything fits, no second try required.
}
}
{
if ( !HasCurrent() && !IsEmpty() )
{
- m_current = 0;
- }
-
- if ( m_current != (size_t)-1 )
- {
- OnFocusLine( m_current );
+ ChangeCurrent(0);
}
}
}
}
-// -------------------------------------------------------------------------------------
-// wxListEvent
-// -------------------------------------------------------------------------------------
-
-IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent)
-
-wxListEvent::wxListEvent( wxEventType commandType, int id )
- : wxNotifyEvent( commandType, id )
-{
- m_code = 0;
- m_itemIndex = 0;
- m_oldItemIndex = 0;
- m_col = 0;
- m_cancelled = FALSE;
- m_pointDrag.x = 0;
- m_pointDrag.y = 0;
-}
-
-void wxListEvent::CopyObject(wxObject& object_dest) const
-{
- wxListEvent *obj = (wxListEvent *)&object_dest;
-
- wxNotifyEvent::CopyObject(object_dest);
-
- obj->m_code = m_code;
- obj->m_itemIndex = m_itemIndex;
- obj->m_oldItemIndex = m_oldItemIndex;
- obj->m_col = m_col;
- obj->m_cancelled = m_cancelled;
- obj->m_pointDrag = m_pointDrag;
- obj->m_item.m_mask = m_item.m_mask;
- obj->m_item.m_itemId = m_item.m_itemId;
- obj->m_item.m_col = m_item.m_col;
- obj->m_item.m_state = m_item.m_state;
- obj->m_item.m_stateMask = m_item.m_stateMask;
- obj->m_item.m_text = m_item.m_text;
- obj->m_item.m_image = m_item.m_image;
- obj->m_item.m_data = m_item.m_data;
- obj->m_item.m_format = m_item.m_format;
- obj->m_item.m_width = m_item.m_width;
-
- if ( m_item.HasAttributes() )
- {
- obj->m_item.SetTextColour(m_item.GetTextColour());
- }
-}
-
// -------------------------------------------------------------------------------------
// wxListCtrl
// -------------------------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxControl)
IMPLEMENT_DYNAMIC_CLASS(wxListView, wxListCtrl)
+IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent)
+
BEGIN_EVENT_TABLE(wxListCtrl,wxControl)
EVT_SIZE(wxListCtrl::OnSize)
EVT_IDLE(wxListCtrl::OnIdle)
wxListCtrl::~wxListCtrl()
{
- if ( m_mainWin )
- m_mainWin->ResetCurrent();
-
if (m_ownsImageListNormal)
delete m_imageListNormal;
if (m_ownsImageListSmall)
{
size_t count = m_mainWin->m_columns.GetCount();
for ( size_t n = 0; n < count; n++ )
- DeleteColumn(n);
+ DeleteColumn(0);
return TRUE;
}
m_mainWin->RefreshLines(itemFrom, itemTo);
}
+void wxListCtrl::Freeze()
+{
+ m_mainWin->Freeze();
+}
+
+void wxListCtrl::Thaw()
+{
+ m_mainWin->Thaw();
+}
+
#endif // wxUSE_LISTCTRL