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; | ||||
|     font_action_group.set_exclusive(true); | ||||
|     auto& font_menu = menubar->add_menu("Font"); | ||||
|     GUI::FontDatabase::the().for_each_fixed_width_font([&](const StringView& font_name) { | ||||
|         auto action = GUI::Action::create_checkable(font_name, [&](auto& action) { | ||||
|             terminal.set_font(GUI::FontDatabase::the().get_by_name(action.text())); | ||||
|             auto metadata = GUI::FontDatabase::the().get_metadata_by_name(action.text()); | ||||
|             ASSERT(metadata.has_value()); | ||||
|             config->write_entry("Text", "Font", metadata.value().path); | ||||
|     GUI::FontDatabase::the().for_each_fixed_width_font([&](const Gfx::Font& font) { | ||||
|         auto action = GUI::Action::create_checkable(font.qualified_name(), [&](auto&) { | ||||
|             terminal.set_font(font); | ||||
|             config->write_entry("Text", "Font", font.qualified_name()); | ||||
|             config->sync(); | ||||
|             terminal.force_repaint(); | ||||
|         }); | ||||
|         font_action_group.add_action(*action); | ||||
|         if (terminal.font().name() == font_name) | ||||
|         if (terminal.font().qualified_name() == font.qualified_name()) | ||||
|             action->set_checked(true); | ||||
|         font_menu.add_action(*action); | ||||
|     }); | ||||
|  |  | |||
|  | @ -396,12 +396,12 @@ TextEditorWidget::TextEditorWidget() | |||
|     font_actions.set_exclusive(true); | ||||
| 
 | ||||
|     auto& font_menu = view_menu.add_submenu("Font"); | ||||
|     GUI::FontDatabase::the().for_each_fixed_width_font([&](const StringView& font_name) { | ||||
|         auto action = GUI::Action::create_checkable(font_name, [&](auto& action) { | ||||
|             m_editor->set_font(GUI::FontDatabase::the().get_by_name(action.text())); | ||||
|     GUI::FontDatabase::the().for_each_fixed_width_font([&](const Gfx::Font& font) { | ||||
|         auto action = GUI::Action::create_checkable(font.qualified_name(), [&](auto&) { | ||||
|             m_editor->set_font(font); | ||||
|             m_editor->update(); | ||||
|         }); | ||||
|         if (m_editor->font().name() == font_name) | ||||
|         if (m_editor->font().qualified_name() == font.qualified_name()) | ||||
|             action->set_checked(true); | ||||
|         font_actions.add_action(*action); | ||||
|         font_menu.add_action(*action); | ||||
|  |  | |||
|  | @ -61,20 +61,15 @@ void BoardView::set_board(const Game::Board* board) | |||
| 
 | ||||
| void BoardView::pick_font() | ||||
| { | ||||
|     constexpr static auto liza_regular = "Liza Regular"; | ||||
|     String best_font_name = liza_regular; | ||||
|     String best_font_name; | ||||
|     int best_font_size = -1; | ||||
|     auto& font_database = GUI::FontDatabase::the(); | ||||
|     font_database.for_each_font([&](const StringView& font_name) { | ||||
|         // Only consider variations of Liza Regular.
 | ||||
|         if (!font_name.starts_with(liza_regular)) | ||||
|     font_database.for_each_font([&](const Gfx::Font& font) { | ||||
|         if (font.family() != "Liza" || font.weight() != 700) | ||||
|             return; | ||||
|         auto metadata = font_database.get_metadata_by_name(font_name); | ||||
|         if (!metadata.has_value()) | ||||
|             return; | ||||
|         auto size = metadata.value().glyph_height; | ||||
|         auto size = font.glyph_height(); | ||||
|         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; | ||||
|         } | ||||
|     }); | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ | |||
|  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| #include <AK/NonnullRefPtrVector.h> | ||||
| #include <AK/QuickSort.h> | ||||
| #include <LibCore/DirIterator.h> | ||||
| #include <LibGUI/FontDatabase.h> | ||||
|  | @ -43,7 +44,12 @@ FontDatabase& FontDatabase::the() | |||
|     return *s_the; | ||||
| } | ||||
| 
 | ||||
| struct FontDatabase::Private { | ||||
|     HashMap<String, RefPtr<Gfx::Font>> full_name_to_font_map; | ||||
| }; | ||||
| 
 | ||||
| FontDatabase::FontDatabase() | ||||
|     : m_private(make<Private>()) | ||||
| { | ||||
|     Core::DirIterator di("/res/fonts", Core::DirIterator::SkipDots); | ||||
|     if (di.has_error()) { | ||||
|  | @ -57,11 +63,7 @@ FontDatabase::FontDatabase() | |||
| 
 | ||||
|         auto path = String::format("/res/fonts/%s", name.characters()); | ||||
|         if (auto font = Gfx::Font::load_from_file(path)) { | ||||
|             Metadata metadata; | ||||
|             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)); | ||||
|             m_private->full_name_to_font_map.set(font->qualified_name(), font); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -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; | ||||
|     names.ensure_capacity(m_name_to_metadata.size()); | ||||
|     for (auto& it : m_name_to_metadata) | ||||
|         names.append(it.key); | ||||
|     quick_sort(names); | ||||
|     for (auto& name : names) | ||||
|         callback(name); | ||||
|     Vector<RefPtr<Gfx::Font>> fonts; | ||||
|     fonts.ensure_capacity(m_private->full_name_to_font_map.size()); | ||||
|     for (auto& it : m_private->full_name_to_font_map) | ||||
|         fonts.append(it.value); | ||||
|     quick_sort(fonts, [](auto& a, auto& b) { return a->qualified_name() < b->qualified_name(); }); | ||||
|     for (auto& font : fonts) | ||||
|         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; | ||||
|     names.ensure_capacity(m_name_to_metadata.size()); | ||||
|     for (auto& it : m_name_to_metadata) { | ||||
|         if (it.value.is_fixed_width) | ||||
|             names.append(it.key); | ||||
|     Vector<RefPtr<Gfx::Font>> fonts; | ||||
|     fonts.ensure_capacity(m_private->full_name_to_font_map.size()); | ||||
|     for (auto& it : m_private->full_name_to_font_map) { | ||||
|         if (it.value->is_fixed_width()) | ||||
|             fonts.append(it.value); | ||||
|     } | ||||
|     quick_sort(names); | ||||
|     for (auto& name : names) | ||||
|         callback(name); | ||||
|     quick_sort(fonts, [](auto& a, auto& b) { return a->qualified_name() < b->qualified_name(); }); | ||||
|     for (auto& font : fonts) | ||||
|         callback(*font); | ||||
| } | ||||
| 
 | ||||
| RefPtr<Gfx::Font> FontDatabase::get_by_name(const StringView& name) | ||||
| { | ||||
|     auto it = m_name_to_metadata.find(name); | ||||
|     if (it == m_name_to_metadata.end()) | ||||
|     auto it = m_private->full_name_to_font_map.find(name); | ||||
|     if (it == m_private->full_name_to_font_map.end()) { | ||||
|         dbgln("Font lookup failed: '{}'", name); | ||||
|         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 { | ||||
| 
 | ||||
| struct Metadata { | ||||
|     String path; | ||||
|     bool is_fixed_width; | ||||
|     int glyph_height; | ||||
| }; | ||||
| 
 | ||||
| class FontDatabase { | ||||
| public: | ||||
|     static FontDatabase& the(); | ||||
| 
 | ||||
|     RefPtr<Gfx::Font> get_by_name(const StringView&); | ||||
|     void for_each_font(Function<void(const StringView&)>); | ||||
|     void for_each_fixed_width_font(Function<void(const StringView&)>); | ||||
| 
 | ||||
|     Optional<Metadata> get_metadata_by_name(const StringView& name) const | ||||
|     { | ||||
|         return m_name_to_metadata.get(name); | ||||
|     } | ||||
|     void for_each_font(Function<void(const Gfx::Font&)>); | ||||
|     void for_each_fixed_width_font(Function<void(const Gfx::Font&)>); | ||||
| 
 | ||||
| private: | ||||
|     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; } | ||||
|     void set_family(String family) { m_family = move(family); } | ||||
| 
 | ||||
|     String qualified_name() const; | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -39,6 +39,7 @@ | |||
| #include <LibGUI/Application.h> | ||||
| #include <LibGUI/Clipboard.h> | ||||
| #include <LibGUI/DragOperation.h> | ||||
| #include <LibGUI/FontDatabase.h> | ||||
| #include <LibGUI/Menu.h> | ||||
| #include <LibGUI/Painter.h> | ||||
| #include <LibGUI/ScrollBar.h> | ||||
|  | @ -121,7 +122,7 @@ TerminalWidget::TerminalWidget(int ptm_fd, bool automatic_size_policy, RefPtr<Co | |||
|     if (font_entry == "default") | ||||
|         set_font(Gfx::Font::default_fixed_width_font()); | ||||
|     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; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling