Skip to content

Commit

Permalink
experimental features: zoom and drag view (adressing #34)
Browse files Browse the repository at this point in the history
  • Loading branch information
stiglers-eponym committed Oct 22, 2024
1 parent 9e3d0c9 commit ff3196b
Show file tree
Hide file tree
Showing 16 changed files with 230 additions and 29 deletions.
7 changes: 5 additions & 2 deletions man/beamerpresenter-ui.5
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,11 @@ clear all drawings on the left/right part of current page, assuming that the pag
.BR "scroll up" / normal / down
scroll the slide view up / to normal position / down. This allows the presenter to add extra space for drawings.
.TP
.BR "zoom in" / reset / out
experimental: zoom the slide view. Use the tool \[dq]drag view\[dq] (experimental) to drag the zoomed view.
.TP
.B save
save drawings to file. Doesn't ask for file name if a file name is known.
save drawings to file. Does not ask for file name if a file name is known.
.TP
.B save as
save drawings to file. Always asks for the file name.
Expand Down Expand Up @@ -408,7 +411,7 @@ drop-down menu of draw tool widths. This must be provided as a JSON object in th
Options in the dictionary for tools. All lengths (e.g. stroke width) are given in points (1/72 inch) in the PDF:
.TP
.B tool
mandatory: pen, fixed width pen, highlighter, eraser, pointer, magnifier, torch, text, click select, rectangle select, freehand select, or none
mandatory: pen, fixed width pen, highlighter, eraser, pointer, magnifier, torch, text, click select, rectangle select, freehand select, drag view, or none
.TP
.B color
color name known to Qt or #RRGGBB or #AARRGGBB
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ add_executable(beamerpresenter
drawing/tool.h drawing/tool.cpp
drawing/drawtool.h
drawing/texttool.h
drawing/dragtool.h
drawing/selectiontool.h drawing/selectiontool.cpp
drawing/pointingtool.h drawing/pointingtool.cpp
drawing/selectionrectitem.h drawing/selectionrectitem.cpp
Expand Down
39 changes: 39 additions & 0 deletions src/drawing/dragtool.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: 2024 Valentin Bruch <[email protected]>
// SPDX-License-Identifier: GPL-3.0-or-later OR AGPL-3.0-or-later

#ifndef DRAGTOOL_H
#define DRAGTOOL_H

#include <QPointF>
#include <cmath>

#include "src/drawing/tool.h"

/** Experimental: DragTool for dragging view */
class DragTool : public Tool
{
QPointF reference_point;
static constexpr int skip_events = 3;
int event_counter = skip_events - 1;

public:
DragTool(const int device = AnyDevice) noexcept : Tool(DragViewTool, device)
{
}
DragTool(const DragTool &other) noexcept : Tool(DragViewTool, other.device())
{
}
~DragTool() {}
const QPointF &reference() const noexcept { return reference_point; }
void setReference(const QPointF &pos) noexcept { reference_point = pos; }
QPointF dragTo(const QPointF target, const bool force) noexcept
{
if (force || ++event_counter >= skip_events)
event_counter = 0;
else
return QPointF();
return reference_point - target;
}
};

#endif // DRAGTOOL_H
3 changes: 3 additions & 0 deletions src/drawing/tool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#if (QT_VERSION_MAJOR >= 6)
#include <QPointingDevice>
#endif
#include "src/drawing/dragtool.h"
#include "src/drawing/drawtool.h"
#include "src/drawing/pointingtool.h"
#include "src/drawing/selectiontool.h"
Expand All @@ -24,6 +25,8 @@ std::shared_ptr<Tool> Tool::copy() const
newtool = new SelectionTool(*static_cast<const SelectionTool*>(this));
else if (_tool == Tool::TextInputTool)
newtool = new TextTool(*static_cast<const TextTool*>(this));
else if (_tool == Tool::DragViewTool)
newtool = new DragTool(*static_cast<const DragTool*>(this));
else
newtool = new Tool(*this);
newtool->setDevice(_device);
Expand Down
5 changes: 4 additions & 1 deletion src/drawing/tool.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ class Tool
// General tools, class Tool
/// Invalid tool
InvalidTool = 0,
/// Draw view
DragViewTool = 1,
/// Text input tool
TextInputTool = 1,
TextInputTool = 2,
/// No tool
NoTool = 0x1f,

Expand Down Expand Up @@ -165,6 +167,7 @@ static const QMap<QString, Tool::BasicTool> string_to_tool{
{QT_TRANSLATE_NOOP("Tool", "torch"), Tool::Torch},
{QT_TRANSLATE_NOOP("Tool", "magnifier"), Tool::Magnifier},
{QT_TRANSLATE_NOOP("Tool", "text"), Tool::TextInputTool},
{QT_TRANSLATE_NOOP("Tool", "drag view"), Tool::DragViewTool},
{QT_TRANSLATE_NOOP("Tool", "click select"), Tool::BasicSelectionTool},
{QT_TRANSLATE_NOOP("Tool", "rectangle select"), Tool::RectSelectionTool},
{QT_TRANSLATE_NOOP("Tool", "freehand select"), Tool::FreehandSelectionTool},
Expand Down
3 changes: 3 additions & 0 deletions src/enumerates.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ enum Action {
ScrollDown, ///< scroll slide down
ScrollUp, ///< scroll slide up
ScrollNormal, ///< scroll slide back to normal
ZoomIn, ///< zoom in on a slide
ZoomOut, ///< zoom out of a slide
ZoomReset, ///< reset slide zoom
SaveDrawings, ///< save drawings to known file name, ask for file name if no
///< file name is known
SaveDrawingsAs, ///< save drawings to file, always ask for file name
Expand Down
6 changes: 6 additions & 0 deletions src/gui/actionbutton.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ const char *action_to_theme_icon(const Action action) noexcept
return "go-first";
case LastPage:
return "go-last";
case ZoomIn:
return "zoom-in";
case ZoomOut:
return "zoom-out";
case ZoomReset:
return "zoom-original";
/* Drawing */
case UndoDrawing:
return "edit-undo";
Expand Down
3 changes: 3 additions & 0 deletions src/names.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ static const QMap<QString, Action> string_to_action_map{
{QT_TRANSLATE_NOOP("SettingsWidget", "scroll home"), ScrollNormal},
{QT_TRANSLATE_NOOP("SettingsWidget", "scroll normal"), ScrollNormal},
{QT_TRANSLATE_NOOP("SettingsWidget", "scroll reset"), ScrollNormal},
{QT_TRANSLATE_NOOP("SettingsWidget", "zoom in"), ZoomIn},
{QT_TRANSLATE_NOOP("SettingsWidget", "zoom out"), ZoomOut},
{QT_TRANSLATE_NOOP("SettingsWidget", "zoom reset"), ZoomReset},
{QT_TRANSLATE_NOOP("SettingsWidget", "save"), SaveDrawings},
{QT_TRANSLATE_NOOP("SettingsWidget", "save as"), SaveDrawingsAs},
{QT_TRANSLATE_NOOP("SettingsWidget", "open"), LoadDrawings},
Expand Down
4 changes: 4 additions & 0 deletions src/preferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <utility>

#include "src/config.h"
#include "src/drawing/dragtool.h"
#include "src/drawing/drawtool.h"
#include "src/drawing/pointingtool.h"
#include "src/drawing/selectiontool.h"
Expand Down Expand Up @@ -132,6 +133,9 @@ std::shared_ptr<Tool> createTool(const QJsonObject &obj,
tool = new TextTool(font, color, device);
break;
}
case Tool::DragViewTool:
tool = new DragTool(device);
break;
case Tool::BasicSelectionTool:
case Tool::RectSelectionTool:
case Tool::FreehandSelectionTool:
Expand Down
83 changes: 74 additions & 9 deletions src/slidescene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "src/config.h"
#include "src/drawing/arrowgraphicsitem.h"
#include "src/drawing/basicgraphicspath.h"
#include "src/drawing/dragtool.h"
#include "src/drawing/ellipsegraphicsitem.h"
#include "src/drawing/flexgraphicslineitem.h"
#include "src/drawing/fullgraphicspath.h"
Expand Down Expand Up @@ -321,24 +322,27 @@ bool SlideScene::handleEvents(const int device, const QList<QPointF> &pos,
"Handling event" << tool->tool() << tool->device() << device);
// Handle draw tool events.
if (tool->tool() & Tool::AnyDrawTool)
handleDrawEvents(std::static_pointer_cast<const DrawTool>(tool), device,
handleDrawEvents(std::dynamic_pointer_cast<const DrawTool>(tool), device,
pos, pressure);
// Handle pointing tool events.
else if (tool->tool() & Tool::AnyPointingTool)
handlePointingEvents(std::static_pointer_cast<PointingTool>(tool), device,
handlePointingEvents(std::dynamic_pointer_cast<PointingTool>(tool), device,
pos);
// Handle selection tool events.
else if (tool->tool() & Tool::AnySelectionTool)
handleSelectionEvents(std::static_pointer_cast<SelectionTool>(tool), device,
pos, start_pos);
handleSelectionEvents(std::dynamic_pointer_cast<SelectionTool>(tool),
device, pos, start_pos);
// Handle text tool events.
// Here we detect start events and not stop events, because otherwise touch
// events will be discarded: If a touch start event is not handled, the whole
// touch event is treated as a mouse event.
else if (tool->tool() == Tool::TextInputTool &&
(device & Tool::AnyEvent) == Tool::StartEvent && pos.size() == 1)
return handleTextEvents(std::static_pointer_cast<const TextTool>(tool),
return handleTextEvents(std::dynamic_pointer_cast<const TextTool>(tool),
device, pos);
else if (tool->tool() == Tool::DragViewTool)
return handleDragView(std::dynamic_pointer_cast<DragTool>(tool), device,
pos, start_pos);
// Fall back to no tool.
else if ((device & Tool::AnyEvent) == Tool::StopEvent && pos.size() == 1)
noToolClicked(pos.constFirst(), start_pos);
Expand All @@ -347,6 +351,24 @@ bool SlideScene::handleEvents(const int device, const QList<QPointF> &pos,
return true;
}

bool SlideScene::handleDragView(std::shared_ptr<DragTool> tool,
const int device, const QList<QPointF> &pos,
const QPointF &start_pos)
{
if (!tool || pos.size() != 1) return false;
if ((device & Tool::AnyEvent) == Tool::StartEvent)
tool->setReference(pos.constFirst());
else {
const QPointF delta = tool->dragTo(
pos.constFirst(), (device & Tool::AnyEvent) == Tool::StopEvent);
if (delta.isNull()) return false;
QRectF rect = sceneRect();
rect.translate(delta);
setSceneRect(rect);
}
return true;
}

bool SlideScene::maybeStartSelectionEvent(const QPointF &pos,
const int device) noexcept
{
Expand Down Expand Up @@ -675,15 +697,58 @@ void SlideScene::receiveAction(const Action action)
debug_verbose(DebugFunctionCalls, action << this);
debug_msg(DebugKeyInput, "SlideScene received action" << action);
switch (action) {
case ScrollDown:
setSceneRect(sceneRect().translated(0, sceneRect().height() / 5));
case ScrollDown: {
QRectF rect = sceneRect();
rect.translate(0, 0.2 * rect.height());
setSceneRect(rect);
break;
case ScrollUp:
setSceneRect(sceneRect().translated(0, -sceneRect().height() / 5));
}
case ScrollUp: {
QRectF rect = sceneRect();
rect.translate(0, -0.2 * rect.height());
setSceneRect(rect);
break;
}
case ScrollNormal:
setSceneRect({{0, 0}, sceneRect().size()});
break;
case ZoomIn: {
const QRectF rect = sceneRect();
setSceneRect(rect.x() + 0.1 / 1.2 * rect.width(),
rect.y() + 0.1 / 1.2 * rect.height(), rect.width() / 1.2,
rect.height() / 1.2);
for (auto view : views()) {
auto *sview = dynamic_cast<SlideView *>(view);
if (sview) sview->setZoomRelative(1.2);
}
break;
}
case ZoomOut: {
const QRectF rect = sceneRect();
setSceneRect(rect.x() - 0.1 / 0.8 * rect.width(),
rect.y() - 0.1 / 0.8 * rect.height(), rect.width() / 0.8,
rect.height() / 0.8);
for (auto view : views()) {
auto *sview = dynamic_cast<SlideView *>(view);
if (sview) sview->setZoomRelative(0.8);
}
break;
}
case ZoomReset: {
qreal zoom = 1.0;
for (auto view : views()) {
auto *sview = dynamic_cast<SlideView *>(view);
if (sview) {
zoom = sview->getZoom();
sview->setZoom(1.0);
}
}
const QRectF rect = sceneRect();
setSceneRect(rect.x() - (zoom - 1) / 2 * rect.width(),
rect.y() - (zoom - 1) / 2 * rect.height(),
rect.width() * zoom, rect.height() * zoom);
break;
}
case PauseMedia:
pauseMedia();
break;
Expand Down
3 changes: 3 additions & 0 deletions src/slidescene.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class QGraphicsRectItem;
class PdfMaster;
class DrawTool;
class TextTool;
class DragTool;
class QFont;
class PointingTool;
class SelectionTool;
Expand Down Expand Up @@ -328,6 +329,8 @@ class SlideScene : public QGraphicsScene
/// Helper function for handleEvents: text tool events
bool handleTextEvents(std::shared_ptr<const TextTool> tool, const int device,
const QList<QPointF> &pos);
bool handleDragView(std::shared_ptr<DragTool> tool, const int device,
const QList<QPointF> &pos, const QPointF &start_pos);
/// Handle selection start events (only called from handleEvents().
void handleSelectionStartEvents(std::shared_ptr<SelectionTool> tool,
const QPointF &pos);
Expand Down
35 changes: 18 additions & 17 deletions src/slideview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ SlideView::SlideView(SlideScene *scene, const PixCache *cache, QWidget *parent)
{
setMouseTracking(true);
setAttribute(Qt::WA_AcceptTouchEvents);
setTransformationAnchor(AnchorViewCenter);
grabGesture(Qt::SwipeGesture);
setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing |
QPainter::RenderHint::SmoothPixmapTransform);
Expand Down Expand Up @@ -55,7 +56,6 @@ void SlideView::pageChanged(const int page, SlideScene *scene)
sliders.clear();
setScene(scene);
const QSizeF &pageSize = scene->sceneRect().size();
qreal resolution;
if (pageSize.width() * height() > pageSize.height() * width())
// page is too wide, determine resolution by x direction
resolution = width() / pageSize.width();
Expand All @@ -78,7 +78,6 @@ void SlideView::pageChangedBlocking(const int page, SlideScene *scene)
sliders.clear();
setScene(scene);
const QSizeF &pageSize = scene->sceneRect().size();
qreal resolution;
if (pageSize.width() * height() > pageSize.height() * width())
// page is too wide, determine resolution by x direction
resolution = width() / pageSize.width();
Expand Down Expand Up @@ -206,10 +205,6 @@ bool SlideView::event(QEvent *event)
return QGraphicsView::event(event);
}
*/
// case QEvent::TabletTrackingChange:
// case QEvent::TabletEnterProximity:
// case QEvent::TabletLeaveProximity:
// break;
case QEvent::TabletPress: {
auto tabletevent = static_cast<const QTabletEvent *>(event);
#if (QT_VERSION_MAJOR >= 6)
Expand Down Expand Up @@ -253,6 +248,22 @@ bool SlideView::event(QEvent *event)
}
}

void SlideView::requestScaledPage(const qreal zoom)
{
const SlideScene *sscene = dynamic_cast<SlideScene *>(scene());
if (!sscene || zoom < 1e-6 || zoom > 1e6) return;
const PixmapGraphicsItem *pageItem = sscene->pageBackground();
if (!pageItem) return;
// Check whether an enlarged page is needed and not "in preparation" yet.
if (waitingForPage == INT_MAX &&
!pageItem->hasWidth(zoom * resolution * sceneRect().width())) {
debug_msg(DebugRendering, "Enlarged page: searched for"
<< zoom * resolution * sceneRect().width());
waitingForPage = static_cast<SlideScene *>(scene())->getPage();
emit requestPage(waitingForPage, zoom * resolution);
}
}

void SlideView::showMagnifier(QPainter *painter,
std::shared_ptr<const PointingTool> tool) noexcept
{
Expand All @@ -261,17 +272,7 @@ void SlideView::showMagnifier(QPainter *painter,
painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
painter->setPen(tool->color());
painter->setBrush(Qt::NoBrush);
const qreal resolution = tool->scale() * painter->transform().m11();
PixmapGraphicsItem *pageItem =
static_cast<SlideScene *>(scene())->pageBackground();
// Check whether an enlarged page is needed and not "in preparation" yet.
if (waitingForPage == INT_MAX &&
!pageItem->hasWidth(resolution * sceneRect().width())) {
debug_msg(DebugRendering, "Enlarged page: searched for"
<< resolution * sceneRect().width());
waitingForPage = static_cast<SlideScene *>(scene())->getPage();
emit requestPage(waitingForPage, resolution);
}
requestScaledPage(tool->scale());
// Draw magnifier(s) at all positions of tool.
for (const auto &pos : tool->pos()) {
// calculate target rect: size of the magnifier
Expand Down
Loading

0 comments on commit ff3196b

Please sign in to comment.