1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 08:27:45 +00:00

PaintBrush: Port all the existing toolbox tools to the Layer world :^)

Many tools are not working perfectly right yet, but we'll fix them!
This commit is contained in:
Andreas Kling 2020-05-12 23:44:46 +02:00
parent 7dd8f1b921
commit 83d24dcb1d
25 changed files with 302 additions and 199 deletions

View file

@ -25,12 +25,16 @@
*/ */
#include "BucketTool.h" #include "BucketTool.h"
#include "ImageEditor.h"
#include "Layer.h"
#include "PaintableWidget.h" #include "PaintableWidget.h"
#include <AK/Queue.h> #include <AK/Queue.h>
#include <AK/SinglyLinkedList.h> #include <AK/SinglyLinkedList.h>
#include <LibGUI/Painter.h> #include <LibGUI/Painter.h>
#include <LibGfx/Bitmap.h> #include <LibGfx/Bitmap.h>
#include <stdio.h> #include <LibGfx/Rect.h>
namespace PaintBrush {
BucketTool::BucketTool() BucketTool::BucketTool()
{ {
@ -57,7 +61,7 @@ static void flood_fill(Gfx::Bitmap& bitmap, const Gfx::Point& start_position, Co
if (bitmap.get_pixel<Gfx::BitmapFormat::RGBA32>(position.x(), position.y()) != target_color) if (bitmap.get_pixel<Gfx::BitmapFormat::RGBA32>(position.x(), position.y()) != target_color)
continue; continue;
bitmap.set_pixel<Gfx::BitmapFormat::RGBA32>(position.x(), position.y(), fill_color); bitmap.set_pixel<Gfx::BitmapFormat::RGBA32>(position.x(), position.y(), fill_color);
if (position.x() != 0) if (position.x() != 0)
@ -74,15 +78,17 @@ static void flood_fill(Gfx::Bitmap& bitmap, const Gfx::Point& start_position, Co
} }
} }
void BucketTool::on_mousedown(GUI::MouseEvent& event) void BucketTool::on_mousedown(Layer& layer, GUI::MouseEvent& event)
{ {
if (!m_widget->rect().contains(event.position())) if (!layer.rect().contains(event.position()))
return; return;
GUI::Painter painter(m_widget->bitmap()); GUI::Painter painter(layer.bitmap());
auto target_color = m_widget->bitmap().get_pixel(event.x(), event.y()); auto target_color = layer.bitmap().get_pixel(event.x(), event.y());
flood_fill(m_widget->bitmap(), event.position(), target_color, m_widget->color_for(event)); flood_fill(layer.bitmap(), event.position(), target_color, PaintableWidget::the().color_for(event));
m_editor->update();
}
m_widget->update();
} }

View file

@ -28,13 +28,17 @@
#include "Tool.h" #include "Tool.h"
namespace PaintBrush {
class BucketTool final : public Tool { class BucketTool final : public Tool {
public: public:
BucketTool(); BucketTool();
virtual ~BucketTool() override; virtual ~BucketTool() override;
virtual void on_mousedown(GUI::MouseEvent&) override; virtual void on_mousedown(Layer&, GUI::MouseEvent&) override;
private: private:
virtual const char* class_name() const override { return "BucketTool"; } virtual const char* class_name() const override { return "BucketTool"; }
}; };
}

View file

@ -25,6 +25,8 @@
*/ */
#include "EllipseTool.h" #include "EllipseTool.h"
#include "ImageEditor.h"
#include "Layer.h"
#include "PaintableWidget.h" #include "PaintableWidget.h"
#include <LibGUI/Action.h> #include <LibGUI/Action.h>
#include <LibGUI/Menu.h> #include <LibGUI/Menu.h>
@ -32,6 +34,8 @@
#include <LibGfx/Rect.h> #include <LibGfx/Rect.h>
#include <LibM/math.h> #include <LibM/math.h>
namespace PaintBrush {
EllipseTool::EllipseTool() EllipseTool::EllipseTool()
{ {
} }
@ -45,14 +49,14 @@ void EllipseTool::draw_using(GUI::Painter& painter)
auto ellipse_intersecting_rect = Gfx::Rect::from_two_points(m_ellipse_start_position, m_ellipse_end_position); auto ellipse_intersecting_rect = Gfx::Rect::from_two_points(m_ellipse_start_position, m_ellipse_end_position);
switch (m_mode) { switch (m_mode) {
case Mode::Outline: case Mode::Outline:
painter.draw_ellipse_intersecting(ellipse_intersecting_rect, m_widget->color_for(m_drawing_button), m_thickness); painter.draw_ellipse_intersecting(ellipse_intersecting_rect, PaintableWidget::the().color_for(m_drawing_button), m_thickness);
break; break;
default: default:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
} }
void EllipseTool::on_mousedown(GUI::MouseEvent& event) void EllipseTool::on_mousedown(Layer&, GUI::MouseEvent& event)
{ {
if (event.button() != GUI::MouseButton::Left && event.button() != GUI::MouseButton::Right) if (event.button() != GUI::MouseButton::Left && event.button() != GUI::MouseButton::Right)
return; return;
@ -63,29 +67,29 @@ void EllipseTool::on_mousedown(GUI::MouseEvent& event)
m_drawing_button = event.button(); m_drawing_button = event.button();
m_ellipse_start_position = event.position(); m_ellipse_start_position = event.position();
m_ellipse_end_position = event.position(); m_ellipse_end_position = event.position();
m_widget->update(); m_editor->update();
} }
void EllipseTool::on_mouseup(GUI::MouseEvent& event) void EllipseTool::on_mouseup(Layer& layer, GUI::MouseEvent& event)
{ {
if (event.button() == m_drawing_button) { if (event.button() == m_drawing_button) {
GUI::Painter painter(m_widget->bitmap()); GUI::Painter painter(layer.bitmap());
draw_using(painter); draw_using(painter);
m_drawing_button = GUI::MouseButton::None; m_drawing_button = GUI::MouseButton::None;
m_widget->update(); m_editor->update();
} }
} }
void EllipseTool::on_mousemove(GUI::MouseEvent& event) void EllipseTool::on_mousemove(Layer& layer, GUI::MouseEvent& event)
{ {
if (m_drawing_button == GUI::MouseButton::None) if (m_drawing_button == GUI::MouseButton::None)
return; return;
if (!m_widget->rect().contains(event.position())) if (!layer.rect().contains(event.position()))
return; return;
m_ellipse_end_position = event.position(); m_ellipse_end_position = event.position();
m_widget->update(); m_editor->update();
} }
void EllipseTool::on_second_paint(GUI::PaintEvent& event) void EllipseTool::on_second_paint(GUI::PaintEvent& event)
@ -93,7 +97,7 @@ void EllipseTool::on_second_paint(GUI::PaintEvent& event)
if (m_drawing_button == GUI::MouseButton::None) if (m_drawing_button == GUI::MouseButton::None)
return; return;
GUI::Painter painter(*m_widget); GUI::Painter painter(*m_editor);
painter.add_clip_rect(event.rect()); painter.add_clip_rect(event.rect());
draw_using(painter); draw_using(painter);
} }
@ -102,7 +106,7 @@ void EllipseTool::on_keydown(GUI::KeyEvent& event)
{ {
if (event.key() == Key_Escape && m_drawing_button != GUI::MouseButton::None) { if (event.key() == Key_Escape && m_drawing_button != GUI::MouseButton::None) {
m_drawing_button = GUI::MouseButton::None; m_drawing_button = GUI::MouseButton::None;
m_widget->update(); m_editor->update();
event.accept(); event.accept();
} }
} }
@ -131,3 +135,5 @@ void EllipseTool::on_contextmenu(GUI::ContextMenuEvent& event)
} }
m_context_menu->popup(event.screen_position()); m_context_menu->popup(event.screen_position());
} }
}

