Files
qelectrotech-source-mirror/sources/ui/diagrambgcolorbutton.cpp
T
Kellermorph 9af562fcbd Remember the sheet background colour between runs
Picking a sheet (folio) background colour in the diagram editor was lost
on every restart. Diagram::background_color is a static initialised to
white and PaletteGraphicsView's s_custom_bg a static bool, and neither
was ever written anywhere -- Diagram::toXml() carries no colour attribute
either -- so closing and reopening a project always came back on the
default and the choice had to be made again.

Store it in QSettings under diagrameditor/sheet_background_* as a pair of
values rather than one: the colour, and whether it was picked explicitly.
Both halves are needed. "#ffffff, follow the system" and "#ffffff, always
white" are the same colour and two behaviours -- the first is what the
views invert on a dark palette -- so keeping only the colour would
silently turn one into the other on the next start, which is the reported
problem one step removed.

The colour is written as HexRgb on purpose. The SVG export gives
Diagram::background_color an alpha of 0 to render a transparent
background and never puts it back, and that transient value must not be
persisted as a permanently transparent sheet.

Applied from main() after the headless export and scripting branch -- those
return before reaching it and must keep rendering on plain white, the rule
ProjectPrintWindow already enforces for printing -- and before QETApp is
constructed, since that constructor already loads the projects given on
the command line. The GUI export dialog is left alone: it renders through
drawBackground(), so what you see is what you export, as it already was
within a session.

Saved at the moment the colour is applied rather than at shutdown, so
neither the print window's temporary white nor the SVG export's alpha can
reach it. The button's constructor now mirrors the stored state instead of
always claiming "system colour", and the "recently used" list is stored
alongside it.

Covered by tst_sheetbackgroundsetting, which pins the custom flag and the
dropped alpha -- the two rules a single stored colour would lose.
2026-09-24 10:30:01 +02:00

