Add GridModify tool, and visibility flag to grids

This commit is contained in:
Yousef Khadadeh 2025-09-10 15:03:06 +03:00
parent 2325d84c22
commit 76dcd4eac5
15 changed files with 271 additions and 16 deletions

View file

@ -66,6 +66,7 @@ set(sources "src/main.cpp"
"src/DrawingProgram/ScreenshotTool.cpp"
"src/DrawingProgram/EditTool.cpp"
"src/DrawingProgram/ImageEditTool.cpp"
"src/DrawingProgram/GridModifyTool.cpp"
"src/DrawingProgram/DrawingProgramSelection.cpp"
"src/DrawingProgram/DrawingProgramEditToolBase.cpp"
"src/DrawingProgram/DrawingProgramToolBase.cpp"

79
data/icons/eyeclose.svg Normal file
View file

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32"
height="32"
viewBox="0 0 8.4666666 8.4666666"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="eyeclosed.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
showgrid="true"
inkscape:zoom="5.7550238"
inkscape:cx="-38.748753"
inkscape:cy="-32.406469"
inkscape:window-width="3440"
inkscape:window-height="1354"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<inkscape:grid
id="grid1"
units="px"
originx="0"
originy="0"
spacingx="0.26458333"
spacingy="0.26458333"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
enabled="true"
visible="true"
dotted="true" />
</sodipodi:namedview>
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:#000000;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round"
d="m 7.6729164,4.2333329 c 0,0 -1.0583334,2.3812501 -3.4395833,2.3812501 -2.3812499,0 -3.43958308,-2.3812501 -3.43958308,-2.3812501"
id="path1-3"
sodipodi:nodetypes="csc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round"
d="M 1.8520832,5.820833 1.0583333,6.614583"
id="path1"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round"
d="m 6.614583,5.820833 0.7937499,0.79375"
id="path1-2"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round"
d="m 4.2333331,6.614583 0,1.0583333"
id="path1-35"
sodipodi:nodetypes="cc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

82
data/icons/eyeopen.svg Normal file
View file

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32"
height="32"
viewBox="0 0 8.4666666 8.4666666"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="eyeopen.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
showgrid="true"
inkscape:zoom="32.555331"
inkscape:cx="0.89079113"
inkscape:cy="13.223641"
inkscape:window-width="3440"
inkscape:window-height="1354"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<inkscape:grid
id="grid1"
units="px"
originx="0"
originy="0"
spacingx="0.26458333"
spacingy="0.26458333"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
enabled="true"
visible="true"
dotted="true" />
</sodipodi:namedview>
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:#000000;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round"
d="m 7.6729164,4.2333329 c 0,0 -1.0583334,2.3812501 -3.4395833,2.3812501 -2.3812499,0 -3.43958308,-2.3812501 -3.43958308,-2.3812501"
id="path1-3"
sodipodi:nodetypes="csc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round"
d="m 7.6729164,4.2333329 c 0,0 -1.0583334,-2.3812497 -3.4395833,-2.3812497 -2.3812499,0 -3.43958309,2.3812497 -3.43958309,2.3812497"
id="path1-3-1"
sodipodi:nodetypes="csc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round"
id="path1"
sodipodi:type="arc"
sodipodi:cx="4.2333331"
sodipodi:cy="4.2333331"
sodipodi:rx="1.0583333"
sodipodi:ry="1.0583333"
sodipodi:start="4.7354737"
sodipodi:end="4.712389"
sodipodi:open="true"
sodipodi:arc-type="arc"
d="M 4.2577623,3.1752818 A 1.0583333,1.0583333 0 0 1 5.2915078,4.2516557 1.0583333,1.0583333 0 0 1 4.2211177,5.2915959 1.0583333,1.0583333 0 0 1 3.1750175,4.2272253 1.0583333,1.0583333 0 0 1 4.2333331,3.1749998" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -6,6 +6,7 @@
#include "../DrawComponents/DrawComponent.hpp"
#include "EllipseDrawTool.hpp"
#include "EyeDropperTool.hpp"
#include "GridModifyTool.hpp"
#include "../InputManager.hpp"
#include "../SharedTypes.hpp"
#include "../Server/CommandList.hpp"
@ -231,6 +232,17 @@ void DrawingProgram::tool_options_gui() {
}
}
void DrawingProgram::modify_grid(const std::string& gridToModifyName) {
if(world.gridMan.grids.contains(gridToModifyName)) {
if(drawTool->get_type() != DrawingProgramToolType::GRIDMODIFY)
switch_to_tool(DrawingProgramToolType::GRIDMODIFY);
GridModifyTool* gridModToolPtr = static_cast<GridModifyTool*>(drawTool.get());
gridModToolPtr->set_grid_name(gridToModifyName);
}
else if(drawTool->get_type() == DrawingProgramToolType::GRIDMODIFY)
switch_to_tool(DrawingProgramToolType::EDIT);
}
void DrawingProgram::update() {
if(world.main.window.lastFrameTime > std::chrono::milliseconds(33)) { // Around 30FPS
if(!badFrametimeTimePoint)

View file

@ -55,6 +55,8 @@ class DrawingProgram {
void switch_to_tool_ptr(std::unique_ptr<DrawingProgramToolBase> newTool);
void clear_draw_cache();
void modify_grid(const std::string& gridToModifyName);
private:
std::optional<std::chrono::steady_clock::time_point> badFrametimeTimePoint;
std::optional<std::chrono::steady_clock::time_point> unorderedObjectsExistTimePoint;
@ -122,4 +124,5 @@ class DrawingProgram {
friend class DrawingProgramCache;
friend class DrawingProgramSelection;
friend class LassoSelectTool;
friend class GridEditTool;
};

View file

@ -10,6 +10,7 @@
#include "EyeDropperTool.hpp"
#include "ScreenshotTool.hpp"
#include "EditTool.hpp"
#include "GridModifyTool.hpp"
DrawingProgramToolBase::DrawingProgramToolBase(DrawingProgram& initDrawP):
drawP(initDrawP)
@ -37,6 +38,8 @@ std::unique_ptr<DrawingProgramToolBase> DrawingProgramToolBase::allocate_tool_ty
return std::make_unique<EyeDropperTool>(drawP);
case DrawingProgramToolType::SCREENSHOT:
return std::make_unique<ScreenshotTool>(drawP);
case DrawingProgramToolType::GRIDMODIFY:
return std::make_unique<GridModifyTool>(drawP);
case DrawingProgramToolType::EDIT:
return std::make_unique<EditTool>(drawP);
}

View file

@ -16,6 +16,7 @@ enum class DrawingProgramToolType : int {
TEXTBOX,
EYEDROPPER,
SCREENSHOT,
GRIDMODIFY,
EDIT
};

View file

@ -0,0 +1,38 @@
#include "GridModifyTool.hpp"
#include "DrawingProgram.hpp"
#include "../MainProgram.hpp"
#include "../DrawData.hpp"
GridModifyTool::GridModifyTool(DrawingProgram& initDrawP):
DrawingProgramToolBase(initDrawP)
{
}
void GridModifyTool::set_grid_name(const std::string& gridToModifyName) {
gridName = gridToModifyName;
}
DrawingProgramToolType GridModifyTool::get_type() {
return DrawingProgramToolType::GRIDMODIFY;
}
void GridModifyTool::gui_toolbox() {
Toolbar& t = drawP.world.main.toolbar;
t.gui.push_id("Grid modify tool");
t.gui.text_label_centered("Edit Grid");
t.gui.text_label_centered(gridName);
t.gui.pop_id();
}
void GridModifyTool::tool_update() {
}
bool GridModifyTool::prevent_undo_or_redo() {
return false;
}
void GridModifyTool::draw(SkCanvas* canvas, const DrawData& drawData) {
}
void GridModifyTool::switch_tool(DrawingProgramToolType newTool) {
}

View file

@ -0,0 +1,18 @@
#pragma once
#include "DrawingProgramToolBase.hpp"
class DrawingProgram;
class GridModifyTool : public DrawingProgramToolBase {
public:
GridModifyTool(DrawingProgram& initDrawP);
void set_grid_name(const std::string& gridToModifyName);
virtual DrawingProgramToolType get_type() override;
virtual void gui_toolbox() override;
virtual void tool_update() override;
virtual void draw(SkCanvas* canvas, const DrawData& drawData) override;
virtual bool prevent_undo_or_redo() override;
virtual void switch_tool(DrawingProgramToolType newTool) override;
private:
std::string gridName;
};

View file

@ -348,7 +348,7 @@ void GUIManager::svg_icon(const std::string& id, const std::string& svgPath, boo
pop_id();
}
bool GUIManager::svg_icon_button(const std::string& id, const std::string& svgPath, bool isSelected, float size, const std::function<void()>& elemUpdate) {
bool GUIManager::svg_icon_button(const std::string& id, const std::string& svgPath, bool isSelected, float size, bool hasBorder, const std::function<void()>& elemUpdate) {
bool toRet = false;
push_id(id);
CLAY ({.layout = {.sizing = {.width = CLAY_SIZING_FIXED(size), .height = CLAY_SIZING_FIXED(size) } } }) {
@ -356,7 +356,7 @@ bool GUIManager::svg_icon_button(const std::string& id, const std::string& svgPa
svg_icon("1", svgPath, is || s.held || s.hovered);
if(elemUpdate)
elemUpdate();
}, true, true, isSelected);
}, hasBorder, true, isSelected);
}
pop_id();
return toRet;

View file

@ -51,7 +51,7 @@ class GUIManager {
bool text_button_sized(const std::string& id, const std::string& text, Clay_SizingAxis x, Clay_SizingAxis y, bool isSelected = false, const std::function<void()>& elemUpdate = nullptr);
void svg_icon(const std::string& id, const std::string& svgPath, bool isHighlighted = false, const std::function<void()>& elemUpdate = nullptr);
bool svg_icon_button(const std::string& id, const std::string& svgPath, bool isSelected = false, float size = 40.0f, const std::function<void()>& elemUpdate = nullptr);
bool svg_icon_button(const std::string& id, const std::string& svgPath, bool isSelected = false, float size = 40.0f, bool hasBorder = true, const std::function<void()>& elemUpdate = nullptr);
void top_to_bottom_window_popup_layout(Clay_SizingAxis x, Clay_SizingAxis y, const std::function<void()>& elemUpdate);
void left_to_right_layout(Clay_SizingAxis x, Clay_SizingAxis y, const std::function<void()>& elemUpdate);

View file

@ -562,7 +562,8 @@ void Toolbar::grid_menu(bool justOpened) {
gui.text_label_centered("No grids yet...");
gui.scroll_bar_many_entries_area("grid menu entries", entryHeight, main.world->gridMan.sorted_names().size(), [&](size_t i, bool isListHovered) {
const std::string& gridName = main.world->gridMan.sorted_names()[i];
bool selectedEntry = gridName == gridMenu.currentSelectedGrid;
WorldGrid& grid = main.world->gridMan.grids[gridName];
bool selectedEntry = gridName == gridMenu.newName;
CLAY({
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(entryHeight)},
@ -573,10 +574,21 @@ void Toolbar::grid_menu(bool justOpened) {
.backgroundColor = selectedEntry ? convert_vec4<Clay_Color>(io->theme->backColor1) : convert_vec4<Clay_Color>(io->theme->backColor2)
}) {
gui.text_label(gridName);
if(Clay_Hovered() && io->mouse.leftClick && isListHovered) {
gridMenu.currentSelectedGrid = gridName;
gridMenu.newName = gridName;
bool changeHappened = false;
CLAY({
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)},
.childAlignment = {.x = CLAY_ALIGN_X_RIGHT, .y = CLAY_ALIGN_Y_CENTER},
.layoutDirection = CLAY_LEFT_TO_RIGHT
}
}) {
if(gui.svg_icon_button("visibility eye", grid.visible ? "data/icons/eyeopen.svg" : "data/icons/eyeclose.svg", false, entryHeight - 2.0f, false)) {
changeHappened = true;
grid.visible = !grid.visible;
}
}
if(Clay_Hovered() && io->mouse.leftClick && isListHovered && !changeHappened)
gridMenu.newName = gridName;
}
});
bool gridExists = std::find(main.world->gridMan.sorted_names().begin(), main.world->gridMan.sorted_names().end(), gridMenu.newName) != main.world->gridMan.sorted_names().end();
@ -615,8 +627,12 @@ void Toolbar::grid_menu(bool justOpened) {
g.gridType = static_cast<WorldGrid::GridType>(typeSelected);
}
}
if(io->mouse.leftClick && !Clay_Hovered() && !justOpened && !dropdownHover)
main.world->drawProg.modify_grid(gridMenu.newName);
if(io->mouse.leftClick && !Clay_Hovered() && !justOpened && !dropdownHover) {
main.world->drawProg.modify_grid("");
gridMenu.newName.clear();
gridMenu.popupOpen = false;
}
}
gui.pop_id();
}
@ -643,7 +659,7 @@ void Toolbar::bookmark_menu(bool justOpened) {
gui.text_label_centered("No bookmarks yet...");
gui.scroll_bar_many_entries_area("bookmark menu entries", entryHeight, main.world->bMan.sorted_names().size(), [&](size_t i, bool isListHovered) {
const std::string& bookmark = main.world->bMan.sorted_names()[i];
bool selectedEntry = bookmark == bookMenu.currentSelectedBookmark;
bool selectedEntry = bookmark == bookMenu.newName;
CLAY({
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(entryHeight)},
@ -657,10 +673,8 @@ void Toolbar::bookmark_menu(bool justOpened) {
if(Clay_Hovered() && io->mouse.leftClick && isListHovered) {
if(selectedEntry && io->mouse.leftClick >= 2)
main.world->bMan.jump_to_bookmark(bookmark);
else {
bookMenu.currentSelectedBookmark = bookmark;
else
bookMenu.newName = bookmark;
}
}
}
});
@ -680,8 +694,10 @@ void Toolbar::bookmark_menu(bool justOpened) {
main.world->bMan.add_bookmark(bookMenu.newName);
}
});
if(io->mouse.leftClick && !Clay_Hovered() && !justOpened)
if(io->mouse.leftClick && !Clay_Hovered() && !justOpened) {
bookMenu.newName.clear();
bookMenu.popupOpen = false;
}
}
gui.pop_id();
}