View file

@ -30,14 +30,16 @@
#include <LibGfx/Point.h> #include <LibGfx/Point.h>
#include <LibGUI/ActionGroup.h> #include <LibGUI/ActionGroup.h>
namespace PaintBrush {
class EllipseTool final : public Tool { class EllipseTool final : public Tool {
public: public:
EllipseTool(); EllipseTool();
virtual ~EllipseTool() override; virtual ~EllipseTool() override;
virtual void on_mousedown(GUI::MouseEvent&) override; virtual void on_mousedown(Layer&, GUI::MouseEvent&) override;
virtual void on_mousemove(GUI::MouseEvent&) override; virtual void on_mousemove(Layer&, GUI::MouseEvent&) override;
virtual void on_mouseup(GUI::MouseEvent&) override; virtual void on_mouseup(Layer&, GUI::MouseEvent&) override;
virtual void on_contextmenu(GUI::ContextMenuEvent&) override; virtual void on_contextmenu(GUI::ContextMenuEvent&) override;
virtual void on_second_paint(GUI::PaintEvent&) override; virtual void on_second_paint(GUI::PaintEvent&) override;
virtual void on_keydown(GUI::KeyEvent&) override; virtual void on_keydown(GUI::KeyEvent&) override;
@ -59,3 +61,5 @@ private:
GUI::ActionGroup m_thickness_actions; GUI::ActionGroup m_thickness_actions;
Mode m_mode { Mode::Outline }; Mode m_mode { Mode::Outline };
}; };
}

View file

@ -25,12 +25,16 @@
*/ */
#include "EraseTool.h" #include "EraseTool.h"
#include "ImageEditor.h"
#include "Layer.h"
#include "PaintableWidget.h" #include "PaintableWidget.h"
#include <LibGUI/Action.h> #include <LibGUI/Action.h>
#include <LibGUI/Menu.h> #include <LibGUI/Menu.h>
#include <LibGUI/Painter.h> #include <LibGUI/Painter.h>
#include <LibGfx/Bitmap.h> #include <LibGfx/Bitmap.h>
namespace PaintBrush {
EraseTool::EraseTool() EraseTool::EraseTool()
{ {
} }
@ -49,26 +53,26 @@ Gfx::Rect EraseTool::build_rect(const Gfx::Point& pos, const Gfx::Rect& widget_r
return Gfx::Rect(ex - eraser_radius, ey - eraser_radius, eraser_size, eraser_size).intersected(widget_rect); return Gfx::Rect(ex - eraser_radius, ey - eraser_radius, eraser_size, eraser_size).intersected(widget_rect);
} }
void EraseTool::on_mousedown(GUI::MouseEvent& event) void EraseTool::on_mousedown(Layer& layer, GUI::MouseEvent& event)
{ {
if (event.button() != GUI::MouseButton::Left && event.button() != GUI::MouseButton::Right) if (event.button() != GUI::MouseButton::Left && event.button() != GUI::MouseButton::Right)
return; return;
Gfx::Rect r = build_rect(event.position(), m_widget->bitmap().rect()); Gfx::Rect r = build_rect(event.position(), layer.rect());
GUI::Painter painter(m_widget->bitmap()); GUI::Painter painter(layer.bitmap());
painter.clear_rect(r, get_color()); painter.clear_rect(r, get_color());
m_widget->update(); m_editor->update();
} }
void EraseTool::on_mousemove(GUI::MouseEvent& event) void EraseTool::on_mousemove(Layer& layer, GUI::MouseEvent& event)
{ {
if (!m_widget->rect().contains(event.position())) if (!m_editor->rect().contains(event.position()))
return; return;
if (event.buttons() & GUI::MouseButton::Left || event.buttons() & GUI::MouseButton::Right) { if (event.buttons() & GUI::MouseButton::Left || event.buttons() & GUI::MouseButton::Right) {
Gfx::Rect r = build_rect(event.position(), m_widget->bitmap().rect()); Gfx::Rect r = build_rect(event.position(), layer.rect());
GUI::Painter painter(m_widget->bitmap()); GUI::Painter painter(layer.bitmap());
painter.clear_rect(r, get_color()); painter.clear_rect(r, get_color());
m_widget->update(); m_editor->update();
} }
} }
@ -106,6 +110,8 @@ void EraseTool::on_contextmenu(GUI::ContextMenuEvent& event)
Color EraseTool::get_color() const Color EraseTool::get_color() const
{ {
if (m_use_secondary_color) if (m_use_secondary_color)
return m_widget->secondary_color(); return PaintableWidget::the().secondary_color();
return Color(255, 255, 255, 0); return Color(255, 255, 255, 0);
} }
}

View file

