diff options
author | Daniel Wilhelm <shieldwed@outlook.com> | 2017-04-20 16:55:28 -0600 |
---|---|---|
committer | Daniel Wilhelm <shieldwed@outlook.com> | 2017-04-20 16:59:56 -0600 |
commit | 823740e1ffa2b3bd39f8dea8062f5c5a0d9c741b (patch) | |
tree | 63222010af3b90a36f29c1c9c360116973cdff38 /wx+/grid.h | |
parent | add .gitattributes for less line ending hassles (diff) | |
download | FreeFileSync-823740e1ffa2b3bd39f8dea8062f5c5a0d9c741b.tar.gz FreeFileSync-823740e1ffa2b3bd39f8dea8062f5c5a0d9c741b.tar.bz2 FreeFileSync-823740e1ffa2b3bd39f8dea8062f5c5a0d9c741b.zip |
normalize most lineendings
Diffstat (limited to 'wx+/grid.h')
-rwxr-xr-x | wx+/grid.h | 726 |
1 files changed, 363 insertions, 363 deletions
@@ -1,363 +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
-
-
- 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 |