Skip to content

Commit d5f8dea

Browse files
elektroniskdg0ytdl3sdo
authored
BoxZoomTool: New tool for zoom-to-box (GH-2360)
Co-authored-by: Kai Pastor <[email protected]> Co-authored-by: Matthias Kühlewein <[email protected]>
1 parent b3d674a commit d5f8dea

File tree

9 files changed

+203
-1
lines changed

9 files changed

+203
-1
lines changed

images/cursor-zoom.png

877 Bytes
Loading

images/view-box-zoom.png

1.33 KB
Loading

resources.qrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
<file>images/cursor-invisible.png</file>
2929
<file>images/cursor-rotate.png</file>
3030
<file>images/cursor-scale.png</file>
31+
<file>images/cursor-zoom.png</file>
3132
<file>images/cut.png</file>
3233
<file>images/delete.png</file>
3334
<file>images/draw-circle.png</file>
@@ -111,6 +112,7 @@
111112
<file>images/tool-touch-cursor.png</file>
112113
<file>images/undo.png</file>
113114
<file>images/view-baseline.png</file>
115+
<file>images/view-box-zoom.png</file>
114116
<file>images/view-hatch-areas.png</file>
115117
<file>images/view-show-all.png</file>
116118
<file>images/view-zoom-in.png</file>

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ set(Mapper_Common_SRCS
226226
templates/template_track.cpp
227227
templates/world_file.cpp
228228

229+
tools/box_zoom_tool.cpp
229230
tools/cut_tool.cpp
230231
tools/cut_hole_tool.cpp
231232
tools/cutout_operation.cpp

src/gui/map/map_editor.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@
143143
#include "templates/template.h"
144144
#include "templates/template_dialog_reopen.h"
145145
#include "templates/template_track.h"
146+
#include "tools/box_zoom_tool.h"
146147
#include "tools/cut_tool.h"
147148
#include "tools/cut_hole_tool.h"
148149
#include "tools/cutout_tool.h"
@@ -1006,6 +1007,7 @@ void MapEditorController::createActions()
10061007
follow_position_act = newCheckAction("follow-position", tr("Keep my location on screen"), this, SLOT(followPositionClicked(bool)), nullptr, QString{}, "view_menu.html");
10071008
zoom_in_act = newAction("zoomin", tr("Zoom in"), this, SLOT(zoomIn()), "view-zoom-in.png", QString{}, "view_menu.html");
10081009
zoom_out_act = newAction("zoomout", tr("Zoom out"), this, SLOT(zoomOut()), "view-zoom-out.png", QString{}, "view_menu.html");
1010+
box_zoom_act = newCheckAction("boxzoom", tr("Zoom to box"), this, SLOT(boxZoom(bool)), "view-box-zoom.png", QString{}, "view_menu.html");
10091011
show_all_act = newAction("showall", tr("Show whole map"), this, SLOT(showWholeMap()), "view-show-all.png", QString{}, "view_menu.html");
10101012
fullscreen_act = newAction("fullscreen", tr("Toggle fullscreen mode"), window, SLOT(toggleFullscreenMode()), nullptr, QString{}, "view_menu.html");
10111013
custom_zoom_act = newAction("setzoom", tr("Set custom zoom factor..."), this, SLOT(setCustomZoomFactorClicked()), nullptr, QString{}, "view_menu.html");
@@ -1186,6 +1188,7 @@ void MapEditorController::createMenuAndToolbars()
11861188
view_menu->addAction(pan_act);
11871189
view_menu->addAction(zoom_in_act);
11881190
view_menu->addAction(zoom_out_act);
1191+
view_menu->addAction(box_zoom_act);
11891192
view_menu->addAction(show_all_act);
11901193
view_menu->addAction(custom_zoom_act);
11911194
view_menu->addSeparator();
@@ -1319,6 +1322,7 @@ void MapEditorController::createMenuAndToolbars()
13191322
toolbar_view->addAction(pan_act);
13201323
toolbar_view->addAction(zoom_in_act);
13211324
toolbar_view->addAction(zoom_out_act);
1325+
toolbar_view->addAction(box_zoom_act);
13221326
toolbar_view->addAction(show_all_act);
13231327
toolbar_view->addAction(template_window_act);
13241328

@@ -2084,10 +2088,20 @@ void MapEditorController::zoomIn()
20842088
{
20852089
main_view->zoomSteps(1);
20862090
}
2091+
20872092
void MapEditorController::zoomOut()
20882093
{
20892094
main_view->zoomSteps(-1);
20902095
}
2096+
2097+
void MapEditorController::boxZoom(bool checked)
2098+
{
2099+
if (checked)
2100+
setTool(new BoxZoomTool(this, box_zoom_act));
2101+
else
2102+
setTool(nullptr);
2103+
}
2104+
20912105
void MapEditorController::setCustomZoomFactorClicked()
20922106
{
20932107
bool ok;
@@ -2448,7 +2462,7 @@ void MapEditorController::selectedSymbolsChanged()
24482462
if (symbol && !symbol->isHidden() && !symbol->isProtected() && current_tool)
24492463
{
24502464
// Auto-switch to a draw tool when selecting a symbol under certain conditions
2451-
if (current_tool->toolType() == MapEditorTool::Pan || current_tool->toolType() == MapEditorTool::Scribble
2465+
if (current_tool->toolType() == MapEditorTool::Pan || current_tool->toolType() == MapEditorTool::BoxZoom || current_tool->toolType() == MapEditorTool::Scribble
24522466
|| ((current_tool->toolType() == MapEditorTool::EditLine || current_tool->toolType() == MapEditorTool::EditPoint) && map->getNumSelectedObjects() == 0))
24532467
{
24542468
current_tool->switchToDefaultDrawTool(active_symbol);
@@ -4299,6 +4313,7 @@ QHash<const Symbol*, Symbol*> MapEditorController::importMap(
42994313
void MapEditorController::setViewOptionsEnabled(bool enabled)
43004314
{
43014315
pan_act->setEnabled(enabled);
4316+
box_zoom_act->setEnabled(enabled);
43024317
show_grid_act->setEnabled(enabled);
43034318
// hatch_areas_view_act->setEnabled(enabled);
43044319
// baseline_view_act->setEnabled(enabled);

src/gui/map/map_editor.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,8 @@ public slots:
310310
void zoomIn();
311311
/** Zooms out in the current map widget. */
312312
void zoomOut();
313+
/** Activates the box zoom tool. */
314+
void boxZoom(bool checked);
313315
/** Shows the dialog to set a custom zoom factor in the current map widget. */
314316
void setCustomZoomFactorClicked();
315317

@@ -726,6 +728,7 @@ protected slots:
726728
QAction* follow_position_act = {};
727729
QAction* zoom_in_act = {};
728730
QAction* zoom_out_act = {};
731+
QAction* box_zoom_act = {};
729732
QAction* show_all_act = {};
730733
QAction* fullscreen_act = {};
731734
QAction* custom_zoom_act = {};

src/tools/box_zoom_tool.cpp

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright 2025 Andreas Bertheussen
3+
*
4+
* This file is part of OpenOrienteering.
5+
*
6+
* OpenOrienteering is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* OpenOrienteering is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with OpenOrienteering. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#include "box_zoom_tool.h"
21+
22+
#include <Qt>
23+
#include <QCursor>
24+
#include <QKeyEvent>
25+
#include <QPixmap>
26+
#include <QRectF>
27+
28+
#include "core/map_coord.h"
29+
#include "gui/main_window.h"
30+
#include "gui/map/map_widget.h"
31+
#include "tools/tool.h"
32+
#include "util/util.h"
33+
34+
namespace OpenOrienteering {
35+
36+
BoxZoomTool::BoxZoomTool(MapEditorController* editor, QAction* tool_action)
37+
: MapEditorToolBase( scaledToScreen(QCursor{ QPixmap(QString::fromLatin1(":/images/cursor-zoom.png")), 12, 12 }), BoxZoom, editor, tool_action)
38+
{
39+
useTouchCursor(false);
40+
}
41+
42+
BoxZoomTool::~BoxZoomTool() = default;
43+
44+
void BoxZoomTool::clickPress()
45+
{
46+
startDragging();
47+
}
48+
49+
bool BoxZoomTool::keyPress(QKeyEvent* event)
50+
{
51+
if (event->key() == Qt::Key_Escape && isDragging())
52+
{
53+
cancelDragging();
54+
return true;
55+
}
56+
return false;
57+
}
58+
59+
void BoxZoomTool::dragStart()
60+
{
61+
mainWindow()->clearStatusBarMessage();
62+
setEditingInProgress(true);
63+
updateDirtyRect();
64+
}
65+
66+
void BoxZoomTool::dragMove()
67+
{
68+
updateDirtyRect();
69+
}
70+
71+
void BoxZoomTool::dragFinish()
72+
{
73+
constexpr auto min_size = 1; // mm
74+
auto const rect = QRectF(click_pos_map, cur_pos_map).normalized();
75+
if (rect.width() >= min_size && rect.height() >= min_size)
76+
mapWidget()->adjustViewToRect(rect, MapWidget::ContinuousZoom);
77+
else
78+
mainWindow()->showStatusBarMessage(tr("The selected box is too small."), 2000);
79+
80+
updateDirtyRect();
81+
setEditingInProgress(false);
82+
}
83+
84+
void BoxZoomTool::dragCanceled()
85+
{
86+
updateDirtyRect();
87+
setEditingInProgress(false);
88+
}
89+
90+
void BoxZoomTool::updateStatusText()
91+
{
92+
setStatusBarText(tr("<b>Drag</b>: Select area to zoom in on. "));
93+
}
94+
95+
void BoxZoomTool::objectSelectionChangedImpl()
96+
{}
97+
98+
void BoxZoomTool::drawImpl(QPainter* painter, MapWidget* widget)
99+
{
100+
drawSelectionOrPreviewObjects(painter, widget, false);
101+
102+
if (isDragging())
103+
drawSelectionBox(painter, widget, click_pos_map, cur_pos_map);
104+
}
105+
106+
int BoxZoomTool::updateDirtyRectImpl(QRectF& rect)
107+
{
108+
rectIncludeSafe(rect, click_pos_map);
109+
rectInclude(rect, cur_pos_map);
110+
return 5;
111+
}
112+
113+
} // namespace OpenOrienteering

src/tools/box_zoom_tool.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2025 Andreas Bertheussen
3+
*
4+
* This file is part of OpenOrienteering.
5+
*
6+
* OpenOrienteering is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* OpenOrienteering is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with OpenOrienteering. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
21+
#ifndef OPENORIENTEERING_BOX_ZOOM_TOOL_H
22+
#define OPENORIENTEERING_BOX_ZOOM_TOOL_H
23+
24+
#include <QObject>
25+
#include <QString>
26+
27+
#include "tools/tool_base.h"
28+
29+
class QAction;
30+
class QKeyEvent;
31+
class QPainter;
32+
class QRectF;
33+
34+
namespace OpenOrienteering {
35+
36+
class MapEditorController;
37+
class MapWidget;
38+
39+
40+
/**
41+
* Tool to zoom to a user defined region.
42+
*/
43+
class BoxZoomTool : public MapEditorToolBase
44+
{
45+
Q_OBJECT
46+
public:
47+
BoxZoomTool(MapEditorController* editor, QAction* tool_action);
48+
~BoxZoomTool() override;
49+
50+
protected:
51+
void updateStatusText() override;
52+
void objectSelectionChangedImpl() override;
53+
void clickPress() override;
54+
bool keyPress(QKeyEvent* event) override;
55+
void dragStart() override;
56+
void dragMove() override;
57+
void dragFinish() override;
58+
void dragCanceled() override;
59+
60+
void drawImpl(QPainter* painter, MapWidget* widget) override;
61+
int updateDirtyRectImpl(QRectF& rect) override;
62+
};
63+
64+
65+
} // namespace OpenOrienteering
66+
67+
#endif

src/tools/tool.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ Q_OBJECT
9090
DrawFreehand = 8,
9191
Pan = 9,
9292
Scribble = 10,
93+
BoxZoom = 11,
9394
Other = 0
9495
};
9596

0 commit comments

Comments
 (0)