@ -29,18 +29,21 @@
#include "Tool.h" #include "Tool.h"
#include <LibGUI/ActionGroup.h> #include <LibGUI/ActionGroup.h>
#include <LibGfx/Point.h> #include <LibGfx/Point.h>
#include <LibGfx/Forward.h>
namespace PaintBrush {
class EraseTool final : public Tool { class EraseTool final : public Tool {
public: public:
EraseTool(); EraseTool();
virtual ~EraseTool() override; virtual ~EraseTool() override;
virtual void on_mousedown(GUI::MouseEvent&) override; virtual void on_mousedown(Layer&, GUI::MouseEvent&) override;
virtual void on_mousemove(GUI::MouseEvent&) override; virtual void on_mousemove(Layer&, GUI::MouseEvent&) override;
virtual void on_contextmenu(GUI::ContextMenuEvent&) override; virtual void on_contextmenu(GUI::ContextMenuEvent&) override;
private: private:
Color get_color() const; Gfx::Color get_color() const;
virtual const char* class_name() const override { return "EraseTool"; } virtual const char* class_name() const override { return "EraseTool"; }
Gfx::Rect build_rect(const Gfx::Point& pos, const Gfx::Rect& widget_rect); Gfx::Rect build_rect(const Gfx::Point& pos, const Gfx::Rect& widget_rect);
RefPtr<GUI::Menu> m_context_menu; RefPtr<GUI::Menu> m_context_menu;
@ -49,3 +52,5 @@ private:
int m_thickness { 1 }; int m_thickness { 1 };
GUI::ActionGroup m_thickness_actions; GUI::ActionGroup m_thickness_actions;
}; };
}

View file

@ -28,6 +28,7 @@
#include "Image.h" #include "Image.h"
#include "Layer.h" #include "Layer.h"
#include "LayerModel.h" #include "LayerModel.h"
#include "Tool.h"
#include <LibGUI/Painter.h> #include <LibGUI/Painter.h>
#include <LibGfx/Palette.h> #include <LibGfx/Palette.h>
@ -61,6 +62,43 @@ void ImageEditor::paint_event(GUI::PaintEvent& event)
} }
} }
static GUI::MouseEvent event_adjusted_for_layer(const GUI::MouseEvent& original_event, const Layer& layer)
{
auto position_in_active_layer_coordinates = original_event.position().translated(-layer.location());
dbg() << "adjusted: " << position_in_active_layer_coordinates;
return {
static_cast<GUI::Event::Type>(original_event.type()),
position_in_active_layer_coordinates, original_event.buttons(),
original_event.button(),
original_event.modifiers(),
original_event.wheel_delta()
};
}
void ImageEditor::mousedown_event(GUI::MouseEvent& event)
{
if (!m_active_layer || !m_active_tool)
return;
auto layer_event = event_adjusted_for_layer(event, *m_active_layer);
m_active_tool->on_mousedown(*m_active_layer, layer_event);
}
void ImageEditor::mousemove_event(GUI::MouseEvent& event)
{
if (!m_active_layer || !m_active_tool)
return;
auto layer_event = event_adjusted_for_layer(event, *m_active_layer);
m_active_tool->on_mousemove(*m_active_layer, layer_event);
}
void ImageEditor::mouseup_event(GUI::MouseEvent& event)
{
if (!m_active_layer || !m_active_tool)
return;
auto layer_event = event_adjusted_for_layer(event, *m_active_layer);
m_active_tool->on_mouseup(*m_active_layer, layer_event);
}
void ImageEditor::set_active_layer(Layer* layer) void ImageEditor::set_active_layer(Layer* layer)
{ {
if (m_active_layer == layer) if (m_active_layer == layer)
@ -69,4 +107,18 @@ void ImageEditor::set_active_layer(Layer* layer)
update(); update();
} }
void ImageEditor::set_active_tool(Tool* tool)
{
if (m_active_tool == tool)
return;
if (m_active_tool)
m_active_tool->clear();
m_active_tool = tool;
if (m_active_tool)
m_active_tool->setup(*this);
}
} }

View file

@ -32,6 +32,7 @@ namespace PaintBrush {
class Image; class Image;
class Layer; class Layer;
class Tool;
class ImageEditor final : public GUI::Frame { class ImageEditor final : public GUI::Frame {
C_OBJECT(ImageEditor); C_OBJECT(ImageEditor);
@ -45,13 +46,21 @@ public:
Layer* active_layer() { return m_active_layer; } Layer* active_layer() { return m_active_layer; }
void set_active_layer(Layer*); void set_active_layer(Layer*);
Tool* active_tool() { return m_active_tool; }
void set_active_tool(Tool*);
private: private:
ImageEditor(); ImageEditor();
virtual void paint_event(GUI::PaintEvent&) override; 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;
RefPtr<Image> m_image; RefPtr<Image> m_image;
RefPtr<Layer> m_active_layer; RefPtr<Layer> m_active_layer;
Tool* m_active_tool { nullptr };
}; };
} }

View file

