Loading files
6f2f93adaThis file is pinned to the selected release. Download the original to open it in your design tool.
/*
* 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 "uihelpers.h"
#include "../editorcommandset.h"
#include "slinthelpers.h"
#include <QtCore>
#include <QtGui>
/*******************************************************************************
* Namespace
******************************************************************************/
namespace librepcb {
namespace editor {
/*******************************************************************************
* Non-Member Functions
******************************************************************************/
qint64 s2l(const ui::Int64& v) noexcept {
return (static_cast<int64_t>(v.msb) << 32) | static_cast<uint32_t>(v.lsb);
}
ui::Int64 l2s(const Length& v) noexcept {
return ui::Int64{
static_cast<int>((v.toNm() >> 32) & 0xFFFFFFFF),
static_cast<int>(v.toNm() & 0xFFFFFFFF),
};
}
Length s2length(const ui::Int64& v) noexcept {
return Length(s2l(v));
}
std::optional<UnsignedLength> s2ulength(const ui::Int64& v) noexcept {
const Length l = s2length(v);
return (l >= 0) ? std::make_optional(UnsignedLength(l)) : std::nullopt;
}
std::optional<PositiveLength> s2plength(const ui::Int64& v) noexcept {
const Length l = s2length(v);
return (l > 0) ? std::make_optional(PositiveLength(l)) : std::nullopt;
}
int l2s(const Angle& v) noexcept {
return v.toMicroDeg();
}
Angle s2angle(int v) noexcept {
return Angle(v);
}
int l2s(const Ratio& v) noexcept {
return v.toPpm();
}
Ratio s2ratio(int v) noexcept {
return Ratio(v);
}
ui::Theme l2s(const UiTheme& v) noexcept {
return ui::Theme{
q2s(v.window),
q2s(v.base),
q2s(v.baseBorder),
q2s(v.baseTextDisabled),
q2s(v.baseTextMuted),
q2s(v.baseText),
q2s(v.baseTextHovered),
q2s(v.baseTextInfo),
q2s(v.baseTextSuccess),
q2s(v.baseTextWarning),
q2s(v.baseTextError),
q2s(v.control),
q2s(v.controlDisabled),
q2s(v.controlHovered),
q2s(v.controlChecked),
q2s(v.controlBorder),
q2s(v.controlBorderDisabled),
q2s(v.controlTextDisabled),
q2s(v.controlTextMuted),
q2s(v.controlText),
q2s(v.selection),
q2s(v.selectionText),
q2s(v.tooltip),
q2s(v.tooltipBorder),
q2s(v.tooltipText),
q2s(v.accent),
q2s(v.accentText),
q2s(v.info),
q2s(v.infoText),
q2s(v.warning),
q2s(v.warningText),
q2s(v.error),
q2s(v.errorText),
};
}
ui::GridStyle l2s(GridStyle v) noexcept {
switch (v) {
case GridStyle::Lines:
return ui::GridStyle::Lines;
case GridStyle::Dots:
return ui::GridStyle::Dots;
case GridStyle::None:
return ui::GridStyle::None;
default:
qCritical() << "Unhandled value in GridStyle conversion.";
return ui::GridStyle::None;
}
}
GridStyle s2l(ui::GridStyle v) noexcept {
switch (v) {
case ui::GridStyle::Lines:
return GridStyle::Lines;
case ui::GridStyle::Dots:
return GridStyle::Dots;
case ui::GridStyle::None:
return GridStyle::None;
default:
qCritical() << "Unhandled value in GridStyle conversion.";
return GridStyle::None;
}
}
ui::LengthUnit l2s(const LengthUnit& v) noexcept {
if (v == LengthUnit::millimeters()) {
return ui::LengthUnit::Millimeters;
} else if (v == LengthUnit::micrometers()) {
return ui::LengthUnit::Micrometers;
} else if (v == LengthUnit::nanometers()) {
return ui::LengthUnit::Nanometers;
} else if (v == LengthUnit::inches()) {
return ui::LengthUnit::Inches;
} else if (v == LengthUnit::mils()) {
return ui::LengthUnit::Mils;
} else {
qCritical() << "Unhandled value in LengthUnit conversion.";
return ui::LengthUnit::Millimeters;
}
}
LengthUnit s2l(ui::LengthUnit v) noexcept {
switch (v) {
case ui::LengthUnit::Millimeters:
return LengthUnit::millimeters();
case ui::LengthUnit::Micrometers:
return LengthUnit::micrometers();
case ui::LengthUnit::Nanometers:
return LengthUnit::nanometers();
case ui::LengthUnit::Inches:
return LengthUnit::inches();
case ui::LengthUnit::Mils:
return LengthUnit::mils();
default:
qCritical() << "Unhandled value in LengthUnit conversion.";
return LengthUnit::millimeters();
}
}
slint::cbindgen_private::TextHorizontalAlignment l2s(const HAlign& v) noexcept {
if (v == HAlign::left()) {
return slint::cbindgen_private::TextHorizontalAlignment::Left;
} else if (v == HAlign::right()) {
return slint::cbindgen_private::TextHorizontalAlignment::Right;
} else {
return slint::cbindgen_private::TextHorizontalAlignment::Center;
}
}
HAlign s2l(slint::cbindgen_private::TextHorizontalAlignment v) noexcept {
switch (v) {
case slint::cbindgen_private::TextHorizontalAlignment::Left:
return HAlign::left();
case slint::cbindgen_private::TextHorizontalAlignment::Right:
return HAlign::right();
default:
return HAlign::center();
}
}
slint::cbindgen_private::TextVerticalAlignment l2s(const VAlign& v) noexcept {
if (v == VAlign::top()) {
return slint::cbindgen_private::TextVerticalAlignment::Top;
} else if (v == VAlign::bottom()) {
return slint::cbindgen_private::TextVerticalAlignment::Bottom;
} else {
return slint::cbindgen_private::TextVerticalAlignment::Center;
}
}
VAlign s2l(slint::cbindgen_private::TextVerticalAlignment v) noexcept {
switch (v) {
case slint::cbindgen_private::TextVerticalAlignment::Top:
return VAlign::top();
case slint::cbindgen_private::TextVerticalAlignment::Bottom:
return VAlign::bottom();
default:
return VAlign::center();
}
}
ui::NotificationType l2s(RuleCheckMessage::Severity v) noexcept {
switch (v) {
case RuleCheckMessage::Severity::Hint:
return ui::NotificationType::Info;
case RuleCheckMessage::Severity::Warning:
return ui::NotificationType::Warning;
case RuleCheckMessage::Severity::Error:
return ui::NotificationType::Critical;
default:
qCritical()
<< "Unhandled value in RuleCheckMessage::Severity conversion.";
return ui::NotificationType::Critical;
}
}
static const std::vector<Package::AssemblyType>& getAssemblyTypes() noexcept {
static const std::vector<Package::AssemblyType> list = {
// ATTENTION: Keep in sync with constants.slint!
Package::AssemblyType::Tht, // clang-format break
Package::AssemblyType::Smt, // clang-format break
Package::AssemblyType::Mixed, // clang-format break
Package::AssemblyType::Other, // clang-format break
Package::AssemblyType::None, // clang-format break
Package::AssemblyType::Auto, // clang-format break
};
return list;
}
int l2s(Package::AssemblyType v) noexcept {
const auto& list = getAssemblyTypes();
const auto it = std::find(list.begin(), list.end(), v);
if (it == list.end()) {
qCritical() << "Unhandled value in Package::AssemblyType conversion.";
return -1;
}
return it - list.begin();
}
std::optional<Package::AssemblyType> s2assemblyType(int v) noexcept {
const auto& list = getAssemblyTypes();
if ((v >= 0) && (v < static_cast<int>(list.size()))) {
return list.at(v);
} else {
qCritical() << "Unhandled value in Package::AssemblyType conversion.";
return std::nullopt;
}
}
ui::ComponentPinoutDisplayMode l2s(const CmpSigPinDisplayType& v) noexcept {
if (v == CmpSigPinDisplayType::none()) {
return ui::ComponentPinoutDisplayMode::None;
} else if (v == CmpSigPinDisplayType::pinName()) {
return ui::ComponentPinoutDisplayMode::PinName;
} else if (v == CmpSigPinDisplayType::componentSignal()) {
return ui::ComponentPinoutDisplayMode::SignalName;
} else if (v == CmpSigPinDisplayType::netSignal()) {
return ui::ComponentPinoutDisplayMode::NetName;
} else {
qCritical() << "Unhandled value in CmpSigPinDisplayType conversion.";
return ui::ComponentPinoutDisplayMode::SignalName;
}
}
const CmpSigPinDisplayType& s2l(ui::ComponentPinoutDisplayMode v) noexcept {
switch (v) {
case ui::ComponentPinoutDisplayMode::None:
return CmpSigPinDisplayType::none();
case ui::ComponentPinoutDisplayMode::PinName:
return CmpSigPinDisplayType::pinName();
case ui::ComponentPinoutDisplayMode::SignalName:
return CmpSigPinDisplayType::componentSignal();
case ui::ComponentPinoutDisplayMode::NetName:
return CmpSigPinDisplayType::netSignal();
default:
qCritical() << "Unhandled value in CmpSigPinDisplayType conversion.";
return CmpSigPinDisplayType::componentSignal();
}
}
ui::EditorCommand l2s(const EditorCommand& cmd, ui::EditorCommand in) noexcept {
QString text = cmd.getDisplayText();
if (cmd.getFlags().testFlag(EditorCommand::Flag::OpensPopup)) {
text += "...";
}
in.text = q2s(text);
in.status_tip = q2s(cmd.getDescription());
const QKeySequence shortcut = cmd.getKeySequences().value(0);
if (shortcut.count() == 1) {
in.shortcut = q2s(shortcut.toString());
in.modifiers = q2s(shortcut[0].keyboardModifiers());
in.key = q2s(shortcut[0].key());
if (in.modifiers.shift && (in.key.size() == 1) &&
std::isalpha(in.key.data()[0])) {
in.key = in.key.to_uppercase();
}
} else {
// Multi-combination shortcuts are not supported yet.
in.shortcut = slint::SharedString();
in.modifiers = slint::private_api::KeyboardModifiers{};
in.key = slint::SharedString();
}
return in;
}
static bool isKeySequence(const slint::private_api::KeyEvent& e,
const QKeySequence& seq) {
// Compare the pressed key (e.g. 'r').
if (e.text.to_lowercase() != q2s(seq[0].key())) {
return false;
}
// Compare the modifiers. For special key characters, allow an additional
// SHIFT modifier as this migh be required on some keyboard layouts. See
// discussion in https://github.com/LibrePCB/LibrePCB/issues/1641.
static QString specialChars = "+-*/.,:;_[]=@#%&()?!{}<>|";
const slint::private_api::KeyboardModifiers seqMod =
q2s(seq[0].keyboardModifiers());
return (e.modifiers == seqMod) ||
((seqMod.shift == false) && //
(e.modifiers.shift == true) && //
(e.modifiers.alt == seqMod.alt) && //
(e.modifiers.control == seqMod.control) && //
(e.modifiers.meta == seqMod.meta) && //
(specialChars.contains(s2q(e.text))));
}
bool isShortcut(const slint::private_api::KeyEvent& e,
const ui::EditorCommand& cmd) noexcept {
// On the first call, build a hash table of all commands for fast lookup.
auto hashCmd = []() {
QHash<slint::SharedString, const EditorCommand*> map;
EditorCommandSet& cmd = EditorCommandSet::instance();
foreach (const EditorCommandCategory* category, cmd.getCategories()) {
foreach (const EditorCommand* command, cmd.getCommands(category)) {
map.insert(q2s(command->getIdentifier()), command);
}
}
return map;
};
static const QHash<slint::SharedString, const EditorCommand*> map = hashCmd();
// Find the command with the corresponding keyboard shortcut.
if (const EditorCommand* c = map.value(cmd.id)) {
for (const QKeySequence& seq : c->getDefaultKeySequences()) {
if (isKeySequence(e, seq)) {
return true;
}
}
}
return false;
}
ui::FeatureState toFs(bool enabled) noexcept {
return enabled ? ui::FeatureState::Enabled : ui::FeatureState::Disabled;
}
/*******************************************************************************
* End of File
******************************************************************************/
} // namespace editor
} // namespace librepcb