mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-15 01:54:14 +02:00
Merge pull request #1355 from ispyisail/feat/upright-symbol-texts
Linux build and tests / Build and test (Qt 6, Debug) (push) Failing after 1m54s
Linux build and tests / Build and test (Qt 6, Debug) (push) Failing after 1m54s
Add an option to keep texts of turned symbols horizontal
This commit is contained in:
+27
-18
@@ -50,19 +50,26 @@ namespace {
|
||||
rectangles, circles, polygons and arcs, and its terminals when
|
||||
@a draw_terminals, as if it were placed at @a elem_pos_x,
|
||||
@a elem_pos_y and turned @a rotation_angle degrees, with @a elmt's
|
||||
mirrors when @a mirrored. Used for every symbol drawn in full, and
|
||||
once per block for a block's content.
|
||||
mirrors and its texts kept readable (Element::symbolTextsTransform())
|
||||
when @a as_placed. Used for every symbol drawn in full, and once per
|
||||
block for a block's content.
|
||||
*/
|
||||
void drawSymbol(const QString &file_path, Element *elmt,
|
||||
qreal elem_pos_x, qreal elem_pos_y,
|
||||
double rotation_angle, bool draw_terminals,
|
||||
bool mirrored = false)
|
||||
bool as_placed = false)
|
||||
{
|
||||
using namespace DxfExport;
|
||||
//The mirrors of an element are about its own axes, before it is
|
||||
//rotated, see Element::setMirror()
|
||||
const bool mirror_h = mirrored && elmt -> hasHorizontalMirror();
|
||||
const bool mirror_v = mirrored && elmt -> hasVerticalMirror();
|
||||
const bool mirror_h = as_placed && elmt -> hasHorizontalMirror();
|
||||
const bool mirror_v = as_placed && elmt -> hasVerticalMirror();
|
||||
const QTransform texts_transform = as_placed
|
||||
? elmt -> symbolTextsTransform()
|
||||
: QTransform();
|
||||
const qreal text_turn = as_placed && elmt -> hasUprightSymbolTexts()
|
||||
? 0
|
||||
: rotation_angle;
|
||||
const qreal mirror_x = mirror_h ? -1 : 1;
|
||||
const qreal mirror_y = mirror_v ? -1 : 1;
|
||||
ElementPictureFactory::primitives primitives = ElementPictureFactory::instance()->getPrimitives(elmt->location());
|
||||
@@ -75,11 +82,13 @@ namespace {
|
||||
fontSize = text->font().pixelSize();
|
||||
|
||||
QPointF text_pos = text->pos();
|
||||
if (mirror_h || mirror_v)
|
||||
//A text the element mirrors, or turns in a project that keeps
|
||||
//symbol texts horizontal, keeps reading as in the symbol:
|
||||
//only its box moves, as ElementPictureFactory draws it on the
|
||||
//folio. It is then drawn as in a symbol neither mirrored nor
|
||||
//turned, moved to where the element puts the box's centre.
|
||||
if (!texts_transform.isIdentity())
|
||||
{
|
||||
//The text keeps reading normally: only its box is
|
||||
//mirrored, about its own centre, as ElementPictureFactory
|
||||
//draws it on the folio
|
||||
QTransform box_transform;
|
||||
box_transform.translate(text->pos().x(), text->pos().y());
|
||||
box_transform.rotate(text->rotation());
|
||||
@@ -88,19 +97,18 @@ namespace {
|
||||
text->boundingRect().width(),
|
||||
text->boundingRect().height());
|
||||
const QPointF centre = box_transform.mapRect(box).center();
|
||||
text_pos += QPointF(centre.x() * (mirror_x - 1),
|
||||
centre.y() * (mirror_y - 1));
|
||||
text_pos += texts_transform.map(centre) - centre;
|
||||
}
|
||||
|
||||
qreal x = elem_pos_x + text_pos.x();
|
||||
qreal y = elem_pos_y + text_pos.y();
|
||||
|
||||
qreal angle = text -> rotation() + rotation_angle;
|
||||
qreal angle = text -> rotation() + text_turn;
|
||||
qreal angler = angle * M_PI/180;
|
||||
int xdir = -sin(angler);
|
||||
int ydir = -cos(angler);
|
||||
|
||||
QPointF transformed_point = DxfExport::rotation_transformed(x, y, elem_pos_x, elem_pos_y, -rotation_angle);
|
||||
QPointF transformed_point = DxfExport::rotation_transformed(x, y, elem_pos_x, elem_pos_y, -text_turn);
|
||||
x = transformed_point.x() - ydir * fontSize * 0.5;
|
||||
y = transformed_point.y() - xdir * fontSize * 0.5;
|
||||
QStringList lines = text->text().split('\n');
|
||||
@@ -384,7 +392,8 @@ void DxfExport::write(Diagram *diagram, int width, int height,
|
||||
QSet<QString> used;
|
||||
for (Element *elmt : std::as_const(list_elements)) {
|
||||
const QString key = elmt -> location().toString();
|
||||
if (elmt -> isMirrored() || block_names.contains(key)
|
||||
if (!elmt -> symbolTextsTransform().isIdentity()
|
||||
|| block_names.contains(key)
|
||||
|| drawsNothing(elmt, properties.draw_terminals))
|
||||
continue;
|
||||
QString file_name = elmt -> location().fileName();
|
||||
@@ -402,11 +411,11 @@ void DxfExport::write(Diagram *diagram, int width, int height,
|
||||
block_models << elmt;
|
||||
}
|
||||
}
|
||||
//A mirrored symbol is drawn in full: an INSERT with a negative
|
||||
//scale would mirror its texts too, which QElectroTech keeps
|
||||
//readable
|
||||
//A mirrored symbol, or a turned one whose texts stay horizontal,
|
||||
//is drawn in full: an INSERT would mirror or turn its texts too,
|
||||
//which QElectroTech keeps readable
|
||||
const auto blockOf = [&block_names](Element *elmt) {
|
||||
return elmt -> isMirrored()
|
||||
return !elmt -> symbolTextsTransform().isIdentity()
|
||||
? QString()
|
||||
: block_names.value(elmt -> location().toString());
|
||||
};
|
||||
|
||||
@@ -95,37 +95,46 @@ void ElementPictureFactory::getPictures(const ElementsLocation &location, QPictu
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementPictureFactory::getMirroredPictures
|
||||
Same as getPictures(), for an element mirrored on its folio
|
||||
(Element::setMirror()). The drawing is the same; only the texts differ:
|
||||
each one is drawn so that, once the element's mirror is applied, its box
|
||||
lands mirrored but its letters still read normally.
|
||||
@brief ElementPictureFactory::getReadablePictures
|
||||
Same as getPictures(), for an element that mirrors or turns its symbol
|
||||
on a folio (Element::symbolTextsTransform()). The drawing is the same;
|
||||
only the texts differ: each one is drawn so that, once the element has
|
||||
applied @p texts_transform, its box lands where the element puts it but
|
||||
its letters read as they do in the symbol itself.
|
||||
@param location
|
||||
@param horizontal : the element's left and right swap
|
||||
@param vertical : the element's top and bottom swap
|
||||
@param texts_transform : the mirrors, then the turn, of the element
|
||||
@param picture
|
||||
@param low_picture
|
||||
*/
|
||||
void ElementPictureFactory::getMirroredPictures(const ElementsLocation &location,
|
||||
bool horizontal,
|
||||
bool vertical,
|
||||
void ElementPictureFactory::getReadablePictures(const ElementsLocation &location,
|
||||
const QTransform &texts_transform,
|
||||
QPicture &picture,
|
||||
QPicture &low_picture)
|
||||
{
|
||||
if(!location.exist() || !(horizontal || vertical)) {
|
||||
if(!location.exist() || texts_transform.isIdentity()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QPair<QUuid, int> key(cacheKey(location),
|
||||
(horizontal ? 1 : 0) | (vertical ? 2 : 0));
|
||||
const QPair<QUuid, int> key(cacheKey(location), readableKey(texts_transform));
|
||||
|
||||
if(!m_mirrored_pictures_H.contains(key)
|
||||
&& !build(location, nullptr, nullptr,
|
||||
QTransform::fromScale(horizontal ? -1 : 1, vertical ? -1 : 1))) {
|
||||
if(!m_readable_pictures_H.contains(key)
|
||||
&& !build(location, nullptr, nullptr, texts_transform)) {
|
||||
return;
|
||||
}
|
||||
picture = m_mirrored_pictures_H.value(key);
|
||||
low_picture = m_mirrored_low_pictures_H.value(key);
|
||||
picture = m_readable_pictures_H.value(key);
|
||||
low_picture = m_readable_low_pictures_H.value(key);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementPictureFactory::readableKey
|
||||
@param texts_transform : mirrors and quarter turns only
|
||||
@return a number for @p texts_transform, the same for the same one
|
||||
*/
|
||||
int ElementPictureFactory::readableKey(const QTransform &texts_transform)
|
||||
{
|
||||
auto digit = [](qreal value) {return qRound(value) + 1;}; // -1, 0 or 1
|
||||
return ((digit(texts_transform.m11()) * 3 + digit(texts_transform.m12())) * 3
|
||||
+ digit(texts_transform.m21())) * 3 + digit(texts_transform.m22());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,9 +156,12 @@ void ElementPictureFactory::dropCache(const ElementsLocation &location)
|
||||
const QUuid uuid = cacheKey(location);
|
||||
m_pictures_H.remove(uuid);
|
||||
m_low_pictures_H.remove(uuid);
|
||||
for (int mirror = 1 ; mirror <= 3 ; ++mirror) {
|
||||
m_mirrored_pictures_H.remove(qMakePair(uuid, mirror));
|
||||
m_mirrored_low_pictures_H.remove(qMakePair(uuid, mirror));
|
||||
const auto keys = m_readable_pictures_H.keys();
|
||||
for (const auto &key : keys) {
|
||||
if (key.first == uuid) {
|
||||
m_readable_pictures_H.remove(key);
|
||||
m_readable_low_pictures_H.remove(key);
|
||||
}
|
||||
}
|
||||
m_pixmap_H.remove(uuid);
|
||||
//The text items belong to the cache; nothing else holds them.
|
||||
@@ -255,16 +267,16 @@ ElementPictureFactory::~ElementPictureFactory()
|
||||
this function draw on it and don't store it.
|
||||
if null, this function create a QPicture for normal and low zoom,
|
||||
draw on it and store it in m_pictures_H and m_low_pictures_H
|
||||
(m_mirrored_pictures_H and m_mirrored_low_pictures_H if @p mirror
|
||||
is not the identity)
|
||||
@param mirror : the mirror of an element to draw the drawing for, see
|
||||
getMirroredPictures()
|
||||
(m_readable_pictures_H and m_readable_low_pictures_H if
|
||||
@p texts_transform is not the identity)
|
||||
@param texts_transform : what an element does to the texts of its
|
||||
symbol, which the drawing undoes, see getReadablePictures()
|
||||
@return
|
||||
*/
|
||||
bool ElementPictureFactory::build(const ElementsLocation &location,
|
||||
QPicture *picture,
|
||||
QPicture *low_picture,
|
||||
const QTransform &mirror)
|
||||
const QTransform &texts_transform)
|
||||
{
|
||||
QDomElement dom = location.xml();
|
||||
|
||||
@@ -324,7 +336,7 @@ bool ElementPictureFactory::build(const ElementsLocation &location,
|
||||
tmp.setCosmetic(true);
|
||||
low_painter.setPen(tmp);
|
||||
|
||||
m_build_mirror = mirror;
|
||||
m_build_texts_undo = texts_transform.inverted();
|
||||
|
||||
//scroll of the Children of the Definition: Parts of the Drawing
|
||||
// Extract PLC master data for rendering plc_table parts
|
||||
@@ -378,21 +390,20 @@ bool ElementPictureFactory::build(const ElementsLocation &location,
|
||||
//End of the drawing
|
||||
painter.end();
|
||||
low_painter.end();
|
||||
m_build_mirror = QTransform();
|
||||
m_build_texts_undo = QTransform();
|
||||
qDeleteAll(low_primitives.m_texts);
|
||||
|
||||
const auto uuid_ = cacheKey(location);
|
||||
if (!mirror.isIdentity()) {
|
||||
//The primitives are those of the drawing without mirror,
|
||||
//already kept by the build of that one
|
||||
if (!texts_transform.isIdentity()) {
|
||||
//The primitives are those of the plain drawing, already kept
|
||||
//by the build of that one
|
||||
qDeleteAll(primitives_.m_texts);
|
||||
const QPair<QUuid, int> key(uuid_, (mirror.m11() < 0 ? 1 : 0)
|
||||
| (mirror.m22() < 0 ? 2 : 0));
|
||||
const QPair<QUuid, int> key(uuid_, readableKey(texts_transform));
|
||||
if (!picture) {
|
||||
m_mirrored_pictures_H.insert(key, pic);
|
||||
m_readable_pictures_H.insert(key, pic);
|
||||
}
|
||||
if (!low_picture) {
|
||||
m_mirrored_low_pictures_H.insert(key, low_pic);
|
||||
m_readable_low_pictures_H.insert(key, low_pic);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -714,17 +725,16 @@ void ElementPictureFactory::parseText(const QDomElement &dom, QPainter &painter,
|
||||
text_transform.rotate(dom.attribute("rotation", "0").toDouble());
|
||||
text_transform.translate(qpainter_offset.x(), qpainter_offset.y());
|
||||
|
||||
if (!m_build_mirror.isIdentity())
|
||||
if (!m_build_texts_undo.isIdentity())
|
||||
{
|
||||
//The element is mirrored about its own axes when it is drawn.
|
||||
//Mirror the text the same way first, about the centre of its
|
||||
//box: the two mirrors cancel on the letters, which read
|
||||
//normally, and the box still ends up where the element's
|
||||
//mirror puts it.
|
||||
//The element mirrors or turns its symbol when it is drawn.
|
||||
//Undo that on the text first, about the centre of its box: the
|
||||
//letters read as in the symbol itself, and the box still ends
|
||||
//up where the element puts it.
|
||||
const QRectF box(QPointF(0, 0), text_document.size());
|
||||
const QPointF centre = text_transform.mapRect(box).center();
|
||||
painter.setTransform(QTransform::fromTranslate(-centre.x(), -centre.y())
|
||||
* m_build_mirror
|
||||
* m_build_texts_undo
|
||||
* QTransform::fromTranslate(centre.x(), centre.y()));
|
||||
}
|
||||
painter.setTransform(text_transform, true);
|
||||
|
||||
@@ -85,7 +85,7 @@ class ElementPictureFactory
|
||||
}
|
||||
|
||||
void getPictures(const ElementsLocation &location, QPicture &picture, QPicture &low_picture);
|
||||
void getMirroredPictures(const ElementsLocation &location, bool horizontal, bool vertical,
|
||||
void getReadablePictures(const ElementsLocation &location, const QTransform &texts_transform,
|
||||
QPicture &picture, QPicture &low_picture);
|
||||
QPixmap pixmap(const ElementsLocation &location);
|
||||
ElementPictureFactory::primitives getPrimitives(const ElementsLocation &location);
|
||||
@@ -98,8 +98,9 @@ class ElementPictureFactory
|
||||
~ElementPictureFactory();
|
||||
|
||||
static QUuid cacheKey(const ElementsLocation &location);
|
||||
static int readableKey(const QTransform &texts_transform);
|
||||
bool build(const ElementsLocation &location, QPicture *picture=nullptr, QPicture *low_picture=nullptr,
|
||||
const QTransform &mirror=QTransform());
|
||||
const QTransform &texts_transform=QTransform());
|
||||
void parseElement(const QDomElement &dom, QPainter &painter, primitives &prim) const;
|
||||
void parseLine (const QDomElement &dom, QPainter &painter, primitives &prim) const;
|
||||
void parseRect (const QDomElement &dom, QPainter &painter, primitives &prim) const;
|
||||
@@ -113,12 +114,13 @@ class ElementPictureFactory
|
||||
|
||||
QHash<QUuid, QPicture> m_pictures_H;
|
||||
QHash<QUuid, QPicture> m_low_pictures_H;
|
||||
/// Drawings for mirrored elements, by element and mirror
|
||||
/// (horizontal, vertical, both), see getMirroredPictures()
|
||||
QHash<QPair<QUuid, int>, QPicture> m_mirrored_pictures_H;
|
||||
QHash<QPair<QUuid, int>, QPicture> m_mirrored_low_pictures_H;
|
||||
/// The mirror build() draws for, read by parseText()
|
||||
QTransform m_build_mirror;
|
||||
/// Drawings whose texts read normally once an element has
|
||||
/// mirrored or turned them, by element and readableKey(), see
|
||||
/// getReadablePictures()
|
||||
QHash<QPair<QUuid, int>, QPicture> m_readable_pictures_H;
|
||||
QHash<QPair<QUuid, int>, QPicture> m_readable_low_pictures_H;
|
||||
/// What build() undoes on each text, read by parseText()
|
||||
QTransform m_build_texts_undo;
|
||||
QHash<QUuid, QPixmap> m_pixmap_H;
|
||||
QHash<QUuid, primitives> m_primitives_H;
|
||||
static ElementPictureFactory* m_factory;
|
||||
|
||||
@@ -167,6 +167,8 @@ Element::Element(
|
||||
//The mirror is about the element's own axis, so it follows the
|
||||
//rotation, see applyMirrorTransform()
|
||||
connect(this, &Element::rotationChanged, this, &Element::applyMirrorTransform);
|
||||
//Texts kept horizontal in a turned symbol depend on the turn
|
||||
connect(this, &Element::rotationChanged, this, [this]() {updateSymbolPictures();});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -299,16 +301,7 @@ void Element::setMirror(bool horizontal, bool vertical)
|
||||
m_horizontal_mirror = horizontal;
|
||||
m_vertical_mirror = vertical;
|
||||
|
||||
m_mirrored_picture = QPicture();
|
||||
m_mirrored_low_zoom_picture = QPicture();
|
||||
if (isMirrored())
|
||||
ElementPictureFactory::instance()->getMirroredPictures(
|
||||
m_location,
|
||||
horizontal,
|
||||
vertical,
|
||||
m_mirrored_picture,
|
||||
m_mirrored_low_zoom_picture);
|
||||
|
||||
updateSymbolPictures();
|
||||
applyMirrorTransform();
|
||||
keepChildrenReadable();
|
||||
update();
|
||||
@@ -325,6 +318,69 @@ QTransform Element::mirrorTransform() const
|
||||
m_vertical_mirror ? -1 : 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Element::hasUprightSymbolTexts
|
||||
@return true if the project of this element keeps the texts of its
|
||||
turned symbols horizontal (QETProject::uprightSymbolTexts())
|
||||
*/
|
||||
bool Element::hasUprightSymbolTexts() const
|
||||
{
|
||||
const Diagram *d = diagram();
|
||||
return d && d->project() && d->project()->uprightSymbolTexts();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Element::symbolTextsTransform
|
||||
@return what this element does to the texts drawn in its symbol, which
|
||||
the drawing undoes to keep them readable (updateSymbolPictures()):
|
||||
its mirrors, and its turn when the project keeps them horizontal.
|
||||
The identity when the symbol is drawn as it is.
|
||||
*/
|
||||
QTransform Element::symbolTextsTransform() const
|
||||
{
|
||||
//QTransform's product applies its left operand first
|
||||
QTransform transform = mirrorTransform();
|
||||
if (hasUprightSymbolTexts())
|
||||
transform *= QTransform().rotate(orientation() * 90);
|
||||
return transform;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Element::updateSymbolPictures
|
||||
Take the drawing of the symbol whose texts read normally once this
|
||||
element has mirrored and turned it (symbolTextsTransform()), or drop it
|
||||
when the plain drawing does.
|
||||
@param force : take it again even if the transform did not change, as
|
||||
when the symbol's definition was reloaded
|
||||
*/
|
||||
void Element::updateSymbolPictures(bool force)
|
||||
{
|
||||
const QTransform transform = symbolTextsTransform();
|
||||
if (transform.isIdentity())
|
||||
{
|
||||
if (!m_readable_transform.isIdentity())
|
||||
{
|
||||
m_readable_transform = QTransform();
|
||||
m_readable_picture = QPicture();
|
||||
m_readable_low_zoom_picture = QPicture();
|
||||
update();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (transform == m_readable_transform && !force)
|
||||
return;
|
||||
|
||||
m_readable_transform = transform;
|
||||
m_readable_picture = QPicture();
|
||||
m_readable_low_zoom_picture = QPicture();
|
||||
ElementPictureFactory::instance()->getReadablePictures(
|
||||
m_location,
|
||||
transform,
|
||||
m_readable_picture,
|
||||
m_readable_low_zoom_picture);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Element::applyMirrorTransform
|
||||
QGraphicsItem applies transform() after the rotation, so the mirrors of
|
||||
@@ -427,9 +483,10 @@ void Element::paint(
|
||||
QBrush brush;
|
||||
painter->setPen(pen);
|
||||
painter->setBrush(brush);
|
||||
const QPicture &picture = isMirrored() ? m_mirrored_picture : m_picture;
|
||||
const QPicture &low_zoom_picture = isMirrored() ? m_mirrored_low_zoom_picture
|
||||
: m_low_zoom_picture;
|
||||
const bool readable = !m_readable_transform.isIdentity();
|
||||
const QPicture &picture = readable ? m_readable_picture : m_picture;
|
||||
const QPicture &low_zoom_picture = readable ? m_readable_low_zoom_picture
|
||||
: m_low_zoom_picture;
|
||||
if (options && options->levelOfDetailFromTransform(painter->worldTransform()) < 0.5)
|
||||
{
|
||||
if (!low_zoom_picture.isNull())
|
||||
@@ -1965,6 +2022,10 @@ QVariant Element::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||
deti->refreshResizeHandlesVisibility();
|
||||
}
|
||||
}
|
||||
//Whether the texts of a turned symbol stay horizontal is the
|
||||
//project's setting, known once the element is on one of its folios
|
||||
else if (change == QGraphicsItem::ItemSceneHasChanged)
|
||||
updateSymbolPictures();
|
||||
return QetGraphicsItem::itemChange(change, value);
|
||||
}
|
||||
|
||||
@@ -2186,13 +2247,7 @@ Element::ReloadPictureResult Element::reloadPicture()
|
||||
|
||||
m_picture = picture;
|
||||
m_low_zoom_picture = low_zoom_picture;
|
||||
if (isMirrored())
|
||||
ElementPictureFactory::instance()->getMirroredPictures(
|
||||
m_location,
|
||||
m_horizontal_mirror,
|
||||
m_vertical_mirror,
|
||||
m_mirrored_picture,
|
||||
m_mirrored_low_zoom_picture);
|
||||
updateSymbolPictures(true);
|
||||
update();
|
||||
return ReloadPictureResult::Reloaded;
|
||||
}
|
||||
|
||||
@@ -195,6 +195,9 @@ class Element : public QetGraphicsItem
|
||||
void setHorizontalMirror(bool mirror);
|
||||
void setVerticalMirror(bool mirror);
|
||||
QTransform mirrorTransform() const;
|
||||
bool hasUprightSymbolTexts() const;
|
||||
QTransform symbolTextsTransform() const;
|
||||
void updateSymbolPictures(bool force = false);
|
||||
void keepReadable(QGraphicsItem *child) const;
|
||||
|
||||
//METHODS related to texts
|
||||
@@ -307,8 +310,11 @@ class Element : public QetGraphicsItem
|
||||
QList <Terminal *> m_terminals;
|
||||
QPicture m_picture;
|
||||
QPicture m_low_zoom_picture;
|
||||
QPicture m_mirrored_picture;
|
||||
QPicture m_mirrored_low_zoom_picture;
|
||||
/// The drawing with its texts kept readable, when the symbol's
|
||||
/// mirror or turn would not leave them so (m_readable_transform)
|
||||
QPicture m_readable_picture;
|
||||
QPicture m_readable_low_zoom_picture;
|
||||
QTransform m_readable_transform;
|
||||
ElementData m_data;
|
||||
QList<QPointF> m_plc_table_positions; // Positions of plc_table parts in the element definition
|
||||
|
||||
|
||||
@@ -306,20 +306,22 @@ void Terminal::paint(
|
||||
QFontMetrics fm(d->m_label_font);
|
||||
QSizeF text_size = fm.size(Qt::TextSingleLine, display_name);
|
||||
|
||||
// On a mirrored element, mirror the name a second time about
|
||||
// the centre of its box, in the frame it is drawn in (turned
|
||||
// by label_rotation): its box stays where the element's mirror
|
||||
// puts it, but it reads normally (Element::keepReadable())
|
||||
const Element *mirrored = qgraphicsitem_cast<Element *>(parentItem());
|
||||
if (mirrored && !mirrored->isMirrored()) mirrored = nullptr;
|
||||
auto keep_readable = [painter, mirrored](const QRectF &rect, qreal label_rotation) {
|
||||
if (!mirrored) return;
|
||||
const QTransform mirror = QTransform().rotate(label_rotation)
|
||||
* mirrored->mirrorTransform()
|
||||
* QTransform().rotate(-label_rotation);
|
||||
// When the element mirrors its symbol, or turns it in a project
|
||||
// that keeps symbol texts horizontal, undo that on the name
|
||||
// about the centre of its box, in the frame it is drawn in
|
||||
// (turned by label_rotation): its box stays where the element
|
||||
// puts it, but it reads as in the symbol (Element::keepReadable())
|
||||
const Element *element = qgraphicsitem_cast<Element *>(parentItem());
|
||||
const QTransform texts_transform = element ? element->symbolTextsTransform()
|
||||
: QTransform();
|
||||
auto keep_readable = [painter, &texts_transform](const QRectF &rect, qreal label_rotation) {
|
||||
if (texts_transform.isIdentity()) return;
|
||||
const QTransform undo = QTransform().rotate(label_rotation)
|
||||
* texts_transform.inverted()
|
||||
* QTransform().rotate(-label_rotation);
|
||||
const QPointF c = rect.center();
|
||||
painter->setTransform(QTransform::fromTranslate(-c.x(), -c.y())
|
||||
* mirror
|
||||
* undo
|
||||
* QTransform::fromTranslate(c.x(), c.y()), true);
|
||||
};
|
||||
|
||||
|
||||
@@ -74,6 +74,11 @@ m_project_properties_handler{this}
|
||||
m_elements_collection = new XmlElementCollection(this);
|
||||
init();
|
||||
|
||||
//A new project keeps the texts of its turned symbols horizontal; a
|
||||
//project saved without the setting is read with it off, so it looks
|
||||
//as it always did (readSymbolTextsXml())
|
||||
m_upright_symbol_texts = true;
|
||||
|
||||
QSettings settings;
|
||||
|
||||
//Read auto break conductor default from global settings
|
||||
@@ -1380,6 +1385,37 @@ void QETProject::setWireHops(WireHops::Mode mode)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::uprightSymbolTexts
|
||||
@return true if the texts drawn in a symbol stay horizontal, and read
|
||||
normally, when the symbol is turned or mirrored on a folio, instead of
|
||||
turning with it. A mirrored symbol always keeps its texts readable.
|
||||
*/
|
||||
bool QETProject::uprightSymbolTexts() const {
|
||||
return m_upright_symbol_texts;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::setUprightSymbolTexts
|
||||
Set whether the texts drawn in a turned symbol stay horizontal, and
|
||||
redraw every symbol of the project.
|
||||
@param upright
|
||||
*/
|
||||
void QETProject::setUprightSymbolTexts(bool upright)
|
||||
{
|
||||
if (upright == m_upright_symbol_texts) {
|
||||
return;
|
||||
}
|
||||
m_upright_symbol_texts = upright;
|
||||
for (Diagram *diagram : diagrams()) {
|
||||
for (QGraphicsItem *item : diagram->items()) {
|
||||
if (Element *element = qgraphicsitem_cast<Element *>(item)) {
|
||||
element->updateSymbolPictures();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::wiringRules
|
||||
@return how many wires a terminal of this project may take
|
||||
@@ -1521,6 +1557,7 @@ QDomDocument QETProject::toXml()
|
||||
// local, non-transmitted usage tracking (time spent on this project)
|
||||
writeUsageXml(project_root);
|
||||
writeWireHopsXml(project_root);
|
||||
writeSymbolTextsXml(project_root);
|
||||
writeWiringRulesXml(project_root);
|
||||
|
||||
// Properties for news diagrams
|
||||
@@ -2032,6 +2069,7 @@ void QETProject::readProjectXml(QDomDocument &xml_project)
|
||||
//Load the local, non-transmitted usage tracking
|
||||
readUsageXml(xml_project);
|
||||
readWireHopsXml(xml_project);
|
||||
readSymbolTextsXml(xml_project);
|
||||
readWiringRulesXml(xml_project);
|
||||
|
||||
//Load the default properties for the new diagrams
|
||||
@@ -2229,6 +2267,21 @@ void QETProject::readWireHopsXml(QDomDocument &xml_project)
|
||||
: WireHops::fromString(crossings.attribute(QStringLiteral("hop")));
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::readSymbolTextsXml
|
||||
Read the <symbol_texts> element of the project, if any. A project
|
||||
without it was saved before the setting existed, or with it off, and
|
||||
keeps the texts of its turned symbols turned.
|
||||
@param xml_project : the xml description of the project
|
||||
*/
|
||||
void QETProject::readSymbolTextsXml(QDomDocument &xml_project)
|
||||
{
|
||||
const QDomElement texts = xml_project.documentElement()
|
||||
.firstChildElement(QStringLiteral("symbol_texts"));
|
||||
m_upright_symbol_texts = !texts.isNull()
|
||||
&& texts.attribute(QStringLiteral("upright")) == QLatin1String("true");
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::readWiringRulesXml
|
||||
Read the <wiring_rules> element of the project, if any.
|
||||
@@ -2420,6 +2473,23 @@ void QETProject::writeWireHopsXml(QDomElement &xml_element)
|
||||
xml_element.appendChild(crossings);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::writeSymbolTextsXml
|
||||
Export whether the texts of turned symbols stay horizontal, as a
|
||||
<symbol_texts> child of \a xml_element. Written only when on, so a
|
||||
project with it off saves exactly as before.
|
||||
*/
|
||||
void QETProject::writeSymbolTextsXml(QDomElement &xml_element)
|
||||
{
|
||||
if (!m_upright_symbol_texts) {
|
||||
return;
|
||||
}
|
||||
QDomElement texts = xml_element.ownerDocument()
|
||||
.createElement(QStringLiteral("symbol_texts"));
|
||||
texts.setAttribute(QStringLiteral("upright"), QStringLiteral("true"));
|
||||
xml_element.appendChild(texts);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::writeWiringRulesXml
|
||||
Export the project's wiring rules as a <wiring_rules> child of
|
||||
|
||||
@@ -229,6 +229,8 @@ class QETProject : public QObject
|
||||
void setAutoConductor (bool ac);
|
||||
WireHops::Mode wireHops() const;
|
||||
void setWireHops(WireHops::Mode mode);
|
||||
bool uprightSymbolTexts() const;
|
||||
void setUprightSymbolTexts(bool upright);
|
||||
WiringRules::Settings wiringRules() const;
|
||||
WiringRules::Settings projectWiringRules() const;
|
||||
void setWiringRules(const WiringRules::Settings &rules);
|
||||
@@ -329,12 +331,14 @@ class QETProject : public QObject
|
||||
void readTerminalStripXml(const QDomDocument &xml_project);
|
||||
void readUsageXml(QDomDocument &xml_project);
|
||||
void readWireHopsXml(QDomDocument &xml_project);
|
||||
void readSymbolTextsXml(QDomDocument &xml_project);
|
||||
void readWiringRulesXml(QDomDocument &xml_project);
|
||||
|
||||
void writeProjectPropertiesXml(QDomElement &);
|
||||
void writeDefaultPropertiesXml(QDomElement &);
|
||||
void writeUsageXml(QDomElement &);
|
||||
void writeWireHopsXml(QDomElement &);
|
||||
void writeSymbolTextsXml(QDomElement &);
|
||||
void writeWiringRulesXml(QDomElement &);
|
||||
void addDiagram(Diagram *diagram, int pos = -1);
|
||||
void detachDiagram(Diagram *diagram);
|
||||
@@ -400,6 +404,9 @@ class QETProject : public QObject
|
||||
void linkElementsToElementAutoNums();
|
||||
bool m_auto_conductor = true;
|
||||
WireHops::Mode m_wire_hops = WireHops::Mode::None;
|
||||
/// Texts drawn in a turned symbol stay horizontal (on for a new
|
||||
/// project, off for one saved without it), see uprightSymbolTexts()
|
||||
bool m_upright_symbol_texts = false;
|
||||
WiringRules::Settings m_wiring_rules;
|
||||
bool m_auto_break_conductor = false;
|
||||
XmlElementCollection *m_elements_collection = nullptr;
|
||||
|
||||
@@ -185,6 +185,11 @@ void ProjectMainConfigPage::applyProjectConf()
|
||||
modified_project = true;
|
||||
}
|
||||
|
||||
if (m_project -> uprightSymbolTexts() != upright_symbol_texts_cb_ -> isChecked()) {
|
||||
m_project -> setUprightSymbolTexts(upright_symbol_texts_cb_ -> isChecked());
|
||||
modified_project = true;
|
||||
}
|
||||
|
||||
//Following the application's rules stores nothing in the project
|
||||
WiringRules::Settings wiring_rules;
|
||||
if (!use_application_rules_cb_ -> isChecked()) {
|
||||
@@ -252,6 +257,14 @@ void ProjectMainConfigPage::initWidgets()
|
||||
"Seul le dessin change : aucun élément n'est ajouté et aucun conducteur n'est coupé.",
|
||||
"tooltip"));
|
||||
|
||||
//Texts of turned symbols kept horizontal
|
||||
upright_symbol_texts_cb_ = new QCheckBox(tr("Garder horizontaux les textes des symboles pivotés",
|
||||
"checkbox label"));
|
||||
upright_symbol_texts_cb_ -> setToolTip(tr("Les textes dessinés dans un symbole et les noms de ses bornes restent "
|
||||
"lisibles quand le symbole est pivoté : leur cadre tourne avec le symbole, "
|
||||
"pas le texte. Décochez pour qu'ils tournent avec le symbole, comme avant.",
|
||||
"tooltip"));
|
||||
|
||||
//How many wires a terminal may take (discussion #1158)
|
||||
wiring_rules_gb_ = new QGroupBox(tr("Conducteurs par borne", "group box title"));
|
||||
use_application_rules_cb_ = new QCheckBox(tr("Utiliser les réglages de l'application", "checkbox label"));
|
||||
@@ -318,6 +331,9 @@ void ProjectMainConfigPage::initLayout()
|
||||
main_layout0 -> addLayout(wire_hops_layout0);
|
||||
main_layout0 -> addSpacing(10);
|
||||
|
||||
main_layout0 -> addWidget(upright_symbol_texts_cb_);
|
||||
main_layout0 -> addSpacing(10);
|
||||
|
||||
QVBoxLayout *wiring_rules_layout = new QVBoxLayout(wiring_rules_gb_);
|
||||
wiring_rules_layout -> addWidget(use_application_rules_cb_);
|
||||
QHBoxLayout *max_wires_layout = new QHBoxLayout();
|
||||
@@ -351,6 +367,7 @@ void ProjectMainConfigPage::readValuesFromProject()
|
||||
|
||||
const int wire_hops_index = wire_hops_cb_ -> findData(WireHops::toString(m_project -> wireHops()));
|
||||
wire_hops_cb_ -> setCurrentIndex(qMax(0, wire_hops_index));
|
||||
upright_symbol_texts_cb_ -> setChecked(m_project -> uprightSymbolTexts());
|
||||
|
||||
//The rules that apply: the project's own or the application's
|
||||
const WiringRules::Settings wiring_rules = m_project -> wiringRules();
|
||||
@@ -406,6 +423,7 @@ void ProjectMainConfigPage::adjustReadOnly()
|
||||
usage_enabled_cb_ -> setDisabled(is_read_only);
|
||||
usage_reset_pb_ -> setDisabled(is_read_only);
|
||||
wire_hops_cb_ -> setDisabled(is_read_only);
|
||||
upright_symbol_texts_cb_ -> setDisabled(is_read_only);
|
||||
wiring_rules_gb_ -> setDisabled(is_read_only);
|
||||
}
|
||||
|
||||
|
||||
@@ -139,6 +139,7 @@ class ProjectMainConfigPage : public ProjectConfigPage {
|
||||
QPushButton *usage_reset_pb_;
|
||||
QLabel *wire_hops_label_;
|
||||
QComboBox *wire_hops_cb_;
|
||||
QCheckBox *upright_symbol_texts_cb_;
|
||||
QGroupBox *wiring_rules_gb_;
|
||||
QCheckBox *use_application_rules_cb_;
|
||||
QLabel *max_wires_label_;
|
||||
|
||||
Reference in New Issue
Block a user