X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b63f9a33301b1cead8b9ccbb16e2f50b0d82bbe9..2ddb8ccf6058826262512539142ec5eda7358b74:/include/wx/headerctrl.h?ds=sidebyside diff --git a/include/wx/headerctrl.h b/include/wx/headerctrl.h index 026cca9c1d..8195f32684 100644 --- a/include/wx/headerctrl.h +++ b/include/wx/headerctrl.h @@ -13,11 +13,17 @@ #include "wx/control.h" +#if wxUSE_HEADERCTRL + +#include "wx/dynarray.h" +#include "wx/vector.h" + #include "wx/headercol.h" // notice that the classes in this header are defined in the core library even // although currently they're only used by wxGrid which is in wxAdv because we // plan to use it in wxListCtrl which is in core too in the future +class WXDLLIMPEXP_FWD_CORE wxHeaderCtrlEvent; // ---------------------------------------------------------------------------- // constants @@ -26,16 +32,18 @@ enum { // allow column drag and drop - wxHD_DRAGDROP = 0x0001, + wxHD_ALLOW_REORDER = 0x0001, + + // allow hiding (and showing back) the columns using the menu shown by + // right clicking the header + wxHD_ALLOW_HIDE = 0x0002, // style used by default when creating the control - wxHD_DEFAULT_STYLE = wxHD_DRAGDROP + wxHD_DEFAULT_STYLE = wxHD_ALLOW_REORDER }; extern WXDLLIMPEXP_DATA_CORE(const char) wxHeaderCtrlNameStr[]; -class WXDLLIMPEXP_FWD_CORE wxHeaderColumn; - // ---------------------------------------------------------------------------- // wxHeaderCtrlBase defines the interface of a header control // ---------------------------------------------------------------------------- @@ -51,29 +59,221 @@ public: wxWindowID winid = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, - long style = 0, + long style = wxHD_DEFAULT_STYLE, const wxString& name = wxHeaderCtrlNameStr); bool Create(wxWindow *parent, wxWindowID winid = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, - long style = 0, + long style = wxHD_DEFAULT_STYLE, const wxString& name = wxHeaderCtrlNameStr); */ - // managing the columns - // -------------------- + // column-related methods + // ---------------------- + + // set the number of columns in the control + // + // this also calls UpdateColumn() for all columns + void SetColumnCount(unsigned int count); - // return the number of columns in the control + // return the number of columns in the control as set by SetColumnCount() unsigned int GetColumnCount() const { return DoGetCount(); } // return whether the control has any columns - bool IsEmpty() const { return GetColumnCount() == 0; } + bool IsEmpty() const { return DoGetCount() == 0; } + + // update the column with the given index + void UpdateColumn(unsigned int idx) + { + wxCHECK_RET( idx < GetColumnCount(), "invalid column index" ); + + DoUpdate(idx); + } + + + // columns order + // ------------- + + // set the columns order: the array defines the column index which appears + // the given position, it must have GetColumnCount() elements and contain + // all indices exactly once + void SetColumnsOrder(const wxArrayInt& order); + wxArrayInt GetColumnsOrder() const; + + // get the index of the column at the given display position + unsigned int GetColumnAt(unsigned int pos) const; + + // get the position at which this column is currently displayed + unsigned int GetColumnPos(unsigned int idx) const; + + // reset the columns order to the natural one + void ResetColumnsOrder(); + + // helper function used by the generic version of this control and also + // wxGrid: reshuffles the array of column indices indexed by positions + // (i.e. using the same convention as for SetColumnsOrder()) so that the + // column with the given index is found at the specified position + static void MoveColumnInOrderArray(wxArrayInt& order, + unsigned int idx, + unsigned int pos); + + + // UI helpers + // ---------- + +#if wxUSE_MENUS + // show the popup menu containing all columns with check marks for the ones + // which are currently shown and return true if something was done using it + // (in this case UpdateColumnVisibility() will have been called) or false + // if the menu was cancelled + // + // this is called from the default right click handler for the controls + // with wxHD_ALLOW_HIDE style + bool ShowColumnsMenu(const wxPoint& pt, const wxString& title = wxString()); + + // append the entries for all our columns to the given menu, with the + // currently visible columns being checked + // + // this is used by ShowColumnsMenu() but can also be used if you use your + // own custom columns menu but nevertheless want to show all the columns in + // it + // + // the ids of the items corresponding to the columns are consecutive and + // start from idColumnsBase + void AddColumnsItems(wxMenu& menu, int idColumnsBase = 0); +#endif // wxUSE_MENUS + + // show the columns customization dialog and return true if something was + // changed using it (in which case UpdateColumnVisibility() and/or + // UpdateColumnsOrder() will have been called) + // + // this is called by the control itself from ShowColumnsMenu() (which in + // turn is only called by the control if wxHD_ALLOW_HIDE style was + // specified) and if the control has wxHD_ALLOW_REORDER style as well + bool ShowCustomizeDialog(); + + + // implementation only from now on + // ------------------------------- + + // the user doesn't need to TAB to this control + virtual bool AcceptsFocusFromKeyboard() const { return false; } + + // this method is only overridden in order to synchronize the control with + // the main window when it is scrolled, the derived class must implement + // DoScrollHorz() + virtual void ScrollWindow(int dx, int dy, const wxRect *rect = NULL); + +protected: + // this method must be implemented by the derived classes to return the + // information for the given column + virtual const wxHeaderColumn& GetColumn(unsigned int idx) const = 0; + + // this method is called from the default EVT_HEADER_SEPARATOR_DCLICK + // handler to update the fitting column width of the given column, it + // should return true if the width was really updated + virtual bool UpdateColumnWidthToFit(unsigned int WXUNUSED(idx), + int WXUNUSED(widthTitle)) + { + return false; + } + + // this method is called from ShowColumnsMenu() and must be overridden to + // update the internal column visibility (there is no need to call + // UpdateColumn() from here, this will be done internally) + virtual void UpdateColumnVisibility(unsigned int WXUNUSED(idx), + bool WXUNUSED(show)) + { + wxFAIL_MSG( "must be overridden if called" ); + } + + // this method is called from ShowCustomizeDialog() to reorder all columns + // at once and should be implemented for controls using wxHD_ALLOW_REORDER + // style (there is no need to call SetColumnsOrder() from here, this is + // done by the control itself) + virtual void UpdateColumnsOrder(const wxArrayInt& WXUNUSED(order)) + { + wxFAIL_MSG( "must be overridden if called" ); + } + + // this method can be overridden in the derived classes to do something + // (e.g. update/resize some internal data structures) before the number of + // columns in the control changes + virtual void OnColumnCountChanging(unsigned int WXUNUSED(count)) { } + + + // helper function for the derived classes: update the array of column + // indices after the number of columns changed + void DoResizeColumnIndices(wxArrayInt& colIndices, unsigned int count); + +private: + // methods implementing our public API and defined in platform-specific + // implementations + virtual void DoSetCount(unsigned int count) = 0; + virtual unsigned int DoGetCount() const = 0; + virtual void DoUpdate(unsigned int idx) = 0; + + virtual void DoScrollHorz(int dx) = 0; + + virtual void DoSetColumnsOrder(const wxArrayInt& order) = 0; + virtual wxArrayInt DoGetColumnsOrder() const = 0; + + // this window doesn't look nice with the border so don't use it by default + virtual wxBorder GetDefaultBorder() const { return wxBORDER_NONE; } + + // event handlers + void OnSeparatorDClick(wxHeaderCtrlEvent& event); +#if wxUSE_MENUS + void OnRClick(wxHeaderCtrlEvent& event); +#endif // wxUSE_MENUS + + DECLARE_EVENT_TABLE() +}; + +// ---------------------------------------------------------------------------- +// wxHeaderCtrl: port-specific header control implementation, notice that this +// is still an ABC which is meant to be used as part of another +// control, see wxHeaderCtrlSimple for a standalone version +// ---------------------------------------------------------------------------- + +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + #include "wx/msw/headerctrl.h" +#else + #define wxHAS_GENERIC_HEADERCTRL + #include "wx/generic/headerctrlg.h" +#endif // platform + +// ---------------------------------------------------------------------------- +// wxHeaderCtrlSimple: concrete header control which can be used standalone +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_CORE wxHeaderCtrlSimple : public wxHeaderCtrl +{ +public: + // control creation + // ---------------- + + wxHeaderCtrlSimple() { Init(); } + wxHeaderCtrlSimple(wxWindow *parent, + wxWindowID winid = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxHD_DEFAULT_STYLE, + const wxString& name = wxHeaderCtrlNameStr) + { + Init(); + + Create(parent, winid, pos, size, style, name); + } + + // managing the columns + // -------------------- // insert the column at the given position, using GetColumnCount() as // position appends it at the end - void InsertColumn(const wxHeaderColumn& col, unsigned int idx) + void InsertColumn(const wxHeaderColumnSimple& col, unsigned int idx) { wxCHECK_RET( idx <= GetColumnCount(), "invalid column index" ); @@ -81,7 +281,7 @@ public: } // append the column to the end of the control - void AppendColumn(const wxHeaderColumn& col) + void AppendColumn(const wxHeaderColumnSimple& col) { DoInsert(col, GetColumnCount()); } @@ -115,54 +315,153 @@ public: ShowColumn(idx, false); } - // indicate that the column is used for sorting in ascending order if - // sortOrder is true, for sorting in descending order if it is false or not - // used for sorting at all if it is -1 - void ShowSortIndicator(unsigned int idx, int sortOrder) + // indicate that the column is used for sorting + void ShowSortIndicator(unsigned int idx, bool ascending = true) { - wxCHECK_RET( sortOrder == 0 || sortOrder == 1 || sortOrder == -1, - "invalid sort order value" ); - wxCHECK_RET( idx < GetColumnCount(), "invalid column index" ); - DoShowSortIndicator(idx, sortOrder); + DoShowSortIndicator(idx, ascending); } - // remove the sort indicator from the given column - void RemoveSortIndicator(unsigned int idx) + // remove the sort indicator completely + void RemoveSortIndicator(); + +protected: + // implement/override base class methods + virtual const wxHeaderColumn& GetColumn(unsigned int idx) const; + virtual bool UpdateColumnWidthToFit(unsigned int idx, int widthTitle); + + // and define another one to be overridden in the derived classes: it + // should return the best width for the given column contents or -1 if not + // implemented, we use it to implement UpdateColumnWidthToFit() + virtual int GetBestFittingWidth(unsigned int WXUNUSED(idx)) const { - DoShowSortIndicator(idx, -1); + return -1; } +private: + // functions implementing our public API + void DoInsert(const wxHeaderColumnSimple& col, unsigned int idx); + void DoDelete(unsigned int idx); + void DoShowColumn(unsigned int idx, bool show); + void DoShowSortIndicator(unsigned int idx, bool ascending); - // implementation only from now on - // ------------------------------- + // common part of all ctors + void Init(); - // the user doesn't need to TAB to this control - virtual bool AcceptsFocusFromKeyboard() const { return false; } + // bring the column count in sync with the number of columns we store + void UpdateColumnCount() { SetColumnCount(m_cols.size()); } - // this method is only overridden in order to synchronize the control with - // the main window when it is scrolled, the derived class must implement - // DoScrollHorz() - virtual void ScrollWindow(int dx, int dy, const wxRect *rect = NULL); -private: - virtual unsigned int DoGetCount() const = 0; - virtual void DoInsert(const wxHeaderColumn& col, unsigned int idx) = 0; - virtual void DoDelete(unsigned int idx) = 0; - virtual void DoShowColumn(unsigned int idx, bool show) = 0; - virtual void DoShowSortIndicator(unsigned int idx, int sortOrder) = 0; - virtual void DoScrollHorz(int dx) = 0; + // all our current columns + typedef wxVector Columns; + Columns m_cols; - // this window doesn't look nice with the border so don't use it by default - virtual wxBorder GetDefaultBorder() const { return wxBORDER_NONE; } + // the column currently used for sorting or -1 if none + unsigned int m_sortKey; + + + DECLARE_NO_COPY_CLASS(wxHeaderCtrlSimple) }; -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - #include "wx/msw/headerctrl.h" -#else - #define wxHAS_GENERIC_HEADERCTRL - #include "wx/generic/headerctrlg.h" -#endif // platform +// ---------------------------------------------------------------------------- +// wxHeaderCtrl events +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_CORE wxHeaderCtrlEvent : public wxNotifyEvent +{ +public: + wxHeaderCtrlEvent(wxEventType commandType = wxEVT_NULL, int winid = 0) + : wxNotifyEvent(commandType, winid), + m_col(-1), + m_width(0), + m_order(static_cast(-1)) + { + } + + wxHeaderCtrlEvent(const wxHeaderCtrlEvent& event) + : wxNotifyEvent(event), + m_col(event.m_col), + m_width(event.m_width), + m_order(event.m_order) + { + } + + // the column which this event pertains to: valid for all header events + int GetColumn() const { return m_col; } + void SetColumn(int col) { m_col = col; } + + // the width of the column: valid for column resizing/dragging events only + int GetWidth() const { return m_width; } + void SetWidth(int width) { m_width = width; } + + // the new position of the column: for end reorder events only + unsigned int GetNewOrder() const { return m_order; } + void SetNewOrder(unsigned int order) { m_order = order; } + + virtual wxEvent *Clone() const { return new wxHeaderCtrlEvent(*this); } + +protected: + // the column affected by the event + int m_col; + + // the current width for the dragging events + int m_width; + + // the new column position for end reorder event + unsigned int m_order; + +private: + DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxHeaderCtrlEvent) +}; + + +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_COMMAND_HEADER_CLICK, wxHeaderCtrlEvent ) +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_COMMAND_HEADER_RIGHT_CLICK, wxHeaderCtrlEvent ) +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_COMMAND_HEADER_MIDDLE_CLICK, wxHeaderCtrlEvent ) + +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_COMMAND_HEADER_DCLICK, wxHeaderCtrlEvent ) +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_COMMAND_HEADER_RIGHT_DCLICK, wxHeaderCtrlEvent ) +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_COMMAND_HEADER_MIDDLE_DCLICK, wxHeaderCtrlEvent ) + +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_COMMAND_HEADER_SEPARATOR_DCLICK, wxHeaderCtrlEvent ) + +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_COMMAND_HEADER_BEGIN_RESIZE, wxHeaderCtrlEvent ) +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_COMMAND_HEADER_RESIZING, wxHeaderCtrlEvent ) +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_COMMAND_HEADER_END_RESIZE, wxHeaderCtrlEvent ) + +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_COMMAND_HEADER_BEGIN_REORDER, wxHeaderCtrlEvent ) +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_COMMAND_HEADER_END_REORDER, wxHeaderCtrlEvent ) + +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_COMMAND_HEADER_DRAGGING_CANCELLED, wxHeaderCtrlEvent ) + +typedef void (wxEvtHandler::*wxHeaderCtrlEventFunction)(wxHeaderCtrlEvent&); + +#define wxHeaderCtrlEventHandler(func) \ + wxEVENT_HANDLER_CAST(wxHeaderCtrlEventFunction, func) + +#define wx__DECLARE_HEADER_EVT(evt, id, fn) \ + wx__DECLARE_EVT1(wxEVT_COMMAND_HEADER_ ## evt, id, wxHeaderCtrlEventHandler(fn)) + +#define EVT_HEADER_CLICK(id, fn) wx__DECLARE_HEADER_EVT(CLICK, id, fn) +#define EVT_HEADER_RIGHT_CLICK(id, fn) wx__DECLARE_HEADER_EVT(RIGHT_CLICK, id, fn) +#define EVT_HEADER_MIDDLE_CLICK(id, fn) wx__DECLARE_HEADER_EVT(MIDDLE_CLICK, id, fn) + +#define EVT_HEADER_DCLICK(id, fn) wx__DECLARE_HEADER_EVT(DCLICK, id, fn) +#define EVT_HEADER_RIGHT_DCLICK(id, fn) wx__DECLARE_HEADER_EVT(RIGHT_DCLICK, id, fn) +#define EVT_HEADER_MIDDLE_DCLICK(id, fn) wx__DECLARE_HEADER_EVT(MIDDLE_DCLICK, id, fn) + +#define EVT_HEADER_SEPARATOR_DCLICK(id, fn) wx__DECLARE_HEADER_EVT(SEPARATOR_DCLICK, id, fn) + +#define EVT_HEADER_BEGIN_RESIZE(id, fn) wx__DECLARE_HEADER_EVT(BEGIN_RESIZE, id, fn) +#define EVT_HEADER_RESIZING(id, fn) wx__DECLARE_HEADER_EVT(RESIZING, id, fn) +#define EVT_HEADER_END_RESIZE(id, fn) wx__DECLARE_HEADER_EVT(END_RESIZE, id, fn) + +#define EVT_HEADER_BEGIN_REORDER(id, fn) wx__DECLARE_HEADER_EVT(BEGIN_REORDER, id, fn) +#define EVT_HEADER_END_REORDER(id, fn) wx__DECLARE_HEADER_EVT(END_REORDER, id, fn) + +#define EVT_HEADER_DRAGGING_CANCELLED(id, fn) wx__DECLARE_HEADER_EVT(DRAGGING_CANCELLED, id, fn) + +#endif // wxUSE_HEADERCTRL #endif // _WX_HEADERCTRL_H_