mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-05 18:54:14 +02:00
Merge branch 'qelectrotech:master' into no-sqlite
This commit is contained in:
@@ -35,13 +35,17 @@ AddTerminalToStripCommand::AddTerminalToStripCommand(QSharedPointer<RealTerminal
|
||||
const auto t_label = terminal->label();
|
||||
const auto ts_name = strip->name();
|
||||
|
||||
const auto str_1 = t_label.isEmpty() ? QObject::tr("Ajouter une borne") :
|
||||
QObject::tr("Ajouter la borne %1").arg(t_label);
|
||||
|
||||
const auto str_2 = ts_name.isEmpty() ? QObject::tr("à un groupe de bornes") :
|
||||
QObject::tr("au groupe de bornes %1").arg(ts_name);
|
||||
|
||||
setText(str_1 % " " % str_2);
|
||||
QString text;
|
||||
if (ts_name.isEmpty()) {
|
||||
text = t_label.isEmpty()
|
||||
? QObject::tr("Ajouter une borne à un groupe de bornes")
|
||||
: QObject::tr("Ajouter la borne %1 à un groupe de bornes").arg(t_label);
|
||||
} else {
|
||||
text = t_label.isEmpty()
|
||||
? QObject::tr("Ajouter une borne au groupe de bornes %1").arg(ts_name)
|
||||
: QObject::tr("Ajouter la borne %1 au groupe de bornes %2").arg(t_label, ts_name);
|
||||
}
|
||||
setText(text);
|
||||
}
|
||||
|
||||
AddTerminalToStripCommand::AddTerminalToStripCommand(QVector<QSharedPointer<RealTerminal>> terminals, TerminalStrip *strip, QUndoCommand *parent) :
|
||||
@@ -50,14 +54,11 @@ AddTerminalToStripCommand::AddTerminalToStripCommand(QVector<QSharedPointer<Real
|
||||
m_new_strip{strip}
|
||||
{
|
||||
const auto ts_name = strip->name();
|
||||
const auto count = m_terminal.size();
|
||||
|
||||
const auto str_1 = m_terminal.size() > 1 ? QObject::tr("Ajouter %1 bornes").arg(m_terminal.size()) :
|
||||
QObject::tr("Ajouter une borne");
|
||||
|
||||
const auto str_2 = ts_name.isEmpty() ? QObject::tr("à un groupe de bornes") :
|
||||
QObject::tr("au groupe de bornes %1").arg(ts_name);
|
||||
|
||||
setText(str_1 % " " % str_2);
|
||||
setText(ts_name.isEmpty()
|
||||
? QObject::tr("Ajouter %n borne(s) à un groupe de bornes", "", count)
|
||||
: QObject::tr("Ajouter %n borne(s) au groupe de bornes %1", "", count).arg(ts_name));
|
||||
}
|
||||
|
||||
|
||||
@@ -137,13 +138,11 @@ void RemoveTerminalFromStripCommand::redo()
|
||||
void RemoveTerminalFromStripCommand::setCommandTitle()
|
||||
{
|
||||
const auto strip_name = m_strip->name();
|
||||
const auto count = m_terminals.size();
|
||||
|
||||
const auto str_1 = m_terminals.size()>1 ? QObject::tr("Enlever %1 bornes").arg(m_terminals.size()):
|
||||
QObject::tr("Enlever une borne");
|
||||
|
||||
const auto str_2 = strip_name.isEmpty() ? QObject::tr("d'un groupe de bornes") :
|
||||
QObject::tr("du groupe de bornes %1").arg(strip_name);
|
||||
setText(str_1 % " " % str_2);
|
||||
setText(strip_name.isEmpty()
|
||||
? QObject::tr("Enlever %n borne(s) d'un groupe de bornes", "", count)
|
||||
: QObject::tr("Enlever %n borne(s) du groupe de bornes %1", "", count).arg(strip_name));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,19 +165,30 @@ MoveTerminalCommand::MoveTerminalCommand(QSharedPointer<PhysicalTerminal> termin
|
||||
t_label.append(", ");
|
||||
t_label.append(real_t->label());
|
||||
}
|
||||
const auto strip_name = old_strip->name();
|
||||
const auto new_strip_name = new_strip->name();
|
||||
|
||||
auto strip_name = old_strip->name();
|
||||
auto new_strip_name = new_strip->name();
|
||||
|
||||
auto str_1 = t_label.isEmpty() ? QObject::tr("Déplacer une borne") :
|
||||
QObject::tr("Déplacer la borne %1").arg(t_label);
|
||||
|
||||
auto str_2 = strip_name.isEmpty() ? QObject::tr(" d'un groupe de bornes") :
|
||||
QObject::tr(" du groupe de bornes %1").arg(strip_name);
|
||||
|
||||
auto str_3 = new_strip_name.isEmpty() ? QObject::tr("vers un groupe de bornes") :
|
||||
QObject::tr("vers le groupe de bornes %1").arg(new_strip_name);
|
||||
setText(str_1 % " " % str_2 % " " % str_3);
|
||||
QString text;
|
||||
if (t_label.isEmpty()) {
|
||||
if (strip_name.isEmpty() && new_strip_name.isEmpty())
|
||||
text = QObject::tr("Déplacer une borne d'un groupe de bornes vers un groupe de bornes");
|
||||
else if (strip_name.isEmpty())
|
||||
text = QObject::tr("Déplacer une borne d'un groupe de bornes vers le groupe de bornes %1").arg(new_strip_name);
|
||||
else if (new_strip_name.isEmpty())
|
||||
text = QObject::tr("Déplacer une borne du groupe de bornes %1 vers un groupe de bornes").arg(strip_name);
|
||||
else
|
||||
text = QObject::tr("Déplacer une borne du groupe de bornes %1 vers le groupe de bornes %2").arg(strip_name, new_strip_name);
|
||||
} else {
|
||||
if (strip_name.isEmpty() && new_strip_name.isEmpty())
|
||||
text = QObject::tr("Déplacer la borne %1 d'un groupe de bornes vers un groupe de bornes").arg(t_label);
|
||||
else if (strip_name.isEmpty())
|
||||
text = QObject::tr("Déplacer la borne %1 d'un groupe de bornes vers le groupe de bornes %2").arg(t_label, new_strip_name);
|
||||
else if (new_strip_name.isEmpty())
|
||||
text = QObject::tr("Déplacer la borne %1 du groupe de bornes %2 vers un groupe de bornes").arg(t_label, strip_name);
|
||||
else
|
||||
text = QObject::tr("Déplacer la borne %1 du groupe de bornes %2 vers le groupe de bornes %3").arg(t_label, strip_name, new_strip_name);
|
||||
}
|
||||
setText(text);
|
||||
}
|
||||
|
||||
MoveTerminalCommand::MoveTerminalCommand(QVector<QSharedPointer<PhysicalTerminal>> terminals, TerminalStrip *old_strip,
|
||||
@@ -191,17 +201,18 @@ MoveTerminalCommand::MoveTerminalCommand(QVector<QSharedPointer<PhysicalTerminal
|
||||
{
|
||||
const auto strip_name = old_strip->name();
|
||||
const auto new_strip_name = new_strip->name();
|
||||
const auto count = m_terminal.size();
|
||||
|
||||
const auto str_1 = m_terminal.size() > 1 ? QObject::tr("Déplacer des bornes") :
|
||||
QObject::tr("Déplacer une borne");
|
||||
|
||||
const auto str_2 = strip_name.isEmpty() ? QObject::tr(" d'un groupe de bornes") :
|
||||
QObject::tr(" du groupe de bornes %1").arg(strip_name);
|
||||
|
||||
const auto str_3 = new_strip_name.isEmpty() ? QObject::tr("vers un groupe de bornes") :
|
||||
QObject::tr("vers le groupe de bornes %1").arg(new_strip_name);
|
||||
|
||||
setText(str_1 % " " % str_2 % " " % str_3);
|
||||
QString text;
|
||||
if (strip_name.isEmpty() && new_strip_name.isEmpty())
|
||||
text = QObject::tr("Déplacer %n borne(s) d'un groupe de bornes vers un groupe de bornes", "", count);
|
||||
else if (strip_name.isEmpty())
|
||||
text = QObject::tr("Déplacer %n borne(s) d'un groupe de bornes vers le groupe de bornes %1", "", count).arg(new_strip_name);
|
||||
else if (new_strip_name.isEmpty())
|
||||
text = QObject::tr("Déplacer %n borne(s) du groupe de bornes %1 vers un groupe de bornes", "", count).arg(strip_name);
|
||||
else
|
||||
text = QObject::tr("Déplacer %n borne(s) du groupe de bornes %1 vers le groupe de bornes %2", "", count).arg(strip_name, new_strip_name);
|
||||
setText(text);
|
||||
}
|
||||
|
||||
void MoveTerminalCommand::undo()
|
||||
|
||||
@@ -275,3 +275,80 @@ QString NumerotationContext::formatValue(const QStringList &item)
|
||||
return QString("%1").arg(value.toInt(), 3, 10, QChar('0'));
|
||||
return QString::number(value.toInt());
|
||||
}
|
||||
|
||||
/**
|
||||
@brief NumerotationContext::saveToSettings
|
||||
Save a hash of named NumerotationContexts to QSettings.
|
||||
@param contexts : the named rules to save
|
||||
@param currentRule : the name of the currently active rule
|
||||
@param settings : QSettings instance
|
||||
@param prefix : settings key prefix (e.g. "autonum/conductor")
|
||||
*/
|
||||
void NumerotationContext::saveToSettings(
|
||||
const QHash<QString, NumerotationContext> &contexts,
|
||||
const QString ¤tRule,
|
||||
QSettings &settings,
|
||||
const QString &prefix)
|
||||
{
|
||||
settings.setValue(prefix + "/current", currentRule);
|
||||
|
||||
// Clear stale array entries before writing (beginWriteArray does not
|
||||
// remove entries beyond the new size).
|
||||
settings.remove(prefix + "/rules");
|
||||
|
||||
QStringList names = contexts.keys();
|
||||
settings.beginWriteArray(prefix + "/rules", names.size());
|
||||
for (int i = 0; i < names.size(); ++i) {
|
||||
settings.setArrayIndex(i);
|
||||
const QString &name = names.at(i);
|
||||
const NumerotationContext &nc = contexts.value(name);
|
||||
|
||||
settings.setValue("name", name);
|
||||
|
||||
// Serialize context to XML string
|
||||
QDomDocument doc;
|
||||
NumerotationContext nc_copy = nc;
|
||||
QDomElement root = nc_copy.toXml(doc, "context");
|
||||
doc.appendChild(root);
|
||||
settings.setValue("xml", doc.toString());
|
||||
}
|
||||
settings.endArray();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief NumerotationContext::loadFromSettings
|
||||
Load named NumerotationContexts from QSettings.
|
||||
@param settings : QSettings instance
|
||||
@param prefix : settings key prefix (e.g. "autonum/conductor")
|
||||
@return pair of (hash of named rules, name of current rule)
|
||||
*/
|
||||
QPair<QHash<QString, NumerotationContext>, QString> NumerotationContext::loadFromSettings(
|
||||
QSettings &settings,
|
||||
const QString &prefix)
|
||||
{
|
||||
QPair<QHash<QString, NumerotationContext>, QString> result;
|
||||
QHash<QString, NumerotationContext> &contexts = result.first;
|
||||
QString ¤tRule = result.second;
|
||||
|
||||
currentRule = settings.value(prefix + "/current").toString();
|
||||
|
||||
int size = settings.beginReadArray(prefix + "/rules");
|
||||
for (int i = 0; i < size; ++i) {
|
||||
settings.setArrayIndex(i);
|
||||
QString name = settings.value("name").toString();
|
||||
QString xmlStr = settings.value("xml").toString();
|
||||
|
||||
if (name.isEmpty() || xmlStr.isEmpty()) continue;
|
||||
|
||||
QDomDocument doc;
|
||||
if (!doc.setContent(xmlStr)) continue;
|
||||
|
||||
QDomElement root = doc.documentElement();
|
||||
NumerotationContext nc;
|
||||
nc.fromXml(root);
|
||||
contexts.insert(name, nc);
|
||||
}
|
||||
settings.endArray();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
#include <QDomElement>
|
||||
#include <QHash>
|
||||
#include <QSettings>
|
||||
|
||||
/**
|
||||
This class represents a numerotation context, i.e. the data (type, value, increase)
|
||||
@@ -60,6 +62,14 @@ class NumerotationContext
|
||||
/// UI preview of a part's value matches what actually gets rendered.
|
||||
static QString formatValue(const QStringList &item);
|
||||
|
||||
static void saveToSettings(const QHash<QString, NumerotationContext> &contexts,
|
||||
const QString ¤tRule,
|
||||
QSettings &settings,
|
||||
const QString &prefix);
|
||||
static QPair<QHash<QString, NumerotationContext>, QString> loadFromSettings(
|
||||
QSettings &settings,
|
||||
const QString &prefix);
|
||||
|
||||
private:
|
||||
QStringList content_;
|
||||
};
|
||||
|
||||
@@ -137,25 +137,14 @@ void ElementTextsMover::endMovement()
|
||||
|
||||
QString ElementTextsMover::undoText() const
|
||||
{
|
||||
QString undo_text;
|
||||
|
||||
if(m_text_count == 1)
|
||||
undo_text.append(QObject::tr("Déplacer un texte d'élément"));
|
||||
else if(m_text_count > 1)
|
||||
undo_text.append(QObject::tr("Déplacer %1 textes d'élément").arg(m_items_hash.size()));
|
||||
|
||||
if(m_group_count >= 1)
|
||||
{
|
||||
if(undo_text.isEmpty())
|
||||
undo_text.append(QObject::tr("Déplacer"));
|
||||
else
|
||||
undo_text.append(QObject::tr(" et"));
|
||||
|
||||
if(m_group_count == 1)
|
||||
undo_text.append(QObject::tr(" un groupe de texte"));
|
||||
else
|
||||
undo_text.append(QObject::tr((" %1 groupes de textes")).arg(m_group_count));
|
||||
}
|
||||
|
||||
return undo_text;
|
||||
QStringList parts;
|
||||
if (m_text_count)
|
||||
parts << QObject::tr("%n texte(s) d'élément", "", m_text_count);
|
||||
if (m_group_count)
|
||||
parts << QObject::tr("%n groupe(s) de textes", "", m_group_count);
|
||||
|
||||
if (parts.isEmpty())
|
||||
return QString(); // should never occur
|
||||
|
||||
return QObject::tr("Déplacer %1").arg(QLocale().createSeparatedList(parts));
|
||||
}
|
||||
|
||||
+110
-57
@@ -21,36 +21,40 @@
|
||||
|
||||
#include <QApplication>
|
||||
#include <QEvent>
|
||||
#include <QPainter>
|
||||
#include <QPaintEvent>
|
||||
#include <QStyleHintReturnMask>
|
||||
#include <QStyleOptionRubberBand>
|
||||
#include <QtMath>
|
||||
|
||||
namespace {
|
||||
/**
|
||||
QGraphicsScene::drawItems() is protected, and QGraphicsView::drawItems()
|
||||
hands the scene the viewport only when the painter is on it. The
|
||||
view paints into an image, and still needs the scene to get the
|
||||
viewport: that is what makes the scene record where it painted
|
||||
each item, which is where the item is erased from when it moves.
|
||||
Naming the member through a derived class is the standard way to
|
||||
a pointer to a protected member; a call through it dispatches to
|
||||
the scene's own override, if any.
|
||||
*/
|
||||
struct SceneAccess : QGraphicsScene
|
||||
{
|
||||
using DrawItems = void (QGraphicsScene::*)(QPainter *, int, QGraphicsItem *[],
|
||||
const QStyleOptionGraphicsItem[], QWidget *);
|
||||
static DrawItems drawItemsPointer() { return &SceneAccess::drawItems; }
|
||||
};
|
||||
}
|
||||
|
||||
PaletteGraphicsView::PaletteGraphicsView(QWidget *parent) :
|
||||
QGraphicsView(parent)
|
||||
{
|
||||
qApp->installEventFilter(this);
|
||||
setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
|
||||
}
|
||||
|
||||
PaletteGraphicsView::PaletteGraphicsView(QGraphicsScene *scene, QWidget *parent) :
|
||||
QGraphicsView(scene, parent)
|
||||
{
|
||||
qApp->installEventFilter(this);
|
||||
setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
|
||||
listenToScene(scene);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PaletteGraphicsView::setScene
|
||||
Same as QGraphicsView::setScene, and keeps the scene's updates flowing
|
||||
(see the class description).
|
||||
*/
|
||||
void PaletteGraphicsView::setScene(QGraphicsScene *scene)
|
||||
{
|
||||
QGraphicsView::setScene(scene);
|
||||
listenToScene(scene);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,21 +76,6 @@ void PaletteGraphicsView::paintingInverted(bool inverted)
|
||||
Q_UNUSED(inverted)
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PaletteGraphicsView::listenToScene
|
||||
Connect a receiver to the scene's changed() signal, dropping the one
|
||||
on the previous scene. Any receiver does; this one has nothing to do.
|
||||
The connection dies with the view.
|
||||
*/
|
||||
void PaletteGraphicsView::listenToScene(QGraphicsScene *scene)
|
||||
{
|
||||
disconnect(m_scene_connection);
|
||||
m_scene_connection = QMetaObject::Connection();
|
||||
if (scene)
|
||||
m_scene_connection = connect(scene, &QGraphicsScene::changed,
|
||||
this, [](const QList<QRectF> &) {});
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PaletteGraphicsView::eventFilter
|
||||
Repaint the whole viewport when the application palette changes. Qt
|
||||
@@ -111,57 +100,121 @@ bool PaletteGraphicsView::eventFilter(QObject *watched, QEvent *event)
|
||||
void PaletteGraphicsView::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
if (invertsLightness())
|
||||
paintInverted(event->rect());
|
||||
else
|
||||
QGraphicsView::paintEvent(event);
|
||||
{
|
||||
paintInverted(event);
|
||||
return;
|
||||
}
|
||||
m_buffer = QImage();
|
||||
QGraphicsView::paintEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PaletteGraphicsView::paintInverted
|
||||
Render \a area of the viewport into an off-screen image, invert the
|
||||
lightness of that image between the palette's Base and Text colors and
|
||||
blit it to the viewport. Inverting the finished rendering turns the
|
||||
white sheet dark and the black ink light in one pass, and keeps the
|
||||
hue of colored strokes.
|
||||
@param area the part of the viewport to repaint, in viewport coordinates
|
||||
Run QGraphicsView::paintEvent() with the drawing hooks redirected to
|
||||
an off-screen image of the viewport, then invert the lightness of the
|
||||
exposed part of that image between the palette's Base and Text colors
|
||||
and blit it to the viewport. Inverting the finished rendering turns
|
||||
the white sheet dark and the black ink light in one pass, and keeps
|
||||
the hue of colored strokes. The image is in viewport coordinates, so
|
||||
the hooks paint with the view's own transform and the scene records
|
||||
the items' places in the viewport, as it does on a light palette.
|
||||
@param event the paint event, for the exposed area
|
||||
*/
|
||||
void PaletteGraphicsView::paintInverted(const QRect &area)
|
||||
void PaletteGraphicsView::paintInverted(QPaintEvent *event)
|
||||
{
|
||||
const QRect rect = area.intersected(viewport()->rect());
|
||||
if (rect.isEmpty())
|
||||
const QRect exposed = event->rect().intersected(viewport()->rect());
|
||||
if (exposed.isEmpty())
|
||||
return;
|
||||
|
||||
const qreal ratio = viewport()->devicePixelRatioF();
|
||||
QImage buffer(qCeil(rect.width() * ratio), qCeil(rect.height() * ratio),
|
||||
QImage::Format_RGB32);
|
||||
buffer.setDevicePixelRatio(ratio);
|
||||
// render() paints only what the scene draws; what it leaves blank is
|
||||
const QSize size(qCeil(viewport()->width() * ratio), qCeil(viewport()->height() * ratio));
|
||||
if (m_buffer.size() != size || m_buffer.devicePixelRatio() != ratio)
|
||||
{
|
||||
m_buffer = QImage(size, QImage::Format_RGB32);
|
||||
m_buffer.setDevicePixelRatio(ratio);
|
||||
}
|
||||
|
||||
m_buffer_painter.begin(&m_buffer);
|
||||
// The hooks paint only what the scene draws; what they leave blank is
|
||||
// the white sheet, which the inversion turns into the Base color.
|
||||
buffer.fill(Qt::white);
|
||||
m_buffer_painter.fillRect(exposed, Qt::white);
|
||||
m_buffer_painter.setClipRect(exposed);
|
||||
m_buffer_painter.setRenderHints(renderHints());
|
||||
m_buffer_painter.setWorldTransform(viewportTransform());
|
||||
|
||||
QPainter buffer_painter(&buffer);
|
||||
buffer_painter.setRenderHints(renderHints());
|
||||
m_inverting = true;
|
||||
paintingInverted(true);
|
||||
render(&buffer_painter, QRectF(QPointF(0, 0), QSizeF(rect.size())),
|
||||
rect, Qt::IgnoreAspectRatio);
|
||||
const OptimizationFlags flags = optimizationFlags();
|
||||
setOptimizationFlag(QGraphicsView::IndirectPainting, true);
|
||||
QGraphicsView::paintEvent(event);
|
||||
setOptimizationFlags(flags);
|
||||
paintingInverted(false);
|
||||
buffer_painter.end();
|
||||
m_inverting = false;
|
||||
|
||||
m_buffer_painter.end();
|
||||
blitInverted(exposed);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PaletteGraphicsView::drawBackground
|
||||
Into the off-screen image while painting inverted, else as
|
||||
QGraphicsView.
|
||||
*/
|
||||
void PaletteGraphicsView::drawBackground(QPainter *painter, const QRectF &rect)
|
||||
{
|
||||
QGraphicsView::drawBackground(m_inverting ? &m_buffer_painter : painter, rect);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PaletteGraphicsView::drawItems
|
||||
Into the off-screen image while painting inverted, with the viewport
|
||||
as the scene's widget (see SceneAccess), else as QGraphicsView.
|
||||
*/
|
||||
void PaletteGraphicsView::drawItems(QPainter *painter, int count, QGraphicsItem *items[],
|
||||
const QStyleOptionGraphicsItem options[])
|
||||
{
|
||||
if (m_inverting && scene())
|
||||
(scene()->*SceneAccess::drawItemsPointer())(&m_buffer_painter, count, items, options, viewport());
|
||||
else
|
||||
QGraphicsView::drawItems(painter, count, items, options);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PaletteGraphicsView::drawForeground
|
||||
Into the off-screen image while painting inverted, else as
|
||||
QGraphicsView.
|
||||
*/
|
||||
void PaletteGraphicsView::drawForeground(QPainter *painter, const QRectF &rect)
|
||||
{
|
||||
QGraphicsView::drawForeground(m_inverting ? &m_buffer_painter : painter, rect);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PaletteGraphicsView::blitInverted
|
||||
Invert the lightness of \a area of the off-screen image and draw it on
|
||||
the viewport, then the selection rubber band on top: the one
|
||||
QGraphicsView::paintEvent() drew went under the blit.
|
||||
@param area the part of the viewport to blit, in viewport coordinates
|
||||
*/
|
||||
void PaletteGraphicsView::blitInverted(const QRect &area)
|
||||
{
|
||||
const qreal ratio = m_buffer.devicePixelRatio();
|
||||
QImage part = m_buffer.copy(QRectF(area.topLeft() * ratio, area.size() * ratio).toAlignedRect());
|
||||
part.setDevicePixelRatio(ratio);
|
||||
// The application palette, for the reason given in invertsLightness().
|
||||
const QPalette application_palette = QApplication::palette();
|
||||
QET::Palette::invertLightness(buffer, application_palette.color(QPalette::Base),
|
||||
QET::Palette::invertLightness(part, application_palette.color(QPalette::Base),
|
||||
application_palette.color(QPalette::Text));
|
||||
|
||||
QPainter painter(viewport());
|
||||
painter.drawImage(rect.topLeft(), buffer);
|
||||
painter.drawImage(area.topLeft(), part);
|
||||
drawRubberBand(painter);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PaletteGraphicsView::drawRubberBand
|
||||
Draw the selection rubber band the way QGraphicsView::paintEvent does.
|
||||
Rendering the view into an off-screen image skips it, so it is drawn
|
||||
here instead, after the inversion, in the palette colors.
|
||||
Draw the selection rubber band the way QGraphicsView::paintEvent does,
|
||||
after the inversion, in the palette colors.
|
||||
@param painter a painter on the viewport
|
||||
*/
|
||||
void PaletteGraphicsView::drawRubberBand(QPainter &painter)
|
||||
|
||||
@@ -19,38 +19,39 @@
|
||||
#define PALETTE_GRAPHICS_VIEW_H
|
||||
|
||||
#include <QGraphicsView>
|
||||
|
||||
class QPainter;
|
||||
#include <QImage>
|
||||
#include <QPainter>
|
||||
|
||||
/**
|
||||
A QGraphicsView that shows its scene with inverted lightness while its
|
||||
palette is dark: white becomes the palette's Base color, black its Text
|
||||
color, and colored strokes keep their hue. The scene itself is left as
|
||||
drawn, so printing and exporting it still give black on white. On a
|
||||
light palette the view paints exactly as QGraphicsView does.
|
||||
A QGraphicsView that shows its scene with inverted lightness while the
|
||||
application palette is dark: white becomes the palette's Base color,
|
||||
black its Text color, and colored strokes keep their hue. The scene
|
||||
itself is left as drawn, so printing and exporting it still give black
|
||||
on white. On a light palette the view paints exactly as QGraphicsView
|
||||
does.
|
||||
|
||||
The view paints through QGraphicsView::render() into an image and blits
|
||||
the inverted image. QGraphicsView delivers scene updates straight to
|
||||
its viewport when nobody listens to QGraphicsScene::changed(), and in
|
||||
that mode the scene clears its "update everything" flag only when the
|
||||
items are painted straight onto the viewport, which never happens
|
||||
here: from the second QGraphicsScene::update() on, every scene update
|
||||
and every item update would wait for an unrelated repaint. So the view
|
||||
listens to changed() on every scene it is given, which makes the scene
|
||||
clear the flag before it emits. Set the scene through this class, not
|
||||
through a QGraphicsView pointer.
|
||||
On a dark palette the view still runs QGraphicsView::paintEvent(), with
|
||||
the IndirectPainting flag set for the duration of that call, so that
|
||||
the background, the items and the foreground come through the
|
||||
drawBackground(), drawItems() and drawForeground() hooks. (That flag
|
||||
selects Qt's older item-painting algorithm, which first builds a list
|
||||
of the exposed items and their style options; it is set only while
|
||||
the view paints inverted.) The hooks
|
||||
paint into an off-screen image the size of the viewport, in viewport
|
||||
coordinates; paintEvent() then inverts the lightness of the exposed
|
||||
part of that image and blits it. Going through the real paint event,
|
||||
and handing the scene the viewport when the items are drawn, keeps the
|
||||
view on QGraphicsView's default update path, which erases a moved item
|
||||
where it was last painted, children included, even a child whose
|
||||
geometry is set while its parent is painted (a terminal's help lines).
|
||||
The alternative, rendering with QGraphicsView::render(), needed a
|
||||
receiver on QGraphicsScene::changed() to keep the scene's updates
|
||||
flowing, and that receiver puts the scene on its Qt 4.4 compatibility
|
||||
path, which erases only the moved item's own old rectangle: a moved
|
||||
element then left its terminals' help lines, which span the whole
|
||||
sheet, behind at every step (#954).
|
||||
|
||||
The constructor also forces QGraphicsView::FullViewportUpdate in place
|
||||
of the default MinimalViewportUpdate. #954 shipped with the default
|
||||
kept, and moving an item then left conductor-shaped ghosts behind on
|
||||
both a light and a dark palette, so the cause is shared code, not
|
||||
paintInverted(): most likely listening to changed() at all, above,
|
||||
changes which of QGraphicsScene's two update paths a view is on, and
|
||||
MinimalViewportUpdate's job of turning the scene's reported dirty
|
||||
rects into the smallest correct viewport region is where that would
|
||||
show up first. FullViewportUpdate removes the need to get that region
|
||||
right by repainting the whole viewport on every update; the class's
|
||||
own benchmark already shows that cost is small next to a frame budget.
|
||||
The CacheBackground cache mode is not supported on the inverted path.
|
||||
*/
|
||||
class PaletteGraphicsView : public QGraphicsView
|
||||
{
|
||||
@@ -60,14 +61,17 @@ class PaletteGraphicsView : public QGraphicsView
|
||||
explicit PaletteGraphicsView(QWidget *parent = nullptr);
|
||||
explicit PaletteGraphicsView(QGraphicsScene *scene, QWidget *parent = nullptr);
|
||||
|
||||
void setScene(QGraphicsScene *scene);
|
||||
bool invertsLightness() const;
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void drawBackground(QPainter *painter, const QRectF &rect) override;
|
||||
void drawItems(QPainter *painter, int count, QGraphicsItem *items[],
|
||||
const QStyleOptionGraphicsItem options[]) override;
|
||||
void drawForeground(QPainter *painter, const QRectF &rect) override;
|
||||
/**
|
||||
Called with true right before the scene is rendered for an
|
||||
Called with true right before the scene is painted for an
|
||||
inverted display and with false right after, so a scene can
|
||||
adapt what it draws (a softer grid, for instance). Does
|
||||
nothing by default.
|
||||
@@ -75,11 +79,17 @@ class PaletteGraphicsView : public QGraphicsView
|
||||
virtual void paintingInverted(bool inverted);
|
||||
|
||||
private:
|
||||
void listenToScene(QGraphicsScene *scene);
|
||||
void paintInverted(const QRect &area);
|
||||
void paintInverted(QPaintEvent *event);
|
||||
void blitInverted(const QRect &area);
|
||||
void drawRubberBand(QPainter &painter);
|
||||
|
||||
QMetaObject::Connection m_scene_connection;
|
||||
/// The off-screen image the hooks paint into while m_inverting:
|
||||
/// the viewport's size, in its coordinates. Kept between paints,
|
||||
/// dropped when the view paints on a light palette again.
|
||||
QImage m_buffer;
|
||||
QPainter m_buffer_painter;
|
||||
/// True while paintEvent() paints for an inverted display.
|
||||
bool m_inverting = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+54
-50
@@ -271,84 +271,88 @@ QString QET::ElementsAndConductorsSentence(
|
||||
int tables_count,
|
||||
int terminal_strip_count)
|
||||
{
|
||||
QString text;
|
||||
QStringList parts;
|
||||
if (elements_count) {
|
||||
text += QObject::tr(
|
||||
"%n élément(s)",
|
||||
"part of a sentence listing the content of a diagram",
|
||||
elements_count
|
||||
parts.append(
|
||||
QObject::tr(
|
||||
"%n élément(s)",
|
||||
"part of a enumerative partial sentence listing the content of a diagram",
|
||||
elements_count
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (conductors_count) {
|
||||
if (!text.isEmpty()) text += ", ";
|
||||
text += QObject::tr(
|
||||
"%n conducteur(s)",
|
||||
"part of a sentence listing the content of a diagram",
|
||||
conductors_count
|
||||
parts.append(
|
||||
QObject::tr(
|
||||
"%n conducteur(s)",
|
||||
"part of a enumerative partial sentence listing the content of a diagram",
|
||||
conductors_count
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (texts_count) {
|
||||
if (!text.isEmpty()) text += ", ";
|
||||
text += QObject::tr(
|
||||
"%n champ(s) de texte",
|
||||
"part of a sentence listing the content of a diagram",
|
||||
texts_count
|
||||
parts.append(
|
||||
QObject::tr(
|
||||
"%n champ(s) de texte",
|
||||
"part of a enumerative partial sentence listing the content of a diagram",
|
||||
texts_count
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (images_count) {
|
||||
if (!text.isEmpty()) text += ", ";
|
||||
// Qt's %n only selects a grammatical singular/plural form (the
|
||||
// "(s)" convention used by every other count here) -- it never
|
||||
// spells the number out as a word, so getting "une image"
|
||||
// instead of the literal "1 image" for the single-item case
|
||||
// means handling that count outside %n entirely, with its own
|
||||
// fixed string.
|
||||
text += images_count == 1
|
||||
? QObject::tr("une image", "part of a sentence listing the content of a diagram")
|
||||
: QObject::tr(
|
||||
"%n images",
|
||||
"part of a sentence listing the content of a diagram",
|
||||
images_count
|
||||
);
|
||||
parts.append(
|
||||
QObject::tr(
|
||||
"%n image(s)",
|
||||
"part of a enumerative partial sentence listing the content of a diagram",
|
||||
images_count
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (shapes_count) {
|
||||
if (!text.isEmpty()) text += ", ";
|
||||
text += QObject::tr(
|
||||
"%n forme(s)",
|
||||
"part of a sentence listing the content of a diagram",
|
||||
shapes_count
|
||||
parts.append(
|
||||
QObject::tr(
|
||||
"%n forme(s)",
|
||||
"part of a enumerative partial sentence listing the content of a diagram",
|
||||
shapes_count
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (element_text_count) {
|
||||
if (!text.isEmpty()) text += ", ";
|
||||
text += QObject::tr(
|
||||
"%n texte(s) d'élément",
|
||||
"part of a sentence listing the content of a diagram",
|
||||
element_text_count);
|
||||
parts.append(
|
||||
QObject::tr(
|
||||
"%n texte(s) d'élément",
|
||||
"part of a enumerative partial sentence listing the content of a diagram",
|
||||
element_text_count
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (tables_count) {
|
||||
if (!text.isEmpty()) text += ", ";
|
||||
text += QObject::tr(
|
||||
"%n tableau(s)",
|
||||
"part of a sentence listing the content of diagram",
|
||||
tables_count);
|
||||
parts.append(
|
||||
QObject::tr(
|
||||
"%n tableau(s)",
|
||||
"part of a enumerative partial sentence listing the content of diagram",
|
||||
tables_count
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (terminal_strip_count) {
|
||||
if (!text.isEmpty()) text += ", ";
|
||||
text += QObject::tr(
|
||||
"%n plan de bornes",
|
||||
"part of a sentence listing the content of a diagram",
|
||||
terminal_strip_count);
|
||||
parts.append(
|
||||
QObject::tr(
|
||||
"%n plan(s) de bornes",
|
||||
"part of a enumerative partial sentence listing the content of a diagram",
|
||||
terminal_strip_count
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return(text);
|
||||
return QLocale().createSeparatedList(parts);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -235,6 +235,8 @@ QString QETApp::loadedQtTranslationFile()
|
||||
*/
|
||||
void QETApp::setLanguage(const QString &desired_language) {
|
||||
QString languages_path = languagesPath();
|
||||
|
||||
QLocale::setDefault(QLocale(desired_language));
|
||||
|
||||
// load Qt library translations
|
||||
QString qt_l10n_path = QLibraryInfo::path(QLibraryInfo::TranslationsPath);
|
||||
@@ -1808,6 +1810,10 @@ void QETApp::useSystemPalette(bool use) {
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
// Widgets with their own style sheet keep the palette they were
|
||||
// polished with; after a live light/dark switch they would stay in
|
||||
// the old colors (see QET::Palette::refreshStyleSheets).
|
||||
QET::Palette::refreshStyleSheets();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -629,7 +629,13 @@ void DynamicElementTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
int diffx = qRound(current_parent_pos.x() - button_down_parent_pos.x());
|
||||
int diffy = qRound(current_parent_pos.y() - button_down_parent_pos.y());
|
||||
QPointF new_pos = m_initial_position + QPointF(diffx, diffy);
|
||||
setPos(new_pos);
|
||||
//Snap to the grid, Ctrl to place freely -- the same line
|
||||
//ElementTextItemGroup::mouseMoveEvent() and
|
||||
//ElementTextsMover::continueMovement() already use, and
|
||||
//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));
|
||||
|
||||
if(diagram())
|
||||
diagram()->elementTextsMover().continueMovement(event);
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace QET {
|
||||
QIcon ConductorEdit;
|
||||
QIcon ConductorSettings;
|
||||
QIcon Configure;
|
||||
QIcon ConfigureShortcuts;
|
||||
QIcon ConfigureToolbars;
|
||||
QIcon IC_CopyFile;
|
||||
QIcon DefaultConductor;
|
||||
@@ -408,6 +409,7 @@ void QET::Icons::initIcons()
|
||||
ConductorEdit = QIcon::fromTheme("conductor-edit");
|
||||
ConductorSettings = QIcon::fromTheme("conductor-reset");
|
||||
Configure = QIcon::fromTheme("configure");
|
||||
ConfigureShortcuts = QIcon::fromTheme("configure-shortcuts");
|
||||
ConfigureToolbars = QIcon::fromTheme("configure-toolbars");
|
||||
IC_CopyFile = QIcon::fromTheme("item-copy");
|
||||
DiagramAdd = QIcon::fromTheme("folio-new");
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace QET {
|
||||
extern QIcon ConductorEdit;
|
||||
extern QIcon ConductorSettings;
|
||||
extern QIcon Configure;
|
||||
extern QIcon ConfigureShortcuts;
|
||||
extern QIcon ConfigureToolbars;
|
||||
extern QIcon IC_CopyFile;
|
||||
extern QIcon DefaultConductor;
|
||||
|
||||
+13
-1
@@ -17,10 +17,11 @@
|
||||
*/
|
||||
#include "qetpalette.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QColor>
|
||||
#include <QImage>
|
||||
#include <QStyle>
|
||||
|
||||
#include <QWidget>
|
||||
#include <cmath>
|
||||
|
||||
namespace {
|
||||
@@ -296,3 +297,14 @@ QPixmap QET::Palette::forPalette(const QPixmap &pixmap, const QPalette &palette)
|
||||
result.setDevicePixelRatio(pixmap.devicePixelRatio());
|
||||
return result;
|
||||
}
|
||||
|
||||
void QET::Palette::refreshStyleSheets()
|
||||
{
|
||||
// Setting the same sheet again is not a no-op: QWidget::setStyleSheet()
|
||||
// asks QStyleSheetStyle to repolish the widget, which recomputes its
|
||||
// palette from the application palette now in force.
|
||||
const QWidgetList widgets = QApplication::allWidgets();
|
||||
for (QWidget *widget : widgets)
|
||||
if (!widget->styleSheet().isEmpty())
|
||||
widget->setStyleSheet(widget->styleSheet());
|
||||
}
|
||||
|
||||
@@ -135,6 +135,18 @@ namespace QET {
|
||||
left alone either way.
|
||||
*/
|
||||
QPixmap forPalette(const QPixmap &pixmap, const QPalette &palette);
|
||||
|
||||
/**
|
||||
Make every widget that carries a style sheet take the current
|
||||
application palette. QApplication::setPalette() reaches plain
|
||||
widgets, but a widget with a style sheet keeps the palette
|
||||
QStyleSheetStyle resolved when the sheet was applied, so after a
|
||||
live light/dark switch it is drawn in the old colors (the folio
|
||||
tab bar and its buttons, the element info widgets, several
|
||||
configuration pages). Re-applying each widget's own sheet makes
|
||||
QStyleSheetStyle resolve it again. Call after setPalette().
|
||||
*/
|
||||
void refreshStyleSheets();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +83,30 @@ m_project_properties_handler{this}
|
||||
m_default_guides.append(g);
|
||||
}
|
||||
settings.endArray();
|
||||
|
||||
//Load global auto-numbering defaults from QSettings
|
||||
{
|
||||
auto conductorData = NumerotationContext::loadFromSettings(settings, QStringLiteral("autonum/conductor"));
|
||||
for (auto it = conductorData.first.constBegin(); it != conductorData.first.constEnd(); ++it) {
|
||||
addConductorAutoNum(it.key(), it.value());
|
||||
}
|
||||
if (!conductorData.second.isEmpty()) {
|
||||
setCurrentConductorAutoNum(conductorData.second);
|
||||
}
|
||||
|
||||
auto elementData = NumerotationContext::loadFromSettings(settings, QStringLiteral("autonum/element"));
|
||||
for (auto it = elementData.first.constBegin(); it != elementData.first.constEnd(); ++it) {
|
||||
addElementAutoNum(it.key(), it.value());
|
||||
}
|
||||
if (!elementData.second.isEmpty()) {
|
||||
setCurrrentElementAutonum(elementData.second);
|
||||
}
|
||||
|
||||
auto folioData = NumerotationContext::loadFromSettings(settings, QStringLiteral("autonum/folio"));
|
||||
for (auto it = folioData.first.constBegin(); it != folioData.first.constEnd(); ++it) {
|
||||
addFolioAutoNum(it.key(), it.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProjectPropertiesHandler &QETProject::projectPropertiesHandler()
|
||||
|
||||
+11
-4
@@ -67,20 +67,27 @@ bool QETStyle::isLineArt(const QImage &image)
|
||||
/**
|
||||
@brief QETStyle::hoverColor
|
||||
The palette's highlight color is the accent users already know from
|
||||
selections. On a dark palette it is too dark to read on a hovered
|
||||
button face, so it is lightened, a step at a time, until it reaches
|
||||
selections, moved away from the hovered button face until it reaches
|
||||
3:1 (WCAG 1.4.11) against the Light role: Fusion paints a hovered
|
||||
auto-raise button with a gradient that runs from Button up to about
|
||||
that color, and the icon has to read on the lightest part of it.
|
||||
that color, and the icon has to read on the lightest part of it. On a
|
||||
dark face the accent is lightened, a step at a time; on a light face it
|
||||
is darkened, which keeps a pale accent (macOS's green or yellow
|
||||
selection color, which comes with black selection text) from being
|
||||
pushed to white. Should twenty steps not get there, the button text
|
||||
color serves, which reads on the face by construction.
|
||||
*/
|
||||
QColor QETStyle::hoverColor(const QPalette &palette)
|
||||
{
|
||||
const QColor face = palette.color(QPalette::Active, QPalette::Light);
|
||||
const bool light_face = face.lightnessF() > 0.5;
|
||||
QColor ink = palette.color(QPalette::Active, QPalette::Highlight);
|
||||
// 3.5 rather than 3.0: the top of Fusion's hover gradient is a shade
|
||||
// lighter than the Light role, so the icon needs some headroom there.
|
||||
for (int step = 0; step < 20 && QET::Palette::contrastRatio(ink, face) < 3.5; ++step)
|
||||
ink = ink.lighter(110);
|
||||
ink = light_face ? ink.darker(110) : ink.lighter(110);
|
||||
if (QET::Palette::contrastRatio(ink, face) < 3.5)
|
||||
ink = palette.color(QPalette::Active, QPalette::ButtonText);
|
||||
return ink;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include "../titleblockpropertieswidget.h"
|
||||
#include "../xrefpropertieswidget.h"
|
||||
#include "guidespropertieswidget.h"
|
||||
#include "../autoNum/numerotationcontext.h"
|
||||
#include "../autoNum/ui/selectautonumw.h"
|
||||
#include <QFont>
|
||||
#include <QFontDialog>
|
||||
#include <QSizePolicy>
|
||||
@@ -101,6 +103,32 @@ NewDiagramPage::NewDiagramPage(QETProject *project,
|
||||
}
|
||||
m_gpw->setGuides(loaded_guides);
|
||||
|
||||
// global auto-numbering defaults (only when editing global settings, not a project)
|
||||
if (!m_project) {
|
||||
auto saw_conductor = new SelectAutonumW(1);
|
||||
auto saw_element = new SelectAutonumW(0);
|
||||
auto saw_folio = new SelectAutonumW(2);
|
||||
|
||||
initAutoNumTab(m_autonum_conductor, saw_conductor, QStringLiteral("autonum/conductor"));
|
||||
initAutoNumTab(m_autonum_element, saw_element, QStringLiteral("autonum/element"));
|
||||
initAutoNumTab(m_autonum_folio, saw_folio, QStringLiteral("autonum/folio"));
|
||||
|
||||
QSettings autonum_settings;
|
||||
loadAutoNumTab(m_autonum_conductor, autonum_settings);
|
||||
loadAutoNumTab(m_autonum_element, autonum_settings);
|
||||
loadAutoNumTab(m_autonum_folio, autonum_settings);
|
||||
|
||||
// Intercept Return key in the combo line edits so it doesn't
|
||||
// activate the dialog's default button (OK).
|
||||
for (auto *tab : {&m_autonum_conductor, &m_autonum_element, &m_autonum_folio}) {
|
||||
if (QComboBox *combo = tab->widget->contextComboBox()) {
|
||||
if (combo->lineEdit()) {
|
||||
combo->lineEdit()->installEventFilter(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//If there is a project, we edit his properties
|
||||
if (m_project) {
|
||||
bpw -> setProperties (m_project -> defaultBorderProperties());
|
||||
@@ -114,6 +142,7 @@ NewDiagramPage::NewDiagramPage(QETProject *project,
|
||||
|
||||
// main tab widget
|
||||
QTabWidget *tab_widget = new QTabWidget(this);
|
||||
m_tab_widget = tab_widget;
|
||||
QWidget *diagram_widget = new QWidget();
|
||||
QVBoxLayout *diagram_layout = new QVBoxLayout(diagram_widget);
|
||||
|
||||
@@ -127,6 +156,19 @@ NewDiagramPage::NewDiagramPage(QETProject *project,
|
||||
tab_widget -> addTab (xrefpw, tr("Références croisées"));
|
||||
tab_widget -> addTab (m_gpw, tr("Guides"));
|
||||
|
||||
// add auto-numbering tab only for global settings (not per project)
|
||||
if (!m_project) {
|
||||
QWidget *autonum_widget = new QWidget();
|
||||
QVBoxLayout *autonum_layout = new QVBoxLayout(autonum_widget);
|
||||
autonum_layout->addWidget(new QLabel(tr("Définir les règles de numérotation automatique par défaut pour les nouveaux projets :")));
|
||||
QTabWidget *autonum_inner_tab = new QTabWidget();
|
||||
autonum_inner_tab->addTab(m_autonum_conductor.widget, tr("Conducteurs"));
|
||||
autonum_inner_tab->addTab(m_autonum_element.widget, tr("Eléments"));
|
||||
autonum_inner_tab->addTab(m_autonum_folio.widget, tr("Folios"));
|
||||
autonum_layout->addWidget(autonum_inner_tab);
|
||||
tab_widget -> addTab (autonum_widget, tr("Numérotation auto"));
|
||||
}
|
||||
|
||||
QVBoxLayout *vlayout1 = new QVBoxLayout();
|
||||
vlayout1->addWidget(tab_widget);
|
||||
|
||||
@@ -230,6 +272,9 @@ void NewDiagramPage::applyConf()
|
||||
settings.setValue(QStringLiteral("color"), current_guides[i].color.name());
|
||||
}
|
||||
settings.endArray();
|
||||
|
||||
// save global auto-numbering defaults
|
||||
persistAutonumSettings();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,6 +340,134 @@ void NewDiagramPage::loadSavedTbp()
|
||||
applyConf();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief NewDiagramPage::isPlaceholder
|
||||
Return true if @a name matches the combo box's built-in placeholder text
|
||||
(first item). This is locale-independent because it reads the actual item text.
|
||||
*/
|
||||
bool NewDiagramPage::isPlaceholder(QComboBox *combo, const QString &name)
|
||||
{
|
||||
return !combo->count() || name == combo->itemText(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief NewDiagramPage::initAutoNumTab
|
||||
Initialise an AutoNumTab struct and connect its signals.
|
||||
*/
|
||||
void NewDiagramPage::initAutoNumTab(AutoNumTab &tab, SelectAutonumW *w, const QString &prefix)
|
||||
{
|
||||
tab.widget = w;
|
||||
tab.prefix = prefix;
|
||||
|
||||
connect(w, &SelectAutonumW::applyPressed, this, [this, &tab]() { saveAutoNumContext(tab); });
|
||||
connect(w, &SelectAutonumW::removeClicked, this, [this, &tab]() { removeAutoNumContext(tab); });
|
||||
connect(w->contextComboBox(), &QComboBox::activated, this, [this, &tab](int index) {
|
||||
if (index >= 0) {
|
||||
QString name = tab.widget->contextComboBox()->itemText(index);
|
||||
if (tab.contexts.contains(name)) {
|
||||
tab.widget->setContext(tab.contexts.value(name));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@brief NewDiagramPage::loadAutoNumTab
|
||||
Load saved rules from QSettings into an AutoNumTab.
|
||||
*/
|
||||
void NewDiagramPage::loadAutoNumTab(AutoNumTab &tab, QSettings &settings)
|
||||
{
|
||||
auto data = NumerotationContext::loadFromSettings(settings, tab.prefix);
|
||||
tab.contexts = data.first;
|
||||
for (auto it = tab.contexts.constBegin(); it != tab.contexts.constEnd(); ++it) {
|
||||
tab.widget->contextComboBox()->addItem(it.key());
|
||||
}
|
||||
if (!tab.contexts.isEmpty() && !data.second.isEmpty()
|
||||
&& tab.contexts.contains(data.second)) {
|
||||
tab.widget->contextComboBox()->setCurrentText(data.second);
|
||||
tab.widget->setContext(tab.contexts.value(data.second));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief NewDiagramPage::saveAutoNumContext
|
||||
Save the current context from an AutoNumTab's widget into its hash and
|
||||
persist to QSettings immediately.
|
||||
*/
|
||||
void NewDiagramPage::saveAutoNumContext(AutoNumTab &tab)
|
||||
{
|
||||
QString name = tab.widget->contextComboBox()->currentText().trimmed();
|
||||
if (name.isEmpty() || isPlaceholder(tab.widget->contextComboBox(), name)) {
|
||||
return;
|
||||
}
|
||||
tab.contexts.insert(name, tab.widget->toNumContext());
|
||||
if (tab.widget->contextComboBox()->findText(name) == -1) {
|
||||
tab.widget->contextComboBox()->addItem(name);
|
||||
}
|
||||
persistAutonumSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief NewDiagramPage::removeAutoNumContext
|
||||
Remove the current context from an AutoNumTab's hash and persist.
|
||||
*/
|
||||
void NewDiagramPage::removeAutoNumContext(AutoNumTab &tab)
|
||||
{
|
||||
QString name = tab.widget->contextComboBox()->currentText().trimmed();
|
||||
if (name.isEmpty() || isPlaceholder(tab.widget->contextComboBox(), name)) {
|
||||
return;
|
||||
}
|
||||
int idx = tab.widget->contextComboBox()->findText(name);
|
||||
if (idx == -1) return;
|
||||
tab.contexts.remove(name);
|
||||
tab.widget->contextComboBox()->removeItem(idx);
|
||||
tab.widget->contextComboBox()->setCurrentText(QString());
|
||||
tab.widget->setContext(NumerotationContext());
|
||||
persistAutonumSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief NewDiagramPage::persistAutonumSettings
|
||||
Save all autonum contexts to QSettings immediately.
|
||||
*/
|
||||
void NewDiagramPage::persistAutonumSettings()
|
||||
{
|
||||
QSettings settings;
|
||||
for (auto *tab : {&m_autonum_conductor, &m_autonum_element, &m_autonum_folio}) {
|
||||
QString current;
|
||||
QComboBox *combo = tab->widget->contextComboBox();
|
||||
if (!isPlaceholder(combo, combo->currentText().trimmed())
|
||||
&& tab->contexts.contains(combo->currentText().trimmed())) {
|
||||
current = combo->currentText().trimmed();
|
||||
}
|
||||
NumerotationContext::saveToSettings(tab->contexts, current,
|
||||
settings, tab->prefix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief NewDiagramPage::eventFilter
|
||||
Intercept Return/Enter in combo box line edits so it doesn't close the
|
||||
settings dialog.
|
||||
*/
|
||||
bool NewDiagramPage::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
auto *ke = static_cast<QKeyEvent *>(event);
|
||||
if ((ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter)) {
|
||||
// Check if this is a line edit inside one of our autonum combos
|
||||
for (auto *tab : {&m_autonum_conductor, &m_autonum_element, &m_autonum_folio}) {
|
||||
if (QComboBox *combo = tab->widget->contextComboBox()) {
|
||||
if (combo->lineEdit() && combo->lineEdit() == obj) {
|
||||
return true; // eat the event
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ConfigPage::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param parent QWidget parent
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "configpage.h"
|
||||
#include "../projectpropertiesdialog.h"
|
||||
#include "../titleblockpropertieswidget.h"
|
||||
#include "../autoNum/numerotationcontext.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QtWidgets>
|
||||
@@ -32,6 +33,7 @@ class XRefPropertiesWidget;
|
||||
class GuidesPropertiesWidget;
|
||||
class QETProject;
|
||||
class TitleBlockProperties;
|
||||
class SelectAutonumW;
|
||||
|
||||
/**
|
||||
@brief The NewDiagramPage class
|
||||
@@ -48,6 +50,7 @@ class NewDiagramPage : public ConfigPage {
|
||||
~NewDiagramPage() override;
|
||||
private:
|
||||
NewDiagramPage(const NewDiagramPage &);
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
public slots:
|
||||
void changeToAutoFolioTab();
|
||||
void setFolioAutonum(QString);
|
||||
@@ -72,7 +75,25 @@ public slots:
|
||||
XRefPropertiesWidget *xrefpw; ///< Widget to edit default xref properties
|
||||
GuidesPropertiesWidget *m_gpw; ///< Widget to edit guides
|
||||
TitleBlockProperties savedTbp; ///< Used to save current TBP and retrieve later
|
||||
QTabWidget *m_tab_widget; ///< Main tab widget (stored for later access)
|
||||
|
||||
// auto-numbering tab data
|
||||
struct AutoNumTab {
|
||||
SelectAutonumW *widget = nullptr;
|
||||
QHash<QString, NumerotationContext> contexts;
|
||||
QString prefix;
|
||||
};
|
||||
AutoNumTab m_autonum_conductor;
|
||||
AutoNumTab m_autonum_element;
|
||||
AutoNumTab m_autonum_folio;
|
||||
|
||||
void initAutoNumTab(AutoNumTab &tab, SelectAutonumW *w, const QString &prefix);
|
||||
void loadAutoNumTab(AutoNumTab &tab, QSettings &settings);
|
||||
void saveAutoNumContext(AutoNumTab &tab);
|
||||
void removeAutoNumContext(AutoNumTab &tab);
|
||||
void persistAutonumSettings();
|
||||
|
||||
static bool isPlaceholder(QComboBox *combo, const QString &name);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -381,5 +381,5 @@ QString ShortcutsConfigPage::title() const
|
||||
|
||||
QIcon ShortcutsConfigPage::icon() const
|
||||
{
|
||||
return QET::Icons::ConfigureToolbars;
|
||||
return QET::Icons::ConfigureShortcuts;
|
||||
}
|
||||
|
||||
@@ -55,21 +55,13 @@ m_diagram(diagram)
|
||||
{
|
||||
openDialog();
|
||||
|
||||
QString text;
|
||||
if(texts_list.count())
|
||||
text.append(QObject::tr("Pivoter %1 textes").arg(texts_list.count()));
|
||||
if(groups_list.count())
|
||||
{
|
||||
if(text.isEmpty())
|
||||
text.append(QObject::tr("Pivoter"));
|
||||
else
|
||||
text.append(QObject::tr(" et"));
|
||||
|
||||
text.append(QObject::tr(" %1 groupes de textes").arg(groups_list.count()));
|
||||
}
|
||||
if(!text.isNull())
|
||||
setText(text);
|
||||
|
||||
QStringList parts;
|
||||
if (texts_list.count())
|
||||
parts << QObject::tr("%n texte(s)", "", texts_list.count());
|
||||
if (groups_list.count())
|
||||
parts << QObject::tr("%n groupe(s) de textes", "", groups_list.count());
|
||||
setText(QObject::tr("Pivoter %1").arg(QLocale().createSeparatedList(parts)));
|
||||
|
||||
for(DiagramTextItem *dti : texts_list)
|
||||
setupAnimation(dti, "rotation", dti->rotation(), m_rotation);
|
||||
for(ElementTextItemGroup *grp : groups_list)
|
||||
@@ -77,7 +69,6 @@ m_diagram(diagram)
|
||||
}
|
||||
else
|
||||
setObsolete(true);
|
||||
|
||||
}
|
||||
|
||||
void RotateTextsCommand::undo()
|
||||
|
||||
Reference in New Issue
Block a user