FontEditor: Add a ListView to sort glyphs by their Unicode block
This commit is contained in:
parent
6704bc0072
commit
aefb2bcf43
Notes:
sideshowbarker
2024-07-17 18:45:32 +09:00
Author: https://github.com/thankyouverycool Commit: https://github.com/SerenityOS/serenity/commit/aefb2bcf43 Pull-request: https://github.com/SerenityOS/serenity/pull/12504 Reviewed-by: https://github.com/trflynn89 ✅
4 changed files with 210 additions and 151 deletions
|
@ -9,6 +9,7 @@
|
|||
#include "GlyphEditorWidget.h"
|
||||
#include "NewFontDialog.h"
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/StringUtils.h>
|
||||
#include <Applications/FontEditor/FontEditorWindowGML.h>
|
||||
#include <LibConfig/Client.h>
|
||||
#include <LibDesktop/Launcher.h>
|
||||
|
@ -24,6 +25,7 @@
|
|||
#include <LibGUI/InputBox.h>
|
||||
#include <LibGUI/ItemListModel.h>
|
||||
#include <LibGUI/Label.h>
|
||||
#include <LibGUI/ListView.h>
|
||||
#include <LibGUI/Menu.h>
|
||||
#include <LibGUI/Menubar.h>
|
||||
#include <LibGUI/MessageBox.h>
|
||||
|
@ -39,7 +41,6 @@
|
|||
#include <LibGfx/Palette.h>
|
||||
#include <LibGfx/TextDirection.h>
|
||||
#include <LibUnicode/CharacterTypes.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static constexpr int s_pangram_count = 8;
|
||||
static char const* pangrams[s_pangram_count] = {
|
||||
|
@ -132,6 +133,7 @@ FontEditorWidget::FontEditorWidget()
|
|||
m_baseline_spinbox = *find_descendant_of_type_named<GUI::SpinBox>("baseline_spinbox");
|
||||
m_fixed_width_checkbox = *find_descendant_of_type_named<GUI::CheckBox>("fixed_width_checkbox");
|
||||
m_font_metadata_groupbox = *find_descendant_of_type_named<GUI::GroupBox>("font_metadata_groupbox");
|
||||
m_unicode_block_listview = *find_descendant_of_type_named<GUI::ListView>("unicode_block_listview");
|
||||
|
||||
m_glyph_editor_widget = m_glyph_editor_container->add<GlyphEditorWidget>();
|
||||
m_glyph_map_widget = glyph_map_container.add<GUI::GlyphMapWidget>();
|
||||
|
@ -210,11 +212,19 @@ FontEditorWidget::FontEditorWidget()
|
|||
});
|
||||
m_show_metadata_action->set_checked(true);
|
||||
m_show_metadata_action->set_status_tip("Show or hide metadata about the current font");
|
||||
m_show_unicode_blocks_action = GUI::Action::create_checkable("&Unicode Blocks", { Mod_Ctrl, Key_U }, [&](auto& action) {
|
||||
set_show_unicode_blocks(action.is_checked());
|
||||
});
|
||||
m_show_unicode_blocks_action->set_checked(true);
|
||||
m_show_unicode_blocks_action->set_status_tip("Show or hide the Unicode block list");
|
||||
m_go_to_glyph_action = GUI::Action::create("&Go to Glyph...", { Mod_Ctrl, Key_G }, Gfx::Bitmap::try_load_from_file("/res/icons/16x16/go-to.png").release_value_but_fixme_should_propagate_errors(), [&](auto&) {
|
||||
String input;
|
||||
if (GUI::InputBox::show(window(), input, "Hexadecimal:", "Go to Glyph") == GUI::InputBox::ExecOK && !input.is_empty()) {
|
||||
int code_point = strtoul(&input[0], nullptr, 16);
|
||||
code_point = clamp(code_point, 0x0000, 0x10FFFF);
|
||||
if (GUI::InputBox::show(window(), input, "Hexadecimal:", "Go to glyph") == GUI::InputBox::ExecOK && !input.is_empty()) {
|
||||
auto maybe_code_point = AK::StringUtils::convert_to_uint_from_hex(input);
|
||||
if (!maybe_code_point.has_value())
|
||||
return;
|
||||
auto code_point = maybe_code_point.value();
|
||||
code_point = clamp(code_point, m_range.first, m_range.last);
|
||||
m_glyph_map_widget->set_focus(true);
|
||||
m_glyph_map_widget->set_active_glyph(code_point);
|
||||
m_glyph_map_widget->scroll_to_glyph(code_point);
|
||||
|
@ -424,6 +434,25 @@ FontEditorWidget::FontEditorWidget()
|
|||
did_modify_font();
|
||||
};
|
||||
|
||||
auto unicode_blocks = Unicode::block_display_names();
|
||||
m_unicode_block_listview->on_activation = [this, unicode_blocks](auto& index) {
|
||||
if (index.row() > 0)
|
||||
m_range = unicode_blocks[index.row() - 1].code_point_range;
|
||||
else
|
||||
m_range = { 0x0000, 0x10FFFF };
|
||||
m_glyph_map_widget->set_active_range(m_range);
|
||||
};
|
||||
|
||||
m_unicode_block_list.append("Show All");
|
||||
for (auto& block : unicode_blocks)
|
||||
m_unicode_block_list.append(block.display_name);
|
||||
|
||||
m_unicode_block_model = GUI::ItemListModel<String>::create(m_unicode_block_list);
|
||||
m_unicode_block_listview->set_model(*m_unicode_block_model);
|
||||
m_unicode_block_listview->set_activates_on_selection(true);
|
||||
m_unicode_block_listview->horizontal_scrollbar().set_visible(false);
|
||||
m_unicode_block_listview->set_cursor(m_unicode_block_model->index(0, 0), GUI::AbstractView::SelectionUpdate::Set);
|
||||
|
||||
GUI::Application::the()->on_action_enter = [this](GUI::Action& action) {
|
||||
auto text = action.status_tip();
|
||||
if (text.is_empty())
|
||||
|
@ -543,6 +572,7 @@ void FontEditorWidget::initialize_menubar(GUI::Window& window)
|
|||
view_menu.add_action(*m_open_preview_action);
|
||||
view_menu.add_separator();
|
||||
view_menu.add_action(*m_show_metadata_action);
|
||||
view_menu.add_action(*m_show_unicode_blocks_action);
|
||||
view_menu.add_separator();
|
||||
auto& scale_menu = view_menu.add_submenu("&Scale");
|
||||
scale_menu.add_action(*m_scale_five_action);
|
||||
|
@ -579,6 +609,14 @@ void FontEditorWidget::set_show_font_metadata(bool show)
|
|||
m_font_metadata_groupbox->set_visible(m_font_metadata);
|
||||
}
|
||||
|
||||
void FontEditorWidget::set_show_unicode_blocks(bool show)
|
||||
{
|
||||
if (m_unicode_blocks == show)
|
||||
return;
|
||||
m_unicode_blocks = show;
|
||||
m_unicode_block_listview->set_visible(m_unicode_blocks);
|
||||
}
|
||||
|
||||
bool FontEditorWidget::open_file(String const& path)
|
||||
{
|
||||
auto bitmap_font = Gfx::BitmapFont::load_from_file(path);
|
||||
|
|
|
@ -35,7 +35,10 @@ public:
|
|||
void initialize_menubar(GUI::Window&);
|
||||
|
||||
bool is_showing_font_metadata() { return m_font_metadata; }
|
||||
void set_show_font_metadata(bool b);
|
||||
void set_show_font_metadata(bool);
|
||||
|
||||
bool is_showing_unicode_blocks() { return m_unicode_blocks; }
|
||||
void set_show_unicode_blocks(bool);
|
||||
|
||||
Function<void()> on_initialize;
|
||||
|
||||
|
@ -87,6 +90,7 @@ private:
|
|||
|
||||
RefPtr<GUI::Action> m_open_preview_action;
|
||||
RefPtr<GUI::Action> m_show_metadata_action;
|
||||
RefPtr<GUI::Action> m_show_unicode_blocks_action;
|
||||
|
||||
GUI::ActionGroup m_glyph_editor_scale_actions;
|
||||
RefPtr<GUI::Action> m_scale_five_action;
|
||||
|
@ -119,9 +123,14 @@ private:
|
|||
RefPtr<GUI::TextBox> m_family_textbox;
|
||||
RefPtr<GUI::CheckBox> m_fixed_width_checkbox;
|
||||
RefPtr<GUI::GroupBox> m_font_metadata_groupbox;
|
||||
RefPtr<GUI::ListView> m_unicode_block_listview;
|
||||
RefPtr<GUI::Model> m_unicode_block_model;
|
||||
|
||||
String m_path;
|
||||
Vector<String> m_font_weight_list;
|
||||
Vector<String> m_font_slope_list;
|
||||
Vector<String> m_unicode_block_list;
|
||||
bool m_font_metadata { true };
|
||||
bool m_unicode_blocks { true };
|
||||
Unicode::CodePointRange m_range { 0x0000, 0x10FFFF };
|
||||
};
|
||||
|
|
|
@ -58,159 +58,171 @@
|
|||
spacing: 6
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
name: "glyph_map_container"
|
||||
layout: @GUI::VerticalBoxLayout {}
|
||||
}
|
||||
|
||||
@GUI::GroupBox {
|
||||
name: "font_metadata_groupbox"
|
||||
title: "Metadata"
|
||||
shrink_to_fit: true
|
||||
layout: @GUI::VerticalBoxLayout {
|
||||
margins: [6, 6, 6, 6]
|
||||
}
|
||||
@GUI::HorizontalSplitter {
|
||||
|
||||
@GUI::Widget {
|
||||
fixed_height: 22
|
||||
layout: @GUI::HorizontalBoxLayout {}
|
||||
layout: @GUI::VerticalBoxLayout {}
|
||||
|
||||
@GUI::Label {
|
||||
name: "name_label"
|
||||
fixed_width: 100
|
||||
text_alignment: "CenterLeft"
|
||||
text: "Name:"
|
||||
@GUI::Widget {
|
||||
name: "glyph_map_container"
|
||||
layout: @GUI::VerticalBoxLayout {}
|
||||
}
|
||||
|
||||
@GUI::TextBox {
|
||||
name: "name_textbox"
|
||||
@GUI::GroupBox {
|
||||
name: "font_metadata_groupbox"
|
||||
title: "Metadata"
|
||||
shrink_to_fit: true
|
||||
layout: @GUI::VerticalBoxLayout {
|
||||
margins: [6, 6, 6, 6]
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
fixed_height: 22
|
||||
layout: @GUI::HorizontalBoxLayout {}
|
||||
|
||||
@GUI::Label {
|
||||
name: "name_label"
|
||||
fixed_width: 100
|
||||
text_alignment: "CenterLeft"
|
||||
text: "Name:"
|
||||
}
|
||||
|
||||
@GUI::TextBox {
|
||||
name: "name_textbox"
|
||||
}
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
fixed_height: 22
|
||||
layout: @GUI::HorizontalBoxLayout {}
|
||||
|
||||
@GUI::Label {
|
||||
name: "family_label"
|
||||
fixed_width: 100
|
||||
text_alignment: "CenterLeft"
|
||||
text: "Family:"
|
||||
}
|
||||
|
||||
@GUI::TextBox {
|
||||
name: "family_textbox"
|
||||
}
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
fixed_height: 22
|
||||
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 {
|
||||
fixed_height: 22
|
||||
layout: @GUI::HorizontalBoxLayout {}
|
||||
|
||||
@GUI::Label {
|
||||
name: "slope_label"
|
||||
fixed_width: 100
|
||||
text_alignment: "CenterLeft"
|
||||
text: "Slope:"
|
||||
}
|
||||
|
||||
@GUI::ComboBox {
|
||||
name: "slope_combobox"
|
||||
model_only: true
|
||||
}
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
fixed_height: 22
|
||||
layout: @GUI::HorizontalBoxLayout {}
|
||||
|
||||
@GUI::Label {
|
||||
name: "presentation_label"
|
||||
fixed_width: 100
|
||||
text_alignment: "CenterLeft"
|
||||
text: "Presentation size:"
|
||||
}
|
||||
|
||||
@GUI::SpinBox {
|
||||
name: "presentation_spinbox"
|
||||
min: 0
|
||||
max: 255
|
||||
}
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
fixed_height: 22
|
||||
layout: @GUI::HorizontalBoxLayout {}
|
||||
|
||||
@GUI::Label {
|
||||
name: "mean_line_label"
|
||||
fixed_width: 100
|
||||
text_alignment: "CenterLeft"
|
||||
text: "Mean line:"
|
||||
}
|
||||
|
||||
@GUI::SpinBox {
|
||||
name: "mean_line_spinbox"
|
||||
min: 0
|
||||
}
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
fixed_height: 22
|
||||
layout: @GUI::HorizontalBoxLayout {}
|
||||
|
||||
@GUI::Label {
|
||||
name: "baseline_label"
|
||||
fixed_width: 100
|
||||
text_alignment: "CenterLeft"
|
||||
text: "Baseline:"
|
||||
}
|
||||
|
||||
@GUI::SpinBox {
|
||||
name: "baseline_spinbox"
|
||||
min: 0
|
||||
}
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
fixed_height: 22
|
||||
layout: @GUI::HorizontalBoxLayout {}
|
||||
|
||||
@GUI::Label {
|
||||
name: "spacing_label"
|
||||
fixed_width: 100
|
||||
text_alignment: "CenterLeft"
|
||||
text: "Glyph spacing:"
|
||||
}
|
||||
|
||||
@GUI::SpinBox {
|
||||
name: "spacing_spinbox"
|
||||
min: 0
|
||||
max: 255
|
||||
}
|
||||
|
||||
@GUI::CheckBox {
|
||||
name: "fixed_width_checkbox"
|
||||
text: "Fixed width"
|
||||
autosize: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
fixed_height: 22
|
||||
layout: @GUI::HorizontalBoxLayout {}
|
||||
|
||||
@GUI::Label {
|
||||
name: "family_label"
|
||||
fixed_width: 100
|
||||
text_alignment: "CenterLeft"
|
||||
text: "Family:"
|
||||
}
|
||||
|
||||
@GUI::TextBox {
|
||||
name: "family_textbox"
|
||||
}
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
fixed_height: 22
|
||||
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 {
|
||||
fixed_height: 22
|
||||
layout: @GUI::HorizontalBoxLayout {}
|
||||
|
||||
@GUI::Label {
|
||||
name: "slope_label"
|
||||
fixed_width: 100
|
||||
text_alignment: "CenterLeft"
|
||||
text: "Slope:"
|
||||
}
|
||||
|
||||
@GUI::ComboBox {
|
||||
name: "slope_combobox"
|
||||
model_only: true
|
||||
}
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
fixed_height: 22
|
||||
layout: @GUI::HorizontalBoxLayout {}
|
||||
|
||||
@GUI::Label {
|
||||
name: "presentation_label"
|
||||
fixed_width: 100
|
||||
text_alignment: "CenterLeft"
|
||||
text: "Presentation size:"
|
||||
}
|
||||
|
||||
@GUI::SpinBox {
|
||||
name: "presentation_spinbox"
|
||||
min: 0
|
||||
max: 255
|
||||
}
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
fixed_height: 22
|
||||
layout: @GUI::HorizontalBoxLayout {}
|
||||
|
||||
@GUI::Label {
|
||||
name: "mean_line_label"
|
||||
fixed_width: 100
|
||||
text_alignment: "CenterLeft"
|
||||
text: "Mean line:"
|
||||
}
|
||||
|
||||
@GUI::SpinBox {
|
||||
name: "mean_line_spinbox"
|
||||
min: 0
|
||||
}
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
fixed_height: 22
|
||||
layout: @GUI::HorizontalBoxLayout {}
|
||||
|
||||
@GUI::Label {
|
||||
name: "baseline_label"
|
||||
fixed_width: 100
|
||||
text_alignment: "CenterLeft"
|
||||
text: "Baseline:"
|
||||
}
|
||||
|
||||
@GUI::SpinBox {
|
||||
name: "baseline_spinbox"
|
||||
min: 0
|
||||
}
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
fixed_height: 22
|
||||
layout: @GUI::HorizontalBoxLayout {}
|
||||
|
||||
@GUI::Label {
|
||||
name: "spacing_label"
|
||||
fixed_width: 100
|
||||
text_alignment: "CenterLeft"
|
||||
text: "Glyph spacing:"
|
||||
}
|
||||
|
||||
@GUI::SpinBox {
|
||||
name: "spacing_spinbox"
|
||||
min: 0
|
||||
max: 255
|
||||
}
|
||||
|
||||
@GUI::CheckBox {
|
||||
name: "fixed_width_checkbox"
|
||||
text: "Fixed width"
|
||||
autosize: true
|
||||
}
|
||||
@GUI::ListView {
|
||||
name: "unicode_block_listview"
|
||||
max_width: 175
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
|
||||
auto window = TRY(GUI::Window::try_create());
|
||||
window->set_icon(app_icon.bitmap_for_size(16));
|
||||
window->resize(440, 470);
|
||||
window->resize(640, 470);
|
||||
|
||||
auto font_editor = TRY(window->try_set_main_widget<FontEditorWidget>());
|
||||
font_editor->initialize_menubar(*window);
|
||||
|
|
Loading…
Add table
Reference in a new issue