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:
parent
7dd8f1b921
commit
83d24dcb1d
25 changed files with 302 additions and 199 deletions
|
@ -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();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 };
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"; }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue