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 "slinthelpers.h"
#include <QtCore>
#include <QtGui>
/*******************************************************************************
* Namespace
******************************************************************************/
namespace librepcb {
namespace editor {
/*******************************************************************************
* Class SlintTranslator
******************************************************************************/
// This is quite ugly, but it seems to work o_o
slint::SharedString SlintTranslator::translate(std::string_view string,
std::string_view context) const {
setContext(context);
setString(string);
mStringBuffer =
QCoreApplication::translate(mContextBuffer.c_str(), mStringBuffer.data())
.toUtf8();
return convertStringToSlint();
}
slint::SharedString SlintTranslator::ntranslate(
uint64_t n, std::string_view singular, std::string_view plural,
std::string_view context) const {
Q_UNUSED(singular);
setContext(context);
setString(plural);
mStringBuffer.replace("{n}", "%n");
mStringBuffer = QCoreApplication::translate(mContextBuffer.c_str(),
mStringBuffer.data(), nullptr, n)
.toUtf8();
mStringBuffer.replace("%n", "{n}");
return convertStringToSlint();
}
void SlintTranslator::setContext(std::string_view context) const noexcept {
mContextBuffer = "ui::";
mContextBuffer.append(context);
}
void SlintTranslator::setString(std::string_view string) const noexcept {
mStringBuffer.setRawData(string.data(), string.size());
auto buildPlaceholder = [this](int i) -> const QByteArray& {
mPlaceholderBuffer = buildSlintPlaceholder(i);
return mPlaceholderBuffer;
};
for (int i = 0; mStringBuffer.contains(buildPlaceholder(i)); ++i) {
mStringBuffer.replace(mPlaceholderBuffer, buildQtPlaceholder(i + 1));
}
for (int i = 1; mStringBuffer.contains("{}"); ++i) {
mStringBuffer.replace(mStringBuffer.indexOf("{}"), 2,
"%" + QByteArray::number(i));
}
}
slint::SharedString SlintTranslator::convertStringToSlint() const noexcept {
auto buildPlaceholder = [this](int i) -> const QByteArray& {
mPlaceholderBuffer = buildQtPlaceholder(i);
return mPlaceholderBuffer;
};
for (int i = 1; mStringBuffer.contains(buildPlaceholder(i)); ++i) {
mStringBuffer.replace(mPlaceholderBuffer, buildSlintPlaceholder(i - 1));
}
return slint::SharedString(std::string_view(mStringBuffer));
}
QByteArray SlintTranslator::buildSlintPlaceholder(int i) noexcept {
return "{" + QByteArray::number(i) + "}";
}
QByteArray SlintTranslator::buildQtPlaceholder(int i) noexcept {
return "%" + QByteArray::number(i);
}
/*******************************************************************************
* Non-Member Functions
******************************************************************************/
slint::LogicalPosition q2s(const QPointF& p) noexcept {
return slint::LogicalPosition(
{static_cast<float>(p.x()), static_cast<float>(p.y())});
}
QPointF s2q(const slint::LogicalPosition& p) noexcept {
return QPointF(p.x, p.y);
}
slint::PhysicalPosition q2s(const QPoint& p) noexcept {
return slint::PhysicalPosition({p.x(), p.y()});
}
QPoint s2q(const slint::PhysicalPosition& p) noexcept {
return QPoint(p.x, p.y);
}
slint::PhysicalSize q2s(const QSize& s) noexcept {
return slint::PhysicalSize({static_cast<uint32_t>(std::max(s.width(), 0)),
static_cast<uint32_t>(std::max(s.height(), 0))});
}
QSize s2q(const slint::PhysicalSize& s) noexcept {
return QSize(s.width, s.height);
}
slint::SharedString q2s(const QString& s) noexcept {
return slint::SharedString(s.toUtf8().data());
}
QString s2q(const slint::SharedString& s) noexcept {
std::string_view view(s);
return QString::fromUtf8(view.data(), view.size());
}
std::shared_ptr<slint::VectorModel<slint::SharedString>> q2s(
const QStringList& s) noexcept {
auto m = std::make_shared<slint::VectorModel<slint::SharedString>>();
for (const QString& item : s) {
m->push_back(q2s(item));
}
return m;
}
QStringList s2q(const slint::Model<slint::SharedString>& s) noexcept {
QStringList list;
for (std::size_t i = 0; i < s.row_count(); ++i) {
if (auto item = s.row_data(i)) {
list.append(s2q(*item));
}
}
return list;
}
bool operator==(const QString& s1, const slint::SharedString& s2) noexcept {
return s1.toUtf8().data() == std::string_view(s2);
}
bool operator!=(const QString& s1, const slint::SharedString& s2) noexcept {
return s1.toUtf8().data() != std::string_view(s2);
}
bool operator==(const slint::SharedString& s1, const QString& s2) noexcept {
return std::string_view(s1) == s2.toUtf8().data();
}
bool operator!=(const slint::SharedString& s1, const QString& s2) noexcept {
return std::string_view(s1) != s2.toUtf8().data();
}
slint::Image q2s(const QPixmap& p) noexcept {
if (p.isNull()) {
return slint::Image();
}
return q2s(p.toImage());
}
slint::Image q2s(QImage img) noexcept {
img.convertTo(QImage::Format_RGBA8888);
return slint::Image(slint::SharedPixelBuffer<slint::Rgba8Pixel>(
img.width(), img.height(),
reinterpret_cast<const slint::Rgba8Pixel*>(img.constBits())));
}
QImage s2image(const slint::Image& img) noexcept {
if (auto data = img.to_rgba8()) {
return QImage(reinterpret_cast<const uchar*>(data->begin()), data->width(),
data->height(), QImage::Format_RGBA8888);
} else {
qWarning() << "Unsupported slint::Image format.";
return QImage();
}
}
slint::Color q2s(const QColor& c) noexcept {
return slint::Color::from_argb_uint8(c.alpha(), c.red(), c.green(), c.blue());
}
slint::private_api::MouseCursor q2s(Qt::CursorShape s) noexcept {
switch (s) {
case Qt::ArrowCursor:
return slint::private_api::MouseCursor::Default;
case Qt::PointingHandCursor:
return slint::private_api::MouseCursor::Pointer;
case Qt::CrossCursor:
return slint::private_api::MouseCursor::Crosshair;
case Qt::ClosedHandCursor:
return slint::private_api::MouseCursor::Grabbing;
default: {
qWarning() << "Unsupported cursor shape:" << s;
return slint::private_api::MouseCursor::Default;
}
}
}
Qt::MouseButton s2q(const slint::private_api::PointerEventButton& b) noexcept {
switch (b) {
case slint::private_api::PointerEventButton::Left:
return Qt::LeftButton;
case slint::private_api::PointerEventButton::Right:
return Qt::RightButton;
case slint::private_api::PointerEventButton::Middle:
return Qt::MiddleButton;
case slint::private_api::PointerEventButton::Back:
return Qt::BackButton;
case slint::private_api::PointerEventButton::Forward:
return Qt::ForwardButton;
default:
return Qt::NoButton;
}
}
slint::private_api::KeyboardModifiers q2s(Qt::KeyboardModifiers m) noexcept {
slint::private_api::KeyboardModifiers ret = {};
ret.alt = m.testFlag(Qt::AltModifier);
ret.control = m.testFlag(Qt::ControlModifier);
ret.shift = m.testFlag(Qt::ShiftModifier);
ret.meta = m.testFlag(Qt::MetaModifier);
return ret;
}
Qt::KeyboardModifiers s2q(
const slint::private_api::KeyboardModifiers& m) noexcept {
Qt::KeyboardModifiers ret;
ret.setFlag(Qt::ShiftModifier, m.shift);
ret.setFlag(Qt::ControlModifier, m.control);
ret.setFlag(Qt::AltModifier, m.alt);
ret.setFlag(Qt::MetaModifier, m.meta);
return ret;
}
slint::SharedString q2s(Qt::Key k) noexcept {
switch (k) {
case Qt::Key::Key_Backspace:
return slint::platform::key_codes::Backspace;
case Qt::Key::Key_Tab:
return slint::platform::key_codes::Tab;
case Qt::Key::Key_Enter:
case Qt::Key::Key_Return:
return slint::platform::key_codes::Return;
case Qt::Key::Key_Escape:
return slint::platform::key_codes::Escape;
case Qt::Key::Key_Backtab:
return slint::platform::key_codes::Backtab;
case Qt::Key::Key_Delete:
return slint::platform::key_codes::Delete;
case Qt::Key::Key_Shift:
return slint::platform::key_codes::Shift;
case Qt::Key::Key_Control:
return slint::platform::key_codes::Control;
case Qt::Key::Key_Alt:
return slint::platform::key_codes::Alt;
case Qt::Key::Key_AltGr:
return slint::platform::key_codes::AltGr;
case Qt::Key::Key_CapsLock:
return slint::platform::key_codes::CapsLock;
case Qt::Key::Key_Meta:
return slint::platform::key_codes::Meta;
case Qt::Key::Key_Up:
return slint::platform::key_codes::UpArrow;
case Qt::Key::Key_Down:
return slint::platform::key_codes::DownArrow;
case Qt::Key::Key_Left:
return slint::platform::key_codes::LeftArrow;
case Qt::Key::Key_Right:
return slint::platform::key_codes::RightArrow;
case Qt::Key::Key_F1:
return slint::platform::key_codes::F1;
case Qt::Key::Key_F2:
return slint::platform::key_codes::F2;
case Qt::Key::Key_F3:
return slint::platform::key_codes::F3;
case Qt::Key::Key_F4:
return slint::platform::key_codes::F4;
case Qt::Key::Key_F5:
return slint::platform::key_codes::F5;
case Qt::Key::Key_F6:
return slint::platform::key_codes::F6;
case Qt::Key::Key_F7:
return slint::platform::key_codes::F7;
case Qt::Key::Key_F8:
return slint::platform::key_codes::F8;
case Qt::Key::Key_F9:
return slint::platform::key_codes::F9;
case Qt::Key::Key_F10:
return slint::platform::key_codes::F10;
case Qt::Key::Key_F11:
return slint::platform::key_codes::F11;
case Qt::Key::Key_F12:
return slint::platform::key_codes::F12;
case Qt::Key::Key_F13:
return slint::platform::key_codes::F13;
case Qt::Key::Key_F14:
return slint::platform::key_codes::F14;
case Qt::Key::Key_F15:
return slint::platform::key_codes::F15;
case Qt::Key::Key_F16:
return slint::platform::key_codes::F16;
case Qt::Key::Key_F17:
return slint::platform::key_codes::F17;
case Qt::Key::Key_F18:
return slint::platform::key_codes::F18;
case Qt::Key::Key_F19:
return slint::platform::key_codes::F19;
case Qt::Key::Key_F20:
return slint::platform::key_codes::F20;
case Qt::Key::Key_F21:
return slint::platform::key_codes::F21;
case Qt::Key::Key_F22:
return slint::platform::key_codes::F22;
case Qt::Key::Key_F23:
return slint::platform::key_codes::F23;
case Qt::Key::Key_F24:
return slint::platform::key_codes::F24;
case Qt::Key::Key_Insert:
return slint::platform::key_codes::Insert;
case Qt::Key::Key_Home:
return slint::platform::key_codes::Home;
case Qt::Key::Key_End:
return slint::platform::key_codes::End;
case Qt::Key::Key_PageUp:
return slint::platform::key_codes::PageUp;
case Qt::Key::Key_PageDown:
return slint::platform::key_codes::PageDown;
case Qt::Key::Key_ScrollLock:
return slint::platform::key_codes::ScrollLock;
case Qt::Key::Key_Pause:
return slint::platform::key_codes::Pause;
case Qt::Key::Key_SysReq:
return slint::platform::key_codes::SysReq;
case Qt::Key::Key_Stop:
return slint::platform::key_codes::Stop;
case Qt::Key::Key_Menu:
return slint::platform::key_codes::Menu;
default: {
const QString s = QKeySequence(k).toString().toLower();
if (s.isEmpty()) {
qWarning() << "Unknown Qt key:" << k;
}
return q2s(s);
}
}
}
Qt::Key s2key(const slint::SharedString& k) noexcept {
if (k == slint::platform::key_codes::Backspace) {
return Qt::Key::Key_Backspace;
} else if (k == slint::platform::key_codes::Tab) {
return Qt::Key::Key_Tab;
} else if (k == slint::platform::key_codes::Return) {
return Qt::Key::Key_Return; // Could also be Key_Enter?
} else if (k == slint::platform::key_codes::Escape) {
return Qt::Key::Key_Escape;
} else if (k == slint::platform::key_codes::Backtab) {
return Qt::Key::Key_Backtab;
} else if (k == slint::platform::key_codes::Delete) {
return Qt::Key::Key_Delete;
} else if (k == slint::platform::key_codes::Shift) {
return Qt::Key::Key_Shift;
} else if (k == slint::platform::key_codes::Control) {
return Qt::Key::Key_Control;
} else if (k == slint::platform::key_codes::Alt) {
return Qt::Key::Key_Alt;
} else if (k == slint::platform::key_codes::AltGr) {
return Qt::Key::Key_AltGr;
} else if (k == slint::platform::key_codes::CapsLock) {
return Qt::Key::Key_CapsLock;
} else if (k == slint::platform::key_codes::Meta) {
return Qt::Key::Key_Meta;
} else if (k == slint::platform::key_codes::UpArrow) {
return Qt::Key::Key_Up;
} else if (k == slint::platform::key_codes::DownArrow) {
return Qt::Key::Key_Down;
} else if (k == slint::platform::key_codes::LeftArrow) {
return Qt::Key::Key_Left;
} else if (k == slint::platform::key_codes::RightArrow) {
return Qt::Key::Key_Right;
} else if (k == slint::platform::key_codes::F1) {
return Qt::Key::Key_F1;
} else if (k == slint::platform::key_codes::F2) {
return Qt::Key::Key_F2;
} else if (k == slint::platform::key_codes::F3) {
return Qt::Key::Key_F3;
} else if (k == slint::platform::key_codes::F4) {
return Qt::Key::Key_F4;
} else if (k == slint::platform::key_codes::F5) {
return Qt::Key::Key_F5;
} else if (k == slint::platform::key_codes::F6) {
return Qt::Key::Key_F6;
} else if (k == slint::platform::key_codes::F7) {
return Qt::Key::Key_F7;
} else if (k == slint::platform::key_codes::F8) {
return Qt::Key::Key_F8;
} else if (k == slint::platform::key_codes::F9) {
return Qt::Key::Key_F9;
} else if (k == slint::platform::key_codes::F10) {
return Qt::Key::Key_F10;
} else if (k == slint::platform::key_codes::F11) {
return Qt::Key::Key_F11;
} else if (k == slint::platform::key_codes::F12) {
return Qt::Key::Key_F12;
} else if (k == slint::platform::key_codes::F13) {
return Qt::Key::Key_F13;
} else if (k == slint::platform::key_codes::F14) {
return Qt::Key::Key_F14;
} else if (k == slint::platform::key_codes::F15) {
return Qt::Key::Key_F15;
} else if (k == slint::platform::key_codes::F16) {
return Qt::Key::Key_F16;
} else if (k == slint::platform::key_codes::F17) {
return Qt::Key::Key_F17;
} else if (k == slint::platform::key_codes::F18) {
return Qt::Key::Key_F18;
} else if (k == slint::platform::key_codes::F19) {
return Qt::Key::Key_F19;
} else if (k == slint::platform::key_codes::F20) {
return Qt::Key::Key_F20;
} else if (k == slint::platform::key_codes::F21) {
return Qt::Key::Key_F21;
} else if (k == slint::platform::key_codes::F22) {
return Qt::Key::Key_F22;
} else if (k == slint::platform::key_codes::F23) {
return Qt::Key::Key_F23;
} else if (k == slint::platform::key_codes::F24) {
return Qt::Key::Key_F24;
} else if (k == slint::platform::key_codes::Insert) {
return Qt::Key::Key_Insert;
} else if (k == slint::platform::key_codes::Home) {
return Qt::Key::Key_Home;
} else if (k == slint::platform::key_codes::End) {
return Qt::Key::Key_End;
} else if (k == slint::platform::key_codes::PageUp) {
return Qt::Key::Key_PageUp;
} else if (k == slint::platform::key_codes::PageDown) {
return Qt::Key::Key_PageDown;
} else if (k == slint::platform::key_codes::ScrollLock) {
return Qt::Key::Key_ScrollLock;
} else if (k == slint::platform::key_codes::Pause) {
return Qt::Key::Key_Pause;
} else if (k == slint::platform::key_codes::SysReq) {
return Qt::Key::Key_SysReq;
} else if (k == slint::platform::key_codes::Stop) {
return Qt::Key::Key_Stop;
} else if (k == slint::platform::key_codes::Menu) {
return Qt::Key::Key_Menu;
} else if (k.size() == 1) {
const QKeySequence seq(s2q(k));
return seq[0].key();
} else {
qWarning() << "Unknown Slint key:" << s2q(k);
return Qt::Key(0);
}
}
static slint::SharedString getInputError(const QString& input) {
if (input.trimmed().isEmpty()) {
return q2s(QCoreApplication::translate("SlintHelpers", "Required"));
} else {
return q2s(QCoreApplication::translate("SlintHelpers", "Invalid"));
}
}
static slint::SharedString getDuplicateError() {
return q2s(QCoreApplication::translate("SlintHelpers", "Duplicate"));
}
static slint::SharedString getRecommendedError() {
return q2s(QCoreApplication::translate("SlintHelpers", "Recommended"));
}
std::optional<ElementName> validateElementName(
const QString& input, slint::SharedString& error) noexcept {
if (auto val = parseElementName(cleanElementName(input))) {
error = slint::SharedString();
return val;
} else {
error = getInputError(input);
return std::nullopt;
}
}
std::optional<Version> validateVersion(const QString& input,
slint::SharedString& error) noexcept {
if (auto val = Version::tryFromString(input.trimmed())) {
error = slint::SharedString();
return val;
} else {
error = getInputError(input);
return std::nullopt;
}
}
std::optional<QString> validateFileName(
const QString& input, slint::SharedString& error,
FilePath::CleanFileNameOptions options, int maxLength,
const QString& requiredSuffix) noexcept {
QString s = input.trimmed();
if ((!requiredSuffix.isEmpty()) && (!s.endsWith(requiredSuffix))) {
error =
q2s(QCoreApplication::translate("SlintHelpers", "Suffix '%1' missing")
.arg(requiredSuffix));
return std::nullopt;
}
// IMPORTANT: Remove suffix before truncating, because the suffix must be
// retained even if the filename gets truncated!
s.chop(requiredSuffix.length());
s = FilePath::cleanFileName(s, options, maxLength - requiredSuffix.length());
if (s.isEmpty()) {
error = getInputError(input);
return std::nullopt;
}
s.append(requiredSuffix);
error = slint::SharedString();
return s;
}
std::optional<AttributeKey> validateAttributeKey(const QString& input,
slint::SharedString& error,
bool isDuplicate) noexcept {
auto val = parseAttributeKey(cleanAttributeKey(input));
if (isDuplicate) {
error = getDuplicateError();
} else if (val) {
error = slint::SharedString();
} else {
error = getInputError(input);
}
return val;
}
std::optional<CircuitIdentifier> validateCircuitIdentifier(
const QString& input, slint::SharedString& error,
bool isDuplicate) noexcept {
auto val = parseCircuitIdentifier(cleanCircuitIdentifier(input));
if (isDuplicate) {
error = getDuplicateError();
} else if (val) {
error = slint::SharedString();
} else {
error = getInputError(input);
}
return val;
}
std::optional<QUrl> validateUrl(const QString& input,
slint::SharedString& error,
bool allowEmpty) noexcept {
const QUrl url = QUrl::fromUserInput(input.trimmed());
const std::optional<QUrl> val =
url.isValid() ? std::make_optional(url) : std::nullopt;
if (val || (allowEmpty && input.trimmed().isEmpty())) {
error = slint::SharedString();
return val;
} else {
error = getInputError(input);
return std::nullopt;
}
}
std::optional<ComponentPrefix> validateComponentPrefix(
const QString& input, slint::SharedString& error) noexcept {
auto val = parseComponentPrefix(cleanComponentPrefix(input));
if (val && (!input.trimmed().isEmpty())) {
error = slint::SharedString();
} else if (!input.trimmed().isEmpty()) {
error = getInputError(input);
} else {
error = getRecommendedError();
}
return val;
}
void validateComponentDefaultValue(const QString& input,
slint::SharedString& error) noexcept {
if (!input.trimmed().isEmpty()) {
error = slint::SharedString();
} else {
error = getRecommendedError();
}
}
/*******************************************************************************
* End of File
******************************************************************************/
} // namespace editor
} // namespace librepcb
97a29b08eThis file is pinned to the selected release. Download the original to open it in your design tool.