This commit is contained in:
Nick 2024-04-27 13:19:01 +08:00 committed by GitHub
commit 71f3ef6f9f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 203 additions and 62 deletions

View File

@ -345,6 +345,7 @@ auto constexpr MyStatic = std::array<std::string_view, TR_N_KEYS>{
"show-filterbar"sv,
"show-notification-area-icon"sv,
"show-options-window"sv,
"show-piecebar"sv,
"show-statusbar"sv,
"show-toolbar"sv,
"show-tracker-scrapes"sv,

View File

@ -346,6 +346,7 @@ enum
TR_KEY_show_filterbar,
TR_KEY_show_notification_area_icon,
TR_KEY_show_options_window,
TR_KEY_show_piecebar,
TR_KEY_show_statusbar,
TR_KEY_show_toolbar,
TR_KEY_show_tracker_scrapes,

View File

@ -128,8 +128,8 @@ MainWindow::MainWindow(Session& session, Prefs& prefs, TorrentModel& model, bool
, model_{ model }
, lvp_style_{ std::make_shared<ListViewProxyStyle>() }
, filter_model_{ prefs }
, torrent_delegate_{ new TorrentDelegate{ this } }
, torrent_delegate_min_{ new TorrentDelegateMin{ this } }
, torrent_delegate_{ new TorrentDelegate{ prefs, this } }
, torrent_delegate_min_{ new TorrentDelegateMin{ prefs, this } }
, network_timer_{ this }
, refresh_timer_{ this }
{

View File

@ -65,6 +65,7 @@ std::array<Prefs::PrefItem, Prefs::PREFS_COUNT> const Prefs::Items{
{ DIR_WATCH_ENABLED, TR_KEY_watch_dir_enabled, QMetaType::Bool },
{ SHOW_TRAY_ICON, TR_KEY_show_notification_area_icon, QMetaType::Bool },
{ START_MINIMIZED, TR_KEY_start_minimized, QMetaType::Bool },
{ SHOW_PIECEBAR, TR_KEY_show_piecebar, QMetaType::Bool },
{ SHOW_NOTIFICATION_ON_ADD, TR_KEY_torrent_added_notification_enabled, QMetaType::Bool },
{ SHOW_NOTIFICATION_ON_COMPLETE, TR_KEY_torrent_complete_notification_enabled, QMetaType::Bool },
{ ASKQUIT, TR_KEY_prompt_before_exit, QMetaType::Bool },
@ -449,6 +450,7 @@ tr_variant Prefs::get_default_app_settings()
settings.try_emplace(TR_KEY_show_notification_area_icon, false);
settings.try_emplace(TR_KEY_start_minimized, false);
settings.try_emplace(TR_KEY_show_options_window, true);
settings.try_emplace(TR_KEY_show_piecebar, true);
settings.try_emplace(TR_KEY_show_statusbar, true);
settings.try_emplace(TR_KEY_show_toolbar, true);
settings.try_emplace(TR_KEY_show_tracker_scrapes, false);

View File

@ -38,6 +38,7 @@ public:
DIR_WATCH_ENABLED,
SHOW_TRAY_ICON,
START_MINIMIZED,
SHOW_PIECEBAR,
SHOW_NOTIFICATION_ON_ADD,
SHOW_NOTIFICATION_ON_COMPLETE,
ASKQUIT,

View File

@ -7,6 +7,7 @@
#include <cassert>
#include <optional>
#include <set>
#include <QCheckBox>
#include <QComboBox>
@ -283,7 +284,24 @@ void PrefsDialog::checkBoxToggled(bool checked)
if (pref_widget.is<QCheckBox>())
{
setPref(pref_widget.getPrefKey(), checked);
auto key = pref_widget.getPrefKey();
setPref(key, checked);
switch (key)
{
case Prefs::SHOW_PIECEBAR:
if (checked)
{
session_.addKeyName(Session::TorrentProperties::MainStats, TR_KEY_pieceCount);
session_.addKeyName(Session::TorrentProperties::MainStats, TR_KEY_pieces);
}
else
{
session_.removeKeyName(Session::TorrentProperties::MainStats, TR_KEY_pieceCount);
session_.removeKeyName(Session::TorrentProperties::MainStats, TR_KEY_pieces);
}
break;
}
}
}
@ -420,6 +438,7 @@ void PrefsDialog::initDesktopTab()
{
linkWidgetToPref(ui_.showTrayIconCheck, Prefs::SHOW_TRAY_ICON);
linkWidgetToPref(ui_.startMinimizedCheck, Prefs::START_MINIMIZED);
linkWidgetToPref(ui_.showPiecebarCheck, Prefs::SHOW_PIECEBAR);
linkWidgetToPref(ui_.notifyOnTorrentAddedCheck, Prefs::SHOW_NOTIFICATION_ON_ADD);
linkWidgetToPref(ui_.notifyOnTorrentCompletedCheck, Prefs::SHOW_NOTIFICATION_ON_COMPLETE);
linkWidgetToPref(ui_.playSoundOnTorrentCompletedCheck, Prefs::COMPLETE_SOUND_ENABLED);

View File

@ -866,6 +866,13 @@ To add a new primary URL, add it after a blank line.</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showPiecebarCheck">
<property name="text">
<string>Show the downloaded pieces in addition to the progressbar</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -537,31 +537,31 @@ std::set<std::string_view> const& Session::getKeyNames(TorrentProperties props)
// changing fields needed by the main window
static auto constexpr MainStatKeys = std::array<tr_quark, 25>{
TR_KEY_downloadedEver,
TR_KEY_editDate,
TR_KEY_error,
TR_KEY_errorString,
TR_KEY_eta,
TR_KEY_haveUnchecked,
TR_KEY_haveValid,
TR_KEY_isFinished,
TR_KEY_leftUntilDone,
TR_KEY_manualAnnounceTime,
TR_KEY_metadataPercentComplete,
TR_KEY_peersConnected,
TR_KEY_peersGettingFromUs,
TR_KEY_peersSendingToUs,
TR_KEY_percentDone,
TR_KEY_queuePosition,
TR_KEY_rateDownload,
TR_KEY_rateUpload,
TR_KEY_recheckProgress,
TR_KEY_seedRatioLimit,
TR_KEY_seedRatioMode,
TR_KEY_sizeWhenDone,
TR_KEY_status,
TR_KEY_uploadedEver,
TR_KEY_webseedsSendingToUs,
TR_KEY_downloadedEver, //
TR_KEY_editDate, //
TR_KEY_error, //
TR_KEY_errorString, //
TR_KEY_eta, //
TR_KEY_haveUnchecked, //
TR_KEY_haveValid, //
TR_KEY_isFinished, //
TR_KEY_leftUntilDone, //
TR_KEY_manualAnnounceTime, //
TR_KEY_metadataPercentComplete, //
TR_KEY_peersConnected, //
TR_KEY_peersGettingFromUs, //
TR_KEY_peersSendingToUs, //
TR_KEY_percentDone, //
TR_KEY_queuePosition, //
TR_KEY_rateDownload, //
TR_KEY_rateUpload, //
TR_KEY_recheckProgress, //
TR_KEY_seedRatioLimit, //
TR_KEY_seedRatioMode, //
TR_KEY_sizeWhenDone, //
TR_KEY_status, //
TR_KEY_uploadedEver, //
TR_KEY_webseedsSendingToUs, //
};
// unchanging fields needed by the details dialog
@ -757,6 +757,12 @@ void Session::refreshAllTorrents()
void Session::initTorrents(torrent_ids_t const& ids)
{
if (prefs_.getBool(Prefs::SHOW_PIECEBAR))
{
addKeyName(TorrentProperties::MainStats, TR_KEY_pieceCount);
addKeyName(TorrentProperties::MainStats, TR_KEY_pieces);
}
refreshTorrents(ids, TorrentProperties::MainAll);
}

View File

@ -214,6 +214,7 @@ Torrent::fields_t Torrent::update(tr_quark const* keys, tr_variant const* const*
HANDLE_KEY(peersSendingToUs, peers_sending_to_us, PEERS_SENDING_TO_US)
HANDLE_KEY(percentDone, percent_done, PERCENT_DONE)
HANDLE_KEY(pieceCount, piece_count, PIECE_COUNT)
HANDLE_KEY(pieces, pieces_b64, PIECES)
HANDLE_KEY(pieceSize, piece_size, PIECE_SIZE)
HANDLE_KEY(primary_mime_type, primary_mime_type, PRIMARY_MIME_TYPE)
HANDLE_KEY(queuePosition, queue_position, QUEUE_POSITION)
@ -273,6 +274,25 @@ Torrent::fields_t Torrent::update(tr_quark const* keys, tr_variant const* const*
}
break;
case TR_KEY_pieces:
{
auto const ba = QByteArray::fromBase64(pieces_b64_.toLocal8Bit());
pieces_.clear();
for (int i = 0; i < ba.count(); ++i)
{
for (int b = 0; b < 8; b++)
{
if (i * 8 + b >= piece_count_)
{
break;
}
pieces_.emplace_back(ba.at(i) & (1 << (7 - b)));
}
}
break;
}
case TR_KEY_trackers:
{
auto tmp = std::set<QString>{};

View File

@ -291,6 +291,11 @@ public:
return piece_count_;
}
std::vector<bool> const& pieces() const noexcept
{
return pieces_;
}
[[nodiscard]] constexpr auto downloadedEver() const noexcept
{
return downloaded_ever_;
@ -605,6 +610,7 @@ public:
PEERS_SENDING_TO_US,
PEER_LIMIT,
PERCENT_DONE,
PIECES,
PIECE_COUNT,
PIECE_SIZE,
PRIMARY_MIME_TYPE,
@ -704,6 +710,9 @@ private:
Speed upload_speed_;
Speed download_speed_;
std::vector<bool> pieces_ = {};
QString pieces_b64_;
Prefs const& prefs_;
TorrentHash hash_;

View File

@ -17,6 +17,7 @@
#include "Formatter.h"
#include "IconCache.h"
#include "Prefs.h"
#include "StyleHelper.h"
#include "Torrent.h"
#include "TorrentDelegate.h"
@ -26,7 +27,8 @@
enum
{
GUI_PAD = 6,
BAR_HEIGHT = 12
PROGRESS_BAR_HEIGHT = 4,
PIECE_BAR_HEIGHT = 8,
};
namespace
@ -49,6 +51,8 @@ public:
QRect name_rect;
QRect status_rect;
QRect bar_rect;
QRect progress_bar_rect;
QRect piece_bar_rect;
QRect progress_rect;
ItemLayout(
@ -124,8 +128,10 @@ ItemLayout::ItemLayout(
name_rect = base_rect.adjusted(0, 0, 0, name_size.height());
status_rect = name_rect.adjusted(0, name_rect.height() + 1, 0, status_size.height() + 1);
bar_rect = status_rect.adjusted(0, status_rect.height() + 1, 0, BAR_HEIGHT + 1);
progress_rect = bar_rect.adjusted(0, bar_rect.height() + 1, 0, progress_size.height() + 1);
bar_rect = status_rect.adjusted(0, status_rect.height() + 1, 0, PROGRESS_BAR_HEIGHT + PIECE_BAR_HEIGHT + 1);
progress_bar_rect = bar_rect.adjusted(0, 0, 0, -PIECE_BAR_HEIGHT);
piece_bar_rect = bar_rect.adjusted(0, PROGRESS_BAR_HEIGHT + 1, 0, 0);
progress_rect = bar_rect.adjusted(0, bar_rect.height() + 1, 0, progress_size.height());
icon_rect = QStyle::alignedRect(
direction,
Qt::AlignLeft | Qt::AlignVCenter,
@ -140,8 +146,9 @@ ItemLayout::ItemLayout(
} // namespace
TorrentDelegate::TorrentDelegate(QObject* parent)
: QStyledItemDelegate{ parent }
TorrentDelegate::TorrentDelegate(Prefs& prefs, QObject* parent)
: prefs_{ prefs }
, QStyledItemDelegate{ parent }
{
progress_bar_style_.minimum = 0;
progress_bar_style_.maximum = 1000;
@ -570,19 +577,19 @@ void TorrentDelegate::drawTorrent(QPainter* painter, QStyleOptionViewItem const&
painter->drawText(layout.status_rect, Qt::AlignLeft | Qt::AlignVCenter, layout.statusText());
painter->setFont(layout.progress_font);
painter->drawText(layout.progress_rect, Qt::AlignLeft | Qt::AlignVCenter, layout.progressText());
progress_bar_style_.rect = layout.bar_rect;
progress_bar_style_.rect = layout.progress_bar_rect;
if (tor.isDownloading())
{
progress_bar_style_.palette.setBrush(QPalette::Highlight, BlueBrush);
progress_bar_style_.palette.setColor(QPalette::Base, BlueBack);
progress_bar_style_.palette.setColor(QPalette::Window, BlueBack);
progress_bar_style_.palette.setBrush(QPalette::Highlight, FrostedBlueBerries);
progress_bar_style_.palette.setColor(QPalette::Base, BlueTriumph);
progress_bar_style_.palette.setColor(QPalette::Window, BlueTriumph);
}
else if (tor.isSeeding())
{
progress_bar_style_.palette.setBrush(QPalette::Highlight, GreenBrush);
progress_bar_style_.palette.setColor(QPalette::Base, GreenBack);
progress_bar_style_.palette.setColor(QPalette::Window, GreenBack);
progress_bar_style_.palette.setBrush(QPalette::Highlight, GolfCourse);
progress_bar_style_.palette.setColor(QPalette::Base, Verde);
progress_bar_style_.palette.setColor(QPalette::Window, GolfCourse);
}
else
{
@ -594,7 +601,58 @@ void TorrentDelegate::drawTorrent(QPainter* painter, QStyleOptionViewItem const&
progress_bar_style_.state = progress_bar_state;
setProgressBarPercentDone(option, tor);
StyleHelper::drawProgressBar(*style, *painter, progress_bar_style_);
auto const brush = progress_bar_style_.palette.brush(QPalette::Highlight);
float const progress = static_cast<float>(progress_bar_style_.progress) / static_cast<float>(progress_bar_style_.maximum);
bool const piecebar_active = prefs_.getBool(Prefs::SHOW_PIECEBAR);
painter->fillRect(layout.bar_rect, option.palette.color(QPalette::Base));
QRect progress_bar_fill_rect = piecebar_active ? layout.progress_bar_rect : layout.bar_rect;
progress_bar_fill_rect.setWidth(progress * layout.progress_bar_rect.width());
painter->fillRect(progress_bar_fill_rect, brush);
painter->setPen(progress_bar_style_.palette.color(QPalette::Base));
if (piecebar_active)
{
if (progress == 1.0)
{
painter->fillRect(layout.bar_rect, brush);
}
else
{
float const piece_width = static_cast<float>(layout.piece_bar_rect.width() - 3) / tor.pieceCount();
int offset = 0;
int section_width = 0;
for (int i = 0; i < tor.pieceCount(); i++)
{
if (!tor.pieces()[i] || i == tor.pieceCount() - 1)
{
QRect const piece_rect = { layout.piece_bar_rect.left() + offset + 2,
layout.piece_bar_rect.top() + 1,
static_cast<int>(section_width * piece_width + 1),
PIECE_BAR_HEIGHT - 3 };
painter->fillRect(piece_rect, brush);
section_width = 0;
}
else
{
if (section_width == 0)
{
offset = i * piece_width;
}
section_width++;
}
}
painter->drawRect(layout.progress_bar_rect);
}
}
painter->drawRect(layout.bar_rect);
painter->restore();
}

View File

@ -14,6 +14,7 @@
class QStyle;
class QStyleOptionProgressBar;
class Prefs;
class Torrent;
class TorrentDelegate : public QStyledItemDelegate
@ -22,7 +23,7 @@ class TorrentDelegate : public QStyledItemDelegate
TR_DISABLE_COPY_MOVE(TorrentDelegate)
public:
explicit TorrentDelegate(QObject* parent = nullptr);
explicit TorrentDelegate(Prefs& prefs, QObject* parent = nullptr);
// QAbstractItemDelegate
QSize sizeHint(QStyleOptionViewItem const& option, QModelIndex const& index) const override;
@ -42,16 +43,18 @@ protected:
static QString shortStatusString(Torrent const& tor);
static QString shortTransferString(Torrent const& tor);
QColor const BlueBack{ "lightgrey" };
QColor const BlueBrush{ "steelblue" };
QColor const GreenBack{ "darkseagreen" };
QColor const GreenBrush{ "forestgreen" };
QColor const FrostedBlueBerries{ "#1847d4" };
QColor const BlueTriumph{ "#5379a9" };
QColor const Verde{ "#62be79" };
QColor const GolfCourse{ "#26a955" };
QColor const SilverBack{ "grey" };
QColor const SilverBrush{ "silver" };
mutable QStyleOptionProgressBar progress_bar_style_ = {};
private:
Prefs& prefs_;
mutable std::optional<int> height_hint_;
mutable QFont height_font_;
mutable QIcon warning_emblem_;

View File

@ -29,7 +29,7 @@ enum
{
GUI_PAD = 6,
BAR_WIDTH = 50,
BAR_HEIGHT = 16,
PROGRESS_BAR_HEIGHT = 16,
LINE_SPACING = 4
};
@ -54,7 +54,7 @@ public:
QRect emblem_rect;
QRect name_rect;
QRect status_rect;
QRect bar_rect;
QRect progress_bar_rect;
ItemLayout(
QString name_text,
@ -67,7 +67,7 @@ public:
[[nodiscard]] QSize size() const
{
return (icon_rect | name_rect | status_rect | bar_rect).size();
return (icon_rect | name_rect | status_rect | progress_bar_rect).size();
}
[[nodiscard]] QString nameText() const
@ -114,7 +114,7 @@ ItemLayout::ItemLayout(
QSize const status_size(status_fm.size(0, status_text_));
QStyleOptionProgressBar bar_style;
bar_style.rect = QRect{ 0, 0, BAR_WIDTH, BAR_HEIGHT };
bar_style.rect = QRect{ 0, 0, BAR_WIDTH, PROGRESS_BAR_HEIGHT };
bar_style.maximum = 100;
bar_style.progress = 100;
bar_style.textVisible = true;
@ -131,8 +131,8 @@ ItemLayout::ItemLayout(
Qt::AlignRight | Qt::AlignBottom,
emblem_icon.actualSize(icon_rect.size() / 2, QIcon::Normal, QIcon::On),
icon_rect);
bar_rect = QStyle::alignedRect(direction, Qt::AlignRight | Qt::AlignVCenter, bar_size, base_rect);
Utils::narrowRect(base_rect, icon_rect.width() + GUI_PAD, bar_rect.width() + GUI_PAD, direction);
progress_bar_rect = QStyle::alignedRect(direction, Qt::AlignRight | Qt::AlignVCenter, bar_size, base_rect);
Utils::narrowRect(base_rect, icon_rect.width() + GUI_PAD, progress_bar_rect.width() + GUI_PAD, direction);
status_rect = QStyle::alignedRect(
direction,
Qt::AlignRight | Qt::AlignVCenter,
@ -244,19 +244,19 @@ void TorrentDelegateMin::drawTorrent(QPainter* painter, QStyleOptionViewItem con
painter->drawText(layout.name_rect, Qt::AlignLeft | Qt::AlignVCenter, layout.nameText());
painter->setFont(layout.status_font);
painter->drawText(layout.status_rect, Qt::AlignLeft | Qt::AlignVCenter, layout.statusText());
progress_bar_style_.rect = layout.bar_rect;
progress_bar_style_.rect = layout.progress_bar_rect;
if (tor.isDownloading())
{
progress_bar_style_.palette.setBrush(QPalette::Highlight, BlueBrush);
progress_bar_style_.palette.setColor(QPalette::Base, BlueBack);
progress_bar_style_.palette.setColor(QPalette::Window, BlueBack);
progress_bar_style_.palette.setBrush(QPalette::Highlight, FrostedBlueBerries);
progress_bar_style_.palette.setColor(QPalette::Base, BlueTriumph);
progress_bar_style_.palette.setColor(QPalette::Window, BlueTriumph);
}
else if (tor.isSeeding())
{
progress_bar_style_.palette.setBrush(QPalette::Highlight, GreenBrush);
progress_bar_style_.palette.setColor(QPalette::Base, GreenBack);
progress_bar_style_.palette.setColor(QPalette::Window, GreenBack);
progress_bar_style_.palette.setBrush(QPalette::Highlight, GolfCourse);
progress_bar_style_.palette.setColor(QPalette::Base, Verde);
progress_bar_style_.palette.setColor(QPalette::Window, GolfCourse);
}
else
{
@ -270,7 +270,21 @@ void TorrentDelegateMin::drawTorrent(QPainter* painter, QStyleOptionViewItem con
progress_bar_style_.textVisible = true;
progress_bar_style_.textAlignment = Qt::AlignCenter;
setProgressBarPercentDone(option, tor);
StyleHelper::drawProgressBar(*style, *painter, progress_bar_style_);
auto const brush = progress_bar_style_.palette.brush(QPalette::Highlight);
float const progress = static_cast<float>(progress_bar_style_.progress) / static_cast<float>(progress_bar_style_.maximum);
painter->fillRect(layout.progress_bar_rect, option.palette.color(QPalette::Base));
QRect progress_bar_fill_rect = layout.progress_bar_rect;
progress_bar_fill_rect.setWidth(progress * layout.progress_bar_rect.width());
painter->fillRect(progress_bar_fill_rect, brush);
painter->setPen(progress_bar_style_.palette.color(QPalette::Base));
painter->drawRect(layout.progress_bar_rect);
painter->setPen(progress_bar_style_.palette.color(QPalette::Text));
painter->drawText(layout.progress_bar_rect, progress_bar_style_.text, QTextOption{ Qt::AlignCenter });
painter->restore();
}

View File

@ -15,8 +15,8 @@ class TorrentDelegateMin : public TorrentDelegate
TR_DISABLE_COPY_MOVE(TorrentDelegateMin)
public:
explicit TorrentDelegateMin(QObject* parent = nullptr)
: TorrentDelegate{ parent }
explicit TorrentDelegateMin(Prefs& prefs, QObject* parent = nullptr)
: TorrentDelegate{ prefs, parent }
{
}