[Spreadsheet] Enable zoom in Spreadsheet (#16130)
* [Spreadsheet] Enable zoom in Spreadsheet Closes #6094. This commit also fixes page tab order of Spreadsheet settings in Preferences. * Spreadsheet: apply clang-format --------- Co-authored-by: Chris Hennes <chennes@pioneerlibrarysystem.org>
This commit is contained in:
231
src/Mod/Spreadsheet/Gui/ZoomableView.cpp
Normal file
231
src/Mod/Spreadsheet/Gui/ZoomableView.cpp
Normal file
@@ -0,0 +1,231 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2024 xtemp09 <xtemp09@gmail.com> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QGraphicsProxyWidget>
|
||||
|
||||
#include "ZoomableView.h"
|
||||
#include "ui_Sheet.h"
|
||||
|
||||
|
||||
ZoomableView::ZoomableView(Ui::Sheet* ui)
|
||||
: QGraphicsView {}
|
||||
, stv {ui->cells}
|
||||
{
|
||||
if (!stv) {
|
||||
Base::Console().DeveloperWarning("ZoomableView", "Failed to find a SheetTableView object");
|
||||
deleteLater();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
QLayoutItem* li_stv = stv->parentWidget()->layout()->replaceWidget(stv, this);
|
||||
if (li_stv == nullptr) {
|
||||
Base::Console().DeveloperWarning("ZoomableView",
|
||||
"Failed to replace the SheetTableView object");
|
||||
deleteLater();
|
||||
return;
|
||||
}
|
||||
delete li_stv;
|
||||
}
|
||||
|
||||
stv->setParent(nullptr);
|
||||
qpw = m_scene.addWidget(stv);
|
||||
setScene(&m_scene);
|
||||
|
||||
setBackgroundBrush(Qt::transparent);
|
||||
setFrameStyle(QFrame::NoFrame);
|
||||
|
||||
setSizePolicy(QSizePolicy {QSizePolicy::Expanding, QSizePolicy::Expanding});
|
||||
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
|
||||
stv->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
stv->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
|
||||
QPointer<QScrollBar> dummySB_h {stv->horizontalScrollBar()},
|
||||
dummySB_v {stv->verticalScrollBar()}, realSB_h {ui->realSB_h}, realSB_v {ui->realSB_v};
|
||||
|
||||
if (!dummySB_h || !dummySB_v || !realSB_h || !realSB_v) {
|
||||
Base::Console().DeveloperWarning("ZoomableView", "Failed to identify the scrollbars");
|
||||
deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
realSB_h->setRange(dummySB_h->minimum(), dummySB_h->maximum());
|
||||
realSB_v->setRange(dummySB_v->minimum(), dummySB_v->maximum());
|
||||
|
||||
realSB_h->setPageStep(dummySB_h->pageStep());
|
||||
realSB_v->setPageStep(dummySB_v->pageStep());
|
||||
|
||||
|
||||
connect(realSB_h, &QAbstractSlider::valueChanged, dummySB_h, &QAbstractSlider::setValue);
|
||||
connect(realSB_v, &QAbstractSlider::valueChanged, dummySB_v, &QAbstractSlider::setValue);
|
||||
|
||||
connect(dummySB_h, &QAbstractSlider::rangeChanged, realSB_h, &QAbstractSlider::setRange);
|
||||
connect(dummySB_v, &QAbstractSlider::rangeChanged, realSB_v, &QAbstractSlider::setRange);
|
||||
|
||||
connect(dummySB_h, &QAbstractSlider::valueChanged, this, &ZoomableView::updateView);
|
||||
connect(dummySB_v, &QAbstractSlider::valueChanged, this, &ZoomableView::updateView);
|
||||
|
||||
connect(this,
|
||||
&ZoomableView::zoomLevelChanged,
|
||||
ui->zoomTB,
|
||||
[zoomTB = ui->zoomTB](int new_zoomLevel) {
|
||||
zoomTB->setText(QStringLiteral("%1%").arg(new_zoomLevel));
|
||||
});
|
||||
|
||||
connect(this,
|
||||
&ZoomableView::zoomLevelChanged,
|
||||
ui->zoomSlider,
|
||||
[zoomSlider = ui->zoomSlider](int new_zoomLevel) {
|
||||
zoomSlider->blockSignals(true);
|
||||
zoomSlider->setValue(new_zoomLevel);
|
||||
zoomSlider->blockSignals(false);
|
||||
});
|
||||
|
||||
connect(ui->zoomPlus, &QToolButton::clicked, this, &ZoomableView::zoomIn);
|
||||
connect(ui->zoomSlider, &QSlider::valueChanged, this, &ZoomableView::setZoomLevel);
|
||||
connect(ui->zoomMinus, &QToolButton::clicked, this, &ZoomableView::zoomOut);
|
||||
|
||||
connect(ui->zoomTB, &QToolButton::clicked, ui->zoomSlider, [zoomSlider = ui->zoomSlider]() {
|
||||
const QString title = tr("Zoom level"), label = tr("New zoom level:");
|
||||
constexpr int min = ZoomableView::min, max = ZoomableView::max, step = 10;
|
||||
const int val = zoomSlider->value();
|
||||
bool ok;
|
||||
const int new_val =
|
||||
QInputDialog::getInt(zoomSlider, title, label, val, min, max, step, &ok);
|
||||
|
||||
if (ok) {
|
||||
zoomSlider->setValue(new_val);
|
||||
}
|
||||
});
|
||||
|
||||
resetZoom();
|
||||
}
|
||||
|
||||
int ZoomableView::zoomLevel() const
|
||||
{
|
||||
return m_zoomLevel;
|
||||
}
|
||||
|
||||
void ZoomableView::setZoomLevel(int new_zoomLevel)
|
||||
{
|
||||
checkLimits(new_zoomLevel);
|
||||
|
||||
if (m_zoomLevel == new_zoomLevel) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_zoomLevel = new_zoomLevel;
|
||||
updateView();
|
||||
Q_EMIT zoomLevelChanged(m_zoomLevel);
|
||||
}
|
||||
|
||||
inline void ZoomableView::checkLimits(int& zoom_level)
|
||||
{
|
||||
zoom_level = qBound(ZoomableView::min, zoom_level, ZoomableView::max);
|
||||
}
|
||||
|
||||
void ZoomableView::zoomIn(void)
|
||||
{
|
||||
setZoomLevel(m_zoomLevel + zoom_step_kb);
|
||||
}
|
||||
|
||||
void ZoomableView::zoomOut(void)
|
||||
{
|
||||
setZoomLevel(m_zoomLevel - zoom_step_kb);
|
||||
}
|
||||
|
||||
void ZoomableView::resetZoom(void)
|
||||
{
|
||||
constexpr const char* path = "User parameter:BaseApp/Preferences/Mod/Spreadsheet";
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(path);
|
||||
const int defaultZoomLevel = static_cast<int>(hGrp->GetInt("DefaultZoomLevel", 100));
|
||||
|
||||
setZoomLevel(defaultZoomLevel);
|
||||
}
|
||||
|
||||
void ZoomableView::updateView(void)
|
||||
{
|
||||
/* QGraphicsView has hardcoded margins therefore we have to avoid fitInView
|
||||
* Find more information at https://bugreports.qt.io/browse/QTBUG-42331 */
|
||||
|
||||
const qreal scale_factor = static_cast<qreal>(m_zoomLevel) / 100.0,
|
||||
new_w = static_cast<qreal>(viewport()->rect().width()) / scale_factor,
|
||||
new_h = static_cast<qreal>(viewport()->rect().height()) / scale_factor;
|
||||
|
||||
const QRectF new_geometry {0.0, 0.0, new_w, new_h};
|
||||
|
||||
const QRect old_geometry {stv->geometry()};
|
||||
stv->setGeometry(1, 1, old_geometry.width() - 1, old_geometry.height() - 1);
|
||||
|
||||
resetTransform();
|
||||
qpw->setGeometry(new_geometry);
|
||||
setSceneRect(new_geometry);
|
||||
scale(scale_factor, scale_factor);
|
||||
centerOn(new_geometry.center());
|
||||
}
|
||||
|
||||
void ZoomableView::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
if (event->modifiers() & Qt::ControlModifier) {
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Plus:
|
||||
zoomIn();
|
||||
event->accept();
|
||||
break;
|
||||
case Qt::Key_Minus:
|
||||
zoomOut();
|
||||
event->accept();
|
||||
break;
|
||||
case Qt::Key_0:
|
||||
resetZoom();
|
||||
event->accept();
|
||||
break;
|
||||
default:
|
||||
QGraphicsView::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
else {
|
||||
QGraphicsView::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void ZoomableView::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
QGraphicsView::resizeEvent(event);
|
||||
updateView();
|
||||
}
|
||||
|
||||
void ZoomableView::wheelEvent(QWheelEvent* event)
|
||||
{
|
||||
if (event->modifiers() & Qt::ControlModifier) {
|
||||
const int y = event->angleDelta().y();
|
||||
setZoomLevel(m_zoomLevel + (y > 0 ? zoom_step_mwheel : -zoom_step_mwheel));
|
||||
event->accept();
|
||||
}
|
||||
else {
|
||||
QGraphicsView::wheelEvent(event);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user