diff --git a/include/zwidget/core/resourcedata.h b/include/zwidget/core/resourcedata.h index 1aeb132..f29ab26 100644 --- a/include/zwidget/core/resourcedata.h +++ b/include/zwidget/core/resourcedata.h @@ -4,5 +4,11 @@ #include #include -std::vector LoadWidgetFontData(const std::string& name); -std::vector LoadWidgetImageData(const std::string& name); +struct SingleFontData +{ + std::vector fontdata; + std::string language; +}; + +std::vector LoadWidgetFontData(const std::string& name); +std::vector LoadWidgetData(const std::string& name); diff --git a/include/zwidget/widgets/checkboxlabel/checkboxlabel.h b/include/zwidget/widgets/checkboxlabel/checkboxlabel.h index 8bcaf5e..0bd8abc 100644 --- a/include/zwidget/widgets/checkboxlabel/checkboxlabel.h +++ b/include/zwidget/widgets/checkboxlabel/checkboxlabel.h @@ -16,6 +16,8 @@ class CheckboxLabel : public Widget void Toggle(); double GetPreferredHeight() const; + std::function FuncChanged; + void SetRadioStyle(bool on) { radiostyle = on; } protected: void OnPaint(Canvas* canvas) override; @@ -27,5 +29,6 @@ class CheckboxLabel : public Widget private: std::string text; bool checked = false; + bool radiostyle = false; bool mouseDownActive = false; }; diff --git a/include/zwidget/widgets/listview/listview.h b/include/zwidget/widgets/listview/listview.h index c7caca8..879bda1 100644 --- a/include/zwidget/widgets/listview/listview.h +++ b/include/zwidget/widgets/listview/listview.h @@ -19,6 +19,7 @@ class ListView : public Widget void Activate(); + std::function OnChanged; std::function OnActivated; protected: diff --git a/include/zwidget/widgets/textedit/textedit.h b/include/zwidget/widgets/textedit/textedit.h index c7dcbf5..e2c6c76 100644 --- a/include/zwidget/widgets/textedit/textedit.h +++ b/include/zwidget/widgets/textedit/textedit.h @@ -149,7 +149,7 @@ class TextEdit : public Widget bool select_all_on_focus_gain = false; - std::shared_ptr font = Font::Create("Segoe UI", 12.0); + std::shared_ptr font = Font::Create("NotoSans", 12.0); template static T clamp(T val, T minval, T maxval) { return std::max(std::min(val, maxval), minval); } diff --git a/src/core/canvas.cpp b/src/core/canvas.cpp index cba12f5..d9f14ce 100644 --- a/src/core/canvas.cpp +++ b/src/core/canvas.cpp @@ -41,9 +41,10 @@ class CanvasGlyph class CanvasFont { public: - CanvasFont(const std::string& fontname, double height) : fontname(fontname), height(height) + CanvasFont(const std::string& fontname, double height, std::vector data) : fontname(fontname), height(height) { - ttf = std::make_unique(std::make_shared(LoadWidgetFontData(fontname))); + auto tdata = std::make_shared(std::move(data)); + ttf = std::make_unique(tdata); textmetrics = ttf->GetTextMetrics(height); } @@ -54,6 +55,7 @@ class CanvasFont CanvasGlyph* getGlyph(uint32_t utfchar) { uint32_t glyphIndex = ttf->GetGlyphIndex(utfchar); + if (glyphIndex == 0) return nullptr; auto& glyph = glyphs[glyphIndex]; if (glyph) @@ -120,6 +122,52 @@ class CanvasFont std::unordered_map> glyphs; }; +class CanvasFontGroup +{ +public: + struct SingleFont + { + std::unique_ptr font; + std::string language; + }; + CanvasFontGroup(const std::string& fontname, double height) : height(height) + { + auto fontdata = LoadWidgetFontData(fontname); + fonts.resize(fontdata.size()); + for (size_t i = 0; i < fonts.size(); i++) + { + fonts[i].font = std::make_unique(fontname, height, fontdata[i].fontdata); + fonts[i].language = fontdata[i].language; + } + } + + CanvasGlyph* getGlyph(uint32_t utfchar, const char* lang = nullptr) + { + for (int i = 0; i < 2; i++) + { + for (auto& fd : fonts) + { + if (i == 1 || lang == nullptr || *lang == 0 || fd.language.empty() || fd.language == lang) + { + auto g = fd.font->getGlyph(utfchar); + if (g) return g; + } + } + } + + return nullptr; + } + + TrueTypeTextMetrics& GetTextMetrics() + { + return fonts[0].font->textmetrics; + } + + double height; + std::vector fonts; + +}; + class BitmapCanvas : public Canvas { public: @@ -172,6 +220,8 @@ class BitmapCanvas : public Canvas int getClipMaxX() const; int getClipMaxY() const; + void setLanguage(const char* lang) { language = lang; } + std::unique_ptr createTexture(int width, int height, const void* pixels, ImageFormat format = ImageFormat::B8G8R8A8); template @@ -179,7 +229,7 @@ class BitmapCanvas : public Canvas DisplayWindow* window = nullptr; - std::unique_ptr font; + std::unique_ptr font; std::unique_ptr whiteTexture; Point origin; @@ -191,6 +241,7 @@ class BitmapCanvas : public Canvas std::vector pixels; std::unordered_map, std::unique_ptr> imageTextures; + std::string language; }; BitmapCanvas::BitmapCanvas(DisplayWindow* window) : window(window) @@ -198,7 +249,7 @@ BitmapCanvas::BitmapCanvas(DisplayWindow* window) : window(window) uiscale = window->GetDpiScale(); uint32_t white = 0xffffffff; whiteTexture = createTexture(1, 1, &white); - font = std::make_unique("Segoe UI", 13.0*uiscale); + font = std::make_unique("NotoSans", 13.0 * uiscale); } BitmapCanvas::~BitmapCanvas() @@ -358,8 +409,8 @@ void BitmapCanvas::drawText(const Point& pos, const Colorf& color, const std::st UTF8Reader reader(text.data(), text.size()); while (!reader.is_end()) { - CanvasGlyph* glyph = font->getGlyph(reader.character()); - if (!glyph->texture) + CanvasGlyph* glyph = font->getGlyph(reader.character(), language.c_str()); + if (!glyph || !glyph->texture) { glyph = font->getGlyph(32); } @@ -379,13 +430,13 @@ void BitmapCanvas::drawText(const Point& pos, const Colorf& color, const std::st Rect BitmapCanvas::measureText(const std::string& text) { double x = 0.0; - double y = font->textmetrics.ascender - font->textmetrics.descender; + double y = font->GetTextMetrics().ascender - font->GetTextMetrics().descender; UTF8Reader reader(text.data(), text.size()); while (!reader.is_end()) { - CanvasGlyph* glyph = font->getGlyph(reader.character()); - if (!glyph->texture) + CanvasGlyph* glyph = font->getGlyph(reader.character(), language.c_str()); + if (!glyph || !glyph->texture) { glyph = font->getGlyph(32); } @@ -401,8 +452,9 @@ VerticalTextPosition BitmapCanvas::verticalTextAlign() { VerticalTextPosition align; align.top = 0.0f; - align.baseline = font->textmetrics.ascender / uiscale; - align.bottom = (font->textmetrics.ascender - font->textmetrics.descender) / uiscale; + auto tm = font->GetTextMetrics(); + align.baseline = tm.ascender / uiscale; + align.bottom = (tm.ascender - tm.descender) / uiscale; return align; } diff --git a/src/core/image.cpp b/src/core/image.cpp index 91e201a..3998d78 100644 --- a/src/core/image.cpp +++ b/src/core/image.cpp @@ -62,7 +62,7 @@ std::shared_ptr Image::LoadResource(const std::string& resourcename, doub if (extension == "png") { - auto filedata = LoadWidgetImageData(resourcename); + auto filedata = LoadWidgetData(resourcename); std::vector pixels; unsigned long width = 0, height = 0; @@ -74,7 +74,7 @@ std::shared_ptr Image::LoadResource(const std::string& resourcename, doub } else if (extension == "svg") { - auto filedata = LoadWidgetImageData(resourcename); + auto filedata = LoadWidgetData(resourcename); filedata.push_back(0); NSVGimage* svgimage = nsvgParse((char*)filedata.data(), "px", (float)(96.0 * dpiscale)); diff --git a/src/core/nanosvg/nanosvg.h b/src/core/nanosvg/nanosvg.h index 60a3238..55f9bc5 100644 --- a/src/core/nanosvg/nanosvg.h +++ b/src/core/nanosvg/nanosvg.h @@ -192,6 +192,11 @@ void nsvgDelete(NSVGimage* image); #include #include +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4244) +#endif + #define NSVG_PI (3.14159265358979323846264338327f) #define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs. @@ -3093,6 +3098,10 @@ void nsvgDelete(NSVGimage* image) free(image); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + #endif // NANOSVG_IMPLEMENTATION #endif // NANOSVG_H diff --git a/src/widgets/checkboxlabel/checkboxlabel.cpp b/src/widgets/checkboxlabel/checkboxlabel.cpp index 80963fc..d8f3026 100644 --- a/src/widgets/checkboxlabel/checkboxlabel.cpp +++ b/src/widgets/checkboxlabel/checkboxlabel.cpp @@ -42,14 +42,14 @@ void CheckboxLabel::OnPaint(Canvas* canvas) { if (checked) { - canvas->fillRect(Rect::xywh(0.0, GetHeight() * 0.5 - 5.0, 10.0, 10.0), Colorf::fromRgba8(100, 100, 100)); - canvas->fillRect(Rect::xywh(1.0, GetHeight() * 0.5 - 4.0, 8.0, 8.0), Colorf::fromRgba8(51, 51, 51)); - canvas->fillRect(Rect::xywh(2.0, GetHeight() * 0.5 - 3.0, 6.0, 6.0), Colorf::fromRgba8(226, 223, 219)); + canvas->fillRect(Rect::xywh(0.0, GetHeight() * 0.5 - 6.0, 10.0, 10.0), Colorf::fromRgba8(100, 100, 100)); + canvas->fillRect(Rect::xywh(1.0, GetHeight() * 0.5 - 5.0, 8.0, 8.0), Colorf::fromRgba8(51, 51, 51)); + canvas->fillRect(Rect::xywh(2.0, GetHeight() * 0.5 - 4.0, 6.0, 6.0), Colorf::fromRgba8(226, 223, 219)); } else { - canvas->fillRect(Rect::xywh(0.0, GetHeight() * 0.5 - 5.0, 10.0, 10.0), Colorf::fromRgba8(68, 68, 68)); - canvas->fillRect(Rect::xywh(1.0, GetHeight() * 0.5 - 4.0, 8.0, 8.0), Colorf::fromRgba8(51, 51, 51)); + canvas->fillRect(Rect::xywh(0.0, GetHeight() * 0.5 - 6.0, 10.0, 10.0), Colorf::fromRgba8(99, 99, 99)); + canvas->fillRect(Rect::xywh(1.0, GetHeight() * 0.5 - 5.0, 8.0, 8.0), Colorf::fromRgba8(51, 51, 51)); } canvas->drawText(Point(14.0, GetHeight() - 5.0), Colorf::fromRgba8(255, 255, 255), text); @@ -83,6 +83,8 @@ void CheckboxLabel::OnKeyUp(EInputKey key) void CheckboxLabel::Toggle() { - checked = !checked; + bool oldchecked = checked; + checked = radiostyle? true : !checked; Update(); + if (checked != oldchecked && FuncChanged) FuncChanged(checked); } diff --git a/src/widgets/listview/listview.cpp b/src/widgets/listview/listview.cpp index 4321277..680b41d 100644 --- a/src/widgets/listview/listview.cpp +++ b/src/widgets/listview/listview.cpp @@ -27,6 +27,7 @@ void ListView::SetSelectedItem(int index) if (selectedItem != index && index >= 0 && index < items.size()) { selectedItem = index; + if (OnChanged) OnChanged(selectedItem); Update(); } }