diff --git a/include/gui/gfx.hpp b/include/gui/gfx.hpp index 244e7e906..de9724c43 100644 --- a/include/gui/gfx.hpp +++ b/include/gui/gfx.hpp @@ -45,7 +45,7 @@ namespace GFX { void DrawTop(void); void DrawBottom(); void DrawSprite(int img, int x, int y, float ScaleX = 1, float ScaleY = 1); - void DrawBox(float xPos, float yPos, float width = 50, float height = 50, bool selected = false, uint32_t clr = UIThemes->BoxInside()); + void DrawBox(float xPos, float yPos, float width = 50, float height = 50, bool selected = false, uint32_t clr = 0, uint32_t borderClr = 0); void DrawCheckbox(float xPos, float yPos, bool selected); void DrawToggle(float xPos, float yPos, bool toggled); void DrawTime(); diff --git a/include/store/store.hpp b/include/store/store.hpp index c8735d436..c2c641951 100644 --- a/include/store/store.hpp +++ b/include/store/store.hpp @@ -61,6 +61,7 @@ class Store { std::vector GetScreenshotList(int index) const; std::vector GetScreenshotNames(int index) const; std::string GetReleaseNotes(int index) const; + uint32_t GetAccentColorEntry(int index) const; std::vector GetDownloadList(int index) const; diff --git a/include/store/storeEntry.hpp b/include/store/storeEntry.hpp index 087267ff0..385c16749 100644 --- a/include/store/storeEntry.hpp +++ b/include/store/storeEntry.hpp @@ -52,6 +52,8 @@ class StoreEntry { int GetSheetIndex() const { return this->SheetIndex; }; int GetEntryIndex() const { return this->EntryIndex; }; + uint32_t GetAccentColor() const { return this->AccentColor; }; + std::vector GetCategoryFull() const { return this->FullCategory; }; std::vector GetConsoleFull() const { return this->FullConsole; }; std::vector GetSizes() const { return this->Sizes; }; @@ -73,6 +75,7 @@ class StoreEntry { int Stars; C2D_Image Icon; int SheetIndex, EntryIndex, Marks; + uint32_t AccentColor; std::vector FullCategory, FullConsole, Sizes, Types, Screenshots, ScreenshotNames; bool UpdateAvailable; }; diff --git a/include/utils/config.hpp b/include/utils/config.hpp index 3a2444ede..aa21c0f19 100644 --- a/include/utils/config.hpp +++ b/include/utils/config.hpp @@ -102,6 +102,10 @@ class Config { std::string theme() const { return this->v_theme; }; void theme(const std::string &v) { this->v_theme = v; if (!this->changesMade) this->changesMade = true; }; + /* If accent color should be used. */ + bool useAccentColor() const { return this->v_useAccentColor; }; + void useAccentColor(bool v) { this->v_useAccentColor = v; }; + /* If showing prompt if action failed / succeeded. */ bool prompt() const { return this->v_prompt; }; void prompt(bool v) { this->v_prompt = v; if (!this->changesMade) this->changesMade = true; }; @@ -122,7 +126,8 @@ class Config { v_shortcutPath = "sdmc:/3ds/Universal-Updater/shortcuts", v_firmPath = "sdmc:/luma/payloads", v_theme = "Default"; bool v_list = false, v_autoUpdate = true, v_metadata = true, v_updateCheck = true, v_updateNightly = false, - v_showBg = false, v_customFont = false, v_changelog = true, v_prompt = true, v_3dsxInFolder = false; + v_showBg = false, v_customFont = false, v_changelog = true, v_prompt = true, v_3dsxInFolder = false, + v_useAccentColor = true; }; #endif diff --git a/include/utils/stringutils.hpp b/include/utils/stringutils.hpp index 84f47d53d..ad52f810e 100644 --- a/include/utils/stringutils.hpp +++ b/include/utils/stringutils.hpp @@ -38,6 +38,7 @@ namespace StringUtils { std::string GetMarkString(int marks); std::vector GetMarks(int marks); std::string format(const char *fmt_str, ...); + uint32_t ParseColorHexString(std::string_view str); }; #endif \ No newline at end of file diff --git a/romfs/lang/en/app.json b/romfs/lang/en/app.json index 72613ede1..0ceb8bae3 100644 --- a/romfs/lang/en/app.json +++ b/romfs/lang/en/app.json @@ -155,5 +155,6 @@ "UPDATING_SPRITE_SHEET": "Updating Spritesheet...", "UPDATING_SPRITE_SHEET2": "Updating Spritesheet %i of %i...", "UPDATING_UNISTORE": "Updating UniStore...", + "USE_ACCENT_COLOR": "Use Accent Color of Entries", "VERSION": "Version" } \ No newline at end of file diff --git a/source/gui/gfx.cpp b/source/gui/gfx.cpp index 0cd112fc6..d35c735f7 100644 --- a/source/gui/gfx.cpp +++ b/source/gui/gfx.cpp @@ -52,17 +52,22 @@ void GFX::DrawBottom() { float height: The Height of the button. bool selected: If selected, or not. uint32_t clr: (Optional) The color of the inside of the box. + uint32_t borderClr: (Optional) The color of the border if selected. */ -void GFX::DrawBox(float xPos, float yPos, float width, float height, bool selected, uint32_t clr) { - Gui::Draw_Rect(xPos, yPos, width, height, UIThemes->BoxInside()); // Draw middle BG. +void GFX::DrawBox(float xPos, float yPos, float width, float height, bool selected, uint32_t clr, uint32_t borderClr) { + if (!clr) clr = UIThemes->BoxInside(); + + Gui::Draw_Rect(xPos, yPos, width, height, clr); // Draw middle BG. if (selected) { static constexpr int depth = 3; - Gui::Draw_Rect(xPos - depth, yPos - depth, width + depth * 2, depth, UIThemes->BoxSelected()); // Top. - Gui::Draw_Rect(xPos - depth, yPos - depth, depth, height + depth * 2, UIThemes->BoxSelected()); // Left. - Gui::Draw_Rect(xPos + width, yPos - depth, depth, height + depth * 2, UIThemes->BoxSelected()); // Right. - Gui::Draw_Rect(xPos - depth, yPos + height, width + depth * 2, depth, UIThemes->BoxSelected()); // Bottom. + if (!borderClr) borderClr = UIThemes->BoxSelected(); + + Gui::Draw_Rect(xPos - depth, yPos - depth, width + depth * 2, depth, borderClr); // Top. + Gui::Draw_Rect(xPos - depth, yPos - depth, depth, height + depth * 2, borderClr); // Left. + Gui::Draw_Rect(xPos + width, yPos - depth, depth, height + depth * 2, borderClr); // Right. + Gui::Draw_Rect(xPos - depth, yPos + height, width + depth * 2, depth, borderClr); // Bottom. } } diff --git a/source/menu/downList.cpp b/source/menu/downList.cpp index 8c75ba0c5..4c2eb70d6 100644 --- a/source/menu/downList.cpp +++ b/source/menu/downList.cpp @@ -108,20 +108,25 @@ static bool CreateShortcut(const std::string &entryName, int index, const std::s const std::vector &sizes: Const Reference to the download sizes as a vector of strings. */ void StoreUtils::DrawDownList(const std::vector &entries, bool fetch, const std::unique_ptr &entry, const std::vector &sizes, const std::vector &installs) { + uint32_t accentColor = 0; + /* For the Top Screen. */ if (StoreUtils::store && StoreUtils::store->GetValid() && !fetch && entry) { if (entries.size() > 0) { - Gui::Draw_Rect(0, 174, 400, 66, UIThemes->DownListPrev()); + accentColor = config->useAccentColor() ? entry->GetAccentColor() : 0; + + if (accentColor) Gui::Draw_Rect(0, 173, 400, 1, UIThemes->EntryOutline()); + Gui::Draw_Rect(0, 174, 400, 66, accentColor ? accentColor : UIThemes->DownListPrev()); const C2D_Image tempImg = entry->GetIcon(); const uint8_t offsetW = (48 - tempImg.subtex->width) / 2; // Center W. const uint8_t offsetH = (48 - tempImg.subtex->height) / 2; // Center H. C2D_DrawImageAt(tempImg, 9 + offsetW, 174 + 9 + offsetH, 0.5); - Gui::DrawString(70, 174 + 15, 0.45f, UIThemes->TextColor(), entries[StoreUtils::store->GetDownloadIndex()], 310, 0, font); + Gui::DrawString(70, 174 + 15, 0.45f, accentColor ? WHITE : UIThemes->TextColor(), entries[StoreUtils::store->GetDownloadIndex()], 310, 0, font); if (!sizes.empty()) { if (sizes[StoreUtils::store->GetDownloadIndex()] != "") { - Gui::DrawString(70, 174 + 30, 0.45f, UIThemes->TextColor(), Lang::get("SIZE") + ": " + sizes[StoreUtils::store->GetDownloadIndex()], 310, 0, font); + Gui::DrawString(70, 174 + 30, 0.45f, accentColor ? WHITE : UIThemes->TextColor(), Lang::get("SIZE") + ": " + sizes[StoreUtils::store->GetDownloadIndex()], 310, 0, font); } } } @@ -133,9 +138,9 @@ void StoreUtils::DrawDownList(const std::vector &entries, bool fetc Animation::QueueEntryDone(); GFX::DrawBottom(); - Gui::Draw_Rect(40, 0, 280, 25, UIThemes->EntryBar()); + Gui::Draw_Rect(40, 0, 280, 25, accentColor ? accentColor : UIThemes->EntryBar()); Gui::Draw_Rect(40, 25, 280, 1, UIThemes->EntryOutline()); - Gui::DrawStringCentered(17, 2, 0.6, UIThemes->TextColor(), Lang::get("AVAILABLE_DOWNLOADS"), 273, 0, font); + Gui::DrawStringCentered(17, 2, 0.6, accentColor ? WHITE : UIThemes->TextColor(), Lang::get("AVAILABLE_DOWNLOADS"), 273, 0, font); if (StoreUtils::store && StoreUtils::store->GetValid() && !fetch && entry) { if (entries.size() > 0) { diff --git a/source/menu/entryInfo.cpp b/source/menu/entryInfo.cpp index cb8ac07f0..a4e908c07 100644 --- a/source/menu/entryInfo.cpp +++ b/source/menu/entryInfo.cpp @@ -44,11 +44,13 @@ extern bool exiting, QueueRuns; */ void StoreUtils::DrawEntryInfo(const std::unique_ptr &entry) { if (StoreUtils::store && entry) { // Ensure, store & entry is not a nullptr. - Gui::Draw_Rect(40, 0, 280, 36, UIThemes->EntryBar()); + uint32_t accentColor = config->useAccentColor() ? entry->GetAccentColor() : 0; + + Gui::Draw_Rect(40, 0, 280, 36, accentColor ? accentColor : UIThemes->EntryBar()); Gui::Draw_Rect(40, 36, 280, 1, UIThemes->EntryOutline()); - Gui::DrawStringCentered(17, 0, 0.6, UIThemes->TextColor(), entry->GetTitle(), 273, 0, font); - Gui::DrawStringCentered(17, 20, 0.4, UIThemes->TextColor(), entry->GetAuthor(), 273, 0, font); + Gui::DrawStringCentered(17, 0, 0.6, accentColor ? WHITE : UIThemes->TextColor(), entry->GetTitle(), 273, 0, font); + Gui::DrawStringCentered(17, 20, 0.4, accentColor ? WHITE : UIThemes->TextColor(), entry->GetAuthor(), 273, 0, font); Gui::DrawStringCentered(17, 50, 0.4, UIThemes->TextColor(), entry->GetDescription(), 248, 0, font, C2D_WordWrap); Gui::DrawString(53, 115, 0.45, UIThemes->TextColor(), Lang::get("VERSION") + ": " + entry->GetVersion(), 248, 0, font); diff --git a/source/menu/grid.cpp b/source/menu/grid.cpp index b5f57074a..1f519cb18 100644 --- a/source/menu/grid.cpp +++ b/source/menu/grid.cpp @@ -80,8 +80,13 @@ void StoreUtils::DrawGrid() { } for (int i = 0, i2 = -5 + (StoreUtils::store->GetScreenIndx() * 5); i2 < 20 + (StoreUtils::store->GetScreenIndx() * 5) && i2 < (int)StoreUtils::entries.size(); i2++, i++) { + uint32_t accentColor = 0; + if (config->useAccentColor() && (int)StoreUtils::entries.size() > i + StoreUtils::store->GetScreenIndx()) { + accentColor = StoreUtils::entries[i + StoreUtils::store->GetScreenIndx()]->GetAccentColor(); + } + /* Boxes. */ - if (i == StoreUtils::store->GetBox()) GFX::DrawBox(GridBoxes[i + 5].x, GridBoxes[i + 5].y + StoreUtils::store->GetAnimOffset(), 50, 50, true); + if (i == StoreUtils::store->GetBox()) GFX::DrawBox(GridBoxes[i + 5].x, GridBoxes[i + 5].y + StoreUtils::store->GetAnimOffset(), 50, 50, true, accentColor); /* Ensure, entries is larger than the index. */ if ((int)StoreUtils::entries.size() > i2) { diff --git a/source/menu/list.cpp b/source/menu/list.cpp index 6fc75e323..1acb5cf71 100644 --- a/source/menu/list.cpp +++ b/source/menu/list.cpp @@ -56,9 +56,14 @@ void StoreUtils::DrawList() { if (StoreUtils::entries.size() > 0) { for (int i = 0; i < 5 && i < (int)StoreUtils::entries.size(); i++) { + uint32_t accentColor = 0; if (i + StoreUtils::store->GetScreenIndx() == StoreUtils::store->GetEntry()) { - GFX::DrawBox(StoreBoxesList[i + 1].x, StoreBoxesList[i + 1].y + StoreUtils::store->GetAnimOffset(), StoreBoxesList[i + 1].w, StoreBoxesList[i + 1].h, false); + if (config->useAccentColor() && (int)StoreUtils::entries.size() > i + StoreUtils::store->GetScreenIndx()) { + accentColor = StoreUtils::entries[i + StoreUtils::store->GetScreenIndx()]->GetAccentColor(); + } + + GFX::DrawBox(StoreBoxesList[i + 1].x, StoreBoxesList[i + 1].y + StoreUtils::store->GetAnimOffset(), StoreBoxesList[i + 1].w, StoreBoxesList[i + 1].h, true, accentColor); } /* Ensure, entries is larger than the index. */ @@ -72,8 +77,8 @@ void StoreUtils::DrawList() { } if (StoreUtils::entries[i - 1 + StoreUtils::store->GetScreenIndx()]->GetUpdateAvl()) GFX::DrawSprite(sprites_update_app_idx, StoreBoxesList[i].x + 32, StoreBoxesList[i].y + 32 + StoreUtils::store->GetAnimOffset()); - Gui::DrawStringCentered(29, StoreBoxesList[i].y + 5 + StoreUtils::store->GetAnimOffset(), 0.6f, UIThemes->TextColor(), StoreUtils::entries[i - 1 + StoreUtils::store->GetScreenIndx()]->GetTitle(), 300, 0, font); - Gui::DrawStringCentered(29, StoreBoxesList[i].y + 24 + StoreUtils::store->GetAnimOffset(), 0.6f, UIThemes->TextColor(), StoreUtils::entries[i - 1 + StoreUtils::store->GetScreenIndx()]->GetAuthor(), 300, 0, font); + Gui::DrawStringCentered(29, StoreBoxesList[i].y + 5 + StoreUtils::store->GetAnimOffset(), 0.6f, accentColor ? WHITE : UIThemes->TextColor(), StoreUtils::entries[i - 1 + StoreUtils::store->GetScreenIndx()]->GetTitle(), 300, 0, font); + Gui::DrawStringCentered(29, StoreBoxesList[i].y + 24 + StoreUtils::store->GetAnimOffset(), 0.6f, accentColor ? WHITE : UIThemes->TextColor(), StoreUtils::entries[i - 1 + StoreUtils::store->GetScreenIndx()]->GetAuthor(), 300, 0, font); } } } diff --git a/source/menu/settings.cpp b/source/menu/settings.cpp index ae1a626d9..f8272e33e 100644 --- a/source/menu/settings.cpp +++ b/source/menu/settings.cpp @@ -60,6 +60,12 @@ static const std::vector toggleAbles = { { 288, 180, 24, 24 } }; +static const std::vector toggleAblesGui = { + { 288, 30, 24, 24 }, + { 288, 108, 24, 24 }, + { 288, 136, 24, 24 }, +}; + static const std::vector dirButtons = { { 41, 34, 280, 24 }, { 41, 64, 280, 24 }, @@ -191,19 +197,23 @@ static void DrawGUISettings(int selection) { Gui::DrawStringCentered(20, 2, 0.6, UIThemes->TextColor(), Lang::get("GUI_SETTINGS"), 248, 0, font); - Gui::Draw_Rect(40, 44, 280, 24, (selection == 0 ? UIThemes->MarkSelected() : UIThemes->MarkUnselected())); - Gui::DrawString(47, 48, 0.5f, UIThemes->TextColor(), Lang::get("UNISTORE_BG"), 210, 0, font); - GFX::DrawToggle(toggleAbles[0].x, toggleAbles[0].y, config->usebg()); - Gui::DrawString(47, 75, 0.4f, UIThemes->TextColor(), Lang::get("UNISTORE_BG_DESC"), 265, 0, font, C2D_WordWrap); + Gui::Draw_Rect(40, 30, 280, 24, (selection == 0 ? UIThemes->MarkSelected() : UIThemes->MarkUnselected())); + Gui::DrawString(47, 34, 0.5f, UIThemes->TextColor(), Lang::get("UNISTORE_BG"), 210, 0, font); + GFX::DrawToggle(toggleAblesGui[0].x, toggleAblesGui[0].y, config->usebg()); + Gui::DrawString(47, 61, 0.4f, UIThemes->TextColor(), Lang::get("UNISTORE_BG_DESC"), 265, 0, font, C2D_WordWrap); - Gui::Draw_Rect(40, 120, 280, 24, (selection == 1 ? UIThemes->MarkSelected() : UIThemes->MarkUnselected())); - Gui::DrawString(47, 124, 0.5f, UIThemes->TextColor(), Lang::get("CUSTOM_FONT"), 210, 0, font); - GFX::DrawToggle(toggleAbles[1].x, toggleAbles[1].y, config->customfont()); - Gui::DrawString(47, 151, 0.4f, UIThemes->TextColor(), Lang::get("CUSTOM_FONT_DESC"), 265, 0, font, C2D_WordWrap); + Gui::Draw_Rect(40, 108, 280, 24, (selection == 1 ? UIThemes->MarkSelected() : UIThemes->MarkUnselected())); + Gui::DrawString(47, 112, 0.5f, UIThemes->TextColor(), Lang::get("USE_ACCENT_COLOR"), 210, 0, font); + GFX::DrawToggle(toggleAblesGui[1].x, toggleAblesGui[1].y, config->useAccentColor()); + + Gui::Draw_Rect(40, 136, 280, 24, (selection == 2 ? UIThemes->MarkSelected() : UIThemes->MarkUnselected())); + Gui::DrawString(47, 140, 0.5f, UIThemes->TextColor(), Lang::get("CUSTOM_FONT"), 210, 0, font); + GFX::DrawToggle(toggleAblesGui[2].x, toggleAblesGui[2].y, config->customfont()); + Gui::DrawString(47, 167, 0.4f, UIThemes->TextColor(), Lang::get("CUSTOM_FONT_DESC"), 265, 0, font, C2D_WordWrap); if (!Themes.empty()) { - Gui::Draw_Rect(40, 196, 280, 24, (selection == 2 ? UIThemes->MarkSelected() : UIThemes->MarkUnselected())); - Gui::DrawString(47, 200, 0.5f, UIThemes->TextColor(), Lang::get("ACTIVE_THEME") + ": " + config->theme(), 270, 0, font); + Gui::Draw_Rect(40, 212, 280, 24, (selection == 3 ? UIThemes->MarkSelected() : UIThemes->MarkUnselected())); + Gui::DrawString(47, 216, 0.5f, UIThemes->TextColor(), Lang::get("ACTIVE_THEME") + ": " + config->theme(), 270, 0, font); } } @@ -505,7 +515,7 @@ static void GUISettingsLogic(int &page, int &selection) { } if (hRepeat & KEY_DOWN) { - if (selection < (Themes.empty() ? 1 : 2)) selection++; + if (selection < (Themes.empty() ? 2 : 3)) selection++; } if (hRepeat & KEY_UP) { @@ -517,10 +527,13 @@ static void GUISettingsLogic(int &page, int &selection) { page = 0; selection = 3; - } else if (touching(touch, toggleAbles[0])) { + } else if (touching(touch, toggleAblesGui[0])) { config->usebg(!config->usebg()); - } else if (touching(touch, toggleAbles[1])) { + } else if (touching(touch, toggleAblesGui[1])) { + config->useAccentColor(!config->useAccentColor()); + + } else if (touching(touch, toggleAblesGui[2])) { config->customfont(!config->customfont()); (config->customfont() ? Init::LoadFont() : Init::UnloadFont()); @@ -537,12 +550,16 @@ static void GUISettingsLogic(int &page, int &selection) { break; case 1: + config->useAccentColor(!config->useAccentColor()); + break; + + case 2: config->customfont(!config->customfont()); (config->customfont() ? Init::LoadFont() : Init::UnloadFont()); break; - case 2: + case 3: if (!Themes.empty()) Overlays::SelectTheme(); break; } diff --git a/source/store/store.cpp b/source/store/store.cpp index 34cd9c816..5621b5951 100644 --- a/source/store/store.cpp +++ b/source/store/store.cpp @@ -28,6 +28,7 @@ #include "download.hpp" #include "gui.hpp" #include "scriptUtils.hpp" +#include "stringutils.hpp" #include "store.hpp" #include @@ -634,4 +635,21 @@ std::string Store::GetReleaseNotes(int index) const { } return ""; +} + +/* + Get the accent color of an entry. + + int index: The Entry Index. +*/ +u32 Store::GetAccentColorEntry(int index) const { + if (!this->valid) return 0; + if (index > (int)this->storeJson["storeContent"].size() - 1) return 0; // Empty. + + if (this->storeJson["storeContent"][index]["info"].contains("color") && this->storeJson["storeContent"][index]["info"]["color"].is_string()) { + const std::string color = this->storeJson["storeContent"][index]["info"]["color"]; + return StringUtils::ParseColorHexString(color); + } + + return 0; } \ No newline at end of file diff --git a/source/store/storeEntry.cpp b/source/store/storeEntry.cpp index f888abc94..d9816e213 100644 --- a/source/store/storeEntry.cpp +++ b/source/store/storeEntry.cpp @@ -52,6 +52,8 @@ StoreEntry::StoreEntry(const std::unique_ptr &store, const std::unique_pt this->SheetIndex = 0; this->EntryIndex = index; + this->AccentColor = store->GetAccentColorEntry(index); + this->FullCategory = store->GetCategoryIndex(index); this->FullConsole = store->GetConsoleEntry(index); diff --git a/source/utils/config.cpp b/source/utils/config.cpp index e2a980ddf..7fb33a843 100644 --- a/source/utils/config.cpp +++ b/source/utils/config.cpp @@ -136,6 +136,7 @@ Config::Config() { if (this->json.contains("UpdateCheck")) this->updatecheck(this->getBool("UpdateCheck")); if (this->json.contains("UpdateNightly")) this->updatenightly(this->getBool("UpdateNightly")); if (this->json.contains("UseBG")) this->usebg(this->getBool("UseBG")); + if (this->json.contains("UseAccentColor")) this->useAccentColor(this->getBool("UseAccentColor")); if (this->json.contains("CustomFont")) this->customfont(this->getBool("CustomFont")); if (this->json.contains("Shortcut_Path")) this->shortcut(this->getString("Shortcut_Path")); if (this->json.contains("Display_Changelog")) this->changelog(this->getBool("Display_Changelog")); @@ -176,6 +177,7 @@ void Config::save() { this->setBool("UpdateCheck", this->updatecheck()); this->setBool("UpdateNightly", this->updatenightly()); this->setBool("UseBG", this->usebg()); + this->setBool("UseAccentColor", this->useAccentColor()); this->setBool("CustomFont", this->customfont()); this->setString("Shortcut_Path", this->shortcut()); this->setBool("Display_Changelog", this->changelog()); diff --git a/source/utils/stringutils.cpp b/source/utils/stringutils.cpp index bd55f107c..6a3a0abac 100644 --- a/source/utils/stringutils.cpp +++ b/source/utils/stringutils.cpp @@ -26,6 +26,7 @@ #include "common.hpp" #include "stringutils.hpp" +#include #include /* @@ -117,4 +118,23 @@ std::string StringUtils::format(const char *fmt_str, ...) { std::unique_ptr formatted(fp, free); return std::string(formatted.get()); +} + +/* + Parse a color hex string (`#RRGGBB`) and return a C2D color. + Return 0 if parsing failed. +*/ +uint32_t StringUtils::ParseColorHexString(std::string_view str) { + if (str.size() != 7) return 0; + if (str[0] != '#') return 0; + + uint8_t colorVal[3]; + for (int i = 0; i < 3; i++) { + const char *colorValStart = str.data() + 1 + i * 2; + auto result = std::from_chars(colorValStart, colorValStart + 2, colorVal[i], 16); + if (result.ec != std::errc()) return 0; + if (result.ptr != colorValStart + 2) return 0; + } + + return C2D_Color32(colorVal[0], colorVal[1], colorVal[2], 255); } \ No newline at end of file