mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 14:57:35 +00:00
FontEditor: Allow application to launch without a font
Since LibFSAC requires a reified window before loading a font, it makes sense to have a safe null state for the app. This lets us stay alive after a failed file request on startup, handle failure at any point during initialization, and claw back memory from all our font RefPtrs. A default startup font or none at all can now be set in FontEditor.ini
This commit is contained in:
parent
aaf60053f1
commit
7fa8fae786
5 changed files with 127 additions and 20 deletions
2
Base/home/anon/.config/FontEditor.ini
Normal file
2
Base/home/anon/.config/FontEditor.ini
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[Defaults]
|
||||||
|
Font=/res/fonts/KaticaRegular10.font
|
|
@ -23,10 +23,13 @@
|
||||||
|
|
||||||
@FontEditor::GlyphEditorWidget {
|
@FontEditor::GlyphEditorWidget {
|
||||||
name: "glyph_editor_widget"
|
name: "glyph_editor_widget"
|
||||||
|
visible: false
|
||||||
}
|
}
|
||||||
|
|
||||||
@GUI::Widget {
|
@GUI::Widget {
|
||||||
|
name: "width_control_container"
|
||||||
preferred_height: "shrink"
|
preferred_height: "shrink"
|
||||||
|
visible: false
|
||||||
layout: @GUI::VerticalBoxLayout {}
|
layout: @GUI::VerticalBoxLayout {}
|
||||||
|
|
||||||
@GUI::SpinBox {
|
@GUI::SpinBox {
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "GlyphEditorWidget.h"
|
#include "GlyphEditorWidget.h"
|
||||||
#include "NewFontDialog.h"
|
#include "NewFontDialog.h"
|
||||||
#include <AK/Array.h>
|
#include <AK/Array.h>
|
||||||
|
#include <AK/ScopeGuard.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
#include <AK/StringUtils.h>
|
#include <AK/StringUtils.h>
|
||||||
|
@ -230,9 +231,9 @@ ErrorOr<void> MainWidget::create_actions()
|
||||||
m_show_unicode_blocks_action = GUI::Action::create_checkable("&Unicode Blocks", { Mod_Ctrl, Key_U }, [this](auto& action) {
|
m_show_unicode_blocks_action = GUI::Action::create_checkable("&Unicode Blocks", { Mod_Ctrl, Key_U }, [this](auto& action) {
|
||||||
m_unicode_block_container->set_visible(action.is_checked());
|
m_unicode_block_container->set_visible(action.is_checked());
|
||||||
if (action.is_checked())
|
if (action.is_checked())
|
||||||
m_search_textbox->set_focus(true);
|
m_search_textbox->set_focus(m_initialized);
|
||||||
else
|
else
|
||||||
m_glyph_map_widget->set_focus(true);
|
m_glyph_map_widget->set_focus(m_initialized);
|
||||||
Config::write_bool("FontEditor"sv, "Layout"sv, "ShowUnicodeBlocks"sv, action.is_checked());
|
Config::write_bool("FontEditor"sv, "Layout"sv, "ShowUnicodeBlocks"sv, action.is_checked());
|
||||||
});
|
});
|
||||||
m_show_unicode_blocks_action->set_checked(show_unicode_blocks);
|
m_show_unicode_blocks_action->set_checked(show_unicode_blocks);
|
||||||
|
@ -463,6 +464,7 @@ ErrorOr<void> MainWidget::create_widgets()
|
||||||
m_font_metadata_groupbox = find_descendant_of_type_named<GUI::GroupBox>("font_metadata_groupbox");
|
m_font_metadata_groupbox = find_descendant_of_type_named<GUI::GroupBox>("font_metadata_groupbox");
|
||||||
m_unicode_block_container = find_descendant_of_type_named<GUI::Widget>("unicode_block_container");
|
m_unicode_block_container = find_descendant_of_type_named<GUI::Widget>("unicode_block_container");
|
||||||
m_toolbar_container = find_descendant_of_type_named<GUI::ToolbarContainer>("toolbar_container");
|
m_toolbar_container = find_descendant_of_type_named<GUI::ToolbarContainer>("toolbar_container");
|
||||||
|
m_width_control_container = find_descendant_of_type_named<GUI::Widget>("width_control_container");
|
||||||
|
|
||||||
m_glyph_map_widget = find_descendant_of_type_named<GUI::GlyphMapWidget>("glyph_map_widget");
|
m_glyph_map_widget = find_descendant_of_type_named<GUI::GlyphMapWidget>("glyph_map_widget");
|
||||||
m_glyph_editor_widget = find_descendant_of_type_named<GlyphEditorWidget>("glyph_editor_widget");
|
m_glyph_editor_widget = find_descendant_of_type_named<GlyphEditorWidget>("glyph_editor_widget");
|
||||||
|
@ -637,19 +639,24 @@ ErrorOr<void> MainWidget::initialize(StringView path, RefPtr<Gfx::BitmapFont>&&
|
||||||
if (m_font == mutable_font)
|
if (m_font == mutable_font)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
TRY(m_glyph_map_widget->initialize(mutable_font));
|
ScopeGuard reset_on_error([&] {
|
||||||
|
if (!m_initialized)
|
||||||
|
reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_initialized = false;
|
||||||
|
m_path = TRY(String::from_utf8(path));
|
||||||
|
m_font = move(mutable_font);
|
||||||
|
|
||||||
|
TRY(m_glyph_map_widget->initialize(m_font));
|
||||||
auto active_glyph = m_glyph_map_widget->active_glyph();
|
auto active_glyph = m_glyph_map_widget->active_glyph();
|
||||||
m_glyph_map_widget->set_focus(true);
|
m_glyph_map_widget->set_focus(true);
|
||||||
m_glyph_map_widget->scroll_to_glyph(active_glyph);
|
m_glyph_map_widget->scroll_to_glyph(active_glyph);
|
||||||
|
|
||||||
auto selection = m_glyph_map_widget->selection().normalized();
|
auto selection = m_glyph_map_widget->selection().normalized();
|
||||||
m_undo_selection = TRY(try_make_ref_counted<UndoSelection>(selection.start(), selection.size(), active_glyph, *mutable_font, *m_glyph_map_widget));
|
m_undo_selection = TRY(try_make_ref_counted<UndoSelection>(selection.start(), selection.size(), active_glyph, *m_font, *m_glyph_map_widget));
|
||||||
m_undo_stack->clear();
|
m_undo_stack->clear();
|
||||||
|
|
||||||
m_path = TRY(String::from_utf8(path));
|
|
||||||
m_font = mutable_font;
|
|
||||||
|
|
||||||
if (m_preview_label)
|
if (m_preview_label)
|
||||||
m_preview_label->set_font(*m_font);
|
m_preview_label->set_font(*m_font);
|
||||||
|
|
||||||
|
@ -692,6 +699,9 @@ ErrorOr<void> MainWidget::initialize(StringView path, RefPtr<Gfx::BitmapFont>&&
|
||||||
window()->set_modified(false);
|
window()->set_modified(false);
|
||||||
update_title();
|
update_title();
|
||||||
update_statusbar();
|
update_statusbar();
|
||||||
|
set_actions_enabled(true);
|
||||||
|
set_widgets_enabled(true);
|
||||||
|
m_initialized = true;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -881,6 +891,9 @@ void MainWidget::did_modify_font()
|
||||||
|
|
||||||
void MainWidget::update_statusbar()
|
void MainWidget::update_statusbar()
|
||||||
{
|
{
|
||||||
|
if (!m_font)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!m_statusbar->is_visible())
|
if (!m_statusbar->is_visible())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1073,4 +1086,88 @@ void MainWidget::show_error(Error error, StringView action, StringView basename)
|
||||||
(void)GUI::MessageBox::try_show_error(window(), maybe_message.release_value());
|
(void)GUI::MessageBox::try_show_error(window(), maybe_message.release_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWidget::reset()
|
||||||
|
{
|
||||||
|
VERIFY(window());
|
||||||
|
|
||||||
|
m_initialized = false;
|
||||||
|
m_font = nullptr;
|
||||||
|
m_path = {};
|
||||||
|
m_undo_selection = nullptr;
|
||||||
|
m_undo_stack->clear();
|
||||||
|
|
||||||
|
(void)m_glyph_map_widget->initialize(nullptr);
|
||||||
|
m_glyph_editor_widget->initialize(nullptr);
|
||||||
|
|
||||||
|
if (m_font_preview_window)
|
||||||
|
m_font_preview_window->close();
|
||||||
|
if (m_preview_label)
|
||||||
|
m_preview_label->set_font(nullptr);
|
||||||
|
|
||||||
|
m_name_textbox->set_text({}, GUI::AllowCallback::No);
|
||||||
|
m_family_textbox->set_text({}, GUI::AllowCallback::No);
|
||||||
|
m_slope_combobox->set_text({}, GUI::AllowCallback::No);
|
||||||
|
m_weight_combobox->set_text({}, GUI::AllowCallback::No);
|
||||||
|
m_presentation_spinbox->set_text({}, GUI::AllowCallback::No);
|
||||||
|
m_baseline_spinbox->set_text({}, GUI::AllowCallback::No);
|
||||||
|
m_mean_line_spinbox->set_text({}, GUI::AllowCallback::No);
|
||||||
|
m_spacing_spinbox->set_text({}, GUI::AllowCallback::No);
|
||||||
|
m_fixed_width_checkbox->set_checked(false, GUI::AllowCallback::No);
|
||||||
|
m_statusbar->set_text(0, {});
|
||||||
|
m_statusbar->set_text(1, {});
|
||||||
|
|
||||||
|
window()->set_modified(false);
|
||||||
|
window()->set_title("Font Editor");
|
||||||
|
set_actions_enabled(false);
|
||||||
|
set_widgets_enabled(false);
|
||||||
|
set_focus(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWidget::set_actions_enabled(bool enabled)
|
||||||
|
{
|
||||||
|
m_save_action->set_enabled(enabled);
|
||||||
|
m_save_as_action->set_enabled(enabled);
|
||||||
|
|
||||||
|
m_cut_action->set_enabled(enabled);
|
||||||
|
m_copy_action->set_enabled(enabled);
|
||||||
|
m_paste_action->set_enabled(enabled && GUI::Clipboard::the().fetch_mime_type() == "glyph/x-fonteditor");
|
||||||
|
m_delete_action->set_enabled(enabled);
|
||||||
|
|
||||||
|
m_copy_text_action->set_enabled(enabled);
|
||||||
|
m_select_all_action->set_enabled(enabled);
|
||||||
|
|
||||||
|
m_go_to_glyph_action->set_enabled(enabled);
|
||||||
|
m_previous_glyph_action->set_enabled(enabled);
|
||||||
|
m_next_glyph_action->set_enabled(enabled);
|
||||||
|
|
||||||
|
m_move_glyph_action->set_enabled(enabled);
|
||||||
|
m_paint_glyph_action->set_enabled(enabled);
|
||||||
|
|
||||||
|
m_flip_horizontal_action->set_enabled(enabled);
|
||||||
|
m_flip_vertical_action->set_enabled(enabled);
|
||||||
|
m_rotate_clockwise_action->set_enabled(enabled);
|
||||||
|
m_rotate_counterclockwise_action->set_enabled(enabled);
|
||||||
|
|
||||||
|
m_open_preview_action->set_enabled(enabled);
|
||||||
|
m_highlight_modifications_action->set_enabled(enabled);
|
||||||
|
m_show_system_emoji_action->set_enabled(enabled);
|
||||||
|
|
||||||
|
m_scale_five_action->set_enabled(enabled);
|
||||||
|
m_scale_ten_action->set_enabled(enabled);
|
||||||
|
m_scale_fifteen_action->set_enabled(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWidget::set_widgets_enabled(bool enabled)
|
||||||
|
{
|
||||||
|
m_font_metadata_groupbox->set_enabled(enabled);
|
||||||
|
m_unicode_block_container->set_enabled(enabled);
|
||||||
|
m_width_control_container->set_enabled(enabled);
|
||||||
|
m_width_control_container->set_visible(enabled);
|
||||||
|
|
||||||
|
m_glyph_map_widget->set_enabled(enabled);
|
||||||
|
m_glyph_editor_widget->set_enabled(enabled);
|
||||||
|
m_glyph_editor_widget->set_visible(enabled);
|
||||||
|
m_statusbar->segment(1).set_visible(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,9 @@ public:
|
||||||
|
|
||||||
virtual ~MainWidget() override = default;
|
virtual ~MainWidget() override = default;
|
||||||
|
|
||||||
|
void show_error(Error, StringView action, StringView basename = {});
|
||||||
|
void reset();
|
||||||
|
|
||||||
ErrorOr<void> initialize(StringView path, RefPtr<Gfx::BitmapFont>&&);
|
ErrorOr<void> initialize(StringView path, RefPtr<Gfx::BitmapFont>&&);
|
||||||
ErrorOr<void> initialize_menubar(GUI::Window&);
|
ErrorOr<void> initialize_menubar(GUI::Window&);
|
||||||
|
|
||||||
|
@ -61,6 +64,8 @@ private:
|
||||||
void update_title();
|
void update_title();
|
||||||
|
|
||||||
void set_scale_and_save(i32);
|
void set_scale_and_save(i32);
|
||||||
|
void set_actions_enabled(bool);
|
||||||
|
void set_widgets_enabled(bool);
|
||||||
|
|
||||||
ErrorOr<void> copy_selected_glyphs();
|
ErrorOr<void> copy_selected_glyphs();
|
||||||
ErrorOr<void> cut_selected_glyphs();
|
ErrorOr<void> cut_selected_glyphs();
|
||||||
|
@ -70,8 +75,6 @@ private:
|
||||||
void push_undo();
|
void push_undo();
|
||||||
void reset_selection_and_push_undo();
|
void reset_selection_and_push_undo();
|
||||||
|
|
||||||
void show_error(Error, StringView action, StringView basename = {});
|
|
||||||
|
|
||||||
RefPtr<GUI::GlyphMapWidget> m_glyph_map_widget;
|
RefPtr<GUI::GlyphMapWidget> m_glyph_map_widget;
|
||||||
RefPtr<GlyphEditorWidget> m_glyph_editor_widget;
|
RefPtr<GlyphEditorWidget> m_glyph_editor_widget;
|
||||||
|
|
||||||
|
@ -122,6 +125,7 @@ private:
|
||||||
RefPtr<GUI::Statusbar> m_statusbar;
|
RefPtr<GUI::Statusbar> m_statusbar;
|
||||||
RefPtr<GUI::ToolbarContainer> m_toolbar_container;
|
RefPtr<GUI::ToolbarContainer> m_toolbar_container;
|
||||||
RefPtr<GUI::Widget> m_unicode_block_container;
|
RefPtr<GUI::Widget> m_unicode_block_container;
|
||||||
|
RefPtr<GUI::Widget> m_width_control_container;
|
||||||
RefPtr<GUI::ComboBox> m_weight_combobox;
|
RefPtr<GUI::ComboBox> m_weight_combobox;
|
||||||
RefPtr<GUI::ComboBox> m_slope_combobox;
|
RefPtr<GUI::ComboBox> m_slope_combobox;
|
||||||
RefPtr<GUI::SpinBox> m_spacing_spinbox;
|
RefPtr<GUI::SpinBox> m_spacing_spinbox;
|
||||||
|
@ -150,6 +154,7 @@ private:
|
||||||
Vector<String> m_font_slope_list;
|
Vector<String> m_font_slope_list;
|
||||||
Vector<String> m_unicode_block_list;
|
Vector<String> m_unicode_block_list;
|
||||||
Unicode::CodePointRange m_range { 0x0000, 0x10FFFF };
|
Unicode::CodePointRange m_range { 0x0000, 0x10FFFF };
|
||||||
|
bool m_initialized { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include <LibGUI/Application.h>
|
#include <LibGUI/Application.h>
|
||||||
#include <LibGUI/Icon.h>
|
#include <LibGUI/Icon.h>
|
||||||
#include <LibGUI/Window.h>
|
#include <LibGUI/Window.h>
|
||||||
#include <LibGfx/Font/BitmapFont.h>
|
|
||||||
#include <LibMain/Main.h>
|
#include <LibMain/Main.h>
|
||||||
|
|
||||||
ErrorOr<int> serenity_main(Main::Arguments arguments)
|
ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
|
@ -47,6 +46,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
|
|
||||||
auto font_editor = TRY(window->set_main_widget<FontEditor::MainWidget>());
|
auto font_editor = TRY(window->set_main_widget<FontEditor::MainWidget>());
|
||||||
TRY(font_editor->initialize_menubar(*window));
|
TRY(font_editor->initialize_menubar(*window));
|
||||||
|
font_editor->reset();
|
||||||
|
|
||||||
window->on_close_request = [&]() -> GUI::Window::CloseRequestDecision {
|
window->on_close_request = [&]() -> GUI::Window::CloseRequestDecision {
|
||||||
if (font_editor->request_close())
|
if (font_editor->request_close())
|
||||||
|
@ -56,16 +56,16 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
|
|
||||||
window->show();
|
window->show();
|
||||||
|
|
||||||
auto path_to_load = path.is_empty() ? "/res/fonts/KaticaRegular10.font"sv : path;
|
auto default_path = TRY(String::from_deprecated_string(Config::read_string("FontEditor"sv, "Defaults"sv, "Font"sv, {})));
|
||||||
auto file = TRY(FileSystemAccessClient::Client::the().request_file_read_only_approved(window, path_to_load));
|
auto path_to_load = path.is_empty() ? default_path : path;
|
||||||
|
auto open_or_error = [&]() -> ErrorOr<void> {
|
||||||
if (!path.is_empty()) {
|
if (path_to_load.is_empty())
|
||||||
TRY(font_editor->open_file(file.filename(), file.release_stream()));
|
return {};
|
||||||
} else {
|
auto file = TRY(FileSystemAccessClient::Client::the().request_file_read_only_approved(window, path_to_load));
|
||||||
auto mapped_file = TRY(Core::MappedFile::map_from_file(file.release_stream(), path_to_load));
|
return TRY(font_editor->open_file(path, file.release_stream()));
|
||||||
auto mutable_font = TRY(TRY(Gfx::BitmapFont::try_load_from_mapped_file(mapped_file))->unmasked_character_set());
|
}();
|
||||||
TRY(font_editor->initialize({}, move(mutable_font)));
|
if (open_or_error.is_error())
|
||||||
}
|
font_editor->show_error(open_or_error.release_error(), "Opening"sv, path_to_load);
|
||||||
|
|
||||||
return app->exec();
|
return app->exec();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue