fix: Padding for Toolbar Text, New Shelf Grid View UI

This commit is contained in:
collecting
2026-04-05 23:18:09 -04:00
parent 256c924de8
commit 8e68d7c780
8 changed files with 399 additions and 94 deletions
+5
View File
@@ -691,6 +691,11 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
image: url(:/overlay/osk_button_Y_disabled.png);
}
QMenuBar::item {
background-color: transparent;
padding: 18px 18px;
}
/*
* Adaptive Dropdown Menu Styling
*/
+1 -1
View File
@@ -695,7 +695,7 @@ QMenuBar {
QMenuBar::item {
background-color: transparent;
padding: 4px 10px;
padding: 18px 18px;
color: #d0d0d0;
}
+1 -1
View File
@@ -164,7 +164,7 @@ QMenuBar {
QMenuBar::item {
background: transparent;
padding: 4px 10px;
padding: 18px 18px;
}
QMenuBar::item:selected {
+1 -1
View File
@@ -374,7 +374,7 @@ QMenuBar {
QMenuBar::item {
background: transparent;
padding: 4px 10px;
padding: 18px 18px;
color: #eff0f1; /* Explicitly set item text color */
}
+117 -42
View File
@@ -1,3 +1,4 @@
#include <cmath>
#include <QApplication>
#include <QFont>
#include <QFontMetrics>
@@ -10,6 +11,7 @@
#include <QStyle>
#include <QStyleOptionViewItem>
#include <QTimer>
#include <QTransform>
#include "citron/game_grid_delegate.h"
#include "citron/game_list_p.h"
@@ -29,23 +31,28 @@ void GameGridDelegate::setGridMode(GridMode mode) {
m_grid_mode = mode;
}
QSize GameGridDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const {
QSize GameGridDelegate::sizeHint(const QStyleOptionViewItem& option,
const QModelIndex& index) const {
const int icon_size = UISettings::values.game_icon_size.GetValue();
const float scale = static_cast<float>(icon_size) / 128.0f;
return QSize(icon_size + static_cast<int>(40 * scale), icon_size + static_cast<int>(85 * scale));
return QSize(icon_size + static_cast<int>(40 * scale),
icon_size + static_cast<int>(104 * scale));
}
void GameGridDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
const QModelIndex& index) const {
if (!index.isValid()) return;
const QModelIndex& index) const {
if (!index.isValid())
return;
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing |
QPainter::SmoothPixmapTransform);
PaintGridItem(painter, option, index);
painter->restore();
}
void GameGridDelegate::AdvanceAnimations() {
if (!m_view || !m_view->isVisible()) return;
if (!m_view || !m_view->isVisible())
return;
auto it_pulse = m_pulse_states.begin();
while (it_pulse != m_pulse_states.end()) {
@@ -59,10 +66,12 @@ void GameGridDelegate::AdvanceAnimations() {
bool& dir = m_pulse_direction[key];
if (dir) {
val += 0.04;
if (val >= 1.0) dir = false;
if (val >= 1.0)
dir = false;
} else {
val -= 0.04;
if (val <= 0.0) dir = true;
if (val <= 0.0)
dir = true;
}
++it_pulse;
}
@@ -77,7 +86,8 @@ void GameGridDelegate::AdvanceAnimations() {
qreal& val = it_entry.value();
if (val < 1.0) {
val += 0.06;
if (val >= 1.0) val = 1.0;
if (val >= 1.0)
val = 1.0;
++it_entry;
} else {
it_entry = m_entry_animations.erase(it_entry);
@@ -88,7 +98,8 @@ void GameGridDelegate::AdvanceAnimations() {
m_population_fade_global -= 0.02;
} else if (!m_is_populating && m_population_fade_global < 1.0) {
m_population_fade_global += 0.03;
if (m_population_fade_global > 1.0) m_population_fade_global = 1.0;
if (m_population_fade_global > 1.0)
m_population_fade_global = 1.0;
}
m_pulse_tick++;
@@ -96,7 +107,7 @@ void GameGridDelegate::AdvanceAnimations() {
}
void GameGridDelegate::PaintGridItem(QPainter* painter, const QStyleOptionViewItem& option,
const QModelIndex& index) const {
const QModelIndex& index) const {
const bool is_selected = option.state & QStyle::State_Selected;
QRect rect = option.rect;
const int icon_size = UISettings::values.game_icon_size.GetValue();
@@ -104,8 +115,9 @@ void GameGridDelegate::PaintGridItem(QPainter* painter, const QStyleOptionViewIt
qreal entry_val = 1.0;
const QPersistentModelIndex key(index);
if (m_entry_animations.contains(key)) entry_val = m_entry_animations[key];
if (m_entry_animations.contains(key))
entry_val = m_entry_animations[key];
qreal final_opacity = entry_val * m_population_fade_global;
painter->setOpacity(final_opacity);
@@ -116,23 +128,69 @@ void GameGridDelegate::PaintGridItem(QPainter* painter, const QStyleOptionViewIt
const int radius = static_cast<int>(14 * scale);
painter->save();
if (is_selected) {
double time_t = m_pulse_tick * 0.032;
double hover_y = std::sin(time_t* 3.0) * (4.0 * scale);
double yaw_angle = std::sin(time_t* 2.5) * 20.0;
double pitch_angle = std::cos(time_t* 1.5) * 10.0;
painter->translate(rect.center());
QTransform transform;
transform.scale(1.04, 1.04);
transform.translate(0, hover_y);
QTransform rot;
rot.rotate(yaw_angle, Qt::YAxis);
rot.rotate(pitch_angle, Qt::XAxis);
painter->setTransform(rot * transform, true);
painter->translate(-rect.center());
// --- 1. Selection Glow ---
QColor glow = AccentColor();
glow.setAlphaF(0.2f);
painter->save();
glow.setAlphaF(0.12f);
painter->setBrush(glow);
painter->setPen(Qt::NoPen);
painter->drawRoundedRect(card_rect.adjusted(static_cast<int>(-4 * scale), static_cast<int>(-4 * scale),
static_cast<int>(4 * scale), static_cast<int>(4 * scale)),
painter->drawRoundedRect(card_rect.adjusted(-4 * scale, -4 * scale, 4 * scale, 4 * scale),
radius + 2, radius + 2);
painter->restore();
}
QColor onyx(22, 22, 26);
painter->setPen(Qt::NoPen);
painter->setBrush(onyx);
painter->setPen(Qt::NoPen);
painter->drawRoundedRect(card_rect, radius, radius);
{
painter->save();
int pin_count = 12;
qreal total_w = card_rect.width() * 0.85;
qreal pin_w = (total_w / pin_count) * 0.4;
qreal spacing = total_w / (pin_count - 1);
qreal start_x = card_rect.left() + (card_rect.width() - total_w) / 2.0;
for (int i = 0; i < pin_count; ++i) {
QRectF pr(start_x + (i * spacing) - (pin_w / 2.0), card_rect.bottom() - (18 * scale),
pin_w, 14 * scale);
QLinearGradient pg(pr.topLeft(), pr.bottomLeft());
pg.setColorAt(0, QColor(10, 10, 12));
pg.setColorAt(0.35, QColor(220, 200, 120)); // Bright Metallic Gold
pg.setColorAt(0.65, QColor(160, 140, 70));
pg.setColorAt(1, QColor(25, 25, 30));
painter->setBrush(pg);
painter->setPen(QPen(QColor(0, 0, 0, 180), 0.3 * scale));
painter->drawRoundedRect(pr, 1 * scale, 1 * scale);
painter->setPen(QPen(QColor(255, 255, 255, 50), 0.5 * scale));
painter->drawLine(pr.left() + pr.width() * 0.2, pr.top() + pr.height() * 0.2,
pr.left() + pr.width() * 0.2, pr.top() + pr.height() * 0.5);
}
painter->restore();
}
if (is_selected) {
QColor border = AccentColor();
qreal pulse = (m_pulse_states.contains(key)) ? m_pulse_states[key] : 0.0;
@@ -146,19 +204,24 @@ void GameGridDelegate::PaintGridItem(QPainter* painter, const QStyleOptionViewIt
label_path.addRoundedRect(label_rect, radius - 6, radius - 6);
// --- Favorites Indicator ---
bool is_fav = (index.data(GameListItem::TypeRole).toInt() == static_cast<int>(GameListItemType::Favorites));
bool is_fav = (index.data(GameListItem::TypeRole).toInt() ==
static_cast<int>(GameListItemType::Favorites));
if (is_fav) {
painter->save();
QColor fav_gold(255, 215, 0, 220); // Vibrant Gold
painter->setPen(QPen(fav_gold, 1.2f * scale));
painter->setBrush(QColor(40, 40, 45, 180));
qreal star_size = 22.0f * scale;
QRectF star_rect(card_rect.right() - (10.0f * scale) - star_size, card_rect.top() + (10.0f * scale),
star_size, star_size);
QRectF star_rect(card_rect.right() - (10.0f * scale) - star_size,
card_rect.top() + (10.0f * scale), star_size, star_size);
painter->drawRoundedRect(star_rect, 6 * scale, 6 * scale);
painter->setPen(fav_gold);
QFont sf = painter->font(); sf.setBold(true); sf.setPointSizeF(11.0f * scale); painter->setFont(sf);
painter->drawText(star_rect.adjusted(0, -1 * scale, 0, 0), Qt::AlignCenter, QStringLiteral(""));
QFont sf = painter->font();
sf.setBold(true);
sf.setPointSizeF(11.0f * scale);
painter->setFont(sf);
painter->drawText(star_rect.adjusted(0, -1 * scale, 0, 0), Qt::AlignCenter,
QStringLiteral(""));
painter->restore();
}
@@ -166,15 +229,17 @@ void GameGridDelegate::PaintGridItem(QPainter* painter, const QStyleOptionViewIt
painter->save();
painter->setClipPath(label_path);
qreal bar_h = 28.0f * scale;
QRectF bottom_bar(label_rect.left(), label_rect.bottom() - bar_h, label_rect.width(), bar_h);
painter->fillRect(bottom_bar, QColor(10, 10, 12));
QPixmap pixmap = index.data(GameListItemPath::HighResIconRole).value<QPixmap>();
if (pixmap.isNull()) pixmap = index.data(Qt::DecorationRole).value<QPixmap>();
if (pixmap.isNull())
pixmap = index.data(Qt::DecorationRole).value<QPixmap>();
if (!pixmap.isNull()) {
QRectF mid_area(label_rect.left(), label_rect.top(), label_rect.width(), bottom_bar.top() - label_rect.top());
QRectF mid_area(label_rect.left(), label_rect.top(), label_rect.width(),
bottom_bar.top() - label_rect.top());
painter->drawPixmap(mid_area, pixmap, pixmap.rect());
}
@@ -188,27 +253,37 @@ void GameGridDelegate::PaintGridItem(QPainter* painter, const QStyleOptionViewIt
QRectF text_rect = bottom_bar.adjusted(10 * scale, 0, -10 * scale, 0);
QString elided = painter->fontMetrics().elidedText(title, Qt::ElideRight, text_rect.width());
painter->drawText(text_rect, Qt::AlignCenter, elided);
painter->restore();
int pins_y = card_rect.bottom() - static_cast<int>(10 * scale);
int p_c = 6;
int p_w = (card_rect.width() - static_cast<int>(40 * scale)) / p_c;
painter->setOpacity(0.8 * final_opacity);
for (int i = 0; i < p_c; ++i) {
painter->fillRect(card_rect.left() + static_cast<int>(20 * scale) + i * p_w, pins_y, p_w - static_cast<int>(6 * scale), static_cast<int>(6 * scale), QColor(40, 40, 45));
}
painter->restore();
}
QColor GameGridDelegate::CardBg() const { return QColor(22, 22, 26); }
QColor GameGridDelegate::TextColor() const { return QColor(255, 255, 255); }
QColor GameGridDelegate::DimColor() const { return QColor(120, 120, 130); }
QColor GameGridDelegate::SelectionColor() const { return QColor(35, 35, 40); }
QColor GameGridDelegate::CardBg() const {
return QColor(22, 22, 26);
}
QColor GameGridDelegate::TextColor() const {
return QColor(255, 255, 255);
}
QColor GameGridDelegate::DimColor() const {
return QColor(120, 120, 130);
}
QColor GameGridDelegate::SelectionColor() const {
return QColor(35, 35, 40);
}
QColor GameGridDelegate::AccentColor() const {
const QString hex = QString::fromStdString(UISettings::values.accent_color.GetValue());
return QColor(hex).isValid() ? QColor(hex) : QColor(0, 150, 255);
}
void GameGridDelegate::SetPopulating(bool populating) { m_is_populating = populating; }
void GameGridDelegate::RegisterEntryAnimation(const QModelIndex& index) { if (index.isValid()) m_entry_animations[QPersistentModelIndex(index)] = 0.0; }
void GameGridDelegate::ClearAnimations() { m_entry_animations.clear(); m_pulse_states.clear(); }
void GameGridDelegate::SetPopulating(bool populating) {
m_is_populating = populating;
}
void GameGridDelegate::RegisterEntryAnimation(const QModelIndex& index) {
if (index.isValid())
m_entry_animations[QPersistentModelIndex(index)] = 0.0;
}
void GameGridDelegate::ClearAnimations() {
m_entry_animations.clear();
m_pulse_states.clear();
}
+11 -2
View File
@@ -1398,9 +1398,17 @@ GameList::GameList(std::shared_ptr<FileSys::VfsFilesystem> vfs_,
else
current = carousel_view->view()->currentIndex();
if (!current.isValid() && !pathName.isEmpty()) {
// Attempt to find the index if the view lost focus
auto matches = item_model->match(item_model->index(0, 0), GameListItemPath::FullPathRole, pathName, 1, Qt::MatchExactly | Qt::MatchRecursive);
if (!matches.isEmpty()) {
current = matches.first();
}
}
if (current.isValid()) {
StartLaunchAnimation(current);
} else {
} else if (!pathName.isEmpty()) {
emit BootGame(pathName, StartGameType::Normal);
}
} else if (action == QStringLiteral("favorite")) {
@@ -2096,7 +2104,8 @@ void GameList::ValidateEntry(const QModelIndex& item) {
}
const auto selected = item.sibling(item.row(), 0);
switch (selected.data(GameListItem::TypeRole).value<GameListItemType>()) {
case GameListItemType::Game: {
case GameListItemType::Game:
case GameListItemType::Favorites: {
const QString file_path = selected.data(GameListItemPath::FullPathRole).toString();
if (file_path.isEmpty())
return;
+262 -47
View File
@@ -1,21 +1,151 @@
#include <QAbstractItemModel>
#include <QItemSelectionModel>
#include <QLabel>
#include <QResizeEvent>
#include <QScrollBar>
#include <QWheelEvent>
#include <QAbstractItemModel>
#include <QLabel>
#include <QItemSelectionModel>
#include <QColor>
#include <QGraphicsDropShadowEffect>
#include <QLinearGradient>
#include <QList>
#include <QListView>
#include <QPaintEvent>
#include <QPainter>
#include <QPen>
#include <QRect>
#include <QScrollArea>
#include "citron/ui/game_grid_view.h"
#include <QTimer>
#include <QWidget>
#include "citron/game_grid_delegate.h"
#include "citron/game_list_p.h"
#include "citron/ui/game_grid_view.h"
#include "citron/uisettings.h"
class WoodBackgroundContainer : public QWidget {
public:
using QWidget::QWidget;
protected:
void paintEvent(QPaintEvent* e) override {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, false);
int w = width();
painter.fillRect(e->rect(), QColor(16, 8, 3));
int panel_w = 90;
for (int x = 0; x < w; x += panel_w) {
QRect panel_rect(x, e->rect().top(), panel_w, e->rect().height());
QLinearGradient panel_grad(x, 0, x + panel_w, 0);
int var = (x / panel_w) % 3;
QColor base_color = (var == 0) ? QColor(36, 18, 8)
: (var == 1) ? QColor(30, 14, 6)
: QColor(40, 20, 9);
panel_grad.setColorAt(0.0, base_color);
panel_grad.setColorAt(0.2, base_color.lighter(105));
panel_grad.setColorAt(0.8, base_color.darker(110));
panel_grad.setColorAt(1.0, QColor(10, 4, 1, 150));
painter.fillRect(panel_rect, panel_grad);
painter.setPen(QPen(QColor(15, 6, 2, 60), 1));
for (int line = 1; line < 4; ++line) {
int lx = x + line * (panel_w / 4) + (var * 2);
painter.drawLine(lx, e->rect().top(), lx, e->rect().bottom());
}
}
}
};
class ContentHeightListView : public QListView {
public:
using QListView::QListView;
protected:
void wheelEvent(QWheelEvent* e) override { e->ignore(); }
void wheelEvent(QWheelEvent* e) override {
e->ignore();
}
void paintEvent(QPaintEvent* e) override {
QPainter painter(this->viewport());
painter.setRenderHint(QPainter::Antialiasing, false);
int w = viewport()->width();
if (this->model() && this->model()->rowCount() > 0) {
int icon_size = UISettings::values.game_icon_size.GetValue();
float scale = static_cast<float>(icon_size) / 128.0f;
int card_h = icon_size + static_cast<int>(64 * scale);
QList<int> row_tops;
for (int i = 0; i < this->model()->rowCount(); ++i) {
QRect r = this->visualRect(this->model()->index(i, 0));
// If any part of the row's indicator item is visible or near visible, collect its
// row Y
if (r.isValid() && r.bottom() >= -200 && r.top() <= viewport()->height() + 200) {
if (!row_tops.contains(r.y())) {
row_tops.append(r.y());
}
}
}
const int shelf_hl = qMax(3, static_cast<int>(5 * scale));
const int shelf_edge = qMax(1, static_cast<int>(2 * scale));
for (int ry : row_tops) {
int shelf_y = ry + static_cast<int>(12 * scale) + card_h;
int item_h = icon_size + static_cast<int>(104 * scale);
int shelf_h = ry + item_h - shelf_y;
QRect shelf_rect(0, shelf_y, w, shelf_h);
// Drop shadow from back edge
QLinearGradient back_shadow(0, shelf_y, 0, shelf_y - 12 * scale);
back_shadow.setColorAt(0.0, QColor(0, 0, 0, 100));
back_shadow.setColorAt(1.0, Qt::transparent);
painter.fillRect(QRect(0, shelf_y - 12 * scale, w, 12 * scale), back_shadow);
painter.fillRect(QRect(0, shelf_y, w, qMax(1, static_cast<int>(4 * scale))),
QColor(0, 0, 0, 180));
QLinearGradient wood_grad(0, shelf_y, 0, shelf_y + shelf_h);
wood_grad.setColorAt(0.00, QColor(110, 65, 20));
wood_grad.setColorAt(0.25, QColor(88, 50, 14));
wood_grad.setColorAt(0.65, QColor(65, 34, 8));
wood_grad.setColorAt(1.00, QColor(42, 22, 4));
painter.fillRect(shelf_rect, wood_grad);
painter.save();
painter.setClipRect(shelf_rect);
for (int g = 0; g < 6; ++g) {
int gy = shelf_y + (shelf_h * g) / 6;
int alpha = (g % 2 == 0) ? 28 : 14;
painter.setPen(QPen(QColor(180, 110, 40, alpha),
qMax(0.8, 0.8 * static_cast<double>(scale))));
painter.drawLine(0, gy, w, gy + qMax(1, static_cast<int>(2 * scale)));
}
painter.restore();
QLinearGradient hl_grad(0, shelf_y, 0, shelf_y + shelf_hl);
hl_grad.setColorAt(0.0, QColor(215, 145, 58, 245));
hl_grad.setColorAt(0.6, QColor(175, 105, 35, 120));
hl_grad.setColorAt(1.0, QColor(140, 80, 22, 0));
painter.setPen(Qt::NoPen);
painter.setBrush(hl_grad);
painter.drawRect(QRect(0, shelf_y, w, shelf_hl));
painter.fillRect(QRect(0, shelf_rect.bottom() - shelf_edge + 1, w, shelf_edge),
QColor(10, 4, 1, 220));
}
}
QListView::paintEvent(e);
}
};
GameGridView::GameGridView(QWidget* parent) : QWidget(parent) {
@@ -26,14 +156,17 @@ GameGridView::GameGridView(QWidget* parent) : QWidget(parent) {
m_scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_scroll_area->setStyleSheet(QStringLiteral("QScrollArea { background: transparent; }"));
m_container = new QWidget(m_scroll_area);
m_container = new WoodBackgroundContainer(m_scroll_area);
m_layout = new QVBoxLayout(m_container);
m_layout->setContentsMargins(0, 20, 0, 20);
m_layout->setSpacing(0);
m_top_help = new QLabel(m_container);
m_top_help->setText(tr("if using controller* Press X for Next Alphabetical Letter | Press -/R/ZR for Details Tab | Press B for Back to List"));
m_top_help->setStyleSheet(QStringLiteral("QLabel { color: rgba(255, 255, 255, 140); font-weight: bold; font-family: 'Outfit', 'Inter', sans-serif; font-size: 14px; }"));
m_top_help->setText(tr("if using controller* Press X for Next Alphabetical Letter | Press "
"-/R/ZR for Details Tab | Press B for Back to List"));
m_top_help->setStyleSheet(
QStringLiteral("QLabel { color: rgba(255, 255, 255, 140); font-weight: bold; font-family: "
"'Outfit', 'Inter', sans-serif; font-size: 14px; }"));
m_top_help->setAlignment(Qt::AlignCenter);
m_layout->addSpacing(10);
m_layout->addWidget(m_top_help);
@@ -55,26 +188,55 @@ GameGridView::GameGridView(QWidget* parent) : QWidget(parent) {
delegate = new GameGridDelegate(view, this);
view->setItemDelegate(delegate);
connect(view, &QListView::activated, this, &GameGridView::itemActivated);
connect(view, &QListView::doubleClicked, this, &GameGridView::itemActivated);
};
m_fav_label = new QLabel(tr("★ FAVORITES"), m_container);
m_fav_label->setStyleSheet(QStringLiteral("QLabel { color: #ffd700; font-weight: bold; font-size: 18px; padding-left: 24px; margin-bottom: 10px; }"));
m_fav_label = new QLabel(tr(" FAVORITES"), m_container);
m_fav_label->setStyleSheet(QStringLiteral(
"QLabel { color: #f5f5f5; font-weight: bold; font-size: 16px; "
"padding: 8px 0px 6px 28px; "
"border-bottom: 2px solid rgba(255, 255, 255, 90); background: transparent; }"));
QGraphicsDropShadowEffect* fav_shadow = new QGraphicsDropShadowEffect(m_fav_label);
fav_shadow->setBlurRadius(3);
fav_shadow->setOffset(1, 1);
fav_shadow->setColor(QColor(0, 0, 0, 255));
m_fav_label->setGraphicsEffect(fav_shadow);
m_layout->addWidget(m_fav_label);
setupView(m_fav_view, m_fav_delegate);
m_fav_view->setStyleSheet(
QStringLiteral("QListView { background: transparent; border: none; }"
"QListView::item { background: transparent; }"
"QListView::item:hover { background: transparent; }"
"QListView::item:selected { background: transparent; }"));
m_layout->addWidget(m_fav_view);
m_main_label = new QLabel(tr("ALL GAMES"), m_container);
m_main_label->setStyleSheet(QStringLiteral("QLabel { color: #0096ff; font-weight: bold; font-size: 18px; padding-left: 24px; margin-top: 20px; margin-bottom: 10px; }"));
m_main_label->setStyleSheet(
QStringLiteral("QLabel { color: #f5f5f5; font-weight: bold; font-size: 16px; "
"padding: 8px 0px 6px 28px; "
"border-bottom: 2px solid rgba(255, 255, 255, 90); background: transparent; "
"margin-top: 18px; }"));
QGraphicsDropShadowEffect* main_shadow = new QGraphicsDropShadowEffect(m_main_label);
main_shadow->setBlurRadius(3);
main_shadow->setOffset(1, 1);
main_shadow->setColor(QColor(0, 0, 0, 255));
m_main_label->setGraphicsEffect(main_shadow);
m_layout->addWidget(m_main_label);
setupView(m_main_view, m_main_delegate);
m_main_view->setStyleSheet(
QStringLiteral("QListView { background: transparent; border: none; }"
"QListView::item { background: transparent; }"
"QListView::item:hover { background: transparent; }"
"QListView::item:selected { background: transparent; }"));
m_layout->addWidget(m_main_view);
m_bottom_hint = new QLabel(m_container);
m_bottom_hint->setText(tr("*You can use your Mouse Wheel or the Scrollbar to navigate the Grid View*"));
m_bottom_hint->setStyleSheet(QStringLiteral("QLabel { color: rgba(255, 255, 255, 100); font-style: italic; font-size: 13px; }"));
m_bottom_hint->setText(
tr("*You can use your Mouse Wheel or the Scrollbar to navigate the Grid View*"));
m_bottom_hint->setStyleSheet(QStringLiteral(
"QLabel { color: rgba(255, 255, 255, 100); font-style: italic; font-size: 13px; }"));
m_bottom_hint->setAlignment(Qt::AlignCenter);
m_layout->addWidget(m_bottom_hint);
m_scroll_area->setWidget(m_container);
QVBoxLayout* main_layout = new QVBoxLayout(this);
main_layout->setContentsMargins(0, 0, 0, 0);
@@ -84,12 +246,26 @@ GameGridView::GameGridView(QWidget* parent) : QWidget(parent) {
}
void GameGridView::ApplyTheme() {
QString style = QStringLiteral(
m_container->setAutoFillBackground(false);
m_scroll_area->setAutoFillBackground(false);
if (m_scroll_area->viewport()) {
m_scroll_area->viewport()->setAutoFillBackground(false);
QPalette vpal = m_scroll_area->viewport()->palette();
vpal.setColor(QPalette::Base, Qt::transparent);
vpal.setColor(QPalette::Window, Qt::transparent);
m_scroll_area->viewport()->setPalette(vpal);
}
m_scroll_area->setStyleSheet(
QStringLiteral("QScrollArea { background: transparent; border: none; } QScrollArea > "
"QWidget > QWidget { background: transparent; }"));
QString list_style = QStringLiteral(
"QListView { background: transparent; border: none; outline: 0; padding: 0px; }"
"QListView::item { padding: 0px; margin: 0px; background: transparent; }"
);
m_fav_view->setStyleSheet(style);
m_main_view->setStyleSheet(style);
"QListView::item:hover { background: transparent; }"
"QListView::item:selected { background: transparent; }");
m_fav_view->setStyleSheet(list_style);
m_main_view->setStyleSheet(list_style);
}
void GameGridView::setModels(QAbstractItemModel* fav_model, QAbstractItemModel* main_model) {
@@ -101,8 +277,8 @@ void GameGridView::setModels(QAbstractItemModel* fav_model, QAbstractItemModel*
m_fav_view->setVisible(has_favs);
if (m_fav_view->selectionModel()) {
connect(m_fav_view->selectionModel(), &QItemSelectionModel::currentChanged,
this, [this](const QModelIndex& current) {
connect(m_fav_view->selectionModel(), &QItemSelectionModel::currentChanged, this,
[this](const QModelIndex& current) {
if (current.isValid()) {
emit itemSelectionChanged(current);
m_main_view->clearSelection();
@@ -111,8 +287,8 @@ void GameGridView::setModels(QAbstractItemModel* fav_model, QAbstractItemModel*
});
}
if (m_main_view->selectionModel()) {
connect(m_main_view->selectionModel(), &QItemSelectionModel::currentChanged,
this, [this](const QModelIndex& current) {
connect(m_main_view->selectionModel(), &QItemSelectionModel::currentChanged, this,
[this](const QModelIndex& current) {
if (current.isValid()) {
emit itemSelectionChanged(current);
m_fav_view->clearSelection();
@@ -124,20 +300,25 @@ void GameGridView::setModels(QAbstractItemModel* fav_model, QAbstractItemModel*
}
QModelIndex GameGridView::currentIndex() const {
if (m_fav_view->hasFocus()) return m_fav_view->currentIndex();
if (m_fav_view->hasFocus())
return m_fav_view->currentIndex();
return m_main_view->currentIndex();
}
void GameGridView::setCurrentIndex(const QModelIndex& index) {
if (index.model() == m_fav_view->model()) m_fav_view->setCurrentIndex(index);
else m_main_view->setCurrentIndex(index);
if (index.model() == m_fav_view->model())
m_fav_view->setCurrentIndex(index);
else
m_main_view->setCurrentIndex(index);
}
QModelIndex GameGridView::indexAt(const QPoint& p) const {
QPoint fp = m_fav_view->mapFrom(this, p);
if (m_fav_view->rect().contains(fp)) return m_fav_view->indexAt(fp);
if (m_fav_view->rect().contains(fp))
return m_fav_view->indexAt(fp);
QPoint mp = m_main_view->mapFrom(this, p);
if (m_main_view->rect().contains(mp)) return m_main_view->indexAt(mp);
if (m_main_view->rect().contains(mp))
return m_main_view->indexAt(mp);
return QModelIndex();
}
@@ -146,18 +327,22 @@ void GameGridView::setControllerFocus(bool focus) {
if (focus) {
if (m_fav_view->isVisible() && m_fav_view->model()->rowCount() > 0) {
m_fav_view->setFocus();
if (!m_fav_view->currentIndex().isValid()) m_fav_view->setCurrentIndex(m_fav_view->model()->index(0, 0));
if (!m_fav_view->currentIndex().isValid())
m_fav_view->setCurrentIndex(m_fav_view->model()->index(0, 0));
} else {
m_main_view->setFocus();
if (!m_main_view->currentIndex().isValid()) m_main_view->setCurrentIndex(m_main_view->model()->index(0, 0));
if (!m_main_view->currentIndex().isValid())
m_main_view->setCurrentIndex(m_main_view->model()->index(0, 0));
}
}
}
void GameGridView::onNavigated(int dx, int dy) {
if (!m_has_focus) return;
if (!m_has_focus)
return;
QListView* current = m_fav_view->hasFocus() ? m_fav_view : m_main_view;
if (!current->model()) return;
if (!current->model())
return;
QModelIndex idx = current->currentIndex();
if (!idx.isValid()) {
@@ -176,14 +361,19 @@ void GameGridView::onNavigated(int dx, int dy) {
}
if (dy < 0 && row < cols && current == m_main_view && m_fav_view->isVisible()) {
m_fav_view->setFocus();
m_fav_view->setCurrentIndex(m_fav_view->model()->index(m_fav_view->model()->rowCount() - 1, 0));
m_fav_view->setCurrentIndex(
m_fav_view->model()->index(m_fav_view->model()->rowCount() - 1, 0));
return;
}
if (dx > 0) row++;
else if (dx < 0) row--;
if (dy > 0) row += cols;
else if (dy < 0) row -= cols;
if (dx > 0)
row++;
else if (dx < 0)
row--;
if (dy > 0)
row += cols;
else if (dy < 0)
row -= cols;
row = qBound(0, row, total - 1);
current->setCurrentIndex(current->model()->index(row, 0));
@@ -191,9 +381,11 @@ void GameGridView::onNavigated(int dx, int dy) {
}
void GameGridView::onActivated() {
if (!m_has_focus) return;
if (!m_has_focus)
return;
QModelIndex cur = currentIndex();
if (cur.isValid()) emit itemActivated(cur);
if (cur.isValid())
emit itemActivated(cur);
}
void GameGridView::onCancelled() {
@@ -210,9 +402,11 @@ void GameGridView::keyPressEvent(QKeyEvent* event) {
m_main_view->setCurrentIndex(m_main_view->model()->index(0, 0));
return;
}
if (!current->model()) return;
if (!current->model())
return;
QModelIndex cur = current->currentIndex();
if (!cur.isValid()) return;
if (!cur.isValid())
return;
QString title = cur.data(Qt::DisplayRole).toString();
QChar cc = title.isEmpty() ? QLatin1Char(' ') : title[0].toUpper();
int tot = current->model()->rowCount();
@@ -231,16 +425,30 @@ void GameGridView::keyPressEvent(QKeyEvent* event) {
}
}
void GameGridView::showEvent(QShowEvent* event) {
QWidget::showEvent(event);
QTimer::singleShot(10, this, &GameGridView::UpdateGridSize);
}
void GameGridView::resizeEvent(QResizeEvent* event) {
QWidget::resizeEvent(event);
UpdateGridSize();
}
void GameGridView::UpdateGridSize() {
if (!m_scroll_area || !m_scroll_area->viewport())
return;
const int is = UISettings::values.game_icon_size.GetValue();
const float s = static_cast<float>(is) / 128.0f;
const int bw = qMax(is + static_cast<int>(40 * s), is + 24);
const int tw = m_scroll_area->viewport()->width();
// If width is too small (widget hidden or layouting), retry shortly
if (tw < 100) {
QTimer::singleShot(100, this, &GameGridView::UpdateGridSize);
return;
}
if (tw > 50) {
int cols = qMax(1, tw / bw);
int aw = tw / cols;
@@ -262,18 +470,23 @@ void GameGridView::UpdateLayoutHeights() {
}
const int count = view->model()->rowCount();
const QSize gs = view->gridSize();
if (gs.width() <= 0 || gs.height() <= 0) return;
if (gs.width() <= 0 || gs.height() <= 0)
return;
const int tw = m_scroll_area->viewport()->width();
const int cols = qMax(1, tw / gs.width());
const int rows = (count + cols - 1) / cols;
view->setFixedHeight(rows * gs.height() + 40);
view->setFixedHeight(rows * gs.height() + 60);
};
updateHeight(m_fav_view);
updateHeight(m_main_view);
}
QAbstractItemModel* GameGridView::favModel() const { return m_fav_view->model(); }
QAbstractItemModel* GameGridView::mainModel() const { return m_main_view->model(); }
QAbstractItemModel* GameGridView::favModel() const {
return m_fav_view->model();
}
QAbstractItemModel* GameGridView::mainModel() const {
return m_main_view->model();
}
QItemSelectionModel* GameGridView::selectionModel() const {
return m_main_view->selectionModel();
@@ -287,14 +500,16 @@ void GameGridView::setModel(QAbstractItemModel* model) {
UpdateGridSize();
}
QRect GameGridView::visualRect(const QModelIndex& index) const {
if (index.model() == m_fav_view->model()) return m_fav_view->visualRect(index);
if (index.model() == m_fav_view->model())
return m_fav_view->visualRect(index);
return m_main_view->visualRect(index);
}
QWidget* GameGridView::viewport() const { return m_scroll_area->viewport(); }
QWidget* GameGridView::viewport() const {
return m_scroll_area->viewport();
}
void GameGridView::scrollTo(const QModelIndex& index) {
QListView* view = (index.model() == m_fav_view->model()) ? m_fav_view : m_main_view;
QRect rect = view->visualRect(index);
rect.moveTop(rect.top() + view->y());
m_scroll_area->ensureVisible(rect.center().x(), rect.center().y(), 50, 50);
}
+1
View File
@@ -54,6 +54,7 @@ signals:
protected:
void keyPressEvent(QKeyEvent* event) override;
void showEvent(QShowEvent* event) override;
void resizeEvent(QResizeEvent* event) override;
private: