2020-01-18 09:38:21 +01:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
2021-09-06 20:48:08 -04:00
|
|
|
* Copyright (c) 2021, Mustafa Quraish <mustafa@cs.toronto.edu>
|
2020-01-18 09:38:21 +01:00
|
|
|
*
|
2021-04-22 01:24:48 -07:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-01-18 09:38:21 +01:00
|
|
|
*/
|
|
|
|
|
2019-11-29 22:34:08 +01:00
|
|
|
#include "LineTool.h"
|
2020-05-12 23:44:46 +02:00
|
|
|
#include "ImageEditor.h"
|
|
|
|
#include "Layer.h"
|
2021-07-17 18:29:28 +02:00
|
|
|
#include <AK/Math.h>
|
2020-02-06 20:33:02 +01:00
|
|
|
#include <LibGUI/Action.h>
|
2021-08-02 23:07:39 +02:00
|
|
|
#include <LibGUI/BoxLayout.h>
|
|
|
|
#include <LibGUI/Label.h>
|
2020-02-06 20:33:02 +01:00
|
|
|
#include <LibGUI/Menu.h>
|
|
|
|
#include <LibGUI/Painter.h>
|
2021-08-05 19:36:38 +02:00
|
|
|
#include <LibGUI/ValueSlider.h>
|
2019-12-17 13:06:52 +01:00
|
|
|
|
2020-05-20 20:35:35 +02:00
|
|
|
namespace PixelPaint {
|
2020-05-12 23:44:46 +02:00
|
|
|
|
2021-06-11 13:27:47 +02:00
|
|
|
static Gfx::IntPoint constrain_line_angle(Gfx::IntPoint const& start_pos, Gfx::IntPoint const& end_pos, float angle_increment)
|
2019-12-17 13:06:52 +01:00
|
|
|
{
|
2021-07-17 18:29:28 +02:00
|
|
|
float current_angle = AK::atan2<float>(end_pos.y() - start_pos.y(), end_pos.x() - start_pos.x()) + float { M_PI * 2 };
|
2019-12-17 13:06:52 +01:00
|
|
|
|
2021-04-15 00:36:14 -07:00
|
|
|
float constrained_angle = ((int)((current_angle + angle_increment / 2) / angle_increment)) * angle_increment;
|
2019-12-17 13:06:52 +01:00
|
|
|
|
|
|
|
auto diff = end_pos - start_pos;
|
2021-07-17 18:29:28 +02:00
|
|
|
float line_length = AK::hypot<float>(diff.x(), diff.y());
|
2019-12-17 13:06:52 +01:00
|
|
|
|
2021-07-17 18:29:28 +02:00
|
|
|
return { start_pos.x() + (int)(AK::cos(constrained_angle) * line_length),
|
|
|
|
start_pos.y() + (int)(AK::sin(constrained_angle) * line_length) };
|
2019-12-17 13:06:52 +01:00
|
|
|
}
|
2019-11-29 22:34:08 +01:00
|
|
|
|
|
|
|
LineTool::LineTool()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
LineTool::~LineTool()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-08-25 10:07:24 +02:00
|
|
|
void LineTool::on_mousedown(Layer* layer, MouseEvent& event)
|
2019-11-29 22:34:08 +01:00
|
|
|
{
|
2021-08-25 10:07:24 +02:00
|
|
|
if (!layer)
|
|
|
|
return;
|
|
|
|
|
2021-08-25 10:06:00 +02:00
|
|
|
auto& layer_event = event.layer_event();
|
2020-05-22 14:45:14 +02:00
|
|
|
if (layer_event.button() != GUI::MouseButton::Left && layer_event.button() != GUI::MouseButton::Right)
|
2019-11-29 22:34:08 +01:00
|
|
|
return;
|
|
|
|
|
2020-02-02 15:07:41 +01:00
|
|
|
if (m_drawing_button != GUI::MouseButton::None)
|
2019-11-29 22:34:08 +01:00
|
|
|
return;
|
|
|
|
|
2020-05-22 14:45:14 +02:00
|
|
|
m_drawing_button = layer_event.button();
|
|
|
|
|
|
|
|
m_line_start_position = layer_event.position();
|
|
|
|
m_line_end_position = layer_event.position();
|
|
|
|
|
2020-05-12 23:44:46 +02:00
|
|
|
m_editor->update();
|
2019-11-29 22:34:08 +01:00
|
|
|
}
|
|
|
|
|
2021-08-25 10:07:24 +02:00
|
|
|
void LineTool::on_mouseup(Layer* layer, MouseEvent& event)
|
2019-11-29 22:34:08 +01:00
|
|
|
{
|
2021-08-25 10:07:24 +02:00
|
|
|
if (!layer)
|
|
|
|
return;
|
|
|
|
|
2021-08-25 10:06:00 +02:00
|
|
|
auto& layer_event = event.layer_event();
|
|
|
|
if (layer_event.button() == m_drawing_button) {
|
2021-08-25 10:07:24 +02:00
|
|
|
GUI::Painter painter(layer->bitmap());
|
2020-05-13 12:47:47 +02:00
|
|
|
painter.draw_line(m_line_start_position, m_line_end_position, m_editor->color_for(m_drawing_button), m_thickness);
|
2020-02-02 15:07:41 +01:00
|
|
|
m_drawing_button = GUI::MouseButton::None;
|
2021-08-25 10:07:24 +02:00
|
|
|
layer->did_modify_bitmap();
|
2020-10-17 16:47:34 +00:00
|
|
|
m_editor->did_complete_action();
|
2019-11-29 22:34:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-25 10:07:24 +02:00
|
|
|
void LineTool::on_mousemove(Layer* layer, MouseEvent& event)
|
2019-11-29 22:34:08 +01:00
|
|
|
{
|
2021-08-25 10:07:24 +02:00
|
|
|
if (!layer)
|
|
|
|
return;
|
|
|
|
|
2021-08-25 10:06:00 +02:00
|
|
|
auto& layer_event = event.layer_event();
|
2020-02-02 15:07:41 +01:00
|
|
|
if (m_drawing_button == GUI::MouseButton::None)
|
2019-11-29 22:34:08 +01:00
|
|
|
return;
|
|
|
|
|
2021-07-10 19:14:50 +02:00
|
|
|
if (layer_event.shift()) {
|
2021-04-15 00:36:14 -07:00
|
|
|
constexpr auto ANGLE_STEP = M_PI / 8;
|
2020-05-22 14:45:14 +02:00
|
|
|
m_line_end_position = constrain_line_angle(m_line_start_position, layer_event.position(), ANGLE_STEP);
|
2021-07-10 19:14:50 +02:00
|
|
|
} else {
|
|
|
|
m_line_end_position = layer_event.position();
|
2019-12-17 13:06:52 +01:00
|
|
|
}
|
2020-05-12 23:44:46 +02:00
|
|
|
m_editor->update();
|
2019-11-29 22:34:08 +01:00
|
|
|
}
|
|
|
|
|
2021-08-25 10:07:24 +02:00
|
|
|
void LineTool::on_second_paint(Layer const* layer, GUI::PaintEvent& event)
|
2019-11-29 22:34:08 +01:00
|
|
|
{
|
2021-08-25 10:07:24 +02:00
|
|
|
if (!layer || m_drawing_button == GUI::MouseButton::None)
|
2019-11-29 22:34:08 +01:00
|
|
|
return;
|
|
|
|
|
2020-05-13 13:41:12 +02:00
|
|
|
GUI::Painter painter(*m_editor);
|
2019-11-29 22:34:08 +01:00
|
|
|
painter.add_clip_rect(event.rect());
|
2021-08-25 10:07:24 +02:00
|
|
|
auto preview_start = m_editor->layer_position_to_editor_position(*layer, m_line_start_position).to_type<int>();
|
|
|
|
auto preview_end = m_editor->layer_position_to_editor_position(*layer, m_line_end_position).to_type<int>();
|
2021-09-06 20:48:08 -04:00
|
|
|
painter.draw_line(preview_start, preview_end, m_editor->color_for(m_drawing_button), m_thickness * m_editor->scale());
|
2019-11-29 22:34:08 +01:00
|
|
|
}
|
|
|
|
|
2020-02-02 15:07:41 +01:00
|
|
|
void LineTool::on_keydown(GUI::KeyEvent& event)
|
2019-11-29 22:39:23 +01:00
|
|
|
{
|
2021-09-03 01:03:15 -04:00
|
|
|
Tool::on_keydown(event);
|
2020-02-02 15:07:41 +01:00
|
|
|
if (event.key() == Key_Escape && m_drawing_button != GUI::MouseButton::None) {
|
|
|
|
m_drawing_button = GUI::MouseButton::None;
|
2020-05-12 23:44:46 +02:00
|
|
|
m_editor->update();
|
2019-11-29 22:39:23 +01:00
|
|
|
event.accept();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-02 23:07:39 +02:00
|
|
|
GUI::Widget* LineTool::get_properties_widget()
|
2019-11-29 22:34:08 +01:00
|
|
|
{
|
2021-08-02 23:07:39 +02:00
|
|
|
if (!m_properties_widget) {
|
|
|
|
m_properties_widget = GUI::Widget::construct();
|
|
|
|
m_properties_widget->set_layout<GUI::VerticalBoxLayout>();
|
|
|
|
|
|
|
|
auto& thickness_container = m_properties_widget->add<GUI::Widget>();
|
|
|
|
thickness_container.set_fixed_height(20);
|
|
|
|
thickness_container.set_layout<GUI::HorizontalBoxLayout>();
|
|
|
|
|
|
|
|
auto& thickness_label = thickness_container.add<GUI::Label>("Thickness:");
|
|
|
|
thickness_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
|
|
|
|
thickness_label.set_fixed_size(80, 20);
|
|
|
|
|
2021-08-05 19:36:38 +02:00
|
|
|
auto& thickness_slider = thickness_container.add<GUI::ValueSlider>(Orientation::Horizontal, "px");
|
2021-08-02 23:07:39 +02:00
|
|
|
thickness_slider.set_range(1, 10);
|
|
|
|
thickness_slider.set_value(m_thickness);
|
2021-08-03 12:46:10 +02:00
|
|
|
|
2021-08-02 23:07:39 +02:00
|
|
|
thickness_slider.on_change = [&](int value) {
|
|
|
|
m_thickness = value;
|
2020-01-21 13:47:57 +01:00
|
|
|
};
|
2021-09-03 01:03:15 -04:00
|
|
|
set_primary_slider(&thickness_slider);
|
2019-11-29 22:34:08 +01:00
|
|
|
}
|
2021-08-02 23:07:39 +02:00
|
|
|
|
|
|
|
return m_properties_widget.ptr();
|
2019-11-29 22:34:08 +01:00
|
|
|
}
|
2020-05-12 23:44:46 +02:00
|
|
|
|
|
|
|
}
|