mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 18:22:45 +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:
		
							parent
							
								
									260b52215c
								
							
						
					
					
						commit
						9d347352a1
					
				
					 8 changed files with 57 additions and 61 deletions
				
			
		|  | @ -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); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -363,4 +363,9 @@ void Font::set_family_fonts() | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | String Font::qualified_name() const | ||||||
|  | { | ||||||
|  |     return String::formatted("{} {} {}", family(), presentation_size(), weight()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling