Browse Source

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.
thankyouverycool 4 years ago
parent
commit
cdfa2614b9

+ 120 - 26
Userland/Applications/FontEditor/FontEditor.cpp

@@ -29,13 +29,20 @@
 #include "GlyphMapWidget.h"
 #include "GlyphMapWidget.h"
 #include <AK/StringBuilder.h>
 #include <AK/StringBuilder.h>
 #include <Applications/FontEditor/FontEditorWindowGML.h>
 #include <Applications/FontEditor/FontEditorWindowGML.h>
+#include <LibDesktop/Launcher.h>
 #include <LibGUI/Action.h>
 #include <LibGUI/Action.h>
+#include <LibGUI/Application.h>
 #include <LibGUI/BoxLayout.h>
 #include <LibGUI/BoxLayout.h>
 #include <LibGUI/Button.h>
 #include <LibGUI/Button.h>
 #include <LibGUI/CheckBox.h>
 #include <LibGUI/CheckBox.h>
+#include <LibGUI/Clipboard.h>
+#include <LibGUI/ComboBox.h>
 #include <LibGUI/FilePicker.h>
 #include <LibGUI/FilePicker.h>
+#include <LibGUI/FontPickerWeightModel.h>
 #include <LibGUI/GroupBox.h>
 #include <LibGUI/GroupBox.h>
 #include <LibGUI/Label.h>
 #include <LibGUI/Label.h>
+#include <LibGUI/Menu.h>
+#include <LibGUI/MenuBar.h>
 #include <LibGUI/MessageBox.h>
 #include <LibGUI/MessageBox.h>
 #include <LibGUI/Painter.h>
 #include <LibGUI/Painter.h>
 #include <LibGUI/SpinBox.h>
 #include <LibGUI/SpinBox.h>
@@ -67,7 +74,6 @@ static RefPtr<GUI::Window> create_font_preview_window(FontEditorWidget& editor)
     preview_box.layout()->set_margins({ 8, 8, 8, 8 });
     preview_box.layout()->set_margins({ 8, 8, 8, 8 });
 
 
     auto& preview_label = preview_box.add<GUI::Label>();
     auto& preview_label = preview_box.add<GUI::Label>();
-    preview_label.set_text("Five quacking zephyrs jolt my wax bed!");
     preview_label.set_font(editor.edited_font());
     preview_label.set_font(editor.edited_font());
 
 
     editor.on_initialize = [&] {
     editor.on_initialize = [&] {
@@ -75,10 +81,14 @@ static RefPtr<GUI::Window> create_font_preview_window(FontEditorWidget& editor)
     };
     };
 
 
     auto& preview_textbox = main_widget.add<GUI::TextBox>();
     auto& preview_textbox = main_widget.add<GUI::TextBox>();
-    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_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;
     return window;
@@ -97,7 +107,8 @@ FontEditorWidget::FontEditorWidget(const String& path, RefPtr<Gfx::BitmapFont>&&
     m_name_textbox = *find_descendant_of_type_named<GUI::TextBox>("name_textbox");
     m_name_textbox = *find_descendant_of_type_named<GUI::TextBox>("name_textbox");
     m_family_textbox = *find_descendant_of_type_named<GUI::TextBox>("family_textbox");
     m_family_textbox = *find_descendant_of_type_named<GUI::TextBox>("family_textbox");
     m_presentation_spinbox = *find_descendant_of_type_named<GUI::SpinBox>("presentation_spinbox");
     m_presentation_spinbox = *find_descendant_of_type_named<GUI::SpinBox>("presentation_spinbox");
-    m_weight_spinbox = *find_descendant_of_type_named<GUI::SpinBox>("weight_spinbox");
+    m_weight_combobox = *find_descendant_of_type_named<GUI::ComboBox>("weight_combobox");
+    m_type_combobox = *find_descendant_of_type_named<GUI::ComboBox>("type_combobox");
     m_spacing_spinbox = *find_descendant_of_type_named<GUI::SpinBox>("spacing_spinbox");
     m_spacing_spinbox = *find_descendant_of_type_named<GUI::SpinBox>("spacing_spinbox");
     m_mean_line_spinbox = *find_descendant_of_type_named<GUI::SpinBox>("mean_line_spinbox");
     m_mean_line_spinbox = *find_descendant_of_type_named<GUI::SpinBox>("mean_line_spinbox");
     m_baseline_spinbox = *find_descendant_of_type_named<GUI::SpinBox>("baseline_spinbox");
     m_baseline_spinbox = *find_descendant_of_type_named<GUI::SpinBox>("baseline_spinbox");
@@ -132,60 +143,83 @@ FontEditorWidget::FontEditorWidget(const String& path, RefPtr<Gfx::BitmapFont>&&
         window()->set_title(String::formatted("{} - Font Editor", open_path.value()));
         window()->set_title(String::formatted("{} - Font Editor", open_path.value()));
         initialize(open_path.value(), move(new_font));
         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);
         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<String> 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();
         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();
         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_editor_widget->paste_glyph();
         m_glyph_map_widget->update_glyph(m_glyph_map_widget->selected_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_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_editor_widget->delete_glyph();
         m_glyph_map_widget->update_glyph(m_glyph_map_widget->selected_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()));
         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)
         if (!m_font_preview_window)
             m_font_preview_window = create_font_preview_window(*this);
             m_font_preview_window = create_font_preview_window(*this);
         m_font_preview_window->show();
         m_font_preview_window->show();
         m_font_preview_window->move_to_front();
         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_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_separator();