@ -25,12 +25,16 @@
*/ */
#include "LineTool.h" #include "LineTool.h"
#include "ImageEditor.h"
#include "Layer.h"
#include "PaintableWidget.h" #include "PaintableWidget.h"
#include <LibGUI/Action.h> #include <LibGUI/Action.h>
#include <LibGUI/Menu.h> #include <LibGUI/Menu.h>
#include <LibGUI/Painter.h> #include <LibGUI/Painter.h>
#include <LibM/math.h> #include <LibM/math.h>
namespace PaintBrush {
static Gfx::Point constrain_line_angle(const Gfx::Point& start_pos, const Gfx::Point& end_pos, float angle_increment) static Gfx::Point constrain_line_angle(const Gfx::Point& start_pos, const Gfx::Point& end_pos, float angle_increment)
{ {
float current_angle = atan2(end_pos.y() - start_pos.y(), end_pos.x() - start_pos.x()) + M_PI * 2.; float current_angle = atan2(end_pos.y() - start_pos.y(), end_pos.x() - start_pos.x()) + M_PI * 2.;
@ -52,7 +56,7 @@ LineTool::~LineTool()
{ {
} }
void LineTool::on_mousedown(GUI::MouseEvent& event) void LineTool::on_mousedown(Layer&, GUI::MouseEvent& event)
{ {
if (event.button() != GUI::MouseButton::Left && event.button() != GUI::MouseButton::Right) if (event.button() != GUI::MouseButton::Left && event.button() != GUI::MouseButton::Right)
return; return;
@ -63,25 +67,25 @@ void LineTool::on_mousedown(GUI::MouseEvent& event)
m_drawing_button = event.button(); m_drawing_button = event.button();
m_line_start_position = event.position(); m_line_start_position = event.position();
m_line_end_position = event.position(); m_line_end_position = event.position();
m_widget->update(); m_editor->update();
} }
void LineTool::on_mouseup(GUI::MouseEvent& event) void LineTool::on_mouseup(Layer& layer, GUI::MouseEvent& event)
{ {
if (event.button() == m_drawing_button) { if (event.button() == m_drawing_button) {
GUI::Painter painter(m_widget->bitmap()); GUI::Painter painter(layer.bitmap());
painter.draw_line(m_line_start_position, m_line_end_position, m_widget->color_for(m_drawing_button), m_thickness); painter.draw_line(m_line_start_position, m_line_end_position, PaintableWidget::the().color_for(m_drawing_button), m_thickness);
m_drawing_button = GUI::MouseButton::None; m_drawing_button = GUI::MouseButton::None;
m_widget->update(); m_editor->update();
} }
} }
void LineTool::on_mousemove(GUI::MouseEvent& event) void LineTool::on_mousemove(Layer&, GUI::MouseEvent& event)
{ {
if (m_drawing_button == GUI::MouseButton::None) if (m_drawing_button == GUI::MouseButton::None)
return; return;
if (!m_widget->rect().contains(event.position())) if (!m_editor->rect().contains(event.position()))
return; return;
if (!m_constrain_angle) { if (!m_constrain_angle) {
@ -90,7 +94,7 @@ void LineTool::on_mousemove(GUI::MouseEvent& event)
const float ANGLE_STEP = M_PI / 8.0f; const float ANGLE_STEP = M_PI / 8.0f;
m_line_end_position = constrain_line_angle(m_line_start_position, event.position(), ANGLE_STEP); m_line_end_position = constrain_line_angle(m_line_start_position, event.position(), ANGLE_STEP);
} }
m_widget->update(); m_editor->update();
} }
void LineTool::on_second_paint(GUI::PaintEvent& event) void LineTool::on_second_paint(GUI::PaintEvent& event)
@ -98,22 +102,26 @@ void LineTool::on_second_paint(GUI::PaintEvent& event)
if (m_drawing_button == GUI::MouseButton::None) if (m_drawing_button == GUI::MouseButton::None)
return; return;
(void)event;
#if 0
GUI::Painter painter(*m_widget); GUI::Painter painter(*m_widget);
painter.add_clip_rect(event.rect()); painter.add_clip_rect(event.rect());
painter.draw_line(m_line_start_position, m_line_end_position, m_widget->color_for(m_drawing_button), m_thickness); painter.draw_line(m_line_start_position, m_line_end_position, m_editor->color_for(m_drawing_button), m_thickness);
#endif
} }
void LineTool::on_keydown(GUI::KeyEvent& event) void LineTool::on_keydown(GUI::KeyEvent& event)
{ {
if (event.key() == Key_Escape && m_drawing_button != GUI::MouseButton::None) { if (event.key() == Key_Escape && m_drawing_button != GUI::MouseButton::None) {
m_drawing_button = GUI::MouseButton::None; m_drawing_button = GUI::MouseButton::None;
m_widget->update(); m_editor->update();
event.accept(); event.accept();
} }
if (event.key() == Key_Shift) { if (event.key() == Key_Shift) {
m_constrain_angle = true; m_constrain_angle = true;
m_widget->update(); m_editor->update();
event.accept(); event.accept();
} }
} }
@ -122,7 +130,7 @@ void LineTool::on_keyup(GUI::KeyEvent& event)
{ {
if (event.key() == Key_Shift) { if (event.key() == Key_Shift) {
m_constrain_angle = false; m_constrain_angle = false;
m_widget->update(); m_editor->update();
event.accept(); event.accept();
} }
} }
@ -147,3 +155,5 @@ void LineTool::on_contextmenu(GUI::ContextMenuEvent& event)
} }
m_context_menu->popup(event.screen_position()); m_context_menu->popup(event.screen_position());
} }
}

View file

@ -27,17 +27,19 @@
#pragma once #pragma once
#include "Tool.h" #include "Tool.h"
#include <LibGfx/Point.h>
#include <LibGUI/ActionGroup.h> #include <LibGUI/ActionGroup.h>
#include <LibGfx/Point.h>
namespace PaintBrush {
class LineTool final : public Tool { class LineTool final : public Tool {
public: public:
LineTool(); LineTool();
virtual ~LineTool() override; virtual ~LineTool() override;
virtual void on_mousedown(GUI::MouseEvent&) override; virtual void on_mousedown(Layer&, GUI::MouseEvent&) override;
virtual void on_mousemove(GUI::MouseEvent&) override; virtual void on_mousemove(Layer&, GUI::MouseEvent&) override;
virtual void on_mouseup(GUI::MouseEvent&) override; virtual void on_mouseup(Layer&, GUI::MouseEvent&) override;
virtual void on_contextmenu(GUI::ContextMenuEvent&) override; virtual void on_contextmenu(GUI::ContextMenuEvent&) override;
virtual void on_second_paint(GUI::PaintEvent&) override; virtual void on_second_paint(GUI::PaintEvent&) override;
virtual void on_keydown(GUI::KeyEvent&) override; virtual void on_keydown(GUI::KeyEvent&) override;
@ -54,3 +56,5 @@ private:
int m_thickness { 1 }; int m_thickness { 1 };
bool m_constrain_angle { false }; bool m_constrain_angle { false };
}; };
}

View file

