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-08-02 14:42:53 +03:00
|
|
|
#include <earcut.hpp>
|
2025-11-18 18:15:50 +03:00
|
|
|
#include <include/core/SkPathBuilder.h>
|
2025-08-02 14:42:53 +03:00
|
|
|
|
2026-03-30 12:32:41 +03:00
|
|
|
#include "../../GUIStuff/ElementHelpers/TextLabelHelpers.hpp"
|
|
|
|
|
|
2025-08-02 14:42:53 +03:00
|
|
|
namespace mapbox {
|
|
|
|
|
namespace util {
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
struct nth<0, Vector2f> {
|
|
|
|
|
inline static auto get(const Vector2f &t) {
|
|
|
|
|
return t.x();
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
template <>
|
|
|
|
|
struct nth<1, Vector2f> {
|
|
|
|
|
inline static auto get(const Vector2f &t) {
|
|
|
|
|
return t.y();
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace util
|
|
|
|
|
} // namespace mapbox
|
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) {
|
|
|
|
|
SCollision::ColliderCollection<float> cC;
|
|
|
|
|
|
|
|
|
|
std::vector<std::vector<Vector2f>> polygon;
|
|
|
|
|
polygon.emplace_back(controls.lassoPoints);
|
|
|
|
|
auto& poly = polygon[0];
|
|
|
|
|
for(auto& v : poly)
|
2026-03-03 10:18:47 +03:00
|
|
|
v = controls.coords.from_this_to_cam_space(drawP.world, v);
|
2026-03-02 16:36:34 +03:00
|
|
|
|
|
|
|
|
std::vector<unsigned> indices = mapbox::earcut(polygon);
|
|
|
|
|
|
|
|
|
|
for(size_t i = 0; i < indices.size(); i += 3) {
|
|
|
|
|
cC.triangle.emplace_back(
|
|
|
|
|
poly[indices[i]],
|
|
|
|
|
poly[indices[i + 1]],
|
|
|
|
|
poly[indices[i + 2]]
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cC.recalculate_bounds();
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|