aboutsummaryrefslogtreecommitdiff
path: root/launcher/ui/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'launcher/ui/widgets')
-rw-r--r--launcher/ui/widgets/InfoFrame.cpp98
-rw-r--r--launcher/ui/widgets/InfoFrame.h4
-rw-r--r--launcher/ui/widgets/ProjectItem.cpp37
3 files changed, 92 insertions, 47 deletions
diff --git a/launcher/ui/widgets/InfoFrame.cpp b/launcher/ui/widgets/InfoFrame.cpp
index 9e0553f8..fdc581b4 100644
--- a/launcher/ui/widgets/InfoFrame.cpp
+++ b/launcher/ui/widgets/InfoFrame.cpp
@@ -97,18 +97,7 @@ void InfoFrame::updateWithResource(const Resource& resource)
setImage();
}
-// https://www.sportskeeda.com/minecraft-wiki/color-codes
-static const QMap<QChar, QString> s_value_to_color = {
- {'0', "#000000"}, {'1', "#0000AA"}, {'2', "#00AA00"}, {'3', "#00AAAA"}, {'4', "#AA0000"},
- {'5', "#AA00AA"}, {'6', "#FFAA00"}, {'7', "#AAAAAA"}, {'8', "#555555"}, {'9', "#5555FF"},
- {'a', "#55FF55"}, {'b', "#55FFFF"}, {'c', "#FF5555"}, {'d', "#FF55FF"}, {'e', "#FFFF55"},
- {'f', "#FFFFFF"}
-};
-
-void InfoFrame::updateWithResourcePack(ResourcePack& resource_pack)
-{
- setName(resource_pack.name());
-
+QString InfoFrame::renderColorCodes(QString input) {
// We have to manually set the colors for use.
//
// A color is set using §x, with x = a hex number from 0 to f.
@@ -116,42 +105,73 @@ void InfoFrame::updateWithResourcePack(ResourcePack& resource_pack)
// We traverse the description and, when one of those is found, we create
// a span element with that color set.
//
- // TODO: Make the same logic for font formatting too.
// TODO: Wrap links inside <a> tags
- auto description = resource_pack.description();
-
- QString description_parsed("<html>");
- bool in_div = false;
-
- auto desc_it = description.constBegin();
- while (desc_it != description.constEnd()) {
- if (*desc_it == u'§') {
- if (in_div)
- description_parsed += "</span>";
-
- auto const& num = *(++desc_it);
- description_parsed += QString("<span style=\"color: %1;\">").arg(s_value_to_color.constFind(num).value());
-
- in_div = true;
-
- desc_it++;
+ // https://minecraft.fandom.com/wiki/Formatting_codes#Color_codes
+ const QMap<QChar, QString> color_codes_map = {
+ {'0', "#000000"}, {'1', "#0000AA"}, {'2', "#00AA00"}, {'3', "#00AAAA"}, {'4', "#AA0000"},
+ {'5', "#AA00AA"}, {'6', "#FFAA00"}, {'7', "#AAAAAA"}, {'8', "#555555"}, {'9', "#5555FF"},
+ {'a', "#55FF55"}, {'b', "#55FFFF"}, {'c', "#FF5555"}, {'d', "#FF55FF"}, {'e', "#FFFF55"},
+ {'f', "#FFFFFF"}
+ };
+ // https://minecraft.fandom.com/wiki/Formatting_codes#Formatting_codes
+ const QMap<QChar, QString> formatting_codes_map = {
+ {'l', "b"}, {'m', "s"}, {'n', "u"}, {'o', "i"}
+ };
+
+ QString html("<html>");
+ QList<QString> tags{};
+
+ auto it = input.constBegin();
+ while (it != input.constEnd()) {
+ // is current char § and is there a following char
+ if (*it == u'§' && (it + 1) != input.constEnd()) {
+ auto const& code = *(++it); // incrementing here!
+
+ auto const color_entry = color_codes_map.constFind(code);
+ auto const tag_entry = formatting_codes_map.constFind(code);
+
+ if (color_entry != color_codes_map.constEnd()) { // color code
+ html += QString("<span style=\"color: %1;\">").arg(color_entry.value());
+ tags << "span";
+ } else if (tag_entry != formatting_codes_map.constEnd()) { // formatting code
+ html += QString("<%1>").arg(tag_entry.value());
+ tags << tag_entry.value();
+ } else if (code == 'r') { // reset all formatting
+ while (!tags.isEmpty()) {
+ html += QString("</%1>").arg(tags.takeLast());
+ }
+ } else { // pass unknown codes through
+ html += QString("§%1").arg(code);
+ }
+ } else {
+ html += *it;
}
-
- description_parsed += *desc_it;
- desc_it++;
+ it++;
}
+ while (!tags.isEmpty()) {
+ html += QString("</%1>").arg(tags.takeLast());
+ }
+ html += "</html>";
- if (in_div)
- description_parsed += "</span>";
- description_parsed += "</html>";
-
- description_parsed.replace("\n", "<br>");
+ html.replace("\n", "<br>");
+ return html;
+}
- setDescription(description_parsed);
+void InfoFrame::updateWithResourcePack(ResourcePack& resource_pack)
+{
+ setName(renderColorCodes(resource_pack.name()));
+ setDescription(renderColorCodes(resource_pack.description()));
setImage(resource_pack.image({64, 64}));
}
+void InfoFrame::updateWithTexturePack(TexturePack& texture_pack)
+{
+ setName(renderColorCodes(texture_pack.name()));
+ setDescription(renderColorCodes(texture_pack.description()));
+ setImage(texture_pack.image({64, 64}));
+}
+
void InfoFrame::clear()
{
setName();
diff --git a/launcher/ui/widgets/InfoFrame.h b/launcher/ui/widgets/InfoFrame.h
index 70d15b1e..84523e28 100644
--- a/launcher/ui/widgets/InfoFrame.h
+++ b/launcher/ui/widgets/InfoFrame.h
@@ -19,6 +19,7 @@
#include "minecraft/mod/Mod.h"
#include "minecraft/mod/ResourcePack.h"
+#include "minecraft/mod/TexturePack.h"
namespace Ui
{
@@ -41,6 +42,9 @@ class InfoFrame : public QFrame {
void updateWithMod(Mod const& m);
void updateWithResource(Resource const& resource);
void updateWithResourcePack(ResourcePack& rp);
+ void updateWithTexturePack(TexturePack& tp);
+
+ static QString renderColorCodes(QString input);
public slots:
void descriptionEllipsisHandler(QString link);
diff --git a/launcher/ui/widgets/ProjectItem.cpp b/launcher/ui/widgets/ProjectItem.cpp
index 56ae35fb..01be88d9 100644
--- a/launcher/ui/widgets/ProjectItem.cpp
+++ b/launcher/ui/widgets/ProjectItem.cpp
@@ -14,9 +14,7 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o
QStyleOptionViewItem opt(option);
initStyleOption(&opt, index);
- auto& rect = opt.rect;
- auto icon_width = rect.height(), icon_height = rect.height();
- auto remaining_width = rect.width() - icon_width;
+ auto rect = opt.rect;
if (opt.state & QStyle::State_Selected) {
painter->fillRect(rect, opt.palette.highlight());
@@ -25,11 +23,34 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o
painter->fillRect(rect, opt.palette.window());
}
- { // Icon painting
- // Square-sized, occupying the left portion
- opt.icon.paint(painter, rect.x(), rect.y(), icon_width, icon_height);
+ // 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);
}
+ // 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());
+
{ // Title painting
auto title = index.data(UserDataTypes::TITLE).toString();
@@ -46,7 +67,7 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o
painter->setFont(font);
// On the top, aligned to the left after the icon
- painter->drawText(rect.x() + icon_width, rect.y() + QFontMetrics(font).height(), title);
+ painter->drawText(rect.x(), rect.y() + QFontMetrics(font).height(), title);
painter->restore();
}
@@ -70,7 +91,7 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o
}
// On the bottom, aligned to the left after the icon, and featuring at most two lines of text (with some margin space to spare)
- painter->drawText(rect.x() + icon_width, rect.y() + rect.height() - 2.2 * opt.fontMetrics.height(), remaining_width,
+ painter->drawText(rect.x(), rect.y() + rect.height() - 2.2 * opt.fontMetrics.height(), remaining_width,
2 * opt.fontMetrics.height(), Qt::TextWordWrap, description);
}