Merge branch 'master' into feature-3dmouse-spnav

This commit is contained in:
Laurent Trinques
2026-09-24 15:45:33 +02:00
committed by GitHub
123 changed files with 135169 additions and 688 deletions
+14 -2
View File
@@ -31,6 +31,7 @@
#include <QMenu>
#include <QPainter>
#include <QPixmap>
#include <QSet>
namespace {
/**
@@ -167,11 +168,22 @@ void ConductorColorToolButton::applyColor(const QColor &color)
}
DiagramContent dc(diagram);
const auto conductors = dc.conductors(DiagramContent::AnyConductor);
if (conductors.isEmpty()) {
const auto selected_conductors = dc.conductors(DiagramContent::AnyConductor);
if (selected_conductors.isEmpty()) {
return;
}
//A wire drawn across a junction is several Conductor objects
//sharing one electrical potential; selecting one segment must
//still recolour the whole potential, the way the F2 dialog's
//"apply to all" already does.
QSet<Conductor *> conductors;
for (Conductor *conductor : selected_conductors)
{
conductors << conductor;
conductors += conductor->relatedPotentialConductors();
}
QUndoCommand *undo = new QUndoCommand(tr("Modifier la couleur de %n conducteur(s)",
"undo caption", conductors.count()));
int changed = 0;
@@ -23,6 +23,7 @@
#include "../../utils/qetsettings.h"
#include "../../utils/qetutils.h"
#include "../../qetmessagebox.h"
#include "../nokde/kcolorbutton.h"
#include <QFileDialog>
#include <QFontDialog>
#include <QSettings>
@@ -74,6 +75,12 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) :
ui->DiagramEditor_Grid_PointSize_min_sb->setValue(settings.value("diagrameditor/grid_pointsize_min", 1).toInt());
ui->DiagramEditor_Grid_PointSize_max_sb->setValue(settings.value("diagrameditor/grid_pointsize_max", 1).toInt());
ui->m_use_system_color_cb->setChecked(settings.value("usesystemcolors", "true").toBool());
bool sysColors = ui->m_use_system_color_cb->isChecked();
ui->m_custom_app_color_kpb->setEnabled(!sysColors);
if (settings.contains("customapplicationcolor"))
ui->m_custom_app_color_kpb->setColor(QColor(settings.value("customapplicationcolor").toString()));
else
ui->m_custom_app_color_kpb->setColor(QApplication::palette().color(QPalette::Window));
bool tabbed = settings.value("diagrameditor/viewmode", "tabbed") == "tabbed";
if(tabbed)
ui->m_use_tab_mode_rb->setChecked(true);
@@ -82,6 +89,25 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) :
ui->m_zoom_out_beyond_folio->setChecked(settings.value("diagrameditor/zoom-out-beyond-of-folio", false).toBool());
ui->m_use_gesture_trackpad->setChecked(settings.value("diagramview/gestures", false).toBool());
ui->m_save_label_paste->setChecked(settings.value("diagramcommands/erase-label-on-copy", true).toBool());
ui->m_enable_scripting->setChecked(QetSettings::scriptingEnabled());
#ifdef QET_HAS_SCRIPTING
if (QetSettings::scriptingForcedByEnvironment()) {
//QET_ENABLE_SCRIPTING wins over the stored value, so let the box
//say so rather than offer a tick that changes nothing.
ui->m_enable_scripting->setEnabled(false);
ui->m_enable_scripting->setToolTip(
tr("Activé par la variable d'environnement "
"QET_ENABLE_SCRIPTING ; ce réglage est sans effet "
"tant qu'elle est définie."));
}
#else
//Built without Qt Qml: there is no scripting to allow. Disabled as
//well as hidden, so applyConf() leaves the stored value alone --
//a hidden box still reports its state, and writing it here would
//quietly clear a preference set on a build that does have Qml.
ui->m_enable_scripting->setVisible(false);
ui->m_enable_scripting->setEnabled(false);
#endif
ui->m_use_folio_label->setChecked(settings.value("genericpanel/folio", true).toBool());
ui->m_border_0->setChecked(settings.value("border-columns_0", false).toBool());
ui->m_autosave_sb->setValue(settings.value("diagrameditor/autosave-interval", 0).toInt());
@@ -206,7 +232,17 @@ void GeneralConfigurationPage::applyConf()
bool must_use_system_colors = ui->m_use_system_color_cb->isChecked();
settings.setValue("usesystemcolors", must_use_system_colors);
if (was_using_system_colors != must_use_system_colors) {
QETApp::instance()->useSystemPalette(must_use_system_colors);
if (must_use_system_colors) {
QETApp::instance()->useSystemPalette(true);
} else {
QColor custom_color = ui->m_custom_app_color_kpb->color();
settings.setValue("customapplicationcolor", custom_color.name());
QETApp::instance()->useCustomPalette(custom_color);
}
} else if (!must_use_system_colors) {
QColor custom_color = ui->m_custom_app_color_kpb->color();
settings.setValue("customapplicationcolor", custom_color.name());
QETApp::instance()->useCustomPalette(custom_color);
}
settings.setValue("border-columns_0",ui->m_border_0->isChecked());
settings.setValue("lang", ui->m_lang_cb->itemData(ui->m_lang_cb->currentIndex()).toString());
@@ -227,6 +263,14 @@ void GeneralConfigurationPage::applyConf()
//DIAGRAM COMMAND
settings.setValue("diagramcommands/erase-label-on-copy", ui->m_save_label_paste->isChecked());
//SCRIPTING
//Left alone while the environment forces it on: the box is disabled
//in that case and writing its state would silently clear the user's
//real preference the first time this dialog is accepted.
if (ui->m_enable_scripting->isEnabled()) {
QetSettings::setScriptingEnabled(ui->m_enable_scripting->isChecked());
}
//GENERIC PANEL
settings.setValue("genericpanel/folio",ui->m_use_folio_label->isChecked());
@@ -625,3 +669,14 @@ void GeneralConfigurationPage::on_m_hdpi_round_cb_clicked(bool checked)
ui->m_hdpi_round_policy_cb->setEnabled(checked);
}
/**
@brief GeneralConfigurationPage::on_m_use_system_color_cb_toggled
Enable/disable the custom color picker when the system color
checkbox is toggled.
@param checked
*/
void GeneralConfigurationPage::on_m_use_system_color_cb_toggled(bool checked)
{
ui->m_custom_app_color_kpb->setEnabled(!checked);
}
@@ -53,6 +53,7 @@ class GeneralConfigurationPage : public ConfigPage
void on_ElementEditor_Grid_PointSize_min_sb_valueChanged(int value);
void on_m_hdpi_round_cb_clicked(bool checked);
void on_m_use_system_color_cb_toggled(bool checked);
private:
void fillLang();
@@ -23,15 +23,26 @@
<attribute name="title">
<string>Apparence</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="m_use_system_color_cb">
<property name="text">
<string>Utiliser les couleurs du système</string>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="m_system_color_layout">
<item>
<widget class="QCheckBox" name="m_use_system_color_cb">
<property name="text">
<string>Utiliser les couleurs du système</string>
</property>
</widget>
</item>
<item>
<widget class="KColorButton" name="m_custom_app_color_kpb">
<property name="toolTip">
<string>Couleur de l'application</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -207,6 +218,16 @@
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="m_enable_scripting">
<property name="text">
<string>Autoriser l'exécution de scripts JavaScript (Projet &gt; Exécuter un script, et --run)</string>
</property>
<property name="toolTip">
<string>Un script s'exécute avec vos droits : il peut lire et modifier le projet ouvert et écrire des fichiers. Désactivé par défaut ; n'exécutez que des scripts dont vous connaissez l'origine.</string>
</property>
</widget>
</item>
<item row="5" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -1161,4 +1182,11 @@ Vous pouvez spécifier ici la valeur par défaut de ce champ pour les éléments
</tabstops>
<resources/>
<connections/>
<customwidgets>
<customwidget>
<class>KColorButton</class>
<extends>QPushButton</extends>
<header>nokde/kcolorbutton.h</header>
</customwidget>
</customwidgets>
</ui>
+41 -2
View File
@@ -23,6 +23,7 @@
#include "../qetdiagrameditor.h"
#include "../projectview.h"
#include "../qetproject.h"
#include "../utils/qetsettings.h"
#include <QApplication>
#include <QColorDialog>
@@ -62,8 +63,28 @@ DiagramBgColorToolButton::DiagramBgColorToolButton(QETDiagramEditor *editor, QWi
setStatusTip(tr("Choisir la couleur de fond du folio",
"status bar tip"));
m_is_system_color = true;
m_current = QApplication::palette().color(QPalette::Base);
//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);
@@ -123,6 +144,7 @@ void DiagramBgColorToolButton::applyColor(const QColor &color)
PaletteGraphicsView::setCustomBackgroundColor(true);
Diagram::background_color = color;
QetSettings::setSheetBackground(QetSettings::SheetBackground{color, true});
QETDiagramEditor *editor = m_editor;
if (!editor) {
@@ -146,6 +168,8 @@ void DiagramBgColorToolButton::applySystemColor()
PaletteGraphicsView::setCustomBackgroundColor(false);
Diagram::background_color = Qt::white;
QetSettings::setSheetBackground(
QetSettings::SheetBackground{QColor(Qt::white), false});
QETDiagramEditor *editor = m_editor;
if (!editor) {
@@ -187,6 +211,21 @@ void DiagramBgColorToolButton::rememberRecent(const QColor &color)
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);
}
/**
+1
View File
@@ -52,6 +52,7 @@ class DiagramBgColorToolButton : public QToolButton
void applySystemColor();
void chooseOtherColor();
void rememberRecent(const QColor &color);
void persistRecent();
void setSwatch(const QColor &color);
static QIcon swatchIcon(const QColor &color);
+114
View File
@@ -0,0 +1,114 @@
/*
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 "duplicateoffsetdialog.h"
#include <QComboBox>
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QSettings>
#include <QSpinBox>
#include <QVBoxLayout>
namespace {
// Stored as one integer per axis, in grid steps -- not pixels, so the
// remembered offset still makes sense if the grid size ever changes.
const QString kOffsetXKey = QStringLiteral("diagrameditor/duplicate_offset_x");
const QString kOffsetYKey = QStringLiteral("diagrameditor/duplicate_offset_y");
}
DuplicateOffsetDialog::DuplicateOffsetDialog(QWidget *parent) :
QDialog(parent)
{
setWindowTitle(tr("Dupliquer"));
auto *form = new QFormLayout;
m_spacing = new QSpinBox(this);
m_spacing->setRange(1, 1000);
m_spacing->setSuffix(tr(" pas de grille"));
form->addRow(tr("Espacement :"), m_spacing);
m_direction = new QComboBox(this);
// Order matches the Direction enum, so currentIndex() can be used
// directly wherever Direction is needed.
m_direction->addItem(tr("Haut"));
m_direction->addItem(tr("Bas"));
m_direction->addItem(tr("Gauche"));
m_direction->addItem(tr("Droite"));
form->addRow(tr("Direction :"), m_direction);
const QPoint saved = savedStepOffset();
// The saved value is a signed (dx, dy) pair, not itself a
// spacing+direction pair, so it has to be decomposed back into the
// two the dialog shows. Exactly one axis is ever non-zero (see
// stepOffset()), so whichever one is picks the direction; a value
// that somehow has neither (only possible if QSettings was hand-
// edited) falls back to the same default stepOffset() would.
int spacing = 1;
Direction direction = Right;
if (saved.x() > 0) { direction = Right; spacing = saved.x(); }
else if (saved.x() < 0) { direction = Left; spacing = -saved.x(); }
else if (saved.y() > 0) { direction = Down; spacing = saved.y(); }
else if (saved.y() < 0) { direction = Up; spacing = -saved.y(); }
m_spacing->setValue(spacing);
m_direction->setCurrentIndex(static_cast<int>(direction));
auto *buttons = new QDialogButtonBox(
QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
auto *layout = new QVBoxLayout(this);
layout->addLayout(form);
layout->addWidget(buttons);
}
QPoint DuplicateOffsetDialog::stepOffset() const
{
const int spacing = m_spacing->value();
switch (static_cast<Direction>(m_direction->currentIndex())) {
case Up: return QPoint(0, -spacing);
case Down: return QPoint(0, spacing);
case Left: return QPoint(-spacing, 0);
case Right: return QPoint(spacing, 0);
}
return QPoint(spacing, 0); // unreachable; keeps -Wreturn-type quiet
}
QPoint DuplicateOffsetDialog::savedStepOffset()
{
QSettings settings;
if (!hasSavedStepOffset()) {
return QPoint(1, 0); // default: one grid step to the right
}
return QPoint(settings.value(kOffsetXKey).toInt(),
settings.value(kOffsetYKey).toInt());
}
void DuplicateOffsetDialog::saveStepOffset(const QPoint &steps)
{
QSettings settings;
settings.setValue(kOffsetXKey, steps.x());
settings.setValue(kOffsetYKey, steps.y());
}
bool DuplicateOffsetDialog::hasSavedStepOffset()
{
QSettings settings;
return settings.contains(kOffsetXKey) && settings.contains(kOffsetYKey);
}
+65
View File
@@ -0,0 +1,65 @@
/*
Copyright 2006-2026 The QElectroTech Team
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
QElectroTech is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DUPLICATEOFFSETDIALOG_H
#define DUPLICATEOFFSETDIALOG_H
#include <QDialog>
#include <QPoint>
class QSpinBox;
class QComboBox;
/**
@brief The DuplicateOffsetDialog class
Asks how far, and in which of the four cardinal directions, Ctrl+D
(DiagramView::duplicate(), bugtracker #991) should offset a copy from
its source. Shown once, then remembered: the answer is stored in
QSettings and reused by every later Ctrl+D press without asking
again, until this dialog is reopened deliberately.
*/
class DuplicateOffsetDialog : public QDialog
{
Q_OBJECT
public:
enum Direction { Up, Down, Left, Right };
explicit DuplicateOffsetDialog(QWidget *parent = nullptr);
/// The offset in grid steps, positive along X to the right
/// and positive along Y downward -- QET's own scene axes,
/// matching the sign convention setPos() already uses
/// everywhere else in this codebase.
QPoint stepOffset() const;
/// Reads the last-confirmed spacing/direction from QSettings,
/// or the default (1 step, right) if none was ever set.
static QPoint savedStepOffset();
/// Writes @p steps to QSettings, in the same X/Y convention
/// as stepOffset().
static void saveStepOffset(const QPoint &steps);
/// Whether a direction/spacing has already been confirmed
/// once, i.e. whether Ctrl+D can skip the dialog.
static bool hasSavedStepOffset();
private:
QSpinBox *m_spacing = nullptr;
QComboBox *m_direction = nullptr;
};
#endif // DUPLICATEOFFSETDIALOG_H
+4 -3
View File
@@ -16,6 +16,7 @@
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "elementinfowidget.h"
#include "../qet.h"
#include <QCheckBox>
#include <QPushButton>
#include "../diagram.h"
@@ -366,18 +367,18 @@ void ElementInfoWidget::updateUi()
// Load the lock status for auto numbering
if (m_element->elementData().m_type == ElementData::Terminal) {
QString lock_value = element_info.value(QStringLiteral("auto_num_locked")).toString();
ui->m_auto_num_locked_cb->setChecked(lock_value == QLatin1String("true"));
ui->m_auto_num_locked_cb->setChecked(QET::infoFlagIsTrue(lock_value));
// English: Load the potential isolating status from the element information mapping
if (m_potential_isolating_cb) {
QString isolating_value = element_info.value(QStringLiteral("potential_isolating")).toString();
m_potential_isolating_cb->setChecked(isolating_value == QLatin1String("true"));
m_potential_isolating_cb->setChecked(QET::infoFlagIsTrue(isolating_value));
}
}
// English: Load the BOM exclusion status from the element information mapping
if (m_exclude_from_bom_cb) {
QString exclude_bom_value = element_info.value(QStringLiteral("exclude_from_bom")).toString();
m_exclude_from_bom_cb->setChecked(exclude_bom_value == QLatin1String("true"));
m_exclude_from_bom_cb->setChecked(QET::infoFlagIsTrue(exclude_bom_value));
}
if (m_live_edit) {
+29 -1
View File
@@ -539,7 +539,35 @@ void MasterPropertiesWidget::updateUi()
tr("Type"), tr("Adresse"), tr("Fonction"),
tr("Commentaire"), tr("Réf. croisée"), tr("Bornes")
});
m_plc_table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
m_plc_table->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
m_plc_table->horizontalHeader()->setSectionsMovable(true);
m_plc_table->horizontalHeader()->resizeSection(0, 120);
m_plc_table->horizontalHeader()->resizeSection(1, 100);
m_plc_table->horizontalHeader()->resizeSection(2, 150);
m_plc_table->horizontalHeader()->resizeSection(3, 150);
m_plc_table->horizontalHeader()->resizeSection(4, 100);
m_plc_table->horizontalHeader()->resizeSection(5, 120);
// Restore a previously saved column layout, if any
auto *plc_hdr = m_plc_table->horizontalHeader();
QSettings plc_settings;
const QVariant plc_hdr_state = plc_settings.value(
QStringLiteral("masterpropertieswidget/plc-table-header-state"));
if (!plc_hdr_state.isNull())
plc_hdr->restoreState(plc_hdr_state.toByteArray());
// Persist the column layout whenever the user resizes or moves a column
auto save_plc_header_state = [plc_hdr]()
{
QSettings settings;
settings.setValue(QStringLiteral("masterpropertieswidget/plc-table-header-state"),
plc_hdr->saveState());
};
connect(plc_hdr, &QHeaderView::sectionResized,
this, save_plc_header_state);
connect(plc_hdr, &QHeaderView::sectionMoved,
this, save_plc_header_state);
m_plc_table->setSelectionBehavior(QAbstractItemView::SelectItems);
m_plc_table->setSelectionMode(QAbstractItemView::ExtendedSelection);
m_plc_table->setMinimumHeight(200);
+3 -2
View File
@@ -1,5 +1,6 @@
#include "terminalnumberingdialog.h"
#include "ui_terminalnumberingdialog.h"
#include "../qet.h"
#include "../qetproject.h"
#include "../diagram.h"
#include "../qetgraphicsitem/element.h"
@@ -34,7 +35,7 @@ TerminalNumberingDialog::TerminalNumberingDialog(QWidget *parent, QETProject *pr
if (elmt->elementData().m_type == ElementData::Terminal) {
// Ignore locked terminals
DiagramContext info = elmt->elementInformations();
if (info.value(QStringLiteral("auto_num_locked")).toString() == QLatin1String("true")) {
if (QET::infoFlagIsTrue(info.value(QStringLiteral("auto_num_locked")).toString())) {
continue;
}
@@ -158,7 +159,7 @@ QUndoCommand* TerminalNumberingDialog::getUndoCommand(QETProject *project) const
DiagramContext info = elmt->elementInformations();
// Ignore locked terminals (if the user checked a 'lock' property)
if (info.value(QStringLiteral("auto_num_locked")).toString() == QLatin1String("true")) {
if (QET::infoFlagIsTrue(info.value(QStringLiteral("auto_num_locked")).toString())) {
continue;
}