2026-05-11 23:06:39 +03:00
|
|
|
/*
|
|
|
|
|
* InfiniPaint
|
|
|
|
|
* Copyright (C) 2025-2026 Yousef Khadadeh
|
|
|
|
|
*
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2025-08-02 12:31:16 +03:00
|
|
|
#include "LassoSelectTool.hpp"
|
2025-12-26 10:40:58 +03:00
|
|
|
#include "../DrawingProgram.hpp"
|
|
|
|
|
#include "../../MainProgram.hpp"
|
|
|
|
|
#include "../../DrawData.hpp"
|
2025-08-02 20:10:33 +03:00
|
|
|
#include "DrawingProgramToolBase.hpp"
|
2025-08-02 12:31:16 +03:00
|
|
|
#include "Helpers/MathExtras.hpp"
|
|
|
|
|
#include "Helpers/SCollision.hpp"
|
2025-12-26 10:40:58 +03:00
|
|
|
#include "../../CoordSpaceHelper.hpp"
|
2025-08-02 12:31:16 +03:00
|
|
|
#include <ranges>
|
2025-11-18 18:15:50 +03:00
|
|
|
#include <include/core/SkPathBuilder.h>
|
2026-05-23 18:27:45 +03:00
|
|
|
#include "../../EarcutIncludes.hpp"
|
2025-08-02 14:42:53 +03:00
|
|
|
|
2026-03-30 12:32:41 +03:00
|
|
|
#include "../../GUIStuff/ElementHelpers/TextLabelHelpers.hpp"
|
|
|
|
|
|
2025-08-02 12:31:16 +03:00
|
|
|
LassoSelectTool::LassoSelectTool(DrawingProgram& initDrawP):
|
2025-08-02 20:10:33 +03:00
|
|
|
DrawingProgramToolBase(initDrawP)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
DrawingProgramToolType LassoSelectTool::get_type() {
|
|
|
|
|
return DrawingProgramToolType::LASSOSELECT;
|
2025-08-02 12:31:16 +03:00
|
|
|
}
|
|
|
|
|
|
2026-04-12 12:36:00 +03:00
|
|
|
void LassoSelectTool::gui_toolbox(Toolbar& t) {
|
2026-03-31 13:17:58 +03:00
|
|
|
auto& gui = drawP.world.main.g.gui;
|
|
|
|
|
gui.new_id("lasso select tool", [&] {
|
|
|
|
|
GUIStuff::ElementHelpers::text_label_centered(gui, "Lasso Select");
|
2026-04-12 12:36:00 +03:00
|
|
|
drawP.selection.selection_gui(t);
|
2026-03-30 18:51:14 +03:00
|
|
|
});
|
2025-08-02 12:31:16 +03:00
|
|
|
}
|
|
|
|
|
|
2026-04-30 12:09:03 +03:00
|
|
|
void LassoSelectTool::gui_phone_toolbox(PhoneDrawingProgramScreen& t) {
|
|
|
|
|
auto& gui = drawP.world.main.g.gui;
|
|
|
|
|
gui.new_id("lasso select tool", [&] {
|
|
|
|
|
drawP.selection.phone_selection_gui(t);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-12 12:36:00 +03:00
|
|
|
void LassoSelectTool::right_click_popup_gui(Toolbar& t, Vector2f popupPos) {
|
2026-03-30 12:32:41 +03:00
|
|
|
drawP.selection_action_menu(popupPos);
|
2025-12-01 17:33:14 +03:00
|
|
|
}
|
|
|
|
|
|
2026-03-02 16:36:34 +03:00
|
|
|
void LassoSelectTool::input_key_callback(const InputManager::KeyCallbackArgs& key) {
|
|
|
|
|
drawP.selection.input_key_callback_modify_selection(key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LassoSelectTool::input_mouse_button_on_canvas_callback(const InputManager::MouseButtonCallbackArgs& button) {
|
|
|
|
|
drawP.selection.input_mouse_button_on_canvas_callback_modify_selection(button);
|
2026-03-31 18:41:19 +03:00
|
|
|
if(!controls.isSelecting && button.button == InputManager::MouseButton::LEFT && button.down && !drawP.selection.is_being_transformed() && !drawP.world.main.g.gui.cursor_obstructed()) {
|
2026-03-02 16:36:34 +03:00
|
|
|
controls = LassoSelectControls();
|
|
|
|
|
controls.coords = drawP.world.drawData.cam.c;
|
|
|
|
|
controls.lassoPoints.emplace_back(controls.coords.get_mouse_pos(drawP.world));
|
|
|
|
|
controls.isSelecting = true;
|
|
|
|
|
}
|
2026-03-02 23:09:48 +03:00
|
|
|
else if(controls.isSelecting && button.button == InputManager::MouseButton::LEFT && !button.down) {
|
2026-03-02 16:36:34 +03:00
|
|
|
if(controls.lassoPoints.size() > 3) {
|
2026-05-24 11:58:52 +03:00
|
|
|
SkPathBuilder cCBuild;
|
2026-03-02 16:36:34 +03:00
|
|
|
|
2026-05-24 11:58:52 +03:00
|
|
|
cCBuild.moveTo(convert_vec2<SkPoint>(controls.coords.from_this_to_cam_space(drawP.world, controls.lassoPoints[0])));
|
|
|
|
|
for(size_t i = 1; i < controls.lassoPoints.size(); i++)
|
|
|
|
|
cCBuild.lineTo(convert_vec2<SkPoint>(controls.coords.from_this_to_cam_space(drawP.world, controls.lassoPoints[i])));
|
|
|
|
|
cCBuild.close();
|
2026-03-02 16:36:34 +03:00
|
|
|
|
2026-05-24 11:58:52 +03:00
|
|
|
SkPath cC = cCBuild.detach();
|
2026-03-02 16:36:34 +03:00
|
|
|
|
|
|
|
|
if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held)
|
|
|
|
|
drawP.selection.add_from_cam_coord_collider_to_selection(cC, drawP.controls.layerSelector, false);
|
|
|
|
|
else if(drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held)
|
|
|
|
|
drawP.selection.remove_from_cam_coord_collider_to_selection(cC, drawP.controls.layerSelector, false);
|
|
|
|
|
else {
|
|
|
|
|
drawP.selection.deselect_all();
|
|
|
|
|
drawP.selection.add_from_cam_coord_collider_to_selection(cC, drawP.controls.layerSelector, false);
|
|
|
|
|
}
|
|
|
|
|
controls.lassoPoints.clear();
|
|
|
|
|
}
|
|
|
|
|
else if(!drawP.world.main.input.key(InputManager::KEY_GENERIC_LSHIFT).held && !drawP.world.main.input.key(InputManager::KEY_GENERIC_LALT).held) {
|
|
|
|
|
drawP.selection.deselect_all();
|
|
|
|
|
}
|
|
|
|
|
controls.isSelecting = false;
|
2026-04-04 20:55:19 +03:00
|
|
|
drawP.world.main.g.gui.set_to_layout();
|
2026-03-02 16:36:34 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LassoSelectTool::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) {
|
|
|
|
|
if(controls.isSelecting) {
|
2026-03-03 10:18:47 +03:00
|
|
|
Vector2f newLassoPoint = controls.coords.from_cam_space_to_this(drawP.world, motion.pos);
|
2026-03-02 16:36:34 +03:00
|
|
|
float lassoPointDist = vec_distance(controls.lassoPoints.back(), newLassoPoint);
|
|
|
|
|
if(lassoPointDist > 4.0f)
|
|
|
|
|
controls.lassoPoints.emplace_back(newLassoPoint);
|
|
|
|
|
}
|
|
|
|
|
drawP.selection.input_mouse_motion_callback_modify_selection(motion);
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-18 11:40:29 +03:00
|
|
|
Vector4f* LassoSelectTool::color_picker_color(Vector4f* oldColor) {
|
|
|
|
|
return drawP.selection.color_picker_color(oldColor);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-30 19:46:08 +03:00
|
|
|
void LassoSelectTool::erase_component(CanvasComponentContainer::ObjInfo* erasedComp) {
|
2025-12-15 15:36:42 +03:00
|
|
|
}
|
|
|
|
|
|
2025-08-02 20:39:21 +03:00
|
|
|
void LassoSelectTool::switch_tool(DrawingProgramToolType newTool) {
|
2025-12-29 15:04:32 +03:00
|
|
|
if(!drawP.is_selection_allowing_tool(newTool))
|
|
|
|
|
drawP.selection.deselect_all();
|
2025-08-02 12:31:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LassoSelectTool::tool_update() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool LassoSelectTool::prevent_undo_or_redo() {
|
2026-03-02 16:36:34 +03:00
|
|
|
return drawP.selection.is_something_selected() || controls.isSelecting;
|
2025-08-02 12:31:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LassoSelectTool::draw(SkCanvas* canvas, const DrawData& drawData) {
|
2026-03-02 16:36:34 +03:00
|
|
|
if(controls.isSelecting) {
|
2025-08-02 12:31:16 +03:00
|
|
|
canvas->save();
|
|
|
|
|
controls.coords.transform_sk_canvas(canvas, drawData);
|
|
|
|
|
|
2025-11-18 18:15:50 +03:00
|
|
|
SkPathBuilder lassoPath;
|
2025-08-02 12:31:16 +03:00
|
|
|
lassoPath.moveTo(convert_vec2<SkPoint>(controls.lassoPoints.front()));
|
|
|
|
|
for(Vector2f& p : controls.lassoPoints | std::views::drop(1))
|
|
|
|
|
lassoPath.lineTo(convert_vec2<SkPoint>(p));
|
|
|
|
|
|
2026-04-15 20:58:25 +03:00
|
|
|
auto paintPair = drawP.select_tool_line_paint(drawData);
|
|
|
|
|
SkPath lassoPathDetach = lassoPath.detach();
|
|
|
|
|
canvas->drawPath(lassoPathDetach, paintPair.first);
|
|
|
|
|
canvas->drawPath(lassoPathDetach, paintPair.second);
|
2025-08-02 12:31:16 +03:00
|
|
|
|
|
|
|
|
canvas->restore();
|
|
|
|
|
}
|
|
|
|
|
}
|