@ -54,29 +54,6 @@ PaintableWidget::~PaintableWidget()
{ {
} }
void PaintableWidget::paint_event(GUI::PaintEvent& event)
{
GUI::Painter painter(*this);
painter.add_clip_rect(event.rect());
painter.fill_rect_with_checkerboard(m_bitmap->rect(), { 8, 8 }, palette().base().darkened(0.9), palette().base());
painter.blit({ 0, 0 }, *m_bitmap, m_bitmap->rect());
}
void PaintableWidget::set_tool(Tool* tool)
{
if (m_tool)
m_tool->clear();
m_tool = tool;
if (m_tool)
m_tool->setup(*this);
}
Tool* PaintableWidget::tool()
{
return m_tool;
}
Color PaintableWidget::color_for(GUI::MouseButton button) const Color PaintableWidget::color_for(GUI::MouseButton button) const
{ {
if (button == GUI::MouseButton::Left) if (button == GUI::MouseButton::Left)
@ -95,52 +72,6 @@ Color PaintableWidget::color_for(const GUI::MouseEvent& event) const
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
void PaintableWidget::mousedown_event(GUI::MouseEvent& event)
{
if (event.button() == GUI::MouseButton::Left || event.button() == GUI::MouseButton::Right) {
if (m_tool)
m_tool->on_mousedown(event);
}
GUI::Widget::mousedown_event(event);
}
void PaintableWidget::mouseup_event(GUI::MouseEvent& event)
{
if (event.button() == GUI::MouseButton::Left || event.button() == GUI::MouseButton::Right) {
if (m_tool)
m_tool->on_mouseup(event);
}
GUI::Widget::mouseup_event(event);
}
void PaintableWidget::mousemove_event(GUI::MouseEvent& event)
{
if (m_tool)
m_tool->on_mousemove(event);
GUI::Widget::mousemove_event(event);
}
void PaintableWidget::second_paint_event(GUI::PaintEvent& event)
{
if (m_tool)
m_tool->on_second_paint(event);
GUI::Widget::second_paint_event(event);
}
void PaintableWidget::keydown_event(GUI::KeyEvent& event)
{
if (m_tool)
m_tool->on_keydown(event);
GUI::Widget::keydown_event(event);
}
void PaintableWidget::keyup_event(GUI::KeyEvent& event)
{
if (m_tool)
m_tool->on_keyup(event);
GUI::Widget::keyup_event(event);
}
void PaintableWidget::set_primary_color(Color color) void PaintableWidget::set_primary_color(Color color)
{ {
if (m_primary_color == color) if (m_primary_color == color)

View file

@ -27,7 +27,6 @@
#pragma once #pragma once
#include <LibGUI/Widget.h> #include <LibGUI/Widget.h>
class Tool;
class PaintableWidget final : public GUI::Widget { class PaintableWidget final : public GUI::Widget {
C_OBJECT(PaintableWidget) C_OBJECT(PaintableWidget)
@ -42,9 +41,6 @@ public:
void set_primary_color(Color); void set_primary_color(Color);
void set_secondary_color(Color); void set_secondary_color(Color);
void set_tool(Tool* tool);
Tool* tool();
Color color_for(const GUI::MouseEvent&) const; Color color_for(const GUI::MouseEvent&) const;
Color color_for(GUI::MouseButton) const; Color color_for(GUI::MouseButton) const;
@ -59,19 +55,8 @@ public:
private: private:
PaintableWidget(); PaintableWidget();
virtual bool accepts_focus() const override { return true; }
virtual void paint_event(GUI::PaintEvent&) override;
virtual void second_paint_event(GUI::PaintEvent&) override;
virtual void mousedown_event(GUI::MouseEvent&) override;
virtual void mouseup_event(GUI::MouseEvent&) override;
virtual void mousemove_event(GUI::MouseEvent&) override;
virtual void keydown_event(GUI::KeyEvent&) override;
virtual void keyup_event(GUI::KeyEvent&) override;
RefPtr<Gfx::Bitmap> m_bitmap; RefPtr<Gfx::Bitmap> m_bitmap;
Color m_primary_color { Color::Black }; Color m_primary_color { Color::Black };
Color m_secondary_color { Color::White }; Color m_secondary_color { Color::White };
Tool* m_tool { nullptr };
}; };

View file

@ -25,11 +25,15 @@
*/ */
#include "PenTool.h" #include "PenTool.h"
#include "ImageEditor.h"
#include "Layer.h"
#include "PaintableWidget.h" #include "PaintableWidget.h"
#include <LibGUI/Action.h> #include <LibGUI/Action.h>
#include <LibGUI/Menu.h> #include <LibGUI/Menu.h>
#include <LibGUI/Painter.h> #include <LibGUI/Painter.h>
namespace PaintBrush {
PenTool::PenTool() PenTool::PenTool()
{ {
} }
@ -38,36 +42,36 @@ PenTool::~PenTool()
{ {
} }
void PenTool::on_mousedown(GUI::MouseEvent& event) void PenTool::on_mousedown(Layer& layer, GUI::MouseEvent& event)
{ {
if (event.button() != GUI::MouseButton::Left && event.button() != GUI::MouseButton::Right) if (event.button() != GUI::MouseButton::Left && event.button() != GUI::MouseButton::Right)
return; return;
GUI::Painter painter(m_widget->bitmap()); GUI::Painter painter(layer.bitmap());
painter.draw_line(event.position(), event.position(), m_widget->color_for(event), m_thickness); painter.draw_line(event.position(), event.position(), PaintableWidget::the().color_for(event), m_thickness);
m_widget->update(); m_editor->update();
m_last_drawing_event_position = event.position(); m_last_drawing_event_position = event.position();
} }
void PenTool::on_mouseup(GUI::MouseEvent& event) void PenTool::on_mouseup(Layer&, GUI::MouseEvent& event)
{ {
if (event.button() == GUI::MouseButton::Left || event.button() == GUI::MouseButton::Right) if (event.button() == GUI::MouseButton::Left || event.button() == GUI::MouseButton::Right)
m_last_drawing_event_position = { -1, -1 }; m_last_drawing_event_position = { -1, -1 };
} }
void PenTool::on_mousemove(GUI::MouseEvent& event) void PenTool::on_mousemove(Layer& layer, GUI::MouseEvent& event)
{ {
if (!m_widget->rect().contains(event.position())) if (!layer.rect().contains(event.position()))
return; return;
if (event.buttons() & GUI::MouseButton::Left || event.buttons() & GUI::MouseButton::Right) { if (event.buttons() & GUI::MouseButton::Left || event.buttons() & GUI::MouseButton::Right) {
GUI::Painter painter(m_widget->bitmap()); GUI::Painter painter(layer.bitmap());
if (m_last_drawing_event_position != Gfx::Point(-1, -1)) if (m_last_drawing_event_position != Gfx::Point(-1, -1))
painter.draw_line(m_last_drawing_event_position, event.position(), m_widget->color_for(event), m_thickness); painter.draw_line(m_last_drawing_event_position, event.position(), PaintableWidget::the().color_for(event), m_thickness);
else else
painter.draw_line(event.position(), event.position(), m_widget->color_for(event), m_thickness); painter.draw_line(event.position(), event.position(), PaintableWidget::the().color_for(event), m_thickness);
m_widget->update(); m_editor->update();
m_last_drawing_event_position = event.position(); m_last_drawing_event_position = event.position();
} }
@ -93,3 +97,5 @@ void PenTool::on_contextmenu(GUI::ContextMenuEvent& event)
} }
m_context_menu->popup(event.screen_position()); m_context_menu->popup(event.screen_position());
} }
}

View file

@ -30,14 +30,16 @@
#include <LibGfx/Point.h> #include <LibGfx/Point.h>
#include <LibGUI/ActionGroup.h> #include <LibGUI/ActionGroup.h>
namespace PaintBrush {
class PenTool final : public Tool { class PenTool final : public Tool {
public: public:
PenTool(); PenTool();
virtual ~PenTool() override; virtual ~PenTool() override;
virtual void on_mousedown(GUI::MouseEvent&) override; virtual void on_mousedown(Layer&, GUI::MouseEvent&) override;
virtual void on_mousemove(GUI::MouseEvent&) override; virtual void on_mousemove(Layer&, GUI::MouseEvent&) override;
virtual void on_mouseup(GUI::MouseEvent&) override; virtual void on_mouseup(Layer&, GUI::MouseEvent&) override;
virtual void on_contextmenu(GUI::ContextMenuEvent&) override; virtual void on_contextmenu(GUI::ContextMenuEvent&) override;
private: private:
@ -48,3 +50,5 @@ private:
int m_thickness { 1 }; int m_thickness { 1 };
GUI::ActionGroup m_thickness_actions; GUI::ActionGroup m_thickness_actions;
}; };
}

View file

@ -25,8 +25,12 @@
*/ */
#include "PickerTool.h" #include "PickerTool.h"
#include "Layer.h"
#include "PaintableWidget.h"
#include <LibGfx/Bitmap.h> #include <LibGfx/Bitmap.h>
namespace PaintBrush {
PickerTool::PickerTool() PickerTool::PickerTool()
{ {
} }
@ -35,14 +39,15 @@ PickerTool::~PickerTool()
{ {
} }
void PickerTool::on_mousedown(GUI::MouseEvent& event) void PickerTool::on_mousedown(Layer& layer, GUI::MouseEvent& event)
{ {
ASSERT(m_widget); if (!layer.rect().contains(event.position()))
if (!m_widget->bitmap().rect().contains(event.position()))
return; return;
auto color = m_widget->bitmap().get_pixel(event.position()); auto color = layer.bitmap().get_pixel(event.position());
if (event.button() == GUI::MouseButton::Left) if (event.button() == GUI::MouseButton::Left)
m_widget->set_primary_color(color); PaintableWidget::the().set_primary_color(color);
else if (event.button() == GUI::MouseButton::Right) else if (event.button() == GUI::MouseButton::Right)
m_widget->set_secondary_color(color); PaintableWidget::the().set_secondary_color(color);
}
} }

View file

@ -28,14 +28,18 @@
#include "Tool.h" #include "Tool.h"
namespace PaintBrush {
class PickerTool final : public Tool { class PickerTool final : public Tool {
public: public:
PickerTool(); PickerTool();
virtual ~PickerTool() override; virtual ~PickerTool() override;
virtual void on_mousedown(GUI::MouseEvent&) override; virtual void on_mousedown(Layer&, GUI::MouseEvent&) override;
private: private:
virtual const char* class_name() const override { return "PickerTool"; } virtual const char* class_name() const override { return "PickerTool"; }
}; };
}

View file

@ -25,13 +25,17 @@
*/ */
#include "RectangleTool.h" #include "RectangleTool.h"
#include "ImageEditor.h"
#include "Layer.h"
#include "PaintableWidget.h" #include "PaintableWidget.h"
#include <LibGfx/Rect.h>
#include <LibGUI/Action.h> #include <LibGUI/Action.h>
#include <LibGUI/Menu.h> #include <LibGUI/Menu.h>
#include <LibGUI/Painter.h> #include <LibGUI/Painter.h>
#include <LibGfx/Rect.h>
#include <LibM/math.h> #include <LibM/math.h>
namespace PaintBrush {
RectangleTool::RectangleTool() RectangleTool::RectangleTool()
{ {
} }
@ -45,20 +49,20 @@ void RectangleTool::draw_using(GUI::Painter& painter)
auto rect_to_draw = Gfx::Rect::from_two_points(m_rectangle_start_position, m_rectangle_end_position); auto rect_to_draw = Gfx::Rect::from_two_points(m_rectangle_start_position, m_rectangle_end_position);
switch (m_mode) { switch (m_mode) {
case Mode::Fill: case Mode::Fill:
painter.fill_rect(rect_to_draw, m_widget->color_for(m_drawing_button)); painter.fill_rect(rect_to_draw, PaintableWidget::the().color_for(m_drawing_button));
break; break;
case Mode::Outline: case Mode::Outline:
painter.draw_rect(rect_to_draw, m_widget->color_for(m_drawing_button)); painter.draw_rect(rect_to_draw, PaintableWidget::the().color_for(m_drawing_button));
break; break;
case Mode::Gradient: case Mode::Gradient:
painter.fill_rect_with_gradient(rect_to_draw, m_widget->primary_color(), m_widget->secondary_color()); painter.fill_rect_with_gradient(rect_to_draw, PaintableWidget::the().primary_color(), PaintableWidget::the().secondary_color());
break; break;
default: default:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
} }
void RectangleTool::on_mousedown(GUI::MouseEvent& event) void RectangleTool::on_mousedown(Layer&, GUI::MouseEvent& event)
{ {
if (event.button() != GUI::MouseButton::Left && event.button() != GUI::MouseButton::Right) if (event.button() != GUI::MouseButton::Left && event.button() != GUI::MouseButton::Right)
return; return;
@ -69,29 +73,29 @@ void RectangleTool::on_mousedown(GUI::MouseEvent& event)
m_drawing_button = event.button(); m_drawing_button = event.button();
m_rectangle_start_position = event.position(); m_rectangle_start_position = event.position();
m_rectangle_end_position = event.position(); m_rectangle_end_position = event.position();
m_widget->update(); m_editor->update();
} }
void RectangleTool::on_mouseup(GUI::MouseEvent& event) void RectangleTool::on_mouseup(Layer& layer, GUI::MouseEvent& event)
{ {
if (event.button() == m_drawing_button) { if (event.button() == m_drawing_button) {
GUI::Painter painter(m_widget->bitmap()); GUI::Painter painter(layer.bitmap());
draw_using(painter); draw_using(painter);
m_drawing_button = GUI::MouseButton::None; m_drawing_button = GUI::MouseButton::None;
m_widget->update(); m_editor->update();
} }
} }
void RectangleTool::on_mousemove(GUI::MouseEvent& event) void RectangleTool::on_mousemove(Layer&, GUI::MouseEvent& event)
{ {
if (m_drawing_button == GUI::MouseButton::None) if (m_drawing_button == GUI::MouseButton::None)
return; return;
if (!m_widget->rect().contains(event.position())) if (!m_editor->rect().contains(event.position()))
return; return;
m_rectangle_end_position = event.position(); m_rectangle_end_position = event.position();
m_widget->update(); m_editor->update();
} }
void RectangleTool::on_second_paint(GUI::PaintEvent& event) void RectangleTool::on_second_paint(GUI::PaintEvent& event)
@ -99,16 +103,19 @@ void RectangleTool::on_second_paint(GUI::PaintEvent& event)
if (m_drawing_button == GUI::MouseButton::None) if (m_drawing_button == GUI::MouseButton::None)
return; return;
(void)event;
#if 0
GUI::Painter painter(*m_widget); GUI::Painter painter(*m_widget);
painter.add_clip_rect(event.rect()); painter.add_clip_rect(event.rect());
draw_using(painter); draw_using(painter);
#endif
} }
void RectangleTool::on_keydown(GUI::KeyEvent& event) void RectangleTool::on_keydown(GUI::KeyEvent& event)
{ {
if (event.key() == Key_Escape && m_drawing_button != GUI::MouseButton::None) { if (event.key() == Key_Escape && m_drawing_button != GUI::MouseButton::None) {
m_drawing_button = GUI::MouseButton::None; m_drawing_button = GUI::MouseButton::None;
m_widget->update(); m_editor->update();
event.accept(); event.accept();
} }
} }
@ -129,3 +136,5 @@ void RectangleTool::on_contextmenu(GUI::ContextMenuEvent& event)
} }
m_context_menu->popup(event.screen_position()); m_context_menu->popup(event.screen_position());
} }
}