-    toolbar.add_action(*open_preview_action);
+    toolbar.add_action(*m_open_preview_action);
+
+    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](u8 glyph) {
+    m_glyph_editor_widget->on_glyph_altered = [this, update_demo](int glyph) {
         m_glyph_map_widget->update_glyph(glyph);
         m_glyph_map_widget->update_glyph(glyph);
         update_demo();
         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_widget->set_glyph(glyph);
         m_glyph_editor_width_spinbox->set_value(m_edited_font->glyph_width(m_glyph_map_widget->selected_glyph()));
         m_glyph_editor_width_spinbox->set_value(m_edited_font->glyph_width(m_glyph_map_widget->selected_glyph()));
         StringBuilder builder;
         StringBuilder builder;
         builder.appendff("{:#02x} (", glyph);
         builder.appendff("{:#02x} (", glyph);
         if (glyph < 128) {
         if (glyph < 128) {
-            builder.append(glyph);
+            if (glyph == 10)
+                builder.append("LF");
+            else
+                builder.append(glyph);
         } else {
         } else {
             builder.append(128 | 64 | (glyph / 64));
             builder.append(128 | 64 | (glyph / 64));
             builder.append(128 | (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());
         status_bar.set_text(builder.to_string());
     };
     };
 
 
@@ -212,9 +246,12 @@ FontEditorWidget::FontEditorWidget(const String& path, RefPtr<Gfx::BitmapFont>&&
         update_demo();
         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<Gfx::FontTypes>(index.row()));
     };
     };
 
 
     m_presentation_spinbox->on_change = [this, update_demo](int value) {
     m_presentation_spinbox->on_change = [this, update_demo](int value) {
@@ -265,19 +302,76 @@ void FontEditorWidget::initialize(const String& path, RefPtr<Gfx::BitmapFont>&&
     m_family_textbox->set_text(m_edited_font->family());
     m_family_textbox->set_text(m_edited_font->family());
 
 
     m_presentation_spinbox->set_value(m_edited_font->presentation_size());
     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_spacing_spinbox->set_value(m_edited_font->glyph_spacing());
     m_mean_line_spinbox->set_value(m_edited_font->mean_line());
     m_mean_line_spinbox->set_value(m_edited_font->mean_line());
     m_baseline_spinbox->set_value(m_edited_font->baseline());
     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<String>::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<Gfx::FontTypes>(i)));
+        m_font_type_list.append(type_count.to_string());
+        type_count.clear();
+    }
+    m_type_combobox->set_model(*GUI::ItemListModel<String>::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_fixed_width_checkbox->set_checked(m_edited_font->is_fixed_width());
 
 
     m_glyph_map_widget->set_selected_glyph('A');
     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)
     if (on_initialize)
         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)
 bool FontEditorWidget::save_as(const String& path)
 {
 {
     auto ret_val = m_edited_font->write_to_file(path);
     auto ret_val = m_edited_font->write_to_file(path);

+ 18 - 1
Userland/Applications/FontEditor/FontEditor.h

@@ -42,6 +42,7 @@ public:
     const String& path() { return m_path; }
     const String& path() { return m_path; }
     const Gfx::BitmapFont& edited_font() { return *m_edited_font; }
     const Gfx::BitmapFont& edited_font() { return *m_edited_font; }
     void initialize(const String& path, RefPtr<Gfx::BitmapFont>&&);
     void initialize(const String& path, RefPtr<Gfx::BitmapFont>&&);
+    void initialize_menubar(GUI::MenuBar&);
 
 
     bool is_showing_font_metadata() { return m_font_metadata; }
     bool is_showing_font_metadata() { return m_font_metadata; }
     void set_show_font_metadata(bool b);
     void set_show_font_metadata(bool b);
@@ -55,10 +56,24 @@ private:
     RefPtr<GlyphMapWidget> m_glyph_map_widget;
     RefPtr<GlyphMapWidget> m_glyph_map_widget;
     RefPtr<GlyphEditorWidget> m_glyph_editor_widget;
     RefPtr<GlyphEditorWidget> m_glyph_editor_widget;
 
 
+    RefPtr<GUI::Action> m_new_action;
+    RefPtr<GUI::Action> m_open_action;
+    RefPtr<GUI::Action> m_save_action;
+    RefPtr<GUI::Action> m_save_as_action;
+
+    RefPtr<GUI::Action> m_cut_action;
+    RefPtr<GUI::Action> m_copy_action;
+    RefPtr<GUI::Action> m_paste_action;
+    RefPtr<GUI::Action> m_delete_action;
+
+    RefPtr<GUI::Action> m_open_preview_action;
+    RefPtr<GUI::Action> m_show_metadata_action;
+
     RefPtr<GUI::Window> m_font_preview_window;
     RefPtr<GUI::Window> m_font_preview_window;
     RefPtr<GUI::Widget> m_left_column_container;
     RefPtr<GUI::Widget> m_left_column_container;
     RefPtr<GUI::Widget> m_glyph_editor_container;
     RefPtr<GUI::Widget> m_glyph_editor_container;
-    RefPtr<GUI::SpinBox> m_weight_spinbox;
+    RefPtr<GUI::ComboBox> m_weight_combobox;
+    RefPtr<GUI::ComboBox> m_type_combobox;
     RefPtr<GUI::SpinBox> m_spacing_spinbox;
     RefPtr<GUI::SpinBox> m_spacing_spinbox;
     RefPtr<GUI::SpinBox> m_baseline_spinbox;
     RefPtr<GUI::SpinBox> m_baseline_spinbox;
     RefPtr<GUI::SpinBox> m_mean_line_spinbox;
     RefPtr<GUI::SpinBox> m_mean_line_spinbox;
@@ -70,5 +85,7 @@ private:
     RefPtr<GUI::GroupBox> m_font_metadata_groupbox;
     RefPtr<GUI::GroupBox> m_font_metadata_groupbox;
 
 
     String m_path;
     String m_path;
+    Vector<String> m_font_weight_list;
+    Vector<String> m_font_type_list;
     bool m_font_metadata { true };
     bool m_font_metadata { true };
 };
 };