282 lines
7.5 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 "diagrambgcolorbutton.h"
#include "../diagram.h"
#include "../diagramview.h"
#include "../palettegraphicsview.h"
#include "../qetdiagrameditor.h"
#include "../projectview.h"
#include "../qetproject.h"
#include "../utils/qetsettings.h"
#include <QApplication>
#include <QColorDialog>
#include <QMenu>
#include <QPainter>
#include <QPixmap>
namespace {
struct NamedColor { const char *context_name; QColor color; };
QList<NamedColor> standardColors()
{
return {
{QT_TRANSLATE_NOOP("DiagramBgColorToolButton", "Blanc"), QColor(0xFF, 0xFF, 0xFF)},
{QT_TRANSLATE_NOOP("DiagramBgColorToolButton", "Blanc cassé"), QColor(0xFD, 0xFB, 0xF5)},
{QT_TRANSLATE_NOOP("DiagramBgColorToolButton", "Gris clair"), QColor(0xE0, 0xE0, 0xE0)},
{QT_TRANSLATE_NOOP("DiagramBgColorToolButton", "Gris"), QColor(0x80, 0x80, 0x80)},
{QT_TRANSLATE_NOOP("DiagramBgColorToolButton", "Gris foncé"), QColor(0x40, 0x40, 0x40)},
{QT_TRANSLATE_NOOP("DiagramBgColorToolButton", "Noir"), QColor(0x00, 0x00, 0x00)},
};
}
const int MAX_RECENT = 6;
}
/**
@brief DiagramBgColorToolButton::DiagramBgColorToolButton
@param editor : the diagram editor this button acts on
@param parent
*/
DiagramBgColorToolButton::DiagramBgColorToolButton(QETDiagramEditor *editor, QWidget *parent) :
QToolButton(parent),
m_editor(editor)
{
setPopupMode(QToolButton::InstantPopup);
setToolTip(tr("Couleur de fond du folio"));
setStatusTip(tr("Choisir la couleur de fond du folio",
"status bar tip"));
//main() already restored the stored choice onto the global
//Diagram::background_color and PaletteGraphicsView flag; mirror it
//here so the button opens on what the editor actually draws, rather
//than always claiming "system colour" as it used to.
if (PaletteGraphicsView::customBackgroundColor()) {
m_is_system_color = false;
m_current = Diagram::background_color;
} else {
m_is_system_color = true;
m_current = QApplication::palette().color(QPalette::Base);
}
for (const QString &name : QetSettings::sheetBackgroundRecentColors())
{
const QColor c(name);
if (c.isValid()) {
m_recent.append(c);
}
}
while (m_recent.size() > MAX_RECENT) {
m_recent.removeLast();
}
setMenu(new QMenu(this));
rebuildMenu();
setSwatch(m_current);
}
/**
@brief DiagramBgColorToolButton::rebuildMenu
*/
void DiagramBgColorToolButton::rebuildMenu()
{
QMenu *m = menu();
m->clear();
QAction *sys = m->addAction(tr("Couleur système"));
connect(sys, &QAction::triggered, this, &DiagramBgColorToolButton::applySystemColor);
m->addSeparator();
for (const auto &nc : standardColors())
{
const QColor c = nc.color;
QAction *a = m->addAction(swatchIcon(c),
tr(nc.context_name));
connect(a, &QAction::triggered, this, [this, c]() { applyColor(c); });
}
if (!m_recent.isEmpty())
{
m->addSeparator();
QAction *title = m->addAction(tr("Récemment utilisées"));
title->setEnabled(false);
for (const QColor &c : std::as_const(m_recent))
{
QAction *a = m->addAction(swatchIcon(c), c.name());
connect(a, &QAction::triggered, this, [this, c]() { applyColor(c); });
}
}
m->addSeparator();
QAction *other = m->addAction(tr("Autre couleur…"));
connect(other, &QAction::triggered, this, &DiagramBgColorToolButton::chooseOtherColor);
}
/**
@brief DiagramBgColorToolButton::applyColor
Set a custom background color on all open diagrams.
@param color
*/
void DiagramBgColorToolButton::applyColor(const QColor &color)
{
if (!color.isValid()) {
return;
}
m_is_system_color = false;
rememberRecent(color);
setSwatch(color);
PaletteGraphicsView::setCustomBackgroundColor(true);
Diagram::background_color = color;
QetSettings::setSheetBackground(QetSettings::SheetBackground{color, true});
QETDiagramEditor *editor = m_editor;
if (!editor) {
return;
}
for (ProjectView *pv : editor->openedProjects())
for (Diagram *d : pv->project()->diagrams())
d->update();
}
/**
@brief DiagramBgColorToolButton::applySystemColor
Restore the system-default background and re-enable dark-mode
inversion.
*/
void DiagramBgColorToolButton::applySystemColor()
{
m_is_system_color = true;
m_current = QApplication::palette().color(QPalette::Base);
setSwatch(m_current);
PaletteGraphicsView::setCustomBackgroundColor(false);
Diagram::background_color = Qt::white;
QetSettings::setSheetBackground(
QetSettings::SheetBackground{QColor(Qt::white), false});
QETDiagramEditor *editor = m_editor;
if (!editor) {
return;
}
for (ProjectView *pv : editor->openedProjects())
for (Diagram *d : pv->project()->diagrams())
d->update();
}
/**
@brief DiagramBgColorToolButton::chooseOtherColor
*/
void DiagramBgColorToolButton::chooseOtherColor()
{
const QColor c = QColorDialog::getColor(m_current, this,
tr("Choisir une couleur de fond"));
if (c.isValid()) {
applyColor(c);
}
}
/**
@brief DiagramBgColorToolButton::rememberRecent
Most recent first, no duplicates, capped.
@param color
*/
void DiagramBgColorToolButton::rememberRecent(const QColor &color)
{
for (const auto &nc : standardColors()) {
if (nc.color == color) {
return;
}
}
m_recent.removeAll(color);
m_recent.prepend(color);
while (m_recent.size() > MAX_RECENT) {
m_recent.removeLast();
}
rebuildMenu();
persistRecent();
}
/**
@brief DiagramBgColorToolButton::persistRecent
Write the "recently used" colours back to the settings, so they are
still there on the next start instead of starting out empty.
*/
void DiagramBgColorToolButton::persistRecent()
{
QStringList names;
for (const QColor &c : std::as_const(m_recent)) {
names << c.name();
}
QetSettings::setSheetBackgroundRecentColors(names);
}
/**
@brief DiagramBgColorToolButton::setSwatch
@param color
*/
void DiagramBgColorToolButton::setSwatch(const QColor &color)
{
m_current = color;
setIcon(swatchIcon(color));
}
/**
@brief DiagramBgColorToolButton::syncFromDiagram
Sync the button swatch to whatever Diagram::background_color is
currently set to. Called when the active folio changes.
*/
void DiagramBgColorToolButton::syncFromDiagram()
{
if (m_is_system_color) {
m_current = QApplication::palette().color(QPalette::Base);
} else {
m_current = Diagram::background_color;
}
setSwatch(m_current);
}
/**
@brief DiagramBgColorToolButton::updateEnabledState
*/
void DiagramBgColorToolButton::updateEnabledState()
{
setEnabled(m_editor && m_editor->currentProjectView());
}
/**
@brief DiagramBgColorToolButton::swatchIcon
@param color
@return a plain square of that colour, outlined so that white and very
light colours are still visible against the toolbar.
*/
QIcon DiagramBgColorToolButton::swatchIcon(const QColor &color)
{
QPixmap pix(16, 16);
pix.fill(Qt::transparent);
QPainter p(&pix);
p.setRenderHint(QPainter::Antialiasing, false);
p.setBrush(color);
p.setPen(QPen(QColor(0x40, 0x40, 0x40), 1));
p.drawRect(0, 0, 15, 15);
p.end();
return QIcon(pix);
}