diff options
author | Daniel Wilhelm <shieldwed@outlook.com> | 2017-02-13 21:25:04 -0700 |
---|---|---|
committer | Daniel Wilhelm <shieldwed@outlook.com> | 2017-02-13 21:25:04 -0700 |
commit | 9d071d2a2cec9a7662a02669488569a017f0ea35 (patch) | |
tree | c83a623fbdff098339b66d21ea2e81f3f67344ae /wx+/grid.h | |
parent | 8.8 (diff) | |
download | FreeFileSync-9d071d2a2cec9a7662a02669488569a017f0ea35.tar.gz FreeFileSync-9d071d2a2cec9a7662a02669488569a017f0ea35.tar.bz2 FreeFileSync-9d071d2a2cec9a7662a02669488569a017f0ea35.zip |
8.9
Diffstat (limited to 'wx+/grid.h')
-rwxr-xr-x[-rw-r--r--] | wx+/grid.h | 729 |
1 files changed, 363 insertions, 366 deletions
diff --git a/wx+/grid.h b/wx+/grid.h index f08d6e41..ff1d4b87 100644..100755 --- a/wx+/grid.h +++ b/wx+/grid.h @@ -1,366 +1,363 @@ -// ***************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 * -// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved * -// ***************************************************************************** - -#ifndef GRID_H_834702134831734869987 -#define GRID_H_834702134831734869987 - -#include <memory> -#include <numeric> -#include <vector> -#include <wx/scrolwin.h> -#include <zen/basic_math.h> -#include <zen/optional.h> - -//a user-friendly, extensible and high-performance grid control - -namespace zen -{ -enum class ColumnType { NONE = -1 }; //user-defiend column type -enum class HoverArea { NONE = -1 }; //user-defined area for mouse selections for a given row (may span multiple columns or split a single column into multiple areas) - -//------------------------ events ------------------------------------------------ -extern const wxEventType EVENT_GRID_MOUSE_LEFT_DOUBLE; // -extern const wxEventType EVENT_GRID_MOUSE_LEFT_DOWN; // -extern const wxEventType EVENT_GRID_MOUSE_LEFT_UP; //generates: GridClickEvent -extern const wxEventType EVENT_GRID_MOUSE_RIGHT_DOWN; // -extern const wxEventType EVENT_GRID_MOUSE_RIGHT_UP; // - -extern const wxEventType EVENT_GRID_SELECT_RANGE; //generates: GridRangeSelectEvent -//NOTE: neither first nor second row need to match EVENT_GRID_MOUSE_LEFT_DOWN/EVENT_GRID_MOUSE_LEFT_UP: user holding SHIFT; moving out of window... - -extern const wxEventType EVENT_GRID_COL_LABEL_MOUSE_LEFT; //generates: GridLabelClickEvent -extern const wxEventType EVENT_GRID_COL_LABEL_MOUSE_RIGHT; // -extern const wxEventType EVENT_GRID_COL_RESIZE; //generates: GridColumnResizeEvent - -//example: wnd.Connect(EVENT_GRID_COL_LABEL_LEFT_CLICK, GridClickEventHandler(MyDlg::OnLeftClick), nullptr, this); - -struct GridClickEvent : public wxMouseEvent -{ - GridClickEvent(wxEventType et, const wxMouseEvent& me, ptrdiff_t row, HoverArea hoverArea) : - wxMouseEvent(me), row_(row), hoverArea_(hoverArea) { SetEventType(et); } - wxEvent* Clone() const override { return new GridClickEvent(*this); } - - const ptrdiff_t row_; //-1 for invalid position, >= rowCount if out of range - const HoverArea hoverArea_; //may be HoverArea::NONE -}; - -struct GridRangeSelectEvent : public wxCommandEvent -{ - GridRangeSelectEvent(size_t rowFirst, size_t rowLast, bool positive, const GridClickEvent* mouseInitiated) : - wxCommandEvent(EVENT_GRID_SELECT_RANGE), rowFirst_(rowFirst), rowLast_(rowLast), positive_(positive), - mouseInitiated_(mouseInitiated ? *mouseInitiated : Opt<GridClickEvent>()) { assert(rowFirst <= rowLast); } - wxEvent* Clone() const override { return new GridRangeSelectEvent(*this); } - - const size_t rowFirst_; //selected range: [rowFirst_, rowLast_) - const size_t rowLast_; - const bool positive_; //"false" when clearing selection! - Opt<GridClickEvent> mouseInitiated_; //filled unless selection was performed via keyboard shortcuts or is result of Grid::clearSelection() -}; - -struct GridLabelClickEvent : public wxMouseEvent -{ - GridLabelClickEvent(wxEventType et, const wxMouseEvent& me, ColumnType colType) : wxMouseEvent(me), colType_(colType) { SetEventType(et); } - wxEvent* Clone() const override { return new GridLabelClickEvent(*this); } - - const ColumnType colType_; //may be ColumnType::NONE -}; - - -struct GridColumnResizeEvent : public wxCommandEvent -{ - GridColumnResizeEvent(int offset, ColumnType colType) : wxCommandEvent(EVENT_GRID_COL_RESIZE), colType_(colType), offset_(offset) {} - wxEvent* Clone() const override { return new GridColumnResizeEvent(*this); } - - const ColumnType colType_; - const int offset_; -}; - -using GridClickEventFunction = void (wxEvtHandler::*)(GridClickEvent&); -using GridRangeSelectEventFunction = void (wxEvtHandler::*)(GridRangeSelectEvent&); -using GridLabelClickEventFunction = void (wxEvtHandler::*)(GridLabelClickEvent&); -using GridColumnResizeEventFunction = void (wxEvtHandler::*)(GridColumnResizeEvent&); - -#define GridClickEventHandler(func) (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(GridClickEventFunction, &func) -#define GridRangeSelectEventHandler(func) (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(GridRangeSelectEventFunction, &func) -#define GridLabelClickEventHandler(func) (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(GridLabelClickEventFunction, &func) -#define GridColumnResizeEventHandler(func)(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(GridColumnResizeEventFunction, &func) - -//------------------------------------------------------------------------------------------------------------ -class Grid; - -void clearArea(wxDC& dc, const wxRect& rect, const wxColor& col); - -class GridData -{ -public: - virtual ~GridData() {} - - virtual size_t getRowCount() const = 0; - - //cell area: - virtual std::wstring getValue(size_t row, ColumnType colType) const = 0; - virtual void renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected); //default implementation - virtual void renderCell (wxDC& dc, const wxRect& rect, size_t row, ColumnType colType, bool enabled, bool selected, HoverArea rowHover); - virtual int getBestSize (wxDC& dc, size_t row, ColumnType colType); //must correspond to renderCell()! - virtual std::wstring getToolTip (size_t row, ColumnType colType) const { return std::wstring(); } - virtual HoverArea getRowMouseHover(size_t row, ColumnType colType, int cellRelativePosX, int cellWidth) { return HoverArea::NONE; } - - //label area: - virtual std::wstring getColumnLabel(ColumnType colType) const = 0; - virtual void renderColumnLabel(Grid& grid, wxDC& dc, const wxRect& rect, ColumnType colType, bool highlighted); //default implementation - virtual std::wstring getToolTip(ColumnType colType) const { return std::wstring(); } - - static const int COLUMN_GAP_LEFT; //for left-aligned text - - //optional helper routines: - static wxSize drawCellText (wxDC& dc, const wxRect& rect, const std::wstring& text, int alignment = wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); //returns text extent - static wxRect drawCellBorder (wxDC& dc, const wxRect& rect); //returns inner rectangle - static void drawCellBackground(wxDC& dc, const wxRect& rect, bool enabled, bool selected, const wxColor& backgroundColor); - - static wxRect drawColumnLabelBorder (wxDC& dc, const wxRect& rect); //returns inner rectangle - static void drawColumnLabelBackground(wxDC& dc, const wxRect& rect, bool highlighted); - static void drawColumnLabelText (wxDC& dc, const wxRect& rect, const std::wstring& text); -}; - - -enum GridEventPolicy -{ - ALLOW_GRID_EVENT, - DENY_GRID_EVENT -}; - - -class Grid : public wxScrolledWindow -{ -public: - Grid(wxWindow* parent, - wxWindowID id = wxID_ANY, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxTAB_TRAVERSAL | wxNO_BORDER, - const wxString& name = wxPanelNameStr); - - size_t getRowCount() const; - - void setRowHeight(int height); - - struct ColumnAttribute - { - ColumnAttribute(ColumnType type, int offset, int stretch, bool visible = true) : type_(type), visible_(visible), stretch_(std::max(stretch, 0)), offset_(offset) { assert(stretch >=0 ); } - ColumnType type_; - bool visible_; - //first, client width is partitioned according to all available stretch factors, then "offset_" is added - //universal model: a non-stretched column has stretch factor 0 with the "offset" becoming identical to final width! - int stretch_; //>= 0 - int offset_; - }; - - void setColumnConfig(const std::vector<ColumnAttribute>& attr); //set column count + widths - std::vector<ColumnAttribute> getColumnConfig() const; - - void setDataProvider(const std::shared_ptr<GridData>& dataView) { dataView_ = dataView; } - /**/ GridData* getDataProvider() { return dataView_.get(); } - const GridData* getDataProvider() const { return dataView_.get(); } - //----------------------------------------------------------------------------- - - void setColumnLabelHeight(int height); - void showRowLabel(bool visible); - - enum ScrollBarStatus - { - SB_SHOW_AUTOMATIC, - SB_SHOW_ALWAYS, - SB_SHOW_NEVER, - }; - //alternative until wxScrollHelper::ShowScrollbars() becomes available in wxWidgets 2.9 - void showScrollBars(ScrollBarStatus horizontal, ScrollBarStatus vertical); - - std::vector<size_t> getSelectedRows() const { return selection_.get(); } - void selectAllRows (GridEventPolicy rangeEventPolicy); - void clearSelection(GridEventPolicy rangeEventPolicy); //turn off range selection event when calling this function in an event handler to avoid recursion! - - void scrollDelta(int deltaX, int deltaY); //in scroll units - - wxWindow& getCornerWin (); - wxWindow& getRowLabelWin(); - wxWindow& getColLabelWin(); - wxWindow& getMainWin (); - const wxWindow& getMainWin() const; - - ptrdiff_t getRowAtPos(int posY) const; //return -1 for invalid position, >= rowCount if out of range; absolute coordinates! - - struct ColumnPosInfo - { - ColumnType colType; //ColumnType::NONE no column at x position! - int cellRelativePosX; - int colWidth; - }; - ColumnPosInfo getColumnAtPos(int posX) const; //absolute position! - - void refreshCell(size_t row, ColumnType colType); - - void enableColumnMove (bool value) { allowColumnMove_ = value; } - void enableColumnResize(bool value) { allowColumnResize_ = value; } - - void setGridCursor(size_t row); //set + show + select cursor (+ emit range selection event) - size_t getGridCursor() const; //returns row - - void scrollTo(size_t row); - - void Refresh(bool eraseBackground = true, const wxRect* rect = nullptr) override; - bool Enable(bool enable = true) override; - - //############################################################################################################ - - static wxColor getColorSelectionGradientFrom(); - static wxColor getColorSelectionGradientTo(); - -private: - void onPaintEvent(wxPaintEvent& event); - void onEraseBackGround(wxEraseEvent& event) {} //[!] - void onSizeEvent(wxSizeEvent& event) { updateWindowSizes(); event.Skip(); } - void onKeyDown(wxKeyEvent& event); - - void updateWindowSizes(bool updateScrollbar = true); - - void selectWithCursor(ptrdiff_t row); - void makeRowVisible(size_t row); - - void redirectRowLabelEvent(wxMouseEvent& event); - - wxSize GetSizeAvailableForScrollTarget(const wxSize& size) override; //required since wxWidgets 2.9 if SetTargetWindow() is used - -#if defined ZEN_WIN || defined ZEN_MAC - void SetScrollbar(int orientation, int position, int thumbSize, int range, bool refresh) override; //get rid of scrollbars, but preserve scrolling behavior! -#endif - - int getBestColumnSize(size_t col) const; //return -1 on error - - void autoSizeColumns(GridEventPolicy columnResizeEventPolicy); - - friend class GridData; - class SubWindow; - class CornerWin; - class RowLabelWin; - class ColLabelWin; - class MainWin; - - class Selection - { - public: - void init(size_t rowCount) { rowSelectionValue.resize(rowCount); clear(); } - - size_t maxSize() const { return rowSelectionValue.size(); } - - std::vector<size_t> get() const - { - std::vector<size_t> result; - for (size_t row = 0; row < rowSelectionValue.size(); ++row) - if (rowSelectionValue[row] != 0) - result.push_back(row); - return result; - } - - void selectAll() { selectRange(0, rowSelectionValue.size(), true); } - void clear () { selectRange(0, rowSelectionValue.size(), false); } - - bool isSelected(size_t row) const { return row < rowSelectionValue.size() ? rowSelectionValue[row] != 0 : false; } - - void selectRange(size_t rowFirst, size_t rowLast, bool positive = true) //select [rowFirst, rowLast), trims if required! - { - if (rowFirst <= rowLast) - { - numeric::clamp<size_t>(rowFirst, 0, rowSelectionValue.size()); - numeric::clamp<size_t>(rowLast, 0, rowSelectionValue.size()); - - std::fill(rowSelectionValue.begin() + rowFirst, rowSelectionValue.begin() + rowLast, positive); - } - else assert(false); - } - - private: - std::vector<char> rowSelectionValue; //effectively a vector<bool> of size "number of rows" - }; - - struct VisibleColumn - { - VisibleColumn(ColumnType type, int offset, int stretch) : type_(type), stretch_(stretch), offset_(offset) {} - ColumnType type_; - int stretch_; //>= 0 - int offset_; - }; - - struct ColumnWidth - { - ColumnWidth(ColumnType type, int width) : type_(type), width_(width) {} - ColumnType type_; - int width_; - }; - std::vector<ColumnWidth> getColWidths() const; // - std::vector<ColumnWidth> getColWidths(int mainWinWidth) const; //evaluate stretched columns - int getColWidthsSum(int mainWinWidth) const; - std::vector<int> getColStretchedWidths(int clientWidth) const; //final width = (normalized) (stretchedWidth + offset) - - Opt<int> getColWidth(size_t col) const - { - const auto& widths = getColWidths(); - if (col < widths.size()) - return widths[col].width_; - return NoValue(); - } - - void setColumnWidth(int width, size_t col, GridEventPolicy columnResizeEventPolicy, bool notifyAsync = false); - - wxRect getColumnLabelArea(ColumnType colType) const; //returns empty rect if column not found - - void selectRangeAndNotify(ptrdiff_t rowFrom, ptrdiff_t rowTo, bool positive, const GridClickEvent* mouseInitiated); //select inclusive range [rowFrom, rowTo] + notify event! - - bool isSelected(size_t row) const { return selection_.isSelected(row); } - - struct ColAction - { - bool wantResize = false; //"!wantResize" means "move" or "single click" - size_t col = 0; - }; - Opt<ColAction> clientPosToColumnAction(const wxPoint& pos) const; - void moveColumn(size_t colFrom, size_t colTo); - ptrdiff_t clientPosToMoveTargetColumn(const wxPoint& pos) const; //return < 0 on error - - ColumnType colToType(size_t col) const; //returns ColumnType::NONE on error - - /* - Visual layout: - -------------------------------- - |CornerWin | ColLabelWin | - |------------------------------| - |RowLabelWin | MainWin | - | | | - -------------------------------- - */ - CornerWin* cornerWin_; - RowLabelWin* rowLabelWin_; - ColLabelWin* colLabelWin_; - MainWin* mainWin_; - - ScrollBarStatus showScrollbarX_ = SB_SHOW_AUTOMATIC; - ScrollBarStatus showScrollbarY_ = SB_SHOW_AUTOMATIC; - - int colLabelHeight_ = 0; - bool drawRowLabel_ = true; - - std::shared_ptr<GridData> dataView_; - Selection selection_; - bool allowColumnMove_ = true; - bool allowColumnResize_ = true; - - std::vector<VisibleColumn> visibleCols_; //individual widths, type and total column count - std::vector<ColumnAttribute> oldColAttributes_; //visible + nonvisible columns; use for conversion in setColumnConfig()/getColumnConfig() *only*! - - size_t rowCountOld_ = 0; //at the time of last Grid::Refresh() -}; -} - -#endif //GRID_H_834702134831734869987 +// *****************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 *
+// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
+// *****************************************************************************
+
+#ifndef GRID_H_834702134831734869987
+#define GRID_H_834702134831734869987
+
+#include <memory>
+#include <numeric>
+#include <vector>
+#include <wx/scrolwin.h>
+#include <zen/basic_math.h>
+#include <zen/optional.h>
+
+//a user-friendly, extensible and high-performance grid control
+
+namespace zen
+{
+enum class ColumnType { NONE = -1 }; //user-defiend column type
+enum class HoverArea { NONE = -1 }; //user-defined area for mouse selections for a given row (may span multiple columns or split a single column into multiple areas)
+
+//------------------------ events ------------------------------------------------
+extern const wxEventType EVENT_GRID_MOUSE_LEFT_DOUBLE; //
+extern const wxEventType EVENT_GRID_MOUSE_LEFT_DOWN; //
+extern const wxEventType EVENT_GRID_MOUSE_LEFT_UP; //generates: GridClickEvent
+extern const wxEventType EVENT_GRID_MOUSE_RIGHT_DOWN; //
+extern const wxEventType EVENT_GRID_MOUSE_RIGHT_UP; //
+
+extern const wxEventType EVENT_GRID_SELECT_RANGE; //generates: GridRangeSelectEvent
+//NOTE: neither first nor second row need to match EVENT_GRID_MOUSE_LEFT_DOWN/EVENT_GRID_MOUSE_LEFT_UP: user holding SHIFT; moving out of window...
+
+extern const wxEventType EVENT_GRID_COL_LABEL_MOUSE_LEFT; //generates: GridLabelClickEvent
+extern const wxEventType EVENT_GRID_COL_LABEL_MOUSE_RIGHT; //
+extern const wxEventType EVENT_GRID_COL_RESIZE; //generates: GridColumnResizeEvent
+
+//example: wnd.Connect(EVENT_GRID_COL_LABEL_LEFT_CLICK, GridClickEventHandler(MyDlg::OnLeftClick), nullptr, this);
+
+struct GridClickEvent : public wxMouseEvent
+{
+ GridClickEvent(wxEventType et, const wxMouseEvent& me, ptrdiff_t row, HoverArea hoverArea) :
+ wxMouseEvent(me), row_(row), hoverArea_(hoverArea) { SetEventType(et); }
+ wxEvent* Clone() const override { return new GridClickEvent(*this); }
+
+ const ptrdiff_t row_; //-1 for invalid position, >= rowCount if out of range
+ const HoverArea hoverArea_; //may be HoverArea::NONE
+};
+
+struct GridRangeSelectEvent : public wxCommandEvent
+{
+ GridRangeSelectEvent(size_t rowFirst, size_t rowLast, bool positive, const GridClickEvent* mouseInitiated) :
+ wxCommandEvent(EVENT_GRID_SELECT_RANGE), rowFirst_(rowFirst), rowLast_(rowLast), positive_(positive),
+ mouseInitiated_(mouseInitiated ? *mouseInitiated : Opt<GridClickEvent>()) { assert(rowFirst <= rowLast); }
+ wxEvent* Clone() const override { return new GridRangeSelectEvent(*this); }
+
+ const size_t rowFirst_; //selected range: [rowFirst_, rowLast_)
+ const size_t rowLast_;
+ const bool positive_; //"false" when clearing selection!
+ Opt<GridClickEvent> mouseInitiated_; //filled unless selection was performed via keyboard shortcuts or is result of Grid::clearSelection()
+};
+
+struct GridLabelClickEvent : public wxMouseEvent
+{
+ GridLabelClickEvent(wxEventType et, const wxMouseEvent& me, ColumnType colType) : wxMouseEvent(me), colType_(colType) { SetEventType(et); }
+ wxEvent* Clone() const override { return new GridLabelClickEvent(*this); }
+
+ const ColumnType colType_; //may be ColumnType::NONE
+};
+
+
+struct GridColumnResizeEvent : public wxCommandEvent
+{
+ GridColumnResizeEvent(int offset, ColumnType colType) : wxCommandEvent(EVENT_GRID_COL_RESIZE), colType_(colType), offset_(offset) {}
+ wxEvent* Clone() const override { return new GridColumnResizeEvent(*this); }
+
+ const ColumnType colType_;
+ const int offset_;
+};
+
+using GridClickEventFunction = void (wxEvtHandler::*)(GridClickEvent&);
+using GridRangeSelectEventFunction = void (wxEvtHandler::*)(GridRangeSelectEvent&);
+using GridLabelClickEventFunction = void (wxEvtHandler::*)(GridLabelClickEvent&);
+using GridColumnResizeEventFunction = void (wxEvtHandler::*)(GridColumnResizeEvent&);
+
+#define GridClickEventHandler(func) (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(GridClickEventFunction, &func)
+#define GridRangeSelectEventHandler(func) (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(GridRangeSelectEventFunction, &func)
+#define GridLabelClickEventHandler(func) (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(GridLabelClickEventFunction, &func)
+#define GridColumnResizeEventHandler(func)(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(GridColumnResizeEventFunction, &func)
+
+//------------------------------------------------------------------------------------------------------------
+class Grid;
+
+void clearArea(wxDC& dc, const wxRect& rect, const wxColor& col);
+
+class GridData
+{
+public:
+ virtual ~GridData() {}
+
+ virtual size_t getRowCount() const = 0;
+
+ //cell area:
+ virtual std::wstring getValue(size_t row, ColumnType colType) const = 0;
+ virtual void renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected); //default implementation
+ virtual void renderCell (wxDC& dc, const wxRect& rect, size_t row, ColumnType colType, bool enabled, bool selected, HoverArea rowHover);
+ virtual int getBestSize (wxDC& dc, size_t row, ColumnType colType); //must correspond to renderCell()!
+ virtual std::wstring getToolTip (size_t row, ColumnType colType) const { return std::wstring(); }
+ virtual HoverArea getRowMouseHover(size_t row, ColumnType colType, int cellRelativePosX, int cellWidth) { return HoverArea::NONE; }
+
+ //label area:
+ virtual std::wstring getColumnLabel(ColumnType colType) const = 0;
+ virtual void renderColumnLabel(Grid& grid, wxDC& dc, const wxRect& rect, ColumnType colType, bool highlighted); //default implementation
+ virtual std::wstring getToolTip(ColumnType colType) const { return std::wstring(); }
+
+ static const int COLUMN_GAP_LEFT; //for left-aligned text
+
+ //optional helper routines:
+ static wxSize drawCellText (wxDC& dc, const wxRect& rect, const std::wstring& text, int alignment = wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); //returns text extent
+ static wxRect drawCellBorder (wxDC& dc, const wxRect& rect); //returns inner rectangle
+ static void drawCellBackground(wxDC& dc, const wxRect& rect, bool enabled, bool selected, const wxColor& backgroundColor);
+
+ static wxRect drawColumnLabelBorder (wxDC& dc, const wxRect& rect); //returns inner rectangle
+ static void drawColumnLabelBackground(wxDC& dc, const wxRect& rect, bool highlighted);
+ static void drawColumnLabelText (wxDC& dc, const wxRect& rect, const std::wstring& text);
+};
+
+
+enum GridEventPolicy
+{
+ ALLOW_GRID_EVENT,
+ DENY_GRID_EVENT
+};
+
+
+class Grid : public wxScrolledWindow
+{
+public:
+ Grid(wxWindow* parent,
+ wxWindowID id = wxID_ANY,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize,
+ long style = wxTAB_TRAVERSAL | wxNO_BORDER,
+ const wxString& name = wxPanelNameStr);
+
+ size_t getRowCount() const;
+
+ void setRowHeight(int height);
+
+ struct ColumnAttribute
+ {
+ ColumnAttribute(ColumnType type, int offset, int stretch, bool visible = true) : type_(type), visible_(visible), stretch_(std::max(stretch, 0)), offset_(offset) { assert(stretch >=0 ); }
+ ColumnType type_;
+ bool visible_;
+ //first, client width is partitioned according to all available stretch factors, then "offset_" is added
+ //universal model: a non-stretched column has stretch factor 0 with the "offset" becoming identical to final width!
+ int stretch_; //>= 0
+ int offset_;
+ };
+
+ void setColumnConfig(const std::vector<ColumnAttribute>& attr); //set column count + widths
+ std::vector<ColumnAttribute> getColumnConfig() const;
+
+ void setDataProvider(const std::shared_ptr<GridData>& dataView) { dataView_ = dataView; }
+ /**/ GridData* getDataProvider() { return dataView_.get(); }
+ const GridData* getDataProvider() const { return dataView_.get(); }
+ //-----------------------------------------------------------------------------
+
+ void setColumnLabelHeight(int height);
+ void showRowLabel(bool visible);
+
+ enum ScrollBarStatus
+ {
+ SB_SHOW_AUTOMATIC,
+ SB_SHOW_ALWAYS,
+ SB_SHOW_NEVER,
+ };
+ //alternative until wxScrollHelper::ShowScrollbars() becomes available in wxWidgets 2.9
+ void showScrollBars(ScrollBarStatus horizontal, ScrollBarStatus vertical);
+
+ std::vector<size_t> getSelectedRows() const { return selection_.get(); }
+ void selectAllRows (GridEventPolicy rangeEventPolicy);
+ void clearSelection(GridEventPolicy rangeEventPolicy); //turn off range selection event when calling this function in an event handler to avoid recursion!
+
+ void scrollDelta(int deltaX, int deltaY); //in scroll units
+
+ wxWindow& getCornerWin ();
+ wxWindow& getRowLabelWin();
+ wxWindow& getColLabelWin();
+ wxWindow& getMainWin ();
+ const wxWindow& getMainWin() const;
+
+ ptrdiff_t getRowAtPos(int posY) const; //return -1 for invalid position, >= rowCount if out of range; absolute coordinates!
+
+ struct ColumnPosInfo
+ {
+ ColumnType colType; //ColumnType::NONE no column at x position!
+ int cellRelativePosX;
+ int colWidth;
+ };
+ ColumnPosInfo getColumnAtPos(int posX) const; //absolute position!
+
+ void refreshCell(size_t row, ColumnType colType);
+
+ void enableColumnMove (bool value) { allowColumnMove_ = value; }
+ void enableColumnResize(bool value) { allowColumnResize_ = value; }
+
+ void setGridCursor(size_t row); //set + show + select cursor (+ emit range selection event)
+ size_t getGridCursor() const; //returns row
+
+ void scrollTo(size_t row);
+
+ void Refresh(bool eraseBackground = true, const wxRect* rect = nullptr) override;
+ bool Enable(bool enable = true) override;
+
+ //############################################################################################################
+
+ static wxColor getColorSelectionGradientFrom();
+ static wxColor getColorSelectionGradientTo();
+
+private:
+ void onPaintEvent(wxPaintEvent& event);
+ void onEraseBackGround(wxEraseEvent& event) {} //[!]
+ void onSizeEvent(wxSizeEvent& event) { updateWindowSizes(); event.Skip(); }
+ void onKeyDown(wxKeyEvent& event);
+
+ void updateWindowSizes(bool updateScrollbar = true);
+
+ void selectWithCursor(ptrdiff_t row);
+ void makeRowVisible(size_t row);
+
+ void redirectRowLabelEvent(wxMouseEvent& event);
+
+ wxSize GetSizeAvailableForScrollTarget(const wxSize& size) override; //required since wxWidgets 2.9 if SetTargetWindow() is used
+
+
+ int getBestColumnSize(size_t col) const; //return -1 on error
+
+ void autoSizeColumns(GridEventPolicy columnResizeEventPolicy);
+
+ friend class GridData;
+ class SubWindow;
+ class CornerWin;
+ class RowLabelWin;
+ class ColLabelWin;
+ class MainWin;
+
+ class Selection
+ {
+ public:
+ void init(size_t rowCount) { rowSelectionValue.resize(rowCount); clear(); }
+
+ size_t maxSize() const { return rowSelectionValue.size(); }
+
+ std::vector<size_t> get() const
+ {
+ std::vector<size_t> result;
+ for (size_t row = 0; row < rowSelectionValue.size(); ++row)
+ if (rowSelectionValue[row] != 0)
+ result.push_back(row);
+ return result;
+ }
+
+ void selectAll() { selectRange(0, rowSelectionValue.size(), true); }
+ void clear () { selectRange(0, rowSelectionValue.size(), false); }
+
+ bool isSelected(size_t row) const { return row < rowSelectionValue.size() ? rowSelectionValue[row] != 0 : false; }
+
+ void selectRange(size_t rowFirst, size_t rowLast, bool positive = true) //select [rowFirst, rowLast), trims if required!
+ {
+ if (rowFirst <= rowLast)
+ {
+ numeric::clamp<size_t>(rowFirst, 0, rowSelectionValue.size());
+ numeric::clamp<size_t>(rowLast, 0, rowSelectionValue.size());
+
+ std::fill(rowSelectionValue.begin() + rowFirst, rowSelectionValue.begin() + rowLast, positive);
+ }
+ else assert(false);
+ }
+
+ private:
+ std::vector<char> rowSelectionValue; //effectively a vector<bool> of size "number of rows"
+ };
+
+ struct VisibleColumn
+ {
+ VisibleColumn(ColumnType type, int offset, int stretch) : type_(type), stretch_(stretch), offset_(offset) {}
+ ColumnType type_;
+ int stretch_; //>= 0
+ int offset_;
+ };
+
+ struct ColumnWidth
+ {
+ ColumnWidth(ColumnType type, int width) : type_(type), width_(width) {}
+ ColumnType type_;
+ int width_;
+ };
+ std::vector<ColumnWidth> getColWidths() const; //
+ std::vector<ColumnWidth> getColWidths(int mainWinWidth) const; //evaluate stretched columns
+ int getColWidthsSum(int mainWinWidth) const;
+ std::vector<int> getColStretchedWidths(int clientWidth) const; //final width = (normalized) (stretchedWidth + offset)
+
+ Opt<int> getColWidth(size_t col) const
+ {
+ const auto& widths = getColWidths();
+ if (col < widths.size())
+ return widths[col].width_;
+ return NoValue();
+ }
+
+ void setColumnWidth(int width, size_t col, GridEventPolicy columnResizeEventPolicy, bool notifyAsync = false);
+
+ wxRect getColumnLabelArea(ColumnType colType) const; //returns empty rect if column not found
+
+ void selectRangeAndNotify(ptrdiff_t rowFrom, ptrdiff_t rowTo, bool positive, const GridClickEvent* mouseInitiated); //select inclusive range [rowFrom, rowTo] + notify event!
+
+ bool isSelected(size_t row) const { return selection_.isSelected(row); }
+
+ struct ColAction
+ {
+ bool wantResize = false; //"!wantResize" means "move" or "single click"
+ size_t col = 0;
+ };
+ Opt<ColAction> clientPosToColumnAction(const wxPoint& pos) const;
+ void moveColumn(size_t colFrom, size_t colTo);
+ ptrdiff_t clientPosToMoveTargetColumn(const wxPoint& pos) const; //return < 0 on error
+
+ ColumnType colToType(size_t col) const; //returns ColumnType::NONE on error
+
+ /*
+ Visual layout:
+ --------------------------------
+ |CornerWin | ColLabelWin |
+ |------------------------------|
+ |RowLabelWin | MainWin |
+ | | |
+ --------------------------------
+ */
+ CornerWin* cornerWin_;
+ RowLabelWin* rowLabelWin_;
+ ColLabelWin* colLabelWin_;
+ MainWin* mainWin_;
+
+ ScrollBarStatus showScrollbarX_ = SB_SHOW_AUTOMATIC;
+ ScrollBarStatus showScrollbarY_ = SB_SHOW_AUTOMATIC;
+
+ int colLabelHeight_ = 0;
+ bool drawRowLabel_ = true;
+
+ std::shared_ptr<GridData> dataView_;
+ Selection selection_;
+ bool allowColumnMove_ = true;
+ bool allowColumnResize_ = true;
+
+ std::vector<VisibleColumn> visibleCols_; //individual widths, type and total column count
+ std::vector<ColumnAttribute> oldColAttributes_; //visible + nonvisible columns; use for conversion in setColumnConfig()/getColumnConfig() *only*!
+
+ size_t rowCountOld_ = 0; //at the time of last Grid::Refresh()
+};
+}
+
+#endif //GRID_H_834702134831734869987
|