diff options
Diffstat (limited to 'launcher/ui/widgets')
-rw-r--r-- | launcher/ui/widgets/InfoFrame.cpp | 98 | ||||
-rw-r--r-- | launcher/ui/widgets/InfoFrame.h | 4 | ||||
-rw-r--r-- | launcher/ui/widgets/ProjectItem.cpp | 37 |
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); } |