mirror of
https://github.com/transmission/transmission.git
synced 2025-12-20 18:38:42 +00:00
chore: savepoint
This commit is contained in:
@@ -61,6 +61,8 @@ target_sources(${TR_NAME}-qt
|
|||||||
MainWindow.h
|
MainWindow.h
|
||||||
MakeDialog.cc
|
MakeDialog.cc
|
||||||
MakeDialog.h
|
MakeDialog.h
|
||||||
|
NativeIcon.cc
|
||||||
|
NativeIcon.h
|
||||||
OptionsDialog.cc
|
OptionsDialog.cc
|
||||||
OptionsDialog.h
|
OptionsDialog.h
|
||||||
PathButton.cc
|
PathButton.cc
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "FilterBarComboBoxDelegate.h"
|
#include "FilterBarComboBoxDelegate.h"
|
||||||
#include "Filters.h"
|
#include "Filters.h"
|
||||||
#include "IconCache.h"
|
#include "IconCache.h"
|
||||||
|
#include "NativeIcon.h"
|
||||||
#include "Prefs.h"
|
#include "Prefs.h"
|
||||||
#include "Torrent.h"
|
#include "Torrent.h"
|
||||||
#include "TorrentFilter.h"
|
#include "TorrentFilter.h"
|
||||||
@@ -37,6 +38,8 @@ enum
|
|||||||
|
|
||||||
FilterBarComboBox* FilterBar::createActivityCombo()
|
FilterBarComboBox* FilterBar::createActivityCombo()
|
||||||
{
|
{
|
||||||
|
auto* const style = QApplication::style();
|
||||||
|
|
||||||
auto* c = new FilterBarComboBox{ this };
|
auto* c = new FilterBarComboBox{ this };
|
||||||
auto* delegate = new FilterBarComboBoxDelegate{ this, c };
|
auto* delegate = new FilterBarComboBoxDelegate{ this, c };
|
||||||
c->setItemDelegate(delegate);
|
c->setItemDelegate(delegate);
|
||||||
@@ -51,32 +54,58 @@ FilterBarComboBox* FilterBar::createActivityCombo()
|
|||||||
FilterBarComboBoxDelegate::setSeparator(model, model->index(1, 0));
|
FilterBarComboBoxDelegate::setSeparator(model, model->index(1, 0));
|
||||||
|
|
||||||
auto const& icons = IconCache::get();
|
auto const& icons = IconCache::get();
|
||||||
|
#if 0
|
||||||
|
struct NativeIcon
|
||||||
|
{
|
||||||
|
using
|
||||||
|
public:
|
||||||
|
struct Spec
|
||||||
|
{
|
||||||
|
// https://developer.apple.com/sf-symbols
|
||||||
|
// https://github.com/andrewtavis/sf-symbols-online
|
||||||
|
QString sfSymbolName;
|
||||||
|
|
||||||
row = new QStandardItem{ icons.getThemeIcon(QStringLiteral("system-run")), tr("Active") };
|
// https://learn.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font
|
||||||
|
QString fluentCodepoint;
|
||||||
|
|
||||||
|
// https://specifications.freedesktop.org/icon-naming/latest/#names
|
||||||
|
QString fdoName;
|
||||||
|
|
||||||
|
// https://doc.qt.io/qt-6/qstyle.html#StandardPixmap-enum
|
||||||
|
std::optional<QStyle::StandardPixmap> fallback;
|
||||||
|
|
||||||
|
QFont::Weight weight = QFont::Normal;
|
||||||
|
};
|
||||||
|
|
||||||
|
static QIcon get(const Spec& spec, QStyle* style = QApplication::style());
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
row = new QStandardItem{ NativeIcon::get({ QStringLiteral("play.fill"), QStringLiteral("e768"), QStringLiteral("media-playback-start"), QStyle::SP_MediaPlay }), tr("Active") };
|
||||||
row->setData(FilterMode::SHOW_ACTIVE, ACTIVITY_ROLE);
|
row->setData(FilterMode::SHOW_ACTIVE, ACTIVITY_ROLE);
|
||||||
model->appendRow(row);
|
model->appendRow(row);
|
||||||
|
|
||||||
row = new QStandardItem{ icons.getThemeIcon(QStringLiteral("go-down")), tr("Downloading") };
|
row = new QStandardItem{ NativeIcon::get({ QStringLiteral("chevron.up"), QStringLiteral("e70e"), QStringLiteral("go-up"), QStyle::SP_ArrowUp }), tr("Seeding") };
|
||||||
row->setData(FilterMode::SHOW_DOWNLOADING, ACTIVITY_ROLE);
|
|
||||||
model->appendRow(row);
|
|
||||||
|
|
||||||
row = new QStandardItem{ icons.getThemeIcon(QStringLiteral("go-up")), tr("Seeding") };
|
|
||||||
row->setData(FilterMode::SHOW_SEEDING, ACTIVITY_ROLE);
|
row->setData(FilterMode::SHOW_SEEDING, ACTIVITY_ROLE);
|
||||||
model->appendRow(row);
|
model->appendRow(row);
|
||||||
|
|
||||||
row = new QStandardItem{ icons.getThemeIcon(QStringLiteral("media-playback-pause")), tr("Paused") };
|
row = new QStandardItem{ NativeIcon::get({ QStringLiteral("chevron.down"), QStringLiteral("e70d"), QStringLiteral("go-down"), QStyle::SP_ArrowUp }), tr("Downloading") };
|
||||||
|
row->setData(FilterMode::SHOW_DOWNLOADING, ACTIVITY_ROLE);
|
||||||
|
model->appendRow(row);
|
||||||
|
|
||||||
|
row = new QStandardItem{ NativeIcon::get({ QStringLiteral("pause.fill"), QStringLiteral("e769"), QStringLiteral("media-playback-pause"), QStyle::SP_MediaPause }), tr("Paused") };
|
||||||
row->setData(FilterMode::SHOW_PAUSED, ACTIVITY_ROLE);
|
row->setData(FilterMode::SHOW_PAUSED, ACTIVITY_ROLE);
|
||||||
model->appendRow(row);
|
model->appendRow(row);
|
||||||
|
|
||||||
row = new QStandardItem{ icons.getThemeIcon(QStringLiteral("dialog-ok")), tr("Finished") };
|
row = new QStandardItem{ tr("Finished") };
|
||||||
row->setData(FilterMode::SHOW_FINISHED, ACTIVITY_ROLE);
|
row->setData(FilterMode::SHOW_FINISHED, ACTIVITY_ROLE);
|
||||||
model->appendRow(row);
|
model->appendRow(row);
|
||||||
|
|
||||||
row = new QStandardItem{ icons.getThemeIcon(QStringLiteral("view-refresh")), tr("Verifying") };
|
row = new QStandardItem{ NativeIcon::get({ QStringLiteral("arrow.clockwise"), QStringLiteral("e72c"), QStringLiteral("view-refresh"), QStyle::SP_BrowserReload }), tr("Verifying") };
|
||||||
row->setData(FilterMode::SHOW_VERIFYING, ACTIVITY_ROLE);
|
row->setData(FilterMode::SHOW_VERIFYING, ACTIVITY_ROLE);
|
||||||
model->appendRow(row);
|
model->appendRow(row);
|
||||||
|
|
||||||
row = new QStandardItem{ icons.getThemeIcon(QStringLiteral("process-stop")), tr("Error") };
|
row = new QStandardItem{ NativeIcon::get({ tr("xmark.circle"), QStringLiteral("eb90"), QStringLiteral("dialog-error"), QStyle::SP_MessageBoxWarning }), tr("Error") };
|
||||||
row->setData(FilterMode::SHOW_ERROR, ACTIVITY_ROLE);
|
row->setData(FilterMode::SHOW_ERROR, ACTIVITY_ROLE);
|
||||||
model->appendRow(row);
|
model->appendRow(row);
|
||||||
|
|
||||||
|
|||||||
130
qt/NativeIcon.cc
Normal file
130
qt/NativeIcon.cc
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
// This file Copyright © Mnemosyne LLC.
|
||||||
|
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||||
|
// or any future license endorsed by Mnemosyne LLC.
|
||||||
|
// License text can be found in the licenses/ folder.
|
||||||
|
|
||||||
|
#include "NativeIcon.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <QtGui/QIcon>
|
||||||
|
#include <QtGui/QPixmap>
|
||||||
|
#include <QtGui/QPainter>
|
||||||
|
#include <QtGui/QFont>
|
||||||
|
#include <QtGui/QGuiApplication>
|
||||||
|
#include <QtGui/QPalette>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
QChar parseCodepoint(QString const& code)
|
||||||
|
{
|
||||||
|
// Supports "E710" or "\uE710"
|
||||||
|
QString s = code.trimmed();
|
||||||
|
if (s.startsWith("\\u", Qt::CaseInsensitive))
|
||||||
|
s = s.mid(2);
|
||||||
|
bool ok = false;
|
||||||
|
uint u = s.toUInt(&ok, 16);
|
||||||
|
return ok ? QChar(u) : QChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap makeFluentPixmap(QString const& codepointHex, int const pointSize)
|
||||||
|
{
|
||||||
|
if (codepointHex.isEmpty())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const QChar glyph = parseCodepoint(codepointHex);
|
||||||
|
if (glyph.isNull())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// Prefer Segoe Fluent Icons (Win11), fall back to Segoe MDL2 Assets (Win10)
|
||||||
|
QFont font;
|
||||||
|
font.setPointSize(pointSize);
|
||||||
|
font.setStyleStrategy(QFont::PreferDefault);
|
||||||
|
|
||||||
|
// Try Fluent first
|
||||||
|
font.setFamily("Segoe Fluent Icons");
|
||||||
|
if (!QFontInfo(font).exactMatch()) {
|
||||||
|
font.setFamily("Segoe MDL2 Assets");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const dpr = qApp->primaryScreen()->devicePixelRatio();
|
||||||
|
auto const px = qRound(pointSize * dpr) + 8; // padding
|
||||||
|
QPixmap pm{px, px};
|
||||||
|
pm.setDevicePixelRatio(dpr);
|
||||||
|
pm.fill(Qt::transparent);
|
||||||
|
|
||||||
|
auto const fg = qApp->palette().color(QPalette::ButtonText);
|
||||||
|
QPainter p{&pm};
|
||||||
|
p.setRenderHint(QPainter::Antialiasing, true);
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(fg);
|
||||||
|
p.setFont(font);
|
||||||
|
|
||||||
|
// Center the glyph
|
||||||
|
QRectF r(0, 0, pm.width() / dpr, pm.height() / dpr);
|
||||||
|
p.drawText(r, Qt::AlignCenter, QString(glyph));
|
||||||
|
p.end();
|
||||||
|
|
||||||
|
return QIcon{pm};
|
||||||
|
}
|
||||||
|
# endif // Q_OS_WIN
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
QIcon NativeIcon::get(Spec const& spec, QStyle* style)
|
||||||
|
{
|
||||||
|
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||||
|
auto constexpr auto IconMetrics = std::array<QStyle::PixelMetric, 7U>{{
|
||||||
|
QStyle::PM_ButtonIconSize
|
||||||
|
QStyle::PM_LargeIconSize,
|
||||||
|
QStyle::PM_ListViewIconSize,
|
||||||
|
QStyle::PM_MessageBoxIconSize,
|
||||||
|
QStyle::PM_SmallIconSize,
|
||||||
|
QStyle::PM_TabBarIconSize,
|
||||||
|
QStyle::PM_ToolBarIconSize,
|
||||||
|
}};
|
||||||
|
|
||||||
|
auto dipSizes = std::set<QSize>{};
|
||||||
|
for (auto const pm : IconMetrics) {
|
||||||
|
auto const dip = style->pixelMetric(pm);
|
||||||
|
dipSizes.emplace(dip, dip);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(Q_OS_MAC)
|
||||||
|
// TODO: try sfSymbolName if on macOS
|
||||||
|
// https://stackoverflow.com/questions/74747658/how-to-convert-a-cgimageref-to-a-qpixmap-in-qt-6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
if (!spec.fluentCodepoint.isEmpty()) {
|
||||||
|
auto icon = QIcon{};
|
||||||
|
for (auto const dipSize : dipSizes)
|
||||||
|
if (auto pixmap = makeFluentIcon(spec.fluentCodepoint, dipSize); !pixmap.isNull())
|
||||||
|
icon.addPixmap(pixmap);
|
||||||
|
if (!icon.isNull())
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!spec.fdoName.isEmpty()) {
|
||||||
|
if (auto icon = QIcon::fromTheme(spec.fdoName + QStringLiteral("-symbolic")); !icon.isNull()) {
|
||||||
|
std::cerr << "using fdo" << std::endl;
|
||||||
|
return icon;
|
||||||
|
} else {
|
||||||
|
std::cerr << "QIcon::fromTheme(" << qPrintable(spec.fdoName) << ") returned empty" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spec.fallback) {
|
||||||
|
if (auto icon = style->standardIcon(*spec.fallback); !icon.isNull()) {
|
||||||
|
std::cerr << "Qt Standard Icon" << std::endl;
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "no match" << std::endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
37
qt/NativeIcon.h
Normal file
37
qt/NativeIcon.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// This file Copyright © Mnemosyne LLC.
|
||||||
|
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||||
|
// or any future license endorsed by Mnemosyne LLC.
|
||||||
|
// License text can be found in the licenses/ folder.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QFont>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStyle>
|
||||||
|
|
||||||
|
struct NativeIcon
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Spec
|
||||||
|
{
|
||||||
|
// https://developer.apple.com/sf-symbols
|
||||||
|
// https://github.com/andrewtavis/sf-symbols-online
|
||||||
|
QString sfSymbolName;
|
||||||
|
|
||||||
|
// https://learn.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font
|
||||||
|
QString fluentCodepoint;
|
||||||
|
|
||||||
|
// https://specifications.freedesktop.org/icon-naming/latest/#names
|
||||||
|
QString fdoName;
|
||||||
|
|
||||||
|
// https://doc.qt.io/qt-6/qstyle.html#StandardPixmap-enum
|
||||||
|
std::optional<QStyle::StandardPixmap> fallback;
|
||||||
|
|
||||||
|
QFont::Weight weight = QFont::Normal;
|
||||||
|
};
|
||||||
|
|
||||||
|
static QIcon get(const Spec& spec, QStyle* style = QApplication::style());
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user