Files
qelectrotech-source-mirror/sources/properties/xrefproperties.cpp
T
ispyisail b8eb5c90a1 Cross references at the folio bottom: stack only when texts overlap, add a checkbox (#1287 follow-up)
The stacking added in #1287 tested the crosses' bounding rects, so
crosses whose frames or empty margins touched were raised although no
text was hidden (the list display case found in review). The texts each
cross really draws are now recorded while its geometry is built, and a
cross is raised only when one of its texts would be drawn over a text of
another one.

A new "Empiler les références dont les textes se chevauchent" checkbox
in the cross reference properties, per type, turns the stacking off;
the crosses of that type are then only centred, as before #1287. It is
saved in the project (xref attribute "stackoverlapping") and in the
settings, and is on when absent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 17:24:11 +13:00

253 lines
8.6 KiB
C++

/*
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 "xrefproperties.h"
#include "../qetapp.h"
#include <QHash>
#include <QMetaEnum>
namespace {
/**
@brief xrefPosFromKey
@param key : stored name of the position, e.g. "AlignBottom"
@return the position, or Qt::AlignBottom if key is empty or not one of
the positions the cross-reference settings offer. Older versions saved
an empty "xrefpos", which drew the cross-reference over the label.
*/
Qt::AlignmentFlag xrefPosFromKey(const QString &key)
{
bool ok = false;
const int value = QMetaEnum::fromType<Qt::Alignment>()
.keyToValue(key.toStdString().data(), &ok);
if (!ok)
return Qt::AlignBottom;
switch (value) {
case Qt::AlignBottom:
case Qt::AlignTop:
case Qt::AlignLeft:
case Qt::AlignRight:
case Qt::AlignBaseline:
case Qt::AlignHCenter:
return Qt::AlignmentFlag(value);
default:
return Qt::AlignBottom;
}
}
}
/**
@brief XRefProperties::XRefProperties
Default Constructor
*/
XRefProperties::XRefProperties()
{
m_show_power_ctc = true;
m_show_terminal_name = true;
m_show_all_configured_slaves = false;
m_stack_overlapping = true;
m_display = Cross;
m_snap_to = Bottom;
m_prefix_keys << "power" << "delay" << "switch";
m_master_label = "%f-%l%c";
m_slave_label = "(%f-%l%c)";
m_offset = 0;
m_slave_offset = 0;
m_xref_pos = Qt::AlignBottom;
}
/**
@brief XRefProperties::toSettings
Save to settings
@param settings: QSettings to use
@param prefix: prefix before properties name
*/
void XRefProperties::toSettings(QSettings &settings,
const QString prefix) const
{
settings.setValue(prefix % "showpowerctc", m_show_power_ctc);
settings.setValue(prefix % "showterminalname", m_show_terminal_name);
settings.setValue(prefix % "showallconfiguredslaves", m_show_all_configured_slaves);
settings.setValue(prefix % "stackoverlapping", m_stack_overlapping);
QString display = m_display == Cross? "cross" : "contacts";
settings.setValue(prefix % "displayhas", display);
QString snap = m_snap_to == Bottom? "bottom" : "label";
settings.setValue(prefix % "snapto", snap);
int offset = m_offset;
settings.setValue(prefix % "offset", offset);
int slave_offset = m_slave_offset;
settings.setValue(prefix % "slave_offset", slave_offset);
QString master_label = m_master_label;
settings.setValue(prefix % "master_label", master_label);
QString slave_label = m_slave_label;
settings.setValue(prefix % "slave_label", slave_label);
QMetaEnum var = QMetaEnum::fromType<Qt::Alignment>();
settings.setValue(prefix % "xrefpos", var.valueToKey(m_xref_pos));
foreach (QString key, m_prefix.keys()) {
settings.setValue(prefix % key % "prefix", m_prefix.value(key));
}
}
/**
@brief XRefProperties::fromSettings
load from settings
@param settings: QSettings to use
@param prefix: prefix before properties name
*/
void XRefProperties::fromSettings(const QSettings &settings,
const QString prefix)
{
m_show_power_ctc = settings.value(prefix % "showpowerctc", true).toBool();
m_show_terminal_name = settings.value(prefix % "showterminalname", true).toBool();
m_show_all_configured_slaves = settings.value(prefix % "showallconfiguredslaves", false).toBool();
m_stack_overlapping = settings.value(prefix % "stackoverlapping", true).toBool();
QString display = settings.value(prefix % "displayhas", "cross").toString();
display == "cross"? m_display = Cross : m_display = Contacts;
QString snap = settings.value(prefix % "snapto", "label").toString();
snap == "bottom"? m_snap_to = Bottom : m_snap_to = Label;
m_offset = settings.value(prefix % "offset", "0").toInt();
m_slave_offset = settings.value(prefix % "slave_offset", "0").toInt();
m_master_label = settings.value(prefix % "master_label", "%f-%l%c").toString();
m_slave_label = settings.value(prefix % "slave_label", "(%f-%l%c)").toString();
m_xref_pos = xrefPosFromKey(settings.value(prefix % "xrefpos").toString());
for (QString key : m_prefix_keys) {
m_prefix.insert(key, settings.value(prefix + key % "prefix").toString());
}
}
/**
@brief XRefProperties::toXml
Save to xml
@param xml_document : QDomElement to use for saving
@return QDomElement
*/
QDomElement XRefProperties::toXml(QDomDocument &xml_document) const
{
QDomElement xml_element = xml_document.createElement("xref");
xml_element.setAttribute("type", m_key);
xml_element.setAttribute("showpowerctc", m_show_power_ctc? "true" : "false");
xml_element.setAttribute("showterminalname", m_show_terminal_name? "true" : "false");
xml_element.setAttribute("showallconfiguredslaves", m_show_all_configured_slaves? "true" : "false");
xml_element.setAttribute("stackoverlapping", m_stack_overlapping? "true" : "false");
QString display = m_display == Cross? "cross" : "contacts";
xml_element.setAttribute("displayhas", display);
QString snap = m_snap_to == Bottom? "bottom" : "label";
xml_element.setAttribute("snapto", snap);
QString xrefpos;
QMetaEnum var = QMetaEnum::fromType<Qt::Alignment>();
xml_element.setAttribute("xrefpos", var.valueToKey(m_xref_pos));
int offset = m_offset;
xml_element.setAttribute("offset", QString::number(offset));
xml_element.setAttribute("slave_offset", QString::number(m_slave_offset));
QString master_label = m_master_label;
xml_element.setAttribute("master_label", master_label);
QString slave_label = m_slave_label;
xml_element.setAttribute("slave_label", slave_label);
foreach (QString key, m_prefix.keys()) {
xml_element.setAttribute(key % "prefix", m_prefix.value(key));
}
return xml_element;
}
/**
@brief XRefProperties::fromXml
Load from xml
@param xml_element: QDomElement to use for load
*/
bool XRefProperties::fromXml(const QDomElement &xml_element) {
m_show_power_ctc = xml_element.attribute("showpowerctc") == "true";
m_show_terminal_name = xml_element.attribute("showterminalname", "true") == "true";
m_show_all_configured_slaves = xml_element.attribute("showallconfiguredslaves", "false") == "true";
m_stack_overlapping = xml_element.attribute("stackoverlapping", "true") == "true";
QString display = xml_element.attribute("displayhas", "cross");
display == "cross"? m_display = Cross : m_display = Contacts;
QString snap = xml_element.attribute("snapto", "label");
snap == "bottom"? m_snap_to = Bottom : m_snap_to = Label;
m_xref_pos = xrefPosFromKey(xml_element.attribute("xrefpos"));
m_offset = xml_element.attribute("offset", "0").toInt();
m_slave_offset = xml_element.attribute("slave_offset", "0").toInt();
m_master_label = xml_element.attribute("master_label", "%f-%l%c");
m_slave_label = xml_element.attribute("slave_label","(%f-%l%c)");
foreach (QString key, m_prefix_keys) {
m_prefix.insert(key, xml_element.attribute(key % "prefix"));
}
return true;
}
/**
@brief XRefProperties::defaultProperties
@return the default properties stored in the setting file
For the xref, there are 2 properties.
For coil, stored with the string "coil" in the returned QHash.
For protection, stored with the string "protection" in the returned QHash.
*/
QHash<QString, XRefProperties> XRefProperties::defaultProperties()
{
QHash <QString, XRefProperties> hash;
QStringList keys;
keys << "coil" << "protection" << "commutator" << "plc";
QSettings settings;
foreach (QString key, keys)
{
XRefProperties properties;
QString str("diagrameditor/defaultxref");
properties.fromSettings(settings, str += key);
hash.insert(key, properties);
}
return hash;
}
bool XRefProperties::operator ==(const XRefProperties &xrp) const{
return (m_show_power_ctc == xrp.m_show_power_ctc
&& m_show_terminal_name == xrp.m_show_terminal_name
&& m_show_all_configured_slaves == xrp.m_show_all_configured_slaves
&& m_stack_overlapping == xrp.m_stack_overlapping
&& m_display == xrp.m_display
&& m_snap_to == xrp.m_snap_to
&& m_prefix == xrp.m_prefix
&& m_master_label== xrp.m_master_label
&& m_offset == xrp.m_offset
&& m_slave_offset== xrp.m_slave_offset
&& m_xref_pos == xrp.m_xref_pos
&& m_slave_label == xrp.m_slave_label);
}
bool XRefProperties::operator !=(const XRefProperties &xrp) const
{
return (! (*this == xrp));
}