mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-08 13:04:13 +02:00
Merge pull request #1378 from ispyisail/feature/symbol-scale
Add Scale element to the element editor, keeping terminals on the grid
This commit is contained in:
@@ -470,6 +470,8 @@ set(QET_SRC_FILES
|
||||
${QET_DIR}/sources/editor/ui/polygoneditor.h
|
||||
${QET_DIR}/sources/editor/ui/rectangleeditor.cpp
|
||||
${QET_DIR}/sources/editor/ui/rectangleeditor.h
|
||||
${QET_DIR}/sources/editor/ui/scaleelementdialog.cpp
|
||||
${QET_DIR}/sources/editor/ui/scaleelementdialog.h
|
||||
${QET_DIR}/sources/editor/ui/terminaleditor.cpp
|
||||
${QET_DIR}/sources/editor/ui/terminaleditor.h
|
||||
${QET_DIR}/sources/editor/ui/texteditor.cpp
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
#include "editorcommands.h"
|
||||
#include "../diagram.h"
|
||||
#include "symbolscale.h"
|
||||
|
||||
/**
|
||||
@brief ElementEditionCommand::ElementEditionCommand
|
||||
@@ -785,3 +786,97 @@ void FlipElementsCommand::undo()
|
||||
{
|
||||
redo();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ScaleElementCommand::ScaleElementCommand
|
||||
@param scene : the element to scale
|
||||
@param factor : scale factor, applied about the hotspot
|
||||
@param scale_text : also scale font sizes
|
||||
@param parent : parent undo command
|
||||
*/
|
||||
ScaleElementCommand::ScaleElementCommand(ElementScene *scene,
|
||||
qreal factor,
|
||||
bool scale_text,
|
||||
QUndoCommand *parent) :
|
||||
ElementEditionCommand(QObject::tr("mise à l'échelle de l'élément", "undo caption"),
|
||||
scene, nullptr, parent),
|
||||
m_factor(factor)
|
||||
{
|
||||
const auto scaledFont = [factor, scale_text](QFont font) {
|
||||
if (scale_text) {
|
||||
if (font.pointSizeF() > 0) {
|
||||
font.setPointSize(SymbolScale::scaledFontSize(font.pointSizeF(), factor));
|
||||
} else if (font.pixelSize() > 0) {
|
||||
font.setPixelSize(SymbolScale::scaledFontSize(font.pixelSize(), factor));
|
||||
}
|
||||
}
|
||||
return font;
|
||||
};
|
||||
|
||||
const auto parts = scene->primitives();
|
||||
for (CustomElementPart *part : parts)
|
||||
{
|
||||
QGraphicsItem *item = part->toItem();
|
||||
//Font before position: changing the font can move a text
|
||||
//to keep its alignment.
|
||||
if (auto text = qgraphicsitem_cast<PartText *>(item)) {
|
||||
addChange(text, "font", scaledFont(text->font()));
|
||||
addChange(text, "pos", text->pos() * factor);
|
||||
}
|
||||
else if (auto field = qgraphicsitem_cast<PartDynamicTextField *>(item)) {
|
||||
addChange(field, "font", scaledFont(field->font()));
|
||||
if (field->textWidth() > 0) {
|
||||
addChange(field, "textWidth", field->textWidth() * factor);
|
||||
}
|
||||
addChange(field, "pos", field->pos() * factor);
|
||||
}
|
||||
else if (auto terminal = qgraphicsitem_cast<PartTerminal *>(item)) {
|
||||
addChange(terminal, "label_font", scaledFont(terminal->labelFont()));
|
||||
addChange(terminal, "label_pos", terminal->labelPos() * factor);
|
||||
addChange(terminal, "pos", terminal->pos() * factor);
|
||||
}
|
||||
else {
|
||||
m_geometry_parts << part;
|
||||
if (auto line = qgraphicsitem_cast<PartLine *>(item)) {
|
||||
addChange(line, "length1", line->firstEndLength() * factor);
|
||||
addChange(line, "length2", line->secondEndLength() * factor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScaleElementCommand::addChange(QObject *object, const char *name, const QVariant &after)
|
||||
{
|
||||
m_changes << PropertyChange{object, name, object->property(name), after};
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ScaleElementCommand::scaleGeometry
|
||||
Scale the drawn parts about the hotspot, from \a from times their
|
||||
original size to \a to times it.
|
||||
*/
|
||||
void ScaleElementCommand::scaleGeometry(qreal from, qreal to)
|
||||
{
|
||||
const QRectF before(0, 0, from, from);
|
||||
const QRectF after(0, 0, to, to);
|
||||
for (CustomElementPart *part : std::as_const(m_geometry_parts)) {
|
||||
part->startUserTransformation(before);
|
||||
part->handleUserTransformation(before, after);
|
||||
}
|
||||
}
|
||||
|
||||
void ScaleElementCommand::undo()
|
||||
{
|
||||
scaleGeometry(m_factor, 1);
|
||||
for (const PropertyChange &change : std::as_const(m_changes)) {
|
||||
change.object->setProperty(change.name.constData(), change.before);
|
||||
}
|
||||
}
|
||||
|
||||
void ScaleElementCommand::redo()
|
||||
{
|
||||
scaleGeometry(1, m_factor);
|
||||
for (const PropertyChange &change : std::as_const(m_changes)) {
|
||||
change.object->setProperty(change.name.constData(), change.after);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,4 +315,37 @@ private:
|
||||
qreal m_axis_y = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@brief The ScaleElementCommand class
|
||||
Scales the whole element about its hotspot by a fixed factor, as one
|
||||
undo step. Drawn parts are scaled the way the resize handles scale them;
|
||||
texts, dynamic text fields and terminals are set explicitly, so their
|
||||
font sizes, terminal name offsets and line end sizes follow too, and a
|
||||
terminal lands exactly on its new position.
|
||||
*/
|
||||
class ScaleElementCommand : public ElementEditionCommand
|
||||
{
|
||||
public:
|
||||
ScaleElementCommand(ElementScene *scene, qreal factor,
|
||||
bool scale_text, QUndoCommand *parent = nullptr);
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
private:
|
||||
struct PropertyChange {
|
||||
QObject *object;
|
||||
QByteArray name;
|
||||
QVariant before;
|
||||
QVariant after;
|
||||
};
|
||||
void addChange(QObject *object, const char *name, const QVariant &after);
|
||||
void scaleGeometry(qreal from, qreal to);
|
||||
|
||||
qreal m_factor;
|
||||
/// Parts scaled through handleUserTransformation()
|
||||
QList<CustomElementPart *> m_geometry_parts;
|
||||
/// Values set directly, in the order they are applied
|
||||
QList<PropertyChange> m_changes;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
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 SYMBOLSCALE_H
|
||||
#define SYMBOLSCALE_H
|
||||
|
||||
#include <QList>
|
||||
#include <QPointF>
|
||||
#include <QtMath>
|
||||
|
||||
/**
|
||||
Which factors an element can be scaled by, in the element editor, without
|
||||
taking its terminals off the grid of the folio.
|
||||
|
||||
A terminal's position is its wire end, relative to the hotspot, and the
|
||||
hotspot of a placed element sits on a grid point. So the wires of an
|
||||
element line up with the grid when every terminal coordinate is a
|
||||
multiple of the grid size. The element is scaled about its hotspot, so a
|
||||
factor is safe when every coordinate times the factor is still a
|
||||
multiple of the grid size.
|
||||
|
||||
The same rule covers an element whose terminals are off the grid today:
|
||||
the factors offered are the ones that bring them all on to it.
|
||||
*/
|
||||
namespace SymbolScale
|
||||
{
|
||||
/// The folio grid the collection is drawn to. Fixed rather than read
|
||||
/// from the user's settings: elements are shared between users.
|
||||
constexpr int grid = 10;
|
||||
|
||||
/// The factors offered, in the order shown.
|
||||
inline QList<qreal> candidates()
|
||||
{
|
||||
return {0.5, 1.5, 2.0, 2.5, 3.0, 4.0};
|
||||
}
|
||||
|
||||
/// True if \a value is a multiple of \a grid_size, ignoring the
|
||||
/// rounding left by saving with two decimals.
|
||||
inline bool onGrid(qreal value, int grid_size = grid)
|
||||
{
|
||||
const qreal steps = value / grid_size;
|
||||
return qAbs(steps - qRound(steps)) * grid_size < 0.005;
|
||||
}
|
||||
|
||||
/// True if every terminal in \a terminals is on the grid.
|
||||
inline bool allOnGrid(const QList<QPointF> &terminals, int grid_size = grid)
|
||||
{
|
||||
for (const QPointF &p : terminals) {
|
||||
if (!onGrid(p.x(), grid_size) || !onGrid(p.y(), grid_size)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// How many of \a terminals are off the grid.
|
||||
inline int offGridCount(const QList<QPointF> &terminals, int grid_size = grid)
|
||||
{
|
||||
int count = 0;
|
||||
for (const QPointF &p : terminals) {
|
||||
if (!onGrid(p.x(), grid_size) || !onGrid(p.y(), grid_size)) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/// The candidate factors that leave every terminal of \a terminals on
|
||||
/// the grid. An element with no terminal can take any of them.
|
||||
inline QList<qreal> safeFactors(const QList<QPointF> &terminals, int grid_size = grid)
|
||||
{
|
||||
QList<qreal> safe;
|
||||
for (const qreal factor : candidates()) {
|
||||
QList<QPointF> scaled;
|
||||
for (const QPointF &p : terminals) {
|
||||
scaled << p * factor;
|
||||
}
|
||||
if (allOnGrid(scaled, grid_size)) {
|
||||
safe << factor;
|
||||
}
|
||||
}
|
||||
return safe;
|
||||
}
|
||||
|
||||
/// Font size after scaling by \a factor: whole points, and never
|
||||
/// below 4 pt, so a halved element keeps readable text.
|
||||
inline int scaledFontSize(qreal size, qreal factor)
|
||||
{
|
||||
return qMax(4, qRound(size * factor));
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SYMBOLSCALE_H
|
||||
@@ -54,6 +54,7 @@
|
||||
#include "../../dxf/dxftoelmt.h"
|
||||
#include "../../qet_elementscaler/qet_elementscaler.h"
|
||||
#include "../UndoCommand/openelmtcommand.h"
|
||||
#include "scaleelementdialog.h"
|
||||
#include "../../toolbarsettings.h"
|
||||
|
||||
#include <QSettings>
|
||||
@@ -1154,6 +1155,12 @@ void QETElementEditor::setupActions()
|
||||
ShortcutManager::instance().registerAction(ui->m_mirror_action, "elementeditor.mirror", tr("Éditeur d'élément"), Qt::Key_M);
|
||||
connect(ui->m_mirror_action, &QAction::triggered, [this]() {this -> elementScene() -> undoStack().push(new MirrorElementsCommand(this->elementScene()));});
|
||||
|
||||
//Scale the whole element by a factor that keeps its terminals on the grid
|
||||
m_scale_element_action = new QAction(tr("Mettre l'élément à l'échelle..."), this);
|
||||
ui->m_edit_menu->addAction(m_scale_element_action);
|
||||
ShortcutManager::instance().registerAction(m_scale_element_action, "elementeditor.scale_element", tr("Éditeur d'élément"), QKeySequence());
|
||||
connect(m_scale_element_action, &QAction::triggered, this, &QETElementEditor::scaleElement);
|
||||
|
||||
|
||||
//Zoom action
|
||||
ShortcutManager::instance().registerAction(ui->m_zoom_in_action, "elementeditor.zoom_in", tr("Éditeur d'élément"), QKeySequence::ZoomIn);
|
||||
@@ -1247,7 +1254,8 @@ void QETElementEditor::updateAction()
|
||||
//Action disabled if read only
|
||||
auto ro_list = m_add_part_action_grp->actions();
|
||||
ro_list << ui->m_paste_from_file_action
|
||||
<< ui->m_paste_from_element_action;
|
||||
<< ui->m_paste_from_element_action
|
||||
<< m_scale_element_action;
|
||||
for (auto action : std::as_const(ro_list)) {
|
||||
action->setDisabled(m_read_only);
|
||||
}
|
||||
@@ -1803,6 +1811,28 @@ void QETElementEditor::on_m_import_dxf_triggered()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETElementEditor::scaleElement
|
||||
Ask for a factor that keeps the terminals on the grid,
|
||||
then scale the whole element by it.
|
||||
*/
|
||||
void QETElementEditor::scaleElement()
|
||||
{
|
||||
QList<QPointF> terminals;
|
||||
for (CustomElementPart *part : m_elmt_scene->primitives()) {
|
||||
if (auto terminal = qgraphicsitem_cast<PartTerminal *>(part->toItem())) {
|
||||
terminals << terminal->scenePos();
|
||||
}
|
||||
}
|
||||
|
||||
ScaleElementDialog dialog(terminals, this);
|
||||
if (dialog.exec() != QDialog::Accepted || dialog.factor() == 1.0) {
|
||||
return;
|
||||
}
|
||||
m_elmt_scene->undoStack().push(
|
||||
new ScaleElementCommand(m_elmt_scene, dialog.factor(), dialog.scaleText()));
|
||||
}
|
||||
|
||||
void QETElementEditor::on_m_import_scaled_element_triggered()
|
||||
{
|
||||
if (ElementScalerIsPresent(true, this))
|
||||
|
||||
@@ -112,6 +112,7 @@ class QETElementEditor : public QMainWindow
|
||||
void on_m_about_qt_action_triggered();
|
||||
void on_m_import_dxf_triggered();
|
||||
void on_m_import_scaled_element_triggered();
|
||||
void scaleElement();
|
||||
|
||||
private:
|
||||
bool canClose();
|
||||
@@ -142,6 +143,7 @@ class QETElementEditor : public QMainWindow
|
||||
QList<QAction *> m_context_menu_action_list;
|
||||
|
||||
QAction
|
||||
*m_scale_element_action = nullptr,
|
||||
*m_undo_action = nullptr,
|
||||
*m_redo_action = nullptr;
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
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 "scaleelementdialog.h"
|
||||
|
||||
#include "../symbolscale.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFormLayout>
|
||||
#include <QLabel>
|
||||
#include <QLocale>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
/**
|
||||
@brief ScaleElementDialog::ScaleElementDialog
|
||||
@param terminals : positions of the element's terminals, in scene
|
||||
coordinates (relative to the hotspot)
|
||||
@param parent
|
||||
*/
|
||||
ScaleElementDialog::ScaleElementDialog(const QList<QPointF> &terminals, QWidget *parent) :
|
||||
QDialog(parent)
|
||||
{
|
||||
setWindowTitle(tr("Mettre l'élément à l'échelle"));
|
||||
|
||||
auto layout = new QVBoxLayout(this);
|
||||
auto form = new QFormLayout();
|
||||
layout->addLayout(form);
|
||||
|
||||
m_factor = new QComboBox(this);
|
||||
const auto factors = SymbolScale::safeFactors(terminals);
|
||||
for (const qreal f : factors) {
|
||||
m_factor->addItem(QStringLiteral("× %1").arg(QLocale().toString(f)), f);
|
||||
}
|
||||
const int two = m_factor->findData(2.0);
|
||||
if (two >= 0) {
|
||||
m_factor->setCurrentIndex(two);
|
||||
}
|
||||
form->addRow(tr("Facteur :"), m_factor);
|
||||
|
||||
m_scale_text = new QCheckBox(tr("Mettre aussi les textes à l'échelle"), this);
|
||||
m_scale_text->setChecked(true);
|
||||
form->addRow(m_scale_text);
|
||||
|
||||
QString explanation;
|
||||
const int off_grid = SymbolScale::offGridCount(terminals);
|
||||
if (off_grid && factors.isEmpty()) {
|
||||
explanation = tr("%n borne(s) de cet élément ne sont pas sur la grille, "
|
||||
"et aucun facteur ne les y amène.", "", off_grid);
|
||||
} else if (off_grid) {
|
||||
explanation = tr("%n borne(s) de cet élément ne sont pas sur la grille. "
|
||||
"Seuls les facteurs qui les y amènent sont proposés.", "", off_grid);
|
||||
} else {
|
||||
explanation = tr("Seuls les facteurs qui gardent les bornes sur la grille "
|
||||
"sont proposés. L'élément est mis à l'échelle autour de son point de saisie.");
|
||||
}
|
||||
auto label = new QLabel(explanation, this);
|
||||
label->setWordWrap(true);
|
||||
layout->addWidget(label);
|
||||
|
||||
auto buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
||||
buttons->button(QDialogButtonBox::Ok)->setEnabled(!factors.isEmpty());
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
layout->addWidget(buttons);
|
||||
|
||||
m_factor->setEnabled(!factors.isEmpty());
|
||||
m_scale_text->setEnabled(!factors.isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
@return the chosen factor, or 1 if none could be offered
|
||||
*/
|
||||
qreal ScaleElementDialog::factor() const
|
||||
{
|
||||
return m_factor->count() ? m_factor->currentData().toReal() : 1.0;
|
||||
}
|
||||
|
||||
bool ScaleElementDialog::scaleText() const
|
||||
{
|
||||
return m_scale_text->isChecked();
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
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 SCALEELEMENTDIALOG_H
|
||||
#define SCALEELEMENTDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
|
||||
/**
|
||||
@brief The ScaleElementDialog class
|
||||
Asks for the factor to scale the whole element by. Only the factors
|
||||
that leave every terminal on the folio grid are offered
|
||||
(see SymbolScale::safeFactors()).
|
||||
*/
|
||||
class ScaleElementDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ScaleElementDialog(const QList<QPointF> &terminals, QWidget *parent = nullptr);
|
||||
|
||||
qreal factor() const;
|
||||
bool scaleText() const;
|
||||
|
||||
private:
|
||||
QComboBox *m_factor = nullptr;
|
||||
QCheckBox *m_scale_text = nullptr;
|
||||
};
|
||||
|
||||
#endif // SCALEELEMENTDIALOG_H
|
||||
@@ -149,6 +149,13 @@ add_test(NAME tst_terminalnamecheck COMMAND tst_terminalnamecheck)
|
||||
target_include_directories(tst_terminalnamecheck PRIVATE ${QET_DIR}/sources)
|
||||
target_link_libraries(tst_terminalnamecheck PRIVATE Qt::Test)
|
||||
|
||||
# symbolscale.h is header-only: which factors the element editor offers
|
||||
# for scaling an element without taking its terminals off the grid.
|
||||
add_executable(tst_symbolscale tst_symbolscale.cpp)
|
||||
add_test(NAME tst_symbolscale COMMAND tst_symbolscale)
|
||||
target_include_directories(tst_symbolscale PRIVATE ${QET_DIR}/sources)
|
||||
target_link_libraries(tst_symbolscale PRIVATE Qt::Test)
|
||||
|
||||
# configprofile.h is header-only: which settings a saved configuration
|
||||
# profile carries, and how loading one replaces the live settings.
|
||||
add_executable(tst_configprofile tst_configprofile.cpp)
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
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 <QtTest>
|
||||
|
||||
#include "editor/symbolscale.h"
|
||||
|
||||
class tst_symbolscale : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
// Terminals 10 px apart: whole factors are safe, halving is not.
|
||||
void tenPitchTakesWholeFactors()
|
||||
{
|
||||
const QList<QPointF> terminals{{0, -20}, {0, 20}, {10, 0}};
|
||||
QCOMPARE(SymbolScale::safeFactors(terminals),
|
||||
(QList<qreal>{2.0, 3.0, 4.0}));
|
||||
}
|
||||
|
||||
// Terminals 20 px apart: every candidate is safe.
|
||||
void twentyPitchTakesEverything()
|
||||
{
|
||||
const QList<QPointF> terminals{{-20, 0}, {20, 40}};
|
||||
QCOMPARE(SymbolScale::safeFactors(terminals), SymbolScale::candidates());
|
||||
}
|
||||
|
||||
// Off the grid by 5 px today: only even factors bring it on.
|
||||
void fivePxOffIsRescuedByEvenFactors()
|
||||
{
|
||||
const QList<QPointF> terminals{{-5, 0}, {5, 30}};
|
||||
QVERIFY(!SymbolScale::allOnGrid(terminals));
|
||||
QCOMPARE(SymbolScale::offGridCount(terminals), 2);
|
||||
QCOMPARE(SymbolScale::safeFactors(terminals),
|
||||
(QList<qreal>{2.0, 4.0}));
|
||||
}
|
||||
|
||||
// Off by an odd amount: nothing helps.
|
||||
void oddOffsetHasNoSafeFactor()
|
||||
{
|
||||
QVERIFY(SymbolScale::safeFactors({{-7, 0}, {0, 20}}).isEmpty());
|
||||
}
|
||||
|
||||
void noTerminalTakesEverything()
|
||||
{
|
||||
QCOMPARE(SymbolScale::safeFactors({}), SymbolScale::candidates());
|
||||
}
|
||||
|
||||
// Saved with two decimals: 19.999 still counts as 20.
|
||||
void savedRoundingIsTolerated()
|
||||
{
|
||||
QVERIFY(SymbolScale::onGrid(19.999));
|
||||
QVERIFY(SymbolScale::onGrid(-30.001));
|
||||
QVERIFY(!SymbolScale::onGrid(19.9));
|
||||
}
|
||||
|
||||
void fontSizeIsWholeAndReadable()
|
||||
{
|
||||
QCOMPARE(SymbolScale::scaledFontSize(9, 2.0), 18);
|
||||
QCOMPARE(SymbolScale::scaledFontSize(9, 1.5), 14);
|
||||
QCOMPARE(SymbolScale::scaledFontSize(6, 0.5), 4);
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_symbolscale)
|
||||
#include "tst_symbolscale.moc"
|
||||
Reference in New Issue
Block a user