Added lasso select tool

This commit is contained in:
Yousef Khadadeh 2025-08-02 12:31:16 +03:00
parent d6d51129ed
commit a4ba969e11
7 changed files with 721 additions and 29 deletions

View file

@ -21,9 +21,13 @@
#include <include/core/SkSurface.h>
#include "../World.hpp"
#include "../MainProgram.hpp"
#include "LassoSelectTool.hpp"
#include <Helpers/Logger.hpp>
#include <Helpers/Parallel.hpp>
#include <cereal/types/unordered_set.hpp>
#include <include/core/SkPathEffect.h>
#include <include/effects/SkDashPathEffect.h>
#include <chrono>
DrawingProgram::DrawingProgram(World& initWorld):
world(initWorld),
@ -32,6 +36,7 @@ DrawingProgram::DrawingProgram(World& initWorld):
brushTool(*this),
eraserTool(*this),
rectSelectTool(*this),
lassoSelectTool(*this),
rectDrawTool(*this),
ellipseDrawTool(*this),
textBoxTool(*this),
@ -200,6 +205,7 @@ void DrawingProgram::toolbar_gui() {
if(t.gui.svg_icon_button("Ellipse Toolbar Button", "data/icons/circle.svg", controls.selectedTool == TOOL_ELLIPSE)) { controls.selectedTool = TOOL_ELLIPSE; }
if(t.gui.svg_icon_button("Rect Toolbar Button", "data/icons/rectangle.svg", controls.selectedTool == TOOL_RECTANGLE)) { controls.selectedTool = TOOL_RECTANGLE; }
if(t.gui.svg_icon_button("RectSelect Toolbar Button", "data/icons/rectselect.svg", controls.selectedTool == TOOL_RECTSELECT)) { controls.selectedTool = TOOL_RECTSELECT; }
if(t.gui.svg_icon_button("LassoSelect Toolbar Button", "data/icons/close.svg", controls.selectedTool == TOOL_LASSOSELECT)) { controls.selectedTool = TOOL_LASSOSELECT; }
if(t.gui.svg_icon_button("Edit Toolbar Button", "data/icons/cursor.svg", controls.selectedTool == TOOL_EDIT)) { controls.selectedTool = TOOL_EDIT; }
if(t.gui.svg_icon_button("Inkdropper Toolbar Button", "data/icons/eyedropper.svg", controls.selectedTool == TOOL_INKDROPPER)) { controls.selectedTool = TOOL_INKDROPPER; }
if(t.gui.svg_icon_button("Screenshot Toolbar Button", "data/icons/camera.svg", controls.selectedTool == TOOL_SCREENSHOT)) { controls.selectedTool = TOOL_SCREENSHOT; }
@ -238,6 +244,9 @@ void DrawingProgram::tool_options_gui() {
case TOOL_ERASER:
eraserTool.gui_toolbox();
break;
case TOOL_LASSOSELECT:
lassoSelectTool.gui_toolbox();
break;
case TOOL_RECTSELECT:
rectSelectTool.gui_toolbox();
break;
@ -259,8 +268,6 @@ void DrawingProgram::tool_options_gui() {
case TOOL_EDIT:
editTool.gui_toolbox();
break;
default:
break;
}
}
}
@ -335,6 +342,9 @@ void DrawingProgram::update() {
case TOOL_ERASER:
eraserTool.tool_update();
break;
case TOOL_LASSOSELECT:
lassoSelectTool.tool_update();
break;
case TOOL_RECTSELECT:
rectSelectTool.tool_update();
break;
@ -356,8 +366,6 @@ void DrawingProgram::update() {
case TOOL_EDIT:
editTool.tool_update();
break;
default:
break;
};
if(controls.leftClickReleased)
@ -382,6 +390,8 @@ bool DrawingProgram::prevent_undo_or_redo() {
return brushTool.prevent_undo_or_redo();
case TOOL_ERASER:
return eraserTool.prevent_undo_or_redo();
case TOOL_LASSOSELECT:
return lassoSelectTool.prevent_undo_or_redo();
case TOOL_RECTSELECT:
return rectSelectTool.prevent_undo_or_redo();
case TOOL_RECTANGLE:
@ -396,12 +406,24 @@ bool DrawingProgram::prevent_undo_or_redo() {
return screenshotTool.prevent_undo_or_redo();
case TOOL_EDIT:
return editTool.prevent_undo_or_redo();
default:
break;
};
return false;
}
SkPaint DrawingProgram::select_tool_line_paint() {
SkScalar intervals[] = {10, 5};
float timeSinceEpoch = std::chrono::duration_cast<std::chrono::duration<float>>(std::chrono::steady_clock::now().time_since_epoch()).count();
sk_sp<SkPathEffect> lassoLineDashEffect = SkDashPathEffect::Make(intervals, 2, -std::fmod(timeSinceEpoch * 50, 15));
SkPaint selectLinePaint;
selectLinePaint.setStyle(SkPaint::kStroke_Style);
selectLinePaint.setStrokeWidth(3);
selectLinePaint.setColor4f(world.canvasTheme.toolFrontColor);
selectLinePaint.setPathEffect(lassoLineDashEffect);
return selectLinePaint;
}
void DrawingProgram::force_rebuild_cache() {
if(controls.selectedTool == TOOL_ERASER)
compCache.test_rebuild_dont_include_set_dont_include_nodes(components.client_list(), eraserTool.erasedComponents, eraserTool.erasedBVHNodes, true);
@ -477,6 +499,7 @@ void DrawingProgram::add_file_to_canvas_by_data(const std::string& fileName, std
}
void DrawingProgram::reset_tools() {
lassoSelectTool.reset_tool();
rectSelectTool.reset_tool();
textBoxTool.reset_tool();
brushTool.reset_tool();
@ -689,6 +712,9 @@ void DrawingProgram::draw(SkCanvas* canvas, const DrawData& drawData) {
case TOOL_ERASER:
eraserTool.draw(canvas, drawData);
break;
case TOOL_LASSOSELECT:
lassoSelectTool.draw(canvas, drawData);
break;
case TOOL_RECTSELECT:
rectSelectTool.draw(canvas, drawData);
break;
@ -710,8 +736,6 @@ void DrawingProgram::draw(SkCanvas* canvas, const DrawData& drawData) {
case TOOL_EDIT:
editTool.draw(canvas, drawData);
break;
default:
break;
}
}

View file

@ -12,6 +12,7 @@
#include "BrushTool.hpp"
#include "EraserTool.hpp"
#include "RectSelectTool.hpp"
#include "LassoSelectTool.hpp"
#include "RectDrawTool.hpp"
#include "EllipseDrawTool.hpp"
#include "TextBoxTool.hpp"
@ -84,9 +85,13 @@ class DrawingProgram {
void add_undo_place_components(const std::unordered_set<CollabListType::ObjectInfoPtr>& objSetToUndo);
void add_undo_erase_components(const std::unordered_set<CollabListType::ObjectInfoPtr>& objSetToUndo);
SkPaint select_tool_line_paint();
BrushTool brushTool;
EraserTool eraserTool;
RectSelectTool rectSelectTool;
LassoSelectTool lassoSelectTool;
RectDrawTool rectDrawTool;
EllipseDrawTool ellipseDrawTool;
TextBoxTool textBoxTool;
@ -102,6 +107,7 @@ class DrawingProgram {
enum Tool : int {
TOOL_BRUSH = 0,
TOOL_ERASER,
TOOL_LASSOSELECT,
TOOL_RECTSELECT,
TOOL_RECTANGLE,
TOOL_ELLIPSE,
@ -142,4 +148,5 @@ class DrawingProgram {
friend class ImageTool;
friend class DrawingProgramCache;
friend class DrawingProgramSelection;
friend class LassoSelectTool;
};

View file

@ -0,0 +1,90 @@
#include "LassoSelectTool.hpp"
#include "DrawingProgram.hpp"
#include "../MainProgram.hpp"
#include "../DrawData.hpp"
#include "Helpers/MathExtras.hpp"
#include "Helpers/SCollision.hpp"
#include "../CoordSpaceHelper.hpp"
#include <ranges>
#include <delaunator.hpp>
LassoSelectTool::LassoSelectTool(DrawingProgram& initDrawP):
drawP(initDrawP)
{
}
void LassoSelectTool::gui_toolbox() {
drawP.world.main.toolbar.gui.text_label_centered("Lasso Select");
}
void LassoSelectTool::reset_tool() {
drawP.selection.deselect_all();
controls = LassoSelectControls();
}
void LassoSelectTool::tool_update() {
switch(controls.selectionMode) {
case 0: {
if(drawP.controls.leftClick) {
if(drawP.selection.is_something_selected()) {
if(!drawP.selection.mouse_collided_with_selection())
reset_tool();
}
else {
reset_tool();
controls.coords = drawP.world.drawData.cam.c;
controls.lassoPoints.emplace_back(controls.coords.get_mouse_pos(drawP.world));
controls.selectionMode = 1;
}
}
break;
}
case 1: {
using namespace SCollision;
Vector2f newLassoPoint = controls.coords.get_mouse_pos(drawP.world);
if(vec_distance(controls.lassoPoints.back(), newLassoPoint)) {
controls.lassoPoints.emplace_back(newLassoPoint);
}
if(!drawP.controls.leftClickHeld) {
std::vector<double> dCoords;
for(Vector2f& lassoPoint : controls.lassoPoints) {
dCoords.emplace_back(lassoPoint.x());
dCoords.emplace_back(lassoPoint.y());
}
delaunator::Delaunator d(dCoords);
ColliderCollection<float> cC;
for(size_t i = 0; i < d.triangles.size(); i += 3) {
SCollision::Triangle tri{
Vector2f{dCoords[2 * d.triangles[i]], dCoords[2 * d.triangles[i] + 1]},
Vector2f{dCoords[2 * d.triangles[i + 1]], dCoords[2 * d.triangles[i + 1] + 1]},
Vector2f{dCoords[2 * d.triangles[i + 2]], dCoords[2 * d.triangles[i + 2] + 1]}
};
cC.triangle.emplace_back(tri);
}
drawP.selection.add_from_cam_coord_collider_to_selection(cC);
controls.selectionMode = 0;
}
break;
}
}
}
bool LassoSelectTool::prevent_undo_or_redo() {
return drawP.selection.is_something_selected() || controls.selectionMode == 1;
}
void LassoSelectTool::draw(SkCanvas* canvas, const DrawData& drawData) {
if(controls.selectionMode == 1) {
canvas->save();
controls.coords.transform_sk_canvas(canvas, drawData);
SkPath lassoPath;
lassoPath.moveTo(convert_vec2<SkPoint>(controls.lassoPoints.front()));
for(Vector2f& p : controls.lassoPoints | std::views::drop(1))
lassoPath.lineTo(convert_vec2<SkPoint>(p));
canvas->drawPath(lassoPath, drawP.select_tool_line_paint());
canvas->restore();
}
}

View file

@ -0,0 +1,29 @@
#pragma once
#include <include/core/SkCanvas.h>
#include "../DrawData.hpp"
#include <Helpers/SCollision.hpp>
#include "../CoordSpaceHelper.hpp"
#include "../DrawComponents/DrawComponent.hpp"
class DrawingProgram;
class LassoSelectTool {
public:
LassoSelectTool(DrawingProgram& initDrawP);
void gui_toolbox();
void tool_update();
void draw(SkCanvas* canvas, const DrawData& drawData);
void reset_tool();
bool prevent_undo_or_redo();
private:
struct LassoSelectControls {
int selectionMode = 0;
CoordSpaceHelper coords;
std::vector<Vector2f> lassoPoints;
} controls;
DrawingProgram& drawP;
};

View file

@ -1,27 +1,10 @@
#include "RectSelectTool.hpp"
#include <chrono>
#include "DrawingProgram.hpp"
#include "../Server/CommandList.hpp"
#include "../MainProgram.hpp"
#include "../DrawData.hpp"
#include "Helpers/FixedPoint.hpp"
#include "Helpers/MathExtras.hpp"
#include "Helpers/SCollision.hpp"
#include "Helpers/Serializers.hpp"
#include "../CoordSpaceHelper.hpp"
#include <cereal/types/vector.hpp>
#include <algorithm>
#include <ranges>
#ifdef USE_SKIA_BACKEND_GRAPHITE
#include <include/gpu/graphite/Surface.h>
#elif USE_SKIA_BACKEND_GANESH
#include <include/gpu/ganesh/GrDirectContext.h>
#include <include/gpu/ganesh/SkSurfaceGanesh.h>
#endif
#define ROTATION_POINT_RADIUS_MULTIPLIER 0.7
#define ROTATION_POINTS_DISTANCE 20.0
RectSelectTool::RectSelectTool(DrawingProgram& initDrawP):
drawP(initDrawP)
@ -83,11 +66,8 @@ void RectSelectTool::draw(SkCanvas* canvas, const DrawData& drawData) {
canvas->save();
controls.coords.transform_sk_canvas(canvas, drawData);
SkPaint selectionPaint;
selectionPaint.setColor4f({0.3f, 0.6f, 0.9f, 0.4f});
SkRect r = SkRect::MakeLTRB(controls.newT[0].x(), controls.newT[0].y(), controls.newT[2].x(), controls.newT[2].y());
canvas->drawRect(r, selectionPaint);
canvas->drawRect(r, drawP.select_tool_line_paint());
canvas->restore();
canvas->restore();