summaryrefslogtreecommitdiff
path: root/wx+/grid.cpp
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:27:42 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:27:42 +0200
commitb916407a2a06f8452e82b74dc44c54acbcc572b0 (patch)
tree46358e0bb035fca0f42edb4b5b8aa5f1613814af /wx+/grid.cpp
parent5.20 (diff)
downloadFreeFileSync-b916407a2a06f8452e82b74dc44c54acbcc572b0.tar.gz
FreeFileSync-b916407a2a06f8452e82b74dc44c54acbcc572b0.tar.bz2
FreeFileSync-b916407a2a06f8452e82b74dc44c54acbcc572b0.zip
5.21
Diffstat (limited to 'wx+/grid.cpp')
-rw-r--r--wx+/grid.cpp317
1 files changed, 171 insertions, 146 deletions
diff --git a/wx+/grid.cpp b/wx+/grid.cpp
index c8d418ee..c9dfbbe9 100644
--- a/wx+/grid.cpp
+++ b/wx+/grid.cpp
@@ -17,8 +17,6 @@
#include <zen/scope_guard.h>
#include <zen/utf.h>
#include <zen/format_unit.h>
-//#include "image_tools.h"
-//#include "rtl.h"
#include "dc.h"
#ifdef ZEN_LINUX
@@ -90,11 +88,11 @@ void GridData::renderCell(Grid& grid, wxDC& dc, const wxRect& rect, size_t row,
rectTmp.x += COLUMN_BORDER_LEFT;
rectTmp.width -= COLUMN_BORDER_LEFT;
- drawCellText(dc, rectTmp, getValue(row, colType), grid.IsEnabled());
+ drawCellText(dc, rectTmp, getValue(row, colType), true);
}
-size_t GridData::getBestSize(wxDC& dc, size_t row, ColumnType colType)
+int GridData::getBestSize(wxDC& dc, size_t row, ColumnType colType)
{
return dc.GetTextExtent(getValue(row, colType)).GetWidth() + 2 * COLUMN_BORDER_LEFT; //some border on left and right side
}
@@ -131,9 +129,6 @@ void GridData::drawCellBackground(wxDC& dc, const wxRect& rect, bool enabled, bo
namespace
{
-#ifdef _MSC_VER
-#pragma warning(disable:4428) // VC wrongly issues warning C4428: universal-character-name encountered in source
-#endif
const wchar_t ELLIPSIS = L'\u2026'; //...
template <class Function> inline
@@ -262,11 +257,7 @@ public:
//SetDoubleBuffered(true); slow as hell!
-#if wxCHECK_VERSION(2, 9, 1)
SetBackgroundStyle(wxBG_STYLE_PAINT);
-#else
- SetBackgroundStyle(wxBG_STYLE_CUSTOM);
-#endif
Connect(wxEVT_SET_FOCUS, wxFocusEventHandler(SubWindow::onFocus), nullptr, this);
Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler(SubWindow::onFocus), nullptr, this);
@@ -434,7 +425,7 @@ public:
wxClientDC dc(this);
wxFont labelFont = GetFont();
- labelFont.SetWeight(wxFONTWEIGHT_BOLD);
+ //labelFont.SetWeight(wxFONTWEIGHT_BOLD);
dc.SetFont(labelFont); //harmonize with RowLabelWin::render()!
int bestWidth = 0;
@@ -455,8 +446,8 @@ public:
return -1;
}
- ptrdiff_t getRowHeight() const { return std::max<ptrdiff_t>(1, rowHeight); } //guarantees to return size >= 1 !
- void setRowHeight(size_t height) { rowHeight = height; }
+ int getRowHeight() const { return std::max(1, rowHeight); } //guarantees to return size >= 1 !
+ void setRowHeight(int height) { rowHeight = height; }
wxRect getRowLabelArea(ptrdiff_t row) const
{
@@ -470,7 +461,7 @@ public:
const int yFrom = refParent().CalcUnscrolledPosition(clientRect.GetTopLeft ()).y;
const int yTo = refParent().CalcUnscrolledPosition(clientRect.GetBottomRight()).y;
- return std::make_pair(std::max<ptrdiff_t>(yFrom / rowHeight, 0),
+ return std::make_pair(std::max(yFrom / rowHeight, 0),
std::min<ptrdiff_t>((yTo / rowHeight) + 1, refParent().getRowCount()));
}
@@ -481,13 +472,32 @@ private:
virtual void render(wxDC& dc, const wxRect& rect)
{
- if (IsEnabled())
+
+ /*
+ IsEnabled() vs IsThisEnabled() since wxWidgets 2.9.5:
+
+ void wxWindowBase::NotifyWindowOnEnableChange(), called from bool wxWindowBase::Enable(), has this buggy exception of NOT
+ refreshing child elements when disabling a IsTopLevel() dialog, e.g. when showing a modal dialog.
+ The unfortunate effect on XP for using IsEnabled() when rendering the grid is that the user can move the modal dialog
+ and *draw* with it on the background while the grid refreshes as disabled incrementally!
+
+ => Don't use IsEnabled() since it considers the top level window. The brittle wxWidgets implementation is right in their intention,
+ but wrong when not refreshing child-windows: the control designer decides how his control should be rendered!
+
+ => IsThisEnabled() OTOH is too shallow and does not consider parent windows which are not top level.
+
+ The perfect solution would be a bool ShouldBeDrawnActive() { return "IsEnabled() but ignore effects of showing a modal dialog"; }
+
+ However "IsThisEnabled()" is good enough (same like the old IsEnabled() on wxWidgets 2.8.12) and it avoids this pathetic behavior on XP.
+ (Similar problem on Win 7: e.g. directly click sync button without comparing first)
+ */
+ if (IsThisEnabled())
clearArea(dc, rect, getColorMainWinBackground());
else
clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
wxFont labelFont = GetFont();
- labelFont.SetWeight(wxFONTWEIGHT_BOLD);
+ //labelFont.SetWeight(wxFONTWEIGHT_BOLD);
dc.SetFont(labelFont); //harmonize with RowLabelWin::getBestWidth()!
auto rowRange = getRowsOnClient(rect); //returns range [begin, end)
@@ -533,7 +543,7 @@ private:
virtual void onMouseMovement(wxMouseEvent& event) { refParent().redirectRowLabelEvent(event); }
virtual void onMouseLeftUp (wxMouseEvent& event) { refParent().redirectRowLabelEvent(event); }
- ptrdiff_t rowHeight;
+ int rowHeight;
};
@@ -542,7 +552,7 @@ namespace
class ColumnResizing
{
public:
- ColumnResizing(wxWindow& wnd, size_t col, size_t compPos, ptrdiff_t startWidth, int clientPosX) :
+ ColumnResizing(wxWindow& wnd, size_t col, size_t compPos, int startWidth, int clientPosX) :
wnd_(wnd), col_(col), compPos_(compPos), startWidth_(startWidth), clientPosX_(clientPosX)
{
wnd_.CaptureMouse();
@@ -553,17 +563,17 @@ public:
wnd_.ReleaseMouse();
}
- size_t getColumn () const { return col_; }
- size_t getComponentPos() const { return compPos_; }
- ptrdiff_t getStartWidth () const { return startWidth_; }
- int getStartPosX () const { return clientPosX_; }
+ size_t getColumn () const { return col_; }
+ size_t getComponentPos() const { return compPos_; }
+ int getStartWidth () const { return startWidth_; }
+ int getStartPosX () const { return clientPosX_; }
private:
wxWindow& wnd_;
- const size_t col_;
- const size_t compPos_;
- const ptrdiff_t startWidth_;
- const int clientPosX_;
+ const size_t col_;
+ const size_t compPos_;
+ const int startWidth_;
+ const int clientPosX_;
};
@@ -609,7 +619,7 @@ private:
virtual void render(wxDC& dc, const wxRect& rect)
{
- if (IsEnabled())
+ if (IsThisEnabled())
clearArea(dc, rect, getColorMainWinBackground());
else
clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
@@ -676,7 +686,7 @@ private:
if (action->wantResize)
{
if (!event.LeftDClick()) //double-clicks never seem to arrive here; why is this checked at all???
- if (Opt<ptrdiff_t> colWidth = refParent().getColWidth(action->col, action->compPos))
+ if (Opt<int> colWidth = refParent().getColWidth(action->col, action->compPos))
activeResizing.reset(new ColumnResizing(*this, action->col, action->compPos, *colWidth, event.GetPosition().x));
}
else //a move or single click
@@ -732,7 +742,7 @@ private:
if (action->wantResize)
{
//auto-size visible range on double-click
- const ptrdiff_t bestWidth = refParent().getBestColumnSize(action->col, action->compPos); //return -1 on error
+ const int bestWidth = refParent().getBestColumnSize(action->col, action->compPos); //return -1 on error
if (bestWidth >= 0)
{
refParent().setColWidthAndNotify(bestWidth, action->col, action->compPos);
@@ -748,8 +758,7 @@ private:
{
const auto col = activeResizing->getColumn();
const auto compPos = activeResizing->getComponentPos();
-
- const ptrdiff_t newWidth = activeResizing->getStartWidth() + event.GetPosition().x - activeResizing->getStartPosX();
+ const int newWidth = activeResizing->getStartWidth() + event.GetPosition().x - activeResizing->getStartPosX();
//set width tentatively
refParent().setColWidthAndNotify(newWidth, col, compPos);
@@ -904,7 +913,7 @@ public:
private:
virtual void render(wxDC& dc, const wxRect& rect)
{
- if (IsEnabled())
+ if (IsThisEnabled())
clearArea(dc, rect, getColorMainWinBackground());
else
clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
@@ -927,8 +936,9 @@ private:
std::vector<std::vector<ColumnWidth>> compAbsWidths = refParent().getColWidths(); //resolve stretched widths
for (auto iterComp = compAbsWidths.begin(); iterComp != compAbsWidths.end(); ++iterComp)
{
- const ptrdiff_t compWidth = std::accumulate(iterComp->begin(), iterComp->end(), static_cast<ptrdiff_t>(0),
- [](ptrdiff_t sum, const ColumnWidth& cw) { return sum + cw.width_; });
+ int compWidth = 0;
+ for (const ColumnWidth& cw : *iterComp)
+ compWidth += cw.width_;
const size_t compPos = iterComp - compAbsWidths.begin();
if (auto prov = refParent().getDataProvider(compPos))
@@ -941,21 +951,19 @@ private:
}
//draw single cells, column by column
- for (auto iterCol = iterComp->begin(); iterCol != iterComp->end(); ++iterCol)
+ for (const ColumnWidth& cw : *iterComp)
{
- const int width = iterCol->width_; //don't use unsigned for calculations!
-
if (cellAreaTL.x > rect.GetRight())
return; //done
- if (cellAreaTL.x + width > rect.x)
+ if (cellAreaTL.x + cw.width_ > rect.x)
for (int row = rowFirst; row < rowLast; ++row)
{
- const wxRect& cellRect = wxRect(cellAreaTL.x, cellAreaTL.y + row * rowHeight, width, rowHeight);
+ const wxRect& cellRect = wxRect(cellAreaTL.x, cellAreaTL.y + row * rowHeight, cw.width_, rowHeight);
RecursiveDcClipper clip(dc, cellRect);
- prov->renderCell(refParent(), dc, cellRect, row, iterCol->type_);
+ prov->renderCell(refParent(), dc, cellRect, row, cw.type_);
}
- cellAreaTL.x += width;
+ cellAreaTL.x += cw.width_;
}
}
else
@@ -977,7 +985,7 @@ private:
drawSelection = activeSelection->isPositiveSelect(); //overwrite default
}
- prov.renderRowBackgound(dc, rect, row, grid.IsEnabled(), drawSelection, wxWindow::FindFocus() == &grid.getMainWin());
+ prov.renderRowBackgound(dc, rect, row, grid.IsThisEnabled(), drawSelection, wxWindow::FindFocus() == &grid.getMainWin());
}
virtual void onMouseLeftDown (wxMouseEvent& event) { onMouseDown(event); }
@@ -1158,8 +1166,8 @@ private:
numeric::confine<ptrdiff_t>(row, 0, rowCount - 1);
- auto& comp = refParent().comp;
- std::for_each(comp.begin(), comp.end(), [](Grid::Component& c) { c.selection.clear(); }); //clear selection, do NOT fire event
+ for (Grid::Component& c : refParent().comp)
+ c.selection.clear(); //clear selection, do NOT fire event
refParent().selectRangeAndNotify(selectionAnchor, row, cursor.second); //set new selection + fire event
cursor.first = row; //don't call setCursor() since it writes to "selectionAnchor"!
@@ -1418,7 +1426,7 @@ Grid::Grid(wxWindow* parent,
colLabelHeight(DEFAULT_COL_LABEL_HEIGHT),
drawRowLabel(true),
comp(1),
- colSizeOld(0)
+ rowCountOld(0)
{
Connect(wxEVT_PAINT, wxPaintEventHandler(Grid::onPaintEvent ), nullptr, this);
Connect(wxEVT_ERASE_BACKGROUND, wxEraseEventHandler(Grid::onEraseBackGround), nullptr, this);
@@ -1654,17 +1662,18 @@ size_t Grid::getRowCount() const
void Grid::Refresh(bool eraseBackground, const wxRect* rect)
{
const size_t rowCountNew = getRowCount();
- if (colSizeOld != rowCountNew)
+ if (rowCountOld != rowCountNew)
{
- colSizeOld = rowCountNew;
- std::for_each(comp.begin(), comp.end(), [&](Component& c) { c.selection.init(rowCountNew); });
+ rowCountOld = rowCountNew;
+ for (Component& c : comp)
+ c.selection.init(rowCountNew);
updateWindowSizes();
}
wxScrolledWindow::Refresh(eraseBackground, rect);
}
-void Grid::setRowHeight(size_t height)
+void Grid::setRowHeight(int height)
{
rowLabelWin_->setRowHeight(height);
updateWindowSizes();
@@ -1680,12 +1689,9 @@ void Grid::setColumnConfig(const std::vector<Grid::ColumnAttribute>& attr, size_
comp[compPos].oldColAttributes = attr;
std::vector<VisibleColumn> visibleCols;
- std::for_each(attr.begin(), attr.end(),
- [&](const ColumnAttribute& ca)
- {
+ for (const ColumnAttribute& ca : attr)
if (ca.visible_)
- visibleCols.push_back(Grid::VisibleColumn(ca.type_, ca.offset_, ca.stretch_));
- });
+ visibleCols.push_back(VisibleColumn(ca.type_, ca.offset_, ca.stretch_));
//"ownership" of visible columns is now within Grid
comp[compPos].visibleCols = visibleCols;
@@ -1707,9 +1713,7 @@ std::vector<Grid::ColumnAttribute> Grid::getColumnConfig(size_t compPos) const
auto iterVcolsend = comp[compPos].visibleCols.end();
//update visible columns but keep order of non-visible ones!
- std::for_each(output.begin(), output.end(),
- [&](ColumnAttribute& ca)
- {
+ for (ColumnAttribute& ca : output)
if (ca.visible_)
{
if (iterVcols != iterVcolsend)
@@ -1722,7 +1726,6 @@ std::vector<Grid::ColumnAttribute> Grid::getColumnConfig(size_t compPos) const
else
assert(false);
}
- });
assert(iterVcols == iterVcolsend);
return output;
@@ -1810,7 +1813,7 @@ void Grid::SetScrollbar(int orientation, int position, int thumbSize, int range,
break;
case SB_SHOW_ALWAYS:
- if (range <= 1) //scrollbars hidden if range == 0 or 1
+ if (range <= 1) //scrollbars would be hidden for range == 0 or 1!
wxScrolledWindow::SetScrollbar(orientation, 0, 199999, 200000, refresh);
else
wxScrolledWindow::SetScrollbar(orientation, position, thumbSize, range, refresh);
@@ -1825,10 +1828,6 @@ void Grid::SetScrollbar(int orientation, int position, int thumbSize, int range,
//get rid of scrollbars, but preserve scrolling behavior!
#ifdef ZEN_WIN
-#ifdef __MINGW32__ //MinGW is clueless...
-#define WM_MOUSEHWHEEL 0x020E
-#endif
-
WXLRESULT Grid::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
{
//we land here if wxWindowMSW::MSWWindowProc() couldn't handle the message
@@ -1873,15 +1872,13 @@ wxRect Grid::getColumnLabelArea(ColumnType colType, size_t compPos) const
auto iterCol = std::find_if(iterComp->begin(), iterComp->end(), [&](const ColumnWidth& cw) { return cw.type_ == colType; });
if (iterCol != iterComp->end())
{
- ptrdiff_t posX = std::accumulate(compAbsWidths.begin(), iterComp, static_cast<ptrdiff_t>(0),
- [](ptrdiff_t sum, const std::vector<ColumnWidth>& cols)
- {
- return sum + std::accumulate(cols.begin(), cols.end(), static_cast<ptrdiff_t>(0),
- [](ptrdiff_t val2, const ColumnWidth& cw) { return val2 + cw.width_; });
- });
+ ptrdiff_t posX = 0;
+ for (auto it = compAbsWidths.begin(); it != iterComp; ++it)
+ for (const ColumnWidth& cw : *it)
+ posX += cw.width_;
- posX += std::accumulate(iterComp->begin(), iterCol, static_cast<ptrdiff_t>(0),
- [](ptrdiff_t sum, const ColumnWidth& cw) { return sum + cw.width_; });
+ for (auto it = iterComp->begin(); it != iterCol; ++it)
+ posX += it->width_;
return wxRect(wxPoint(posX, 0), wxSize(iterCol->width_, colLabelHeight));
}
@@ -1895,19 +1892,16 @@ Opt<Grid::ColAction> Grid::clientPosToColumnAction(const wxPoint& pos) const
const int absPosX = CalcUnscrolledPosition(pos).x;
if (absPosX >= 0)
{
- ptrdiff_t accuWidth = 0;
+ int accuWidth = 0;
std::vector<std::vector<ColumnWidth>> compAbsWidths = getColWidths(); //resolve stretched widths
- for (auto iterComp = compAbsWidths.begin(); iterComp != compAbsWidths.end(); ++iterComp)
+ for (size_t compPos = 0; compPos < compAbsWidths.size(); ++compPos)
{
- const size_t compPos = iterComp - compAbsWidths.begin();
const int resizeTolerance = columnResizeAllowed(compPos) ? COLUMN_RESIZE_TOLERANCE : 0;
- for (auto iterCol = iterComp->begin(); iterCol != iterComp->end(); ++iterCol)
+ for (size_t col = 0; col < compAbsWidths[compPos].size(); ++col)
{
- const size_t col = iterCol - iterComp->begin();
-
- accuWidth += iterCol->width_;
+ accuWidth += compAbsWidths[compPos][col].width_;
if (std::abs(absPosX - accuWidth) < resizeTolerance)
{
ColAction out = {};
@@ -1956,16 +1950,14 @@ ptrdiff_t Grid::clientPosToMoveTargetColumn(const wxPoint& pos, size_t compPos)
auto iterComp = compAbsWidths.begin() + compPos;
const int absPosX = CalcUnscrolledPosition(pos).x;
- ptrdiff_t accuWidth = std::accumulate(compAbsWidths.begin(), iterComp, static_cast<ptrdiff_t>(0),
- [](ptrdiff_t sum, const std::vector<ColumnWidth>& cols)
- {
- return sum + std::accumulate(cols.begin(), cols.end(), static_cast<ptrdiff_t>(0),
- [](ptrdiff_t sum2, const ColumnWidth& cw) { return sum2 + cw.width_; });
- });
+ int accuWidth = 0;
+ for (auto it = compAbsWidths.begin(); it != iterComp; ++it)
+ for (const ColumnWidth& cw : *it)
+ accuWidth += cw.width_;
for (auto iterCol = iterComp->begin(); iterCol != iterComp->end(); ++iterCol)
{
- const ptrdiff_t width = iterCol->width_; //beware dreaded unsigned conversions!
+ const int width = iterCol->width_; //beware dreaded unsigned conversions!
accuWidth += width;
if (absPosX < accuWidth - width / 2)
@@ -1994,16 +1986,13 @@ Opt<std::pair<ColumnType, size_t>> Grid::getColumnAtPos(int posX) const
{
std::vector<std::vector<ColumnWidth>> compAbsWidths = getColWidths(); //resolve negative/stretched widths
- ptrdiff_t accWidth = 0;
- for (auto iterComp = compAbsWidths.begin(); iterComp != compAbsWidths.end(); ++iterComp)
- for (auto iterCol = iterComp->begin(); iterCol != iterComp->end(); ++iterCol)
+ int accWidth = 0;
+ for (size_t compPos = 0; compPos < compAbsWidths.size(); ++compPos)
+ for (const ColumnWidth& cw : compAbsWidths[compPos])
{
- accWidth += iterCol->width_;
+ accWidth += cw.width_;
if (posX < accWidth)
- {
- const size_t compPos = iterComp - compAbsWidths.begin();
- return std::make_pair(iterCol->type_, compPos);
- }
+ return std::make_pair(cw.type_, compPos);
}
}
return NoValue();
@@ -2025,7 +2014,8 @@ void Grid::setGridCursor(size_t row, size_t compPos)
mainWin_->setCursor(row, compPos);
mainWin_->makeRowVisible(row);
- std::for_each(comp.begin(), comp.end(), [](Grid::Component& c) { c.selection.clear(); }); //clear selection, do NOT fire event
+ for (Grid::Component& c : comp)
+ c.selection.clear(); //clear selection, do NOT fire event
selectRangeAndNotify(row, row, compPos); //set new selection + fire event
mainWin_->Refresh();
@@ -2114,7 +2104,7 @@ std::pair<size_t, size_t> Grid::getGridCursor() const
}
-ptrdiff_t Grid::getBestColumnSize(size_t col, size_t compPos) const
+int Grid::getBestColumnSize(size_t col, size_t compPos) const
{
if (compPos < comp.size())
{
@@ -2127,7 +2117,7 @@ ptrdiff_t Grid::getBestColumnSize(size_t col, size_t compPos) const
wxClientDC dc(mainWin_);
dc.SetFont(mainWin_->GetFont()); //harmonize with MainWin::render()
- size_t maxSize = 0;
+ int maxSize = 0;
auto rowRange = rowLabelWin_->getRowsOnClient(mainWin_->GetClientRect()); //returns range [begin, end)
for (auto row = rowRange.first; row < rowRange.second; ++row)
@@ -2140,22 +2130,25 @@ ptrdiff_t Grid::getBestColumnSize(size_t col, size_t compPos) const
}
-void Grid::setColWidthAndNotify(ptrdiff_t width, size_t col, size_t compPos, bool notifyAsync)
+void Grid::setColWidthAndNotify(int width, size_t col, size_t compPos, bool notifyAsync)
{
if (compPos < comp.size() && col < comp[compPos].visibleCols.size())
{
VisibleColumn& vcRs = comp[compPos].visibleCols[col];
- const int mainWinWidth = mainWin_->GetClientSize().GetWidth();
- const ptrdiff_t stretchTotal = getStretchTotal();
- const ptrdiff_t stretchedWithCol = getColStretchedWidth(vcRs.stretch_, stretchTotal, mainWinWidth);
-
- vcRs.offset_ = width - stretchedWithCol; //width := stretchedWidth + offset
+ const std::vector<std::vector<int>> stretchedWidths = getColStretchedWidths(mainWin_->GetClientSize().GetWidth());
+ if (stretchedWidths.size() != comp.size() || stretchedWidths[compPos].size() != comp[compPos].visibleCols.size())
+ {
+ assert(false);
+ return;
+ }
//CAVEATS:
//I. fixed-size columns: normalize offset so that resulting width is at least COLUMN_MIN_WIDTH: this is NOT enforced by getColWidths()!
//II. stretched columns: do not allow user to set offsets so small that they result in negative (non-normalized) widths: this gives an
//unusual delay when enlarging the column again later
- vcRs.offset_ = std::max(vcRs.offset_, COLUMN_MIN_WIDTH - stretchedWithCol);
+ width = std::max(width, COLUMN_MIN_WIDTH);
+
+ vcRs.offset_ = width - stretchedWidths[compPos][col]; //width := stretchedWidth + offset
//III. resizing any column should normalize *all* other stretched columns' offsets considering current mainWinWidth!
// test case:
@@ -2163,17 +2156,13 @@ void Grid::setColWidthAndNotify(ptrdiff_t width, size_t col, size_t compPos, boo
//2. shrink main window width so that horizontal scrollbars are shown despite the streched column
//3. shrink a fixed-size column so that the scrollbars vanish and columns cover full width again
//4. now verify that the stretched column is resizing immediately if main window is enlarged again
- std::for_each(comp.begin(), comp.end(), [&](Component& c)
+ for (size_t compPos2 = 0; compPos2 < comp.size(); ++compPos2)
{
- std::for_each(c.visibleCols.begin(), c.visibleCols.end(), [&](VisibleColumn& vc)
- {
- if (vc.stretch_ > 0) //normalize stretched columns only
- {
- const ptrdiff_t stretchedWidth = Grid::getColStretchedWidth(vc.stretch_, stretchTotal, mainWinWidth);
- vc.offset_ = std::max(vc.offset_, COLUMN_MIN_WIDTH - stretchedWidth);
- }
- });
- });
+ auto& visibleCols = comp[compPos2].visibleCols;
+ for (size_t col2 = 0; col2 < visibleCols.size(); ++col2)
+ if (visibleCols[col2].stretch_ > 0) //normalize stretched columns only
+ visibleCols[col2].offset_ = std::max(visibleCols[col2].offset_, COLUMN_MIN_WIDTH - stretchedWidths[compPos2][col2]);
+ }
GridColumnResizeEvent sizeEvent(vcRs.offset_, vcRs.type_, compPos);
if (wxEvtHandler* evtHandler = GetEventHandler())
@@ -2194,10 +2183,9 @@ void Grid::autoSizeColumns(size_t compPos)
if (compPos < comp.size() && comp[compPos].allowColumnResize)
{
auto& visibleCols = comp[compPos].visibleCols;
- for (auto it = visibleCols.begin(); it != visibleCols.end(); ++it)
+ for (size_t col = 0; col < visibleCols.size(); ++col)
{
- const size_t col = it - visibleCols.begin();
- const ptrdiff_t bestWidth = getBestColumnSize(col, compPos); //return -1 on error
+ const int bestWidth = getBestColumnSize(col, compPos); //return -1 on error
if (bestWidth >= 0)
setColWidthAndNotify(bestWidth, col, compPos, true);
}
@@ -2207,20 +2195,55 @@ void Grid::autoSizeColumns(size_t compPos)
}
-ptrdiff_t Grid::getStretchTotal() const //sum of all stretch factors
+std::vector<std::vector<int>> Grid::getColStretchedWidths(int clientWidth) const //final width = (normalized) (stretchedWidth + offset)
{
- return std::accumulate(comp.begin(), comp.end(), static_cast<ptrdiff_t>(0),
- [](ptrdiff_t sum, const Component& c)
+ assert(clientWidth >= 0);
+ clientWidth = std::max(clientWidth, 0);
+ int stretchTotal = 0;
+ for (const Component& c : comp)
+ for (const VisibleColumn& vc : c.visibleCols)
+ {
+ assert(vc.stretch_ >= 0);
+ stretchTotal += vc.stretch_;
+ }
+
+ int remainingWidth = clientWidth;
+
+ std::vector<std::vector<int>> output;
+ for (const Component& c : comp)
{
- return sum + std::accumulate(c.visibleCols.begin(), c.visibleCols.end(), static_cast<ptrdiff_t>(0),
- [](ptrdiff_t val2, const Grid::VisibleColumn& vc) { return val2 + vc.stretch_; });
- });
-}
+ output.push_back(std::vector<int>());
+ auto& compWidths = output.back();
+ if (stretchTotal <= 0)
+ compWidths.resize(c.visibleCols.size()); //fill with zeros
+ else
+ for (const VisibleColumn& vc : c.visibleCols)
+ {
+ const int width = clientWidth * vc.stretch_ / stretchTotal; //rounds down!
+ compWidths.push_back(width);
+ remainingWidth -= width;
+ }
+ }
-ptrdiff_t Grid::getColStretchedWidth(ptrdiff_t stretch, ptrdiff_t stretchTotal, int mainWinWidth) //final width := stretchedWidth + (normalized) offset
-{
- return stretchTotal > 0 ? mainWinWidth * stretch / stretchTotal : 0; //rounds down! => not all of clientWidth is correctly distributed according to stretch factors
+ //distribute *all* of clientWidth: should suffice to enlarge the first few stretched columns; no need to minimize total absolute error of distribution
+ if (stretchTotal > 0)
+ if (remainingWidth > 0)
+ {
+ for (size_t compPos2 = 0; compPos2 < comp.size(); ++compPos2)
+ {
+ auto& visibleCols = comp[compPos2].visibleCols;
+ for (size_t col2 = 0; col2 < visibleCols.size(); ++col2)
+ if (visibleCols[col2].stretch_ > 0)
+ {
+ ++output[compPos2][col2];
+ if (--remainingWidth == 0)
+ return output;
+ }
+ }
+ assert(false);
+ }
+ return output;
}
@@ -2232,39 +2255,41 @@ std::vector<std::vector<Grid::ColumnWidth>> Grid::getColWidths() const
std::vector<std::vector<Grid::ColumnWidth>> Grid::getColWidths(int mainWinWidth) const //evaluate stretched columns; structure matches "comp"
{
- std::vector<std::vector<ColumnWidth>> output;
+ const std::vector<std::vector<int>> stretchedWidths = getColStretchedWidths(mainWinWidth);
+ assert(stretchedWidths.size() == comp.size());
- const ptrdiff_t stretchTotal = getStretchTotal();
+ std::vector<std::vector<ColumnWidth>> output;
- std::for_each(comp.begin(), comp.end(), [&](const Component& c)
+ for (size_t compPos2 = 0; compPos2 < comp.size(); ++compPos2)
{
+ assert(stretchedWidths[compPos2].size() == comp[compPos2].visibleCols.size());
+
output.push_back(std::vector<ColumnWidth>());
auto& compWidths = output.back();
- std::for_each(c.visibleCols.begin(), c.visibleCols.end(), [&](const VisibleColumn& vc)
+ auto& visibleCols = comp[compPos2].visibleCols;
+ for (size_t col2 = 0; col2 < visibleCols.size(); ++col2)
{
- ptrdiff_t widthNormalized = Grid::getColStretchedWidth(vc.stretch_, stretchTotal, mainWinWidth) + vc.offset_;
+ const auto& vc = visibleCols[col2];
+ int width = stretchedWidths[compPos2][col2] + vc.offset_;
if (vc.stretch_ > 0)
- widthNormalized = std::max(widthNormalized, static_cast<ptrdiff_t>(COLUMN_MIN_WIDTH)); //normalization really needed here: e.g. smaller main window would result in negative width
+ width = std::max(width, COLUMN_MIN_WIDTH); //normalization really needed here: e.g. smaller main window would result in negative width
else
- widthNormalized = std::max(widthNormalized, static_cast<ptrdiff_t>(0)); //support smaller width than COLUMN_MIN_WIDTH if set via configuration
+ width = std::max(width, 0); //support smaller width than COLUMN_MIN_WIDTH if set via configuration
- compWidths.push_back(Grid::ColumnWidth(vc.type_, widthNormalized));
- });
- });
+ compWidths.push_back(ColumnWidth(vc.type_, width));
+ }
+ }
return output;
}
-ptrdiff_t Grid::getColWidthsSum(int mainWinWidth) const
+int Grid::getColWidthsSum(int mainWinWidth) const
{
- auto widths = getColWidths(mainWinWidth);
- return std::accumulate(widths.begin(), widths.end(), static_cast<ptrdiff_t>(0),
- [](ptrdiff_t sum, const std::vector<Grid::ColumnWidth>& cols)
- {
- return sum + std::accumulate(cols.begin(), cols.end(), static_cast<ptrdiff_t>(0),
- [](ptrdiff_t val2, const Grid::ColumnWidth& cw) { return val2 + cw.width_; });
- });
+ int sum = 0;
+ for (const std::vector<ColumnWidth>& cols : getColWidths(mainWinWidth))
+ for (const ColumnWidth& cw : cols)
+ sum += cw.width_;
+ return sum;
};
-
bgstack15