From 48c8efc58c9eb41da96b053806deb395d2e66443 Mon Sep 17 00:00:00 2001 From: Daniel Wilhelm Date: Wed, 9 May 2018 00:07:47 +0200 Subject: 9.7 --- wx+/grid.h | 151 +++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 101 insertions(+), 50 deletions(-) (limited to 'wx+/grid.h') diff --git a/wx+/grid.h b/wx+/grid.h index 14006205..8b916f2f 100755 --- a/wx+/grid.h +++ b/wx+/grid.h @@ -28,7 +28,7 @@ extern const wxEventType EVENT_GRID_MOUSE_LEFT_UP; //generates: GridClickEve 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 +extern const wxEventType EVENT_GRID_SELECT_RANGE; //generates: GridSelectEvent //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 @@ -41,54 +41,60 @@ 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); } + GridClickEvent* 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 +struct MouseSelect { - GridRangeSelectEvent(size_t rowFirst, size_t rowLast, bool positive, const GridClickEvent* mouseInitiated) : + GridClickEvent click; + bool complete = false; //false if this is a preliminary "clear range" event for mouse-down, before the actual selection has happened during mouse-up +}; + +struct GridSelectEvent : public wxCommandEvent +{ + GridSelectEvent(size_t rowFirst, size_t rowLast, bool positive, const MouseSelect* mouseSelect) : wxCommandEvent(EVENT_GRID_SELECT_RANGE), rowFirst_(rowFirst), rowLast_(rowLast), positive_(positive), - mouseInitiated_(mouseInitiated ? *mouseInitiated : Opt()) { assert(rowFirst <= rowLast); } - wxEvent* Clone() const override { return new GridRangeSelectEvent(*this); } + mouseSelect_(mouseSelect ? *mouseSelect : Opt()) { assert(rowFirst <= rowLast); } + GridSelectEvent* Clone() const override { return new GridSelectEvent(*this); } const size_t rowFirst_; //selected range: [rowFirst_, rowLast_) const size_t rowLast_; const bool positive_; //"false" when clearing selection! - Opt mouseInitiated_; //filled unless selection was performed via keyboard shortcuts or is result of Grid::clearSelection() + const Opt mouseSelect_; //filled unless selection was performed via keyboard shortcuts }; 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); } + GridLabelClickEvent* 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); } + GridColumnResizeEvent* Clone() const override { return new GridColumnResizeEvent(*this); } const ColumnType colType_; const int offset_; }; using GridClickEventFunction = void (wxEvtHandler::*)(GridClickEvent&); -using GridRangeSelectEventFunction = void (wxEvtHandler::*)(GridRangeSelectEvent&); +using GridSelectEventFunction = void (wxEvtHandler::*)(GridSelectEvent&); 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 GridClickEventHandler(func) (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(GridClickEventFunction, &func) +#define GridSelectEventHandler(func) (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(GridSelectEventFunction, &func) +#define GridLabelClickEventHandler(func) (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(GridLabelClickEventFunction, &func) #define GridColumnResizeEventHandler(func)(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(GridColumnResizeEventFunction, &func) //------------------------------------------------------------------------------------------------------------ + class Grid; @@ -146,19 +152,18 @@ public: void setRowHeight(int height); - struct ColumnAttribute + struct ColAttributes { - 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_; + ColumnType type = ColumnType::NONE; //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_; + int offset = 0; + int stretch = 0; //>= 0 + bool visible = false; }; - void setColumnConfig(const std::vector& attr); //set column count + widths - std::vector getColumnConfig() const; + void setColumnConfig(const std::vector& attr); //set column count + widths + std::vector getColumnConfig() const; void setDataProvider(const std::shared_ptr& dataView) { dataView_ = dataView; } /**/ GridData* getDataProvider() { return dataView_.get(); } @@ -178,8 +183,9 @@ public: void showScrollBars(ScrollBarStatus horizontal, ScrollBarStatus vertical); std::vector 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 selectRow(size_t row, GridEventPolicy rangeEventPolicy); + void selectAllRows (GridEventPolicy rangeEventPolicy); //turn off range selection event when calling this function in an event handler to avoid recursion! + void clearSelection(GridEventPolicy rangeEventPolicy) { clearSelectionImpl(nullptr /*mouseSelect*/, rangeEventPolicy); } // void scrollDelta(int deltaX, int deltaY); //in scroll units @@ -193,9 +199,9 @@ public: struct ColumnPosInfo { - ColumnType colType; //ColumnType::NONE no column at x position! - int cellRelativePosX; - int colWidth; + ColumnType colType = ColumnType::NONE; //ColumnType::NONE no column at x position! + int cellRelativePosX = 0; + int colWidth = 0; }; ColumnPosInfo getColumnAtPos(int posX) const; //absolute position! @@ -208,6 +214,9 @@ public: size_t getGridCursor() const; //returns row void scrollTo(size_t row); + size_t getTopRow() const; + + void makeRowVisible(size_t row); void Refresh(bool eraseBackground = true, const wxRect* rect = nullptr) override; bool Enable(bool enable = true) override; @@ -226,7 +235,6 @@ private: void updateWindowSizes(bool updateScrollbar = true); void selectWithCursor(ptrdiff_t row); - void makeRowVisible(size_t row); void redirectRowLabelEvent(wxMouseEvent& event); @@ -247,53 +255,52 @@ private: class Selection { public: - void init(size_t rowCount) { rowSelectionValue.resize(rowCount); clear(); } + void init(size_t rowCount) { selected_.resize(rowCount); clear(); } - size_t maxSize() const { return rowSelectionValue.size(); } + size_t maxSize() const { return selected_.size(); } std::vector get() const { std::vector result; - for (size_t row = 0; row < rowSelectionValue.size(); ++row) - if (rowSelectionValue[row] != 0) + for (size_t row = 0; row < selected_.size(); ++row) + if (selected_[row] != 0) result.push_back(row); return result; } - void selectAll() { selectRange(0, rowSelectionValue.size(), true); } - void clear () { selectRange(0, rowSelectionValue.size(), false); } + void selectRow(size_t row) { selectRange(row, row + 1, true); } + void selectAll () { selectRange(0, selected_.size(), true); } + void clear () { selectRange(0, selected_.size(), false); } - bool isSelected(size_t row) const { return row < rowSelectionValue.size() ? rowSelectionValue[row] != 0 : false; } + bool isSelected(size_t row) const { return row < selected_.size() ? selected_[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(rowFirst, 0, rowSelectionValue.size()); - numeric::clamp(rowLast, 0, rowSelectionValue.size()); + numeric::clamp(rowFirst, 0, selected_.size()); + numeric::clamp(rowLast, 0, selected_.size()); - std::fill(rowSelectionValue.begin() + rowFirst, rowSelectionValue.begin() + rowLast, positive); + std::fill(selected_.begin() + rowFirst, selected_.begin() + rowLast, positive); } else assert(false); } private: - std::vector rowSelectionValue; //effectively a vector of size "number of rows" + std::vector selected_; //effectively a vector 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_; + ColumnType type = ColumnType::NONE; + int offset = 0; + int stretch = 0; //>= 0 }; struct ColumnWidth { - ColumnWidth(ColumnType type, int width) : type_(type), width_(width) {} - ColumnType type_; - int width_; + ColumnType type = ColumnType::NONE; + int width = 0; }; std::vector getColWidths() const; // std::vector getColWidths(int mainWinWidth) const; //evaluate stretched columns @@ -304,7 +311,7 @@ private: { const auto& widths = getColWidths(); if (col < widths.size()) - return widths[col].width_; + return widths[col].width; return NoValue(); } @@ -312,7 +319,9 @@ private: 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! + void selectRangeAndNotify(ptrdiff_t rowFrom, ptrdiff_t rowTo, bool positive, const MouseSelect* mouseSelect); //select inclusive range [rowFrom, rowTo] + notify event! + + void clearSelectionImpl(const MouseSelect* mouseSelect, GridEventPolicy rangeEventPolicy); bool isSelected(size_t row) const { return selection_.isSelected(row); } @@ -352,11 +361,53 @@ private: bool allowColumnMove_ = true; bool allowColumnResize_ = true; - std::vector visibleCols_; //individual widths, type and total column count - std::vector oldColAttributes_; //visible + nonvisible columns; use for conversion in setColumnConfig()/getColumnConfig() *only*! + std::vector visibleCols_; //individual widths, type and total column count + std::vector oldColAttributes_; //visible + nonvisible columns; use for conversion in setColumnConfig()/getColumnConfig() *only*! size_t rowCountOld_ = 0; //at the time of last Grid::Refresh() }; + +//------------------------------------------------------------------------------------------------------------ + +template +std::vector makeConsistent(const std::vector& attribs, const std::vector& defaults) +{ + using ColTypeReal = decltype(ColAttrReal().type); + std::vector output; + + std::set usedTypes; //remove duplicates + auto appendUnique = [&](const std::vector& attr) + { + std::copy_if(attr.begin(), attr.end(), std::back_inserter(output), + [&](const ColAttrReal& a) { return usedTypes.insert(a.type).second; }); + }; + appendUnique(attribs); + appendUnique(defaults); //make sure each type is existing! + + return output; +} + + +template +std::vector convertColAttributes(const std::vector& attribs, const std::vector& defaults) +{ + std::vector output; + for (const ColAttrReal& ca : makeConsistent(attribs, defaults)) + output.push_back({ static_cast(ca.type), ca.offset, ca.stretch, ca.visible }); + return output; +} + + +template +std::vector convertColAttributes(const std::vector& attribs) +{ + using ColTypeReal = decltype(ColAttrReal().type); + + std::vector output; + for (const Grid::ColAttributes& ca : attribs) + output.push_back({ static_cast(ca.type), ca.offset, ca.stretch, ca.visible }); + return output; +} } #endif //GRID_H_834702134831734869987 -- cgit