1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 05:38:11 +00:00

LibGfx+LibGUI+Clients: Make fonts findable by their qualified name

The qualified name of a font is "<Family> <Size> <Weight>". You can
get the QN of a Font via the Font::qualified_name() API, and you can
get any system font by QN from the GUI::FontDatabase. :^)
This commit is contained in:
Andreas Kling 2020-10-25 19:28:06 +01:00
parent 260b52215c
commit 9d347352a1
8 changed files with 57 additions and 61 deletions

View file

@ -330,17 +330,15 @@ int main(int argc, char** argv)
GUI::ActionGroup font_action_group; GUI::ActionGroup font_action_group;
font_action_group.set_exclusive(true); font_action_group.set_exclusive(true);
auto& font_menu = menubar->add_menu("Font"); auto& font_menu = menubar->add_menu("Font");
GUI::FontDatabase::the().for_each_fixed_width_font([&](const StringView& font_name) { GUI::FontDatabase::the().for_each_fixed_width_font([&](const Gfx::Font& font) {
auto action = GUI::Action::create_checkable(font_name, [&](auto& action) { auto action = GUI::Action::create_checkable(font.qualified_name(), [&](auto&) {
terminal.set_font(GUI::FontDatabase::the().get_by_name(action.text())); terminal.set_font(font);
auto metadata = GUI::FontDatabase::the().get_metadata_by_name(action.text()); config->write_entry("Text", "Font", font.qualified_name());
ASSERT(metadata.has_value());
config->write_entry("Text", "Font", metadata.value().path);
config->sync(); config->sync();
terminal.force_repaint(); terminal.force_repaint();
}); });
font_action_group.add_action(*action); font_action_group.add_action(*action);
if (terminal.font().name() == font_name) if (terminal.font().qualified_name() == font.qualified_name())
action->set_checked(true); action->set_checked(true);
font_menu.add_action(*action); font_menu.add_action(*action);
}); });

View file

