diff --git a/include/app/LedDisplay.hpp b/include/app/LedDisplay.hpp index d6c6f3a3..97e1f969 100644 --- a/include/app/LedDisplay.hpp +++ b/include/app/LedDisplay.hpp @@ -20,7 +20,7 @@ struct LedDisplaySeparator : widget::Widget { struct LedDisplayChoice : widget::OpaqueWidget { std::string text; - std::shared_ptr font; + std::string fontPath; math::Vec textOffset; NVGcolor color; NVGcolor bgColor; @@ -30,7 +30,7 @@ struct LedDisplayChoice : widget::OpaqueWidget { }; struct LedDisplayTextField : ui::TextField { - std::shared_ptr font; + std::string fontPath; math::Vec textOffset; NVGcolor color; LedDisplayTextField(); diff --git a/include/window.hpp b/include/window.hpp index 3f279eb0..294b28bd 100644 --- a/include/window.hpp +++ b/include/window.hpp @@ -58,10 +58,6 @@ struct Window { float windowRatio = 1.f; std::shared_ptr uiFont; - /** Use load*() instead of modifying these directly. */ - std::map> fontCache; - std::map> imageCache; - Window(); ~Window(); void run(); diff --git a/src/app/LedDisplay.cpp b/src/app/LedDisplay.cpp index 5d85bc1e..b961dd03 100644 --- a/src/app/LedDisplay.cpp +++ b/src/app/LedDisplay.cpp @@ -24,6 +24,7 @@ LedDisplaySeparator::LedDisplaySeparator() { box.size = math::Vec(); } + void LedDisplaySeparator::draw(const DrawArgs& args) { nvgBeginPath(args.vg); nvgMoveTo(args.vg, 0, 0); @@ -36,12 +37,13 @@ void LedDisplaySeparator::draw(const DrawArgs& args) { LedDisplayChoice::LedDisplayChoice() { box.size = mm2px(math::Vec(0, 28.0 / 3)); - font = APP->window->loadFont(asset::system("res/fonts/ShareTechMono-Regular.ttf")); + fontPath = asset::system("res/fonts/ShareTechMono-Regular.ttf"); color = nvgRGB(0xff, 0xd7, 0x14); bgColor = nvgRGBAf(0, 0, 0, 0); textOffset = math::Vec(10, 18); } + void LedDisplayChoice::draw(const DrawArgs& args) { nvgScissor(args.vg, RECT_ARGS(args.clipBox)); if (bgColor.a > 0.0) { @@ -51,7 +53,8 @@ void LedDisplayChoice::draw(const DrawArgs& args) { nvgFill(args.vg); } - if (font->handle >= 0) { + std::shared_ptr font = APP->window->loadFont(fontPath); + if (font && font->handle >= 0) { nvgFillColor(args.vg, color); nvgFontFaceId(args.vg, font->handle); nvgTextLetterSpacing(args.vg, 0.0); @@ -62,6 +65,7 @@ void LedDisplayChoice::draw(const DrawArgs& args) { nvgResetScissor(args.vg); } + void LedDisplayChoice::onButton(const ButtonEvent& e) { OpaqueWidget::onButton(e); @@ -74,7 +78,7 @@ void LedDisplayChoice::onButton(const ButtonEvent& e) { LedDisplayTextField::LedDisplayTextField() { - font = APP->window->loadFont(asset::system("res/fonts/ShareTechMono-Regular.ttf")); + fontPath = asset::system("res/fonts/ShareTechMono-Regular.ttf"); color = nvgRGB(0xff, 0xd7, 0x14); textOffset = math::Vec(5, 5); } @@ -90,16 +94,18 @@ void LedDisplayTextField::draw(const DrawArgs& args) { nvgFill(args.vg); // Text - if (font->handle >= 0) { + std::shared_ptr font = APP->window->loadFont(fontPath); + if (font && font->handle >= 0) { bndSetFont(font->handle); NVGcolor highlightColor = color; highlightColor.a = 0.5; int begin = std::min(cursor, selection); int end = (this == APP->event->selectedWidget) ? std::max(cursor, selection) : -1; - bndIconLabelCaret(args.vg, textOffset.x, textOffset.y, - box.size.x - 2 * textOffset.x, box.size.y - 2 * textOffset.y, - -1, color, 12, text.c_str(), highlightColor, begin, end); + bndIconLabelCaret(args.vg, + textOffset.x, textOffset.y, + box.size.x - 2 * textOffset.x, box.size.y - 2 * textOffset.y, + -1, color, 12, text.c_str(), highlightColor, begin, end); bndSetFont(APP->window->uiFont->handle); } @@ -107,11 +113,17 @@ void LedDisplayTextField::draw(const DrawArgs& args) { nvgResetScissor(args.vg); } + int LedDisplayTextField::getTextPosition(math::Vec mousePos) { + std::shared_ptr font = APP->window->loadFont(fontPath); + if (!font || !font->handle) + return 0; + bndSetFont(font->handle); - int textPos = bndIconLabelTextPosition(APP->window->vg, textOffset.x, textOffset.y, - box.size.x - 2 * textOffset.x, box.size.y - 2 * textOffset.y, - -1, 12, text.c_str(), mousePos.x, mousePos.y); + int textPos = bndIconLabelTextPosition(APP->window->vg, + textOffset.x, textOffset.y, + box.size.x - 2 * textOffset.x, box.size.y - 2 * textOffset.y, + -1, 12, text.c_str(), mousePos.x, mousePos.y); bndSetFont(APP->window->uiFont->handle); return textPos; } diff --git a/src/svg.cpp b/src/svg.cpp index 1d6fb9cc..f09372b4 100644 --- a/src/svg.cpp +++ b/src/svg.cpp @@ -1,6 +1,7 @@ #include #include #include +#include // #define DEBUG_ONLY(x) x @@ -18,12 +19,9 @@ Svg::~Svg() { void Svg::loadFile(const std::string& filename) { handle = nsvgParseFromFile(filename.c_str(), "px", SVG_DPI); - if (handle) { - INFO("Loaded SVG %s", filename.c_str()); - } - else { - WARN("Failed to load SVG %s", filename.c_str()); - } + if (!handle) + throw Exception("Failed to load SVG %s", filename.c_str()); + INFO("Loaded SVG %s", filename.c_str()); } @@ -31,12 +29,10 @@ void Svg::loadString(const std::string& str) { // nsvgParse modifies the input string std::string strCopy = str; handle = nsvgParse(&strCopy[0], "px", SVG_DPI); - if (handle) { - INFO("Loaded SVG"); - } - else { - WARN("Failed to load SVG"); - } + std::string strEllip = string::ellipsize(str, 40); + if (!handle) + throw Exception("Failed to load SVG \"%s\"", strEllip.c_str()); + INFO("Loaded SVG \"%s\"", strEllip.c_str()); } @@ -46,16 +42,26 @@ void Svg::draw(NVGcontext* vg) { -static std::map> svgCache; +static std::map> svgCache; std::shared_ptr Svg::load(const std::string& filename) { - auto sp = svgCache[filename].lock(); - if (!sp) { - svgCache[filename] = sp = std::make_shared(); - sp->loadFile(filename); + const auto& pair = svgCache.find(filename); + if (pair != svgCache.end()) + return pair->second; + + // Load svg + std::shared_ptr svg; + try { + svg = std::make_shared(); + svg->loadFile(filename); + } + catch (Exception& e) { + WARN("%s", e.what()); + svg = NULL; } - return sp; + svgCache[filename] = svg; + return svg; } diff --git a/src/window.cpp b/src/window.cpp index 71e59c05..08fdb0c4 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -29,12 +29,9 @@ namespace rack { void Font::loadFile(const std::string& filename, NVGcontext* vg) { this->vg = vg; handle = nvgCreateFont(vg, filename.c_str(), filename.c_str()); - if (handle >= 0) { - INFO("Loaded font %s", filename.c_str()); - } - else { - WARN("Failed to load font %s", filename.c_str()); - } + if (handle < 0) + throw Exception("Failed to load font %s", filename.c_str()); + INFO("Loaded font %s", filename.c_str()); } @@ -51,12 +48,9 @@ std::shared_ptr Font::load(const std::string& filename) { void Image::loadFile(const std::string& filename, NVGcontext* vg) { this->vg = vg; handle = nvgCreateImage(vg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); - if (handle > 0) { - INFO("Loaded image %s", filename.c_str()); - } - else { - WARN("Failed to load image %s", filename.c_str()); - } + if (handle <= 0) + throw Exception("Failed to load image %s", filename.c_str()); + INFO("Loaded image %s", filename.c_str()); } @@ -88,6 +82,9 @@ struct Window::Internal { double lastFrameTime = 0.0; math::Vec lastMousePos; + + std::map> fontCache; + std::map> imageCache; }; @@ -611,22 +608,42 @@ double Window::getFrameTimeOverdue() { std::shared_ptr Window::loadFont(const std::string& filename) { - auto sp = fontCache[filename].lock(); - if (!sp) { - fontCache[filename] = sp = std::make_shared(); - sp->loadFile(filename, vg); + const auto& pair = internal->fontCache.find(filename); + if (pair != internal->fontCache.end()) + return pair->second; + + // Load font + std::shared_ptr font; + try { + font = std::make_shared(); + font->loadFile(filename, vg); } - return sp; + catch (Exception& e) { + WARN("%s", e.what()); + font = NULL; + } + internal->fontCache[filename] = font; + return font; } std::shared_ptr Window::loadImage(const std::string& filename) { - auto sp = imageCache[filename].lock(); - if (!sp) { - imageCache[filename] = sp = std::make_shared(); - sp->loadFile(filename, vg); - } - return sp; + const auto& pair = internal->imageCache.find(filename); + if (pair != internal->imageCache.end()) + return pair->second; + + // Load image + std::shared_ptr image; + try { + image = std::make_shared(); + image->loadFile(filename, vg); + } + catch (Exception& e) { + WARN("%s", e.what()); + image = NULL; + } + internal->imageCache[filename] = image; + return image; }