diff --git a/Base/res/icons/16x16/selection-move.png b/Base/res/icons/16x16/selection-move.png new file mode 100644 index 00000000000..eee0e8dfca5 Binary files /dev/null and b/Base/res/icons/16x16/selection-move.png differ diff --git a/Userland/Applications/FontEditor/FontEditor.cpp b/Userland/Applications/FontEditor/FontEditor.cpp index cd25307adb7..bd4130b4446 100644 --- a/Userland/Applications/FontEditor/FontEditor.cpp +++ b/Userland/Applications/FontEditor/FontEditor.cpp @@ -108,6 +108,7 @@ FontEditorWidget::FontEditorWidget(const String& path, RefPtr&& auto& toolbar = *find_descendant_of_type_named("toolbar"); auto& statusbar = *find_descendant_of_type_named("statusbar"); auto& glyph_map_container = *find_descendant_of_type_named("glyph_map_container"); + auto& move_glyph_button = *find_descendant_of_type_named("move_glyph_button"); m_glyph_editor_container = *find_descendant_of_type_named("glyph_editor_container"); m_left_column_container = *find_descendant_of_type_named("left_column_container"); m_glyph_editor_width_spinbox = *find_descendant_of_type_named("glyph_editor_width_spinbox"); @@ -299,6 +300,15 @@ FontEditorWidget::FontEditorWidget(const String& path, RefPtr&& m_glyph_editor_scale_actions.add_action(*m_scale_fifteen_action); m_glyph_editor_scale_actions.set_exclusive(true); + move_glyph_button.on_click = [&] { + if (move_glyph_button.is_checked()) + m_glyph_editor_widget->set_mode(GlyphEditorWidget::Move); + else + m_glyph_editor_widget->set_mode(GlyphEditorWidget::Paint); + }; + move_glyph_button.set_checkable(true); + move_glyph_button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/selection-move.png")); + 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 7c9e7a0dc81..aa82a255702 100644 --- a/Userland/Applications/FontEditor/FontEditorWindow.gml +++ b/Userland/Applications/FontEditor/FontEditorWindow.gml @@ -31,13 +31,24 @@ layout: @GUI::VerticalBoxLayout { } - @GUI::SpinBox { - name: "glyph_editor_width_spinbox" - } + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + } - @GUI::CheckBox { - name: "glyph_editor_present_checkbox" - text: "Glyph Present" + @GUI::SpinBox { + name: "glyph_editor_width_spinbox" + } + + @GUI::CheckBox { + name: "glyph_editor_present_checkbox" + text: "Show" + } + + @GUI::Button { + name: "move_glyph_button" + fixed_width: 22 + button_style: "Coolbar" + } } } diff --git a/Userland/Applications/FontEditor/GlyphEditorWidget.cpp b/Userland/Applications/FontEditor/GlyphEditorWidget.cpp index 48f278933ca..c7307cad795 100644 --- a/Userland/Applications/FontEditor/GlyphEditorWidget.cpp +++ b/Userland/Applications/FontEditor/GlyphEditorWidget.cpp @@ -11,6 +11,9 @@ #include #include +static int x_offset; +static int y_offset; + GlyphEditorWidget::~GlyphEditorWidget() { } @@ -153,13 +156,49 @@ void GlyphEditorWidget::paint_event(GUI::PaintEvent& event) void GlyphEditorWidget::mousedown_event(GUI::MouseEvent& event) { - draw_at_mouse(event); + if (!(font().raw_glyph_width(m_glyph) > 0)) + return; + + if (on_undo_event) + on_undo_event(false); + if (mode() == Paint) { + draw_at_mouse(event); + } else { + memset(m_movable_bits, 0, sizeof(m_movable_bits)); + auto bitmap = font().glyph(m_glyph).glyph_bitmap(); + for (int x = s_max_width; x < s_max_width + bitmap.width(); x++) + for (int y = s_max_height; y < s_max_height + bitmap.height(); y++) + m_movable_bits[x][y] = bitmap.bit_at(x - s_max_width, y - s_max_height); + x_offset = (event.x() - 1) / m_scale; + y_offset = (event.y() - 1) / m_scale; + move_at_mouse(event); + } +} + +void GlyphEditorWidget::mouseup_event(GUI::MouseEvent&) +{ + if (on_undo_event) + on_undo_event(true); } void GlyphEditorWidget::mousemove_event(GUI::MouseEvent& event) { - if (event.buttons() & (GUI::MouseButton::Left | GUI::MouseButton::Right)) + if (!(font().raw_glyph_width(m_glyph) > 0)) + return; + if (!(event.buttons() & (GUI::MouseButton::Left | GUI::MouseButton::Right))) + return; + if (mode() == Paint) draw_at_mouse(event); + else + move_at_mouse(event); +} + +void GlyphEditorWidget::enter_event(Core::Event&) +{ + if (mode() == Move) + set_override_cursor(Gfx::StandardCursor::Move); + else + set_override_cursor(Gfx::StandardCursor::None); } void GlyphEditorWidget::draw_at_mouse(const GUI::MouseEvent& event) @@ -183,6 +222,23 @@ void GlyphEditorWidget::draw_at_mouse(const GUI::MouseEvent& event) update(); } +void GlyphEditorWidget::move_at_mouse(const GUI::MouseEvent& event) +{ + int x_delta = ((event.x() - 1) / m_scale) - x_offset; + int y_delta = ((event.y() - 1) / m_scale) - y_offset; + auto bitmap = font().glyph(m_glyph).glyph_bitmap(); + if (abs(x_delta) > bitmap.width() || abs(y_delta) > bitmap.height()) + return; + for (int x = 0; x < bitmap.width(); x++) { + for (int y = 0; y < bitmap.height(); y++) { + bitmap.set_bit_at(x, y, m_movable_bits[s_max_width + x - x_delta][s_max_height + y - y_delta]); + } + } + 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 b64f4d8e06f..2d74f450978 100644 --- a/Userland/Applications/FontEditor/GlyphEditorWidget.h +++ b/Userland/Applications/FontEditor/GlyphEditorWidget.h @@ -10,9 +10,17 @@ #include #include +static constexpr int s_max_width = 32; +static constexpr int s_max_height = 36; + class GlyphEditorWidget final : public GUI::Frame { C_OBJECT(GlyphEditorWidget) public: + enum Mode { + Paint, + Move + }; + virtual ~GlyphEditorWidget() override; void initialize(Gfx::BitmapFont&); @@ -34,6 +42,9 @@ public: int scale() const { return m_scale; } void set_scale(int scale); + Mode mode() const { return m_mode; } + void set_mode(Mode mode) { m_mode = mode; } + Function on_glyph_altered; Function on_undo_event; @@ -42,10 +53,15 @@ private: virtual void paint_event(GUI::PaintEvent&) override; virtual void mousedown_event(GUI::MouseEvent&) override; virtual void mousemove_event(GUI::MouseEvent&) override; + virtual void mouseup_event(GUI::MouseEvent&) override; + virtual void enter_event(Core::Event&) override; void draw_at_mouse(const GUI::MouseEvent&); + void move_at_mouse(const GUI::MouseEvent&); RefPtr m_font; int m_glyph { 0 }; int m_scale { 10 }; + u8 m_movable_bits[s_max_width * 3][s_max_height * 3] = {}; + Mode m_mode { Paint }; };