+ 16 - 11
Userland/Applications/FontEditor/FontEditorWindow.gml

@@ -54,7 +54,7 @@
 
 
             @GUI::GroupBox {
             @GUI::GroupBox {
                 name: "font_metadata_groupbox"
                 name: "font_metadata_groupbox"
-                title: "Font metadata"
+                title: "Metadata"
                 fixed_height: 220
                 fixed_height: 220
                 layout: @GUI::VerticalBoxLayout {
                 layout: @GUI::VerticalBoxLayout {
                     margins: [8, 16, 8, 4]
                     margins: [8, 16, 8, 4]
@@ -97,16 +97,15 @@
                     }
                     }
 
 
                     @GUI::Label {
                     @GUI::Label {
-                        name: "presentation_label"
+                        name: "weight_label"
                         fixed_width: 100
                         fixed_width: 100
                         text_alignment: "CenterLeft"
                         text_alignment: "CenterLeft"
-                        text: "Presentation size:"
+                        text: "Weight:"
                     }
                     }
 
 
-                    @GUI::SpinBox {
-                        name: "presentation_spinbox"
-                        min: 0
-                        max: 255
+                    @GUI::ComboBox {
+                        name: "weight_combobox"
+                        model_only: true
                     }
                     }
                 }
                 }
 
 
@@ -115,16 +114,16 @@
                     }
                     }
 
 
                     @GUI::Label {
                     @GUI::Label {
-                        name: "weight_label"
+                        name: "presentation_label"
                         fixed_width: 100
                         fixed_width: 100
                         text_alignment: "CenterLeft"
                         text_alignment: "CenterLeft"
-                        text: "Weight:"
+                        text: "Presentation size:"
                     }
                     }
 
 
                     @GUI::SpinBox {
                     @GUI::SpinBox {
-                        name: "weight_spinbox"
+                        name: "presentation_spinbox"
                         min: 0
                         min: 0
-                        max: 65535
+                        max: 255
                     }
                     }
                 }
                 }
 
 
@@ -194,6 +193,12 @@
                     }
                     }
 
 
                     @GUI::Widget {
                     @GUI::Widget {
+                        fixed_width: 16
+                    }
+
+                    @GUI::ComboBox {
+                        name: "type_combobox"
+                        model_only: true
                     }
                     }
                 }
                 }
             }
             }

+ 1 - 1
Userland/Applications/FontEditor/GlyphEditorWidget.h

