Save tool configuration, and put close popup infront of other popups

This commit is contained in:
Yousef Khadadeh 2026-01-26 19:08:36 +03:00
parent 2e9e8eaf8b
commit f46d25b8e6
21 changed files with 167 additions and 68 deletions

View file

@ -59,6 +59,7 @@ set(sources "src/main.cpp"
"src/RichText/TextBox.cpp"
"src/RichText/TextStyleModifier.cpp"
"src/RichText/ParagraphStyleData.cpp"
"src/DrawingProgram/ToolConfiguration.cpp"
"src/DrawingProgram/DrawingProgramSelection.cpp"
"src/DrawingProgram/DrawingProgramCache.cpp"
"src/DrawingProgram/DrawingProgram.cpp"

View file

@ -151,10 +151,12 @@ void DrawingProgram::toolbar_gui() {
if(newRotationAngle != oldRotationAngle)
world.drawData.cam.c.rotate_about(world.drawData.cam.c.from_space(world.main.window.size.cast<float>() * 0.5f), newRotationAngle - oldRotationAngle);
if(t.gui.big_color_button("Foreground Color", &controls.foregroundColor, &controls.foregroundColor == t.colorLeft))
t.color_selector_left(&controls.foregroundColor == t.colorLeft ? nullptr : &controls.foregroundColor);
if(t.gui.big_color_button("Background Color", &controls.backgroundColor, &controls.backgroundColor == t.colorLeft))
t.color_selector_left(&controls.backgroundColor == t.colorLeft ? nullptr : &controls.backgroundColor);
auto& globalConf = world.main.toolConfig.globalConf;
if(t.gui.big_color_button("Foreground Color", &globalConf.foregroundColor, &globalConf.foregroundColor == t.colorLeft))
t.color_selector_left(&globalConf.foregroundColor == t.colorLeft ? nullptr : &globalConf.foregroundColor);
if(t.gui.big_color_button("Background Color", &globalConf.backgroundColor, &globalConf.backgroundColor == t.colorLeft))
t.color_selector_left(&globalConf.backgroundColor == t.colorLeft ? nullptr : &globalConf.backgroundColor);
}
t.gui.pop_id();
}
@ -633,5 +635,5 @@ void DrawingProgram::draw(SkCanvas* canvas, const DrawData& drawData) {
}
Vector4f* DrawingProgram::get_foreground_color_ptr() {
return &controls.foregroundColor;
return &world.main.toolConfig.globalConf.foregroundColor;
}

View file

