+#include "wx/imaglist.h"
+#include "wx/dynarray.h"
+
+#ifdef __WXGTK__
+#include <gtk/gtk.h>
+#include "wx/gtk/win_gtk.h"
+#endif
+
+// ----------------------------------------------------------------------------
+// events
+// ----------------------------------------------------------------------------
+
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK)
+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_CACHE_HINT)
+
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
+
+// the height of the header window (FIXME: should depend on its font!)
+static const int HEADER_HEIGHT = 23;
+
+// the scrollbar units
+static const int SCROLL_UNIT_X = 15;
+static const int SCROLL_UNIT_Y = 15;
+
+// the spacing between the lines (in report mode)
+static const int LINE_SPACING = 0;
+
+// extra margins around the text label
+static const int EXTRA_WIDTH = 3;
+static const int EXTRA_HEIGHT = 4;
+
+// offset for the header window
+static const int HEADER_OFFSET_X = 1;
+static const int HEADER_OFFSET_Y = 1;
+
+// when autosizing the columns, add some slack
+static const int AUTOSIZE_COL_MARGIN = 10;
+
+// default and minimal widths for the header columns
+static const int WIDTH_COL_DEFAULT = 80;
+static const int WIDTH_COL_MIN = 10;
+
+// ============================================================================
+// 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)
+//-----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxListItemData
+{
+public:
+ wxListItemData(wxListMainWindow *owner);
+ ~wxListItemData();
+
+ void SetItem( const wxListItem &info );
+ void SetImage( int image ) { m_image = image; }
+ void SetData( long data ) { m_data = data; }
+ void SetPosition( int x, int y );
+ void SetSize( int width, int height );
+
+ bool HasText() const { return !m_text.empty(); }
+ const wxString& GetText() const { return m_text; }
+ void SetText(const wxString& text) { m_text = text; }
+
+ // we can't use empty string for measuring the string width/height, so
+ // always return something
+ wxString GetTextForMeasuring() const
+ {
+ wxString s = GetText();
+ if ( s.empty() )
+ s = _T('H');
+
+ return s;
+ }
+
+ bool IsHit( int x, int y ) const;
+
+ int GetX() const;
+ int GetY() const;
+ int GetWidth() const;
+ int GetHeight() const;
+
+ int GetImage() const { return m_image; }
+ bool HasImage() const { return GetImage() != -1; }
+
+ void GetItem( wxListItem &info ) const;
+
+ void SetAttr(wxListItemAttr *attr) { m_attr = attr; }
+ wxListItemAttr *GetAttr() const { return m_attr; }
+
+public:
+ // the item image or -1
+ int m_image;
+
+ // user data associated with the item
+ long m_data;
+
+ // the item coordinates are not used in report mode, instead this pointer
+ // is NULL and the owner window is used to retrieve the item position and
+ // size
+ wxRect *m_rect;
+
+ // the list ctrl we are in
+ wxListMainWindow *m_owner;
+
+ // custom attributes or NULL
+ wxListItemAttr *m_attr;
+
+protected:
+ // common part of all ctors
+ void Init();
+
+ wxString m_text;
+};
+
+//-----------------------------------------------------------------------------
+// wxListHeaderData (internal)
+//-----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxListHeaderData : public wxObject
+{
+protected:
+ long m_mask;
+ int m_image;
+ wxString m_text;
+ int m_format;
+ int m_width;
+ int m_xpos,
+ m_ypos;
+ int m_height;
+
+public:
+ wxListHeaderData();
+ wxListHeaderData( const wxListItem &info );
+ void SetItem( const wxListItem &item );
+ void SetPosition( int x, int y );
+ void SetWidth( int w );
+ void SetFormat( int format );
+ void SetHeight( int h );
+ bool HasImage() const;
+
+ bool HasText() const { return !m_text.empty(); }
+ const wxString& GetText() const { return m_text; }
+ void SetText(const wxString& text) { m_text = text; }
+
+ void GetItem( wxListItem &item );
+
+ bool IsHit( int x, int y ) const;
+ int GetImage() const;
+ int GetWidth() const;
+ int GetFormat() const;
+
+private:
+ DECLARE_DYNAMIC_CLASS(wxListHeaderData);
+};
+
+//-----------------------------------------------------------------------------
+// wxListLineData (internal)
+//-----------------------------------------------------------------------------
+
+WX_DECLARE_LIST(wxListItemData, wxListItemDataList);
+#include "wx/listimpl.cpp"
+WX_DEFINE_LIST(wxListItemDataList);
+
+class WXDLLEXPORT wxListLineData
+{
+public:
+ // the list of subitems: only may have more than one item in report mode
+ wxListItemDataList m_items;
+
+ // this is not used in report view
+ struct GeometryInfo
+ {
+ // total item rect
+ wxRect m_rectAll;
+
+ // label only
+ wxRect m_rectLabel;
+
+ // icon only
+ wxRect m_rectIcon;
+
+ // the part to be highlighted
+ wxRect m_rectHighlight;
+ } *m_gi;
+
+ // is this item selected? [NB: not used in virtual mode]
+ bool m_highlighted;
+
+ // back pointer to the list ctrl
+ wxListMainWindow *m_owner;
+
+public:
+ wxListLineData(wxListMainWindow *owner);
+
+ ~wxListLineData() { delete m_gi; }
+
+ // are we in report mode?
+ inline bool InReportView() const;
+
+ // are we in virtual report mode?
+ inline bool IsVirtual() const;
+
+ // these 2 methods shouldn't be called for report view controls, in that
+ // case we determine our position/size ourselves
+
+ // calculate the size of the line
+ void CalculateSize( wxDC *dc, int spacing );
+
+ // remember the position this line appears at
+ void SetPosition( int x, int y, int window_width, int spacing );
+
+ // wxListCtrl API
+
+ void SetImage( int image ) { SetImage(0, image); }
+ int GetImage() const { return GetImage(0); }
+ bool HasImage() const { return GetImage() != -1; }
+ bool HasText() const { return !GetText(0).empty(); }
+
+ void SetItem( int index, const wxListItem &info );
+ void GetItem( int index, wxListItem &info );
+
+ wxString GetText(int index) const;
+ void SetText( int index, const wxString s );
+
+ wxListItemAttr *GetAttr() const;
+ void SetAttr(wxListItemAttr *attr);
+
+ // return true if the highlighting really changed
+ bool Highlight( bool on );
+
+ void ReverseHighlight();
+
+ bool IsHighlighted() const
+ {
+ wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") );
+
+ return m_highlighted;
+ }
+
+ // draw the line on the given DC in icon/list mode
+ void Draw( wxDC *dc );
+
+ // the same in report mode
+ void DrawInReportMode( wxDC *dc,
+ const wxRect& rect,
+ const wxRect& rectHL,
+ bool highlighted );
+
+private:
+ // set the line to contain num items (only can be > 1 in report mode)
+ void InitItems( int num );
+
+ // get the mode (i.e. style) of the list control
+ inline int GetMode() const;
+
+ // prepare the DC for drawing with these item's attributes, return true if
+ // we need to draw the items background to highlight it, false otherwise
+ bool SetAttributes(wxDC *dc,
+ const wxListItemAttr *attr,
+ bool highlight);
+
+ // 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 );
+ int GetImage( int index ) const;
+};
+
+WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData, wxListLineDataArray);
+#include "wx/arrimpl.cpp"
+WX_DEFINE_OBJARRAY(wxListLineDataArray);
+
+//-----------------------------------------------------------------------------
+// wxListHeaderWindow (internal)
+//-----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxListHeaderWindow : public wxWindow
+{
+protected:
+ wxListMainWindow *m_owner;
+ wxCursor *m_currentCursor;
+ wxCursor *m_resizeCursor;
+ bool m_isDragging;
+
+ // column being resized
+ int m_column;
+
+ // divider line position in logical (unscrolled) coords
+ int m_currentX;
+
+ // minimal position beyond which the divider line can't be dragged in
+ // logical coords
+ int m_minX;
+
+public:
+ wxListHeaderWindow();
+ virtual ~wxListHeaderWindow();
+
+ wxListHeaderWindow( wxWindow *win,
+ wxWindowID id,
+ wxListMainWindow *owner,
+ const wxPoint &pos = wxDefaultPosition,
+ const wxSize &size = wxDefaultSize,
+ long style = 0,
+ const wxString &name = "wxlistctrlcolumntitles" );
+
+ void DoDrawRect( wxDC *dc, int x, int y, int w, int h );
+ void DrawCurrent();
+ void AdjustDC(wxDC& dc);
+
+ void OnPaint( wxPaintEvent &event );
+ void OnMouse( wxMouseEvent &event );
+ void OnSetFocus( wxFocusEvent &event );
+
+ // needs refresh
+ bool m_dirty;
+
+private:
+ DECLARE_DYNAMIC_CLASS(wxListHeaderWindow)
+ DECLARE_EVENT_TABLE()
+};
+
+//-----------------------------------------------------------------------------
+// wxListRenameTimer (internal)
+//-----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxListRenameTimer: public wxTimer
+{
+private:
+ wxListMainWindow *m_owner;
+
+public:
+ wxListRenameTimer( wxListMainWindow *owner );
+ void Notify();
+};
+
+//-----------------------------------------------------------------------------
+// wxListTextCtrl (internal)
+//-----------------------------------------------------------------------------
+
+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" );
+ void OnChar( wxKeyEvent &event );
+ void OnKeyUp( wxKeyEvent &event );
+ void OnKillFocus( wxFocusEvent &event );
+
+private:
+ DECLARE_DYNAMIC_CLASS(wxListTextCtrl);
+ DECLARE_EVENT_TABLE()
+};
+
+//-----------------------------------------------------------------------------
+// wxListMainWindow (internal)
+//-----------------------------------------------------------------------------
+
+WX_DECLARE_LIST(wxListHeaderData, wxListHeaderDataList);
+#include "wx/listimpl.cpp"
+WX_DEFINE_LIST(wxListHeaderDataList);
+
+class WXDLLEXPORT wxListMainWindow : public wxScrolledWindow
+{
+public:
+ wxListMainWindow();
+ wxListMainWindow( wxWindow *parent,
+ wxWindowID id,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize,
+ long style = 0,
+ const wxString &name = _T("listctrlmainwindow") );
+
+ virtual ~wxListMainWindow();
+
+ bool HasFlag(int flag) const { return m_parent->HasFlag(flag); }
+
+ // return true if this is a virtual list control
+ bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL); }
+
+ // return true if the control is in report mode
+ bool InReportView() const { return HasFlag(wxLC_REPORT); }
+
+ // return true if we are in single selection mode, false if multi sel
+ bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL); }
+
+ // do we have a header window?
+ bool HasHeader() const
+ { return HasFlag(wxLC_REPORT) && !HasFlag(wxLC_NO_HEADER); }
+
+ void HighlightAll( bool on );
+
+ // all these functions only do something if the line is currently visible
+
+ // change the line "selected" state, return TRUE if it really changed
+ bool HighlightLine( size_t line, bool highlight = TRUE);
+
+ // as HighlightLine() but do it for the range of lines: this is incredibly
+ // more efficient for virtual list controls!
+ //
+ // NB: unlike HighlightLine() this one does refresh the lines on screen
+ void HighlightLines( size_t lineFrom, size_t lineTo, bool on = TRUE );
+
+ // toggle the line state and refresh it
+ void ReverseHighlight( size_t line )
+ { HighlightLine(line, !IsHighlighted(line)); RefreshLine(line); }
+
+ // return true if the line is highlighted
+ bool IsHighlighted(size_t line) const;
+
+ // refresh one or several lines at once
+ void RefreshLine( size_t line );
+ void RefreshLines( size_t lineFrom, size_t lineTo );
+
+ // refresh all lines below the given one: the difference with
+ // RefreshLines() is that the index here might not be a valid one (happens
+ // when the last line is deleted)
+ void RefreshAfter( size_t lineFrom );
+
+ // the methods which are forwarded to wxListLineData itself in list/icon
+ // modes but are here because the lines don't store their positions in the
+ // report mode
+
+ // get the bound rect for the entire line
+ wxRect GetLineRect(size_t line) const;
+
+ // get the bound rect of the label
+ wxRect GetLineLabelRect(size_t line) const;
+
+ // get the bound rect of the items icon (only may be called if we do have
+ // an icon!)
+ wxRect GetLineIconRect(size_t line) const;
+
+ // get the rect to be highlighted when the item has focus
+ wxRect GetLineHighlightRect(size_t line) const;
+
+ // get the size of the total line rect
+ wxSize GetLineSize(size_t line) const
+ { return GetLineRect(line).GetSize(); }
+
+ // return the hit code for the corresponding position (in this line)
+ long HitTestLine(size_t line, int x, int y) const;
+
+ // bring the selected item into view, scrolling to it if necessary
+ void MoveToItem(size_t item);
+
+ // bring the current item into view
+ void MoveToFocus() { MoveToItem(m_current); }
+
+ void EditLabel( long item );
+ void OnRenameTimer();
+ void OnRenameAccept();
+
+ void OnMouse( wxMouseEvent &event );
+
+ // called to switch the selection from the current item to newCurrent,
+ void OnArrowChar( size_t newCurrent, const wxKeyEvent& event );
+
+ void OnChar( wxKeyEvent &event );
+ void OnKeyDown( wxKeyEvent &event );
+ void OnSetFocus( wxFocusEvent &event );
+ void OnKillFocus( wxFocusEvent &event );
+ void OnScroll(wxScrollWinEvent& event) ;
+
+ void OnPaint( wxPaintEvent &event );
+
+ void DrawImage( int index, wxDC *dc, int x, int y );
+ void GetImageSize( int index, int &width, int &height ) const;
+ int GetTextLength( const wxString &s ) const;
+
+ void SetImageList( wxImageList *imageList, int which );
+ void SetItemSpacing( int spacing, bool isSmall = FALSE );
+ int GetItemSpacing( bool isSmall = FALSE );
+
+ void SetColumn( int col, wxListItem &item );
+ void SetColumnWidth( int col, int width );
+ void GetColumn( int col, wxListItem &item ) const;
+ int GetColumnWidth( int col ) const;
+ int GetColumnCount() const { return m_columns.GetCount(); }
+
+ // returns the sum of the heights of all columns
+ int GetHeaderWidth() const;
+
+ int GetCountPerPage() const;
+
+ void SetItem( wxListItem &item );
+ void GetItem( wxListItem &item );
+ 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();
+
+ // set the scrollbars and update the positions of the items
+ void RecalculatePositions(bool noRefresh = FALSE);