From 5535a4afbcd9ebfd18a2329ddb6f24ec28fd5bc6 Mon Sep 17 00:00:00 2001 From: Joris Goosen Date: Thu, 13 Jun 2024 15:36:48 +0200 Subject: [PATCH] Scroll faster (#5560) * make it go fast * even faster! * better mouseclick handling and now we can drag the data in editmode too! * clean up --- Common/timers.cpp | 5 +- .../components/JASP/Widgets/DataTableView.qml | 3 - .../JASP/Widgets/DataTableViewEdit.qml | 2 +- .../JASP/Widgets/DataTableViewItem.qml | 2 +- .../components/JASP/Widgets/JASPDataView.qml | 75 +------- .../JASP/Widgets/LabelEditorWindow.qml | 4 +- Desktop/qquick/datasetview.cpp | 166 +++++++++++++----- Desktop/qquick/datasetview.h | 10 +- 8 files changed, 143 insertions(+), 124 deletions(-) diff --git a/Common/timers.cpp b/Common/timers.cpp index 5d866aac68..e2a3e3f934 100644 --- a/Common/timers.cpp +++ b/Common/timers.cpp @@ -1,8 +1,9 @@ #include "timers.h" #ifdef PROFILE_JASP -#include - +#include +#include +#include static std::map * timers = nullptr; boost::timer::cpu_timer * _getTimer(std::string timerName) diff --git a/Desktop/components/JASP/Widgets/DataTableView.qml b/Desktop/components/JASP/Widgets/DataTableView.qml index e8ef078808..81186689a1 100644 --- a/Desktop/components/JASP/Widgets/DataTableView.qml +++ b/Desktop/components/JASP/Widgets/DataTableView.qml @@ -81,9 +81,6 @@ FocusScope cacheItems: true //!ribbonModel.dataMode maxColWidth: 250 * jaspTheme.uiScale expandDataSet: ribbonModel.dataMode - - doubleClickWorkaround: !ribbonModel.dataMode - //flickableInteractive: !ribbonModel.dataMode onDoubleClicked: __myRoot.doubleClicked() function showPopupMenu(fromItem, globalPos, rowIndex, columnIndex) diff --git a/Desktop/components/JASP/Widgets/DataTableViewEdit.qml b/Desktop/components/JASP/Widgets/DataTableViewEdit.qml index 617fb5bf7e..51f3090ddf 100644 --- a/Desktop/components/JASP/Widgets/DataTableViewEdit.qml +++ b/Desktop/components/JASP/Widgets/DataTableViewEdit.qml @@ -192,7 +192,7 @@ Item anchors.fill: parent acceptedButtons: Qt.RightButton - onPressed: (mouse) => + onClicked: (mouse) => { if(mouse.buttons & Qt.RightButton) dataTableView.showPopupMenu(editItemRoot, mapToGlobal(mouse.x, mouse.y), rowIndex, columnIndex); diff --git a/Desktop/components/JASP/Widgets/DataTableViewItem.qml b/Desktop/components/JASP/Widgets/DataTableViewItem.qml index 8b91ce8b52..806071cff1 100644 --- a/Desktop/components/JASP/Widgets/DataTableViewItem.qml +++ b/Desktop/components/JASP/Widgets/DataTableViewItem.qml @@ -85,7 +85,7 @@ Item toolTipTimeOut: 10000 toolTipDelay: 400 - onPressed: (mouse) => + onClicked: (mouse) => { if(ribbonModel.dataMode) { diff --git a/Desktop/components/JASP/Widgets/JASPDataView.qml b/Desktop/components/JASP/Widgets/JASPDataView.qml index c27b9dde50..cd968cd48b 100644 --- a/Desktop/components/JASP/Widgets/JASPDataView.qml +++ b/Desktop/components/JASP/Widgets/JASPDataView.qml @@ -14,7 +14,6 @@ FocusScope property string toolTip: "" property alias cursorShape: wheelCatcher.cursorShape property alias mouseArea: wheelCatcher - property bool doubleClickWorkaround: true property alias isMainDataViewer: theView.mainData readonly property alias editCoordinates: theView.editCoordinates @@ -52,6 +51,9 @@ FocusScope readonly property real flickableHeight: myFlickable.height property real contentFlickSize: 100 + + + signal doubleClicked() Keys.onUpPressed: (event) => { budgeUp(); event.accepted = true; } Keys.onLeftPressed: (event) => { budgeLeft(); event.accepted = true; } @@ -121,6 +123,7 @@ FocusScope contentHeight: theView.height contentWidth: theView.width + DataSetView { z: -10 @@ -147,79 +150,17 @@ FocusScope onSelectionBudgesRight: __JASPDataViewRoot.budgeRight() } } - /* + MouseArea { id: wheelCatcher anchors.fill: myFlickable - acceptedButtons: Qt.NoButton + acceptedButtons: Qt.LeftButton cursorShape: Qt.PointingHandCursor - z: 1000 - + z: -1000 + onDoubleClicked: __JASPDataViewRoot.doubleClicked() } - */ - - signal doubleClicked() - - JASPMouseAreaToolTipped - { - id: wheelCatcher - z: 1000 - anchors.fill: myFlickable - anchors.leftMargin: theView.rowNumberWidth - anchors.topMargin: theView.headerHeight - - toolTipText: __JASPDataViewRoot.doubleClickWorkaround ? qsTr("Double click to edit data") : "" - - acceptedButtons: __JASPDataViewRoot.doubleClickWorkaround ? Qt.LeftButton : Qt.NoButton - dragging: myFlickable.dragging - //hoverEnabled: !flickableInteractive - - property real lastTimeClicked: -1 - property real doubleClickTime: 400 - - onPressed: (mouse)=> - { - //console.log("doubleclick workaround pressed") - if(!__JASPDataViewRoot.doubleClickWorkaround) - { - mouse.accepted = false; - return; - } - - var curTime = new Date().getTime() - - if(lastTimeClicked === -1 || curTime - lastTimeClicked > doubleClickTime) - { - // console.log("doubleclick workaround pressed set time") - lastTimeClicked = curTime - mouse.accepted = false - } - else - { - // console.log("doubleclick workaround activated") - lastTimeClicked = -1 - __JASPDataViewRoot.doubleClicked() - } - } - onWheel: (wheel)=> - { - if(wheel.angleDelta.y == 120) - { - if(wheel.modifiers & Qt.ShiftModifier) horiScroller.scrollUp() - else vertiScroller.scrollUp() - } - else if(wheel.angleDelta.y == -120) - { - if(wheel.modifiers & Qt.ShiftModifier) horiScroller.scrollDown() - else vertiScroller.scrollDown() - } - else - wheel.accepted = false; - } - } - JASPScrollBar { id: vertiScroller; diff --git a/Desktop/components/JASP/Widgets/LabelEditorWindow.qml b/Desktop/components/JASP/Widgets/LabelEditorWindow.qml index d1fccfa72b..2898675d4d 100644 --- a/Desktop/components/JASP/Widgets/LabelEditorWindow.qml +++ b/Desktop/components/JASP/Widgets/LabelEditorWindow.qml @@ -43,9 +43,7 @@ FocusScope expandDataSet: false toolTip: qsTr("Edit the labels here or choose which values should be filtered out.") mouseArea.enabled: false - mouseArea.visible: false - //flickableInteractive: false - doubleClickWorkaround: false + mouseArea.visible: false Binding { diff --git a/Desktop/qquick/datasetview.cpp b/Desktop/qquick/datasetview.cpp index 7edafa81df..77557f99ce 100644 --- a/Desktop/qquick/datasetview.cpp +++ b/Desktop/qquick/datasetview.cpp @@ -247,7 +247,7 @@ void DataSetView::calculateCellSizesAndClear(bool clearStorage) _storedLineFlags.clear(); _storedDisplayText.clear(); - storeAllItems(); + storeAllItems(); //if(clearStorage) // clearCaches(); @@ -299,8 +299,8 @@ void DataSetView::calculateCellSizesAndClear(bool clearStorage) void DataSetView::viewportChangedDelayed() { - _delayViewportChangedTimer->start(); - //viewportChanged(); + //_delayViewportChangedTimer->start(); + viewportChanged(); } void DataSetView::viewportChanged() @@ -318,7 +318,7 @@ void DataSetView::viewportChanged() #endif determineCurrentViewPortIndices(); - storeAllItems(); + storeOutOfViewItems(); buildNewLinesAndCreateNewItems(); JASPTIMER_RESUME(DataSetView::updateCalledForRender); @@ -358,8 +358,8 @@ void DataSetView::determineCurrentViewPortIndices() if(_currentViewportColMax == -1) _currentViewportColMax = _model->columnCount(); - _currentViewportColMin = std::max(0, std::min(_model->columnCount(), _currentViewportColMin - _viewportMargin)); - _currentViewportColMax = std::max(0, std::min(_model->columnCount(), _currentViewportColMax + _viewportMargin)); + _currentViewportColMin = std::max(0, std::min(_model->columnCount(), _currentViewportColMin - _viewportMargin)); + _currentViewportColMax = std::max(0, std::min(_model->columnCount(), _currentViewportColMax + _viewportMargin)); _currentViewportRowMin = std::max(0, std::min(_model->rowCount(), qRound(leftTop.y() / _dataRowsMaxHeight) - (1 + _viewportMargin))); _currentViewportRowMax = std::max(0, std::min(_model->rowCount(), qRound(rightBottom.y() / _dataRowsMaxHeight) + (1 + _viewportMargin))); @@ -374,44 +374,122 @@ void DataSetView::determineCurrentViewPortIndices() void DataSetView::storeAllItems() { - JASPTIMER_SCOPE(DataSetView::storeAllItems); - - for(auto & subVec : _cellTextItems) - { - for(auto & intTextItem : subVec.second) - { - if(intTextItem.second) - { - intTextItem.second->item->setVisible(false); - - if (_cacheItems) _textItemStorage.push(intTextItem.second); - else delete intTextItem.second; - } - } - subVec.second.clear(); - } - - _cellTextItems.clear(); - - for(auto & intItem : _columnHeaderItems) - { - intItem.second->item->setVisible(false); - - if (_cacheItems) _columnHeaderStorage.push(intItem.second); - else delete intItem.second; - } - - _columnHeaderItems.clear(); - - for(auto & intItem : _rowNumberItems) - { - intItem.second->item->setVisible(false); - - if (_cacheItems) _rowNumberStorage.push(intItem.second); - else delete intItem.second; - } - - _rowNumberItems.clear(); + JASPTIMER_SCOPE(DataSetView::storeAllItems); + + for(auto & subVec : _cellTextItems) + { + for(auto & intTextItem : subVec.second) + { + if(intTextItem.second) + { + intTextItem.second->item->setVisible(false); + + if (_cacheItems) _textItemStorage.push(intTextItem.second); + else delete intTextItem.second; + } + } + subVec.second.clear(); + } + + _cellTextItems.clear(); + + for(auto & intItem : _columnHeaderItems) + { + intItem.second->item->setVisible(false); + + if (_cacheItems) _columnHeaderStorage.push(intItem.second); + else delete intItem.second; + } + + _columnHeaderItems.clear(); + + for(auto & intItem : _rowNumberItems) + { + intItem.second->item->setVisible(false); + + if (_cacheItems) _rowNumberStorage.push(intItem.second); + else delete intItem.second; + } + + _rowNumberItems.clear(); +} + +void DataSetView::storeOutOfViewItems() +{ + JASPTIMER_SCOPE(DataSetView::storeOutOfViewItems); + + { + ItemCxsByColRow cleanList; + + for(auto & subVec : _cellTextItems) + { + for(auto & intTextItem : subVec.second) + { + if(intTextItem.second) + { + int col = subVec.first, + row = intTextItem.first; + + if(col < _currentViewportColMin || col > _currentViewportColMax || row < _currentViewportRowMin || row > _currentViewportRowMax) + { + intTextItem.second->item->setVisible(false); + + if (_cacheItems) _textItemStorage.push(intTextItem.second); + else delete intTextItem.second; + } + else + { + cleanList[col][row] = intTextItem.second; + } + } + } + } + + _cellTextItems = cleanList ; + } + + { + ItemCxsByIndex cleanList; + + for(auto & intItem : _columnHeaderItems) + { + int col = intItem.first; + + if(col < _currentViewportColMin || col > _currentViewportColMax) + { + intItem.second->item->setVisible(false); + + if (_cacheItems) _columnHeaderStorage.push(intItem.second); + else delete intItem.second; + } + else + cleanList[col] = intItem.second; + } + + _columnHeaderItems = cleanList; + } + + + { + ItemCxsByIndex cleanList; + + for(auto & intItem : _rowNumberItems) + { + int row = intItem.first; + + if(row < _currentViewportRowMin || row > _currentViewportRowMax) + { + intItem.second->item->setVisible(false); + + if (_cacheItems) _rowNumberStorage.push(intItem.second); + else delete intItem.second; + } + else + cleanList[row] = intItem.second; + } + + _rowNumberItems = cleanList; + } } void DataSetView::addLine(float x0, float y0, float x1, float y1) diff --git a/Desktop/qquick/datasetview.h b/Desktop/qquick/datasetview.h index aec7d4eb84..86134c341e 100644 --- a/Desktop/qquick/datasetview.h +++ b/Desktop/qquick/datasetview.h @@ -41,6 +41,9 @@ struct ItemContextualized QQmlContext * context = nullptr; }; +typedef std::map> ItemCxsByColRow; +typedef std::map ItemCxsByIndex; + /// Custom QQuickItem to render data tables witch caching and only displaying the necessary cells and lines /// Supports scaling the data into millions of columns and rows without any noticable slowdowns (the model could slow it down though) /// Contains custom rendering code for the lines to make sure they are always a single pixel wide. @@ -275,7 +278,8 @@ public slots: void _copy(QPoint where, bool clear); void calculateCellSizesAndClear(bool clearStorage); void determineCurrentViewPortIndices(); - void storeAllItems(); + void storeAllItems(); + void storeOutOfViewItems(); void buildNewLinesAndCreateNewItems(); void columnIndexSelectedApply(int columnIndex, std::function applyThis); void columnIndexSelectedApply(int columnIndex, std::function applyThis); @@ -321,9 +325,9 @@ public slots: std::stack _textItemStorage, _rowNumberStorage, _columnHeaderStorage; - std::map _rowNumberItems, + ItemCxsByIndex _rowNumberItems, _columnHeaderItems; - std::map> _cellTextItems; //[col][row] + ItemCxsByColRow _cellTextItems; //[col][row] std::vector _lines; QQuickItem * _leftTopItem = nullptr, * _extraColumnItem = nullptr,