@@ -51,7 +51,7 @@ public:
     Gfx::BitmapFont& font() { return *m_font; }
     Gfx::BitmapFont& font() { return *m_font; }
     const Gfx::BitmapFont& font() const { return *m_font; }
     const Gfx::BitmapFont& font() const { return *m_font; }
 
 
-    Function<void(u8)> on_glyph_altered;
+    Function<void(int)> on_glyph_altered;
 
 
 private:
 private:
     GlyphEditorWidget() {};
     GlyphEditorWidget() {};

+ 1 - 1
Userland/Applications/FontEditor/GlyphMapWidget.h

@@ -38,6 +38,7 @@ public:
 
 
     int selected_glyph() const { return m_selected_glyph; }
     int selected_glyph() const { return m_selected_glyph; }
     void set_selected_glyph(int);
     void set_selected_glyph(int);
+    void scroll_to_glyph(int glyph);
 
 
     int rows() const { return m_rows; }
     int rows() const { return m_rows; }
     int columns() const { return m_columns; }
     int columns() const { return m_columns; }
@@ -57,7 +58,6 @@ private:
     virtual void resize_event(GUI::ResizeEvent&) override;
     virtual void resize_event(GUI::ResizeEvent&) override;
 
 
     Gfx::IntRect get_outer_rect(int glyph) const;
     Gfx::IntRect get_outer_rect(int glyph) const;
-    void scroll_to_glyph(int glyph);
 
 
     RefPtr<Gfx::BitmapFont> m_font;
     RefPtr<Gfx::BitmapFont> m_font;
     int m_glyph_count { 384 };
     int m_glyph_count { 384 };

+ 3 - 74
Userland/Applications/FontEditor/main.cpp

@@ -28,18 +28,13 @@
 #include <AK/URL.h>
 #include <AK/URL.h>
 #include <LibCore/ArgsParser.h>
 #include <LibCore/ArgsParser.h>
 #include <LibDesktop/Launcher.h>
 #include <LibDesktop/Launcher.h>
-#include <LibGUI/Action.h>
 #include <LibGUI/Application.h>
 #include <LibGUI/Application.h>
-#include <LibGUI/FilePicker.h>
 #include <LibGUI/Icon.h>
 #include <LibGUI/Icon.h>
-#include <LibGUI/Menu.h>
 #include <LibGUI/MenuBar.h>
 #include <LibGUI/MenuBar.h>
 #include <LibGUI/MessageBox.h>
 #include <LibGUI/MessageBox.h>
 #include <LibGUI/Window.h>
 #include <LibGUI/Window.h>
-#include <LibGfx/Bitmap.h>
 #include <LibGfx/BitmapFont.h>
 #include <LibGfx/BitmapFont.h>
 #include <LibGfx/FontDatabase.h>
 #include <LibGfx/FontDatabase.h>
-#include <LibGfx/Point.h>
 #include <stdio.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <unistd.h>
 
 
@@ -99,80 +94,14 @@ int main(int argc, char** argv)
     auto window = GUI::Window::construct();
     auto window = GUI::Window::construct();
     window->set_icon(app_icon.bitmap_for_size(16));
     window->set_icon(app_icon.bitmap_for_size(16));
     window->resize(440, 470);
     window->resize(440, 470);
-    window->set_main_widget<FontEditorWidget>(path, move(edited_font));
     window->set_title(String::formatted("{} - Font Editor", path));
     window->set_title(String::formatted("{} - Font Editor", path));
 
 
-    auto set_edited_font = [&](const String& path, RefPtr<Gfx::BitmapFont>&& 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<FontEditorWidget*>(window->main_widget())->initialize(path, move(font));
-    };
+    auto& font_editor = window->set_main_widget<FontEditorWidget>(path, move(edited_font));
 
 
     auto menubar = GUI::MenuBar::construct();
     auto menubar = GUI::MenuBar::construct();
-
-    auto& app_menu = menubar->add_menu("&File");
-    app_menu.add_action(GUI::CommonActions::make_open_action([&](auto&) {
-        Optional<String> 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<Gfx::BitmapFont> new_font = static_ptr_cast<Gfx::BitmapFont>(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<FontEditorWidget*>(window->main_widget());
-        editor->save_as(editor->path());
-    }));
-    app_menu.add_action(GUI::CommonActions::make_save_as_action([&](auto&) {
-        FontEditorWidget* editor = static_cast<FontEditorWidget*>(window->main_widget());
-        LexicalPath lexical_path(editor->path());
-        Optional<String> 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<FontEditorWidget*>(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->set_menubar(move(menubar));
+
     window->show();
     window->show();
 
 
     return app->exec();
     return app->exec();