View file

@ -28,15 +28,18 @@
#include "Tool.h" #include "Tool.h"
#include <LibGfx/Point.h> #include <LibGfx/Point.h>
#include <LibGUI/Forward.h>
namespace PaintBrush {
class RectangleTool final : public Tool { class RectangleTool final : public Tool {
public: public:
RectangleTool(); RectangleTool();
virtual ~RectangleTool() override; virtual ~RectangleTool() override;
virtual void on_mousedown(GUI::MouseEvent&) override; virtual void on_mousedown(Layer&, GUI::MouseEvent&) override;
virtual void on_mousemove(GUI::MouseEvent&) override; virtual void on_mousemove(Layer&, GUI::MouseEvent&) override;
virtual void on_mouseup(GUI::MouseEvent&) override; virtual void on_mouseup(Layer&, GUI::MouseEvent&) override;
virtual void on_contextmenu(GUI::ContextMenuEvent&) override; virtual void on_contextmenu(GUI::ContextMenuEvent&) override;
virtual void on_second_paint(GUI::PaintEvent&) override; virtual void on_second_paint(GUI::PaintEvent&) override;
virtual void on_keydown(GUI::KeyEvent&) override; virtual void on_keydown(GUI::KeyEvent&) override;
@ -57,3 +60,5 @@ private:
RefPtr<GUI::Menu> m_context_menu; RefPtr<GUI::Menu> m_context_menu;
Mode m_mode { Mode::Outline }; Mode m_mode { Mode::Outline };
}; };
}

