#include #include #include #include #include #include #include #include using namespace bwidgets; const Color Font::default_color_bg {255, 255, 255, SDL_ALPHA_OPAQUE}; const Color Font::default_color_fg {0, 0, 0, SDL_ALPHA_OPAQUE}; Font::Font(TTF_Font* f) : _data {ptr_or_throw(f)}, ascent {TTF_FontAscent(f)}, descent {TTF_FontDescent(f)}, faces {TTF_FontFaces(f)}, family_name {TTF_FontFaceFamilyName(f)}, fixed_width {TTF_FontFaceIsFixedWidth(f) != 0}, height {TTF_FontHeight(f)}, line_skip {TTF_FontLineSkip(f)}, style_name {TTF_FontFaceStyleName(f)} {} Font::Font(const std::string_view file, const int size) : Font {TTF_OpenFont(file.data(), size)} {} auto Font::hinting() const noexcept -> Font::Hinting { return static_cast(TTF_GetFontHinting(_data.get())); } auto Font::hinting(const Font::Hinting h) noexcept -> Font* { TTF_SetFontHinting(_data.get(), static_cast(h)); return this; } auto Font::kerning() const noexcept -> bool { return TTF_GetFontKerning(_data.get()) != 0; } auto Font::kerning(const bool allowed) noexcept -> Font* { TTF_SetFontKerning(_data.get(), static_cast(allowed)); return this; } auto Font::outline() const noexcept -> int { return TTF_GetFontOutline(_data.get()); } auto Font::outline(const int size) noexcept -> Font* { TTF_SetFontOutline(_data.get(), size); return this; } auto Font::render(const RenderMode m, const std::string_view str, const Color fg, const Color bg) -> std::unique_ptr { const char* const c_str = str.empty() ? " " : str.data(); auto renderer = [bg, c_str, fg, m, this]() -> std::function { switch (m) { case RenderMode::BLENDED: return [fg, c_str, this]() { return TTF_RenderUTF8_Blended(_data.get(), c_str, fg()); }; case RenderMode::SHADED: return [bg, fg, c_str, this]() { return TTF_RenderUTF8_Shaded(_data.get(), c_str, fg(), bg()); }; case RenderMode::SOLID: return [fg, c_str, this]() { return TTF_RenderUTF8_Solid(_data.get(), c_str, fg()); }; default: throw std::logic_error("missing switch case."); } }(); return std::unique_ptr(ptr_or_throw(renderer())); } auto Font::style() const noexcept -> uint8_t { return TTF_GetFontStyle(_data.get()); } auto Font::style(const uint8_t s) noexcept -> Font* { TTF_SetFontStyle(_data.get(), s); return this; } auto Font::text_size(const std::string_view str) const noexcept -> Size { Size s {}; TTF_SizeUTF8(_data.get(), str.data(), &s.w, &s.h); return s; } auto Font::find(const std::string_view pat) -> std::string { const auto conf = std::unique_ptr( ptr_or_throw(FcInitLoadConfigAndFonts(), "fontconfig init failed.")); const auto pattern = [&conf, pat]() { auto pattern = std::unique_ptr(ptr_or_throw( FcNameParse(reinterpret_cast(pat.data())), "pattern parsing failed")); success_or_throw( FcConfigSubstitute(conf.get(), pattern.get(), FcMatchPattern), "FcConfigSubstitute failed", [](auto code) { return code == FcTrue; }); return pattern; }(); FcDefaultSubstitute(pattern.get()); std::string file_path = [&conf, &pattern]() { FcResult res {}; const auto font = std::unique_ptr(ptr_or_throw( FcFontMatch(conf.get(), pattern.get(), &res), "no font found.")); if (FcChar8* file = nullptr; FcPatternGetString(font.get(), FC_FILE, 0, &file) == FcResultMatch) { // "I know what I'm doing" // NOLINTNEXTLINE std::string _file_path {reinterpret_cast(file)}; return _file_path; } throw FCError("no font found."); }(); return file_path; }