2022-07-15 02:23:41 +01:00
|
|
|
#include "ProjectItem.h"
|
|
|
|
|
|
|
|
#include "Common.h"
|
|
|
|
|
|
|
|
#include <QIcon>
|
|
|
|
#include <QPainter>
|
|
|
|
|
|
|
|
ProjectItemDelegate::ProjectItemDelegate(QWidget* parent) : QStyledItemDelegate(parent) {}
|
|
|
|
|
|
|
|
void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
|
|
|
{
|
|
|
|
painter->save();
|
|
|
|
|
|
|
|
QStyleOptionViewItem opt(option);
|
|
|
|
initStyleOption(&opt, index);
|
|
|
|
|
2022-07-29 17:50:08 +01:00
|
|
|
auto rect = opt.rect;
|
2022-07-15 02:23:41 +01:00
|
|
|
|
|
|
|
if (opt.state & QStyle::State_Selected) {
|
|
|
|
painter->fillRect(rect, opt.palette.highlight());
|
|
|
|
painter->setPen(opt.palette.highlightedText().color());
|
|
|
|
} else if (opt.state & QStyle::State_MouseOver) {
|
|
|
|
painter->fillRect(rect, opt.palette.window());
|
|
|
|
}
|
|
|
|
|
2022-07-29 17:50:08 +01:00
|
|
|
// The default icon size will be a square (and height is usually the lower value).
|
|
|
|
auto icon_width = rect.height(), icon_height = rect.height();
|
|
|
|
int icon_x_margin = (rect.height() - icon_width) / 2;
|
|
|
|
int icon_y_margin = (rect.height() - icon_height) / 2;
|
|
|
|
|
|
|
|
if (!opt.icon.isNull()) { // Icon painting
|
|
|
|
{
|
|
|
|
auto icon_size = opt.decorationSize;
|
|
|
|
icon_width = icon_size.width();
|
|
|
|
icon_height = icon_size.height();
|
|
|
|
|
|
|
|
icon_x_margin = (rect.height() - icon_width) / 2;
|
|
|
|
icon_y_margin = (rect.height() - icon_height) / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Centralize icon with a margin to separate from the other elements
|
|
|
|
int x = rect.x() + icon_x_margin;
|
|
|
|
int y = rect.y() + icon_y_margin;
|
|
|
|
|
|
|
|
// Prevent 'scaling null pixmap' warnings
|
|
|
|
if (icon_width > 0 && icon_height > 0)
|
|
|
|
opt.icon.paint(painter, x, y, icon_width, icon_height);
|
2022-07-15 02:23:41 +01:00
|
|
|
}
|
|
|
|
|
2022-07-29 17:50:08 +01:00
|
|
|
// Change the rect so that funther painting is easier
|
|
|
|
auto remaining_width = rect.width() - icon_width - 2 * icon_x_margin;
|
|
|
|
rect.setRect(rect.x() + icon_width + 2 * icon_x_margin, rect.y(), remaining_width, rect.height());
|
|
|
|
|
2022-10-18 19:13:02 +01:00
|
|
|
int title_height = 0;
|
|
|
|
|
2022-07-15 02:23:41 +01:00
|
|
|
{ // Title painting
|
|
|
|
auto title = index.data(UserDataTypes::TITLE).toString();
|
|
|
|
|
|
|
|
painter->save();
|
|
|
|
|
|
|
|
auto font = opt.font;
|
|
|
|
if (index.data(UserDataTypes::SELECTED).toBool()) {
|
|
|
|
// Set nice font
|
|
|
|
font.setBold(true);
|
|
|
|
font.setUnderline(true);
|
|
|
|
}
|
2023-06-08 18:26:09 +01:00
|
|
|
if (index.data(UserDataTypes::INSTALLED).toBool()) {
|
2023-06-15 12:12:29 +01:00
|
|
|
auto hRect = opt.rect;
|
|
|
|
hRect.setX(hRect.x() + 1);
|
|
|
|
hRect.setY(hRect.y() + 1);
|
|
|
|
hRect.setHeight(hRect.height() - 2);
|
|
|
|
hRect.setWidth(hRect.width() - 2);
|
2023-06-08 18:26:09 +01:00
|
|
|
// Set nice font
|
|
|
|
font.setItalic(true);
|
|
|
|
font.setOverline(true);
|
2023-06-15 12:12:29 +01:00
|
|
|
painter->drawRect(hRect);
|
2023-06-08 18:26:09 +01:00
|
|
|
}
|
2022-07-15 02:23:41 +01:00
|
|
|
|
|
|
|
font.setPointSize(font.pointSize() + 2);
|
|
|
|
painter->setFont(font);
|
|
|
|
|
2022-10-18 19:13:02 +01:00
|
|
|
title_height = QFontMetrics(font).height();
|
|
|
|
|
2022-07-15 02:23:41 +01:00
|
|
|
// On the top, aligned to the left after the icon
|
2022-10-18 19:13:02 +01:00
|
|
|
painter->drawText(rect.x(), rect.y() + title_height, title);
|
2022-07-15 02:23:41 +01:00
|
|
|
|
|
|
|
painter->restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
{ // Description painting
|
|
|
|
auto description = index.data(UserDataTypes::DESCRIPTION).toString();
|
|
|
|
|
|
|
|
QTextLayout text_layout(description, opt.font);
|
|
|
|
|
|
|
|
qreal height = 0;
|
|
|
|
auto cut_text = viewItemTextLayout(text_layout, remaining_width, height);
|
|
|
|
|
|
|
|
// Get first line unconditionally
|
|
|
|
description = cut_text.first().second;
|
2022-10-20 07:02:05 +01:00
|
|
|
auto num_lines = 1;
|
|
|
|
|
2022-07-15 02:23:41 +01:00
|
|
|
// Get second line, elided if needed
|
2022-10-20 18:51:09 +01:00
|
|
|
if (cut_text.size() > 1) {
|
|
|
|
// 2.5x so because there should be some margin left from the 2x so things don't get too squishy.
|
|
|
|
if (rect.height() - title_height <= 2.5 * opt.fontMetrics.height()) {
|
|
|
|
// If there's not enough space, show only a single line, elided.
|
|
|
|
description = opt.fontMetrics.elidedText(description, opt.textElideMode, cut_text.at(0).first);
|
2022-10-20 07:02:05 +01:00
|
|
|
} else {
|
2022-10-20 18:51:09 +01:00
|
|
|
if (cut_text.size() > 2) {
|
|
|
|
description += opt.fontMetrics.elidedText(cut_text.at(1).second, opt.textElideMode, cut_text.at(1).first);
|
|
|
|
} else {
|
|
|
|
description += cut_text.at(1).second;
|
|
|
|
}
|
|
|
|
num_lines += 1;
|
2022-10-20 07:02:05 +01:00
|
|
|
}
|
2022-07-15 02:23:41 +01:00
|
|
|
}
|
|
|
|
|
2022-10-18 19:13:02 +01:00
|
|
|
int description_x = rect.x();
|
|
|
|
|
|
|
|
// Have the y-value be set based on the number of lines in the description, to centralize the
|
|
|
|
// description text with the space between the base and the title.
|
|
|
|
int description_y = rect.y() + title_height + (rect.height() - title_height) / 2;
|
2022-10-20 07:02:05 +01:00
|
|
|
if (num_lines == 1)
|
2022-10-18 19:13:02 +01:00
|
|
|
description_y -= opt.fontMetrics.height() / 2;
|
|
|
|
else
|
|
|
|
description_y -= opt.fontMetrics.height();
|
|
|
|
|
2022-07-15 02:23:41 +01:00
|
|
|
// On the bottom, aligned to the left after the icon, and featuring at most two lines of text (with some margin space to spare)
|
2023-08-14 17:16:53 +01:00
|
|
|
painter->drawText(description_x, description_y, remaining_width, cut_text.size() * opt.fontMetrics.height(), Qt::TextWordWrap,
|
|
|
|
description);
|
2022-07-15 02:23:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
painter->restore();
|
|
|
|
}
|