Loading files
/*
* LibrePCB - Professional EDA for everyone!
* Copyright (C) 2013 LibrePCB Developers, see AUTHORS.md for contributors.
* https://librepcb.org/
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*******************************************************************************
* Includes
******************************************************************************/
#include "keysequenceseditorwidget.h"
#include "../utils/editortoolbox.h"
#include <QtCore>
#include <QtWidgets>
/*******************************************************************************
* Namespace
******************************************************************************/
namespace librepcb {
namespace editor {
/*******************************************************************************
* Constructors / Destructor
******************************************************************************/
KeySequencesEditorWidget::KeySequencesEditorWidget(
const QList<QKeySequence>& defaultSequences, QWidget* parent) noexcept
: QWidget(parent),
mLayout(new QVBoxLayout()),
mDefault(defaultSequences),
mOverrides(),
mRowHeight(25) {
mLayout->setContentsMargins(0, 0, 0, 0);
mLayout->setSpacing(0);
setLayout(mLayout);
}
KeySequencesEditorWidget::~KeySequencesEditorWidget() noexcept {
}
/*******************************************************************************
* General Methods
******************************************************************************/
void KeySequencesEditorWidget::setOverrides(
const std::optional<QList<QKeySequence> >& overrides) noexcept {
mOverrides = overrides;
updateWidgets();
}
void KeySequencesEditorWidget::setRowHeight(int height) noexcept {
foreach (QKeySequenceEdit* edt, findChildren<QKeySequenceEdit*>()) {
edt->setFixedHeight(height);
}
foreach (QToolButton* btn, findChildren<QToolButton*>()) {
btn->setFixedHeight(height);
if (btn->sizePolicy().horizontalPolicy() == QSizePolicy::Fixed) {
btn->setFixedWidth(height);
}
btn->setIconSize(QSize(height, height) * 0.8);
}
mRowHeight = height;
}
/*******************************************************************************
* Private Methods
******************************************************************************/
void KeySequencesEditorWidget::updateWidgets() noexcept {
setFocusProxy(nullptr);
while (mLayout->count() > 0) {
QLayoutItem* item = mLayout->takeAt(0);
Q_ASSERT(item);
EditorToolbox::deleteLayoutItemRecursively(item);
}
QList<QKeySequence> sequences = mOverrides ? (*mOverrides) : mDefault;
for (int i = 0; i <= sequences.count(); ++i) {
QHBoxLayout* hLayout = new QHBoxLayout();
hLayout->setContentsMargins(0, 0, 0, 0);
hLayout->setSpacing(0);
QKeySequenceEdit* edit = new QKeySequenceEdit(this);
edit->setKeySequence(sequences.value(i));
if (i == 0) {
// When opening this widget, move focus into first edit field.
setFocusProxy(edit);
}
connect(edit, &QKeySequenceEdit::editingFinished, edit, [this, edit, i]() {
bool modified = false;
if (!mOverrides) {
modified = true;
mOverrides = mDefault;
}
const bool exists = (i < mOverrides->count());
const bool valid = !edit->keySequence().isEmpty();
if (valid && exists) {
modified = modified || (mOverrides->value(i) != edit->keySequence());
mOverrides->replace(i, edit->keySequence());
} else if (exists) {
modified = true;
mOverrides->removeAt(i);
} else if (valid) {
modified = true;
mOverrides->append(edit->keySequence());
}
// To avoid focus issues, only refresh the list if it has been modified.
if (modified) {
scheduleUpdateWidgets();
}
});
hLayout->addWidget(edit);
if (i < sequences.count()) {
QToolButton* btnClear = new QToolButton(this);
btnClear->setToolTip(tr("Remove this shortcut"));
btnClear->setIcon(QIcon(":/img/actions/delete.png"));
connect(btnClear, &QToolButton::clicked, this, [this, i]() {
if (!mOverrides) {
mOverrides = mDefault;
}
mOverrides->removeAt(i);
scheduleUpdateWidgets();
});
hLayout->addWidget(btnClear);
} else {
QToolButton* btnReset = new QToolButton(this);
btnReset->setToolTip(tr("Restore default shortcut(s)"));
btnReset->setIcon(QIcon(":/img/actions/undo.png"));
btnReset->setEnabled(mOverrides.has_value());
connect(btnReset, &QToolButton::clicked, this, [this]() {
mOverrides = std::nullopt;
scheduleUpdateWidgets();
});
hLayout->addWidget(btnReset);
}
mLayout->addLayout(hLayout);
}
QHBoxLayout* hLayout = new QHBoxLayout();
hLayout->setContentsMargins(0, 0, 0, 0);
hLayout->setSpacing(0);
QToolButton* btnApply = new QToolButton(this);
btnApply->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
btnApply->setToolTip(tr("Apply"));
btnApply->setIcon(QIcon(":/img/actions/apply.png"));
connect(btnApply, &QToolButton::clicked, this,
&KeySequencesEditorWidget::applyTriggered);
hLayout->addWidget(btnApply);
QToolButton* btnCancel = new QToolButton(this);
btnCancel->setToolTip(tr("Cancel"));
btnCancel->setIcon(QIcon(":/img/actions/cancel.png"));
connect(btnCancel, &QToolButton::clicked, this,
&KeySequencesEditorWidget::cancelTriggered);
hLayout->addWidget(btnCancel);
mLayout->addLayout(hLayout);
setFixedHeight(mRowHeight * (sequences.count() + 2));
setRowHeight(mRowHeight);
}
void KeySequencesEditorWidget::scheduleUpdateWidgets() noexcept {
// Helper to call updateWidgets() without ending up in a recursion which
// causes widgets to be deleted in their signal handler. Fixes
// https://github.com/LibrePCB/LibrePCB/issues/1643.
QMetaObject::invokeMethod(this, &KeySequencesEditorWidget::updateWidgets,
Qt::QueuedConnection);
}
/*******************************************************************************
* End of File
******************************************************************************/
} // namespace editor
} // namespace librepcb
94ec4b8feThis file is pinned to the selected release. Download the original to open it in your design tool.