PaintBrush: Add a "line" tool for drawing straight lines

This implements "preview" of the line by allowing tool subclasses to
hook the second_paint_event on the PaintableWidget.

Work towards #375.
This commit is contained in:
Andreas Kling 2019-11-29 22:34:08 +01:00
parent f04394b9f3
commit 4e6cd541c9
8 changed files with 137 additions and 9 deletions

View file

@ -0,0 +1,79 @@
#include "LineTool.h"
#include "PaintableWidget.h"
#include <LibGUI/GAction.h>
#include <LibGUI/GMenu.h>
#include <LibGUI/GPainter.h>
LineTool::LineTool()
{
}
LineTool::~LineTool()
{
}
void LineTool::on_mousedown(GMouseEvent& event)
{
if (event.button() != GMouseButton::Left && event.button() != GMouseButton::Right)
return;
if (m_drawing_button != GMouseButton::None)
return;
m_drawing_button = event.button();
m_line_start_position = event.position();
m_line_end_position = event.position();
m_widget->update();
}
void LineTool::on_mouseup(GMouseEvent& event)
{
if (event.button() == m_drawing_button) {
GPainter painter(m_widget->bitmap());
painter.draw_line(m_line_start_position, m_line_end_position, m_widget->color_for(m_drawing_button), m_thickness);
m_drawing_button = GMouseButton::None;
m_widget->update();
}
}
void LineTool::on_mousemove(GMouseEvent& event)
{
if (m_drawing_button == GMouseButton::None)
return;
if (!m_widget->rect().contains(event.position()))
return;
m_line_end_position = event.position();
m_widget->update();
}
void LineTool::on_second_paint(GPaintEvent& event)
{
if (m_drawing_button == GMouseButton::None)
return;
GPainter painter(*m_widget);
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);
}
void LineTool::on_contextmenu(GContextMenuEvent& event)
{
if (!m_context_menu) {
m_context_menu = make<GMenu>();
m_context_menu->add_action(GAction::create("1", [this](auto&) {
m_thickness = 1;
}));
m_context_menu->add_action(GAction::create("2", [this](auto&) {
m_thickness = 2;
}));
m_context_menu->add_action(GAction::create("3", [this](auto&) {
m_thickness = 3;
}));
m_context_menu->add_action(GAction::create("4", [this](auto&) {
m_thickness = 4;
}));
}
m_context_menu->popup(event.screen_position());
}

View file

@ -0,0 +1,27 @@
#pragma once
#include "Tool.h"
#include <LibDraw/Point.h>
class GMenu;
class LineTool final : public Tool {
public:
LineTool();
virtual ~LineTool() override;
virtual void on_mousedown(GMouseEvent&) override;
virtual void on_mousemove(GMouseEvent&) override;
virtual void on_mouseup(GMouseEvent&) override;
virtual void on_contextmenu(GContextMenuEvent&) override;
virtual void on_second_paint(GPaintEvent&) override;
private:
virtual const char* class_name() const override { return "LineTool"; }
GMouseButton m_drawing_button { GMouseButton::None };
Point m_line_start_position;
Point m_line_end_position;
OwnPtr<GMenu> m_context_menu;
int m_thickness { 1 };
};

View file

@ -6,6 +6,7 @@ OBJS = \
ToolboxWidget.o \
Tool.o \
PenTool.o \
LineTool.o \
EraseTool.o \
BucketTool.o \
ColorDialog.o \

View file

@ -46,7 +46,16 @@ Tool* PaintableWidget::tool()
return m_tool;
}
Color PaintableWidget::color_for(const GMouseEvent& event)
Color PaintableWidget::color_for(GMouseButton button) const
{
if (button == GMouseButton::Left)
return m_primary_color;
if (button == GMouseButton::Right)
return m_secondary_color;
ASSERT_NOT_REACHED();
}
Color PaintableWidget::color_for(const GMouseEvent& event) const
{
if (event.buttons() & GMouseButton::Left)
return m_primary_color;
@ -80,6 +89,13 @@ void PaintableWidget::mousemove_event(GMouseEvent& event)
GWidget::mousemove_event(event);
}
void PaintableWidget::second_paint_event(GPaintEvent& event)
{
if (m_tool)
m_tool->on_second_paint(event);
GWidget::second_paint_event(event);
}
void PaintableWidget::set_primary_color(Color color)
{
if (m_primary_color == color)

View file

@ -20,7 +20,8 @@ public:
void set_tool(Tool* tool);
Tool* tool();
Color color_for(const GMouseEvent&);
Color color_for(const GMouseEvent&) const;
Color color_for(GMouseButton) const;
void set_bitmap(const GraphicsBitmap&);
@ -32,6 +33,7 @@ public:
private:
virtual void paint_event(GPaintEvent&) override;
virtual void second_paint_event(GPaintEvent&) override;
virtual void mousedown_event(GMouseEvent&) override;
virtual void mouseup_event(GMouseEvent&) override;
virtual void mousemove_event(GMouseEvent&) override;

View file

@ -9,10 +9,11 @@ public:
virtual const char* class_name() const = 0;
virtual void on_mousedown(GMouseEvent&) { }
virtual void on_mousemove(GMouseEvent&) { }
virtual void on_mouseup(GMouseEvent&) { }
virtual void on_contextmenu(GContextMenuEvent&) { }
virtual void on_mousedown(GMouseEvent&) {}
virtual void on_mousemove(GMouseEvent&) {}
virtual void on_mouseup(GMouseEvent&) {}
virtual void on_contextmenu(GContextMenuEvent&) {}
virtual void on_second_paint(GPaintEvent&) {}
void clear() { m_widget = nullptr; }
void setup(PaintableWidget& widget) { m_widget = widget.make_weak_ptr(); }

View file

@ -1,13 +1,14 @@
#include "ToolboxWidget.h"
#include "BucketTool.h"
#include "SprayTool.h"
#include "EraseTool.h"
#include "LineTool.h"
#include "PaintableWidget.h"
#include "PenTool.h"
#include "PickerTool.h"
#include "EraseTool.h"
#include "SprayTool.h"
#include <LibDraw/PNGLoader.h>
#include <LibGUI/GBoxLayout.h>
#include <LibGUI/GButton.h>
#include <LibDraw/PNGLoader.h>
class ToolButton final : public GButton {
C_OBJECT(ToolButton)
@ -69,6 +70,7 @@ ToolboxWidget::ToolboxWidget(GWidget* parent)
add_tool("Spray", "spray", make<SprayTool>());
add_tool("Color Picker", "picker", make<PickerTool>());
add_tool("Erase", "eraser", make<EraseTool>());
add_tool("Line", "line", make<LineTool>());
}
ToolboxWidget::~ToolboxWidget()

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B