summaryrefslogtreecommitdiff
path: root/ui/custom_grid.cpp
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:22:18 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:22:18 +0200
commitbcc5cc28c6dc5178e8f4fd0cc521034ae5def388 (patch)
treebacc60d27b435d32172f97643576c5e4e953177d /ui/custom_grid.cpp
parent5.9 (diff)
downloadFreeFileSync-bcc5cc28c6dc5178e8f4fd0cc521034ae5def388.tar.gz
FreeFileSync-bcc5cc28c6dc5178e8f4fd0cc521034ae5def388.tar.bz2
FreeFileSync-bcc5cc28c6dc5178e8f4fd0cc521034ae5def388.zip
5.10
Diffstat (limited to 'ui/custom_grid.cpp')
-rw-r--r--ui/custom_grid.cpp80
1 files changed, 49 insertions, 31 deletions
diff --git a/ui/custom_grid.cpp b/ui/custom_grid.cpp
index e7152905..975dca5a 100644
--- a/ui/custom_grid.cpp
+++ b/ui/custom_grid.cpp
@@ -11,6 +11,7 @@
#include <zen/file_error.h>
#include <zen/basic_math.h>
#include <zen/format_unit.h>
+#include <zen/scope_guard.h>
#include <wx+/tooltip.h>
#include <wx+/string_conv.h>
#include <wx+/rtl.h>
@@ -71,7 +72,7 @@ void refreshCell(Grid& grid, size_t row, ColumnType colType)
}
-std::pair<ptrdiff_t, ptrdiff_t> getVisibleRows(Grid& grid) //returns range [from, to)
+std::pair<ptrdiff_t, ptrdiff_t> getVisibleRows(const Grid& grid) //returns range [from, to)
{
const wxSize clientSize = grid.getMainWin().GetClientSize();
if (clientSize.GetHeight() > 0)
@@ -79,15 +80,15 @@ std::pair<ptrdiff_t, ptrdiff_t> getVisibleRows(Grid& grid) //returns range [from
wxPoint topLeft = grid.CalcUnscrolledPosition(wxPoint(0, 0));
wxPoint bottom = grid.CalcUnscrolledPosition(wxPoint(0, clientSize.GetHeight() - 1));
- ptrdiff_t rowFrom = grid.getRowAtPos(topLeft.y); //returns < 0 if column not found; absolute coordinates!
+ const ptrdiff_t rowCount = grid.getRowCount();
+ const ptrdiff_t rowFrom = grid.getRowAtPos(topLeft.y); //return -1 for invalid position, rowCount if out of range
if (rowFrom >= 0)
{
- ptrdiff_t rowEnd = grid.getRowAtPos(bottom.y); //returns < 0 if column not found; absolute coordinates!
- if (rowEnd < 0)
- rowEnd = grid.getRowCount();
+ const ptrdiff_t rowTo = grid.getRowAtPos(bottom.y);
+ if (0 <= rowTo && rowTo < rowCount)
+ return std::make_pair(rowFrom, rowTo + 1);
else
- ++rowEnd;
- return std::make_pair(rowFrom, rowEnd);
+ return std::make_pair(rowFrom, rowCount);
}
}
return std::make_pair(0, 0);
@@ -448,7 +449,6 @@ private:
static const int CELL_BORDER = 2;
-
virtual void renderCell(Grid& grid, wxDC& dc, const wxRect& rect, size_t row, ColumnType colType)
{
wxRect rectTmp = rect;
@@ -784,20 +784,20 @@ public:
if (static_cast<ColumnTypeMiddle>(colType) == COL_TYPE_MIDDLE_VALUE &&
row < refGrid().getRowCount())
{
- refGrid().clearSelection();
- dragSelection.reset(new std::pair<size_t, BlockPosition>(row, mousePosToBlock(clientPos, row)));
+ refGrid().clearSelection(false); //don't emit event, prevent recursion!
+ dragSelection = make_unique<std::pair<size_t, BlockPosition>>(row, mousePosToBlock(clientPos, row));
}
}
- void onSelectEnd(size_t rowFrom, size_t rowTo) //we cannot reuse row from "onSelectBegin": rowFrom and rowTo may be different if user is holding shift
+ void onSelectEnd(size_t rowFirst, size_t rowLast) //we cannot reuse row from "onSelectBegin": if user is holding shift, this may now be in the middle of the range!
{
- refGrid().clearSelection();
+ refGrid().clearSelection(false); //don't emit event, prevent recursion!
//issue custom event
if (dragSelection)
{
- if (rowFrom < refGrid().getRowCount() &&
- rowTo < refGrid().getRowCount()) //row is -1 on capture lost!
+ if (rowFirst < rowLast && //may be empty? probably not in this context
+ rowLast <= refGrid().getRowCount())
{
if (wxEvtHandler* evtHandler = refGrid().GetEventHandler())
switch (dragSelection->second)
@@ -807,25 +807,25 @@ public:
const FileSystemObject* fsObj = getRawData(dragSelection->first);
const bool setIncluded = fsObj ? !fsObj->isActive() : true;
- CheckRowsEvent evt(rowFrom, rowTo, setIncluded);
+ CheckRowsEvent evt(rowFirst, rowLast, setIncluded);
evtHandler->ProcessEvent(evt);
}
break;
case BLOCKPOS_LEFT:
{
- SyncDirectionEvent evt(rowFrom, rowTo, SYNC_DIR_LEFT);
+ SyncDirectionEvent evt(rowFirst, rowLast, SYNC_DIR_LEFT);
evtHandler->ProcessEvent(evt);
}
break;
case BLOCKPOS_MIDDLE:
{
- SyncDirectionEvent evt(rowFrom, rowTo, SYNC_DIR_NONE);
+ SyncDirectionEvent evt(rowFirst, rowLast, SYNC_DIR_NONE);
evtHandler->ProcessEvent(evt);
}
break;
case BLOCKPOS_RIGHT:
{
- SyncDirectionEvent evt(rowFrom, rowTo, SYNC_DIR_RIGHT);
+ SyncDirectionEvent evt(rowFirst, rowLast, SYNC_DIR_RIGHT);
evtHandler->ProcessEvent(evt);
}
break;
@@ -844,12 +844,13 @@ public:
}
else
{
- if (static_cast<ColumnTypeMiddle>(colType) == COL_TYPE_MIDDLE_VALUE)
+ if (static_cast<ColumnTypeMiddle>(colType) == COL_TYPE_MIDDLE_VALUE &&
+ row < refGrid().getRowCount())
{
if (highlight) //refresh old highlight
refreshCell(refGrid(), highlight->first, static_cast<ColumnType>(COL_TYPE_MIDDLE_VALUE));
- highlight.reset(new std::pair<size_t, BlockPosition>(row, mousePosToBlock(clientPos, row)));
+ highlight = make_unique<std::pair<size_t, BlockPosition>>(row, mousePosToBlock(clientPos, row));
refreshCell(refGrid(), highlight->first, static_cast<ColumnType>(COL_TYPE_MIDDLE_VALUE));
//show custom tooltip
@@ -1193,7 +1194,8 @@ public:
GridDataMiddle& provMiddle,
GridDataRight& provRight) :
gridL_(gridL), gridC_(gridC), gridR_(gridR), scrollMaster(nullptr),
- provLeft_(provLeft), provMiddle_(provMiddle), provRight_(provRight)
+ provLeft_(provLeft), provMiddle_(provMiddle), provRight_(provRight),
+ scrollbarUpdatePending(false)
{
gridL_.Connect(EVENT_GRID_COL_RESIZE, GridColumnResizeEventHandler(GridEventManager::onResizeColumnL), nullptr, this);
gridR_.Connect(EVENT_GRID_COL_RESIZE, GridColumnResizeEventHandler(GridEventManager::onResizeColumnR), nullptr, this);
@@ -1238,6 +1240,8 @@ public:
Connect(EVENT_ALIGN_SCROLLBARS, wxEventHandler(GridEventManager::onAlignScrollBars), NULL, this);
}
+ ~GridEventManager() { assert(!scrollbarUpdatePending); }
+
private:
void onCenterSelectBegin(GridClickEvent& event)
{
@@ -1248,15 +1252,14 @@ private:
void onCenterSelectEnd(GridRangeSelectEvent& event)
{
- if (event.positive_) //we do NOT want to react on GridRangeSelectEvent() within Grid::clearSelectionAll() directly following right mouse click!
- provMiddle_.onSelectEnd(event.rowFrom_, event.rowTo_);
+ provMiddle_.onSelectEnd(event.rowFirst_, event.rowLast_);
event.Skip();
}
void onCenterMouseMovement(wxMouseEvent& event)
{
const wxPoint& topLeftAbs = gridC_.CalcUnscrolledPosition(event.GetPosition());
- const int row = gridC_.getRowAtPos(topLeftAbs.y); //returns < 0 if column not found; absolute coordinates!
+ const ptrdiff_t row = gridC_.getRowAtPos(topLeftAbs.y); //return -1 for invalid position, rowCount if one past the end
if (auto colInfo = gridC_.getColumnAtPos(topLeftAbs.x)) //(column type, component position)
{
//redirect mouse movement to middle grid component
@@ -1277,7 +1280,7 @@ private:
void onGridSelection(const Grid& grid, Grid& other)
{
if (!wxGetKeyState(WXK_CONTROL)) //clear other grid unless user is holding CTRL
- other.clearSelection();
+ other.clearSelection(false); //don't emit event, prevent recursion!
}
void onKeyDownL(wxKeyEvent& event) { onKeyDown(event, gridL_); }
@@ -1397,13 +1400,22 @@ private:
//harmonize placement of horizontal scrollbar to avoid grids getting out of sync!
//since this affects the grid that is currently repainted as well, we do work asynchronously!
//avoids at least this problem: remaining graphics artifact when changing from Grid::SB_SHOW_ALWAYS to Grid::SB_SHOW_NEVER at location of old scrollbar (Windows only)
- wxCommandEvent alignEvent(EVENT_ALIGN_SCROLLBARS);
- AddPendingEvent(alignEvent); //waits until next idle event - may take up to a second if the app is busy on wxGTK!
+
+ //perf note: send one async event at most, else they may accumulate and create perf issues, see grid.cpp
+ if (!scrollbarUpdatePending)
+ {
+ scrollbarUpdatePending = true;
+ wxCommandEvent alignEvent(EVENT_ALIGN_SCROLLBARS);
+ AddPendingEvent(alignEvent); //waits until next idle event - may take up to a second if the app is busy on wxGTK!
+ }
}
void onAlignScrollBars(wxEvent& event)
{
- auto needsHorizontalScrollbars = [](Grid& grid) -> bool
+ ZEN_ON_SCOPE_EXIT(scrollbarUpdatePending = false);
+ assert(scrollbarUpdatePending);
+
+ auto needsHorizontalScrollbars = [](const Grid& grid) -> bool
{
const wxWindow& mainWin = grid.getMainWin();
return mainWin.GetVirtualSize().GetWidth() > mainWin.GetClientSize().GetWidth();
@@ -1433,6 +1445,8 @@ private:
GridDataLeft& provLeft_;
GridDataMiddle& provMiddle_;
GridDataRight& provRight_;
+
+ bool scrollbarUpdatePending;
};
}
@@ -1541,6 +1555,7 @@ private:
};
}
+
void gridview::setupIcons(Grid& gridLeft, Grid& gridCenter, Grid& gridRight, bool show, IconBuffer::IconSize sz)
{
auto* provLeft = dynamic_cast<GridDataLeft*>(gridLeft .getDataProvider());
@@ -1548,7 +1563,7 @@ void gridview::setupIcons(Grid& gridLeft, Grid& gridCenter, Grid& gridRight, boo
if (provLeft && provRight)
{
- int newRowHeight = 0;
+ int iconHeight = 0;
if (show)
{
auto iconMgr = std::make_shared<IconManager>(sz);
@@ -1556,14 +1571,17 @@ void gridview::setupIcons(Grid& gridLeft, Grid& gridCenter, Grid& gridRight, boo
provLeft ->setIconManager(iconMgr);
provRight->setIconManager(iconMgr);
- newRowHeight = iconMgr->iconBuffer.getSize() + 1; //+ 1 for line between rows
+ iconHeight = iconMgr->iconBuffer.getSize();
}
else
{
provLeft ->setIconManager(nullptr);
provRight->setIconManager(nullptr);
- newRowHeight = IconBuffer(IconBuffer::SIZE_SMALL).getSize() + 1; //+ 1 for line between rows
+ iconHeight = IconBuffer(IconBuffer::SIZE_SMALL).getSize();
}
+
+ const int newRowHeight = std::max(iconHeight, gridLeft.getMainWin().GetCharHeight()) + 1; //add some space
+
gridLeft .setRowHeight(newRowHeight);
gridCenter.setRowHeight(newRowHeight);
gridRight .setRowHeight(newRowHeight);
bgstack15