[Client] Flat moderation headers and detail tab shape

This commit is contained in:
Lukas Brübach 2026-10-13 22:56:03 +02:00
parent e105ba4f1b
commit 51ce7867da
7 changed files with 160 additions and 0 deletions

View file

@ -391,6 +391,8 @@ set(cockatrice_SOURCES
src/interface/widgets/tabs/api/edhrec/tab_edhrec.cpp
src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.cpp
src/interface/widgets/tabs/alt_table_delegate.cpp
src/interface/widgets/tabs/moderation_header_style.cpp
src/interface/widgets/tabs/moderation_tab_style.cpp
src/interface/widgets/tabs/report_status_delegate.cpp
src/interface/widgets/tabs/tab.cpp
src/interface/widgets/tabs/tab_account.cpp

View file

@ -0,0 +1,56 @@
#include "moderation_header_style.h"
#include <QApplication>
#include <QPainter>
#include <QPalette>
#include <QStyleOption>
namespace
{
constexpr qreal HOVER_WASH_ALPHA = 0.12;
} // namespace
ModerationHeaderStyle::ModerationHeaderStyle(QStyle *base) : QProxyStyle(base)
{
}
void ModerationHeaderStyle::drawControl(ControlElement element,
const QStyleOption *option,
QPainter *painter,
const QWidget *widget) const
{
if (element != CE_Header || option == nullptr || painter == nullptr) {
QProxyStyle::drawControl(element, option, painter, widget);
return;
}
const auto *headerOpt = qstyleoption_cast<const QStyleOptionHeader *>(option);
if (headerOpt == nullptr || !headerOpt->icon.isNull()) {
QProxyStyle::drawControl(element, option, painter, widget);
return;
}
painter->save();
painter->fillRect(headerOpt->rect, headerOpt->palette.window());
const bool enabled = (headerOpt->state & State_Enabled) != 0;
if (enabled && (headerOpt->state & State_MouseOver) != 0) {
QColor wash = headerOpt->palette.color(QPalette::Highlight);
wash.setAlphaF(HOVER_WASH_ALPHA);
painter->fillRect(headerOpt->rect, wash);
}
painter->setPen(headerOpt->palette.color(QPalette::Mid));
painter->drawLine(headerOpt->rect.bottomLeft(), headerOpt->rect.bottomRight());
painter->restore();
QRect textRect = headerOpt->rect.adjusted(4, 0, -4, 0);
const QString elided = headerOpt->fontMetrics.elidedText(headerOpt->text, Qt::ElideRight, textRect.width());
QStyle *style = widget != nullptr ? widget->style() : QApplication::style();
style->drawItemText(painter, textRect, Qt::AlignLeft | Qt::AlignVCenter, headerOpt->palette, enabled, elided,
QPalette::WindowText);
if (headerOpt->sortIndicator != QStyleOptionHeader::None) {
QProxyStyle::drawPrimitive(PE_IndicatorHeaderArrow, option, painter, widget);
}
}

View file

@ -0,0 +1,25 @@
#ifndef MODERATION_HEADER_STYLE_H
#define MODERATION_HEADER_STYLE_H
#include <QProxyStyle>
#include <qtmetamacros.h>
/**
* Flat header sections for the moderation tables (report queue, user alts).
* Replaces the native gradient header with the palette Window background, a
* 1px Mid bottom rule, and WindowText labels, so headers follow the active
* theme. Sort indicators are still drawn by the base style. Headers with
* icons fall back to the base style untouched.
*/
class ModerationHeaderStyle : public QProxyStyle
{
Q_OBJECT
public:
explicit ModerationHeaderStyle(QStyle *base = nullptr);
void drawControl(ControlElement element,
const QStyleOption *option,
QPainter *painter,
const QWidget *widget = nullptr) const override;
};
#endif // MODERATION_HEADER_STYLE_H

View file

@ -0,0 +1,46 @@
#include "moderation_tab_style.h"
#include <QPalette>
#include <QStyleOption>
namespace
{
constexpr int UNDERLINE_HEIGHT = 2;
constexpr qreal HOVER_WASH_ALPHA = 0.08;
} // namespace
ModerationTabStyle::ModerationTabStyle(QStyle *base) : QProxyStyle(base)
{
}
void ModerationTabStyle::drawControl(ControlElement element,
const QStyleOption *option,
QPainter *painter,
const QWidget *widget) const
{
if (element != CE_TabBarTabShape || option == nullptr || painter == nullptr) {
QProxyStyle::drawControl(element, option, painter, widget);
return;
}
const auto *tabOpt = qstyleoption_cast<const QStyleOptionTab *>(option);
if (tabOpt == nullptr) {
QProxyStyle::drawControl(element, option, painter, widget);
return;
}
painter->save();
painter->fillRect(tabOpt->rect, tabOpt->palette.window());
const bool enabled = (tabOpt->state & State_Enabled) != 0;
if ((tabOpt->state & State_Selected) != 0) {
const QRect underline(tabOpt->rect.left(), tabOpt->rect.bottom() - UNDERLINE_HEIGHT + 1, tabOpt->rect.width(),
UNDERLINE_HEIGHT);
painter->fillRect(underline, tabOpt->palette.color(QPalette::Highlight));
} else if (enabled && (tabOpt->state & State_MouseOver) != 0) {
QColor wash = tabOpt->palette.color(QPalette::Highlight);
wash.setAlphaF(HOVER_WASH_ALPHA);
painter->fillRect(tabOpt->rect, wash);
}
painter->restore();
}

View file

@ -0,0 +1,25 @@
#ifndef MODERATION_TAB_STYLE_H
#define MODERATION_TAB_STYLE_H
#include <QProxyStyle>
#include <qtmetamacros.h>
/**
* Flat tab shapes for the moderation detail tabs (report queue detailTabs).
* Replaces the native tab frame with the palette Window background plus a
* 2px Highlight underline on the selected tab and a faint Highlight wash on
* hover. Labels (text, elide, focus) are left to the base style, so keyboard
* focus stays distinguishable.
*/
class ModerationTabStyle : public QProxyStyle
{
Q_OBJECT
public:
explicit ModerationTabStyle(QStyle *base = nullptr);
void drawControl(ControlElement element,
const QStyleOption *option,
QPainter *painter,
const QWidget *widget = nullptr) const override;
};
#endif // MODERATION_TAB_STYLE_H

View file

@ -4,6 +4,7 @@
#include "alt_table_delegate.h"
#include "libcockatrice/protocol/pb/response.pb.h"
#include "libcockatrice/protocol/pb/response_user_alts.pb.h"
#include "moderation_header_style.h"
#include <QAbstractItemView>
#include <QDateTime>
@ -76,6 +77,7 @@ void configureAltTable(QTableWidget *table)
table->setAlternatingRowColors(true);
table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
table->horizontalHeader()->setStretchLastSection(true);
table->horizontalHeader()->setStyle(new ModerationHeaderStyle(table->horizontalHeader()->style()));
}
} // namespace

