X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ae0d8c14454193a9cb8e95ea28206014ac5aa611..31478355f8348d7dfb1c647919b62b224acfa8a0:/src/generic/listctrl.cpp diff --git a/src/generic/listctrl.cpp b/src/generic/listctrl.cpp index d372557375..ac046f88fd 100644 --- a/src/generic/listctrl.cpp +++ b/src/generic/listctrl.cpp @@ -47,14 +47,31 @@ #include "wx/textctrl.h" #endif -#include "wx/imaglist.h" -#include "wx/listctrl.h" - -#ifdef __WXGTK__ - #include - #include "wx/gtk/win_gtk.h" +// under Win32 we always use the native version and also may use the generic +// one, however some things should be done only if we use only the generic +// version +#if defined(__WIN32__) && !defined(__WXUNIVERSAL__) + #define HAVE_NATIVE_LISTCTRL #endif +// if we have the native control, wx/listctrl.h declares it and not this one +#ifdef HAVE_NATIVE_LISTCTRL + #include "wx/generic/listctrl.h" +#else // !HAVE_NATIVE_LISTCTRL + #include "wx/listctrl.h" + + // 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 // HAVE_NATIVE_LISTCTRL/!HAVE_NATIVE_LISTCTRL + +#include "wx/selstore.h" + +#include "wx/renderer.h" + // ---------------------------------------------------------------------------- // events // ---------------------------------------------------------------------------- @@ -118,83 +135,6 @@ static const int IMAGE_MARGIN_IN_REPORT_MODE = 5; // private classes // ============================================================================ -// ---------------------------------------------------------------------------- -// wxSelectionStore -// ---------------------------------------------------------------------------- - -int CMPFUNC_CONV wxSizeTCmpFn(size_t n1, size_t n2) { return n1 - n2; } - -WX_DEFINE_SORTED_EXPORTED_ARRAY(size_t, wxIndexArray); - -// this class is used to store the selected items in the virtual list control -// (but it is not tied to list control and so can be used with other controls -// such as wxListBox in wxUniv) -// -// the idea is to make it really smart later (i.e. store the selections as an -// array of ranes + individual items) but, as I don't have time to do it now -// (this would require writing code to merge/break ranges and much more) keep -// it simple but define a clean interface to it which allows it to be made -// smarter later -class WXDLLEXPORT wxSelectionStore -{ -public: - wxSelectionStore() : m_itemsSel(wxSizeTCmpFn) { Init(); } - - // set the total number of items we handle - void SetItemCount(size_t count) { m_count = count; } - - // special case of SetItemCount(0) - void Clear() { m_itemsSel.Clear(); m_count = 0; } - - // must be called when a new item is inserted/added - void OnItemAdd(size_t item) { wxFAIL_MSG( _T("TODO") ); } - - // must be called when an item is deleted - void OnItemDelete(size_t item); - - // select one item, use SelectRange() insted if possible! - // - // returns true if the items selection really changed - bool SelectItem(size_t item, bool select = TRUE); - - // select the range of items - // - // return true and fill the itemsChanged array with the indices of items - // which have changed state if "few" of them did, otherwise return false - // (meaning that too many items changed state to bother counting them - // individually) - bool SelectRange(size_t itemFrom, size_t itemTo, - bool select = TRUE, - wxArrayInt *itemsChanged = NULL); - - // return true if the given item is selected - bool IsSelected(size_t item) const; - - // return the total number of selected items - size_t GetSelectedCount() const - { - return m_defaultState ? m_count - m_itemsSel.GetCount() - : m_itemsSel.GetCount(); - } - -private: - // (re)init - void Init() { m_defaultState = FALSE; } - - // the total number of items we handle - size_t m_count; - - // the default state: normally, FALSE (i.e. off) but maybe set to TRUE if - // there are more selected items than non selected ones - this allows to - // handle selection of all items efficiently - bool m_defaultState; - - // the array of items whose selection state is different from default - wxIndexArray m_itemsSel; - - DECLARE_NO_COPY_CLASS(wxSelectionStore) -}; - //----------------------------------------------------------------------------- // wxListItemData (internal) //----------------------------------------------------------------------------- @@ -315,7 +255,7 @@ WX_DECLARE_LIST(wxListItemData, wxListItemDataList); #include "wx/listimpl.cpp" WX_DEFINE_LIST(wxListItemDataList); -class WXDLLEXPORT wxListLineData +class wxListLineData { public: // the list of subitems: only may have more than one item in report mode @@ -346,7 +286,11 @@ public: public: wxListLineData(wxListMainWindow *owner); - ~wxListLineData() { delete m_gi; } + ~wxListLineData() + { + WX_CLEAR_LIST(wxListItemDataList, m_items); + delete m_gi; + } // are we in report mode? inline bool InReportView() const; @@ -413,6 +357,10 @@ private: const wxListItemAttr *attr, bool highlight); + // draw the text on the DC with the correct justification; also add an + // ellipsis if the text is too large to fit in the current width + void DrawTextFormatted(wxDC *dc, const wxString &text, int col, int x, int y, int width); + // these are only used by GetImage/SetImage above, we don't support images // with subitems at the public API level yet void SetImage( int index, int image ); @@ -435,7 +383,7 @@ protected: wxCursor *m_resizeCursor; bool m_isDragging; - // column being resized + // column being resized or -1 int m_column; // divider line position in logical (unscrolled) coords @@ -454,11 +402,10 @@ public: const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = 0, - const wxString &name = "wxlistctrlcolumntitles" ); + const wxString &name = wxT("wxlistctrlcolumntitles") ); virtual ~wxListHeaderWindow(); - void DoDrawRect( wxDC *dc, int x, int y, int w, int h ); void DrawCurrent(); void AdjustDC(wxDC& dc); @@ -473,6 +420,10 @@ private: // common part of all ctors void Init(); + // generate and process the list event of the given type, return true if + // it wasn't vetoed, i.e. if we should proceed + bool SendListEvent(wxEventType type, wxPoint pos); + DECLARE_DYNAMIC_CLASS(wxListHeaderWindow) DECLARE_EVENT_TABLE() }; @@ -497,27 +448,23 @@ public: class WXDLLEXPORT wxListTextCtrl: public wxTextCtrl { -private: - bool *m_accept; - wxString *m_res; - wxListMainWindow *m_owner; - wxString m_startValue; - public: - wxListTextCtrl() {} - wxListTextCtrl( wxWindow *parent, const wxWindowID id, - bool *accept, wxString *res, wxListMainWindow *owner, - const wxString &value = "", - const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, - int style = 0, - const wxValidator& validator = wxDefaultValidator, - const wxString &name = "listctrltextctrl" ); + wxListTextCtrl(wxListMainWindow *owner, size_t itemEdit); + +protected: void OnChar( wxKeyEvent &event ); void OnKeyUp( wxKeyEvent &event ); void OnKillFocus( wxFocusEvent &event ); + bool AcceptChanges(); + void Finish(); + private: - DECLARE_DYNAMIC_CLASS(wxListTextCtrl); + wxListMainWindow *m_owner; + wxString m_startValue; + size_t m_itemEdited; + bool m_finished; + DECLARE_EVENT_TABLE() }; @@ -529,7 +476,7 @@ WX_DECLARE_LIST(wxListHeaderData, wxListHeaderDataList); #include "wx/listimpl.cpp" WX_DEFINE_LIST(wxListHeaderDataList); -class WXDLLEXPORT wxListMainWindow : public wxScrolledWindow +class wxListMainWindow : public wxScrolledWindow { public: wxListMainWindow(); @@ -626,8 +573,11 @@ public: void Freeze(); void Thaw(); + void SetFocus(); + void OnRenameTimer(); - void OnRenameAccept(); + bool OnRenameAccept(size_t itemEdit, const wxString& value); + void OnRenameCancelled(size_t itemEdit); void OnMouse( wxMouseEvent &event ); @@ -646,7 +596,7 @@ public: void GetImageSize( int index, int &width, int &height ) const; int GetTextLength( const wxString &s ) const; - void SetImageList( wxImageList *imageList, int which ); + void SetImageList( wxImageListType *imageList, int which ); void SetItemSpacing( int spacing, bool isSmall = FALSE ); int GetItemSpacing( bool isSmall = FALSE ); @@ -662,12 +612,29 @@ public: int GetCountPerPage() const; void SetItem( wxListItem &item ); - void GetItem( wxListItem &item ); + void GetItem( wxListItem &item ) const; void SetItemState( long item, long state, long stateMask ); - int GetItemState( long item, long stateMask ); - void GetItemRect( long index, wxRect &rect ); - bool GetItemPosition( long item, wxPoint& pos ); - int GetSelectedItemCount(); + int GetItemState( long item, long stateMask ) const; + void GetItemRect( long index, wxRect &rect ) const; + bool GetItemPosition( long item, wxPoint& pos ) const; + int GetSelectedItemCount() const; + + wxString GetItemText(long item) const + { + wxListItem info; + info.m_itemId = item; + GetItem( info ); + return info.m_text; + } + + void SetItemText(long item, const wxString& value) + { + wxListItem info; + info.m_mask = wxLIST_MASK_TEXT; + info.m_itemId = item; + info.m_text = value; + SetItem( info ); + } // set the scrollbars and update the positions of the items void RecalculatePositions(bool noRefresh = FALSE); @@ -675,7 +642,7 @@ public: // refresh the window and the header void RefreshAll(); - long GetNextItem( long item, int geometry, int state ); + long GetNextItem( long item, int geometry, int state ) const; void DeleteItem( long index ); void DeleteAllItems(); void DeleteColumn( int col ); @@ -716,9 +683,9 @@ public: // these are for wxListLineData usage only // get the backpointer to the list ctrl - wxListCtrl *GetListCtrl() const + wxGenericListCtrl *GetListCtrl() const { - return wxStaticCast(GetParent(), wxListCtrl); + return wxStaticCast(GetParent(), wxGenericListCtrl); } // get the height of all lines (assuming they all do have the same height) @@ -734,7 +701,8 @@ public: } //protected: - // the array of all line objects for a non virtual list control + // the array of all line objects for a non virtual list control (for the + // virtual list control we only ever use m_lines[0]) wxListLineDataArray m_lines; // the list of column objects @@ -743,9 +711,6 @@ public: // currently focused item or -1 size_t m_current; - // the item currently being edited or -1 - size_t m_currentEdit; - // the number of lines per page int m_linesPerPage; @@ -760,16 +725,14 @@ public: wxColour *m_highlightColour; int m_xScroll, m_yScroll; - wxImageList *m_small_image_list; - wxImageList *m_normal_image_list; + wxImageListType *m_small_image_list; + wxImageListType *m_normal_image_list; int m_small_spacing; int m_normal_spacing; bool m_hasFocus; bool m_lastOnSame; wxTimer *m_renameTimer; - bool m_renameAccept; - wxString m_renameRes; bool m_isCreated; int m_dragCount; wxPoint m_dragStart; @@ -826,7 +789,7 @@ protected: #ifdef __WXMAC__ return *wxWHITE; #else - return wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT); + return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT); #endif } @@ -856,191 +819,16 @@ private: // if this is > 0, the control is frozen and doesn't redraw itself size_t m_freezeCount; - DECLARE_DYNAMIC_CLASS(wxListMainWindow); + DECLARE_DYNAMIC_CLASS(wxListMainWindow) DECLARE_EVENT_TABLE() + + friend class wxGenericListCtrl; }; // ============================================================================ // implementation // ============================================================================ -// ---------------------------------------------------------------------------- -// wxSelectionStore -// ---------------------------------------------------------------------------- - -bool wxSelectionStore::IsSelected(size_t item) const -{ - bool isSel = m_itemsSel.Index(item) != wxNOT_FOUND; - - // if the default state is to be selected, being in m_itemsSel means that - // the item is not selected, so we have to inverse the logic - return m_defaultState ? !isSel : isSel; -} - -bool wxSelectionStore::SelectItem(size_t item, bool select) -{ - // search for the item ourselves as like this we get the index where to - // insert it later if needed, so we do only one search in the array instead - // of two (adding item to a sorted array requires a search) - size_t index = m_itemsSel.IndexForInsert(item); - bool isSel = index < m_itemsSel.GetCount() && m_itemsSel[index] == item; - - if ( select != m_defaultState ) - { - if ( !isSel ) - { - m_itemsSel.AddAt(item, index); - - return TRUE; - } - } - else // reset to default state - { - if ( isSel ) - { - m_itemsSel.RemoveAt(index); - return TRUE; - } - } - - return FALSE; -} - -bool wxSelectionStore::SelectRange(size_t itemFrom, size_t itemTo, - bool select, - wxArrayInt *itemsChanged) -{ - // 100 is hardcoded but it shouldn't matter much: the important thing is - // that we don't refresh everything when really few (e.g. 1 or 2) items - // change state - static const size_t MANY_ITEMS = 100; - - wxASSERT_MSG( itemFrom <= itemTo, _T("should be in order") ); - - // are we going to have more [un]selected items than the other ones? - if ( itemTo - itemFrom > m_count/2 ) - { - if ( select != m_defaultState ) - { - // the default state now becomes the same as 'select' - m_defaultState = select; - - // so all the old selections (which had state select) shouldn't be - // selected any more, but all the other ones should - wxIndexArray selOld = m_itemsSel; - m_itemsSel.Empty(); - - // TODO: it should be possible to optimize the searches a bit - // knowing the possible range - - size_t item; - for ( item = 0; item < itemFrom; item++ ) - { - if ( selOld.Index(item) == wxNOT_FOUND ) - m_itemsSel.Add(item); - } - - for ( item = itemTo + 1; item < m_count; item++ ) - { - if ( selOld.Index(item) == wxNOT_FOUND ) - m_itemsSel.Add(item); - } - - // many items (> half) changed state - itemsChanged = NULL; - } - else // select == m_defaultState - { - // get the inclusive range of items between itemFrom and itemTo - size_t count = m_itemsSel.GetCount(), - start = m_itemsSel.IndexForInsert(itemFrom), - end = m_itemsSel.IndexForInsert(itemTo); - - if ( start == count || m_itemsSel[start] < itemFrom ) - { - start++; - } - - if ( end == count || m_itemsSel[end] > itemTo ) - { - end--; - } - - if ( start <= end ) - { - // delete all of them (from end to avoid changing indices) - for ( int i = end; i >= (int)start; i-- ) - { - if ( itemsChanged ) - { - if ( itemsChanged->GetCount() > MANY_ITEMS ) - { - // stop counting (see comment below) - itemsChanged = NULL; - } - else - { - itemsChanged->Add(m_itemsSel[i]); - } - } - - m_itemsSel.RemoveAt(i); - } - } - } - } - else // "few" items change state - { - if ( itemsChanged ) - { - itemsChanged->Empty(); - } - - // just add the items to the selection - for ( size_t item = itemFrom; item <= itemTo; item++ ) - { - if ( SelectItem(item, select) && itemsChanged ) - { - itemsChanged->Add(item); - - if ( itemsChanged->GetCount() > MANY_ITEMS ) - { - // stop counting them, we'll just eat gobs of memory - // for nothing at all - faster to refresh everything in - // this case - itemsChanged = NULL; - } - } - } - } - - // we set it to NULL if there are many items changing state - return itemsChanged != NULL; -} - -void wxSelectionStore::OnItemDelete(size_t item) -{ - size_t count = m_itemsSel.GetCount(), - i = m_itemsSel.IndexForInsert(item); - - if ( i < count && m_itemsSel[i] == item ) - { - // this item itself was in m_itemsSel, remove it from there - m_itemsSel.RemoveAt(i); - - count--; - } - - // and adjust the index of all which follow it - while ( i < count ) - { - // all following elements must be greater than the one we deleted - wxASSERT_MSG( m_itemsSel[i] > item, _T("logic error") ); - - m_itemsSel[i++]--; - } -} - //----------------------------------------------------------------------------- // wxListItemData //----------------------------------------------------------------------------- @@ -1302,7 +1090,6 @@ inline bool wxListLineData::IsVirtual() const wxListLineData::wxListLineData( wxListMainWindow *owner ) { m_owner = owner; - m_items.DeleteContents( TRUE ); if ( InReportView() ) { @@ -1320,7 +1107,7 @@ wxListLineData::wxListLineData( wxListMainWindow *owner ) void wxListLineData::CalculateSize( wxDC *dc, int spacing ) { - wxListItemDataList::Node *node = m_items.GetFirst(); + wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); wxCHECK_RET( node, _T("no subitems at all??") ); wxListItemData *item = node->GetData(); @@ -1427,10 +1214,10 @@ void wxListLineData::CalculateSize( wxDC *dc, int spacing ) } void wxListLineData::SetPosition( int x, int y, - int window_width, + int WXUNUSED(window_width), int spacing ) { - wxListItemDataList::Node *node = m_items.GetFirst(); + wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); wxCHECK_RET( node, _T("no subitems at all??") ); wxListItemData *item = node->GetData(); @@ -1444,8 +1231,8 @@ void wxListLineData::SetPosition( int x, int y, if ( item->HasImage() ) { - m_gi->m_rectIcon.x = m_gi->m_rectAll.x + 4 - + (spacing - m_gi->m_rectIcon.width)/2; + m_gi->m_rectIcon.x = m_gi->m_rectAll.x + 4 + + (m_gi->m_rectAll.width - m_gi->m_rectIcon.width) / 2; m_gi->m_rectIcon.y = m_gi->m_rectAll.y + 4; } @@ -1503,7 +1290,7 @@ void wxListLineData::InitItems( int num ) void wxListLineData::SetItem( int index, const wxListItem &info ) { - wxListItemDataList::Node *node = m_items.Item( index ); + wxListItemDataList::compatibility_iterator node = m_items.Item( index ); wxCHECK_RET( node, _T("invalid column index in SetItem") ); wxListItemData *item = node->GetData(); @@ -1512,7 +1299,7 @@ void wxListLineData::SetItem( int index, const wxListItem &info ) void wxListLineData::GetItem( int index, wxListItem &info ) { - wxListItemDataList::Node *node = m_items.Item( index ); + wxListItemDataList::compatibility_iterator node = m_items.Item( index ); if (node) { wxListItemData *item = node->GetData(); @@ -1524,7 +1311,7 @@ wxString wxListLineData::GetText(int index) const { wxString s; - wxListItemDataList::Node *node = m_items.Item( index ); + wxListItemDataList::compatibility_iterator node = m_items.Item( index ); if (node) { wxListItemData *item = node->GetData(); @@ -1536,7 +1323,7 @@ wxString wxListLineData::GetText(int index) const void wxListLineData::SetText( int index, const wxString s ) { - wxListItemDataList::Node *node = m_items.Item( index ); + wxListItemDataList::compatibility_iterator node = m_items.Item( index ); if (node) { wxListItemData *item = node->GetData(); @@ -1546,7 +1333,7 @@ void wxListLineData::SetText( int index, const wxString s ) void wxListLineData::SetImage( int index, int image ) { - wxListItemDataList::Node *node = m_items.Item( index ); + wxListItemDataList::compatibility_iterator node = m_items.Item( index ); wxCHECK_RET( node, _T("invalid column index in SetImage()") ); wxListItemData *item = node->GetData(); @@ -1555,7 +1342,7 @@ void wxListLineData::SetImage( int index, int image ) int wxListLineData::GetImage( int index ) const { - wxListItemDataList::Node *node = m_items.Item( index ); + wxListItemDataList::compatibility_iterator node = m_items.Item( index ); wxCHECK_MSG( node, -1, _T("invalid column index in GetImage()") ); wxListItemData *item = node->GetData(); @@ -1564,7 +1351,7 @@ int wxListLineData::GetImage( int index ) const wxListItemAttr *wxListLineData::GetAttr() const { - wxListItemDataList::Node *node = m_items.GetFirst(); + wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); wxCHECK_MSG( node, NULL, _T("invalid column index in GetAttr()") ); wxListItemData *item = node->GetData(); @@ -1573,7 +1360,7 @@ wxListItemAttr *wxListLineData::GetAttr() const void wxListLineData::SetAttr(wxListItemAttr *attr) { - wxListItemDataList::Node *node = m_items.GetFirst(); + wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); wxCHECK_RET( node, _T("invalid column index in SetAttr()") ); wxListItemData *item = node->GetData(); @@ -1594,7 +1381,7 @@ bool wxListLineData::SetAttributes(wxDC *dc, wxColour colText; if ( highlighted ) { - colText = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); } else { @@ -1646,7 +1433,7 @@ bool wxListLineData::SetAttributes(wxDC *dc, void wxListLineData::Draw( wxDC *dc ) { - wxListItemDataList::Node *node = m_items.GetFirst(); + wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); wxCHECK_RET( node, _T("no subitems at all??") ); bool highlighted = IsHighlighted(); @@ -1689,18 +1476,17 @@ void wxListLineData::DrawInReportMode( wxDC *dc, dc->DrawRectangle( rectHL ); } - wxListItemDataList::Node *node = m_items.GetFirst(); - wxCHECK_RET( node, _T("no subitems at all??") ); - - size_t col = 0; wxCoord x = rect.x + HEADER_OFFSET_X, y = rect.y + (LINE_SPACING + EXTRA_HEIGHT) / 2; - while ( node ) + size_t col = 0; + for ( wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); + node; + node = node->GetNext(), col++ ) { wxListItemData *item = node->GetData(); - int width = m_owner->GetColumnWidth(col++); + int width = m_owner->GetColumnWidth(col); int xOld = x; x += width; @@ -1716,14 +1502,83 @@ void wxListLineData::DrawInReportMode( wxDC *dc, width -= ix; } - wxDCClipper clipper(*dc, xOld, y, width, rect.height); + wxDCClipper clipper(*dc, xOld, y, width - 8, rect.height); if ( item->HasText() ) { - dc->DrawText( item->GetText(), xOld, y ); + DrawTextFormatted(dc, item->GetText(), col, xOld, y, width - 8); } + } +} - node = node->GetNext(); +void wxListLineData::DrawTextFormatted(wxDC *dc, + const wxString &text, + int col, + int x, + int y, + int width) +{ + wxString drawntext, ellipsis; + wxCoord w, h, base_w; + wxListItem item; + + // determine if the string can fit inside the current width + dc->GetTextExtent(text, &w, &h); + if (w <= width) + { + // it can, draw it using the items alignment + m_owner->GetColumn(col, item); + switch ( item.GetAlign() ) + { + default: + wxFAIL_MSG( _T("unknown list item format") ); + // fall through + + case wxLIST_FORMAT_LEFT: + // nothing to do + break; + + case wxLIST_FORMAT_RIGHT: + x += width - w; + break; + + case wxLIST_FORMAT_CENTER: + x += (width - w) / 2; + break; + } + + dc->DrawText(text, x, y); + } + else // otherwise, truncate and add an ellipsis if possible + { + // determine the base width + ellipsis = wxString(wxT("...")); + dc->GetTextExtent(ellipsis, &base_w, &h); + + // continue until we have enough space or only one character left + wxCoord w_c, h_c; + size_t len = text.Length(); + drawntext = text.Left(len); + while (len > 1) + { + dc->GetTextExtent(drawntext.Last(), &w_c, &h_c); + drawntext.RemoveLast(); + len--; + w -= w_c; + if (w + base_w <= width) + break; + } + + // if still not enough space, remove ellipsis characters + while (ellipsis.Length() > 0 && w + base_w > width) + { + ellipsis = ellipsis.Left(ellipsis.Length() - 1); + dc->GetTextExtent(ellipsis, &base_w, &h); + } + + // now draw the text + dc->DrawText(drawntext, x, y); + dc->DrawText(ellipsis, x + w, y); } } @@ -1748,7 +1603,7 @@ void wxListLineData::ReverseHighlight( void ) // wxListHeaderWindow //----------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow,wxWindow); +IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow,wxWindow) BEGIN_EVENT_TABLE(wxListHeaderWindow,wxWindow) EVT_PAINT (wxListHeaderWindow::OnPaint) @@ -1785,7 +1640,7 @@ wxListHeaderWindow::wxListHeaderWindow( wxWindow *win, m_owner = owner; m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE ); - SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE ) ); + SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) ); } wxListHeaderWindow::~wxListHeaderWindow() @@ -1793,60 +1648,10 @@ wxListHeaderWindow::~wxListHeaderWindow() delete m_resizeCursor; } -void wxListHeaderWindow::DoDrawRect( wxDC *dc, int x, int y, int w, int h ) -{ -#ifdef __WXGTK__ - GtkStateType state = m_parent->IsEnabled() ? GTK_STATE_NORMAL - : GTK_STATE_INSENSITIVE; - - x = dc->XLOG2DEV( x ); - - gtk_paint_box (m_wxwindow->style, GTK_PIZZA(m_wxwindow)->bin_window, - state, GTK_SHADOW_OUT, - (GdkRectangle*) NULL, m_wxwindow, "button", - 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->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( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID ); - - dc->SetPen( pen ); - dc->DrawLine( x+w-m_corner, y, x+w-1, y+h ); // right (inner) - dc->DrawRectangle( x+1, y+h-1, w-2, 1 ); // bottom (inner) - - dc->SetPen( *wxWHITE_PEN ); - dc->DrawRectangle( x, y, w-m_corner+1, 1 ); // top (outer) - dc->DrawRectangle( x, y, 1, h ); // left (outer) - dc->DrawLine( x, y+h-1, x+1, y+h-1 ); - dc->DrawLine( x+w-1, y, x+w-1, y+1 ); -#else // !GTK, !Mac - const int m_corner = 1; - - dc->SetBrush( *wxTRANSPARENT_BRUSH ); - - dc->SetPen( *wxBLACK_PEN ); - 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 ); - - dc->SetPen( pen ); - dc->DrawLine( x+w-m_corner, y, x+w-1, y+h ); // right (inner) - dc->DrawRectangle( x+1, y+h-1, w-2, 1 ); // bottom (inner) - - dc->SetPen( *wxWHITE_PEN ); - dc->DrawRectangle( x, y, w-m_corner+1, 1 ); // top (outer) - dc->DrawRectangle( x, y, 1, h ); // left (outer) - dc->DrawLine( x, y+h-1, x+1, y+h-1 ); - dc->DrawLine( x+w-1, y, x+w-1, y+1 ); +#ifdef __WXUNIVERSAL__ +#include "wx/univ/renderer.h" +#include "wx/univ/theme.h" #endif -} // shift the DC origin to match the position of the main window horz // scrollbar: this allows us to always use logical coords @@ -1864,11 +1669,7 @@ void wxListHeaderWindow::AdjustDC(wxDC& dc) void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) { -#ifdef __WXGTK__ - wxClientDC dc( this ); -#else wxPaintDC dc( this ); -#endif PrepareDC( dc ); AdjustDC( dc ); @@ -1903,32 +1704,77 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) // inside the column rect int cw = wCol - 2; - dc.SetPen( *wxWHITE_PEN ); - - DoDrawRect( &dc, x, HEADER_OFFSET_Y, cw, h-2 ); - - // if we have an image, draw it on the right of the label - int image = item.m_image; + wxRendererNative::Get().DrawHeaderButton + ( + this, + dc, + wxRect(x, HEADER_OFFSET_Y, cw, h - 2), + m_parent->IsEnabled() ? 0 + : wxCONTROL_DISABLED + ); + + // see if we have enough space for the column label + + // for this we need the width of the text + wxCoord wLabel; + dc.GetTextExtent(item.GetText(), &wLabel, NULL); + wLabel += 2*EXTRA_WIDTH; + + // and the width of the icon, if any + static const int MARGIN_BETWEEN_TEXT_AND_ICON = 2; + int ix = 0, // init them just to suppress the compiler warnings + iy = 0; + const int image = item.m_image; + wxImageListType *imageList; if ( image != -1 ) { - wxImageList *imageList = m_owner->m_small_image_list; + imageList = m_owner->m_small_image_list; if ( imageList ) { - int ix, iy; imageList->GetSize(image, ix, iy); + wLabel += ix + MARGIN_BETWEEN_TEXT_AND_ICON; + } + } + else + { + imageList = NULL; + } - imageList->Draw - ( - image, - dc, - x + cw - ix - 1, - HEADER_OFFSET_Y + (h - 4 - iy)/2, - wxIMAGELIST_DRAW_TRANSPARENT - ); + // ignore alignment if there is not enough space anyhow + int xAligned; + switch ( wLabel < cw ? item.GetAlign() : wxLIST_FORMAT_LEFT ) + { + default: + wxFAIL_MSG( _T("unknown list item format") ); + // fall through - cw -= ix + 2; - } - //else: ignore the column image + case wxLIST_FORMAT_LEFT: + xAligned = x; + break; + + case wxLIST_FORMAT_RIGHT: + xAligned = x + cw - wLabel; + break; + + case wxLIST_FORMAT_CENTER: + xAligned = x + (cw - wLabel) / 2; + break; + } + + + // if we have an image, draw it on the right of the label + if ( imageList ) + { + imageList->Draw + ( + image, + dc, + xAligned + wLabel - ix - MARGIN_BETWEEN_TEXT_AND_ICON, + 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 @@ -1936,7 +1782,7 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 ); dc.DrawText( item.GetText(), - x + EXTRA_WIDTH, HEADER_OFFSET_Y + EXTRA_HEIGHT ); + xAligned + EXTRA_WIDTH, HEADER_OFFSET_Y + EXTRA_HEIGHT ); x += wCol; } @@ -1948,9 +1794,9 @@ void wxListHeaderWindow::DrawCurrent() { 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 ); @@ -1979,6 +1825,8 @@ void wxListHeaderWindow::OnMouse( wxMouseEvent &event ) if (m_isDragging) { + SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING, event.GetPosition()); + // we don't draw the line beyond our window, but we allow dragging it // there int w = 0; @@ -1996,6 +1844,7 @@ void wxListHeaderWindow::OnMouse( wxMouseEvent &event ) m_isDragging = FALSE; m_dirty = TRUE; m_owner->SetColumnWidth( m_column, m_currentX - m_minX ); + SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG, event.GetPosition()); } else { @@ -2018,8 +1867,9 @@ void wxListHeaderWindow::OnMouse( wxMouseEvent &event ) int xpos = 0; // find the column where this event occured - int countCol = m_owner->GetColumnCount(); - for (int col = 0; col < countCol; col++) + int col, + countCol = m_owner->GetColumnCount(); + for (col = 0; col < countCol; col++) { xpos += m_owner->GetColumnWidth( col ); m_column = col; @@ -2040,33 +1890,29 @@ void wxListHeaderWindow::OnMouse( wxMouseEvent &event ) m_minX = xpos; } + if ( col == countCol ) + m_column = -1; + if (event.LeftDown() || event.RightUp()) { if (hit_border && event.LeftDown()) { - m_isDragging = TRUE; - m_currentX = x; - DrawCurrent(); - CaptureMouse(); + if ( SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, + event.GetPosition()) ) + { + m_isDragging = TRUE; + m_currentX = x; + DrawCurrent(); + CaptureMouse(); + } + //else: column resizing was vetoed by the user code } else // click on a column { - wxWindow *parent = GetParent(); - wxListEvent le( event.LeftDown() + SendListEvent( event.LeftDown() ? wxEVT_COMMAND_LIST_COL_CLICK : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK, - parent->GetId() ); - le.SetEventObject( parent ); - le.m_pointDrag = event.GetPosition(); - - // the position should be relative to the parent window, not - // this one for compatibility with MSW and common sense: the - // user code doesn't know anything at all about this header - // window, so why should it get positions relative to it? - le.m_pointDrag.y -= GetSize().y; - - le.m_col = m_column; - parent->GetEventHandler()->ProcessEvent( le ); + event.GetPosition()); } } else if (event.Moving()) @@ -2094,6 +1940,23 @@ void wxListHeaderWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) ) m_owner->SetFocus(); } +bool wxListHeaderWindow::SendListEvent(wxEventType type, wxPoint pos) +{ + wxWindow *parent = GetParent(); + wxListEvent le( type, parent->GetId() ); + le.SetEventObject( parent ); + le.m_pointDrag = pos; + + // the position should be relative to the parent window, not + // this one for compatibility with MSW and common sense: the + // user code doesn't know anything at all about this header + // window, so why should it get positions relative to it? + le.m_pointDrag.y -= GetSize().y; + + le.m_col = m_column; + return !parent->GetEventHandler()->ProcessEvent( le ) || le.IsAllowed(); +} + //----------------------------------------------------------------------------- // wxListRenameTimer (internal) //----------------------------------------------------------------------------- @@ -2112,72 +1975,99 @@ void wxListRenameTimer::Notify() // wxListTextCtrl (internal) //----------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxListTextCtrl,wxTextCtrl); - BEGIN_EVENT_TABLE(wxListTextCtrl,wxTextCtrl) EVT_CHAR (wxListTextCtrl::OnChar) EVT_KEY_UP (wxListTextCtrl::OnKeyUp) EVT_KILL_FOCUS (wxListTextCtrl::OnKillFocus) END_EVENT_TABLE() -wxListTextCtrl::wxListTextCtrl( wxWindow *parent, - const wxWindowID id, - bool *accept, - wxString *res, - wxListMainWindow *owner, - const wxString &value, - const wxPoint &pos, - const wxSize &size, - int style, - const wxValidator& validator, - const wxString &name ) - : wxTextCtrl( parent, id, value, pos, size, style, validator, name ) -{ - m_res = res; - m_accept = accept; +wxListTextCtrl::wxListTextCtrl(wxListMainWindow *owner, size_t itemEdit) + : m_startValue(owner->GetItemText(itemEdit)), + m_itemEdited(itemEdit) +{ m_owner = owner; - (*m_accept) = FALSE; - (*m_res) = ""; - m_startValue = value; + m_finished = FALSE; + + wxRect rectLabel = owner->GetLineLabelRect(itemEdit); + + m_owner->CalcScrolledPosition(rectLabel.x, rectLabel.y, + &rectLabel.x, &rectLabel.y); + + (void)Create(owner, wxID_ANY, m_startValue, + wxPoint(rectLabel.x-4,rectLabel.y-4), + wxSize(rectLabel.width+11,rectLabel.height+8)); } -void wxListTextCtrl::OnChar( wxKeyEvent &event ) +void wxListTextCtrl::Finish() { - if (event.m_keyCode == WXK_RETURN) + if ( !m_finished ) { - (*m_accept) = TRUE; - (*m_res) = GetValue(); + wxPendingDelete.Append(this); - if (!wxPendingDelete.Member(this)) - wxPendingDelete.Append(this); + m_finished = TRUE; - if ((*m_accept) && ((*m_res) != m_startValue)) - m_owner->OnRenameAccept(); + m_owner->SetFocus(); + } +} - return; +bool wxListTextCtrl::AcceptChanges() +{ + const wxString value = GetValue(); + + if ( value == m_startValue ) + { + // nothing changed, always accept + return TRUE; } - if (event.m_keyCode == WXK_ESCAPE) + + if ( !m_owner->OnRenameAccept(m_itemEdited, value) ) { - (*m_accept) = FALSE; - (*m_res) = ""; + // vetoed by the user + return FALSE; + } - if (!wxPendingDelete.Member(this)) - wxPendingDelete.Append(this); + // accepted, do rename the item + m_owner->SetItemText(m_itemEdited, value); - return; - } + return TRUE; +} - event.Skip(); +void wxListTextCtrl::OnChar( wxKeyEvent &event ) +{ + switch ( event.m_keyCode ) + { + case WXK_RETURN: + if ( !AcceptChanges() ) + { + // vetoed by the user code + break; + } + //else: fall through + + case WXK_ESCAPE: + Finish(); + m_owner->OnRenameCancelled( m_itemEdited ); + break; + + default: + event.Skip(); + } } 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("MM"), &sx, &sy); if (myPos.x + sx > parentSize.x) sx = parentSize.x - myPos.x; if (mySize.x > sx) @@ -2187,20 +2077,25 @@ void wxListTextCtrl::OnKeyUp( wxKeyEvent &event ) event.Skip(); } -void wxListTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) ) +void wxListTextCtrl::OnKillFocus( wxFocusEvent &event ) { - if (!wxPendingDelete.Member(this)) - wxPendingDelete.Append(this); - - if ((*m_accept) && ((*m_res) != m_startValue)) - m_owner->OnRenameAccept(); + if ( !m_finished ) + { + // We must finish regardless of success, otherwise we'll get focus problems + Finish(); + + if ( !AcceptChanges() ) + m_owner->OnRenameCancelled( m_itemEdited ); + } + + event.Skip(); } //----------------------------------------------------------------------------- // wxListMainWindow //----------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow,wxScrolledWindow); +IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow,wxScrolledWindow) BEGIN_EVENT_TABLE(wxListMainWindow,wxScrolledWindow) EVT_PAINT (wxListMainWindow::OnPaint) @@ -2214,7 +2109,6 @@ END_EVENT_TABLE() void wxListMainWindow::Init() { - m_columns.DeleteContents( TRUE ); m_dirty = TRUE; m_countVirt = 0; m_lineFrom = @@ -2224,8 +2118,8 @@ void wxListMainWindow::Init() m_headerWidth = m_lineHeight = 0; - m_small_image_list = (wxImageList *) NULL; - m_normal_image_list = (wxImageList *) NULL; + m_small_image_list = (wxImageListType *) NULL; + m_normal_image_list = (wxImageListType *) NULL; m_small_spacing = 30; m_normal_spacing = 40; @@ -2236,10 +2130,8 @@ void wxListMainWindow::Init() m_lastOnSame = FALSE; m_renameTimer = new wxListRenameTimer( this ); - m_renameAccept = FALSE; m_current = - m_currentEdit = m_lineLastClicked = m_lineBeforeLastClicked = (size_t)-1; @@ -2284,7 +2176,7 @@ wxListMainWindow::wxListMainWindow( wxWindow *parent, m_highlightBrush = new wxBrush ( - wxSystemSettings::GetSystemColour + wxSystemSettings::GetColour ( wxSYS_COLOUR_HIGHLIGHT ), @@ -2293,7 +2185,7 @@ wxListMainWindow::wxListMainWindow( wxWindow *parent, m_highlightUnfocusedBrush = new wxBrush ( - wxSystemSettings::GetSystemColour + wxSystemSettings::GetColour ( wxSYS_COLOUR_BTNSHADOW ), @@ -2306,12 +2198,13 @@ wxListMainWindow::wxListMainWindow( wxWindow *parent, InitScrolling(); SetScrollbars( m_xScroll, m_yScroll, 0, 0, 0, 0 ); - SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX ) ); + SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX ) ); } wxListMainWindow::~wxListMainWindow() { DoDeleteAllItems(); + WX_CLEAR_LIST(wxListHeaderDataList, m_columns); delete m_highlightBrush; delete m_highlightUnfocusedBrush; @@ -2321,7 +2214,7 @@ wxListMainWindow::~wxListMainWindow() void wxListMainWindow::CacheLineData(size_t line) { - wxListCtrl *listctrl = GetListCtrl(); + wxGenericListCtrl *listctrl = GetListCtrl(); wxListLineData *ld = GetDummyLine(); @@ -2339,15 +2232,27 @@ wxListLineData *wxListMainWindow::GetDummyLine() const { wxASSERT_MSG( !IsEmpty(), _T("invalid line index") ); - if ( m_lines.IsEmpty() ) + wxASSERT_MSG( IsVirtual(), _T("GetDummyLine() shouldn't be called") ); + + wxListMainWindow *self = wxConstCast(this, wxListMainWindow); + + // we need to recreate the dummy line if the number of columns in the + // control changed as it would have the incorrect number of fields + // otherwise + if ( !m_lines.IsEmpty() && + m_lines[0].m_items.GetCount() != (size_t)GetColumnCount() ) { - // normal controls are supposed to have something in m_lines - // already if it's not empty - wxASSERT_MSG( IsVirtual(), _T("logic error") ); + self->m_lines.Clear(); + } - wxListMainWindow *self = wxConstCast(this, wxListMainWindow); + if ( m_lines.IsEmpty() ) + { wxListLineData *line = new wxListLineData(self); self->m_lines.Add(line); + + // don't waste extra memory -- there never going to be anything + // else/more in this array + self->m_lines.Shrink(); } return &m_lines[0]; @@ -2374,8 +2279,16 @@ wxCoord wxListMainWindow::GetLineHeight() const if ( y < SCROLL_UNIT_Y ) y = SCROLL_UNIT_Y; - y += EXTRA_HEIGHT; + if ( m_small_image_list && m_small_image_list->GetImageCount() ) + { + int iw = 0; + int ih = 0; + m_small_image_list->GetSize(0, iw, ih); + y = wxMax(y, ih); + } + + y += EXTRA_HEIGHT; self->m_lineHeight = y + LINE_SPACING; } @@ -2448,7 +2361,10 @@ long wxListMainWindow::HitTestLine(size_t line, int x, int y) const if ( ld->HasImage() && GetLineIconRect(line).Inside(x, y) ) return wxLIST_HITTEST_ONITEMICON; - if ( ld->HasText() ) + // VS: Testing for "ld->HasText() || InReportView()" instead of + // "ld->HasText()" is needed to make empty lines in report view + // possible + if ( ld->HasText() || InReportView() ) { wxRect rect = InReportView() ? GetLineRect(line) : GetLineLabelRect(line); @@ -2595,22 +2511,24 @@ void wxListMainWindow::RefreshAfter( size_t lineFrom ) { if ( HasFlag(wxLC_REPORT) ) { - size_t visibleFrom; - GetVisibleLinesRange(&visibleFrom, NULL); + size_t visibleFrom, visibleTo; + GetVisibleLinesRange(&visibleFrom, &visibleTo); if ( lineFrom < visibleFrom ) lineFrom = visibleFrom; + else if ( lineFrom > visibleTo ) + return; wxRect rect; rect.x = 0; rect.y = GetLineY(lineFrom); + CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); wxSize size = GetClientSize(); rect.width = size.x; // refresh till the bottom of the window rect.height = size.y - rect.y; - CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); RefreshRect( rect ); } else // !report @@ -2636,14 +2554,6 @@ void wxListMainWindow::RefreshSelected() to = GetItemCount() - 1; } - // VZ: this code would work fine if wxGTK wxWindow::Refresh() were - // reasonable, i.e. if it only generated one expose event for - // several calls to it - as it is, each Refresh() results in a - // repaint which provokes flicker too horrible to be seen - // - // when/if wxGTK is fixed, this code should be restored as normally it - // should generate _less_ flicker than the version below -#ifndef __WXGTK__ if ( HasCurrent() && m_current >= from && m_current <= to ) { RefreshLine(m_current); @@ -2657,26 +2567,6 @@ void wxListMainWindow::RefreshSelected() RefreshLine(line); } } -#else // __WXGTK__ - size_t selMin = (size_t)-1, - selMax = 0; - - for ( size_t line = from; line <= to; line++ ) - { - if ( IsHighlighted(line) || (line == m_current) ) - { - if ( line < selMin ) - selMin = line; - if ( line > selMax ) - selMax = line; - } - } - - if ( selMin != (size_t)-1 ) - { - RefreshLines(selMin, selMax); - } -#endif // !__WXGTK__/__WXGTK__ } void wxListMainWindow::Freeze() @@ -2765,7 +2655,8 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) wxPen pen(GetRuleColour(), 1, wxSOLID); wxSize clientSize = GetClientSize(); - for ( size_t i = visibleFrom; i <= visibleTo; i++ ) + // Don't draw the first one + for ( size_t i = visibleFrom+1; i <= visibleTo; i++ ) { dc.SetPen(pen); dc.SetBrush( *wxTRANSPARENT_BRUSH ); @@ -2774,12 +2665,12 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) } // Draw last horizontal rule - if ( visibleTo > visibleFrom ) + if ( visibleTo == GetItemCount() - 1 ) { dc.SetPen(pen); dc.SetBrush( *wxTRANSPARENT_BRUSH ); - dc.DrawLine(0 - dev_x, m_lineTo*lineHeight, - clientSize.x - dev_x , m_lineTo*lineHeight ); + dc.DrawLine(0 - dev_x, (m_lineTo+1)*lineHeight, + clientSize.x - dev_x , (m_lineTo+1)*lineHeight ); } } @@ -2791,8 +2682,8 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) int col = 0; wxRect firstItemRect; wxRect lastItemRect; - GetItemRect(0, firstItemRect); - GetItemRect(GetItemCount() - 1, lastItemRect); + GetItemRect(visibleFrom, firstItemRect); + GetItemRect(visibleTo, lastItemRect); int x = firstItemRect.GetX(); dc.SetPen(pen); dc.SetBrush(* wxTRANSPARENT_BRUSH); @@ -2800,8 +2691,8 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) { int colWidth = GetColumnWidth(col); x += colWidth; - dc.DrawLine(x - dev_x, firstItemRect.GetY() - 1 - dev_y, - x - dev_x, lastItemRect.GetBottom() + 1 - dev_y); + dc.DrawLine(x - dev_x - 2, firstItemRect.GetY() - 1 - dev_y, + x - dev_x - 2, lastItemRect.GetBottom() + 1 - dev_y); } } } @@ -2892,45 +2783,29 @@ void wxListMainWindow::ChangeCurrent(size_t current) void wxListMainWindow::EditLabel( long item ) { wxCHECK_RET( (item >= 0) && ((size_t)item < GetItemCount()), - wxT("wrong index in wxListCtrl::EditLabel()") ); + wxT("wrong index in wxGenericListCtrl::EditLabel()") ); - m_currentEdit = (size_t)item; + size_t itemEdit = (size_t)item; wxListEvent le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, GetParent()->GetId() ); le.SetEventObject( GetParent() ); le.m_itemIndex = item; - wxListLineData *data = GetLine(m_currentEdit); + wxListLineData *data = GetLine(itemEdit); wxCHECK_RET( data, _T("invalid index in EditLabel()") ); data->GetItem( 0, le.m_item ); - GetParent()->GetEventHandler()->ProcessEvent( le ); - - if (!le.IsAllowed()) + if ( GetParent()->GetEventHandler()->ProcessEvent( le ) && !le.IsAllowed() ) + { + // vetoed by user code return; + } // 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) + if ( m_dirty ) wxSafeYield(); - wxClientDC dc(this); - PrepareDC( dc ); + wxListTextCtrl *text = new wxListTextCtrl(this, itemEdit); - wxString s = data->GetText(0); - wxRect rectLabel = GetLineLabelRect(m_currentEdit); - - rectLabel.x = dc.LogicalToDeviceX( rectLabel.x ); - rectLabel.y = dc.LogicalToDeviceY( rectLabel.y ); - - wxListTextCtrl *text = new wxListTextCtrl - ( - this, -1, - &m_renameAccept, - &m_renameRes, - this, - s, - wxPoint(rectLabel.x-4,rectLabel.y-4), - wxSize(rectLabel.width+11,rectLabel.height+8) - ); text->SetFocus(); } @@ -2941,28 +2816,51 @@ void wxListMainWindow::OnRenameTimer() EditLabel( m_current ); } -void wxListMainWindow::OnRenameAccept() +bool wxListMainWindow::OnRenameAccept(size_t itemEdit, const wxString& value) { wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() ); le.SetEventObject( GetParent() ); - le.m_itemIndex = m_currentEdit; + le.m_itemIndex = itemEdit; - wxListLineData *data = GetLine(m_currentEdit); - wxCHECK_RET( data, _T("invalid index in OnRenameAccept()") ); + wxListLineData *data = GetLine(itemEdit); + wxCHECK_MSG( data, FALSE, _T("invalid index in OnRenameAccept()") ); data->GetItem( 0, le.m_item ); - le.m_item.m_text = m_renameRes; - GetParent()->GetEventHandler()->ProcessEvent( le ); + le.m_item.m_text = value; + return !GetParent()->GetEventHandler()->ProcessEvent( le ) || + le.IsAllowed(); +} - if (!le.IsAllowed()) return; +#ifdef __VMS__ // Ignore unreacheable code +# pragma message disable initnotreach +#endif - wxListItem info; - info.m_mask = wxLIST_MASK_TEXT; - info.m_itemId = le.m_itemIndex; - info.m_text = m_renameRes; - info.SetTextColour(le.m_item.GetTextColour()); - SetItem( info ); +void wxListMainWindow::OnRenameCancelled(size_t itemEdit) +{ + // wxMSW seems not to notify the program about + // cancelled label edits. + return; + + // let owner know that the edit was cancelled + wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() ); + + // These only exist for wxTreeCtrl, which should probably be changed + // le.m_editCancelled = TRUE; + // le.m_label = wxEmptyString; + + le.SetEventObject( GetParent() ); + le.m_itemIndex = itemEdit; + + wxListLineData *data = GetLine(itemEdit); + wxCHECK_RET( data, _T("invalid index in OnRenameCancelled()") ); + + data->GetItem( 0, le.m_item ); + + GetEventHandler()->ProcessEvent( le ); } +#ifdef __VMS__ +# pragma message enable initnotreach +#endif void wxListMainWindow::OnMouse( wxMouseEvent &event ) { @@ -3028,6 +2926,7 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) wxListEvent le( command, GetParent()->GetId() ); le.SetEventObject( GetParent() ); + le.m_itemIndex = current; le.m_pointDrag = m_dragStart; GetParent()->GetEventHandler()->ProcessEvent( le ); @@ -3050,7 +2949,7 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) m_renameTimer->Stop(); m_lastOnSame = FALSE; - if ( current == m_lineBeforeLastClicked ) + if ( current == m_lineLastClicked ) { SendNotify( current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED ); @@ -3205,7 +3104,7 @@ void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event) ChangeCurrent(newCurrent); - HighlightLine( oldCurrent, FALSE ); + // refresh the old focus to remove it RefreshLine( oldCurrent ); if ( !event.ControlDown() ) @@ -3248,7 +3147,7 @@ void wxListMainWindow::OnChar( wxKeyEvent &event ) 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 = (int)event.KeyCode(); + le.m_code = event.GetKeyCode(); le.SetEventObject( parent ); parent->GetEventHandler()->ProcessEvent( le ); } @@ -3265,7 +3164,7 @@ void wxListMainWindow::OnChar( wxKeyEvent &event ) ke.SetEventObject( parent ); if (parent->GetEventHandler()->ProcessEvent( ke )) return; - if (event.KeyCode() == WXK_TAB) + if (event.GetKeyCode() == WXK_TAB) { wxNavigationKeyEvent nevent; nevent.SetWindowChange( event.ControlDown() ); @@ -3283,7 +3182,7 @@ void wxListMainWindow::OnChar( wxKeyEvent &event ) return; } - switch (event.KeyCode()) + switch (event.GetKeyCode()) { case WXK_UP: if ( m_current > 0 ) @@ -3400,9 +3299,25 @@ void wxListMainWindow::OnChar( wxKeyEvent &event ) // focus handling // ---------------------------------------------------------------------------- -#ifdef __WXGTK__ -extern wxWindow *g_focusWindow; -#endif +void wxListMainWindow::SetFocus() +{ + // VS: wxListMainWindow derives from wxPanel (via wxScrolledWindow) and wxPanel + // overrides SetFocus in such way that it does never change focus from + // panel's child to the panel itself. Unfortunately, we must be able to change + // focus to the panel from wxListTextCtrl because the text control should + // disappear when the user clicks outside it. + + wxWindow *oldFocus = FindFocus(); + + if ( oldFocus && oldFocus->GetParent() == this ) + { + wxWindow::SetFocus(); + } + else + { + wxScrolledWindow::SetFocus(); + } +} void wxListMainWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) ) { @@ -3420,10 +3335,6 @@ void wxListMainWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) ) if ( !GetParent() ) return; -#ifdef __WXGTK__ - g_focusWindow = GetParent(); -#endif - wxFocusEvent event( wxEVT_SET_FOCUS, GetParent()->GetId() ); event.SetEventObject( GetParent() ); GetParent()->GetEventHandler()->ProcessEvent( event ); @@ -3492,7 +3403,7 @@ int wxListMainWindow::GetTextLength( const wxString &s ) const return lw + AUTOSIZE_COL_MARGIN; } -void wxListMainWindow::SetImageList( wxImageList *imageList, int which ) +void wxListMainWindow::SetImageList( wxImageListType *imageList, int which ) { m_dirty = TRUE; @@ -3514,6 +3425,7 @@ void wxListMainWindow::SetImageList( wxImageList *imageList, int which ) { m_small_image_list = imageList; m_small_spacing = width + 14; + m_lineHeight = 0; // ensure that the line height will be recalc'd } } @@ -3541,7 +3453,7 @@ int wxListMainWindow::GetItemSpacing( bool isSmall ) void wxListMainWindow::SetColumn( int col, wxListItem &item ) { - wxListHeaderDataList::Node *node = m_columns.Item( col ); + wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); wxCHECK_RET( node, _T("invalid column index in SetColumn") ); @@ -3574,7 +3486,7 @@ void wxListMainWindow::SetColumnWidth( int col, int width ) if ( headerWin ) headerWin->m_dirty = TRUE; - wxListHeaderDataList::Node *node = m_columns.Item( col ); + wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); wxCHECK_RET( node, _T("no column?") ); wxListHeaderData *column = node->GetData(); @@ -3602,7 +3514,7 @@ void wxListMainWindow::SetColumnWidth( int col, int width ) for ( size_t i = 0; i < count; i++ ) { wxListLineData *line = GetLine(i); - wxListItemDataList::Node *n = line->m_items.Item( col ); + wxListItemDataList::compatibility_iterator n = line->m_items.Item( col ); wxCHECK_RET( n, _T("no subitem?") ); @@ -3655,7 +3567,7 @@ int wxListMainWindow::GetHeaderWidth() const void wxListMainWindow::GetColumn( int col, wxListItem &item ) const { - wxListHeaderDataList::Node *node = m_columns.Item( col ); + wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); wxCHECK_RET( node, _T("invalid column index in GetColumn") ); wxListHeaderData *column = node->GetData(); @@ -3664,7 +3576,7 @@ void wxListMainWindow::GetColumn( int col, wxListItem &item ) const int wxListMainWindow::GetColumnWidth( int col ) const { - wxListHeaderDataList::Node *node = m_columns.Item( col ); + wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); wxCHECK_MSG( node, 0, _T("invalid column index") ); wxListHeaderData *column = node->GetData(); @@ -3687,16 +3599,10 @@ void wxListMainWindow::SetItem( wxListItem &item ) line->SetItem( item.m_col, item ); } - if ( InReportView() ) - { - // just refresh the line to show the new value of the text/image - RefreshLine((size_t)id); - } - else // !report - { - // refresh everything (resulting in horrible flicker - FIXME!) - m_dirty = TRUE; - } + // update the item on screen + wxRect rectItem; + GetItemRect(id, rectItem); + RefreshRect(rectItem); } void wxListMainWindow::SetItemState( long litem, long state, long stateMask ) @@ -3737,6 +3643,14 @@ void wxListMainWindow::SetItemState( long litem, long state, long stateMask ) { ResetCurrent(); + if ( IsSingleSel() ) + { + // we must unselect the old current item as well or we + // might end up with more than one selected item in a + // single selection control + HighlightLine(oldCurrent, FALSE); + } + RefreshLine( oldCurrent ); } } @@ -3779,7 +3693,7 @@ void wxListMainWindow::SetItemState( long litem, long state, long stateMask ) } } -int wxListMainWindow::GetItemState( long item, long stateMask ) +int wxListMainWindow::GetItemState( long item, long stateMask ) const { wxCHECK_MSG( item >= 0 && (size_t)item < GetItemCount(), 0, _T("invalid list ctrl item index in GetItemState()") ); @@ -3801,7 +3715,7 @@ int wxListMainWindow::GetItemState( long item, long stateMask ) return ret; } -void wxListMainWindow::GetItem( wxListItem &item ) +void wxListMainWindow::GetItem( wxListItem &item ) const { wxCHECK_RET( item.m_itemId >= 0 && (size_t)item.m_itemId < GetItemCount(), _T("invalid item index in GetItem") ); @@ -3830,7 +3744,7 @@ void wxListMainWindow::SetItemCount(long count) m_dirty = TRUE; } -int wxListMainWindow::GetSelectedItemCount() +int wxListMainWindow::GetSelectedItemCount() const { // deal with the quick case first if ( IsSingleSel() ) @@ -3859,7 +3773,7 @@ int wxListMainWindow::GetSelectedItemCount() // item position/size // ---------------------------------------------------------------------------- -void wxListMainWindow::GetItemRect( long index, wxRect &rect ) +void wxListMainWindow::GetItemRect( long index, wxRect &rect ) const { wxCHECK_RET( index >= 0 && (size_t)index < GetItemCount(), _T("invalid index in GetItemRect") ); @@ -3869,7 +3783,7 @@ void wxListMainWindow::GetItemRect( long index, wxRect &rect ) CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y); } -bool wxListMainWindow::GetItemPosition(long item, wxPoint& pos) +bool wxListMainWindow::GetItemPosition(long item, wxPoint& pos) const { wxRect rect; GetItemRect(item, rect); @@ -3897,9 +3811,25 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh) 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) ) { @@ -3917,7 +3847,7 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh) ResetVisibleLinesRange(); SetScrollbars( m_xScroll, m_yScroll, - (GetHeaderWidth() + m_xScroll - 1)/m_xScroll, + GetHeaderWidth() / m_xScroll, (entireHeight + m_yScroll - 1)/m_yScroll, GetScrollPos(wxHORIZONTAL), GetScrollPos(wxVERTICAL), @@ -3929,13 +3859,26 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh) // 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; @@ -3948,7 +3891,7 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh) 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); @@ -3959,8 +3902,8 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh) 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; @@ -3968,17 +3911,21 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh) 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. } } @@ -4018,7 +3965,7 @@ void wxListMainWindow::UpdateCurrent() long wxListMainWindow::GetNextItem( long item, int WXUNUSED(geometry), - int state ) + int state ) const { long ret = item, max = GetItemCount(); @@ -4106,12 +4053,28 @@ void wxListMainWindow::DeleteItem( long lindex ) void wxListMainWindow::DeleteColumn( int col ) { - wxListHeaderDataList::Node *node = m_columns.Item( col ); + wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); wxCHECK_RET( node, wxT("invalid column index in DeleteColumn()") ); m_dirty = TRUE; - m_columns.DeleteNode( node ); + delete node->GetData(); + m_columns.Erase( node ); + + if ( !IsVirtual() ) + { + // update all the items + for ( size_t i = 0; i < m_lines.GetCount(); i++ ) + { + wxListLineData * const line = GetLine(i); + wxListItemDataList::compatibility_iterator n = line->m_items.Item( col ); + delete n->GetData(); + line->m_items.Erase(n); + } + } + + // invalidate it as it has to be recalculated + m_headerWidth = 0; } void wxListMainWindow::DoDeleteAllItems() @@ -4157,9 +4120,9 @@ void wxListMainWindow::DeleteAllItems() void wxListMainWindow::DeleteEverything() { - DeleteAllItems(); + WX_CLEAR_LIST(wxListHeaderDataList, m_columns); - m_columns.Clear(); + DeleteAllItems(); } // ---------------------------------------------------------------------------- @@ -4267,7 +4230,10 @@ void wxListMainWindow::InsertItem( wxListItem &item ) int mode = 0; if ( HasFlag(wxLC_REPORT) ) + { mode = wxLC_REPORT; + ResetVisibleLinesRange(); + } else if ( HasFlag(wxLC_LIST) ) mode = wxLC_LIST; else if ( HasFlag(wxLC_ICON) ) @@ -4286,6 +4252,9 @@ void wxListMainWindow::InsertItem( wxListItem &item ) m_lines.Insert( line, id ); m_dirty = TRUE; + + SendNotify(id, wxEVT_COMMAND_LIST_INSERT_ITEM); + RefreshLines(id, GetItemCount() - 1); } @@ -4296,16 +4265,35 @@ void wxListMainWindow::InsertColumn( long col, wxListItem &item ) { if (item.m_width == wxLIST_AUTOSIZE_USEHEADER) item.m_width = GetTextLength( item.m_text ); + wxListHeaderData *column = new wxListHeaderData( item ); - if ((col >= 0) && (col < (int)m_columns.GetCount())) + bool insert = (col >= 0) && ((size_t)col < m_columns.GetCount()); + if ( insert ) { - wxListHeaderDataList::Node *node = m_columns.Item( col ); + wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); m_columns.Insert( node, column ); } else { m_columns.Append( column ); } + + if ( !IsVirtual() ) + { + // update all the items + for ( size_t i = 0; i < m_lines.GetCount(); i++ ) + { + wxListLineData * const line = GetLine(i); + wxListItemData * const data = new wxListItemData(this); + if ( insert ) + line->m_items.Insert(col, data); + else + line->m_items.Append(data); + } + } + + // invalidate it as it has to be recalculated + m_headerWidth = 0; } } @@ -4355,13 +4343,11 @@ void wxListMainWindow::OnScroll(wxScrollWinEvent& event) if ( event.GetOrientation() == wxHORIZONTAL && HasHeader() ) { - wxListCtrl* lc = GetListCtrl(); + wxGenericListCtrl* lc = GetListCtrl(); wxCHECK_RET( lc, _T("no listctrl window?") ); - lc->m_headerWin->Refresh() ; -#ifdef __WXMAC__ - lc->m_headerWin->MacUpdateImmediately() ; -#endif + lc->m_headerWin->Refresh(); + lc->m_headerWin->Update(); } } @@ -4415,62 +4401,20 @@ void wxListMainWindow::GetVisibleLinesRange(size_t *from, size_t *to) } // ------------------------------------------------------------------------------------- -// wxListItem +// wxGenericListCtrl // ------------------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxGenericListCtrl, wxControl) -wxListItem::wxListItem() -{ - m_attr = NULL; - - Clear(); -} - -void wxListItem::Clear() -{ - m_mask = 0; - m_itemId = 0; - m_col = 0; - m_state = 0; - m_stateMask = 0; - m_image = -1; - m_data = 0; - m_format = wxLIST_FORMAT_CENTRE; - m_width = 0; - m_text.clear(); - - ClearAttributes(); -} - -void wxListItem::ClearAttributes() -{ - if (m_attr) - { - delete m_attr; - m_attr = NULL; - } -} - -// ------------------------------------------------------------------------------------- -// 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) +BEGIN_EVENT_TABLE(wxGenericListCtrl,wxControl) + EVT_SIZE(wxGenericListCtrl::OnSize) END_EVENT_TABLE() -wxListCtrl::wxListCtrl() +wxGenericListCtrl::wxGenericListCtrl() { - m_imageListNormal = (wxImageList *) NULL; - m_imageListSmall = (wxImageList *) NULL; - m_imageListState = (wxImageList *) NULL; + m_imageListNormal = (wxImageListType *) NULL; + m_imageListSmall = (wxImageListType *) NULL; + m_imageListState = (wxImageListType *) NULL; m_ownsImageListNormal = m_ownsImageListSmall = @@ -4480,7 +4424,7 @@ wxListCtrl::wxListCtrl() m_headerWin = (wxListHeaderWindow*) NULL; } -wxListCtrl::~wxListCtrl() +wxGenericListCtrl::~wxGenericListCtrl() { if (m_ownsImageListNormal) delete m_imageListNormal; @@ -4490,7 +4434,7 @@ wxListCtrl::~wxListCtrl() delete m_imageListState; } -void wxListCtrl::CreateHeaderWindow() +void wxGenericListCtrl::CreateHeaderWindow() { m_headerWin = new wxListHeaderWindow ( @@ -4501,7 +4445,7 @@ void wxListCtrl::CreateHeaderWindow() ); } -bool wxListCtrl::Create(wxWindow *parent, +bool wxGenericListCtrl::Create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, @@ -4511,7 +4455,7 @@ bool wxListCtrl::Create(wxWindow *parent, { m_imageListNormal = m_imageListSmall = - m_imageListState = (wxImageList *) NULL; + m_imageListState = (wxImageListType *) NULL; m_ownsImageListNormal = m_ownsImageListSmall = m_ownsImageListState = FALSE; @@ -4528,7 +4472,7 @@ bool wxListCtrl::Create(wxWindow *parent, return FALSE; // don't create the inner window with the border - style &= ~wxSUNKEN_BORDER; + style &= ~wxBORDER_MASK; m_mainWin = new wxListMainWindow( this, -1, wxPoint(0,0), size, style ); @@ -4546,7 +4490,7 @@ bool wxListCtrl::Create(wxWindow *parent, return TRUE; } -void wxListCtrl::SetSingleStyle( long style, bool add ) +void wxGenericListCtrl::SetSingleStyle( long style, bool add ) { wxASSERT_MSG( !(style & wxLC_VIRTUAL), _T("wxLC_VIRTUAL can't be [un]set") ); @@ -4575,7 +4519,7 @@ void wxListCtrl::SetSingleStyle( long style, bool add ) SetWindowStyleFlag( flag ); } -void wxListCtrl::SetWindowStyleFlag( long flag ) +void wxGenericListCtrl::SetWindowStyleFlag( long flag ) { if (m_mainWin) { @@ -4616,47 +4560,47 @@ void wxListCtrl::SetWindowStyleFlag( long flag ) wxWindow::SetWindowStyleFlag( flag ); } -bool wxListCtrl::GetColumn(int col, wxListItem &item) const +bool wxGenericListCtrl::GetColumn(int col, wxListItem &item) const { m_mainWin->GetColumn( col, item ); return TRUE; } -bool wxListCtrl::SetColumn( int col, wxListItem& item ) +bool wxGenericListCtrl::SetColumn( int col, wxListItem& item ) { m_mainWin->SetColumn( col, item ); return TRUE; } -int wxListCtrl::GetColumnWidth( int col ) const +int wxGenericListCtrl::GetColumnWidth( int col ) const { return m_mainWin->GetColumnWidth( col ); } -bool wxListCtrl::SetColumnWidth( int col, int width ) +bool wxGenericListCtrl::SetColumnWidth( int col, int width ) { m_mainWin->SetColumnWidth( col, width ); return TRUE; } -int wxListCtrl::GetCountPerPage() const +int wxGenericListCtrl::GetCountPerPage() const { return m_mainWin->GetCountPerPage(); // different from Windows ? } -bool wxListCtrl::GetItem( wxListItem &info ) const +bool wxGenericListCtrl::GetItem( wxListItem &info ) const { m_mainWin->GetItem( info ); return TRUE; } -bool wxListCtrl::SetItem( wxListItem &info ) +bool wxGenericListCtrl::SetItem( wxListItem &info ) { m_mainWin->SetItem( info ); return TRUE; } -long wxListCtrl::SetItem( long index, int col, const wxString& label, int imageId ) +long wxGenericListCtrl::SetItem( long index, int col, const wxString& label, int imageId ) { wxListItem info; info.m_text = label; @@ -4672,18 +4616,18 @@ long wxListCtrl::SetItem( long index, int col, const wxString& label, int imageI return TRUE; } -int wxListCtrl::GetItemState( long item, long stateMask ) const +int wxGenericListCtrl::GetItemState( long item, long stateMask ) const { return m_mainWin->GetItemState( item, stateMask ); } -bool wxListCtrl::SetItemState( long item, long state, long stateMask ) +bool wxGenericListCtrl::SetItemState( long item, long state, long stateMask ) { m_mainWin->SetItemState( item, state, stateMask ); return TRUE; } -bool wxListCtrl::SetItemImage( long item, int image, int WXUNUSED(selImage) ) +bool wxGenericListCtrl::SetItemImage( long item, int image, int WXUNUSED(selImage) ) { wxListItem info; info.m_image = image; @@ -4693,24 +4637,17 @@ bool wxListCtrl::SetItemImage( long item, int image, int WXUNUSED(selImage) ) return TRUE; } -wxString wxListCtrl::GetItemText( long item ) const +wxString wxGenericListCtrl::GetItemText( long item ) const { - wxListItem info; - info.m_itemId = item; - m_mainWin->GetItem( info ); - return info.m_text; + return m_mainWin->GetItemText(item); } -void wxListCtrl::SetItemText( long item, const wxString &str ) +void wxGenericListCtrl::SetItemText( long item, const wxString& str ) { - wxListItem info; - info.m_mask = wxLIST_MASK_TEXT; - info.m_itemId = item; - info.m_text = str; - m_mainWin->SetItem( info ); + m_mainWin->SetItemText(item, str); } -long wxListCtrl::GetItemData( long item ) const +long wxGenericListCtrl::GetItemData( long item ) const { wxListItem info; info.m_itemId = item; @@ -4718,7 +4655,7 @@ long wxListCtrl::GetItemData( long item ) const return info.m_data; } -bool wxListCtrl::SetItemData( long item, long data ) +bool wxGenericListCtrl::SetItemData( long item, long data ) { wxListItem info; info.m_mask = wxLIST_MASK_DATA; @@ -4728,69 +4665,105 @@ bool wxListCtrl::SetItemData( long item, long data ) return TRUE; } -bool wxListCtrl::GetItemRect( long item, wxRect &rect, int WXUNUSED(code) ) const +bool wxGenericListCtrl::GetItemRect( long item, wxRect &rect, int WXUNUSED(code) ) const { m_mainWin->GetItemRect( item, rect ); + if ( m_mainWin->HasHeader() ) + rect.y += HEADER_HEIGHT + 1; return TRUE; } -bool wxListCtrl::GetItemPosition( long item, wxPoint& pos ) const +bool wxGenericListCtrl::GetItemPosition( long item, wxPoint& pos ) const { m_mainWin->GetItemPosition( item, pos ); return TRUE; } -bool wxListCtrl::SetItemPosition( long WXUNUSED(item), const wxPoint& WXUNUSED(pos) ) +bool wxGenericListCtrl::SetItemPosition( long WXUNUSED(item), const wxPoint& WXUNUSED(pos) ) { return 0; } -int wxListCtrl::GetItemCount() const +int wxGenericListCtrl::GetItemCount() const { return m_mainWin->GetItemCount(); } -int wxListCtrl::GetColumnCount() const +int wxGenericListCtrl::GetColumnCount() const { return m_mainWin->GetColumnCount(); } -void wxListCtrl::SetItemSpacing( int spacing, bool isSmall ) +void wxGenericListCtrl::SetItemSpacing( int spacing, bool isSmall ) { m_mainWin->SetItemSpacing( spacing, isSmall ); } -int wxListCtrl::GetItemSpacing( bool isSmall ) const +int wxGenericListCtrl::GetItemSpacing( bool isSmall ) const { return m_mainWin->GetItemSpacing( isSmall ); } -int wxListCtrl::GetSelectedItemCount() const +void wxGenericListCtrl::SetItemTextColour( long item, const wxColour &col ) +{ + wxListItem info; + info.m_itemId = item; + info.SetTextColour( col ); + m_mainWin->SetItem( info ); +} + +wxColour wxGenericListCtrl::GetItemTextColour( long item ) const +{ + wxListItem info; + info.m_itemId = item; + m_mainWin->GetItem( info ); + return info.GetTextColour(); +} + +void wxGenericListCtrl::SetItemBackgroundColour( long item, const wxColour &col ) +{ + wxListItem info; + info.m_itemId = item; + info.SetBackgroundColour( col ); + m_mainWin->SetItem( info ); +} + +wxColour wxGenericListCtrl::GetItemBackgroundColour( long item ) const +{ + wxListItem info; + info.m_itemId = item; + m_mainWin->GetItem( info ); + return info.GetBackgroundColour(); +} + +int wxGenericListCtrl::GetSelectedItemCount() const { return m_mainWin->GetSelectedItemCount(); } -wxColour wxListCtrl::GetTextColour() const +wxColour wxGenericListCtrl::GetTextColour() const { return GetForegroundColour(); } -void wxListCtrl::SetTextColour(const wxColour& col) +void wxGenericListCtrl::SetTextColour(const wxColour& col) { SetForegroundColour(col); } -long wxListCtrl::GetTopItem() const +long wxGenericListCtrl::GetTopItem() const { - return 0; + size_t top; + m_mainWin->GetVisibleLinesRange(&top, NULL); + return (long)top; } -long wxListCtrl::GetNextItem( long item, int geom, int state ) const +long wxGenericListCtrl::GetNextItem( long item, int geom, int state ) const { return m_mainWin->GetNextItem( item, geom, state ); } -wxImageList *wxListCtrl::GetImageList(int which) const +wxImageListType *wxGenericListCtrl::GetImageList(int which) const { if (which == wxIMAGE_LIST_NORMAL) { @@ -4804,10 +4777,10 @@ wxImageList *wxListCtrl::GetImageList(int which) const { return m_imageListState; } - return (wxImageList *) NULL; + return (wxImageListType *) NULL; } -void wxListCtrl::SetImageList( wxImageList *imageList, int which ) +void wxGenericListCtrl::SetImageList( wxImageListType *imageList, int which ) { if ( which == wxIMAGE_LIST_NORMAL ) { @@ -4831,7 +4804,7 @@ void wxListCtrl::SetImageList( wxImageList *imageList, int which ) m_mainWin->SetImageList( imageList, which ); } -void wxListCtrl::AssignImageList(wxImageList *imageList, int which) +void wxGenericListCtrl::AssignImageList(wxImageListType *imageList, int which) { SetImageList(imageList, which); if ( which == wxIMAGE_LIST_NORMAL ) @@ -4842,24 +4815,24 @@ void wxListCtrl::AssignImageList(wxImageList *imageList, int which) m_ownsImageListState = TRUE; } -bool wxListCtrl::Arrange( int WXUNUSED(flag) ) +bool wxGenericListCtrl::Arrange( int WXUNUSED(flag) ) { return 0; } -bool wxListCtrl::DeleteItem( long item ) +bool wxGenericListCtrl::DeleteItem( long item ) { m_mainWin->DeleteItem( item ); return TRUE; } -bool wxListCtrl::DeleteAllItems() +bool wxGenericListCtrl::DeleteAllItems() { m_mainWin->DeleteAllItems(); return TRUE; } -bool wxListCtrl::DeleteAllColumns() +bool wxGenericListCtrl::DeleteAllColumns() { size_t count = m_mainWin->m_columns.GetCount(); for ( size_t n = 0; n < count; n++ ) @@ -4868,56 +4841,63 @@ bool wxListCtrl::DeleteAllColumns() return TRUE; } -void wxListCtrl::ClearAll() +void wxGenericListCtrl::ClearAll() { m_mainWin->DeleteEverything(); } -bool wxListCtrl::DeleteColumn( int col ) +bool wxGenericListCtrl::DeleteColumn( int col ) { m_mainWin->DeleteColumn( col ); + + // if we don't have the header any longer, we need to relayout the window + if ( !GetColumnCount() ) + { + ResizeReportView(FALSE /* no header */); + } + return TRUE; } -void wxListCtrl::Edit( long item ) +void wxGenericListCtrl::Edit( long item ) { m_mainWin->EditLabel( item ); } -bool wxListCtrl::EnsureVisible( long item ) +bool wxGenericListCtrl::EnsureVisible( long item ) { m_mainWin->EnsureVisible( item ); return TRUE; } -long wxListCtrl::FindItem( long start, const wxString& str, bool partial ) +long wxGenericListCtrl::FindItem( long start, const wxString& str, bool partial ) { return m_mainWin->FindItem( start, str, partial ); } -long wxListCtrl::FindItem( long start, long data ) +long wxGenericListCtrl::FindItem( long start, long data ) { return m_mainWin->FindItem( start, data ); } -long wxListCtrl::FindItem( long WXUNUSED(start), const wxPoint& WXUNUSED(pt), +long wxGenericListCtrl::FindItem( long WXUNUSED(start), const wxPoint& WXUNUSED(pt), int WXUNUSED(direction)) { return 0; } -long wxListCtrl::HitTest( const wxPoint &point, int &flags ) +long wxGenericListCtrl::HitTest( const wxPoint &point, int &flags ) { return m_mainWin->HitTest( (int)point.x, (int)point.y, flags ); } -long wxListCtrl::InsertItem( wxListItem& info ) +long wxGenericListCtrl::InsertItem( wxListItem& info ) { m_mainWin->InsertItem( info ); return info.m_itemId; } -long wxListCtrl::InsertItem( long index, const wxString &label ) +long wxGenericListCtrl::InsertItem( long index, const wxString &label ) { wxListItem info; info.m_text = label; @@ -4926,7 +4906,7 @@ long wxListCtrl::InsertItem( long index, const wxString &label ) return InsertItem( info ); } -long wxListCtrl::InsertItem( long index, int imageIndex ) +long wxGenericListCtrl::InsertItem( long index, int imageIndex ) { wxListItem info; info.m_mask = wxLIST_MASK_IMAGE; @@ -4935,7 +4915,7 @@ long wxListCtrl::InsertItem( long index, int imageIndex ) return InsertItem( info ); } -long wxListCtrl::InsertItem( long index, const wxString &label, int imageIndex ) +long wxGenericListCtrl::InsertItem( long index, const wxString &label, int imageIndex ) { wxListItem info; info.m_text = label; @@ -4945,16 +4925,25 @@ long wxListCtrl::InsertItem( long index, const wxString &label, int imageIndex ) return InsertItem( info ); } -long wxListCtrl::InsertColumn( long col, wxListItem &item ) +long wxGenericListCtrl::InsertColumn( long col, wxListItem &item ) { - wxASSERT( m_headerWin ); + wxCHECK_MSG( m_headerWin, -1, _T("can't add column in non report mode") ); + m_mainWin->InsertColumn( col, item ); + + // if we hadn't had header before and have it now we need to relayout the + // window + if ( GetColumnCount() == 1 && m_mainWin->HasHeader() ) + { + ResizeReportView(TRUE /* have header */); + } + m_headerWin->Refresh(); return 0; } -long wxListCtrl::InsertColumn( long col, const wxString &heading, +long wxGenericListCtrl::InsertColumn( long col, const wxString &heading, int format, int width ) { wxListItem item; @@ -4970,7 +4959,7 @@ long wxListCtrl::InsertColumn( long col, const wxString &heading, return InsertColumn( col, item ); } -bool wxListCtrl::ScrollList( int WXUNUSED(dx), int WXUNUSED(dy) ) +bool wxGenericListCtrl::ScrollList( int WXUNUSED(dx), int WXUNUSED(dy) ) { return 0; } @@ -4985,7 +4974,7 @@ bool wxListCtrl::ScrollList( int WXUNUSED(dx), int WXUNUSED(dy) ) // or zero if the two items are equivalent. // data is arbitrary data to be passed to the sort function. -bool wxListCtrl::SortItems( wxListCtrlCompare fn, long data ) +bool wxGenericListCtrl::SortItems( wxListCtrlCompare fn, long data ) { m_mainWin->SortItems( fn, data ); return TRUE; @@ -4995,7 +4984,7 @@ bool wxListCtrl::SortItems( wxListCtrlCompare fn, long data ) // event handlers // ---------------------------------------------------------------------------- -void wxListCtrl::OnSize(wxSizeEvent& event) +void wxGenericListCtrl::OnSize(wxSizeEvent& WXUNUSED(event)) { if ( !m_mainWin ) return; @@ -5005,7 +4994,7 @@ void wxListCtrl::OnSize(wxSizeEvent& event) m_mainWin->RecalculatePositions(); } -void wxListCtrl::ResizeReportView(bool showHeader) +void wxGenericListCtrl::ResizeReportView(bool showHeader) { int cw, ch; GetClientSize( &cw, &ch ); @@ -5021,10 +5010,10 @@ void wxListCtrl::ResizeReportView(bool showHeader) } } -void wxListCtrl::OnIdle( wxIdleEvent & event ) +void wxGenericListCtrl::OnInternalIdle() { - event.Skip(); - + wxWindow::OnInternalIdle(); + // do it only if needed if ( !m_mainWin->m_dirty ) return; @@ -5036,7 +5025,7 @@ void wxListCtrl::OnIdle( wxIdleEvent & event ) // font/colours // ---------------------------------------------------------------------------- -bool wxListCtrl::SetBackgroundColour( const wxColour &colour ) +bool wxGenericListCtrl::SetBackgroundColour( const wxColour &colour ) { if (m_mainWin) { @@ -5047,7 +5036,7 @@ bool wxListCtrl::SetBackgroundColour( const wxColour &colour ) return TRUE; } -bool wxListCtrl::SetForegroundColour( const wxColour &colour ) +bool wxGenericListCtrl::SetForegroundColour( const wxColour &colour ) { if ( !wxWindow::SetForegroundColour( colour ) ) return FALSE; @@ -5066,7 +5055,7 @@ bool wxListCtrl::SetForegroundColour( const wxColour &colour ) return TRUE; } -bool wxListCtrl::SetFont( const wxFont &font ) +bool wxGenericListCtrl::SetFont( const wxFont &font ) { if ( !wxWindow::SetFont( font ) ) return FALSE; @@ -5091,34 +5080,34 @@ bool wxListCtrl::SetFont( const wxFont &font ) #if wxUSE_DRAG_AND_DROP -void wxListCtrl::SetDropTarget( wxDropTarget *dropTarget ) +void wxGenericListCtrl::SetDropTarget( wxDropTarget *dropTarget ) { m_mainWin->SetDropTarget( dropTarget ); } -wxDropTarget *wxListCtrl::GetDropTarget() const +wxDropTarget *wxGenericListCtrl::GetDropTarget() const { return m_mainWin->GetDropTarget(); } #endif // wxUSE_DRAG_AND_DROP -bool wxListCtrl::SetCursor( const wxCursor &cursor ) +bool wxGenericListCtrl::SetCursor( const wxCursor &cursor ) { return m_mainWin ? m_mainWin->wxWindow::SetCursor(cursor) : FALSE; } -wxColour wxListCtrl::GetBackgroundColour() const +wxColour wxGenericListCtrl::GetBackgroundColour() const { return m_mainWin ? m_mainWin->GetBackgroundColour() : wxColour(); } -wxColour wxListCtrl::GetForegroundColour() const +wxColour wxGenericListCtrl::GetForegroundColour() const { return m_mainWin ? m_mainWin->GetForegroundColour() : wxColour(); } -bool wxListCtrl::DoPopupMenu( wxMenu *menu, int x, int y ) +bool wxGenericListCtrl::DoPopupMenu( wxMenu *menu, int x, int y ) { #if wxUSE_MENUS return m_mainWin->PopupMenu( menu, x, y ); @@ -5127,7 +5116,7 @@ bool wxListCtrl::DoPopupMenu( wxMenu *menu, int x, int y ) #endif // wxUSE_MENUS } -void wxListCtrl::SetFocus() +void wxGenericListCtrl::SetFocus() { /* The test in window.cpp fails as we are a composite window, so it checks against "this", but not m_mainWin. */ @@ -5139,24 +5128,24 @@ void wxListCtrl::SetFocus() // virtual list control support // ---------------------------------------------------------------------------- -wxString wxListCtrl::OnGetItemText(long item, long col) const +wxString wxGenericListCtrl::OnGetItemText(long WXUNUSED(item), long WXUNUSED(col)) const { // this is a pure virtual function, in fact - which is not really pure // because the controls which are not virtual don't need to implement it - wxFAIL_MSG( _T("not supposed to be called") ); + wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemText not supposed to be called") ); return wxEmptyString; } -int wxListCtrl::OnGetItemImage(long item) const +int wxGenericListCtrl::OnGetItemImage(long WXUNUSED(item)) const { // same as above - wxFAIL_MSG( _T("not supposed to be called") ); + wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemImage not supposed to be called") ); return -1; } -wxListItemAttr *wxListCtrl::OnGetItemAttr(long item) const +wxListItemAttr *wxGenericListCtrl::OnGetItemAttr(long item) const { wxASSERT_MSG( item >= 0 && item < GetItemCount(), _T("invalid item index in OnGetItemAttr()") ); @@ -5165,31 +5154,83 @@ wxListItemAttr *wxListCtrl::OnGetItemAttr(long item) const return NULL; } -void wxListCtrl::SetItemCount(long count) +void wxGenericListCtrl::SetItemCount(long count) { wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") ); m_mainWin->SetItemCount(count); } -void wxListCtrl::RefreshItem(long item) +void wxGenericListCtrl::RefreshItem(long item) { m_mainWin->RefreshLine(item); } -void wxListCtrl::RefreshItems(long itemFrom, long itemTo) +void wxGenericListCtrl::RefreshItems(long itemFrom, long itemTo) { m_mainWin->RefreshLines(itemFrom, itemTo); } -void wxListCtrl::Freeze() +/* + * Generic wxListCtrl is more or less a container for two other + * windows which drawings are done upon. These are namely + * 'm_headerWin' and 'm_mainWin'. + * Here we override 'virtual wxWindow::Refresh()' to mimic the + * behaviour wxListCtrl has under wxMSW. + */ +void wxGenericListCtrl::Refresh(bool eraseBackground, const wxRect *rect) +{ + if (!rect) + { + // The easy case, no rectangle specified. + if (m_headerWin) + m_headerWin->Refresh(eraseBackground); + + if (m_mainWin) + m_mainWin->Refresh(eraseBackground); + } + else + { + // Refresh the header window + if (m_headerWin) + { + wxRect rectHeader = m_headerWin->GetRect(); + rectHeader.Intersect(*rect); + if (rectHeader.GetWidth() && rectHeader.GetHeight()) + { + int x, y; + m_headerWin->GetPosition(&x, &y); + rectHeader.Offset(-x, -y); + m_headerWin->Refresh(eraseBackground, &rectHeader); + } + + } + + // Refresh the main window + if (m_mainWin) + { + wxRect rectMain = m_mainWin->GetRect(); + rectMain.Intersect(*rect); + if (rectMain.GetWidth() && rectMain.GetHeight()) + { + int x, y; + m_mainWin->GetPosition(&x, &y); + rectMain.Offset(-x, -y); + m_mainWin->Refresh(eraseBackground, &rectMain); + } + } + } +} + +void wxGenericListCtrl::Freeze() { m_mainWin->Freeze(); } -void wxListCtrl::Thaw() +void wxGenericListCtrl::Thaw() { m_mainWin->Thaw(); } #endif // wxUSE_LISTCTRL +