@ -96,10 +96,6 @@ class DrawingProgram {
DrawingProgramToolType toolTypeAfterTempMove;
struct GlobalControls {
float relativeWidth = 15.0f;
Vector4f foregroundColor{1.0f, 1.0f, 1.0f, 1.0f};
Vector4f backgroundColor{0.0f, 0.0f, 0.0f, 1.0f};
WorldVec previousMouseWorldPos = {0, 0};
WorldVec currentMouseWorldPos = {0, 0};
bool leftClick = false;

View file

@ -0,0 +1,9 @@
#include "ToolConfiguration.hpp"
float ToolConfiguration::get_relative_width(float relativeWidthLocal) const {
return globalConf.useGlobalRelativeWidth ? globalConf.relativeWidth : relativeWidthLocal;
}
void ToolConfiguration::relative_width_slider(GUIStuff::GUIManager& gui, const char* label, float* relativeWidthLocal) {
gui.slider_scalar_field<float>("relstrokewidth", label, globalConf.useGlobalRelativeWidth ? &globalConf.relativeWidth : relativeWidthLocal, 3.0f, 40.0f);
}

View file

@ -0,0 +1,63 @@
#pragma once
#include "../SharedTypes.hpp"
#include "Tools/ScreenshotTool.hpp"
#include "nlohmann/json.hpp"
#include "../GUIStuff/GUIManager.hpp"
class ToolConfiguration {
public:
struct BrushToolConfig {
bool hasRoundCaps = true;
float relativeWidth = 15.0f;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(BrushToolConfig, hasRoundCaps, relativeWidth)
} brush;
struct EraserToolConfig {
float relativeWidth = 15.0f;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(EraserToolConfig, relativeWidth)
} eraser;
struct EllipseDrawToolConfig {
float relativeWidth = 15.0f;
int fillStrokeMode = 1;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(EllipseDrawToolConfig, relativeWidth, fillStrokeMode)
} ellipseDraw;
struct RectDrawToolConfig {
float relativeWidth = 15.0f;
float relativeRadiusWidth = 10.0f;
int fillStrokeMode = 1;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(RectDrawToolConfig, relativeWidth, relativeRadiusWidth, fillStrokeMode)
} rectDraw;
struct EyeDropperToolConfig {
bool selectingStrokeColor = true;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(EyeDropperToolConfig, selectingStrokeColor)
} eyeDropper;
struct LineDrawToolConfig {
bool hasRoundCaps = true;
float relativeWidth = 15.0f;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(LineDrawToolConfig, hasRoundCaps, relativeWidth)
} lineDraw;
struct ScreenshotToolConfig {
int setDimensionSize = 1000;
bool setDimensionIsX = true;
ScreenshotTool::ScreenshotType selectedType = ScreenshotTool::ScreenshotType::SCREENSHOT_JPG;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ScreenshotToolConfig, setDimensionSize, setDimensionIsX, selectedType)
} screenshot;
struct GlobalConfig {
Vector4f foregroundColor{1.0f, 1.0f, 1.0f, 1.0f};
Vector4f backgroundColor{0.0f, 0.0f, 0.0f, 1.0f};
float relativeWidth = 15.0f;
bool useGlobalRelativeWidth = false;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GlobalConfig, useGlobalRelativeWidth, foregroundColor, backgroundColor, relativeWidth)
} globalConf;
float get_relative_width(float relativeWidthLocal) const;
void relative_width_slider(GUIStuff::GUIManager& gui, const char* label, float* relativeWidthLocal);
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ToolConfiguration, brush, eraser, ellipseDraw, rectDraw, eyeDropper, lineDraw, screenshot, globalConf)
};

View file

