Qt: make grid view customizable by stylesheet

This commit is contained in:
CozmoP 2018-12-23 00:45:00 +01:00
parent 7bb23d15bd
commit ca9952ceef
5 changed files with 188 additions and 61 deletions

View File

@ -6,21 +6,20 @@
/* http://www.informit.com/articles/article.aspx?p=1613548 */
ThumbnailDelegate::ThumbnailDelegate(QObject* parent) :
QStyledItemDelegate(parent)
ThumbnailDelegate::ThumbnailDelegate(const GridItem &gridItem, QObject* parent) :
QStyledItemDelegate(parent), m_style(gridItem)
{
}
void ThumbnailDelegate::paint(QPainter* painter, const QStyleOptionViewItem &option, const QModelIndex& index) const
{
QStyleOptionViewItem opt = option;
const QWidget *widget = opt.widget;
QStyle *style = widget->style();
int margin = 11;
int textMargin = 4;
int textHeight = painter->fontMetrics().height() + margin + margin;
int padding = m_style.padding;
int textTopMargin = 4; /* Qt seemingly reports -4 the actual line height. */
int textHeight = painter->fontMetrics().height() + padding + padding;
QRect rect = opt.rect;
QRect adjusted = rect.adjusted(margin, margin, -margin, -textHeight + textMargin);
QRect adjusted = rect.adjusted(padding, padding, -padding, -textHeight + textTopMargin);
QPixmap pixmap = index.data(PlaylistModel::THUMBNAIL).value<QPixmap>();
painter->save();
@ -34,14 +33,14 @@ void ThumbnailDelegate::paint(QPainter* painter, const QStyleOptionViewItem &opt
if (!pixmap.isNull())
{
QPixmap pixmapScaled = pixmap.scaled(adjusted.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
style->drawItemPixmap(painter, adjusted, Qt::AlignHCenter | Qt::AlignBottom, pixmapScaled);
style->drawItemPixmap(painter, adjusted, Qt::AlignHCenter | m_style.thumbnailVerticalAlignmentFlag, pixmapScaled);
}
/* draw the text */
if (!opt.text.isEmpty())
{
QPalette::ColorGroup cg = opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
QRect textRect = QRect(rect.x() + margin, rect.y() + adjusted.height() - textMargin + margin, rect.width() - 2 * margin, textHeight);
QRect textRect = QRect(rect.x() + padding, rect.y() + adjusted.height() - textTopMargin + padding, rect.width() - 2 * padding, textHeight);
QString elidedText = painter->fontMetrics().elidedText(opt.text, opt.textElideMode, textRect.width(), Qt::TextShowMnemonic);
if (cg == QPalette::Normal && !(opt.state & QStyle::State_Active))
@ -95,7 +94,8 @@ void GridView::calculateRectsIfNecessary() const
const int maxWidth = viewport()->width();
switch (m_viewMode) {
switch (m_viewMode)
{
case Anchored:
{
int columns = (maxWidth - m_spacing) / (m_size + m_spacing);
@ -114,7 +114,6 @@ void GridView::calculateRectsIfNecessary() const
m_rectForRow[row] = QRectF(x, y, m_size, m_size);
x = nextX;
}
m_idealHeight = y + m_size + m_spacing;
}
break;
}
@ -137,7 +136,6 @@ void GridView::calculateRectsIfNecessary() const
m_rectForRow[row] = QRectF(x, y, m_size, m_size);
x = nextX;
}
m_idealHeight = y + m_size + m_spacing;
}
break;
}
@ -156,7 +154,7 @@ void GridView::calculateRectsIfNecessary() const
}
break;
}
m_idealHeight = y + m_size + m_spacing;
m_hashIsDirty = false;
viewport()->update();
}
@ -407,3 +405,77 @@ void GridView::updateGeometries()
emit(visibleItemsChangedMaybe());
}
QString GridView::getLayout() const
{
switch (m_viewMode)
{
case Simple:
return "simple";
case Anchored:
return "anchored";
case Centered:
default:
return "centered";
}
}
void GridView::setLayout(QString layout)
{
if (layout == "anchored")
m_viewMode = Anchored;
else if (layout == "centered")
m_viewMode = Centered;
else if (layout == "fixed")
m_viewMode = Simple;
}
int GridView::getSpacing() const
{
return m_spacing;
}
void GridView::setSpacing(const int spacing)
{
m_spacing = spacing;
}
GridItem::GridItem(QWidget* parent) : QWidget(parent)
, thumbnailVerticalAlignmentFlag(Qt::AlignBottom)
, padding(11)
{
}
int GridItem::getPadding() const
{
return padding;
}
void GridItem::setPadding(const int value)
{
padding = value;
}
QString GridItem::getThumbnailVerticalAlign() const
{
switch (thumbnailVerticalAlignmentFlag)
{
case Qt::AlignTop:
return "top";
case Qt::AlignVCenter:
return "center";
case Qt::AlignBottom:
default:
return "bottom";
}
}
void GridItem::setThumbnailVerticalAlign(const QString valign)
{
if (valign == "top")
thumbnailVerticalAlignmentFlag = Qt::AlignTop;
else if (valign == "center")
thumbnailVerticalAlignmentFlag = Qt::AlignVCenter;
else if (valign == "bottom")
thumbnailVerticalAlignmentFlag = Qt::AlignBottom;
}

View File

