Fix bugtracker #112: no snap in the symbol editor below 100 % zoom

Below 100 % ElementView::drawBackground() hid the grid and also set the
snap step to 1 unit, so anything dragged while zoomed out landed off the
grid with nothing on screen to show it. A large symbol opens fitted to
the window below 100 %, which is why the report also says "when the
selection is big".

Keep hiding the grid below 100 % (its dots would merge into a grey
wash), but snap every 10 units, as at 100 %. The zoom-to-grid rule moves
into a header-only ElementViewGrid so it can be tested without an
editor window, like textgrid.h.

Checked in the editor: a one-rectangle symbol zoomed out to about 0.6x,
its edge dragged by (15, 10) px and saved: master moves it by (28, 18),
this branch by (30, 20). tst_elementviewgrid fails with the old step 1
and passes now; ctest 45/45.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-10-02 19:13:01 +13:00
parent 8d2243586e
commit 86da56b866
4 changed files with 119 additions and 21 deletions
+7 -21
View File
@@ -17,6 +17,8 @@
*/
#include "elementview.h"
#include "elementviewgrid.h"
#include "../qetapp.h"
#include "UndoCommand/pastepartscommand.h"
#include "ui/qetelementeditor.h"
@@ -535,27 +537,11 @@ void ElementView::drawBackground(QPainter *p, const QRectF &r) {
// choisit la granularite de la grille en fonction du zoom en cours
// selects the grid granularity according to the current zoom level
int drawn_x_grid = 1;//scene_ -> xGrid();
int drawn_y_grid = 1;//scene_ -> yGrid();
bool draw_grid = true;
bool draw_cross = false;
if (zoom_factor < 1.0) { //< no grid
draw_grid = false;
} else if (zoom_factor < 4.0) { //< grid 10*10
drawn_x_grid *= 10;
drawn_y_grid *= 10;
}else if (zoom_factor < 8.0) { //< grid 5*5
drawn_x_grid *= 5;
drawn_y_grid *= 5;
draw_cross = true;
} else if (zoom_factor < 10.0) { //< grid 2*2
drawn_x_grid *= 2;
drawn_y_grid *= 2;
draw_cross = true;
} else { //< grid 1*1
draw_cross = true;
}
const ElementViewGrid grid = ElementViewGrid::forZoom(zoom_factor);
const int drawn_x_grid = grid.step;
const int drawn_y_grid = grid.step;
const bool draw_grid = grid.draw_grid;
const bool draw_cross = grid.draw_cross;
m_scene->setGrid(drawn_x_grid, drawn_y_grid);
+60
View File
@@ -0,0 +1,60 @@
/*
Copyright 2006-2026 The QElectroTech Team
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
QElectroTech 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ELEMENTVIEWGRID_H
#define ELEMENTVIEWGRID_H
#include <QtGlobal>
/**
The symbol editor's grid at a given zoom: the step parts snap to, and
how the grid is drawn. The step gets finer as the view zooms in, so a
small detail can be placed precisely.
Below 100 % the grid is not drawn (its dots would merge into a grey
wash), but parts still snap every 10 units, as at 100 %. Snapping to 1
unit there left everything dragged while zoomed out off the grid, with
nothing on screen to show it (bugtracker #112).
*/
struct ElementViewGrid
{
int step = 10;
bool draw_grid = true;
bool draw_cross = false;
static ElementViewGrid forZoom(qreal zoom_factor)
{
ElementViewGrid grid;
if (zoom_factor < 1.0) {
grid.draw_grid = false;
} else if (zoom_factor < 4.0) {
grid.step = 10;
} else if (zoom_factor < 8.0) {
grid.step = 5;
grid.draw_cross = true;
} else if (zoom_factor < 10.0) {
grid.step = 2;
grid.draw_cross = true;
} else {
grid.step = 1;
grid.draw_cross = true;
}
return grid;
}
};
#endif // ELEMENTVIEWGRID_H
+7
View File
@@ -104,6 +104,13 @@ add_test(NAME tst_textgrid COMMAND tst_textgrid)
target_include_directories(tst_textgrid PRIVATE ${QET_DIR}/sources)
target_link_libraries(tst_textgrid PRIVATE Qt::Test)
# elementviewgrid.h is header-only: the symbol editor's snap step at each
# zoom (bugtracker #112), tested without an editor window.
add_executable(tst_elementviewgrid tst_elementviewgrid.cpp)
add_test(NAME tst_elementviewgrid COMMAND tst_elementviewgrid)
target_include_directories(tst_elementviewgrid PRIVATE ${QET_DIR}/sources)
target_link_libraries(tst_elementviewgrid PRIVATE Qt::Test)
# alignment.h is header-only too (it builds on textgrid.h): the geometry
# behind the align commands, tested without a scene.
add_executable(tst_alignment tst_alignment.cpp)
+45
View File
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <QtTest>
#include "editor/elementviewgrid.h"
// The symbol editor's snap step at each zoom (bugtracker #112): below
// 100 % the grid is hidden but parts must still snap every 10 units.
class tst_elementviewgrid : public QObject
{
Q_OBJECT
private slots:
void stepAtZoom_data()
{
QTest::addColumn<qreal>("zoom");
QTest::addColumn<int>("step");
QTest::addColumn<bool>("drawGrid");
QTest::addColumn<bool>("drawCross");
QTest::newRow("10 % (fit to a big symbol)") << 0.10 << 10 << false << false;
QTest::newRow("62.5 %, the #112 case") << 0.625 << 10 << false << false;
QTest::newRow("100 %") << 1.0 << 10 << true << false;
QTest::newRow("200 %") << 2.0 << 10 << true << false;
QTest::newRow("400 %") << 4.0 << 5 << true << true;
QTest::newRow("800 %") << 8.0 << 2 << true << true;
QTest::newRow("1000 %") << 10.0 << 1 << true << true;
}
void stepAtZoom()
{
QFETCH(qreal, zoom);
QFETCH(int, step);
QFETCH(bool, drawGrid);
QFETCH(bool, drawCross);
const ElementViewGrid grid = ElementViewGrid::forZoom(zoom);
QCOMPARE(grid.step, step);
QCOMPARE(grid.draw_grid, drawGrid);
QCOMPARE(grid.draw_cross, drawCross);
}
};
QTEST_APPLESS_MAIN(tst_elementviewgrid)
#include "tst_elementviewgrid.moc"