Merge master into stage 2 (#1042) as the base of the stage PRs

This commit is contained in:
ispyisail
2026-09-26 21:40:18 +12:00
32 changed files with 1516 additions and 106 deletions
+51
View File
@@ -0,0 +1,51 @@
/*
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 BORDERCELLLABELS_H
#define BORDERCELLLABELS_H
#include <QString>
/// The labels the border of a folio writes on its rows and columns, shared
/// by BorderTitleBlock::draw() and the cell rulers of DiagramView so the
/// two cannot disagree. Header-only so it can be unit-tested directly --
/// see tests/qttest/tst_bordercelllabels.cpp.
namespace BorderCellLabels {
/// @return the label of row \a row, counted from 1: A..Z, then AA, AB...
/// (the sequence BorderTitleBlock::incrementLetters() walks through).
inline QString rowLabel(int row)
{
QString label;
while (row > 0) {
--row;
label.prepend(QChar('A' + row % 26));
row /= 26;
}
return label;
}
/// @return the label of column \a column, counted from 1. When
/// \a starts_at_zero (the "border-columns_0" setting) the first column
/// is labelled 0.
inline QString columnLabel(int column, bool starts_at_zero)
{
return QString::number(starts_at_zero ? column - 1 : column);
}
}
#endif // BORDERCELLLABELS_H
+46 -11
View File
@@ -17,6 +17,7 @@
*/
#include "bordertitleblock.h"
#include "bordercelllabels.h"
#include "createdxf.h"
#include "diagram.h"
#include "diagramposition.h"
@@ -29,6 +30,7 @@
#include <QLocale>
#include <QPainter>
#include <QRegularExpression>
#include <utility>
#define MIN_COLUMN_COUNT 3
@@ -533,6 +535,8 @@ void BorderTitleBlock::draw(QPainter *painter)
//Draw the nums of columns
if (display_border_ && display_columns_) {
const bool columns_start_at_zero =
settings.value("border-columns_0", true).toBool();
for (int i = 1 ; i <= columns_count_ ; ++ i) {
QRectF numbered_rectangle = QRectF(
diagram_rect_.topLeft().x()
@@ -543,23 +547,15 @@ void BorderTitleBlock::draw(QPainter *painter)
columns_header_height_
);
painter -> drawRect(numbered_rectangle);
if (settings.value("border-columns_0", true).toBool()){
painter -> drawText(numbered_rectangle,
Qt::AlignVCenter
| Qt::AlignCenter,
QString("%1").arg(i - 1));
}else{
painter -> drawText(numbered_rectangle,
Qt::AlignVCenter
| Qt::AlignCenter,
QString("%1").arg(i));
}
BorderCellLabels::columnLabel(i, columns_start_at_zero));
}
}
//Draw the nums of rows
if (display_border_ && display_rows_) {
QString row_string("A");
for (int i = 1 ; i <= rows_count_ ; ++ i) {
QRectF lettered_rectangle = QRectF(
diagram_rect_.topLeft().x(),
@@ -575,8 +571,7 @@ void BorderTitleBlock::draw(QPainter *painter)
painter -> drawText(lettered_rectangle,
Qt::AlignVCenter
| Qt::AlignCenter,
row_string);
row_string = incrementLetters(row_string);
BorderCellLabels::rowLabel(i));
}
}
@@ -935,6 +930,46 @@ void BorderTitleBlock::updateDiagramContextForTitleBlock(
m_titleblock_template_renderer -> setContext(context);
}
/**
@brief BorderTitleBlock::cellRect
Convert a cell written the way the border labels it (ex : B13, the row
letter(s) then the column number) to its rect in scene coordinate.
This is the reverse of convertPosition().
@param cell : the cell to convert, case and surrounding spaces ignored
@return the rect of the cell, or a null QRectF if \a cell is not a
cell reference or lies outside of the border.
*/
QRectF BorderTitleBlock::cellRect(const QString &cell) const
{
static const QRegularExpression cell_re(
QStringLiteral("^\\s*([A-Za-z]+)\\s*(\\d{1,4})\\s*$"));
const QRegularExpressionMatch match = cell_re.match(cell);
if (!match.hasMatch())
return QRectF();
//Row letters count like A..Z, AA, AB... (see incrementLetters())
int row = 0;
for (const QChar c : match.captured(1).toUpper()) {
row = row * 26 + (c.unicode() - 'A' + 1);
if (row > rows_count_)
return QRectF();
}
int column = match.captured(2).toInt();
QSettings settings;
if (settings.value("border-columns_0", true).toBool())
++column;
if (row < 1 || column < 1 || column > columns_count_)
return QRectF();
const QPointF top_left = insideBorderRect().topLeft();
return QRectF(top_left.x() + (column - 1) * columns_width_,
top_left.y() + (row - 1) * rows_height_,
columns_width_,
rows_height_);
}
/**
@brief BorderTitleBlock::incrementLetters
increments string with Letters A to Z
+1
View File
@@ -159,6 +159,7 @@ class BorderTitleBlock : public QObject
void setDiagramHeight(const qreal &);
DiagramPosition convertPosition(const QPointF &);
QRectF cellRect(const QString &cell) const;
// methods to set title block basic data
void setFolio(const QString &folio);
+170
View File
@@ -0,0 +1,170 @@
/*
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/>.
*/
#include "cellruler.h"
#include "bordercelllabels.h"
#include "diagram.h"
#include "diagramview.h"
#include <QPainter>
#include <QSettings>
/**
@brief CellRuler::CellRuler
@param orientation : Qt::Horizontal for the column numbers along the
top, Qt::Vertical for the row letters along the left
@param view : the view this ruler is placed on
*/
CellRuler::CellRuler(Qt::Orientation orientation, DiagramView *view) :
QWidget(view),
m_orientation(orientation),
m_view(view)
{
setAttribute(Qt::WA_OpaquePaintEvent);
hide();
}
/**
@brief CellRuler::thickness
@return the height of the top ruler, which is also the width of the
side ruler, so the corner they share is square. Constant whatever the
zoom.
*/
int CellRuler::thickness() const
{
const QFontMetrics metrics = fontMetrics();
return qMax(metrics.height(), metrics.horizontalAdvance(QStringLiteral("WW"))) + 6;
}
/**
@brief CellRuler::setLeadingSpace
@param space : pixels left empty before the first pixel of the
viewport, along this ruler
*/
void CellRuler::setLeadingSpace(int space)
{
m_leading_space = space;
update();
}
/**
@brief CellRuler::paintEvent
Draw a cell for each column (or row) of the folio border, at the
position the view shows it. When the cells get too small for their
labels, only one label every 2, 5, 10... cells is written.
*/
void CellRuler::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
QPainter painter(this);
painter.fillRect(rect(), palette().color(QPalette::Button));
const bool horizontal = m_orientation == Qt::Horizontal;
const int length = horizontal ? width() : height();
const int depth = horizontal ? height() : width();
//Separate the ruler from the drawing
painter.setPen(palette().color(QPalette::Dark));
if (horizontal) {
painter.drawLine(0, depth - 1, length, depth - 1);
} else {
painter.drawLine(depth - 1, 0, depth - 1, length);
}
Diagram *diagram = m_view->diagram();
if (!diagram) {
return;
}
const BorderTitleBlock &border = diagram->border_and_titleblock;
const QRectF inside = border.insideBorderRect();
const QTransform transform = m_view->viewportTransform();
const int count = horizontal ? border.columnsCount() : border.rowsCount();
const qreal cell_size = horizontal ? border.columnsWidth() : border.rowsHeight();
const qreal first = horizontal ? inside.left() : inside.top();
const qreal scale = horizontal ? transform.m11() : transform.m22();
const qreal offset = (horizontal ? transform.dx() : transform.dy()) + m_leading_space;
const qreal cell_pixels = cell_size * scale;
if (count < 1 || cell_pixels <= 0) {
return;
}
const bool columns_start_at_zero =
QSettings().value("border-columns_0", true).toBool();
auto label = [&](int index) {
return horizontal ? BorderCellLabels::columnLabel(index, columns_start_at_zero)
: BorderCellLabels::rowLabel(index);
};
//Room one label needs along the ruler, and the smallest step
//between written labels that gives it that room
const QFontMetrics metrics = fontMetrics();
const int label_room = horizontal
? metrics.horizontalAdvance(label(count)) + 6
: metrics.height() + 2;
int step = 1;
for (int candidate : {1, 2, 5, 10, 20, 50, 100, 200, 500}) {
step = candidate;
if (candidate * cell_pixels >= label_room) {
break;
}
}
for (int i = 1 ; i <= count ; ++i) {
const qreal start = offset + (first + (i - 1) * cell_size) * scale;
const qreal end = start + cell_pixels;
if (end < m_leading_space || start > length) {
continue;
}
//Cell edges, drawn only when the cells are wide enough
//for them to read as cells rather than as a hatching
painter.setPen(palette().color(QPalette::Dark));
if (cell_pixels >= 4) {
if (horizontal) {
painter.drawLine(QPointF(start, 0), QPointF(start, depth - 1));
if (i == count) painter.drawLine(QPointF(end, 0), QPointF(end, depth - 1));
} else {
painter.drawLine(QPointF(0, start), QPointF(depth - 1, start));
if (i == count) painter.drawLine(QPointF(0, end), QPointF(depth - 1, end));
}
}
//Written labels are the ones a multiple of step: 0, 5, 10...
//for the columns, A, F, K... for the rows
const int position = (horizontal && !columns_start_at_zero) ? i : i - 1;
if (position % step != 0) {
continue;
}
painter.setPen(palette().color(QPalette::ButtonText));
const qreal centre = (start + end) / 2;
const QRectF text_rect = horizontal
? QRectF(centre - label_room / 2.0, 0, label_room, depth - 1)
: QRectF(0, centre - label_room / 2.0, depth - 1, label_room);
painter.drawText(text_rect, Qt::AlignCenter | Qt::TextDontClip, label(i));
}
//Keep the corner empty: the other ruler's labels do not belong there
if (m_leading_space > 0) {
painter.fillRect(horizontal ? QRect(0, 0, m_leading_space, depth - 1)
: QRect(0, 0, depth - 1, m_leading_space),
palette().color(QPalette::Button));
}
}
+54
View File
@@ -0,0 +1,54 @@
/*
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 CELLRULER_H
#define CELLRULER_H
#include <QWidget>
class DiagramView;
/**
@brief The CellRuler class
A bar along the top or the left edge of a DiagramView that repeats the
column numbers or the row letters of the folio border, aligned with the
cells at any zoom, so they stay in sight however far the view is
scrolled. It sits in the view's margins, outside of the scene: printing
and exporting are unaffected.
*/
class CellRuler : public QWidget
{
Q_OBJECT
public:
CellRuler(Qt::Orientation orientation, DiagramView *view);
int thickness() const;
void setLeadingSpace(int space);
protected:
void paintEvent(QPaintEvent *event) override;
private:
Qt::Orientation m_orientation;
DiagramView *m_view;
/// Pixels before the viewport starts, left empty: the corner the
/// side ruler fills when both rulers are shown.
int m_leading_space = 0;
};
#endif // CELLRULER_H
+24
View File
@@ -42,6 +42,7 @@
#include "qetinformation.h"
#include "qetproject.h"
#include "diagramsortkeys.h"
#include "textgrid.h"
#include <QTextStream>
#include <algorithm>
#include <climits>
@@ -2684,6 +2685,29 @@ QPointF Diagram::snapToGrid(const QPointF &p)
return (QPointF(p_x, p_y));
}
/**
@brief Diagram::snapToTextGrid
Return the nearest point of p on the text grid, see TextGrid.
Ctrl held rounds to the nearest pixel instead, as snapToGrid() does.
@param p point to find the nearest snapped point
@return
*/
QPointF Diagram::snapToTextGrid(const QPointF &p)
{
QSettings settings;
const qreal divisor =
QApplication::keyboardModifiers().testFlag(Qt::ControlModifier)
? 0
: settings.value(TextGrid::settings_key, 1).toReal();
return TextGrid::snap(p,
settings.value(QStringLiteral("diagrameditor/Xgrid"),
Diagram::xGrid).toInt(),
settings.value(QStringLiteral("diagrameditor/Ygrid"),
Diagram::yGrid).toInt(),
divisor);
}
/**
+1
View File
@@ -233,6 +233,7 @@ class Diagram : public QGraphicsScene
BorderOptions borderOptions();
DiagramPosition convertPosition(const QPointF &);
static QPointF snapToGrid(const QPointF &p);
static QPointF snapToTextGrid(const QPointF &p);
bool drawTerminals() const;
void setDrawTerminals(bool);
+125 -3
View File
@@ -16,6 +16,7 @@
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "diagramview.h"
#include "cellruler.h"
#include "lastusedstyle.h"
#include "qetproject.h"
#include "QPropertyUndoCommand/qpropertyundocommand.h"
@@ -43,6 +44,7 @@
#include <QDropEvent>
#include <QPainter>
#include <QPointer>
#include <algorithm>
/**
Constructeur
@@ -107,6 +109,13 @@ DiagramView::DiagramView(Diagram *diagram, QWidget *parent) :
connect(&(m_diagram -> border_and_titleblock), &BorderTitleBlock::informationChanged, this, &DiagramView::updateWindowTitle);
connect(diagram, &Diagram::findElementRequired, this, &DiagramView::findElementRequired);
m_top_ruler = new CellRuler(Qt::Horizontal, this);
m_side_ruler = new CellRuler(Qt::Vertical, this);
m_cell_rulers_shown = QSettings().value("diagrameditor/cell_rulers", false).toBool();
connect(&m_diagram->border_and_titleblock, &BorderTitleBlock::borderChanged, this, &DiagramView::updateCellRulers);
connect(&m_diagram->border_and_titleblock, &BorderTitleBlock::displayChanged, this, &DiagramView::updateCellRulers);
updateCellRulers();
QShortcut *edit_conductor_color_shortcut = new QShortcut(QKeySequence(Qt::Key_F2), this);
connect(edit_conductor_color_shortcut, &QShortcut::activated, [this]()
{
@@ -443,6 +452,23 @@ void DiagramView::zoomReset()
adjustGridToZoom();
}
/**
@brief DiagramView::zoomToRect
Adjust zoom to fit \a rect, in scene coordinate, in the view.
@param rect
*/
void DiagramView::zoomToRect(const QRectF &rect)
{
fitInView(rect, Qt::KeepAspectRatio);
//Zooming in makes the scroll bars appear, which resizes the viewport
//from a queued call; that resize is anchored under the mouse and
//would scroll away from rect, so center again once it has run.
QMetaObject::invokeMethod(this, [this, rect]() {
centerOn(rect.center());
}, Qt::QueuedConnection);
adjustGridToZoom();
}
/**
Copie les elements selectionnes du schema dans le presse-papier puis les supprime
Copies the selected elements from the diagram to the clipboard and then deletes them
@@ -1228,6 +1254,82 @@ void DiagramView::paintingInverted(bool inverted)
m_diagram->setInvertedLightness(inverted);
}
/**
@brief DiagramView::setCellRulersShown
Show or hide the rulers that keep the column numbers and the row
letters of the folio border in sight along the edges of this view.
@param shown
*/
void DiagramView::setCellRulersShown(bool shown)
{
m_cell_rulers_shown = shown;
updateCellRulers();
}
/**
@brief DiagramView::updateCellRulers
Show each ruler when the rulers are wanted and the folio shows the
matching header, and give it room in the margins of the view. The
part of the folio in sight stays in sight when the viewport resizes.
*/
void DiagramView::updateCellRulers()
{
const BorderTitleBlock &border = m_diagram->border_and_titleblock;
const bool top = m_cell_rulers_shown
&& border.borderIsDisplayed() && border.columnsAreDisplayed();
const bool side = m_cell_rulers_shown
&& border.borderIsDisplayed() && border.rowsAreDisplayed();
const int thickness = m_top_ruler->thickness();
m_top_ruler->setVisible(top);
m_side_ruler->setVisible(side);
m_side_ruler->setLeadingSpace(top ? thickness : 0);
const QMargins margins(side ? thickness : 0, top ? thickness : 0, 0, 0);
if (margins != viewportMargins()) {
const QPointF centre = mapToScene(viewport()->rect().center());
setViewportMargins(margins);
centerOn(centre);
}
placeCellRulers();
m_top_ruler->update();
m_side_ruler->update();
}
/**
@brief DiagramView::placeCellRulers
Lay the rulers along the top and the left edges of the viewport, the
side ruler covering the corner too when both are shown.
*/
void DiagramView::placeCellRulers()
{
if (!m_top_ruler) {
return;
}
const QRect viewport_rect = viewport()->geometry();
const int thickness = m_top_ruler->thickness();
const int corner = m_top_ruler->isHidden() ? 0 : thickness;
m_top_ruler->setGeometry(viewport_rect.left(), viewport_rect.top() - thickness,
viewport_rect.width(), thickness);
m_side_ruler->setGeometry(viewport_rect.left() - thickness, viewport_rect.top() - corner,
thickness, viewport_rect.height() + corner);
}
/**
@brief DiagramView::viewportEvent
Keep the rulers along the viewport when it resizes, which it also does
without the view resizing, when the scroll bars come and go.
@param event
@return what QGraphicsView::viewportEvent() returns
*/
bool DiagramView::viewportEvent(QEvent *event)
{
if (event->type() == QEvent::Resize) {
placeCellRulers();
}
return PaletteGraphicsView::viewportEvent(event);
}
/**
@brief DiagramView::paintEvent
Reimplemented from QGraphicsView
@@ -1237,6 +1339,13 @@ void DiagramView::paintEvent(QPaintEvent *event)
{
PaletteGraphicsView::paintEvent(event);
//Scrolling and zooming both repaint the viewport: follow them
if (viewportTransform() != m_rulers_transform) {
m_rulers_transform = viewportTransform();
m_top_ruler->update();
m_side_ruler->update();
}
if (m_free_rubberbanding && m_free_rubberband.count() >= 3)
{
QPainter painter(viewport());
@@ -1357,10 +1466,15 @@ QList<QAction *> DiagramView::contextMenuActions() const
{
if (m_diagram->selectedItems().isEmpty())
{
//Drawing comes first. The row and column actions change
//the folio's layout and are rarely wanted, so they sit one
//level down where a stray click cannot reach them.
list << m_paste_here;
list << m_separators.at(0);
list << qde->m_add_item_menu->menuAction();
list << m_separators.at(1);
list << qde->m_edit_diagram_properties;
list << qde->m_row_column_actions_group.actions();
list << qde->m_row_column_menu->menuAction();
}
else
{
@@ -1376,11 +1490,19 @@ QList<QAction *> DiagramView::contextMenuActions() const
list << qde->m_depth_action_group->actions();
}
//Remove from the context menu the actions which are disabled.
//Remove from the context menu the actions which are disabled,
//and the submenus in which every action is disabled.
const QList<QAction *> actions = list;
for(QAction *action : actions)
{
if (!action->isEnabled()) {
bool usable = action->isEnabled();
if (usable && action->menu())
{
const QList<QAction *> sub_actions = action->menu()->actions();
usable = std::any_of(sub_actions.cbegin(), sub_actions.cend(),
[](QAction *a) { return a->isEnabled(); });
}
if (!usable) {
list.removeAll(action);
}
}
+11
View File
@@ -24,6 +24,7 @@
#include <QClipboard>
#include "palettegraphicsview.h"
class CellRuler;
class Conductor;
class Diagram;
class QETDiagramEditor;
@@ -62,6 +63,11 @@ class DiagramView : public PaletteGraphicsView
QList<QAction *> m_separators;
QPolygonF m_free_rubberband;
bool m_free_rubberbanding = false;
CellRuler *m_top_ruler = nullptr;
CellRuler *m_side_ruler = nullptr;
bool m_cell_rulers_shown = false;
/// Last viewport transform the rulers were painted for
QTransform m_rulers_transform;
public:
@@ -78,6 +84,7 @@ class DiagramView : public PaletteGraphicsView
/// cursor query (QCursor::pos()/setPos() are silently ignored by
/// several window managers and compositors, Wayland included).
QPoint lastMousePos() const { return m_last_mouse_pos; }
void setCellRulersShown(bool shown);
bool startElementPlacement(const ElementsLocation &location,
const QPointF &scene_pos);
@@ -95,6 +102,7 @@ class DiagramView : public PaletteGraphicsView
///Set for one call only, by the Escape handler, to let focus leave the view.
bool m_releasing_focus = false;
void paintEvent(QPaintEvent *event) override;
bool viewportEvent(QEvent *event) override;
void paintingInverted(bool inverted) override;
void mousePressEvent(QMouseEvent *) override;
void mouseMoveEvent(QMouseEvent *) override;
@@ -117,6 +125,8 @@ class DiagramView : public PaletteGraphicsView
QRectF viewedSceneRect() const;
bool mustIntegrateTitleBlockTemplate(const TitleBlockTemplateLocation &) const;
bool gestures() const;
void updateCellRulers();
void placeCellRulers();
/// Lowest and highest allowed value of the view transform scale (m11).
/// Prevents wheel-zoom from driving the transform to overflow, which
@@ -147,6 +157,7 @@ class DiagramView : public PaletteGraphicsView
void zoomFit();
void zoomContent();
void zoomReset();
void zoomToRect(const QRectF &rect);
void cut();
void copy();
void paste(const QPointF & = QPointF(), QClipboard::Mode = QClipboard::Clipboard);
+23 -1
View File
@@ -22,8 +22,11 @@
#include "qetapp.h"
#include "qetgraphicsitem/dynamicelementtextitem.h"
#include "qetgraphicsitem/elementtextitemgroup.h"
#include "qetdiagrameditor.h"
#include "textgrid.h"
#include <QObject>
#include <QSettings>
/**
@brief ElementTextsMover::ElementTextsMover
@@ -80,6 +83,19 @@ int ElementTextsMover::beginMovement(Diagram *diagram, QGraphicsItem *driver_ite
return -1;
m_movement_running = true;
m_status_bar.clear();
if (!diagram->views().isEmpty())
if (const auto qde = QETApp::diagramEditorAncestorOf(diagram->views().at(0)))
m_status_bar = qde->statusBar();
if (m_status_bar)
{
const qreal divisor = QSettings().value(TextGrid::settings_key, 1).toReal();
m_status_bar->showMessage(divisor > 0
? QObject::tr("Grille des textes %1. Relâcher Maj et maintenir Ctrl pour placer librement.")
.arg(TextGrid::ratioLabel(divisor))
: QObject::tr("Grille des textes désactivée."));
}
return m_items_hash.size();
}
@@ -101,7 +117,7 @@ void ElementTextsMover::continueMovement(QGraphicsSceneMouseEvent *event)
button_down_parent_pos = qgi->mapToParent(qgi->mapFromScene(event->buttonDownScenePos(Qt::LeftButton)));
QPointF new_pos = m_items_hash.value(qgi) + current_parent_pos - button_down_parent_pos;
event->modifiers() == Qt::ControlModifier ? qgi->setPos(new_pos) : qgi->setPos(Diagram::snapToGrid(new_pos));
event->modifiers() == Qt::ControlModifier ? qgi->setPos(new_pos) : qgi->setPos(Diagram::snapToTextGrid(new_pos));
}
}
@@ -112,13 +128,19 @@ void ElementTextsMover::continueMovement(QGraphicsSceneMouseEvent *event)
void ElementTextsMover::endMovement()
{
//No movement or no items to move
if (m_status_bar)
m_status_bar->clearMessage();
if(!m_movement_running || m_items_hash.isEmpty())
return;
//Movement is null
QGraphicsItem *qgi = m_items_hash.keys().first();
if(qgi->pos() == m_items_hash.value(qgi))
{
m_movement_running = false;
return;
}
QUndoCommand *undo = new QUndoCommand(undoText());
+3
View File
@@ -21,6 +21,8 @@
#include <QSet>
#include <QPointF>
#include <QHash>
#include <QPointer>
#include <QStatusBar>
class QGraphicsItem;
class DiagramTextItem;
@@ -55,6 +57,7 @@ class ElementTextsMover
QHash <DiagramTextItem *, QPointF> m_texts_hash;
QHash <QGraphicsItemGroup *, QPointF> m_grps_hash;
QHash <QGraphicsItem *, QPointF> m_items_hash;
QPointer<QStatusBar> m_status_bar;
int m_text_count = 0,
m_group_count = 0;
};
+1
View File
@@ -2231,6 +2231,7 @@ void QETApp::configureQET()
// affiche le dialogue puis evite de le lier a un quelconque widget parent
cd.exec();
cd.setParent(nullptr, cd.windowFlags());
emit textGridChanged();
#ifdef QET_SPACEMOUSE_SUPPORT
if (m_space_mouse_listener) {
+4
View File
@@ -260,6 +260,10 @@ class QETApp : public QObject
static QString m_interface_language;
signals:
/// The text grid setting changed, see TextGrid.
void textGridChanged();
public slots:
void systray(QSystemTrayIcon::ActivationReason);
void reduceEveryEditor();
+74 -3
View File
@@ -20,6 +20,7 @@
#include "scripting/qetscripting.h"
#endif
#include <QCoreApplication>
#include <QToolButton>
#include "ElementsCollection/elementscollectionwidget.h"
#include "QWidgetAnimation/qwidgetanimation.h"
#include "autoNum/ui/autonumberingdockwidget.h"
@@ -48,6 +49,7 @@
#include "qeticons.h"
#include "qetmessagebox.h"
#include "recentfiles.h"
#include "textgrid.h"
#include "shortcutmanager.h"
#include "ui/bomexportdialog.h"
#include "ui/conductorcolortoolbutton.h"
@@ -488,6 +490,33 @@ void QETDiagramEditor::setUpActions()
}
});
//Snap step for dragged texts, as a fraction of the folio grid
m_text_grid_menu = new QMenu(tr("Grille des textes"), this);
m_text_grid_menu->setIcon(QET::Icons::Grid);
m_text_grid_menu->setToolTipsVisible(true);
m_text_grid_button = new QToolButton(this);
m_text_grid_button->setMenu(m_text_grid_menu);
m_text_grid_button->setPopupMode(QToolButton::InstantPopup);
m_text_grid_button->setToolButtonStyle(Qt::ToolButtonTextOnly);
m_text_grid_button->setToolTip(tr("Grille d'accrochage des textes déplacés à la souris.\n"
"Maintenir Ctrl pendant le déplacement pour placer librement."));
auto text_grid_group = new QActionGroup(this);
for (const qreal divisor : TextGrid::divisors)
{
QAction *action = m_text_grid_menu->addAction(
divisor > 0 ? TextGrid::ratioLabel(divisor) : tr("Désactivée"));
action->setCheckable(true);
action->setData(divisor);
text_grid_group->addAction(action);
}
connect(text_grid_group, &QActionGroup::triggered, this, [](QAction *action) {
QSettings().setValue(TextGrid::settings_key, action->data());
emit QETApp::instance()->textGridChanged();
});
connect(QETApp::instance(), &QETApp::textGridChanged,
this, &QETDiagramEditor::updateTextGridButton);
updateTextGridButton();
// Draw or not the custom guides
m_draw_guides = new QAction ( QIcon::fromTheme("guides"), tr("Afficher les guides"), this);
m_draw_guides->setStatusTip(tr("Affiche ou masque les guides"));
@@ -500,6 +529,18 @@ void QETDiagramEditor::setUpActions()
}
});
//Keep the column numbers and row letters of the folio in sight
m_cell_rulers = new QAction(tr("Garder les en-têtes visibles"), this);
m_cell_rulers->setStatusTip(tr("Garde les numéros de colonne et les lettres de ligne du folio visibles au bord de la vue"));
m_cell_rulers->setCheckable(true);
m_cell_rulers->setChecked(settings.value("diagrameditor/cell_rulers", false).toBool());
connect(m_cell_rulers, &QAction::triggered, [this](bool checked) {
QSettings().setValue("diagrameditor/cell_rulers", checked);
foreach (ProjectView *prjv, this->openedProjects())
foreach (DiagramView *dv, prjv->diagram_views())
dv->setCellRulersShown(checked);
});
//Edit current diagram properties
m_edit_diagram_properties = new QAction(QET::Icons::DialogInformation, tr("Propriétés du folio"), this);
ShortcutManager::instance().registerAction(m_edit_diagram_properties, "diagrameditor.edit_diagram_properties", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_L);
@@ -983,6 +1024,7 @@ void QETDiagramEditor::setUpToolBar()
view_tool_bar -> addWidget(new DiagramEditorHandlerSizeWidget(this));
view_tool_bar -> addSeparator();
view_tool_bar -> addAction(m_draw_grid);
view_tool_bar -> addWidget(m_text_grid_button);
view_tool_bar -> addAction(m_draw_guides);
view_tool_bar -> addWidget(m_background_color_button);
view_tool_bar -> addSeparator();
@@ -1072,9 +1114,9 @@ void QETDiagramEditor::setUpMenu()
//toolbar button has no key, so text fields, images and every drawing
//shape simply could not be added. m_depth_action_group below has
//always been in both places; this brings these into line with it.
QMenu *menu_add_item = menu_edition -> addMenu(tr("A&jouter"));
menu_add_item -> setIcon(QET::Icons::Add);
menu_add_item -> addActions(m_add_item_actions_group.actions());
m_add_item_menu = menu_edition -> addMenu(tr("A&jouter"));
m_add_item_menu -> setIcon(QET::Icons::Add);
m_add_item_menu -> addActions(m_add_item_actions_group.actions());
menu_edition -> addSeparator();
menu_edition -> addActions(m_select_actions_group.actions());
menu_edition -> addSeparator();
@@ -1084,6 +1126,12 @@ void QETDiagramEditor::setUpMenu()
menu_edition -> addSeparator();
menu_edition -> addAction(m_edit_diagram_properties);
menu_edition -> addActions(m_row_column_actions_group.actions());
//Not added to a menu here: it exists so the folio's context menu can
//hold the row and column actions one level down (see
//DiagramView::contextMenuActions()).
m_row_column_menu = new QMenu(tr("Lignes et colonnes"), this);
m_row_column_menu -> setIcon(QET::Icons::EditTableInsertColumnRight);
m_row_column_menu -> addActions(m_row_column_actions_group.actions());
menu_edition -> addSeparator();
menu_edition -> addActions(m_depth_action_group->actions());
menu_edition -> addSeparator();
@@ -1137,7 +1185,9 @@ void QETDiagramEditor::setUpMenu()
menu_affichage -> addAction(m_mode_visualise);
menu_affichage -> addSeparator();
menu_affichage -> addAction(m_draw_grid);
menu_affichage -> addMenu(m_text_grid_menu);
menu_affichage -> addAction(m_draw_guides);
menu_affichage -> addAction(m_cell_rulers);
menu_affichage -> addMenu(m_background_color_button->menu());
menu_affichage -> addSeparator();
menu_affichage -> addActions(m_zoom_actions_group.actions());
@@ -1970,6 +2020,7 @@ void QETDiagramEditor::slot_updateActions()
m_background_color_button-> setEnabled(opened_diagram);
m_draw_grid-> setEnabled(opened_diagram);
m_draw_guides-> setEnabled(opened_diagram);
m_cell_rulers-> setEnabled(opened_diagram);
//Project menu
m_project_edit_properties -> setEnabled(opened_project);
@@ -3301,3 +3352,23 @@ void QETDiagramEditor::slot_runScript() {
QetScripting::runOnProject(script_path, project, currentDiagramView());
}
#endif
/**
@brief QETDiagramEditor::updateTextGridButton
Show the current text grid on its toolbar button and check it in its menu.
*/
void QETDiagramEditor::updateTextGridButton()
{
const qreal divisor = QSettings().value(TextGrid::settings_key, 1).toReal();
for (QAction *action : m_text_grid_menu->actions())
{
if (qFuzzyCompare(action->data().toReal() + 1, divisor + 1))
{
action->setChecked(true);
m_text_grid_button->setText(tr("Textes %1").arg(action->text()));
return;
}
}
//A divisor the menu does not offer, set by hand in the config file
m_text_grid_button->setText(tr("Textes %1").arg(TextGrid::ratioLabel(divisor)));
}
+10
View File
@@ -28,6 +28,8 @@
#include <QSignalMapper>
#include <QUndoGroup>
class QToolButton;
class QMdiSubWindow;
class QETProject;
class QETResult;
@@ -167,6 +169,7 @@ class QETDiagramEditor : public QETMainWindow
void subWindowActivated(QMdiSubWindow *subWindows);
private slots:
void updateTextGridButton();
void selectionChanged();
public:
@@ -180,6 +183,10 @@ class QETDiagramEditor : public QETMainWindow
m_row_column_actions_group, /// Action related to add/remove rows/column in diagram
m_selection_actions_group, ///Action related to edit a selected item
*m_depth_action_group = nullptr;
QMenu
*m_add_item_menu = nullptr, ///< Submenu of m_add_item_actions_group
*m_row_column_menu = nullptr; ///< Submenu of m_row_column_actions_group
private:
QActionGroup
@@ -208,6 +215,7 @@ class QETDiagramEditor : public QETMainWindow
*m_auto_break_conductor, ///< Enable/Disable the use of auto break conductor
*m_draw_grid, ///< Switch the background grid display or not
*m_draw_guides = nullptr, ///< Switch the custom guides display or not
*m_cell_rulers = nullptr, ///< Keep the folio column/row headers in sight or not
*m_project_edit_properties, ///< Edit the properties of the current project.
*m_project_add_diagram, ///< Add a diagram to the current project.
*m_remove_diagram_from_project, ///< Delete a diagram from the current project
@@ -247,6 +255,8 @@ class QETDiagramEditor : public QETMainWindow
ConductorColorToolButton *m_conductor_color_button = nullptr;
///< Diagram background color picker, in the "Affichage" toolbar
DiagramBgColorToolButton *m_background_color_button = nullptr;
QMenu *m_text_grid_menu = nullptr; ///< Snap step used when dragging texts
QToolButton *m_text_grid_button = nullptr;
QList <QAction *> m_zoom_action_toolBar; ///Only zoom action must displayed in the toolbar
@@ -185,7 +185,7 @@ void ConductorTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
if (parent_conductor_) {
if (parent_conductor_->nearShape().contains(intended_pos)) {
event->modifiers() == Qt::ControlModifier ? setPos(intended_pos) : setPos(Diagram::snapToGrid(intended_pos));
event->modifiers() == Qt::ControlModifier ? setPos(intended_pos) : setPos(Diagram::snapToTextGrid(intended_pos));
parent_conductor_ -> setHighlighted(Conductor::Normal);
} else {
parent_conductor_ -> setHighlighted(Conductor::Alert);
+1 -1
View File
@@ -370,7 +370,7 @@ void DiagramTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
//Set the actual pos
QPointF new_pos = event->scenePos() + m_mouse_to_origin_movement;
event->modifiers() == Qt::ControlModifier ? setPos(new_pos) : setPos(Diagram::snapToGrid(new_pos));
event->modifiers() == Qt::ControlModifier ? setPos(new_pos) : setPos(Diagram::snapToTextGrid(new_pos));
//Update the actual movement for other selected item
@@ -639,7 +639,7 @@ void DynamicElementTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
//DiagramTextItem::mouseMoveEvent() for independent texts.
//Without it this was the only text move in the editor that
//ignored the grid.
event->modifiers() == Qt::ControlModifier ? setPos(new_pos) : setPos(Diagram::snapToGrid(new_pos));
event->modifiers() == Qt::ControlModifier ? setPos(new_pos) : setPos(Diagram::snapToTextGrid(new_pos));
if(diagram())
diagram()->elementTextsMover().continueMovement(event);
@@ -688,7 +688,7 @@ void ElementTextItemGroup::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
button_down_parent_pos = mapToParent(mapFromScene(event->buttonDownScenePos(Qt::LeftButton)));
QPointF new_pos = m_initial_position + current_parent_pos - button_down_parent_pos;
event->modifiers() == Qt::ControlModifier ? setPos(new_pos) : setPos(Diagram::snapToGrid(new_pos));
event->modifiers() == Qt::ControlModifier ? setPos(new_pos) : setPos(Diagram::snapToTextGrid(new_pos));
if(diagram())
diagram()->elementTextsMover().continueMovement(event);
+62
View File
@@ -0,0 +1,62 @@
/*
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 TEXTGRID_H
#define TEXTGRID_H
#include <QList>
#include <QPointF>
#include <QString>
#include <QtMath>
/**
The text grid: the step texts snap to when dragged with the mouse,
a fraction of the folio grid. A divisor of 1 is the folio grid itself,
0 means no grid. Because every step divides the folio grid, a text
snapped to it still lines up with every element and with the texts
of other elements.
*/
namespace TextGrid
{
/// The choices offered in the menu and the preferences, 0 first.
inline const QList<qreal> divisors{0, 1, 2, 5, 10};
/// QSettings key holding the divisor.
inline const QString settings_key{QStringLiteral("diagrameditor/text_grid_divisor")};
/// "1:5" for 5. Not meaningful for 0.
inline QString ratioLabel(qreal divisor) {
return QStringLiteral("1:") + QString::number(divisor);
}
/**
@return p snapped to a grid of x_grid / divisor by y_grid / divisor,
or rounded to the nearest pixel when divisor is 0 or less.
*/
inline QPointF snap(const QPointF &p, int x_grid, int y_grid, qreal divisor)
{
if (divisor <= 0 || x_grid <= 0 || y_grid <= 0)
return QPointF(qRound(p.x()), qRound(p.y()));
const qreal x_step = x_grid / divisor;
const qreal y_step = y_grid / divisor;
return QPointF(qRound(p.x() / x_step) * x_step,
qRound(p.y() / y_step) * y_step);
}
}
#endif // TEXTGRID_H
@@ -23,6 +23,7 @@
#include "../../utils/qetsettings.h"
#include "../../utils/qetutils.h"
#include "../../qetmessagebox.h"
#include "../../textgrid.h"
#include "../nokde/kcolorbutton.h"
#include <QFileDialog>
#include <QFontDialog>
@@ -71,6 +72,15 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) :
ui->m_collection_dblclick_edits->setChecked(!settings.value("elementscollection/double-click-inserts", true).toBool());
ui->DiagramEditor_xGrid_sb->setValue(settings.value("diagrameditor/Xgrid", 10).toInt());
ui->DiagramEditor_yGrid_sb->setValue(settings.value("diagrameditor/Ygrid", 10).toInt());
for (const qreal divisor : TextGrid::divisors)
ui->DiagramEditor_textGrid_cb->addItem(
divisor > 0 ? TextGrid::ratioLabel(divisor) : tr("Désactivée"),
divisor);
int text_grid_index = ui->DiagramEditor_textGrid_cb->findData(
settings.value(TextGrid::settings_key, 1).toReal());
if (text_grid_index < 0)
text_grid_index = ui->DiagramEditor_textGrid_cb->findData(qreal(1));
ui->DiagramEditor_textGrid_cb->setCurrentIndex(text_grid_index);
ui->DiagramEditor_xKeyGrid_sb->setValue(settings.value("diagrameditor/key_Xgrid", 10).toInt());
ui->DiagramEditor_yKeyGrid_sb->setValue(settings.value("diagrameditor/key_Ygrid", 10).toInt());
ui->DiagramEditor_xKeyGridFine_sb->setValue(settings.value("diagrameditor/key_fine_Xgrid", 1).toInt());
@@ -291,6 +301,7 @@ void GeneralConfigurationPage::applyConf()
//Grid step and key navigation
settings.setValue("diagrameditor/Xgrid", ui->DiagramEditor_xGrid_sb->value());
settings.setValue("diagrameditor/Ygrid", ui->DiagramEditor_yGrid_sb->value());
settings.setValue(TextGrid::settings_key, ui->DiagramEditor_textGrid_cb->currentData());
settings.setValue("diagrameditor/key_Xgrid", ui->DiagramEditor_xKeyGrid_sb->value());
settings.setValue("diagrameditor/key_Ygrid", ui->DiagramEditor_yKeyGrid_sb->value());
settings.setValue("diagrameditor/key_fine_Xgrid", ui->DiagramEditor_xKeyGridFine_sb->value());
@@ -794,6 +794,26 @@ Vous pouvez spécifier ici la valeur par défaut de ce champ pour les éléments
</property>
</spacer>
</item>
<item row="3" column="0">
<widget class="QLabel" name="Label_Diagram_textGrid">
<property name="text">
<string>Grille des textes déplacés à la souris</string>
</property>
<property name="toolTip">
<string>Fraction de la grille des folios. Maintenir Ctrl pendant le déplacement pour placer librement.</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QComboBox" name="DiagramEditor_textGrid_cb">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
</item>
+116 -1
View File
@@ -18,12 +18,15 @@
#include "jumptoelementdialog.h"
#include "../diagram.h"
#include "../diagramview.h"
#include "../qetproject.h"
#include "../qetgraphicsitem/element.h"
#include <QEvent>
#include <QKeyEvent>
#include <QLineEdit>
#include <QListWidget>
#include <QRegularExpression>
#include <QVBoxLayout>
/**
@@ -38,7 +41,7 @@ JumpToElementDialog::JumpToElementDialog(Diagram *diagram, QWidget *parent) :
setWindowTitle(tr("Atteindre un élément", "window title"));
m_filter_edit = new QLineEdit(this);
m_filter_edit->setPlaceholderText(tr("Nom, label ou information de l'élément…"));
m_filter_edit->setPlaceholderText(tr("Nom, label ou information de l'élément, ou case (ex. B13 ou 3-B13)…"));
m_filter_edit->installEventFilter(this);
m_result_list = new QListWidget(this);
@@ -86,6 +89,7 @@ void JumpToElementDialog::buildCandidates()
Candidate candidate;
candidate.element = element;
candidate.label = label;
candidate.display_text = label.isEmpty() ? name : (label + QStringLiteral(" — ") + name);
QStringList search_parts;
@@ -111,6 +115,7 @@ void JumpToElementDialog::updateFilteredList(const QString &filter_text)
m_result_list->clear();
const QString needle = filter_text.trimmed().toLower();
bool exact_label_match = false;
for (int i = 0; i < m_candidates.size(); ++i) {
const Candidate &candidate = m_candidates.at(i);
if (!candidate.element) {
@@ -121,6 +126,18 @@ void JumpToElementDialog::updateFilteredList(const QString &filter_text)
}
auto *list_item = new QListWidgetItem(candidate.display_text, m_result_list);
list_item->setData(Qt::UserRole, i);
if (candidate.label.compare(needle, Qt::CaseInsensitive) == 0) {
exact_label_match = true;
}
}
//A cell of the border, on this folio (ex : B13) or on another one
//(ex : 3-B13, folio 3, the way cross references write it), comes
//first, unless an element is labelled exactly like it: Enter keeps
//jumping to that element.
if (QListWidgetItem *cell_item = cellItem(needle)) {
m_result_list->insertItem(exact_label_match ? m_result_list->count() : 0,
cell_item);
}
if (m_result_list->count() > 0) {
@@ -142,6 +159,17 @@ void JumpToElementDialog::activateCurrentItem()
}
const int index = current->data(Qt::UserRole).toInt();
if (index == -1) {
const QList<Diagram *> diagrams = m_diagram->project()
? m_diagram->project()->diagrams()
: QList<Diagram *>();
const int folio = current->data(Qt::UserRole + 2).toInt();
if (folio >= 0 && folio < diagrams.size()) {
zoomToCell(diagrams.at(folio), current->data(Qt::UserRole + 1).toRectF());
}
accept();
return;
}
if (index < 0 || index >= m_candidates.size()) {
reject();
return;
@@ -159,6 +187,93 @@ void JumpToElementDialog::activateCurrentItem()
accept();
}
/**
@brief JumpToElementDialog::cellItem
@param needle : the typed text, trimmed and lower case
@return a new list item for the cell \a needle names, on m_diagram
(ex : b13) or on the folio at a position of the project (ex : 3-b13,
3b13, p3b13), or nullptr if \a needle names no cell of an existing
folio. The item holds -1, the cell rect and the folio position.
*/
QListWidgetItem *JumpToElementDialog::cellItem(const QString &needle) const
{
if (!m_diagram || !m_diagram->project()) {
return nullptr;
}
const QList<Diagram *> diagrams = m_diagram->project()->diagrams();
Diagram *diagram = m_diagram;
QString cell = needle;
QString text;
QRectF cell_rect = diagram->border_and_titleblock.cellRect(cell);
if (cell_rect.isNull()) {
//A folio position then a cell, like %f-%l%c in cross references
static const QRegularExpression folio_cell_re(
QStringLiteral("^p?\\s*(\\d{1,4})\\s*[-/.:]?\\s*([a-z]+\\s*\\d{1,4})$"));
const QRegularExpressionMatch match = folio_cell_re.match(needle);
if (!match.hasMatch()) {
return nullptr;
}
const int folio = match.captured(1).toInt();
if (folio < 1 || folio > diagrams.size()) {
return nullptr;
}
diagram = diagrams.at(folio - 1);
cell = match.captured(2);
cell_rect = diagram->border_and_titleblock.cellRect(cell);
if (cell_rect.isNull()) {
return nullptr;
}
}
cell = cell.remove(QLatin1Char(' ')).toUpper();
if (diagram == m_diagram) {
text = tr("Case %1").arg(cell);
} else {
const QString title = diagram->title();
text = title.isEmpty()
? tr("Folio %1, case %2").arg(diagrams.indexOf(diagram) + 1).arg(cell)
: tr("Folio %1 (%2), case %3").arg(diagrams.indexOf(diagram) + 1).arg(title, cell);
}
auto *item = new QListWidgetItem(text);
item->setData(Qt::UserRole, -1);
item->setData(Qt::UserRole + 1, cell_rect);
item->setData(Qt::UserRole + 2, diagrams.indexOf(diagram));
return item;
}
/**
@brief JumpToElementDialog::zoomToCell
Show \a diagram and zoom its view on \a cell_rect with one cell of
context around it.
@param diagram : the folio holding the cell
@param cell_rect : the cell, in scene coordinate
*/
void JumpToElementDialog::zoomToCell(Diagram *diagram, const QRectF &cell_rect)
{
const QRectF rect = cell_rect.adjusted(-cell_rect.width(), -cell_rect.height(),
cell_rect.width(), cell_rect.height());
const bool other_folio = diagram != m_diagram;
if (other_folio) {
diagram->showMe();
}
for (QGraphicsView *view : diagram->views()) {
if (auto *diagram_view = qobject_cast<DiagramView *>(view)) {
if (other_folio) {
//A folio shown for the first time is laid out at
//its size once the tab switch has been handled
QMetaObject::invokeMethod(diagram_view, [diagram_view, rect]() {
diagram_view->zoomToRect(rect);
}, Qt::QueuedConnection);
} else {
diagram_view->zoomToRect(rect);
}
return;
}
}
}
/**
@brief JumpToElementDialog::eventFilter
Redirect Up/Down/Enter/Escape typed in the filter field to the result
+6 -1
View File
@@ -25,13 +25,15 @@ class Diagram;
class Element;
class QLineEdit;
class QListWidget;
class QListWidgetItem;
/**
@brief The JumpToElementDialog class
A lightweight, transient "quick open" popup: type part of an element's
label or other information to live-filter the elements on a diagram,
then Enter to select the chosen element on the diagram and scroll it
into view. Up/Down move through the filtered list, Escape cancels
into view. Typing a cell of the border instead (ex : B13, or 3-B13 for
the third folio of the project) offers to zoom on that cell. Up/Down move through the filtered list, Escape cancels
without changing the current selection.
*/
class JumpToElementDialog : public QDialog
@@ -51,9 +53,12 @@ class JumpToElementDialog : public QDialog
private:
void buildCandidates();
QListWidgetItem *cellItem(const QString &needle) const;
void zoomToCell(Diagram *diagram, const QRectF &cell_rect);
struct Candidate {
QPointer<Element> element;
QString label;
QString display_text;
QString search_text;
};