From cdfa2614b958b4e70987cbb3e4c51136f60f70d9 Mon Sep 17 00:00:00 2001 From: thankyouverycool <66646555+thankyouverycool@users.noreply.github.com> Date: Sat, 10 Apr 2021 13:40:59 -0400 Subject: [PATCH] FontEditor: Move menu bar into editor and tweak several widgets Actions are now shared between menu bar and toolbar. Adds an edit menu to complement toolbar actions. Glyphs are now passed as ints instead of u8s; fixes Latin Extended+ glyphs failing to update in real time on map. Converts weight and type to more human-readable combo box lists. Selected glyph now scrolls into view on load. --- .../Applications/FontEditor/FontEditor.cpp | 146 ++++++++++++++---- Userland/Applications/FontEditor/FontEditor.h | 19 ++- .../FontEditor/FontEditorWindow.gml | 43 +++--- .../FontEditor/GlyphEditorWidget.h | 2 +- .../Applications/FontEditor/GlyphMapWidget.h | 2 +- Userland/Applications/FontEditor/main.cpp | 77 +-------- 6 files changed, 167 insertions(+), 122 deletions(-) diff --git a/Userland/Applications/FontEditor/FontEditor.cpp b/Userland/Applications/FontEditor/FontEditor.cpp index 393cb01965..8d44690be4 100644 --- a/Userland/Applications/FontEditor/FontEditor.cpp +++ b/Userland/Applications/FontEditor/FontEditor.cpp @@ -29,13 +29,20 @@ #include "GlyphMapWidget.h" #include #include +#include #include +#include #include #include #include +#include +#include #include +#include #include #include +#include +#include #include #include #include @@ -67,7 +74,6 @@ static RefPtr create_font_preview_window(FontEditorWidget& editor) preview_box.layout()->set_margins({ 8, 8, 8, 8 }); auto& preview_label = preview_box.add(); - preview_label.set_text("Five quacking zephyrs jolt my wax bed!"); preview_label.set_font(editor.edited_font()); editor.on_initialize = [&] { @@ -75,10 +81,14 @@ static RefPtr create_font_preview_window(FontEditorWidget& editor) }; auto& preview_textbox = main_widget.add(); - preview_textbox.set_text("Five quacking zephyrs jolt my wax bed!"); + preview_textbox.set_text("waxy and quivering jocks fumble the pizza"); + preview_textbox.set_placeholder("Preview text"); preview_textbox.on_change = [&] { - preview_label.set_text(preview_textbox.text()); + auto preview = String::formatted("{}\n{}", + preview_textbox.text(), + preview_textbox.text().to_uppercase()); + preview_label.set_text(preview); }; return window; @@ -97,7 +107,8 @@ FontEditorWidget::FontEditorWidget(const String& path, RefPtr&& m_name_textbox = *find_descendant_of_type_named("name_textbox"); m_family_textbox = *find_descendant_of_type_named("family_textbox"); m_presentation_spinbox = *find_descendant_of_type_named("presentation_spinbox"); - m_weight_spinbox = *find_descendant_of_type_named("weight_spinbox"); + m_weight_combobox = *find_descendant_of_type_named("weight_combobox"); + m_type_combobox = *find_descendant_of_type_named("type_combobox"); m_spacing_spinbox = *find_descendant_of_type_named("spacing_spinbox"); m_mean_line_spinbox = *find_descendant_of_type_named("mean_line_spinbox"); m_baseline_spinbox = *find_descendant_of_type_named("baseline_spinbox"); @@ -132,60 +143,83 @@ FontEditorWidget::FontEditorWidget(const String& path, RefPtr&& window()->set_title(String::formatted("{} - Font Editor", open_path.value())); initialize(open_path.value(), move(new_font)); }); - auto save_action = GUI::CommonActions::make_save_action([&](auto&) { + m_save_action = GUI::CommonActions::make_save_action([&](auto&) { save_as(m_path); }); - auto cut_action = GUI::CommonActions::make_cut_action([&](auto&) { + m_save_as_action = GUI::CommonActions::make_save_as_action([&](auto&) { + LexicalPath lexical_path(m_path); + Optional save_path = GUI::FilePicker::get_save_filepath(window(), lexical_path.title(), lexical_path.extension()); + if (!save_path.has_value()) + return; + + if (save_as(save_path.value())) + window()->set_title(String::formatted("{} - Font Editor", save_path.value())); + }); + m_cut_action = GUI::CommonActions::make_cut_action([&](auto&) { m_glyph_editor_widget->cut_glyph(); }); - auto copy_action = GUI::CommonActions::make_copy_action([&](auto&) { + m_copy_action = GUI::CommonActions::make_copy_action([&](auto&) { m_glyph_editor_widget->copy_glyph(); }); - auto paste_action = GUI::CommonActions::make_paste_action([&](auto&) { + m_paste_action = GUI::CommonActions::make_paste_action([&](auto&) { m_glyph_editor_widget->paste_glyph(); m_glyph_map_widget->update_glyph(m_glyph_map_widget->selected_glyph()); }); - auto delete_action = GUI::CommonActions::make_delete_action([&](auto&) { + m_paste_action->set_enabled(GUI::Clipboard::the().mime_type() == "glyph/x-fonteditor"); + m_delete_action = GUI::CommonActions::make_delete_action([&](auto&) { m_edited_font->set_glyph_width(m_glyph_map_widget->selected_glyph(), m_edited_font->max_glyph_width()); m_glyph_editor_widget->delete_glyph(); m_glyph_map_widget->update_glyph(m_glyph_map_widget->selected_glyph()); m_glyph_editor_width_spinbox->set_value(m_edited_font->glyph_width(m_glyph_map_widget->selected_glyph())); }); - auto open_preview_action = GUI::Action::create("Preview", Gfx::Bitmap::load_from_file("/res/icons/16x16/find.png"), [&](auto&) { + m_open_preview_action = GUI::Action::create("Preview Font", Gfx::Bitmap::load_from_file("/res/icons/16x16/find.png"), [&](auto&) { if (!m_font_preview_window) m_font_preview_window = create_font_preview_window(*this); m_font_preview_window->show(); m_font_preview_window->move_to_front(); }); - open_preview_action->set_checked(false); + m_open_preview_action->set_checked(false); + m_show_metadata_action = GUI::Action::create_checkable("Font Metadata", { Mod_Ctrl, Key_M }, [&](auto& action) { + set_show_font_metadata(action.is_checked()); + }); + m_show_metadata_action->set_checked(true); - toolbar.add_action(*open_action); - toolbar.add_action(*save_action); + toolbar.add_action(*m_new_action); + toolbar.add_action(*m_open_action); + toolbar.add_action(*m_save_action); toolbar.add_separator(); - toolbar.add_action(*cut_action); - toolbar.add_action(*copy_action); - toolbar.add_action(*paste_action); - toolbar.add_action(*delete_action); + toolbar.add_action(*m_cut_action); + toolbar.add_action(*m_copy_action); + toolbar.add_action(*m_paste_action); + toolbar.add_action(*m_delete_action); toolbar.add_separator(); - toolbar.add_action(*open_preview_action); + toolbar.add_action(*m_open_preview_action); - m_glyph_editor_widget->on_glyph_altered = [this, update_demo](u8 glyph) { + GUI::Clipboard::the().on_change = [&](const String& data_type) { + m_paste_action->set_enabled(data_type == "glyph/x-fonteditor"); + }; + + m_glyph_editor_widget->on_glyph_altered = [this, update_demo](int glyph) { m_glyph_map_widget->update_glyph(glyph); update_demo(); }; - m_glyph_map_widget->on_glyph_selected = [&](size_t glyph) { + m_glyph_map_widget->on_glyph_selected = [&](int glyph) { m_glyph_editor_widget->set_glyph(glyph); m_glyph_editor_width_spinbox->set_value(m_edited_font->glyph_width(m_glyph_map_widget->selected_glyph())); StringBuilder builder; builder.appendff("{:#02x} (", glyph); if (glyph < 128) { - builder.append(glyph); + if (glyph == 10) + builder.append("LF"); + else + builder.append(glyph); } else { builder.append(128 | 64 | (glyph / 64)); builder.append(128 | (glyph % 64)); } - builder.append(')'); + builder.append(") "); + builder.appendff("[{}x{}]", m_edited_font->glyph_width(glyph), m_edited_font->glyph_height()); status_bar.set_text(builder.to_string()); }; @@ -212,9 +246,12 @@ FontEditorWidget::FontEditorWidget(const String& path, RefPtr&& update_demo(); }; - m_weight_spinbox->on_change = [this, update_demo](int value) { - m_edited_font->set_weight(value); - update_demo(); + m_weight_combobox->on_change = [this]() { + m_edited_font->set_weight(GUI::name_to_weight(m_weight_combobox->text())); + }; + + m_type_combobox->on_change = [this](auto&, const auto& index) { + m_edited_font->set_type(static_cast(index.row())); }; m_presentation_spinbox->on_change = [this, update_demo](int value) { @@ -265,19 +302,76 @@ void FontEditorWidget::initialize(const String& path, RefPtr&& m_family_textbox->set_text(m_edited_font->family()); m_presentation_spinbox->set_value(m_edited_font->presentation_size()); - m_weight_spinbox->set_value(m_edited_font->weight()); m_spacing_spinbox->set_value(m_edited_font->glyph_spacing()); m_mean_line_spinbox->set_value(m_edited_font->mean_line()); m_baseline_spinbox->set_value(m_edited_font->baseline()); + m_font_weight_list.clear(); + for (auto& it : GUI::font_weight_names) + m_font_weight_list.append(it.name); + m_weight_combobox->set_model(*GUI::ItemListModel::create(m_font_weight_list)); + + int i = 0; + for (auto it : GUI::font_weight_names) { + if (it.weight == m_edited_font->weight()) { + m_weight_combobox->set_selected_index(i); + break; + } + i++; + } + + m_font_type_list.clear(); + StringBuilder type_count; + for (int i = 0; i < Gfx::FontTypes::__Count; i++) { + type_count.appendff("{}", Gfx::BitmapFont::type_name_by_type(static_cast(i))); + m_font_type_list.append(type_count.to_string()); + type_count.clear(); + } + m_type_combobox->set_model(*GUI::ItemListModel::create(m_font_type_list)); + m_type_combobox->set_selected_index(m_edited_font->type()); + m_fixed_width_checkbox->set_checked(m_edited_font->is_fixed_width()); m_glyph_map_widget->set_selected_glyph('A'); + deferred_invoke([this](auto&) { + m_glyph_map_widget->set_focus(true); + m_glyph_map_widget->scroll_to_glyph(m_glyph_map_widget->selected_glyph()); + }); if (on_initialize) on_initialize(); } +void FontEditorWidget::initialize_menubar(GUI::MenuBar& menubar) +{ + auto& app_menu = menubar.add_menu("&File"); + app_menu.add_action(*m_new_action); + app_menu.add_action(*m_open_action); + app_menu.add_action(*m_save_action); + app_menu.add_action(*m_save_as_action); + app_menu.add_separator(); + app_menu.add_action(GUI::CommonActions::make_quit_action([this](auto&) { + GUI::Application::the()->quit(); + })); + + auto& edit_menu = menubar.add_menu("&Edit"); + edit_menu.add_action(*m_cut_action); + edit_menu.add_action(*m_copy_action); + edit_menu.add_action(*m_paste_action); + edit_menu.add_action(*m_delete_action); + + auto& view_menu = menubar.add_menu("&View"); + view_menu.add_action(*m_open_preview_action); + view_menu.add_separator(); + view_menu.add_action(*m_show_metadata_action); + + auto& help_menu = menubar.add_menu("&Help"); + help_menu.add_action(GUI::CommonActions::make_help_action([](auto&) { + Desktop::Launcher::open(URL::create_with_file_protocol("/usr/share/man/man1/FontEditor.md"), "/bin/Help"); + })); + help_menu.add_action(GUI::CommonActions::make_about_action("Font Editor", GUI::Icon::default_icon("app-font-editor"), window())); +} + bool FontEditorWidget::save_as(const String& path) { auto ret_val = m_edited_font->write_to_file(path); diff --git a/Userland/Applications/FontEditor/FontEditor.h b/Userland/Applications/FontEditor/FontEditor.h index 0f2a55041c..98131b9412 100644 --- a/Userland/Applications/FontEditor/FontEditor.h +++ b/Userland/Applications/FontEditor/FontEditor.h @@ -42,6 +42,7 @@ public: const String& path() { return m_path; } const Gfx::BitmapFont& edited_font() { return *m_edited_font; } void initialize(const String& path, RefPtr&&); + void initialize_menubar(GUI::MenuBar&); bool is_showing_font_metadata() { return m_font_metadata; } void set_show_font_metadata(bool b); @@ -55,10 +56,24 @@ private: RefPtr m_glyph_map_widget; RefPtr m_glyph_editor_widget; + RefPtr m_new_action; + RefPtr m_open_action; + RefPtr m_save_action; + RefPtr m_save_as_action; + + RefPtr m_cut_action; + RefPtr m_copy_action; + RefPtr m_paste_action; + RefPtr m_delete_action; + + RefPtr m_open_preview_action; + RefPtr m_show_metadata_action; + RefPtr m_font_preview_window; RefPtr m_left_column_container; RefPtr m_glyph_editor_container; - RefPtr m_weight_spinbox; + RefPtr m_weight_combobox; + RefPtr m_type_combobox; RefPtr m_spacing_spinbox; RefPtr m_baseline_spinbox; RefPtr m_mean_line_spinbox; @@ -70,5 +85,7 @@ private: RefPtr m_font_metadata_groupbox; String m_path; + Vector m_font_weight_list; + Vector m_font_type_list; bool m_font_metadata { true }; }; diff --git a/Userland/Applications/FontEditor/FontEditorWindow.gml b/Userland/Applications/FontEditor/FontEditorWindow.gml index c6500eca0d..37ce603a57 100644 --- a/Userland/Applications/FontEditor/FontEditorWindow.gml +++ b/Userland/Applications/FontEditor/FontEditorWindow.gml @@ -54,7 +54,7 @@ @GUI::GroupBox { name: "font_metadata_groupbox" - title: "Font metadata" + title: "Metadata" fixed_height: 220 layout: @GUI::VerticalBoxLayout { margins: [8, 16, 8, 4] @@ -92,6 +92,23 @@ } } + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + } + + @GUI::Label { + name: "weight_label" + fixed_width: 100 + text_alignment: "CenterLeft" + text: "Weight:" + } + + @GUI::ComboBox { + name: "weight_combobox" + model_only: true + } + } + @GUI::Widget { layout: @GUI::HorizontalBoxLayout { } @@ -110,24 +127,6 @@ } } - @GUI::Widget { - layout: @GUI::HorizontalBoxLayout { - } - - @GUI::Label { - name: "weight_label" - fixed_width: 100 - text_alignment: "CenterLeft" - text: "Weight:" - } - - @GUI::SpinBox { - name: "weight_spinbox" - min: 0 - max: 65535 - } - } - @GUI::Widget { layout: @GUI::HorizontalBoxLayout { } @@ -194,6 +193,12 @@ } @GUI::Widget { + fixed_width: 16 + } + + @GUI::ComboBox { + name: "type_combobox" + model_only: true } } } diff --git a/Userland/Applications/FontEditor/GlyphEditorWidget.h b/Userland/Applications/FontEditor/GlyphEditorWidget.h index 5d38fe90f7..3ee0317b2f 100644 --- a/Userland/Applications/FontEditor/GlyphEditorWidget.h +++ b/Userland/Applications/FontEditor/GlyphEditorWidget.h @@ -51,7 +51,7 @@ public: Gfx::BitmapFont& font() { return *m_font; } const Gfx::BitmapFont& font() const { return *m_font; } - Function on_glyph_altered; + Function on_glyph_altered; private: GlyphEditorWidget() {}; diff --git a/Userland/Applications/FontEditor/GlyphMapWidget.h b/Userland/Applications/FontEditor/GlyphMapWidget.h index 45cf3357f9..3c6a683c32 100644 --- a/Userland/Applications/FontEditor/GlyphMapWidget.h +++ b/Userland/Applications/FontEditor/GlyphMapWidget.h @@ -38,6 +38,7 @@ public: int selected_glyph() const { return m_selected_glyph; } void set_selected_glyph(int); + void scroll_to_glyph(int glyph); int rows() const { return m_rows; } int columns() const { return m_columns; } @@ -57,7 +58,6 @@ private: virtual void resize_event(GUI::ResizeEvent&) override; Gfx::IntRect get_outer_rect(int glyph) const; - void scroll_to_glyph(int glyph); RefPtr m_font; int m_glyph_count { 384 }; diff --git a/Userland/Applications/FontEditor/main.cpp b/Userland/Applications/FontEditor/main.cpp index 6f3e8a0973..0f1dde82f7 100644 --- a/Userland/Applications/FontEditor/main.cpp +++ b/Userland/Applications/FontEditor/main.cpp @@ -28,18 +28,13 @@ #include #include #include -#include #include -#include #include -#include #include #include #include -#include #include #include -#include #include #include @@ -99,80 +94,14 @@ int main(int argc, char** argv) auto window = GUI::Window::construct(); window->set_icon(app_icon.bitmap_for_size(16)); window->resize(440, 470); - window->set_main_widget(path, move(edited_font)); window->set_title(String::formatted("{} - Font Editor", path)); - auto set_edited_font = [&](const String& path, RefPtr&& font) { - // Convert 256 char font to 384 char font. - if (font->type() == Gfx::FontTypes::Default) - font->set_type(Gfx::FontTypes::LatinExtendedA); - - // Convert 384 char font to 1280 char font. - // Dirty hack. Should be refactored. - if (font->type() == Gfx::FontTypes::LatinExtendedA) - font->set_type(Gfx::FontTypes::Cyrillic); - - window->set_title(String::formatted("{} - Font Editor", path)); - static_cast(window->main_widget())->initialize(path, move(font)); - }; + auto& font_editor = window->set_main_widget(path, move(edited_font)); auto menubar = GUI::MenuBar::construct(); - - auto& app_menu = menubar->add_menu("&File"); - app_menu.add_action(GUI::CommonActions::make_open_action([&](auto&) { - Optional open_path = GUI::FilePicker::get_open_filepath(window, {}, "/res/fonts/"); - if (!open_path.has_value()) - return; - - auto bitmap_font = Gfx::BitmapFont::load_from_file(open_path.value()); - if (!bitmap_font) { - String message = String::formatted("Couldn't load font: {}\n", open_path.value()); - GUI::MessageBox::show(window, message, "Font Editor", GUI::MessageBox::Type::Error); - return; - } - RefPtr new_font = static_ptr_cast(bitmap_font->clone()); - if (!new_font) { - String message = String::formatted("Couldn't load font: {}\n", open_path.value()); - GUI::MessageBox::show(window, message, "Font Editor", GUI::MessageBox::Type::Error); - return; - } - - set_edited_font(open_path.value(), move(new_font)); - })); - app_menu.add_action(GUI::CommonActions::make_save_action([&](auto&) { - FontEditorWidget* editor = static_cast(window->main_widget()); - editor->save_as(editor->path()); - })); - app_menu.add_action(GUI::CommonActions::make_save_as_action([&](auto&) { - FontEditorWidget* editor = static_cast(window->main_widget()); - LexicalPath lexical_path(editor->path()); - Optional save_path = GUI::FilePicker::get_save_filepath(window, lexical_path.title(), lexical_path.extension()); - if (!save_path.has_value()) - return; - - if (editor->save_as(save_path.value())) - window->set_title(String::formatted("{} - Font Editor", save_path.value())); - })); - app_menu.add_separator(); - app_menu.add_action(GUI::CommonActions::make_quit_action([&](auto&) { - app->quit(); - })); - - auto& view_menu = menubar->add_menu("&View"); - auto set_font_metadata = GUI::Action::create_checkable("Font &Metadata", { Mod_Ctrl, Key_M }, [&](auto& action) { - static_cast(window->main_widget())->set_show_font_metadata(action.is_checked()); - }); - set_font_metadata->set_checked(true); - view_menu.add_action(*set_font_metadata); - - auto& help_menu = menubar->add_menu("&Help"); - help_menu.add_action(GUI::CommonActions::make_help_action([](auto&) { - Desktop::Launcher::open(URL::create_with_file_protocol("/usr/share/man/man1/FontEditor.md"), "/bin/Help"); - })); - - help_menu.add_action(GUI::CommonActions::make_about_action("Font Editor", app_icon, window)); - + font_editor.initialize_menubar(menubar); window->set_menubar(move(menubar)); + window->show(); return app->exec();