@ -54,6 +54,8 @@ bool BrushTool::extensive_point_checking_back(const BrushStrokeCanvasComponent&
}
void BrushTool::tool_update() {
auto& toolConfig = drawP.world.main.toolConfig;
if(drawP.controls.cursorHoveringOverCanvas)
drawP.world.main.input.hideCursor = true;
@ -94,11 +96,11 @@ void BrushTool::tool_update() {
BrushStrokeCanvasComponentPoint p;
p.pos = drawP.world.main.input.mouse.pos;
p.width = drawP.controls.relativeWidth * penWidth;
p.width = toolConfig.get_relative_width(toolConfig.brush.relativeWidth) * penWidth;
prevPointUnaltered = p.pos;
newBrushStroke.d->points.emplace_back(p);
newBrushStroke.d->color = drawP.controls.foregroundColor;
newBrushStroke.d->hasRoundCaps = hasRoundCaps;
newBrushStroke.d->color = toolConfig.globalConf.foregroundColor;
newBrushStroke.d->hasRoundCaps = toolConfig.brush.hasRoundCaps;
newBrushStrokeContainer->coords = drawP.world.drawData.cam.c;
objInfoBeingEdited = drawP.layerMan.add_component_to_layer_being_edited(newBrushStrokeContainer);
addedTemporaryPoint = false;
@ -110,7 +112,7 @@ void BrushTool::tool_update() {
BrushStrokeCanvasComponentPoint p;
p.pos = containerPtr->coords.get_mouse_pos(drawP.world);
p.width = drawP.controls.relativeWidth * penWidth;
p.width = toolConfig.get_relative_width(toolConfig.brush.relativeWidth) * penWidth;
if(!addedTemporaryPoint) {
if(extensive_point_checking(brushStroke, p.pos)) {
@ -129,7 +131,7 @@ void BrushTool::tool_update() {
brushStroke.d->points.back().width = std::max(brushStroke.d->points.back().width, p.width);
brushStroke.d->points[brushStroke.d->points.size() - 2].width = std::max(brushStroke.d->points[brushStroke.d->points.size() - 2].width, p.width);
}
if((!drawingMinimumRelativeToSize && distToPrev >= 10.0) || (drawingMinimumRelativeToSize && distToPrev >= drawP.controls.relativeWidth * BrushStrokeCanvasComponent::DRAW_MINIMUM_LIMIT)) {
if((!drawingMinimumRelativeToSize && distToPrev >= 10.0) || (drawingMinimumRelativeToSize && distToPrev >= toolConfig.get_relative_width(toolConfig.brush.relativeWidth) * BrushStrokeCanvasComponent::DRAW_MINIMUM_LIMIT)) {
brushStroke.d->points.back() = p;
addedTemporaryPoint = false;
@ -163,8 +165,8 @@ void BrushTool::gui_toolbox() {
Toolbar& t = drawP.world.main.toolbar;
t.gui.push_id("brush tool");
t.gui.text_label_centered("Brush");
t.gui.checkbox_field("hasroundcaps", "Round Caps", &hasRoundCaps);
t.gui.slider_scalar_field("relwidth", "Size", &drawP.controls.relativeWidth, 3.0f, 40.0f);
t.gui.checkbox_field("hasroundcaps", "Round Caps", &drawP.world.main.toolConfig.brush.hasRoundCaps);
drawP.world.main.toolConfig.relative_width_slider(t.gui, "Size", &drawP.world.main.toolConfig.brush.relativeWidth);
t.gui.pop_id();
}
@ -184,11 +186,11 @@ void BrushTool::draw(SkCanvas* canvas, const DrawData& drawData) {
linePaint.setColor4f(drawP.world.canvasTheme.get_tool_front_color());
linePaint.setStroke(true);
linePaint.setStrokeWidth(0.0f);
float width;
float width = drawP.world.main.toolConfig.get_relative_width(drawP.world.main.toolConfig.brush.relativeWidth);
if(objInfoBeingEdited)
width = drawP.controls.relativeWidth * penWidth * 0.5f;
width *= penWidth * 0.5f;
else
width = drawP.controls.relativeWidth * 0.5f;
width *= 0.5f;
Vector2f pos = drawData.main->input.mouse.pos;
canvas->drawCircle(pos.x(), pos.y(), width, linePaint);
}

View file

@ -38,7 +38,6 @@ class BrushTool : public DrawingProgramToolBase {
std::deque<SmoothingPoint> penSmoothingData;
CanvasComponentContainer::ObjInfo* objInfoBeingEdited = nullptr;
bool hasRoundCaps = true;
bool drawingMinimumRelativeToSize = true;
bool midwayInterpolation = true;
Vector2f prevPointUnaltered = {0, 0};

View file

@ -19,13 +19,15 @@ DrawingProgramToolType EllipseDrawTool::get_type() {
void EllipseDrawTool::gui_toolbox() {
Toolbar& t = drawP.world.main.toolbar;
auto& toolConfig = drawP.world.main.toolConfig;
auto& fillStrokeMode = toolConfig.ellipseDraw.fillStrokeMode;
t.gui.push_id("ellipse draw tool");
t.gui.text_label_centered("Draw Ellipse");
if(t.gui.radio_button_field("fillonly", "Fill only", fillStrokeMode == 0)) fillStrokeMode = 0;
if(t.gui.radio_button_field("outlineonly", "Outline only", fillStrokeMode == 1)) fillStrokeMode = 1;
if(t.gui.radio_button_field("filloutline", "Fill and Outline", fillStrokeMode == 2)) fillStrokeMode = 2;
if(fillStrokeMode == 1 || fillStrokeMode == 2)
t.gui.slider_scalar_field("relstrokewidth", "Outline Size", &drawP.controls.relativeWidth, 3.0f, 40.0f);
toolConfig.relative_width_slider(t.gui, "Outline Size", &toolConfig.ellipseDraw.relativeWidth);
t.gui.pop_id();
}
@ -45,19 +47,21 @@ void EllipseDrawTool::switch_tool(DrawingProgramToolType newTool) {
}
void EllipseDrawTool::tool_update() {
auto& toolConfig = drawP.world.main.toolConfig;
if(!objInfoBeingEdited) {
if(drawP.controls.leftClick && drawP.layerMan.is_a_layer_being_edited()) {
CanvasComponentContainer* newContainer = new CanvasComponentContainer(drawP.world.netObjMan, CanvasComponentType::ELLIPSE);
EllipseCanvasComponent& newEllipse = static_cast<EllipseCanvasComponent&>(newContainer->get_comp());
startAt = drawP.world.main.input.mouse.pos;
newEllipse.d.strokeColor = drawP.controls.foregroundColor;
newEllipse.d.fillColor = drawP.controls.backgroundColor;
newEllipse.d.strokeWidth = drawP.controls.relativeWidth;
newEllipse.d.strokeColor = toolConfig.globalConf.foregroundColor;
newEllipse.d.fillColor = toolConfig.globalConf.backgroundColor;
newEllipse.d.strokeWidth = toolConfig.get_relative_width(toolConfig.ellipseDraw.relativeWidth);
newEllipse.d.p1 = startAt;
newEllipse.d.p2 = startAt;
newEllipse.d.p2 = ensure_points_have_distance(newEllipse.d.p1, newEllipse.d.p2, MINIMUM_DISTANCE_BETWEEN_BOUNDS);
newEllipse.d.fillStrokeMode = static_cast<uint8_t>(fillStrokeMode);
newEllipse.d.fillStrokeMode = static_cast<uint8_t>(toolConfig.ellipseDraw.fillStrokeMode);
newContainer->coords = drawP.world.drawData.cam.c;
objInfoBeingEdited = drawP.layerMan.add_component_to_layer_being_edited(newContainer);

View file

@ -21,6 +21,5 @@ class EllipseDrawTool : public DrawingProgramToolBase {
void commit();
Vector2f startAt;
int fillStrokeMode = 1;
CanvasComponentContainer::ObjInfo* objInfoBeingEdited = nullptr;
};

View file

@ -16,7 +16,7 @@ void EraserTool::gui_toolbox() {
Toolbar& t = drawP.world.main.toolbar;
t.gui.push_id("eraser tool");
t.gui.text_label_centered("Eraser");
t.gui.slider_scalar_field("relwidth", "Size", &drawP.controls.relativeWidth, 3.0f, 40.0f);
drawP.world.main.toolConfig.relative_width_slider(t.gui, "Size", &drawP.world.main.toolConfig.eraser.relativeWidth);
t.gui.text_label("Erase from:");
if(t.gui.radio_button_field("layer edited", "Layer being edited", drawP.controls.layerSelector == DrawingProgramLayerManager::LayerSelector::LAYER_BEING_EDITED))
drawP.controls.layerSelector = DrawingProgramLayerManager::LayerSelector::LAYER_BEING_EDITED;
@ -46,7 +46,8 @@ void EraserTool::tool_update() {
if(drawP.controls.leftClickHeld) {
const Vector2f& prevMousePos = drawP.controls.leftClick ? drawP.world.main.input.mouse.pos : drawP.world.main.input.mouse.lastPos;
SCollision::ColliderCollection<float> cC;
SCollision::generate_wide_line(cC, prevMousePos, drawP.world.main.input.mouse.pos, drawP.controls.relativeWidth * 2.0f, true);
float width = drawP.world.main.toolConfig.get_relative_width(drawP.world.main.toolConfig.eraser.relativeWidth);
SCollision::generate_wide_line(cC, prevMousePos, drawP.world.main.input.mouse.pos, width * 2.0f, true);
auto cCWorld = drawP.world.drawData.cam.c.collider_to_world<SCollision::ColliderCollection<WorldScalar>, SCollision::ColliderCollection<float>>(cC);
drawP.drawCache.traverse_bvh_run_function(cCWorld.bounds, [&](const auto& bvhNode) {
@ -96,7 +97,8 @@ void EraserTool::draw(SkCanvas* canvas, const DrawData& drawData) {
linePaint.setColor4f(c);
linePaint.setStyle(SkPaint::kStroke_Style);
linePaint.setStrokeCap(SkPaint::kRound_Cap);
linePaint.setStrokeWidth(drawP.controls.relativeWidth * 2.0f);
float width = drawP.world.main.toolConfig.get_relative_width(drawP.world.main.toolConfig.eraser.relativeWidth);
linePaint.setStrokeWidth(width * 2.0f);
SkPathBuilder erasePath;
erasePath.moveTo(convert_vec2<SkPoint>(drawData.main->input.mouse.lastPos));
erasePath.lineTo(convert_vec2<SkPoint>(drawData.main->input.mouse.pos));

View file

@ -31,6 +31,7 @@ DrawingProgramToolType EyeDropperTool::get_type() {
void EyeDropperTool::gui_toolbox() {
Toolbar& t = drawP.world.main.toolbar;
auto& selectingStrokeColor = drawP.world.main.toolConfig.eyeDropper.selectingStrokeColor;
t.gui.push_id("Color select tool");
t.gui.text_label_centered("Color Select");
if(t.gui.radio_button_field("Stroke Color", "Stroke Color", selectingStrokeColor)) selectingStrokeColor = true;
@ -48,6 +49,9 @@ void EyeDropperTool::erase_component(CanvasComponentContainer::ObjInfo* erasedCo
}
void EyeDropperTool::tool_update() {
auto& toolConfig = drawP.world.main.toolConfig;
auto& selectingStrokeColor = drawP.world.main.toolConfig.eyeDropper.selectingStrokeColor;
if(drawP.controls.leftClick) {
SkSurfaceProps props;
#ifdef USE_BACKEND_OPENGLES_3_0
@ -89,9 +93,9 @@ void EyeDropperTool::tool_update() {
#endif
if(selectingStrokeColor)
drawP.controls.foregroundColor = readData.cast<float>() / 255.0f;
toolConfig.globalConf.foregroundColor = readData.cast<float>() / 255.0f;
else
drawP.controls.backgroundColor = readData.cast<float>() / 255.0f;
toolConfig.globalConf.backgroundColor = readData.cast<float>() / 255.0f;
}
}

View file

@ -14,6 +14,4 @@ class EyeDropperTool : public DrawingProgramToolBase {
virtual void draw(SkCanvas* canvas, const DrawData& drawData) override;
virtual bool prevent_undo_or_redo() override;
virtual void switch_tool(DrawingProgramToolType newTool) override;
private:
bool selectingStrokeColor = true;
};

View file

@ -18,10 +18,11 @@ DrawingProgramToolType LineDrawTool::get_type() {
void LineDrawTool::gui_toolbox() {
Toolbar& t = drawP.world.main.toolbar;
auto& toolConfig = drawP.world.main.toolConfig;
t.gui.push_id("rect draw tool");
t.gui.text_label_centered("Draw Line");
t.gui.slider_scalar_field("relstrokewidth", "Size", &drawP.controls.relativeWidth, 3.0f, 40.0f);
t.gui.checkbox_field("hasroundcaps", "Round Caps", &hasRoundCaps);
toolConfig.relative_width_slider(t.gui, "Size", &toolConfig.lineDraw.relativeWidth);
t.gui.checkbox_field("hasroundcaps", "Round Caps", &toolConfig.lineDraw.hasRoundCaps);
t.gui.pop_id();
}
@ -41,6 +42,7 @@ void LineDrawTool::switch_tool(DrawingProgramToolType newTool) {
}
void LineDrawTool::tool_update() {
auto& toolConfig = drawP.world.main.toolConfig;
if(!objInfoBeingEdited) {
if(drawP.controls.leftClick && drawP.layerMan.is_a_layer_being_edited()) {
CanvasComponentContainer* newBrushStrokeContainer = new CanvasComponentContainer(drawP.world.netObjMan, CanvasComponentType::BRUSHSTROKE);
@ -48,12 +50,12 @@ void LineDrawTool::tool_update() {
BrushStrokeCanvasComponentPoint p;
p.pos = drawP.world.main.input.mouse.pos;
p.width = drawP.controls.relativeWidth;
p.width = toolConfig.get_relative_width(toolConfig.lineDraw.relativeWidth);
newBrushStroke.d->points.emplace_back(p);
p.pos = ensure_points_have_distance(p.pos, p.pos, 1.0f);
newBrushStroke.d->points.emplace_back(p);
newBrushStroke.d->color = drawP.controls.foregroundColor;
newBrushStroke.d->hasRoundCaps = hasRoundCaps;
newBrushStroke.d->color = toolConfig.globalConf.foregroundColor;
newBrushStroke.d->hasRoundCaps = toolConfig.lineDraw.hasRoundCaps;
newBrushStrokeContainer->coords = drawP.world.drawData.cam.c;
objInfoBeingEdited = drawP.layerMan.add_component_to_layer_being_edited(newBrushStrokeContainer);
}

View file

@ -20,6 +20,5 @@ class LineDrawTool : public DrawingProgramToolBase {
void commit();
Vector2f startAt;
bool hasRoundCaps = true;
CanvasComponentContainer::ObjInfo* objInfoBeingEdited = nullptr;
};

View file

@ -16,6 +16,9 @@ DrawingProgramToolType RectDrawTool::get_type() {
void RectDrawTool::gui_toolbox() {
Toolbar& t = drawP.world.main.toolbar;
auto& toolConfig = drawP.world.main.toolConfig;
auto& fillStrokeMode = toolConfig.rectDraw.fillStrokeMode;
auto& relativeRadiusWidth = toolConfig.rectDraw.relativeRadiusWidth;
t.gui.push_id("rect draw tool");
t.gui.text_label_centered("Draw Rectangle");
t.gui.slider_scalar_field("relradiuswidth", "Corner Radius", &relativeRadiusWidth, 0.0f, 40.0f);
@ -23,7 +26,7 @@ void RectDrawTool::gui_toolbox() {
if(t.gui.radio_button_field("outlineonly", "Outline only", fillStrokeMode == 1)) fillStrokeMode = 1;
if(t.gui.radio_button_field("filloutline", "Fill and Outline", fillStrokeMode == 2)) fillStrokeMode = 2;
if(fillStrokeMode == 1 || fillStrokeMode == 2)
t.gui.slider_scalar_field("relstrokewidth", "Outline Size", &drawP.controls.relativeWidth, 3.0f, 40.0f);
toolConfig.relative_width_slider(t.gui, "Outline Size", &toolConfig.rectDraw.relativeWidth);
t.gui.pop_id();
}
@ -43,16 +46,20 @@ void RectDrawTool::switch_tool(DrawingProgramToolType newTool) {
}
void RectDrawTool::tool_update() {
auto& toolConfig = drawP.world.main.toolConfig;
auto& fillStrokeMode = toolConfig.rectDraw.fillStrokeMode;
auto& relativeRadiusWidth = toolConfig.rectDraw.relativeRadiusWidth;
if(!objInfoBeingEdited) {
if(drawP.controls.leftClick && drawP.layerMan.is_a_layer_being_edited()) {
CanvasComponentContainer* newContainer = new CanvasComponentContainer(drawP.world.netObjMan, CanvasComponentType::RECTANGLE);
RectangleCanvasComponent& newRectangle = static_cast<RectangleCanvasComponent&>(newContainer->get_comp());
startAt = drawP.world.main.input.mouse.pos;
newRectangle.d.strokeColor = drawP.controls.foregroundColor;
newRectangle.d.fillColor = drawP.controls.backgroundColor;
newRectangle.d.strokeColor = toolConfig.globalConf.foregroundColor;
newRectangle.d.fillColor = toolConfig.globalConf.backgroundColor;
newRectangle.d.cornerRadius = relativeRadiusWidth;
newRectangle.d.strokeWidth = drawP.controls.relativeWidth;
newRectangle.d.strokeWidth = toolConfig.get_relative_width(toolConfig.rectDraw.relativeWidth);
newRectangle.d.p1 = startAt;
newRectangle.d.p2 = startAt;
newRectangle.d.p2 = ensure_points_have_distance(newRectangle.d.p1, newRectangle.d.p2, MINIMUM_DISTANCE_BETWEEN_BOUNDS);

View file

@ -20,7 +20,5 @@ class RectDrawTool : public DrawingProgramToolBase {
void commit();
Vector2f startAt;
float relativeRadiusWidth = 10.0f;
int fillStrokeMode = 1;
CanvasComponentContainer::ObjInfo* objInfoBeingEdited = nullptr;
};

View file

@ -49,32 +49,33 @@ DrawingProgramToolType ScreenshotTool::get_type() {
void ScreenshotTool::gui_toolbox() {
Toolbar& t = drawP.world.main.toolbar;
auto& screenshotConfig = drawP.world.main.toolConfig.screenshot;
t.gui.push_id("screenshot tool");
t.gui.text_label_centered("Screenshot");
auto oldImgSize = controls.imageSize;
if(controls.selectionMode == 0)
t.gui.text_label("Select an area on the canvas...");
if(controls.selectionMode != 0 && controls.selectedType != SCREENSHOT_SVG)
if(controls.selectionMode != 0 && screenshotConfig.selectedType != SCREENSHOT_SVG)
t.gui.input_scalar_fields("Image Size", "Image Size", &controls.imageSize, 2, 0, 999999999);
if(controls.selectionMode == 2) {
t.gui.left_to_right_line_layout([&]() {
t.gui.text_label("Image Type");
t.gui.dropdown_select("image type select", &controls.selectedType, controls.typeSelections);
t.gui.dropdown_select("image type select", (size_t*)(&screenshotConfig.selectedType), controls.typeSelections);
});
if(controls.selectedType != SCREENSHOT_SVG)
if(screenshotConfig.selectedType != SCREENSHOT_SVG)
t.gui.checkbox_field("Display Grid", "Display Grid", &controls.displayGrid);
else
t.gui.text_label("Note: Screenshot will ignore blend\nmodes and layer alpha");
if(controls.selectedType != 0)
if(screenshotConfig.selectedType != 0)
t.gui.checkbox_field("Transparent Background", "Transparent Background", &controls.transparentBackground);
if(controls.imageSize.x() != oldImgSize.x()) {
controls.setDimensionSize = controls.imageSize.x();
controls.setDimensionIsX = true;
screenshotConfig.setDimensionSize = controls.imageSize.x();
screenshotConfig.setDimensionIsX = true;
controls.imageSize.y() = controls.imageSize.x() * (controls.rectY2 - controls.rectY1) / (controls.rectX2 - controls.rectX1);
}
else if(controls.imageSize.y() != oldImgSize.y()) {
controls.setDimensionSize = controls.imageSize.y();
controls.setDimensionIsX = false;
screenshotConfig.setDimensionSize = controls.imageSize.y();
screenshotConfig.setDimensionIsX = false;
controls.imageSize.x() = controls.imageSize.y() * (controls.rectX2 - controls.rectX1) / (controls.rectY2 - controls.rectY1);
}
if(t.gui.text_button_wide("Take Screenshot", "Take Screenshot")) {
@ -84,7 +85,7 @@ void ScreenshotTool::gui_toolbox() {
#else
// We can't actually use the extension from the callback, so we have to set the extension of choice beforehand
Toolbar::ExtensionFilter setExtensionFilter;
switch(controls.selectedType) {
switch(screenshotConfig.selectedType) {
case SCREENSHOT_JPG:
setExtensionFilter = {"JPEG", "jpg;jpeg"};
break;
@ -335,6 +336,7 @@ void ScreenshotTool::switch_tool(DrawingProgramToolType newTool) {
}
void ScreenshotTool::tool_update() {
auto& screenshotConfig = drawP.world.main.toolConfig.screenshot;
if(controls.setToTakeScreenshot) {
controls.setToTakeScreenshot = false;
take_screenshot(controls.screenshotSavePath);
@ -401,12 +403,12 @@ void ScreenshotTool::tool_update() {
float tempX2 = std::max(controls.rectX1, controls.rectX2);
float tempY1 = std::min(controls.rectY1, controls.rectY2);
float tempY2 = std::max(controls.rectY1, controls.rectY2);
if(controls.setDimensionIsX) {
controls.imageSize.x() = controls.setDimensionSize;
if(screenshotConfig.setDimensionIsX) {
controls.imageSize.x() = screenshotConfig.setDimensionSize;
controls.imageSize.y() = controls.imageSize.x() * (tempY2 - tempY1) / (tempX2 - tempX1);
}
else {
controls.imageSize.y() = controls.setDimensionSize;
controls.imageSize.y() = screenshotConfig.setDimensionSize;
controls.imageSize.x() = controls.imageSize.y() * (tempX2 - tempX1) / (tempY2 - tempY1);
}

View file

@ -18,6 +18,13 @@ class ScreenshotTool : public DrawingProgramToolBase {
virtual void draw(SkCanvas* canvas, const DrawData& drawData) override;
virtual void switch_tool(DrawingProgramToolType newTool) override;
virtual bool prevent_undo_or_redo() override;
enum ScreenshotType : size_t {
SCREENSHOT_JPG,
SCREENSHOT_PNG,
SCREENSHOT_WEBP,
SCREENSHOT_SVG
};
private:
void commit_rect();
void take_screenshot(const std::filesystem::path& filePath);
@ -35,13 +42,6 @@ class ScreenshotTool : public DrawingProgramToolBase {
// InputManager::SystemCursorType::E_RESIZE
//};
enum ScreenshotType : size_t {
SCREENSHOT_JPG,
SCREENSHOT_PNG,
SCREENSHOT_WEBP,
SCREENSHOT_SVG
};
struct ScreenshotControls {
CoordSpaceHelper translateBeginCoords;
WorldVec translateBeginPos;
@ -54,17 +54,21 @@ class ScreenshotTool : public DrawingProgramToolBase {
int selectionMode = 0;
int dragType = 0;
Vector2i imageSize = {0, 0};
int setDimensionSize = 1000;
bool setDimensionIsX = true;
std::array<SCollision::Circle<float>, 8> circles;
bool displayGrid = true;
bool transparentBackground = false;
size_t selectedType = SCREENSHOT_JPG;
std::vector<std::string> typeSelections = {".jpg", ".png", ".webp", ".svg"};
std::atomic<bool> setToTakeScreenshot = false;
std::filesystem::path screenshotSavePath;
} controls;
};
NLOHMANN_JSON_SERIALIZE_ENUM(ScreenshotTool::ScreenshotType, {
{ScreenshotTool::ScreenshotType::SCREENSHOT_JPG, "jpg"},
{ScreenshotTool::ScreenshotType::SCREENSHOT_PNG, "png"},
{ScreenshotTool::ScreenshotType::SCREENSHOT_WEBP, "webp"},
{ScreenshotTool::ScreenshotType::SCREENSHOT_SVG, "svg"}
})

View file

@ -180,6 +180,7 @@ void MainProgram::save_config() {
j["window"]["maximized"] = window.maximized;
j["window"]["fullscreen"] = window.fullscreen;
j["fileselectorpath"] = toolbar.file_selector_path();
j["toolConfig"] = toolConfig;
f << std::setw(4) << j;
f.close();
@ -239,6 +240,10 @@ void MainProgram::load_config() {
toolbar.file_selector_path() = homePath;
}
#endif
try {
j.at("toolConfig").get_to(toolConfig);
}
catch(...) {}
f.close();
} catch(...) {}
}

View file

@ -11,6 +11,7 @@
#include <include/core/SkSurfaceProps.h>
#include "Toolbar.hpp"
#include "World.hpp"
#include "DrawingProgram/ToolConfiguration.hpp"
#ifdef USE_SKIA_BACKEND_GRAPHITE
#include "include/gpu/graphite/Recorder.h"
@ -73,6 +74,7 @@ class MainProgram {
TimePoint deltaTime;
Toolbar toolbar;
std::shared_ptr<World> world;
ToolConfiguration toolConfig;
std::ofstream* logFile;
std::deque<Toolbar::LogMessage> logMessages;

View file

@ -476,7 +476,7 @@ void Toolbar::close_popup_gui() {
},
.backgroundColor = convert_vec4<Clay_Color>(io->theme->backColor1),
.cornerRadius = CLAY_CORNER_RADIUS(io->theme->windowCorners1),
.floating = {.attachPoints = {.element = CLAY_ATTACH_POINT_CENTER_CENTER, .parent = CLAY_ATTACH_POINT_CENTER_CENTER}, .attachTo = CLAY_ATTACH_TO_PARENT}
.floating = {.zIndex = 1, .attachPoints = {.element = CLAY_ATTACH_POINT_CENTER_CENTER, .parent = CLAY_ATTACH_POINT_CENTER_CENTER}, .attachTo = CLAY_ATTACH_TO_PARENT}
}) {
gui.obstructing_window();
gui.push_id("Close single file popup gui");
@ -1700,6 +1700,7 @@ void Toolbar::options_menu() {
gui.slider_scalar_field("drag zoom slider", "Drag zoom speed", &dragZoomSpeed, 0.0, 1.0, 3);
gui.slider_scalar_field("scroll zoom slider", "Scroll zoom speed", &scrollZoomSpeed, 0.0, 1.0, 3);
gui.checkbox_field("flip zoom tool direction", "Flip zoom tool direction", &flipZoomToolDirection);
gui.checkbox_field("make all tools share same size", "Make all tools share size", &main.toolConfig.globalConf.useGlobalRelativeWidth);
gui.input_scalar_field("jump transition time", "Jump transition time", &jumpTransitionTime, 0.01f, 1000.0f, 2);
gui.input_scalar_field("Max GUI Scale", "Max GUI Scale", &guiScale, 0.5f, 5.0f, 1);