@ -4,19 +4,32 @@
#include <QAbstractItemView>
#include <QStyledItemDelegate>
#define DEFAULT_GRID_ITEM_MARGIN 11
#define DEFAULT_GRID_ITEM_THUMBNAIL_ALIGNMENT "bottom"
#define DEFAULT_GRID_SPACING 7
#define DEFAULT_GRID_LAYOUT "centered"
class GridItem;
class ThumbnailDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
ThumbnailDelegate(QObject* parent = 0);
ThumbnailDelegate(const GridItem &gridItem, QObject* parent = 0);
void paint(QPainter* painter, const QStyleOptionViewItem &option, const QModelIndex& index) const;
private:
const GridItem &m_style;
};
class GridView : public QAbstractItemView
{
Q_OBJECT
Q_PROPERTY(QString layout READ getLayout WRITE setLayout DESIGNABLE true SCRIPTABLE true)
Q_PROPERTY(int spacing READ getSpacing WRITE setSpacing DESIGNABLE true SCRIPTABLE true)
public:
enum ViewMode
{
@ -35,6 +48,10 @@ public:
void scrollTo(const QModelIndex &index, QAbstractItemView::ScrollHint);
void setGridSize(const int newSize);
void setviewMode(ViewMode mode);
QString getLayout() const;
void setLayout(QString layout);
int getSpacing() const;
void setSpacing(const int spacing);
signals:
void visibleItemsChangedMaybe() const;
@ -63,7 +80,7 @@ private:
void refresh();
int m_size = 255;
int m_spacing = 7;
int m_spacing = DEFAULT_GRID_SPACING;
QVector<QModelIndex> m_visibleIndexes;
ViewMode m_viewMode = Centered;
mutable int m_idealHeight;

View File

@ -431,5 +431,9 @@ static const QString qt_theme_dark_stylesheet = QStringLiteral(R"(
GridView {
background-color:rgb(25,25,25);
selection-color: white;
qproperty-layout: "fixed";
}
GridItem {
qproperty-thumbnailvalign: "center";
}
)");

View File

@ -322,6 +322,7 @@ MainWindow::MainWindow(QWidget *parent) :
,m_playlistThumbnailDownloadWasCanceled(false)
,m_pendingDirScrollPath()
,m_thumbnailTimer(new QTimer(this))
,m_gridItem(this)
{
settings_t *settings = config_get_ptr();
QDir playlistDir(settings->paths.directory_playlist);
@ -417,7 +418,7 @@ MainWindow::MainWindow(QWidget *parent) :
m_tableView->setSortingEnabled(true);
m_tableView->verticalHeader()->setVisible(false);
m_gridView->setItemDelegate(new ThumbnailDelegate(this));
m_gridView->setItemDelegate(new ThumbnailDelegate(m_gridItem, this));
m_gridView->setModel(m_proxyModel);
m_logWidget->setObjectName("logWidget");
@ -566,6 +567,7 @@ MainWindow::MainWindow(QWidget *parent) :
connect(m_thumbnailTimer, SIGNAL(timeout()), this, SLOT(updateVisibleItems()));
connect(this, SIGNAL(updateThumbnails()), this, SLOT(updateVisibleItems()));
/* TODO: Handle scroll and resize differently. */
connect(m_gridView, SIGNAL(visibleItemsChangedMaybe()), this, SLOT(startTimer()));
connect(m_gridView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(currentItemChanged(const QModelIndex&)));
@ -1134,6 +1136,8 @@ void MainWindow::setTheme(Theme theme)
{
m_currentTheme = theme;
setDefaultCustomProperties();
switch(theme)
{
case THEME_SYSTEM_DEFAULT:
@ -1159,6 +1163,14 @@ void MainWindow::setTheme(Theme theme)
}
}
void MainWindow::setDefaultCustomProperties()
{
m_gridView->setLayout(QString(DEFAULT_GRID_LAYOUT));
m_gridView->setSpacing(DEFAULT_GRID_SPACING);
m_gridItem.setThumbnailVerticalAlign(QString(DEFAULT_GRID_ITEM_THUMBNAIL_ALIGNMENT));
m_gridItem.setPadding(DEFAULT_GRID_ITEM_MARGIN);
}
void MainWindow::changeThumbnailType(ThumbnailType type)
{
m_playlistModel->setThumbnailType(type);

View File

@ -271,6 +271,26 @@ public slots:
void appendMessage(const QString& text);
};
/* Used to store styling since delegates don't inherit QWidget. */
class GridItem : public QWidget
{
Q_OBJECT
Q_PROPERTY(QString thumbnailvalign READ getThumbnailVerticalAlign WRITE setThumbnailVerticalAlign)
Q_PROPERTY(int padding READ getPadding WRITE setPadding)
public:
GridItem(QWidget* parent);
Qt::AlignmentFlag thumbnailVerticalAlignmentFlag;
int padding;
int getPadding() const;
void setPadding(const int value);
QString getThumbnailVerticalAlign() const;
void setThumbnailVerticalAlign(const QString valign);
};
class MainWindow : public QMainWindow
{
Q_OBJECT
@ -347,6 +367,7 @@ public:
QString getSpecialPlaylistPath(SpecialPlaylist playlist);
QVector<QPair<QString, QString> > getPlaylists();
QString getScrubbedString(QString str);
void setDefaultCustomProperties();
signals:
void thumbnailChanged(const QPixmap &pixmap);
@ -574,6 +595,7 @@ private:
QString m_pendingDirScrollPath;
QTimer *m_thumbnailTimer;
GridItem m_gridItem;
protected:
void closeEvent(QCloseEvent *event);