[desktop] Add basic carousel view (#4112)

Adds a basic carousel view, or essentially a horizontal list a la Android/Qt Quick.

Lacks a lot of niceties like autoscroll, smooth shifts, etc. Will work on those later

Also fixed a bug introduced recently that capped game icon size to 8 at the low end, breaking the None option

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4112
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
This commit is contained in:
crueter 2026-06-22 21:04:47 +02:00
parent 68aaea6085
commit 39be450fa3
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
16 changed files with 300 additions and 45 deletions

View file

@ -18,27 +18,16 @@ void GameCard::paint(QPainter* painter, const QStyleOptionViewItem& option,
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
constexpr int cardMargin = 8;
constexpr int cardCornerRadius = 10;
const int column = index.row() % m_columns;
const int cell_width = option.rect.width();
const int card_width = cell_width - m_padding;
const int row_width = m_columns * cell_width;
const int total_gap = row_width - cardMargin * 2 - m_columns * card_width;
const int gap = (m_columns > 1) ? (total_gap / (m_columns - 1)) : 0;
const int card_left = option.rect.left() - column * cell_width + cardMargin + column * (card_width + gap) + 4;
const QRect cardRect(card_left, option.rect.top() + 4, card_width - 8,
option.rect.height() - cardMargin);
const QRect cardRect = getCardRect(option, index);
QPalette palette = option.palette;
QColor backgroundColor = palette.window().color();
QColor borderColor = palette.dark().color();
QColor textColor = palette.text().color();
// highlight blue on select
// highlight on select or hover
if (option.state & QStyle::State_Selected) {
backgroundColor = palette.highlight().color();
borderColor = palette.highlight().color().lighter(150);
@ -60,7 +49,7 @@ void GameCard::paint(QPainter* painter, const QStyleOptionViewItem& option,
scaled.scale(icon_size, icon_size, Qt::KeepAspectRatio);
iconRect = {cardRect.left() + (cardRect.width() - scaled.width()) / 2,
cardRect.top() + cardMargin, scaled.width(), scaled.height()};
cardRect.top() + cardMargin - 1, scaled.width(), scaled.height()};
painter->setRenderHint(QPainter::SmoothPixmapTransform, true);
@ -94,12 +83,62 @@ void GameCard::paint(QPainter* painter, const QStyleOptionViewItem& option,
painter->restore();
}
QRect GameCard::getCardRect(const QStyleOptionViewItem& option, const QModelIndex& index) const {
const int cell_width = option.rect.width();
const int card_width = cell_width - m_padding;
int card_left, card_top, card_height;
if (m_columns >= 1) {
// grid mode
// center everything in-line, such that the leftmost and rightmost cards
// have ~ equal padding to the edge of the viewport
// spacing between each card is larger, but equal to each other
const int column = index.row() % m_columns;
const int row_width = m_columns * cell_width;
const int total_gap = row_width - cardMargin * 2 - m_columns * card_width;
const int gap = (m_columns > 1) ? (total_gap / (m_columns - 1)) : 0;
card_left =
option.rect.left() - column * cell_width + cardMargin + column * (card_width + gap) + 4;
// fill cell vertically
card_top = option.rect.top() + cardMargin;
card_height = option.rect.height() - cardMargin - 1;
} else {
// carousel mode
card_left = option.rect.left() + cardMargin + 4;
// the delegate itself takes up the full height, but the card itself
// gets centered
const int content_height = m_contentSize.height() - cardMargin;
const int cell_height = option.rect.height();
card_height = std::min(content_height, cell_height - cardMargin * 2) - 1;
card_top = option.rect.top() + (cell_height - card_height) / 2;
}
return QRect(card_left, card_top, card_width - cardMargin, card_height);
}
bool GameCard::hitTest(const QPoint& point, const QModelIndex& index, const QWidget* widget,
const QRect& cellRect) const {
QStyleOptionViewItem option;
option.initFrom(widget);
option.rect = cellRect;
return getCardRect(option, index).contains(point);
}
QSize GameCard::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const {
return m_size;
}
void GameCard::setSize(const QSize& newSize, const int padding, const int columns) {
void GameCard::setSize(const QSize& newSize, const QSize& contentSize, const int padding,
const int columns) {
m_size = newSize;
m_contentSize = contentSize;
m_padding = padding;
m_columns = columns;
}