summaryrefslogtreecommitdiff
path: root/wx+/grid.h
diff options
context:
space:
mode:
Diffstat (limited to 'wx+/grid.h')
-rwxr-xr-x[-rw-r--r--]wx+/grid.h729
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
bgstack15