Snap a moved multi-part selection to the editor grid too (bugtracker #112)

A selection of several parts is moved by ElementPrimitiveDecorator, which
snapped to a fixed 1-unit step at every zoom. That is the "selection is
big" half of #112: below 100 % one part landed on the 10 grid but a
multi-part selection did not, and at 100-400 % it ignored the grid too.

It now snaps to the editor's current grid, as a single part does; Ctrl
still gives the fine 1-unit step. Resizing and arrow-key moves are
unchanged.

Also from review: add rows just below each zoom threshold to
tst_elementviewgrid (each catches a moved threshold the old rows missed),
and use one grid_step in drawBackground() instead of identical x/y copies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-10-02 21:09:24 +13:00
parent 86da56b866
commit a16bac8f84
3 changed files with 21 additions and 8 deletions
+7 -1
View File
@@ -206,7 +206,13 @@ void ElementPrimitiveDecorator::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
// When moving the selection, consider the position of the first selected item
QPointF current_position = scene_pos - mouse_offset_;
QPointF rounded_current_position = snapConstPointToGrid(current_position);
// Snap to the editor's grid, as a single part does (bugtracker
// #112); Ctrl keeps the fine 1-unit step.
ElementScene *element_scene = qobject_cast<ElementScene *>(scene());
QPointF rounded_current_position =
(element_scene && !(event->modifiers() & Qt::ControlModifier))
? element_scene->snapToGrid(current_position)
: snapConstPointToGrid(current_position);
movement = rounded_current_position - decorated_items_.at(0) -> toItem() -> scenePos();
QRectF bounding_rect = modified_bounding_rect_;
+6 -7
View File
@@ -538,12 +538,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
const ElementViewGrid grid = ElementViewGrid::forZoom(zoom_factor);
const int drawn_x_grid = grid.step;
const int drawn_y_grid = grid.step;
const int grid_step = 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);
m_scene->setGrid(grid_step, grid_step);
if (draw_grid) {
// draw the dots of the grid
@@ -573,12 +572,12 @@ void ElementView::drawBackground(QPainter *p, const QRectF &r) {
qreal limit_y = r.y() + r.height();
int g_x = (int)ceil(r.x());
while (g_x % drawn_x_grid) ++ g_x;
while (g_x % grid_step) ++ g_x;
int g_y = (int)ceil(r.y());
while (g_y % drawn_y_grid) ++ g_y;
while (g_y % grid_step) ++ g_y;
for (int gx = g_x ; gx < limit_x ; gx += drawn_x_grid) {
for (int gy = g_y ; gy < limit_y ; gy += drawn_y_grid) {
for (int gx = g_x ; gx < limit_x ; gx += grid_step) {
for (int gy = g_y ; gy < limit_y ; gy += grid_step) {
if (draw_cross) {
if (!(gx % 10) && !(gy % 10)) {
p -> drawLine(QLineF(gx - (pen.width()/4.0), gy, gx + (pen.width()/4.0), gy));
+8
View File
@@ -24,6 +24,14 @@ private slots:
QTest::newRow("400 %") << 4.0 << 5 << true << true;
QTest::newRow("800 %") << 8.0 << 2 << true << true;
QTest::newRow("1000 %") << 10.0 << 1 << true << true;
// Just below each threshold: the comparisons are strict (<), so a
// change to <= would move these rows into the next band.
QTest::newRow("99.9 %") << 0.999 << 10 << false << false;
QTest::newRow("399.9 %") << 3.999 << 10 << true << false;
QTest::newRow("401 %") << 4.01 << 5 << true << true;
QTest::newRow("799.9 %") << 7.999 << 5 << true << true;
QTest::newRow("999.9 %") << 9.999 << 2 << true << true;
}
void stepAtZoom()