diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-02-10 08:35:01 +0100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-02-10 08:35:01 +0100 |
commit | 2cf1dd5b6f10b898f24203c879290d665531a989 (patch) | |
tree | e06e872f557e489b2d0fe3cb0ea2302e8a72ef91 /Applications/FontEditor/FontEditor.cpp | |
parent | 29f2a22d34554737a67af5b2b2ab8613591383be (diff) | |
download | serenity-2cf1dd5b6f10b898f24203c879290d665531a989.zip |
Move apps into a top-level Applications/ directory.
Diffstat (limited to 'Applications/FontEditor/FontEditor.cpp')
-rw-r--r-- | Applications/FontEditor/FontEditor.cpp | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/Applications/FontEditor/FontEditor.cpp b/Applications/FontEditor/FontEditor.cpp new file mode 100644 index 0000000000..6d2e0c346e --- /dev/null +++ b/Applications/FontEditor/FontEditor.cpp @@ -0,0 +1,247 @@ +#include "FontEditor.h" +#include <SharedGraphics/Painter.h> +#include <LibGUI/GButton.h> +#include <LibGUI/GLabel.h> +#include <LibGUI/GTextBox.h> + +FontEditorWidget::FontEditorWidget(const String& path, RetainPtr<Font>&& edited_font, GWidget* parent) + : GWidget(parent) + , m_edited_font(move(edited_font)) +{ + if (path.is_empty()) + m_path = "/saved.font"; + else + m_path = path; + + m_glyph_map_widget = new GlyphMapWidget(*m_edited_font, this); + m_glyph_map_widget->move_to({ 90, 5 }); + + m_glyph_editor_widget = new GlyphEditorWidget(*m_edited_font, this); + m_glyph_editor_widget->move_to({ 5, 5 }); + + m_name_textbox = new GTextBox(this); + m_name_textbox->set_relative_rect({ 5, 135, 100, 20 }); + m_name_textbox->set_text(m_edited_font->name()); + m_name_textbox->on_change = [this] (GTextBox&) { + m_edited_font->set_name(m_name_textbox->text()); + }; + + auto* save_button = new GButton(this); + save_button->set_caption("Save"); + save_button->set_relative_rect({ 5, 170, 100, 20 }); + save_button->on_click = [this] (GButton&) { + dbgprintf("write to file: '%s'\n", m_path.characters()); + m_edited_font->write_to_file(m_path); + }; + + auto* quit_button = new GButton(this); + quit_button->set_caption("Quit"); + quit_button->set_relative_rect({ 110, 170, 100, 20 }); + quit_button->on_click = [] (GButton&) { + exit(0); + }; + + auto* info_label = new GLabel(this); + info_label->set_relative_rect({ 5, 110, 100, 20 }); + + auto* demo_label_1 = new GLabel(this); + demo_label_1->set_font(m_edited_font.copy_ref()); + demo_label_1->set_text("quick fox jumps nightly above wizard."); + demo_label_1->set_relative_rect({ 110, 120, 300, 20 }); + + auto* demo_label_2 = new GLabel(this); + demo_label_2->set_font(m_edited_font.copy_ref()); + demo_label_2->set_text("QUICK FOX JUMPS NIGHTLY ABOVE WIZARD!"); + demo_label_2->set_relative_rect({ 110, 140, 300, 20 }); + + m_glyph_editor_widget->on_glyph_altered = [this, demo_label_1, demo_label_2] { + m_glyph_map_widget->update(); + demo_label_1->update(); + demo_label_2->update(); + }; + + m_glyph_map_widget->on_glyph_selected = [this, info_label] (byte glyph) { + m_glyph_editor_widget->set_glyph(glyph); + info_label->set_text(String::format("0x%b (%c)", glyph, glyph)); + }; + + m_glyph_map_widget->set_selected_glyph('A'); +} + +FontEditorWidget::~FontEditorWidget() +{ +} + +GlyphMapWidget::GlyphMapWidget(Font& mutable_font, GWidget* parent) + : GWidget(parent) + , m_font(mutable_font) +{ + set_relative_rect({ 0, 0, preferred_width(), preferred_height() }); +} + +GlyphMapWidget::~GlyphMapWidget() +{ +} + +int GlyphMapWidget::preferred_width() const +{ + return columns() * (font().glyph_width() + m_horizontal_spacing) + 2; +} + +int GlyphMapWidget::preferred_height() const +{ + return rows() * (font().glyph_height() + m_vertical_spacing) + 2; +} + +void GlyphMapWidget::set_selected_glyph(byte glyph) +{ + if (m_selected_glyph == glyph) + return; + m_selected_glyph = glyph; + if (on_glyph_selected) + on_glyph_selected(glyph); + update(); +} + +Rect GlyphMapWidget::get_outer_rect(byte glyph) const +{ + int row = glyph / columns(); + int column = glyph % columns(); + return { + column * (font().glyph_width() + m_horizontal_spacing) + 1, + row * (font().glyph_height() + m_vertical_spacing) + 1, + font().glyph_width() + m_horizontal_spacing, + font().glyph_height() + m_horizontal_spacing + }; +} + +void GlyphMapWidget::paint_event(GPaintEvent&) +{ + Painter painter(*this); + painter.set_font(font()); + painter.fill_rect(rect(), Color::White); + painter.draw_rect(rect(), Color::Black); + + byte glyph = 0; + + for (int row = 0; row < rows(); ++row) { + for (int column = 0; column < columns(); ++column, ++glyph) { + Rect outer_rect = get_outer_rect(glyph); + Rect inner_rect( + outer_rect.x() + m_horizontal_spacing / 2, + outer_rect.y() + m_vertical_spacing / 2, + font().glyph_width(), + font().glyph_height() + ); + if (glyph == m_selected_glyph) { + painter.fill_rect(outer_rect, Color::Red); + painter.draw_glyph(inner_rect.location(), glyph, Color::White); + } else { + painter.draw_glyph(inner_rect.location(), glyph, Color::Black); + } + } + } + + if (is_focused()) + painter.draw_focus_rect(rect()); +} + +void GlyphMapWidget::mousedown_event(GMouseEvent& event) +{ + // FIXME: This is a silly loop. + for (unsigned glyph = 0; glyph < 256; ++glyph) { + if (get_outer_rect(glyph).contains(event.position())) { + set_selected_glyph(glyph); + break; + } + } +} + +GlyphEditorWidget::GlyphEditorWidget(Font& mutable_font, GWidget* parent) + : GWidget(parent) + , m_font(mutable_font) +{ + set_relative_rect({ 0, 0, preferred_width(), preferred_height() }); +} + +GlyphEditorWidget::~GlyphEditorWidget() +{ +} + +void GlyphEditorWidget::set_glyph(byte glyph) +{ + if (m_glyph == glyph) + return; + m_glyph = glyph; + update(); +} + +void GlyphEditorWidget::paint_event(GPaintEvent&) +{ + Painter painter(*this); + painter.fill_rect(rect(), Color::White); + painter.draw_rect(rect(), Color::Black); + + for (int y = 0; y < font().glyph_height(); ++y) + painter.draw_line({ 0, y * m_scale }, { font().glyph_width() * m_scale, y * m_scale }, Color::Black); + + for (int x = 0; x < font().glyph_width(); ++x) + painter.draw_line({ x * m_scale, 0 }, { x * m_scale, font().glyph_height() * m_scale }, Color::Black); + + painter.translate(1, 1); + + auto bitmap = font().glyph_bitmap(m_glyph); + + for (int y = 0; y < font().glyph_height(); ++y) { + for (int x = 0; x < font().glyph_width(); ++x) { + Rect rect { x * m_scale, y * m_scale, m_scale, m_scale }; + if (bitmap.bit_at(x, y)) + painter.fill_rect(rect, Color::Black); + } + } + + if (is_focused()) { + painter.translate(-1, -1); + painter.draw_focus_rect(rect()); + } +} + +void GlyphEditorWidget::mousedown_event(GMouseEvent& event) +{ + draw_at_mouse(event); +} + +void GlyphEditorWidget::mousemove_event(GMouseEvent& event) +{ + if (event.buttons() & (GMouseButton::Left | GMouseButton::Right)) + draw_at_mouse(event); +} + +void GlyphEditorWidget::draw_at_mouse(const GMouseEvent& event) +{ + bool set = event.buttons() & GMouseButton::Left; + bool unset = event.buttons() & GMouseButton::Right; + if (!(set ^ unset)) + return; + int x = (event.x() - 1) / m_scale; + int y = (event.y() - 1) / m_scale; + auto bitmap = font().glyph_bitmap(m_glyph); + ASSERT((unsigned)x < bitmap.width()); + ASSERT((unsigned)y < bitmap.height()); + if (bitmap.bit_at(x, y) == set) + return; + bitmap.set_bit_at(x, y, set); + if (on_glyph_altered) + on_glyph_altered(); + update(); +} + +int GlyphEditorWidget::preferred_width() const +{ + return font().glyph_width() * m_scale + 1; +} + +int GlyphEditorWidget::preferred_height() const +{ + return font().glyph_height() * m_scale + 1; +} |