Files
transmission/qt/MainWindow.h
Charles Kerr bfa1950fbe feat: native icons in Qt client (#7819)
* chore: savepoint

* chore: code style

* refactor: add std::string_view constructor for NativeIcon::Spec

* chore: add TODO comment

* feat: honor per-desktop HIG on when to show menu icons

* chore: remove Faenza system-run icon

unused since b58e95910b

* chore: remove Faenza view-refresh icon

not needed due to b58e95910b

* chore: remove Faenza media-playback-pause icon

not needed due to b58e95910b

* chore: remove Faenza media-playback-start icon

not needed due to b58e95910b

* chore: add a safeguard against merging with incomplete TODO items

* feat: add more icons

refactor: remove some tracer cerr statements

* refactor: remove IconCache use from MainWindow

* chore: remove Faenza icon set

* chore: re-enable remote session network icon

* fix: FTBFS on Windows

* refactor: use symbolic names for Segoe icons

* docs: add links to Segoe MDL2 Assets icon list

* chore: savepoint

segoe icons work

still a WIP; includes test code that should not ship

* feat: use segoe::FastForward for action_StartNow

feat: use segoe::Move for action_SetLocation

refactor: make it easier for devs to force a font at compile time for development work

segoe license does not allow bundling but does allow dev work

chore: code_style.sh

* refactor: remove unused addEmblem()

* docs: add code comment on how to force an icon font

* fix: Win 10, 11 icons play nicely with dark mode

* chore: savepoint

add draft of SF Symbol -> QPixmap loader

* chore: remove dangling font reference from qrc file

* fix: FTBFS

* refactor: use bribri code for NSImage -> QPixmap

* feat: support dark, light mode when rendering SF Symbol monochrome icons

* fixup! feat: support dark, light mode when rendering SF Symbol monochrome icons

fix: fail gracefully on macOS 11

* chore: code style

* chore: tweak some SF Symbol icon choices

* chore: consistent uppercase for hex segoe QChars

* chore: undefine DEV_FORCE_FONT_FAMILY and DEV_FORCE_FONT_RESOURCE

* chore: savepoint

* refactor: clean up NativeIcon impl

* refactor: remove unused MenuMode::Other

* refactor: DRY in FilterBar::createActivityCombo()

* chore: remove obsolete code comment

* refactor: rename icons::Facet as icons::Type

* fix: oops

* refactor: minor cleanup

* fix: tyop

* chore: remove unused #includes

* fix: add modes for some icons

* refactor: tweak some icon choices on macOS

* fix: ensure icons are visible on File, Help menus

fix: remove unused local variable

* refactor: tweak some icon choices for XDG

* refactor: remove the fallback QStyle::StandardPixmaps

These interfere with deciding whether an icon is well-defined and
unambiguous as per the macOS and Windows HIG guidelines.

If a standard or unambiguous icon exists in the native icon sets,
specify it with an SF Symbols name, a Segoe codepoint,
or XDG standard icon name. Otherwise, leave those fields blank.

* refactor: remove unused #includes

* docs: add "choosing icons" section in NativeIcons.cc

* refactor: simplify icons::shouldBeShownInMenu()

* refactor: reduce unnecessary code shear from main

* refactor: make TorrentDelegate::warning_emblem_ const

* refactor: extract-method MainWindow::updateActionIcons()

* feat: update MainWindow icons when light/dark theme changes

* feat: restore the QStyle::StandardPixmaps as fallbacks

Can be used on older Windows / macOS if Segoe or SF Symbols are unavailable

* refactor: add button text for add/edit/remove tracker buttons

QStyle::StandardPixmap doesn't have good icons for these,
so let's ensure that these buttons have visible text.

* fix: building NativeIconMac.mm on mac even if not clang

* chore: iwyu in new code

* docs: tweak the "Choosing Icons" comments again

* fix: handle changed QStyles in icons::icon()

do not cache point_sizes set between calls

refactor: const correctness

* fixup! refactor: simplify icons::shouldBeShownInMenu()

refactor: minor code tweak, declare vars in order that they are used
2025-11-30 10:09:20 -06:00

216 lines
5.9 KiB
C++

// 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 <cstddef>
#include <ctime>
#include <memory>
#include <QMainWindow>
#include <QNetworkReply>
#include <QPointer>
#include <QStringList>
#include <QSystemTrayIcon>
#include <QTimer>
#include <QWidgetList>
#include "Filters.h"
#include "Speed.h"
#include "TorrentFilter.h"
#include "Typedefs.h"
#include "ui_MainWindow.h"
class QAction;
class QIcon;
class QMenu;
class AboutDialog;
class AddData;
class DetailsDialog;
class ListViewProxyStyle;
class Prefs;
class PrefsDialog;
class Session;
class SessionDialog;
class StatsDialog;
class TorrentDelegate;
class TorrentDelegateMin;
class TorrentModel;
extern "C"
{
struct tr_variant;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(Session&, Prefs&, TorrentModel&, bool minimized);
MainWindow(MainWindow&&) = delete;
MainWindow(MainWindow const&) = delete;
MainWindow& operator=(MainWindow&&) = delete;
MainWindow& operator=(MainWindow const&) = delete;
[[nodiscard]] constexpr QSystemTrayIcon& trayIcon() noexcept
{
return tray_icon_;
}
public slots:
void startAll();
void startSelected();
void startSelectedNow();
void pauseAll();
void pauseSelected();
void removeSelected();
void deleteSelected();
void verifySelected();
void queueMoveTop();
void queueMoveUp();
void queueMoveDown();
void queueMoveBottom();
void reannounceSelected();
void setToolbarVisible(bool);
void setFilterbarVisible(bool);
void setStatusbarVisible(bool);
void setCompactView(bool);
void wrongAuthentication();
void openSession();
protected:
// QWidget
void contextMenuEvent(QContextMenuEvent*) override;
void dragEnterEvent(QDragEnterEvent*) override;
void dropEvent(QDropEvent*) override;
bool event(QEvent*) override;
private slots:
void addTorrents(QStringList const& filenames);
void copyMagnetLinkToClipboard();
void dataReadProgress();
void dataSendProgress();
void newTorrent();
void onNetworkResponse(QNetworkReply::NetworkError code, QString const& message);
void onRefreshTimer();
void onSessionSourceChanged();
void onSetPrefs();
void onSetPrefs(bool);
void onSortModeChanged(QAction const* action);
void onStatsModeChanged(QAction const* action);
void openAbout();
void openDonate() const;
void openFolder();
void openHelp() const;
void openPreferences();
void openProperties();
void openStats();
void openTorrent();
void openURL();
void refreshPref(int key);
void removeTorrents(bool const delete_files);
void setLocation();
void setSortAscendingPref(bool);
void toggleSpeedMode();
void toggleWindows(bool do_show);
void trayActivated(QSystemTrayIcon::ActivationReason);
private:
[[nodiscard]] torrent_ids_t getSelectedTorrents(bool with_metadata_only = false) const;
void updateNetworkLabel();
void refreshSoon(int fields);
QMenu* createOptionsMenu();
QMenu* createStatsModeMenu();
void initStatusBar();
void clearSelection();
void addTorrentFromClipboard();
void addTorrent(AddData add_me, bool show_options);
// QWidget
void hideEvent(QHideEvent* event) override;
void showEvent(QShowEvent* event) override;
Session& session_;
Prefs& prefs_;
TorrentModel& model_;
std::shared_ptr<ListViewProxyStyle> lvp_style_;
QPixmap pixmap_network_error_;
QPixmap pixmap_network_idle_;
QPixmap pixmap_network_receive_;
QPixmap pixmap_network_transmit_;
QPixmap pixmap_network_transmit_receive_;
Ui_MainWindow ui_ = {};
time_t last_full_update_time_ = {};
QPointer<SessionDialog> session_dialog_;
QPointer<PrefsDialog> prefs_dialog_;
QPointer<AboutDialog> about_dialog_;
QPointer<StatsDialog> stats_dialog_;
QPointer<DetailsDialog> details_dialog_;
QSystemTrayIcon tray_icon_;
TorrentFilter filter_model_;
TorrentDelegate* torrent_delegate_ = {};
TorrentDelegateMin* torrent_delegate_min_ = {};
time_t last_send_time_ = {};
time_t last_read_time_ = {};
QTimer network_timer_;
bool network_error_ = {};
QAction* dlimit_off_action_ = {};
QAction* dlimit_on_action_ = {};
QAction* ulimit_off_action_ = {};
QAction* ulimit_on_action_ = {};
QAction* ratio_off_action_ = {};
QAction* ratio_on_action_ = {};
QWidgetList hidden_;
QWidget* filter_bar_ = {};
QAction* alt_speed_action_ = {};
QString error_message_;
bool auto_add_clipboard_links_ = {};
QStringList clipboard_processed_keys_ = {};
QString const total_ratio_stats_mode_name_ = QStringLiteral("total-ratio");
QString const total_transfer_stats_mode_name_ = QStringLiteral("total-transfer");
QString const session_ratio_stats_mode_name_ = QStringLiteral("session-ratio");
QString const session_transfer_stats_mode_name_ = QStringLiteral("session-transfer");
QString const show_options_checkbox_name_ = QStringLiteral("show-options-checkbox");
struct TransferStats
{
Speed speed_up;
Speed speed_down;
size_t peers_sending = 0;
size_t peers_receiving = 0;
};
[[nodiscard]] TransferStats getTransferStats() const;
enum
{
REFRESH_TITLE = (1 << 0),
REFRESH_STATUS_BAR = (1 << 1),
REFRESH_TRAY_ICON = (1 << 2),
REFRESH_TORRENT_VIEW_HEADER = (1 << 3),
REFRESH_ACTION_SENSITIVITY = (1 << 4),
REFRESH_ICONS = (1 << 5)
};
int refresh_fields_ = {};
QTimer refresh_timer_;
void refreshActionSensitivity();
void refreshIcons();
void refreshStatusBar(TransferStats const&);
void refreshTitle();
void refreshTorrentViewHeader();
void refreshTrayIcon(TransferStats const&);
};