Pārlūkot izejas kodu

PaintBrush: Add an "ellipse tool"

The tool currently supports drawing an elliptical line of a specified
thickness. Further improvements can include adding a fill mode, and
holding down shift to draw a perfect circle.

Closes #375.
Shannon Booth 5 gadi atpakaļ
vecāks
revīzija
c85bdff57a

+ 106 - 0
Applications/PaintBrush/EllipseTool.cpp

@@ -0,0 +1,106 @@
+#include "EllipseTool.h"
+#include "PaintableWidget.h"
+#include <LibDraw/Rect.h>
+#include <LibGUI/GAction.h>
+#include <LibGUI/GMenu.h>
+#include <LibGUI/GPainter.h>
+#include <LibM/math.h>
+
+EllipseTool::EllipseTool()
+{
+}
+
+EllipseTool::~EllipseTool()
+{
+}
+
+void EllipseTool::draw_using(Painter& painter)
+{
+    auto ellipse_intersecting_rect = Rect::from_two_points(m_ellipse_start_position, m_ellipse_end_position);
+    switch (m_mode) {
+    case Mode::Outline:
+        painter.draw_ellipse_intersecting(ellipse_intersecting_rect, m_widget->color_for(m_drawing_button), m_thickness);
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+}
+
+void EllipseTool::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_ellipse_start_position = event.position();
+    m_ellipse_end_position = event.position();
+    m_widget->update();
+}
+
+void EllipseTool::on_mouseup(GMouseEvent& event)
+{
+    if (event.button() == m_drawing_button) {
+        GPainter painter(m_widget->bitmap());
+        draw_using(painter);
+        m_drawing_button = GMouseButton::None;
+        m_widget->update();
+    }
+}
+
+void EllipseTool::on_mousemove(GMouseEvent& event)
+{
+    if (m_drawing_button == GMouseButton::None)
+        return;
+
+    if (!m_widget->rect().contains(event.position()))
+        return;
+
+    m_ellipse_end_position = event.position();
+    m_widget->update();
+}
+
+void EllipseTool::on_second_paint(GPaintEvent& event)
+{
+    if (m_drawing_button == GMouseButton::None)
+        return;
+
+    GPainter painter(*m_widget);
+    painter.add_clip_rect(event.rect());
+    draw_using(painter);
+}
+
+void EllipseTool::on_keydown(GKeyEvent& event)
+{
+    if (event.key() == Key_Escape && m_drawing_button != GMouseButton::None) {
+        m_drawing_button = GMouseButton::None;
+        m_widget->update();
+        event.accept();
+    }
+}
+
+void EllipseTool::on_contextmenu(GContextMenuEvent& event)
+{
+    if (!m_context_menu) {
+        m_context_menu = GMenu::construct();
+        m_context_menu->add_action(GAction::create("Outline", [this](auto&) {
+            m_mode = Mode::Outline;
+        }));
+        m_context_menu->add_separator();
+        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());
+}

+ 36 - 0
Applications/PaintBrush/EllipseTool.h

@@ -0,0 +1,36 @@
+#pragma once
+
+#include "Tool.h"
+#include <LibDraw/Point.h>
+
+class GMenu;
+class Painter;
+
+class EllipseTool final : public Tool {
+public:
+    EllipseTool();
+    virtual ~EllipseTool() 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;
+    virtual void on_keydown(GKeyEvent&) override;
+
+private:
+    enum class Mode {
+        Outline,
+        // FIXME: Add Mode::Fill
+    };
+
+    virtual const char* class_name() const override { return "EllipseTool"; }
+    void draw_using(Painter& painter);
+
+    GMouseButton m_drawing_button { GMouseButton::None };
+    Point m_ellipse_start_position;
+    Point m_ellipse_end_position;
+    RefPtr<GMenu> m_context_menu;
+    int m_thickness { 1 };
+    Mode m_mode { Mode::Outline };
+};

+ 1 - 0
Applications/PaintBrush/Makefile

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

+ 2 - 0
Applications/PaintBrush/ToolboxWidget.cpp

@@ -1,5 +1,6 @@
 #include "ToolboxWidget.h"
 #include "BucketTool.h"
+#include "EllipseTool.h"
 #include "EraseTool.h"
 #include "LineTool.h"
 #include "PaintableWidget.h"
@@ -72,6 +73,7 @@ ToolboxWidget::ToolboxWidget(GWidget* parent)
     add_tool("Erase", "eraser", make<EraseTool>());
     add_tool("Line", "line", make<LineTool>());
     add_tool("Rectangle", "rectangle", make<RectangleTool>());
+    add_tool("Ellipse", "circle", make<EllipseTool>());
 }
 
 ToolboxWidget::~ToolboxWidget()

BIN
Base/res/icons/paintbrush/circle.png