View file

@ -165,13 +165,11 @@ class Toolbar {
struct BookmarkMenu {
bool popupOpen = false;
std::string currentSelectedBookmark;
std::string newName;
} bookMenu;
struct GridMenu {
bool popupOpen = false;
std::string currentSelectedGrid;
std::string newName;
} gridMenu;

View file

@ -105,6 +105,9 @@ sk_sp<SkShader> WorldGrid::get_shader(GridType gType, const SkColor4f& gridColor
}
void WorldGrid::draw(GridManager& gMan, SkCanvas* canvas, const DrawData& drawData) {
if(!visible)
return;
if(!circlePointEffect) {
circlePointEffect = compile_effect_shader_init("Circle Point", circlePointShaderCode);
squarePointEffect = compile_effect_shader_init("Square Point", squarePointShaderCode);
@ -113,7 +116,7 @@ void WorldGrid::draw(GridManager& gMan, SkCanvas* canvas, const DrawData& drawDa
}
float alteredZoom = static_cast<float>(((size / WorldScalar(GRID_CACHE_SIZE_INT)) / drawData.cam.c.inverseScale));
if(alteredZoom > 0.5f) {
if(alteredZoom > 0.4f) {
Vector2f fracCamPos;
fracCamPos.x() = static_cast<float>((drawData.cam.c.pos.x() % size) / drawData.cam.c.inverseScale);

View file

@ -15,6 +15,7 @@ class WorldGrid {
RULED
} gridType = GridType::CIRCLE_POINTS;
WorldScalar size{50000000};
bool visible = true;
private:
static sk_sp<SkShader> get_shader(GridType gType, const SkColor4f& gridColor, float gridScale);
static sk_sp<SkRuntimeEffect> compile_effect_shader_init(const char* shaderName, const char* shaderCode);