diff options
author | Ben Wiederhake <BenWiederhake.GitHub@gmx.de> | 2021-11-20 02:38:24 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-11-20 12:56:35 +0100 |
commit | 7180813cd452d496f7f06543923b8a4e110e3d8d (patch) | |
tree | 91ce6194a424b333dd4e1984d9e962e0e8463d04 /Userland/Applications/FontEditor | |
parent | 1dfb3ff4ebb82dc991f7fd257a5da99d2ceecd7a (diff) | |
download | serenity-7180813cd452d496f7f06543923b8a4e110e3d8d.zip |
FontEditor: Support flipping and rotating
This is especially useful for highly symmetric scripts like this:
https://www.unicode.org/charts/PDF/U1400.pdf
Diffstat (limited to 'Userland/Applications/FontEditor')
4 files changed, 138 insertions, 2 deletions
diff --git a/Userland/Applications/FontEditor/FontEditor.cpp b/Userland/Applications/FontEditor/FontEditor.cpp index 7e8080d6c8..5aa52c189f 100644 --- a/Userland/Applications/FontEditor/FontEditor.cpp +++ b/Userland/Applications/FontEditor/FontEditor.cpp @@ -113,6 +113,9 @@ FontEditorWidget::FontEditorWidget(const String& path, RefPtr<Gfx::BitmapFont>&& auto& toolbar = *find_descendant_of_type_named<GUI::Toolbar>("toolbar"); auto& glyph_map_container = *find_descendant_of_type_named<GUI::Widget>("glyph_map_container"); auto& move_glyph_button = *find_descendant_of_type_named<GUI::Button>("move_glyph_button"); + auto& rotate_90_button = *find_descendant_of_type_named<GUI::Button>("rotate_90"); + auto& flip_vertical_button = *find_descendant_of_type_named<GUI::Button>("flip_vertical"); + auto& flip_horizontal_button = *find_descendant_of_type_named<GUI::Button>("flip_horizontal"); m_statusbar = *find_descendant_of_type_named<GUI::Statusbar>("statusbar"); m_glyph_editor_container = *find_descendant_of_type_named<GUI::Widget>("glyph_editor_container"); m_left_column_container = *find_descendant_of_type_named<GUI::Widget>("left_column_container"); @@ -329,6 +332,21 @@ FontEditorWidget::FontEditorWidget(const String& path, RefPtr<Gfx::BitmapFont>&& }; move_glyph_button.set_icon(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/selection-move.png").release_value_but_fixme_should_propagate_errors()); + rotate_90_button.on_click = [&](auto) { + m_glyph_editor_widget->rotate_90(); + }; + rotate_90_button.set_icon(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/edit-rotate-cw.png").release_value_but_fixme_should_propagate_errors()); + + flip_vertical_button.on_click = [&](auto) { + m_glyph_editor_widget->flip_vertically(); + }; + flip_vertical_button.set_icon(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/edit-flip-vertical.png").release_value_but_fixme_should_propagate_errors()); + + flip_horizontal_button.on_click = [&](auto) { + m_glyph_editor_widget->flip_horizontally(); + }; + flip_horizontal_button.set_icon(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/edit-flip-horizontal.png").release_value_but_fixme_should_propagate_errors()); + GUI::Clipboard::the().on_change = [&](const String& data_type) { m_paste_action->set_enabled(data_type == "glyph/x-fonteditor"); }; diff --git a/Userland/Applications/FontEditor/FontEditorWindow.gml b/Userland/Applications/FontEditor/FontEditorWindow.gml index b2f09d4fef..3a5c24b17a 100644 --- a/Userland/Applications/FontEditor/FontEditorWindow.gml +++ b/Userland/Applications/FontEditor/FontEditorWindow.gml @@ -58,9 +58,37 @@ checkable: true } } - } - @GUI::Widget { + @GUI::Widget { + shrink_to_fit: true + + layout: @GUI::HorizontalBoxLayout { + } + + @GUI::Button { + name: "flip_vertical" + fixed_width: 22 + tooltip: "Flip vertically (top to bottom)" + button_style: "Coolbar" + focus_policy: "TabFocus" + } + + @GUI::Button { + name: "flip_horizontal" + fixed_width: 22 + tooltip: "Flip horizontally (left to right)" + button_style: "Coolbar" + focus_policy: "TabFocus" + } + + @GUI::Button { + name: "rotate_90" + fixed_width: 22 + tooltip: "Rotate 90° clockwise" + button_style: "Coolbar" + focus_policy: "TabFocus" + } + } } } diff --git a/Userland/Applications/FontEditor/GlyphEditorWidget.cpp b/Userland/Applications/FontEditor/GlyphEditorWidget.cpp index d4877bca4e..d33f606e37 100644 --- a/Userland/Applications/FontEditor/GlyphEditorWidget.cpp +++ b/Userland/Applications/FontEditor/GlyphEditorWidget.cpp @@ -250,6 +250,92 @@ void GlyphEditorWidget::move_at_mouse(const GUI::MouseEvent& event) update(); } +static Vector<Vector<u8>> glyph_as_matrix(Gfx::GlyphBitmap const& bitmap) +{ + Vector<Vector<u8>> result; + result.ensure_capacity(bitmap.height()); + + for (int y = 0; y < bitmap.height(); y++) { + result.empend(); + auto& row = result.last(); + row.ensure_capacity(bitmap.width()); + for (int x = 0; x < bitmap.width(); x++) { + row.append(bitmap.bit_at(x, y)); + } + } + + return result; +} + +void GlyphEditorWidget::rotate_90() +{ + if (on_undo_event) + on_undo_event(); + + auto bitmap = font().raw_glyph(m_glyph).glyph_bitmap(); + auto matrix = glyph_as_matrix(bitmap); + + for (int y = 0; y < bitmap.height(); y++) { + for (int x = 0; x < bitmap.width(); x++) { + int source_x = y; + int source_y = bitmap.width() - 1 - x; + bool value = false; + if (source_x < bitmap.width() && source_y < bitmap.height()) { + value = matrix[source_y][source_x]; + } + bitmap.set_bit_at(x, y, value); + } + } + + if (on_glyph_altered) + on_glyph_altered(m_glyph); + update(); +} + +void GlyphEditorWidget::flip_vertically() +{ + if (on_undo_event) + on_undo_event(); + + auto bitmap = font().raw_glyph(m_glyph).glyph_bitmap(); + auto matrix = glyph_as_matrix(bitmap); + + for (int y = 0; y < bitmap.height(); y++) { + for (int x = 0; x < bitmap.width(); x++) { + int source_x = x; + int source_y = bitmap.height() - 1 - y; + bool value = matrix[source_y][source_x]; + bitmap.set_bit_at(x, y, value); + } + } + + if (on_glyph_altered) + on_glyph_altered(m_glyph); + update(); +} + +void GlyphEditorWidget::flip_horizontally() +{ + if (on_undo_event) + on_undo_event(); + + auto bitmap = font().raw_glyph(m_glyph).glyph_bitmap(); + auto matrix = glyph_as_matrix(bitmap); + + for (int y = 0; y < bitmap.height(); y++) { + for (int x = 0; x < bitmap.width(); x++) { + int source_x = bitmap.width() - 1 - x; + int source_y = y; + bool value = matrix[source_y][source_x]; + bitmap.set_bit_at(x, y, value); + } + } + + if (on_glyph_altered) + on_glyph_altered(m_glyph); + update(); +} + int GlyphEditorWidget::preferred_width() const { return frame_thickness() * 2 + font().max_glyph_width() * m_scale - 1; diff --git a/Userland/Applications/FontEditor/GlyphEditorWidget.h b/Userland/Applications/FontEditor/GlyphEditorWidget.h index 9a5d6cf7f9..6cc42c44ab 100644 --- a/Userland/Applications/FontEditor/GlyphEditorWidget.h +++ b/Userland/Applications/FontEditor/GlyphEditorWidget.h @@ -34,6 +34,10 @@ public: void delete_glyph(); bool is_glyph_empty(); + void rotate_90(); + void flip_vertically(); + void flip_horizontally(); + int preferred_width() const; int preferred_height() const; |