mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-08 04:50:08 +03:00
FontEditor: Add undo and redo commands
This commit is contained in:
parent
2785e12b76
commit
44cd121e30
Notes:
sideshowbarker
2024-07-18 19:12:42 +09:00
Author: https://github.com/thankyouverycool Commit: https://github.com/SerenityOS/serenity/commit/44cd121e309 Pull-request: https://github.com/SerenityOS/serenity/pull/6563
@ -12,6 +12,7 @@ set(SOURCES
|
||||
NewFontDialog.cpp
|
||||
NewFontDialogPage1GML.h
|
||||
NewFontDialogPage2GML.h
|
||||
UndoGlyph.h
|
||||
)
|
||||
|
||||
serenity_app(FontEditor ICON app-font-editor)
|
||||
|
@ -236,6 +236,14 @@ FontEditorWidget::FontEditorWidget(const String& path, RefPtr<Gfx::BitmapFont>&&
|
||||
m_glyph_editor_width_spinbox->set_value(glyph_width);
|
||||
m_glyph_editor_present_checkbox->set_checked(glyph_width > 0);
|
||||
});
|
||||
m_undo_action = GUI::CommonActions::make_undo_action([&](auto&) {
|
||||
undo();
|
||||
});
|
||||
m_undo_action->set_enabled(false);
|
||||
m_redo_action = GUI::CommonActions::make_redo_action([&](auto&) {
|
||||
redo();
|
||||
});
|
||||
m_redo_action->set_enabled(false);
|
||||
m_open_preview_action = GUI::Action::create("&Preview Font", { Mod_Ctrl, Key_P }, Gfx::Bitmap::load_from_file("/res/icons/16x16/find.png"), [&](auto&) {
|
||||
if (!m_font_preview_window)
|
||||
m_font_preview_window = create_font_preview_window(*this);
|
||||
@ -259,6 +267,9 @@ FontEditorWidget::FontEditorWidget(const String& path, RefPtr<Gfx::BitmapFont>&&
|
||||
toolbar.add_action(*m_paste_action);
|
||||
toolbar.add_action(*m_delete_action);
|
||||
toolbar.add_separator();
|
||||
toolbar.add_action(*m_undo_action);
|
||||
toolbar.add_action(*m_redo_action);
|
||||
toolbar.add_separator();
|
||||
toolbar.add_action(*m_open_preview_action);
|
||||
|
||||
m_scale_five_action = GUI::Action::create_checkable("500%", { Mod_Ctrl, Key_1 }, [&](auto&) {
|
||||
@ -297,7 +308,16 @@ FontEditorWidget::FontEditorWidget(const String& path, RefPtr<Gfx::BitmapFont>&&
|
||||
update_demo();
|
||||
};
|
||||
|
||||
m_glyph_map_widget->on_glyph_selected = [&](int glyph) {
|
||||
m_glyph_editor_widget->on_undo_event = [this](bool finalize) {
|
||||
m_undo_stack->push(make<GlyphUndoCommand>(*m_undo_glyph));
|
||||
if (finalize)
|
||||
m_undo_stack->finalize_current_combo();
|
||||
did_change_undo_stack();
|
||||
};
|
||||
|
||||
m_glyph_map_widget->on_glyph_selected = [&, update_statusbar](int glyph) {
|
||||
if (m_undo_glyph)
|
||||
m_undo_glyph->set_code_point(glyph);
|
||||
m_glyph_editor_widget->set_glyph(glyph);
|
||||
auto glyph_width = m_edited_font->raw_glyph_width(m_glyph_map_widget->selected_glyph());
|
||||
m_glyph_editor_width_spinbox->set_value(glyph_width);
|
||||
@ -447,6 +467,10 @@ void FontEditorWidget::initialize(const String& path, RefPtr<Gfx::BitmapFont>&&
|
||||
m_glyph_map_widget->scroll_to_glyph(m_glyph_map_widget->selected_glyph());
|
||||
});
|
||||
|
||||
m_undo_stack = make<GUI::UndoStack>();
|
||||
m_undo_glyph = adopt(*new UndoGlyph(m_glyph_map_widget->selected_glyph(), *m_edited_font));
|
||||
did_change_undo_stack();
|
||||
|
||||
if (on_initialize)
|
||||
on_initialize();
|
||||
}
|
||||
@ -464,6 +488,9 @@ void FontEditorWidget::initialize_menubar(GUI::Menubar& menubar)
|
||||
}));
|
||||
|
||||
auto& edit_menu = menubar.add_menu("&Edit");
|
||||
edit_menu.add_action(*m_undo_action);
|
||||
edit_menu.add_action(*m_redo_action);
|
||||
edit_menu.add_separator();
|
||||
edit_menu.add_action(*m_cut_action);
|
||||
edit_menu.add_action(*m_copy_action);
|
||||
edit_menu.add_action(*m_paste_action);
|
||||
@ -504,3 +531,35 @@ void FontEditorWidget::set_show_font_metadata(bool show)
|
||||
m_font_metadata = show;
|
||||
m_font_metadata_groupbox->set_visible(m_font_metadata);
|
||||
}
|
||||
|
||||
void FontEditorWidget::undo()
|
||||
{
|
||||
if (!m_undo_stack->can_undo())
|
||||
return;
|
||||
m_undo_stack->undo();
|
||||
did_change_undo_stack();
|
||||
|
||||
m_glyph_editor_widget->update();
|
||||
m_glyph_map_widget->update();
|
||||
if (m_font_preview_window)
|
||||
m_font_preview_window->update();
|
||||
}
|
||||
|
||||
void FontEditorWidget::redo()
|
||||
{
|
||||
if (!m_undo_stack->can_redo())
|
||||
return;
|
||||
m_undo_stack->redo();
|
||||
did_change_undo_stack();
|
||||
|
||||
m_glyph_editor_widget->update();
|
||||
m_glyph_map_widget->update();
|
||||
if (m_font_preview_window)
|
||||
m_font_preview_window->update();
|
||||
}
|
||||
|
||||
void FontEditorWidget::did_change_undo_stack()
|
||||
{
|
||||
m_undo_action->set_enabled(m_undo_stack->can_undo());
|
||||
m_redo_action->set_enabled(m_undo_stack->can_redo());
|
||||
}
|
||||
|
@ -6,6 +6,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "UndoGlyph.h"
|
||||
#include <LibGUI/ActionGroup.h>
|
||||
#include <LibGUI/UndoStack.h>
|
||||
#include <LibGUI/Widget.h>
|
||||
#include <LibGfx/BitmapFont.h>
|
||||
|
||||
@ -31,6 +34,11 @@ public:
|
||||
|
||||
private:
|
||||
FontEditorWidget(const String& path, RefPtr<Gfx::BitmapFont>&&);
|
||||
|
||||
void undo();
|
||||
void redo();
|
||||
void did_change_undo_stack();
|
||||
|
||||
RefPtr<Gfx::BitmapFont> m_edited_font;
|
||||
|
||||
RefPtr<GlyphMapWidget> m_glyph_map_widget;
|
||||
@ -46,6 +54,11 @@ private:
|
||||
RefPtr<GUI::Action> m_paste_action;
|
||||
RefPtr<GUI::Action> m_delete_action;
|
||||
|
||||
RefPtr<GUI::Action> m_undo_action;
|
||||
RefPtr<GUI::Action> m_redo_action;
|
||||
RefPtr<UndoGlyph> m_undo_glyph;
|
||||
OwnPtr<GUI::UndoStack> m_undo_stack;
|
||||
|
||||
RefPtr<GUI::Action> m_open_preview_action;
|
||||
RefPtr<GUI::Action> m_show_metadata_action;
|
||||
|
||||
|
@ -34,10 +34,14 @@ void GlyphEditorWidget::set_glyph(int glyph)
|
||||
|
||||
void GlyphEditorWidget::delete_glyph()
|
||||
{
|
||||
if (on_undo_event)
|
||||
on_undo_event(false);
|
||||
auto bitmap = font().glyph(m_glyph).glyph_bitmap();
|
||||
for (int x = 0; x < bitmap.width(); x++)
|
||||
for (int y = 0; y < bitmap.height(); y++)
|
||||
bitmap.set_bit_at(x, y, false);
|
||||
if (on_undo_event)
|
||||
on_undo_event(true);
|
||||
if (on_glyph_altered)
|
||||
on_glyph_altered(m_glyph);
|
||||
update();
|
||||
@ -82,6 +86,9 @@ void GlyphEditorWidget::paste_glyph()
|
||||
if (!mime_type.starts_with("glyph/"))
|
||||
return;
|
||||
|
||||
if (on_undo_event)
|
||||
on_undo_event(false);
|
||||
|
||||
auto byte_buffer = GUI::Clipboard::the().data();
|
||||
auto buffer_height = GUI::Clipboard::the().data_and_type().metadata.get("height").value().to_int();
|
||||
auto buffer_width = GUI::Clipboard::the().data_and_type().metadata.get("width").value().to_int();
|
||||
@ -102,6 +109,8 @@ void GlyphEditorWidget::paste_glyph()
|
||||
bitmap.set_bit_at(x, y, bits[x][y]);
|
||||
}
|
||||
}
|
||||
if (on_undo_event)
|
||||
on_undo_event(true);
|
||||
if (on_glyph_altered)
|
||||
on_glyph_altered(m_glyph);
|
||||
update();
|
||||
|
@ -35,6 +35,7 @@ public:
|
||||
void set_scale(int scale);
|
||||
|
||||
Function<void(int)> on_glyph_altered;
|
||||
Function<void(bool finalize)> on_undo_event;
|
||||
|
||||
private:
|
||||
GlyphEditorWidget() {};
|
||||
|
65
Userland/Applications/FontEditor/UndoGlyph.h
Normal file
65
Userland/Applications/FontEditor/UndoGlyph.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2021, the SerenityOS developers
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibGUI/Command.h>
|
||||
#include <LibGUI/UndoStack.h>
|
||||
#include <LibGfx/BitmapFont.h>
|
||||
|
||||
class UndoGlyph : public RefCounted<UndoGlyph> {
|
||||
public:
|
||||
explicit UndoGlyph(const size_t code_point, const Gfx::BitmapFont& font)
|
||||
: m_code_point(code_point)
|
||||
, m_font(font)
|
||||
{
|
||||
}
|
||||
RefPtr<UndoGlyph> save_state() const
|
||||
{
|
||||
auto state = adopt(*new UndoGlyph(m_code_point, *m_font));
|
||||
auto glyph = font().glyph(m_code_point).glyph_bitmap();
|
||||
for (int x = 0; x < glyph.width(); x++)
|
||||
for (int y = 0; y < glyph.height(); y++)
|
||||
state->m_bits[x][y] = glyph.bit_at(x, y);
|
||||
return state;
|
||||
}
|
||||
void restore_state(const UndoGlyph& state) const
|
||||
{
|
||||
auto bitmap = font().glyph(state.m_code_point).glyph_bitmap();
|
||||
for (int x = 0; x < bitmap.width(); x++)
|
||||
for (int y = 0; y < bitmap.height(); y++)
|
||||
bitmap.set_bit_at(x, y, state.m_bits[x][y]);
|
||||
}
|
||||
void set_code_point(size_t point) { m_code_point = point; }
|
||||
void set_font(Gfx::BitmapFont& font) { m_font = font; }
|
||||
const Gfx::BitmapFont& font() const { return *m_font; }
|
||||
|
||||
private:
|
||||
size_t m_code_point;
|
||||
RefPtr<Gfx::BitmapFont> m_font;
|
||||
u8 m_bits[32][36] = {};
|
||||
};
|
||||
|
||||
class GlyphUndoCommand : public GUI::Command {
|
||||
public:
|
||||
GlyphUndoCommand(UndoGlyph& glyph)
|
||||
: m_state(glyph.save_state())
|
||||
, m_undo_glyph(glyph)
|
||||
{
|
||||
}
|
||||
virtual void undo() override
|
||||
{
|
||||
m_undo_glyph.restore_state(*m_state);
|
||||
}
|
||||
virtual void redo() override
|
||||
{
|
||||
undo();
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<UndoGlyph> m_state;
|
||||
UndoGlyph& m_undo_glyph;
|
||||
};
|
Loading…
Reference in New Issue
Block a user