View file

@ -25,15 +25,19 @@
*/ */
#include "SprayTool.h" #include "SprayTool.h"
#include "ImageEditor.h"
#include "Layer.h"
#include "PaintableWidget.h" #include "PaintableWidget.h"
#include <AK/Queue.h> #include <AK/Queue.h>
#include <AK/SinglyLinkedList.h> #include <AK/SinglyLinkedList.h>
#include <LibGUI/Painter.h>
#include <LibGUI/Action.h> #include <LibGUI/Action.h>
#include <LibGUI/Menu.h> #include <LibGUI/Menu.h>
#include <LibGUI/Painter.h>
#include <LibGfx/Bitmap.h> #include <LibGfx/Bitmap.h>
#include <stdio.h>
#include <LibM/math.h> #include <LibM/math.h>
#include <stdio.h>
namespace PaintBrush {
SprayTool::SprayTool() SprayTool::SprayTool()
{ {
@ -55,10 +59,14 @@ static double nrand()
void SprayTool::paint_it() void SprayTool::paint_it()
{ {
GUI::Painter painter(m_widget->bitmap()); auto* layer = m_editor->active_layer();
auto& bitmap = m_widget->bitmap(); if (!layer)
return;
auto& bitmap = layer->bitmap();
GUI::Painter painter(bitmap);
ASSERT(bitmap.bpp() == 32); ASSERT(bitmap.bpp() == 32);
m_widget->update(); m_editor->update();
const double minimal_radius = 10; const double minimal_radius = 10;
const double base_radius = minimal_radius * m_thickness; const double base_radius = minimal_radius * m_thickness;
for (int i = 0; i < 100 + (nrand() * 800); i++) { for (int i = 0; i < 100 + (nrand() * 800); i++) {
@ -74,18 +82,18 @@ void SprayTool::paint_it()
} }
} }
void SprayTool::on_mousedown(GUI::MouseEvent& event) void SprayTool::on_mousedown(Layer&, GUI::MouseEvent& event)
{ {
if (!m_widget->rect().contains(event.position())) if (!m_editor->rect().contains(event.position()))
return; return;
m_color = m_widget->color_for(event); m_color = PaintableWidget::the().color_for(event);
m_last_pos = event.position(); m_last_pos = event.position();
m_timer->start(); m_timer->start();
paint_it(); paint_it();
} }
void SprayTool::on_mousemove(GUI::MouseEvent& event) void SprayTool::on_mousemove(Layer&, GUI::MouseEvent& event)
{ {
m_last_pos = event.position(); m_last_pos = event.position();
if (m_timer->is_active()) { if (m_timer->is_active()) {
@ -94,7 +102,7 @@ void SprayTool::on_mousemove(GUI::MouseEvent& event)
} }
} }
void SprayTool::on_mouseup(GUI::MouseEvent&) void SprayTool::on_mouseup(Layer&, GUI::MouseEvent&)
{ {
m_timer->stop(); m_timer->stop();
} }
@ -120,3 +128,4 @@ void SprayTool::on_contextmenu(GUI::ContextMenuEvent& event)
m_context_menu->popup(event.screen_position()); m_context_menu->popup(event.screen_position());
} }
}

View file