View file

@ -4,6 +4,8 @@
#include "../utility/report_utils.h"
#include "abstract_client.h"
#include "libcockatrice/protocol/pb/response.pb.h"
#include "moderation_header_style.h"
#include "moderation_tab_style.h"
#include "report_status_delegate.h"
#include "tab_supervisor.h"
@ -123,6 +125,7 @@ TabReport::TabReport(TabSupervisor *_tabSupervisor, AbstractClient *_client) : T
table->horizontalHeader()->setSectionResizeMode(COL_TIME, QHeaderView::ResizeToContents);
table->horizontalHeader()->setSectionResizeMode(COL_REPORTED, QHeaderView::Stretch);
table->horizontalHeader()->setSectionResizeMode(COL_REPORTER, QHeaderView::ResizeToContents);
table->horizontalHeader()->setStyle(new ModerationHeaderStyle(table->horizontalHeader()->style()));
connect(table, &QTableWidget::itemSelectionChanged, this, &TabReport::onSelectionChanged);
table->setContextMenuPolicy(Qt::CustomContextMenu);
connect(table, &QTableWidget::customContextMenuRequested, this, &TabReport::showTableContextMenu);
@ -246,6 +249,7 @@ TabReport::TabReport(TabSupervisor *_tabSupervisor, AbstractClient *_client) : T
});
detailTabs = new QTabWidget;
detailTabs->tabBar()->setStyle(new ModerationTabStyle(detailTabs->tabBar()->style()));
detailTabs->addTab(descPage, QString());
detailTabs->addTab(chatPage, QString());
detailTabs->addTab(commentsPage, QString());