@ -396,12 +396,12 @@ TextEditorWidget::TextEditorWidget()
font_actions.set_exclusive(true); font_actions.set_exclusive(true);
auto& font_menu = view_menu.add_submenu("Font"); auto& font_menu = view_menu.add_submenu("Font");
GUI::FontDatabase::the().for_each_fixed_width_font([&](const StringView& font_name) { GUI::FontDatabase::the().for_each_fixed_width_font([&](const Gfx::Font& font) {
auto action = GUI::Action::create_checkable(font_name, [&](auto& action) { auto action = GUI::Action::create_checkable(font.qualified_name(), [&](auto&) {
m_editor->set_font(GUI::FontDatabase::the().get_by_name(action.text())); m_editor->set_font(font);
m_editor->update(); m_editor->update();
}); });
if (m_editor->font().name() == font_name) if (m_editor->font().qualified_name() == font.qualified_name())
action->set_checked(true); action->set_checked(true);
font_actions.add_action(*action); font_actions.add_action(*action);
font_menu.add_action(*action); font_menu.add_action(*action);

View file

@ -61,20 +61,15 @@ void BoardView::set_board(const Game::Board* board)
void BoardView::pick_font() void BoardView::pick_font()
{ {
constexpr static auto liza_regular = "Liza Regular"; String best_font_name;
String best_font_name = liza_regular;
int best_font_size = -1; int best_font_size = -1;
auto& font_database = GUI::FontDatabase::the(); auto& font_database = GUI::FontDatabase::the();
font_database.for_each_font([&](const StringView& font_name) { font_database.for_each_font([&](const Gfx::Font& font) {
// Only consider variations of Liza Regular. if (font.family() != "Liza" || font.weight() != 700)
if (!font_name.starts_with(liza_regular))
return; return;
auto metadata = font_database.get_metadata_by_name(font_name); auto size = font.glyph_height();
if (!metadata.has_value())
return;
auto size = metadata.value().glyph_height;
if (size * 2 <= m_cell_size && size > best_font_size) { if (size * 2 <= m_cell_size && size > best_font_size) {
best_font_name = font_name; best_font_name = font.qualified_name();
best_font_size = size; best_font_size = size;
} }
}); });

View file

@ -24,6 +24,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <AK/NonnullRefPtrVector.h>
#include <AK/QuickSort.h> #include <AK/QuickSort.h>
#include <LibCore/DirIterator.h> #include <LibCore/DirIterator.h>
#include <LibGUI/FontDatabase.h> #include <LibGUI/FontDatabase.h>
@ -43,7 +44,12 @@ FontDatabase& FontDatabase::the()
return *s_the; return *s_the;
} }
struct FontDatabase::Private {
HashMap<String, RefPtr<Gfx::Font>> full_name_to_font_map;
};
FontDatabase::FontDatabase() FontDatabase::FontDatabase()
: m_private(make<Private>())
{ {
Core::DirIterator di("/res/fonts", Core::DirIterator::SkipDots); Core::DirIterator di("/res/fonts", Core::DirIterator::SkipDots);
if (di.has_error()) { if (di.has_error()) {
@ -57,11 +63,7 @@ FontDatabase::FontDatabase()
auto path = String::format("/res/fonts/%s", name.characters()); auto path = String::format("/res/fonts/%s", name.characters());
if (auto font = Gfx::Font::load_from_file(path)) { if (auto font = Gfx::Font::load_from_file(path)) {
Metadata metadata; m_private->full_name_to_font_map.set(font->qualified_name(), font);
metadata.path = path;
metadata.glyph_height = font->glyph_height();
metadata.is_fixed_width = font->is_fixed_width();
m_name_to_metadata.set(font->name(), move(metadata));
} }
} }
} }
@ -70,36 +72,39 @@ FontDatabase::~FontDatabase()
{ {
} }
void FontDatabase::for_each_font(Function<void(const StringView&)> callback) void FontDatabase::for_each_font(Function<void(const Gfx::Font&)> callback)
{ {
Vector<String> names; Vector<RefPtr<Gfx::Font>> fonts;
names.ensure_capacity(m_name_to_metadata.size()); fonts.ensure_capacity(m_private->full_name_to_font_map.size());
for (auto& it : m_name_to_metadata) for (auto& it : m_private->full_name_to_font_map)
names.append(it.key); fonts.append(it.value);
quick_sort(names); quick_sort(fonts, [](auto& a, auto& b) { return a->qualified_name() < b->qualified_name(); });
for (auto& name : names) for (auto& font : fonts)
callback(name); callback(*font);
} }
void FontDatabase::for_each_fixed_width_font(Function<void(const StringView&)> callback) void FontDatabase::for_each_fixed_width_font(Function<void(const Gfx::Font&)> callback)
{ {
Vector<String> names; Vector<RefPtr<Gfx::Font>> fonts;
names.ensure_capacity(m_name_to_metadata.size()); fonts.ensure_capacity(m_private->full_name_to_font_map.size());
for (auto& it : m_name_to_metadata) { for (auto& it : m_private->full_name_to_font_map) {
if (it.value.is_fixed_width) if (it.value->is_fixed_width())
names.append(it.key); fonts.append(it.value);
} }
quick_sort(names); quick_sort(fonts, [](auto& a, auto& b) { return a->qualified_name() < b->qualified_name(); });
for (auto& name : names) for (auto& font : fonts)
callback(name); callback(*font);
} }
RefPtr<Gfx::Font> FontDatabase::get_by_name(const StringView& name) RefPtr<Gfx::Font> FontDatabase::get_by_name(const StringView& name)
{ {
auto it = m_name_to_metadata.find(name); auto it = m_private->full_name_to_font_map.find(name);
if (it == m_name_to_metadata.end()) if (it == m_private->full_name_to_font_map.end()) {
dbgln("Font lookup failed: '{}'", name);
return nullptr; return nullptr;
return Gfx::Font::load_from_file((*it).value.path); }
dbgln("Font lookup succeeded: '{}'", name);
return it->value;
} }
} }

View file

@ -33,30 +33,20 @@
namespace GUI { namespace GUI {
struct Metadata {
String path;
bool is_fixed_width;
int glyph_height;
};
class FontDatabase { class FontDatabase {
public: public:
static FontDatabase& the(); static FontDatabase& the();
RefPtr<Gfx::Font> get_by_name(const StringView&); RefPtr<Gfx::Font> get_by_name(const StringView&);
void for_each_font(Function<void(const StringView&)>); void for_each_font(Function<void(const Gfx::Font&)>);
void for_each_fixed_width_font(Function<void(const StringView&)>); void for_each_fixed_width_font(Function<void(const Gfx::Font&)>);
Optional<Metadata> get_metadata_by_name(const StringView& name) const
{
return m_name_to_metadata.get(name);
}
private: private:
FontDatabase(); FontDatabase();
~FontDatabase(); ~FontDatabase();
HashMap<String, Metadata> m_name_to_metadata; struct Private;
OwnPtr<Private> m_private;
}; };
} }

View file

@ -363,4 +363,9 @@ void Font::set_family_fonts()
} }
} }
String Font::qualified_name() const
{
return String::formatted("{} {} {}", family(), presentation_size(), weight());
}
} }

View file

@ -151,6 +151,8 @@ public:
const String& family() const { return m_family; } const String& family() const { return m_family; }
void set_family(String family) { m_family = move(family); } void set_family(String family) { m_family = move(family); }
String qualified_name() const;
private: private:
Font(String name, String family, unsigned* rows, u8* widths, bool is_fixed_width, u8 glyph_width, u8 glyph_height, u8 glyph_spacing, FontTypes type, u8 baseline, u8 mean_line, u8 presentation_size, u16 weight); Font(String name, String family, unsigned* rows, u8* widths, bool is_fixed_width, u8 glyph_width, u8 glyph_height, u8 glyph_spacing, FontTypes type, u8 baseline, u8 mean_line, u8 presentation_size, u16 weight);

View file

@ -39,6 +39,7 @@
#include <LibGUI/Application.h> #include <LibGUI/Application.h>
#include <LibGUI/Clipboard.h> #include <LibGUI/Clipboard.h>
#include <LibGUI/DragOperation.h> #include <LibGUI/DragOperation.h>
#include <LibGUI/FontDatabase.h>
#include <LibGUI/Menu.h> #include <LibGUI/Menu.h>
#include <LibGUI/Painter.h> #include <LibGUI/Painter.h>
#include <LibGUI/ScrollBar.h> #include <LibGUI/ScrollBar.h>
@ -121,7 +122,7 @@ TerminalWidget::TerminalWidget(int ptm_fd, bool automatic_size_policy, RefPtr<Co
if (font_entry == "default") if (font_entry == "default")
set_font(Gfx::Font::default_fixed_width_font()); set_font(Gfx::Font::default_fixed_width_font());
else else
set_font(Gfx::Font::load_from_file(font_entry)); set_font(GUI::FontDatabase::the().get_by_name(font_entry));
m_line_height = font().glyph_height() + m_line_spacing; m_line_height = font().glyph_height() + m_line_spacing;