@ -31,14 +31,16 @@
#include <LibGUI/ActionGroup.h> #include <LibGUI/ActionGroup.h>
#include <LibGUI/Painter.h> #include <LibGUI/Painter.h>
namespace PaintBrush {
class SprayTool final : public Tool { class SprayTool final : public Tool {
public: public:
SprayTool(); SprayTool();
virtual ~SprayTool() override; virtual ~SprayTool() override;
virtual void on_mousedown(GUI::MouseEvent&) override; virtual void on_mousedown(Layer&, GUI::MouseEvent&) override;
virtual void on_mouseup(GUI::MouseEvent&) override; virtual void on_mouseup(Layer&, GUI::MouseEvent&) override;
virtual void on_mousemove(GUI::MouseEvent&) override; virtual void on_mousemove(Layer&, GUI::MouseEvent&) override;
virtual void on_contextmenu(GUI::ContextMenuEvent&) override; virtual void on_contextmenu(GUI::ContextMenuEvent&) override;
private: private:
@ -51,3 +53,5 @@ private:
GUI::ActionGroup m_thickness_actions; GUI::ActionGroup m_thickness_actions;
int m_thickness { 1 }; int m_thickness { 1 };
}; };
}

View file

@ -25,6 +25,9 @@
*/ */
#include "Tool.h" #include "Tool.h"
#include "ImageEditor.h"
namespace PaintBrush {
Tool::Tool() Tool::Tool()
{ {
@ -33,3 +36,10 @@ Tool::Tool()
Tool::~Tool() Tool::~Tool()
{ {
} }
void Tool::setup(ImageEditor& editor)
{
m_editor = editor.make_weak_ptr();
}
}

View file

@ -26,7 +26,12 @@
#pragma once #pragma once
#include "PaintableWidget.h" #include <LibGUI/Event.h>
namespace PaintBrush {
class ImageEditor;
class Layer;
class Tool { class Tool {
public: public:
@ -34,18 +39,20 @@ public:
virtual const char* class_name() const = 0; virtual const char* class_name() const = 0;
virtual void on_mousedown(GUI::MouseEvent&) {} virtual void on_mousedown(Layer&, GUI::MouseEvent&) {}
virtual void on_mousemove(GUI::MouseEvent&) {} virtual void on_mousemove(Layer&, GUI::MouseEvent&) {}
virtual void on_mouseup(GUI::MouseEvent&) {} virtual void on_mouseup(Layer&, GUI::MouseEvent&) {}
virtual void on_contextmenu(GUI::ContextMenuEvent&) {} virtual void on_contextmenu(GUI::ContextMenuEvent&) {}
virtual void on_second_paint(GUI::PaintEvent&) {} virtual void on_second_paint(GUI::PaintEvent&) {}
virtual void on_keydown(GUI::KeyEvent&) {} virtual void on_keydown(GUI::KeyEvent&) {}
virtual void on_keyup(GUI::KeyEvent&) {} virtual void on_keyup(GUI::KeyEvent&) {}
void clear() { m_widget = nullptr; } void clear() { m_editor = nullptr; }
void setup(PaintableWidget& widget) { m_widget = widget.make_weak_ptr(); } void setup(ImageEditor&);
protected: protected:
Tool(); Tool();
WeakPtr<PaintableWidget> m_widget; WeakPtr<ImageEditor> m_editor;
}; };
}

View file

@ -37,6 +37,8 @@
#include <LibGUI/BoxLayout.h> #include <LibGUI/BoxLayout.h>
#include <LibGUI/Button.h> #include <LibGUI/Button.h>
namespace PaintBrush {
class ToolButton final : public GUI::Button { class ToolButton final : public GUI::Button {
C_OBJECT(ToolButton) C_OBJECT(ToolButton)
public: public:
@ -82,11 +84,11 @@ ToolboxWidget::ToolboxWidget()
button.set_icon(Gfx::Bitmap::load_from_file(String::format("/res/icons/paintbrush/%s.png", icon_name.to_string().characters()))); button.set_icon(Gfx::Bitmap::load_from_file(String::format("/res/icons/paintbrush/%s.png", icon_name.to_string().characters())));
button.on_checked = [button = &button](auto checked) { button.on_checked = [this, button = &button](auto checked) {
if (checked) if (checked)
PaintableWidget::the().set_tool(&button->tool()); on_tool_selection(&button->tool());
else else
PaintableWidget::the().set_tool(nullptr); on_tool_selection(nullptr);
}; };
}; };
@ -103,3 +105,5 @@ ToolboxWidget::ToolboxWidget()
ToolboxWidget::~ToolboxWidget() ToolboxWidget::~ToolboxWidget()
{ {
} }
}

View file

@ -28,9 +28,19 @@
#include <LibGUI/Frame.h> #include <LibGUI/Frame.h>
namespace PaintBrush {
class Tool;
class ToolboxWidget final : public GUI::Frame { class ToolboxWidget final : public GUI::Frame {
C_OBJECT(ToolboxWidget) C_OBJECT(ToolboxWidget)
public: public:
explicit ToolboxWidget();
virtual ~ToolboxWidget() override; virtual ~ToolboxWidget() override;
Function<void(Tool*)> on_tool_selection;
private:
explicit ToolboxWidget();
}; };
}

View file

@ -67,7 +67,7 @@ int main(int argc, char** argv)
horizontal_container.set_layout<GUI::HorizontalBoxLayout>(); horizontal_container.set_layout<GUI::HorizontalBoxLayout>();
horizontal_container.layout()->set_spacing(0); horizontal_container.layout()->set_spacing(0);
horizontal_container.add<ToolboxWidget>(); auto& toolbox = horizontal_container.add<PaintBrush::ToolboxWidget>();
auto& vertical_container = horizontal_container.add<GUI::Widget>(); auto& vertical_container = horizontal_container.add<GUI::Widget>();
vertical_container.set_layout<GUI::VerticalBoxLayout>(); vertical_container.set_layout<GUI::VerticalBoxLayout>();
@ -76,6 +76,10 @@ int main(int argc, char** argv)
auto& image_editor = vertical_container.add<PaintBrush::ImageEditor>(); auto& image_editor = vertical_container.add<PaintBrush::ImageEditor>();
image_editor.set_focus(true); image_editor.set_focus(true);
toolbox.on_tool_selection = [&](auto* tool) {
image_editor.set_active_tool(tool);
};
auto& paintable_widget = vertical_container.add<PaintableWidget>(); auto& paintable_widget = vertical_container.add<PaintableWidget>();
paintable_widget.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fixed); paintable_widget.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fixed);
paintable_widget.set_preferred_size(0, 0); paintable_widget.set_preferred_size(0, 0);