Working on getting textbox edit tool functional

This commit is contained in:
Yousef Khadadeh 2026-04-04 17:52:43 +03:00
parent 262bf23bce
commit 0087048a02
43 changed files with 605 additions and 295 deletions

View file

@ -53,6 +53,7 @@ set(sources "src/main.cpp"
"src/GUIHolder.cpp"
"src/GlobalConfig.cpp"
"src/RichTextUserInput.cpp"
"src/CustomEvents.cpp"
"src/Bookmarks/BookmarkListItem.cpp"
"src/Bookmarks/BookmarkManager.cpp"
"src/ResourceDisplay/ResourceDisplay.cpp"

38
src/CustomEvents.cpp Normal file
View file

@ -0,0 +1,38 @@
#include "CustomEvents.hpp"
#include <SDL3/SDL.h>
#include <queue>
namespace CustomEvents {
bool alreadyInitialized = false;
uint32_t PASTE_EVENT;
std::queue<PasteEventData> pasteEventData;
void init() {
if(!alreadyInitialized) {
PASTE_EVENT = SDL_RegisterEvents(1);
alreadyInitialized = true;
}
}
bool emit_paste_event(const PasteEventData& pasteData) {
SDL_Event event;
SDL_zero(event);
event.type = PASTE_EVENT;
if(SDL_PushEvent(&event)) {
pasteEventData.push(pasteData);
return true;
}
return false;
}
const PasteEventData& get_paste_event_data() {
return pasteEventData.front();
}
void pop_paste_event_data() {
pasteEventData.pop();
}
}

26
src/CustomEvents.hpp Normal file
View file

@ -0,0 +1,26 @@
#pragma once
#include <cstdint>
#include <string>
#include <optional>
#include "RichText/TextBox.hpp"
namespace CustomEvents {
void init();
enum class PasteEventDataType {
TEXT,
IMAGE
};
struct PasteEventData {
PasteEventDataType type;
std::string data;
std::optional<RichText::TextData> richText;
std::optional<Vector2f> mousePos;
};
bool emit_paste_event(const PasteEventData& pasteData);
const PasteEventData& get_paste_event_data();
void pop_paste_event_data();
extern uint32_t PASTE_EVENT;
}

View file

@ -58,6 +58,10 @@ void DrawingProgram::on_tab_out() {
controls.middleClickHeld = false;
}
void DrawingProgram::input_paste_callback(const CustomEvents::PasteEventData& paste) {
drawTool->input_paste_callback(paste);
}
void DrawingProgram::input_drop_file_callback(const InputManager::DropCallbackArgs& drop) {
if(std::filesystem::is_regular_file(drop.data)) {
#ifdef __EMSCRIPTEN_
@ -83,6 +87,14 @@ void DrawingProgram::input_drop_text_callback(const InputManager::DropCallbackAr
}
}
void DrawingProgram::input_text_key_callback(const InputManager::KeyCallbackArgs& key) {
drawTool->input_text_key_callback(key);
}
void DrawingProgram::input_text_callback(const InputManager::TextCallbackArgs& text) {
drawTool->input_text_callback(text);
}
void DrawingProgram::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) {
auto buttonCallbacks = [&](const InputManager::MouseButtonCallbackArgs& b) {
drawTool->input_mouse_button_on_canvas_callback(b);

View file

@ -59,8 +59,11 @@ class DrawingProgram {
void send_transforms_for(const std::vector<CanvasComponentContainer::ObjInfo*>& objsToSendTransformsFor);
void on_tab_out();
void input_paste_callback(const CustomEvents::PasteEventData& paste);
void input_drop_text_callback(const InputManager::DropCallbackArgs& drop);
void input_drop_file_callback(const InputManager::DropCallbackArgs& drop);
void input_text_key_callback(const InputManager::KeyCallbackArgs& key);
void input_text_callback(const InputManager::TextCallbackArgs& text);
void input_key_callback(const InputManager::KeyCallbackArgs& key);
void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button);
void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion);
@ -131,7 +134,6 @@ class DrawingProgram {
std::optional<Vector2f> rightClickPopupLocation;
uint32_t nextID = 0;
friend class EyeDropperTool;

View file

@ -55,6 +55,9 @@ std::unique_ptr<DrawingProgramToolBase> DrawingProgramToolBase::allocate_tool_ty
return nullptr;
}
void DrawingProgramToolBase::input_paste_callback(const CustomEvents::PasteEventData& paste) {}
void DrawingProgramToolBase::input_text_key_callback(const InputManager::KeyCallbackArgs& key) {}
void DrawingProgramToolBase::input_text_callback(const InputManager::TextCallbackArgs& text) {}
void DrawingProgramToolBase::input_key_callback(const InputManager::KeyCallbackArgs& key) {}
void DrawingProgramToolBase::input_mouse_button_on_canvas_callback(const InputManager::MouseButtonCallbackArgs& button) {}
void DrawingProgramToolBase::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) {}

View file

@ -36,6 +36,9 @@ class DrawingProgramToolBase {
virtual void draw(SkCanvas* canvas, const DrawData& drawData) = 0;
virtual void switch_tool(DrawingProgramToolType newTool) = 0;
virtual bool prevent_undo_or_redo() = 0;
virtual void input_paste_callback(const CustomEvents::PasteEventData& paste);
virtual void input_text_key_callback(const InputManager::KeyCallbackArgs& key);
virtual void input_text_callback(const InputManager::TextCallbackArgs& text);
virtual void input_key_callback(const InputManager::KeyCallbackArgs& key);
virtual void input_mouse_button_on_canvas_callback(const InputManager::MouseButtonCallbackArgs& button);
virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion);

View file

@ -33,7 +33,7 @@ void EditTool::gui_toolbox() {
auto& gui = drawP.world.main.g.gui;
if(objInfoBeingEdited)
compEditTool->edit_gui(objInfoBeingEdited);
compEditTool->edit_gui();
else {
gui.new_id("edit tool", [&] {
text_label_centered(gui, "Edit");
@ -46,6 +46,21 @@ void EditTool::erase_component(CanvasComponentContainer::ObjInfo* erasedComp) {
switch_tool(get_type());
}
void EditTool::input_paste_callback(const CustomEvents::PasteEventData& paste) {
if(objInfoBeingEdited)
compEditTool->input_paste_callback(paste);
}
void EditTool::input_text_key_callback(const InputManager::KeyCallbackArgs& key) {
if(objInfoBeingEdited)
compEditTool->input_text_key_callback(key);
}
void EditTool::input_text_callback(const InputManager::TextCallbackArgs& text) {
if(objInfoBeingEdited)
compEditTool->input_text_callback(text);
}
void EditTool::input_key_callback(const InputManager::KeyCallbackArgs& key) {
drawP.selection.input_key_callback_modify_selection(key);
}
@ -122,12 +137,12 @@ void EditTool::input_mouse_button_on_canvas_callback(const InputManager::MouseBu
switch_tool(get_type());
if(objInfoBeingEdited)
compEditTool->input_mouse_button_on_canvas_callback(objInfoBeingEdited, button, pointDragging);
compEditTool->input_mouse_button_on_canvas_callback(button, pointDragging);
}
}
else {
if(objInfoBeingEdited)
compEditTool->input_mouse_button_on_canvas_callback(objInfoBeingEdited, button, pointDragging);
compEditTool->input_mouse_button_on_canvas_callback(button, pointDragging);
if(pointDragging)
pointDragging = nullptr;
}
@ -147,14 +162,14 @@ void EditTool::input_mouse_motion_callback(const InputManager::MouseMotionCallba
objInfoBeingEdited->obj->commit_update(drawP);
}
}
compEditTool->input_mouse_motion_callback(objInfoBeingEdited, motion, pointDragging);
compEditTool->input_mouse_motion_callback(motion, pointDragging);
}
drawP.selection.input_mouse_motion_callback_modify_selection(motion);
}
void EditTool::right_click_popup_gui(Vector2f popupPos) {
if(objInfoBeingEdited)
return compEditTool->right_click_popup_gui(objInfoBeingEdited, popupPos);
return compEditTool->right_click_popup_gui(popupPos);
else
return drawP.selection_action_menu(popupPos);
}
@ -165,7 +180,7 @@ void EditTool::add_point_handle(const HandleData& handle) {
void EditTool::switch_tool(DrawingProgramToolType newTool) {
if(objInfoBeingEdited) {
compEditTool->commit_edit_updates(objInfoBeingEdited, prevData);
compEditTool->commit_edit_updates(prevData);
objInfoBeingEdited->obj->commit_update(drawP);
objInfoBeingEdited->obj->send_comp_update(drawP, true);
@ -221,23 +236,23 @@ void EditTool::edit_start(CanvasComponentContainer::ObjInfo* comp, bool initUndo
bool isEditing = true;
switch(comp->obj->get_comp().get_type()) {
case CanvasComponentType::TEXTBOX: {
compEditTool = std::make_unique<TextBoxEditTool>(drawP);
compEditTool = std::make_unique<TextBoxEditTool>(drawP, comp);
break;
}
case CanvasComponentType::ELLIPSE: {
compEditTool = std::make_unique<EllipseDrawEditTool>(drawP);
compEditTool = std::make_unique<EllipseDrawEditTool>(drawP, comp);
break;
}
case CanvasComponentType::RECTANGLE: {
compEditTool = std::make_unique<RectDrawEditTool>(drawP);
compEditTool = std::make_unique<RectDrawEditTool>(drawP, comp);
break;
}
case CanvasComponentType::IMAGE: {
compEditTool = std::make_unique<ImageEditTool>(drawP);
compEditTool = std::make_unique<ImageEditTool>(drawP, comp);
break;
}
case CanvasComponentType::BRUSHSTROKE: {
compEditTool = std::make_unique<BrushEditTool>(drawP);
compEditTool = std::make_unique<BrushEditTool>(drawP, comp);
break;
}
default: {
@ -249,7 +264,7 @@ void EditTool::edit_start(CanvasComponentContainer::ObjInfo* comp, bool initUndo
objInfoBeingEdited = comp;
oldData = comp->obj->get_comp().get_data_copy();
undoAfterEditDone = initUndoAfterEditDone;
compEditTool->edit_start(*this, objInfoBeingEdited, prevData);
compEditTool->edit_start(*this, prevData);
drawP.world.main.g.gui.set_to_layout();
}
}
@ -261,7 +276,7 @@ bool EditTool::is_editable(CanvasComponentContainer::ObjInfo* comp) {
void EditTool::tool_update() {
if(objInfoBeingEdited) {
objInfoBeingEdited->obj->send_comp_update(drawP, false);
bool shouldNotReset = compEditTool->edit_update(objInfoBeingEdited);
bool shouldNotReset = compEditTool->edit_update();
if(!shouldNotReset)
switch_tool(get_type());
}

View file

@ -26,6 +26,9 @@ class EditTool : public DrawingProgramToolBase {
virtual void switch_tool(DrawingProgramToolType newTool) override;
virtual void draw(SkCanvas* canvas, const DrawData& drawData) override;
virtual bool prevent_undo_or_redo() override;
virtual void input_paste_callback(const CustomEvents::PasteEventData& paste) override;
virtual void input_text_key_callback(const InputManager::KeyCallbackArgs& key) override;
virtual void input_text_callback(const InputManager::TextCallbackArgs& text) override;
virtual void input_key_callback(const InputManager::KeyCallbackArgs& key) override;
virtual void input_mouse_button_on_canvas_callback(const InputManager::MouseButtonCallbackArgs& button) override;
virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) override;

View file

@ -7,18 +7,18 @@
#include "../../../GUIStuff/ElementHelpers/TextLabelHelpers.hpp"
#include "../../../GUIStuff/ElementHelpers/LayoutHelpers.hpp"
BrushEditTool::BrushEditTool(DrawingProgram& initDrawP):
DrawingProgramEditToolBase(initDrawP)
BrushEditTool::BrushEditTool(DrawingProgram& initDrawP, CanvasComponentContainer::ObjInfo* initComp):
DrawingProgramEditToolBase(initDrawP, initComp)
{}
void BrushEditTool::edit_gui(CanvasComponentContainer::ObjInfo* comp) {
void BrushEditTool::edit_gui() {
using namespace GUIStuff;
using namespace ElementHelpers;
auto& a = static_cast<BrushStrokeCanvasComponent&>(comp->obj->get_comp());
auto& gui = drawP.world.main.g.gui;
Toolbar& t = drawP.world.main.toolbar;
auto commit_update_func = [&, comp] { comp->obj->commit_update(drawP); };
auto commit_update_func = [&] { comp->obj->commit_update(drawP); };
gui.new_id("edit tool brush", [&] {
text_label_centered(gui, "Edit Brush Stroke");
@ -29,14 +29,14 @@ void BrushEditTool::edit_gui(CanvasComponentContainer::ObjInfo* comp) {
});
}
void BrushEditTool::edit_start(EditTool& editTool, CanvasComponentContainer::ObjInfo* comp, std::any& prevData) {
void BrushEditTool::edit_start(EditTool& editTool, std::any& prevData) {
auto& a = static_cast<BrushStrokeCanvasComponent&>(comp->obj->get_comp());
oldColor = a.d.color;
}
void BrushEditTool::commit_edit_updates(CanvasComponentContainer::ObjInfo* comp, std::any& prevData) {
void BrushEditTool::commit_edit_updates(std::any& prevData) {
}
bool BrushEditTool::edit_update(CanvasComponentContainer::ObjInfo* comp) {
bool BrushEditTool::edit_update() {
return true;
}

View file

@ -8,11 +8,11 @@ class DrawingProgram;
class BrushEditTool : public DrawingProgramEditToolBase {
public:
BrushEditTool(DrawingProgram& initDrawP);
virtual void edit_start(EditTool& editTool, CanvasComponentContainer::ObjInfo* comp, std::any& prevData) override;
virtual void commit_edit_updates(CanvasComponentContainer::ObjInfo* comp, std::any& prevData) override;
virtual bool edit_update(CanvasComponentContainer::ObjInfo* comp) override;
virtual void edit_gui(CanvasComponentContainer::ObjInfo* comp) override;
BrushEditTool(DrawingProgram& initDrawP, CanvasComponentContainer::ObjInfo* initComp);
virtual void edit_start(EditTool& editTool, std::any& prevData) override;
virtual void commit_edit_updates(std::any& prevData) override;
virtual bool edit_update() override;
virtual void edit_gui() override;
private:
Vector4f oldColor;
};

View file

@ -1,17 +1,21 @@
#include "DrawingProgramEditToolBase.hpp"
#include "../../../MainProgram.hpp"
DrawingProgramEditToolBase::DrawingProgramEditToolBase(DrawingProgram& initDrawP):
drawP(initDrawP)
DrawingProgramEditToolBase::DrawingProgramEditToolBase(DrawingProgram& initDrawP, CanvasComponentContainer::ObjInfo* initComp):
drawP(initDrawP),
comp(initComp)
{}
void DrawingProgramEditToolBase::right_click_popup_gui(CanvasComponentContainer::ObjInfo* comp, Vector2f popupPos) {
void DrawingProgramEditToolBase::right_click_popup_gui(Vector2f popupPos) {
Toolbar& t = drawP.world.main.toolbar;
t.paint_popup(popupPos);
}
void DrawingProgramEditToolBase::input_key_callback(CanvasComponentContainer::ObjInfo* comp, const InputManager::KeyCallbackArgs& key) {}
void DrawingProgramEditToolBase::input_mouse_button_on_canvas_callback(CanvasComponentContainer::ObjInfo* comp, const InputManager::MouseButtonCallbackArgs& button, bool isDraggingPoint) {}
void DrawingProgramEditToolBase::input_mouse_motion_callback(CanvasComponentContainer::ObjInfo* comp, const InputManager::MouseMotionCallbackArgs& motion, bool isDraggingPoint) {}
void DrawingProgramEditToolBase::input_paste_callback(const CustomEvents::PasteEventData& paste) {}
void DrawingProgramEditToolBase::input_text_key_callback(const InputManager::KeyCallbackArgs& key) {}
void DrawingProgramEditToolBase::input_text_callback(const InputManager::TextCallbackArgs& text) {}
void DrawingProgramEditToolBase::input_key_callback(const InputManager::KeyCallbackArgs& key) {}
void DrawingProgramEditToolBase::input_mouse_button_on_canvas_callback(const InputManager::MouseButtonCallbackArgs& button, bool isDraggingPoint) {}
void DrawingProgramEditToolBase::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion, bool isDraggingPoint) {}
DrawingProgramEditToolBase::~DrawingProgramEditToolBase() {}

View file

@ -8,16 +8,20 @@ class EditTool;
class DrawingProgramEditToolBase {
public:
DrawingProgramEditToolBase(DrawingProgram& initDrawP);
virtual void edit_start(EditTool& editTool, CanvasComponentContainer::ObjInfo* compContainer, std::any& prevData) = 0;
virtual void commit_edit_updates(CanvasComponentContainer::ObjInfo* compContainer, std::any& prevData) = 0;
virtual bool edit_update(CanvasComponentContainer::ObjInfo* compContainer) = 0;
virtual void edit_gui(CanvasComponentContainer::ObjInfo* compContainer) = 0;
virtual void right_click_popup_gui(CanvasComponentContainer::ObjInfo* comp, Vector2f popupPos);
virtual void input_key_callback(CanvasComponentContainer::ObjInfo* comp, const InputManager::KeyCallbackArgs& key);
virtual void input_mouse_button_on_canvas_callback(CanvasComponentContainer::ObjInfo* comp, const InputManager::MouseButtonCallbackArgs& button, bool isDraggingPoint);
virtual void input_mouse_motion_callback(CanvasComponentContainer::ObjInfo* comp, const InputManager::MouseMotionCallbackArgs& motion, bool isDraggingPoint);
DrawingProgramEditToolBase(DrawingProgram& initDrawP, CanvasComponentContainer::ObjInfo* initComp);
virtual void edit_start(EditTool& editTool, std::any& prevData) = 0;
virtual void commit_edit_updates(std::any& prevData) = 0;
virtual bool edit_update() = 0;
virtual void edit_gui() = 0;
virtual void right_click_popup_gui(Vector2f popupPos);
virtual void input_paste_callback(const CustomEvents::PasteEventData& paste);
virtual void input_text_key_callback(const InputManager::KeyCallbackArgs& key);
virtual void input_text_callback(const InputManager::TextCallbackArgs& text);
virtual void input_key_callback(const InputManager::KeyCallbackArgs& key);
virtual void input_mouse_button_on_canvas_callback(const InputManager::MouseButtonCallbackArgs& button, bool isDraggingPoint);
virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion, bool isDraggingPoint);
virtual ~DrawingProgramEditToolBase();
protected:
DrawingProgram& drawP;
CanvasComponentContainer::ObjInfo* comp;
};

View file

@ -12,19 +12,19 @@
#include "../../../GUIStuff/ElementHelpers/LayoutHelpers.hpp"
#include "../../../GUIStuff/ElementHelpers/NumberSliderHelpers.hpp"
EllipseDrawEditTool::EllipseDrawEditTool(DrawingProgram& initDrawP):
DrawingProgramEditToolBase(initDrawP)
EllipseDrawEditTool::EllipseDrawEditTool(DrawingProgram& initDrawP, CanvasComponentContainer::ObjInfo* initComp):
DrawingProgramEditToolBase(initDrawP, initComp)
{}
void EllipseDrawEditTool::edit_gui(CanvasComponentContainer::ObjInfo* comp) {
void EllipseDrawEditTool::edit_gui() {
using namespace GUIStuff;
using namespace ElementHelpers;
auto& a = static_cast<EllipseCanvasComponent&>(comp->obj->get_comp());
auto& gui = drawP.world.main.g.gui;
Toolbar& t = drawP.world.main.toolbar;
auto commit_update_func = [&, comp] { comp->obj->commit_update(drawP); };
auto commit_update_and_layout_func = [&, comp] {
auto commit_update_func = [&] { comp->obj->commit_update(drawP); };
auto commit_update_and_layout_func = [&] {
comp->obj->commit_update(drawP);
drawP.world.main.g.gui.set_to_layout();
};
@ -52,7 +52,7 @@ void EllipseDrawEditTool::edit_gui(CanvasComponentContainer::ObjInfo* comp) {
});
}
void EllipseDrawEditTool::edit_start(EditTool& editTool, CanvasComponentContainer::ObjInfo* comp, std::any& prevData) {
void EllipseDrawEditTool::edit_start(EditTool& editTool, std::any& prevData) {
auto& a = static_cast<EllipseCanvasComponent&>(comp->obj->get_comp());
prevData = a.d;
@ -60,9 +60,9 @@ void EllipseDrawEditTool::edit_start(EditTool& editTool, CanvasComponentContaine
editTool.add_point_handle({&a.d.p2, &a.d.p1, nullptr});
}
void EllipseDrawEditTool::commit_edit_updates(CanvasComponentContainer::ObjInfo* comp, std::any& prevData) {
void EllipseDrawEditTool::commit_edit_updates(std::any& prevData) {
}
bool EllipseDrawEditTool::edit_update(CanvasComponentContainer::ObjInfo* comp) {
bool EllipseDrawEditTool::edit_update() {
return true;
}

View file

@ -9,11 +9,11 @@ class DrawingProgram;
class EllipseDrawEditTool : public DrawingProgramEditToolBase {
public:
EllipseDrawEditTool(DrawingProgram& initDrawP);
virtual void edit_start(EditTool& editTool, CanvasComponentContainer::ObjInfo* comp, std::any& prevData) override;
virtual void commit_edit_updates(CanvasComponentContainer::ObjInfo* comp, std::any& prevData) override;
virtual bool edit_update(CanvasComponentContainer::ObjInfo* comp) override;
virtual void edit_gui(CanvasComponentContainer::ObjInfo* comp) override;
EllipseDrawEditTool(DrawingProgram& initDrawP, CanvasComponentContainer::ObjInfo* initComp);
virtual void edit_start(EditTool& editTool, std::any& prevData) override;
virtual void commit_edit_updates(std::any& prevData) override;
virtual bool edit_update() override;
virtual void edit_gui() override;
private:
void commit();

View file

@ -17,11 +17,11 @@
#include <EmscriptenHelpers/emscripten_browser_file.h>
#endif
ImageEditTool::ImageEditTool(DrawingProgram& initDrawP):
DrawingProgramEditToolBase(initDrawP)
ImageEditTool::ImageEditTool(DrawingProgram& initDrawP, CanvasComponentContainer::ObjInfo* initComp):
DrawingProgramEditToolBase(initDrawP, initComp)
{}
void ImageEditTool::edit_start(EditTool& editTool, CanvasComponentContainer::ObjInfo* comp, std::any& prevData) {
void ImageEditTool::edit_start(EditTool& editTool, std::any& prevData) {
auto& a = static_cast<ImageCanvasComponent&>(comp->obj->get_comp());
static Vector2f staticZero = {0.0f, 0.0f};
static Vector2f staticOne = {1.0f, 1.0f};
@ -36,17 +36,17 @@ void ImageEditTool::edit_start(EditTool& editTool, CanvasComponentContainer::Obj
comp->obj->commit_update(drawP);
}
void ImageEditTool::commit_edit_updates(CanvasComponentContainer::ObjInfo* comp, std::any& prevData) {
void ImageEditTool::commit_edit_updates(std::any& prevData) {
auto& a = static_cast<ImageCanvasComponent&>(comp->obj->get_comp());
a.d.editing = false;
comp->obj->commit_update(drawP);
}
bool ImageEditTool::edit_update(CanvasComponentContainer::ObjInfo* comp) {
bool ImageEditTool::edit_update() {
return true;
}
void ImageEditTool::edit_gui(CanvasComponentContainer::ObjInfo* comp) {
void ImageEditTool::edit_gui() {
using namespace GUIStuff;
using namespace ElementHelpers;

View file

@ -6,9 +6,9 @@ class DrawingProgram;
class ImageEditTool : public DrawingProgramEditToolBase {
public:
ImageEditTool(DrawingProgram& initDrawP);
virtual void edit_start(EditTool& editTool, CanvasComponentContainer::ObjInfo* comp, std::any& prevData) override;
virtual void commit_edit_updates(CanvasComponentContainer::ObjInfo* comp, std::any& prevData) override;
virtual bool edit_update(CanvasComponentContainer::ObjInfo* comp) override;
virtual void edit_gui(CanvasComponentContainer::ObjInfo* comp) override;
ImageEditTool(DrawingProgram& initDrawP, CanvasComponentContainer::ObjInfo* initComp);
virtual void edit_start(EditTool& editTool, std::any& prevData) override;
virtual void commit_edit_updates(std::any& prevData) override;
virtual bool edit_update() override;
virtual void edit_gui() override;
};

View file

@ -9,20 +9,20 @@
#include "../../../GUIStuff/ElementHelpers/TextLabelHelpers.hpp"
#include "../../../GUIStuff/ElementHelpers/RadioButtonHelpers.hpp"
RectDrawEditTool::RectDrawEditTool(DrawingProgram& initDrawP):
DrawingProgramEditToolBase(initDrawP)
RectDrawEditTool::RectDrawEditTool(DrawingProgram& initDrawP, CanvasComponentContainer::ObjInfo* initComp):
DrawingProgramEditToolBase(initDrawP, initComp)
{}
void RectDrawEditTool::edit_gui(CanvasComponentContainer::ObjInfo* comp) {
void RectDrawEditTool::edit_gui() {
using namespace GUIStuff;
using namespace ElementHelpers;
auto& a = static_cast<RectangleCanvasComponent&>(comp->obj->get_comp());
auto commit_update_and_layout_func = [&, comp] {
auto commit_update_and_layout_func = [&] {
comp->obj->commit_update(drawP);
drawP.world.main.g.gui.set_to_layout();
};
auto commit_update_func = [&, comp] { comp->obj->commit_update(drawP); };
auto commit_update_func = [&] { comp->obj->commit_update(drawP); };
Toolbar& t = drawP.world.main.toolbar;
auto& gui = drawP.world.main.g.gui;
@ -50,16 +50,16 @@ void RectDrawEditTool::edit_gui(CanvasComponentContainer::ObjInfo* comp) {
});
}
void RectDrawEditTool::edit_start(EditTool& editTool, CanvasComponentContainer::ObjInfo* comp, std::any& prevData) {
void RectDrawEditTool::edit_start(EditTool& editTool, std::any& prevData) {
auto& a = static_cast<RectangleCanvasComponent&>(comp->obj->get_comp());
prevData = a.d;
editTool.add_point_handle({&a.d.p1, nullptr, &a.d.p2});
editTool.add_point_handle({&a.d.p2, &a.d.p1, nullptr});
}
void RectDrawEditTool::commit_edit_updates(CanvasComponentContainer::ObjInfo* comp, std::any& prevData) {
void RectDrawEditTool::commit_edit_updates(std::any& prevData) {
}
bool RectDrawEditTool::edit_update(CanvasComponentContainer::ObjInfo* comp) {
bool RectDrawEditTool::edit_update() {
return true;
}

View file

@ -8,11 +8,11 @@ class DrawingProgram;
class RectDrawEditTool : public DrawingProgramEditToolBase {
public:
RectDrawEditTool(DrawingProgram& initDrawP);
virtual void edit_start(EditTool& editTool, CanvasComponentContainer::ObjInfo* comp, std::any& prevData) override;
virtual void commit_edit_updates(CanvasComponentContainer::ObjInfo* comp, std::any& prevData) override;
virtual bool edit_update(CanvasComponentContainer::ObjInfo* comp) override;
virtual void edit_gui(CanvasComponentContainer::ObjInfo* comp) override;
RectDrawEditTool(DrawingProgram& initDrawP, CanvasComponentContainer::ObjInfo* initComp);
virtual void edit_start(EditTool& editTool, std::any& prevData) override;
virtual void commit_edit_updates(std::any& prevData) override;
virtual bool edit_update() override;
virtual void edit_gui() override;
private:
std::optional<RectangleCanvasComponent::Data> oldData;
};

View file

@ -16,89 +16,137 @@
#include "../../../GUIStuff/ElementHelpers/TextLabelHelpers.hpp"
#include "../../../GUIStuff/ElementHelpers/LayoutHelpers.hpp"
#include "../../../GUIStuff/ElementHelpers/ButtonHelpers.hpp"
#include "../../../GUIStuff/ElementHelpers/NumberSliderHelpers.hpp"
#include "../../../GUIStuff/Elements/PositionAdjustingPopupMenu.hpp"
using namespace RichText;
TextBoxEditTool::TextBoxEditTool(DrawingProgram& initDrawP):
DrawingProgramEditToolBase(initDrawP)
TextBoxEditTool::TextBoxEditTool(DrawingProgram& initDrawP, CanvasComponentContainer::ObjInfo* initComp):
DrawingProgramEditToolBase(initDrawP, initComp)
{}
void TextBoxEditTool::edit_gui(CanvasComponentContainer::ObjInfo* comp) {
void TextBoxEditTool::commit_update_func() {
comp->obj->commit_update(drawP);
}
void TextBoxEditTool::commit_update_and_layout_func() {
comp->obj->commit_update(drawP);
drawP.world.main.g.gui.set_to_layout();
}
void TextBoxEditTool::edit_gui() {
using namespace GUIStuff;
using namespace ElementHelpers;
auto& a = static_cast<TextBoxCanvasComponent&>(comp->obj->get_comp());
Toolbar& t = drawP.world.main.toolbar;
auto& gui = drawP.world.main.g.gui;
auto& currentMods = *currentModsPtr;
gui.new_id("edit tool text", [&] {
text_label_centered(gui, "Edit Text");
left_to_right_line_layout(gui, [&] {
text_label(gui, "Font");
//if(gui.font_picker("font picker", &newFontName)) {
// currentMods[TextStyleModifier::ModifierType::FONT_FAMILIES] = std::make_shared<FontFamiliesTextStyleModifier>(std::vector<SkString>{SkString{newFontName.c_str(), newFontName.size()}});
// add_undo_if_selecting_area(a, [&]() {a.textBox->set_text_style_modifier_between(a.cursor->selectionBeginPos, a.cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::FONT_FAMILIES]);});
//}
});
//left_to_right_line_layout(gui, [&] {
// text_label(gui, "Font");
// if(gui.font_picker("font picker", &newFontName)) {
// currentMods[TextStyleModifier::ModifierType::FONT_FAMILIES] = std::make_shared<FontFamiliesTextStyleModifier>(std::vector<SkString>{SkString{newFontName.c_str(), newFontName.size()}});
// add_undo_if_selecting_area(a, [&]() {a.textBox->set_text_style_modifier_between(a.cursor->selectionBeginPos, a.cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::FONT_FAMILIES]);});
// }
//});
//left_to_right_line_centered_layout(gui, [&] {
// if(svg_icon_button("Bold button", "data/icons/RemixIcon/bold.svg", newIsBold)) {
// newIsBold = !newIsBold;
// currentMods[TextStyleModifier::ModifierType::WEIGHT] = std::make_shared<WeightTextStyleModifier>(newIsBold ? SkFontStyle::Weight::kBold_Weight : SkFontStyle::Weight::kNormal_Weight);
// add_undo_if_selecting_area(a, [&]() {a.textBox->set_text_style_modifier_between(a.cursor->selectionBeginPos, a.cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::WEIGHT]);});
// }
left_to_right_line_centered_layout(gui, [&] {
svg_icon_button(gui, "Bold button", "data/icons/RemixIcon/bold.svg", {
.isSelected = newIsBold,
.onClick = [&] {
newIsBold = !newIsBold;
currentMods[TextStyleModifier::ModifierType::WEIGHT] = std::make_shared<WeightTextStyleModifier>(newIsBold ? SkFontStyle::Weight::kBold_Weight : SkFontStyle::Weight::kNormal_Weight);
add_undo_if_selecting_area(a, [&]() {a.textBox->set_text_style_modifier_between(a.cursor->selectionBeginPos, a.cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::WEIGHT]);});
commit_update_func();
}
});
// if(gui.svg_icon_button("Italic button", "data/icons/RemixIcon/italic.svg", newIsItalic)) {
// newIsItalic = !newIsItalic;
// currentMods[TextStyleModifier::ModifierType::SLANT] = std::make_shared<SlantTextStyleModifier>(newIsItalic ? SkFontStyle::Slant::kItalic_Slant : SkFontStyle::Slant::kUpright_Slant);
// add_undo_if_selecting_area(a, [&]() {a.textBox->set_text_style_modifier_between(a.cursor->selectionBeginPos, a.cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::SLANT]);});
// }
svg_icon_button(gui, "Italic button", "data/icons/RemixIcon/italic.svg", {
.isSelected = newIsItalic,
.onClick = [&] {
newIsItalic = !newIsItalic;
currentMods[TextStyleModifier::ModifierType::SLANT] = std::make_shared<SlantTextStyleModifier>(newIsItalic ? SkFontStyle::Slant::kItalic_Slant : SkFontStyle::Slant::kUpright_Slant);
add_undo_if_selecting_area(a, [&]() {a.textBox->set_text_style_modifier_between(a.cursor->selectionBeginPos, a.cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::SLANT]);});
commit_update_func();
}
});
// bool decorationEdited = false;
// if(gui.svg_icon_button("Underline button", "data/icons/RemixIcon/underline.svg", newIsUnderlined)) {
// newIsUnderlined = !newIsUnderlined;
// decorationEdited = true;
// }
// if(gui.svg_icon_button("Strikethrough button", "data/icons/RemixIcon/strikethrough.svg", newIsLinethrough)) {
// newIsLinethrough = !newIsLinethrough;
// decorationEdited = true;
// }
// if(gui.svg_icon_button("Overline button", "data/icons/RemixIcon/overline.svg", newIsOverline)) {
// newIsOverline = !newIsOverline;
// decorationEdited = true;
// }
// if(decorationEdited) {
// currentMods[TextStyleModifier::ModifierType::DECORATION] = std::make_shared<DecorationTextStyleModifier>(get_new_decoration_value());
// add_undo_if_selecting_area(a, [&]() {a.textBox->set_text_style_modifier_between(a.cursor->selectionBeginPos, a.cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::DECORATION]);});
// }
//});
auto decorationChange = [&] {
currentMods[TextStyleModifier::ModifierType::DECORATION] = std::make_shared<DecorationTextStyleModifier>(get_new_decoration_value());
add_undo_if_selecting_area(a, [&]() {a.textBox->set_text_style_modifier_between(a.cursor->selectionBeginPos, a.cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::DECORATION]);});
commit_update_func();
};
//gui.left_to_right_line_centered_layout([&]() {
// if(gui.svg_icon_button("Align left button", "data/icons/RemixIcon/align-left.svg", currentPStyle.textAlignment == skia::textlayout::TextAlign::kLeft))
// add_undo([&](){a.textBox->set_text_alignment_between(a.cursor->selectionBeginPos.fParagraphIndex, a.cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextAlign::kLeft);});
// if(gui.svg_icon_button("Align center button", "data/icons/RemixIcon/align-center.svg", currentPStyle.textAlignment == skia::textlayout::TextAlign::kCenter))
// add_undo([&](){a.textBox->set_text_alignment_between(a.cursor->selectionBeginPos.fParagraphIndex, a.cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextAlign::kCenter);});
// if(gui.svg_icon_button("Align right button", "data/icons/RemixIcon/align-right.svg", currentPStyle.textAlignment == skia::textlayout::TextAlign::kRight))
// add_undo([&](){a.textBox->set_text_alignment_between(a.cursor->selectionBeginPos.fParagraphIndex, a.cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextAlign::kRight);});
// if(gui.svg_icon_button("Align justify button", "data/icons/RemixIcon/align-justify.svg", currentPStyle.textAlignment == skia::textlayout::TextAlign::kJustify))
// add_undo([&](){a.textBox->set_text_alignment_between(a.cursor->selectionBeginPos.fParagraphIndex, a.cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextAlign::kJustify);});
// if(gui.svg_icon_button("Text direction left", "data/icons/RemixIcon/text-direction-l.svg", currentPStyle.textDirection == skia::textlayout::TextDirection::kLtr))
// add_undo([&](){a.textBox->set_text_direction_between(a.cursor->selectionBeginPos.fParagraphIndex, a.cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextDirection::kLtr);});
// if(gui.svg_icon_button("Text direction right", "data/icons/RemixIcon/text-direction-r.svg", currentPStyle.textDirection == skia::textlayout::TextDirection::kRtl))
// add_undo([&](){a.textBox->set_text_direction_between(a.cursor->selectionBeginPos.fParagraphIndex, a.cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextDirection::kRtl);});
//});
svg_icon_button(gui, "Underline button", "data/icons/RemixIcon/underline.svg", {
.isSelected = newIsUnderlined,
.onClick = [&, decorationChange] {
newIsUnderlined = !newIsUnderlined;
decorationChange();
}
});
//if(gui.slider_scalar_field<uint32_t>("Font Size Slider", "Font Size", &newFontSize, 3, 100)) {
// hold_undo_data("Font Size", a);
// currentMods[TextStyleModifier::ModifierType::SIZE] = std::make_shared<SizeTextStyleModifier>(newFontSize);
// a.textBox->set_text_style_modifier_between(a.cursor->selectionBeginPos, a.cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::SIZE]);
//}
//else
// release_undo_data("Font Size");
svg_icon_button(gui, "Strikethrough button", "data/icons/RemixIcon/strikethrough.svg", {
.isSelected = newIsLinethrough,
.onClick = [&, decorationChange] {
newIsLinethrough = !newIsLinethrough;
decorationChange();
}
});
svg_icon_button(gui, "Overline button", "data/icons/RemixIcon/overline.svg", {
.isSelected = newIsOverline,
.onClick = [&, decorationChange] {
newIsOverline = !newIsOverline;
decorationChange();
}
});
});
left_to_right_line_centered_layout(gui, [&]() {
auto paragraph_operation_button = [&](const char* id, const char* svgPath, bool isSelected, const std::function<void()>& func) {
svg_icon_button(gui, id, svgPath, {
.isSelected = isSelected,
.onClick = [&, func] {
add_undo(func);
commit_update_func();
}
});
};
paragraph_operation_button("Align left button", "data/icons/RemixIcon/align-left.svg", currentPStyle.textAlignment == skia::textlayout::TextAlign::kLeft, [&] {
a.textBox->set_text_alignment_between(a.cursor->selectionBeginPos.fParagraphIndex, a.cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextAlign::kLeft);
});
paragraph_operation_button("Align center button", "data/icons/RemixIcon/align-center.svg", currentPStyle.textAlignment == skia::textlayout::TextAlign::kCenter, [&] {
a.textBox->set_text_alignment_between(a.cursor->selectionBeginPos.fParagraphIndex, a.cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextAlign::kCenter);
});
paragraph_operation_button("Align right button", "data/icons/RemixIcon/align-right.svg", currentPStyle.textAlignment == skia::textlayout::TextAlign::kRight, [&] {
a.textBox->set_text_alignment_between(a.cursor->selectionBeginPos.fParagraphIndex, a.cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextAlign::kRight);
});
paragraph_operation_button("Align justify button", "data/icons/RemixIcon/align-justify.svg", currentPStyle.textAlignment == skia::textlayout::TextAlign::kJustify, [&] {
a.textBox->set_text_alignment_between(a.cursor->selectionBeginPos.fParagraphIndex, a.cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextAlign::kJustify);
});
paragraph_operation_button("Text direction left button", "data/icons/RemixIcon/text-direction-l.svg", currentPStyle.textDirection == skia::textlayout::TextDirection::kLtr, [&] {
a.textBox->set_text_direction_between(a.cursor->selectionBeginPos.fParagraphIndex, a.cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextDirection::kLtr);
});
paragraph_operation_button("Text direction right button", "data/icons/RemixIcon/text-direction-r.svg", currentPStyle.textDirection == skia::textlayout::TextDirection::kRtl, [&] {
a.textBox->set_text_direction_between(a.cursor->selectionBeginPos.fParagraphIndex, a.cursor->selectionEndPos.fParagraphIndex, skia::textlayout::TextDirection::kRtl);
});
});
slider_scalar_field<uint32_t>(gui, "Font Size Slider", "Font Size", &newFontSize, 3, 100, TextBoxScalarOptions{
.onEdit = [&] {
currentMods[TextStyleModifier::ModifierType::SIZE] = std::make_shared<SizeTextStyleModifier>(newFontSize);
a.textBox->set_text_style_modifier_between(a.cursor->selectionBeginPos, a.cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::SIZE]);
commit_update_func();
},
.onSelect = [&] { hold_undo_data("Font Size", a); },
.onDeselect = [&] { release_undo_data("Font Size"); }
});
//// Text color
//gui.left_to_right_line_layout([&]() {
@ -117,8 +165,6 @@ void TextBoxEditTool::edit_gui(CanvasComponentContainer::ObjInfo* comp) {
// a.textBox->set_text_style_modifier_between(a.cursor->selectionBeginPos, a.cursor->selectionEndPos, currentMods[TextStyleModifier::ModifierType::COLOR]);
//}
//// Highlight color
//gui.left_to_right_line_layout([&]() {
// if(gui.color_button_big("Highlight Color", &newHighlightColor, &newHighlightColor == t.colorRight)) {
@ -160,10 +206,37 @@ void TextBoxEditTool::edit_gui(CanvasComponentContainer::ObjInfo* comp) {
//return oldInputChangedTextBox;
}
void TextBoxEditTool::input_key_callback(CanvasComponentContainer::ObjInfo* comp, const InputManager::KeyCallbackArgs& key) {
void TextBoxEditTool::input_paste_callback(const CustomEvents::PasteEventData& paste) {
if(textboxID.has_value() && textboxID.value() == drawP.world.main.input.text.current_textbox_editing_id()) {
auto& a = static_cast<TextBoxCanvasComponent&>(comp->obj->get_comp());
if(userInput->input_paste_callback(paste)) {
commit_update_and_layout_func();
set_styles_at_selection(a);
}
}
}
void TextBoxEditTool::input_mouse_button_on_canvas_callback(CanvasComponentContainer::ObjInfo* comp, const InputManager::MouseButtonCallbackArgs& button, bool isDraggingPoint) {
void TextBoxEditTool::input_text_key_callback(const InputManager::KeyCallbackArgs& key) {
if(textboxID.has_value() && textboxID.value() == drawP.world.main.input.text.current_textbox_editing_id()) {
auto& a = static_cast<TextBoxCanvasComponent&>(comp->obj->get_comp());
auto changes = userInput->input_key_callback(drawP.world.main.input, key);
if(changes.textEdited || changes.cursorChanged) {
commit_update_and_layout_func();
set_styles_at_selection(a);
}
}
}
void TextBoxEditTool::input_text_callback(const InputManager::TextCallbackArgs& text) {
if(textboxID.has_value() && textboxID.value() == drawP.world.main.input.text.current_textbox_editing_id()) {
auto& a = static_cast<TextBoxCanvasComponent&>(comp->obj->get_comp());
userInput->add_text_to_textbox(text.str);
commit_update_and_layout_func();
set_styles_at_selection(a);
}
}
void TextBoxEditTool::input_mouse_button_on_canvas_callback(const InputManager::MouseButtonCallbackArgs& button, bool isDraggingPoint) {
if(button.button == InputManager::MouseButton::LEFT && !isDraggingPoint) {
auto& a = static_cast<TextBoxCanvasComponent&>(comp->obj->get_comp());
@ -175,11 +248,16 @@ void TextBoxEditTool::input_mouse_button_on_canvas_callback(CanvasComponentConta
bool collidesWithBox = comp->obj->collides_with_cam_coords(drawP.world.drawData.cam.c, mousePointCollection);
auto oldCursor = *a.cursor;
a.textBox->process_mouse_left_button(*a.cursor, a.get_mouse_pos(drawP), (button.down && button.clicks && collidesWithBox) ? button.clicks : 0, button.down, input.key(InputManager::KEY_GENERIC_LSHIFT).held);
if(oldCursor != *a.cursor) {
set_styles_at_selection(a);
commit_update_and_layout_func();
}
}
}
void TextBoxEditTool::input_mouse_motion_callback(CanvasComponentContainer::ObjInfo* comp, const InputManager::MouseMotionCallbackArgs& motion, bool isDraggingPoint) {
void TextBoxEditTool::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion, bool isDraggingPoint) {
auto& a = static_cast<TextBoxCanvasComponent&>(comp->obj->get_comp());
a.init_text_box(drawP);
@ -192,11 +270,16 @@ void TextBoxEditTool::input_mouse_motion_callback(CanvasComponentContainer::ObjI
InputManager& input = drawP.world.main.input;
auto oldCursor = *a.cursor;
a.textBox->process_mouse_left_button(*a.cursor, a.get_mouse_pos(drawP), 0, drawP.controls.leftClickHeld, input.key(InputManager::KEY_GENERIC_LSHIFT).held);
if(oldCursor != *a.cursor) {
set_styles_at_selection(a);
commit_update_and_layout_func();
}
}
}
void TextBoxEditTool::right_click_popup_gui(CanvasComponentContainer::ObjInfo* comp, Vector2f popupPos) {
void TextBoxEditTool::right_click_popup_gui(Vector2f popupPos) {
using namespace GUIStuff;
using namespace ElementHelpers;
@ -241,8 +324,7 @@ void TextBoxEditTool::release_undo_data(const std::string& undoName) {
auto it = undoHeldData.find(undoName);
if(it != undoHeldData.end()) {
std::pair<RichText::TextBox::Cursor, RichText::TextData>& undoData = it->second;
InputManager& input = drawP.world.main.input;
//input.text.add_textbox_undo(undoData.first, undoData.second);
userInput->add_textbox_undo(undoData.first, undoData.second);
undoHeldData.erase(it);
}
}
@ -250,15 +332,12 @@ void TextBoxEditTool::release_undo_data(const std::string& undoName) {
void TextBoxEditTool::add_undo_if_selecting_area(TextBoxCanvasComponent& a, const std::function<void()>& func) {
if(a.cursor->selectionBeginPos == a.cursor->selectionEndPos)
func();
else {
InputManager& input = drawP.world.main.input;
//input.text.do_textbox_operation_with_undo(func);
}
else
userInput->do_textbox_operation_with_undo(func);
}
void TextBoxEditTool::add_undo(const std::function<void()>& func) {
InputManager& input = drawP.world.main.input;
//input.text.do_textbox_operation_with_undo(func);
userInput->do_textbox_operation_with_undo(func);
}
uint8_t TextBoxEditTool::get_new_decoration_value() {
@ -295,11 +374,12 @@ void TextBoxEditTool::set_styles_at_selection(TextBoxCanvasComponent& a) {
currentPStyle = a.textBox->get_paragraph_style_data_at(start.fParagraphIndex);
}
void TextBoxEditTool::commit_edit_updates(CanvasComponentContainer::ObjInfo* comp, std::any& prevData) {
void TextBoxEditTool::commit_edit_updates(std::any& prevData) {
auto& a = static_cast<TextBoxCanvasComponent&>(comp->obj->get_comp());
a.d.editing = false;
comp->obj->commit_update(drawP);
//drawP.world.main.input.remove_rich_text_box_input(a.textBox);
if(textboxID.has_value())
drawP.world.main.input.remove_text_box(textboxID.value());
}
TextBoxEditTool::TextBoxEditToolAllData TextBoxEditTool::get_all_data(const TextBoxCanvasComponent& a) {
@ -309,7 +389,7 @@ TextBoxEditTool::TextBoxEditToolAllData TextBoxEditTool::get_all_data(const Text
};
}
void TextBoxEditTool::edit_start(EditTool& editTool, CanvasComponentContainer::ObjInfo* comp, std::any& prevData) {
void TextBoxEditTool::edit_start(EditTool& editTool, std::any& prevData) {
auto& a = static_cast<TextBoxCanvasComponent&>(comp->obj->get_comp());
auto& cur = a.cursor;
auto& textbox = a.textBox;
@ -321,7 +401,6 @@ void TextBoxEditTool::edit_start(EditTool& editTool, CanvasComponentContainer::O
textbox->process_mouse_left_button(*cur, textSelectPos, 1, false, false);
prevData = get_all_data(a);
a.d.editing = true;
a.textBox->inputChangedTextBox = true;
set_styles_at_selection(a);
@ -330,15 +409,16 @@ void TextBoxEditTool::edit_start(EditTool& editTool, CanvasComponentContainer::O
comp->obj->commit_update(drawP);
//drawP.world.main.input.set_rich_text_box_input_back(a.textBox, a.cursor, true, nullptr, {
// .inputType = SDL_TextInputType::SDL_TEXTINPUT_TYPE_TEXT,
// .capitalization = SDL_Capitalization::SDL_CAPITALIZE_NONE,
// .autocorrect = true,
// .multiline = true,
// .androidInputType = InputManager::AndroidInputType::ANDROIDTEXT_TYPE_CLASS_TEXT
//}, currentModsPtr);
userInput = std::make_unique<RichTextUserInput>(textbox, cur, currentModsPtr);
textboxID = drawP.world.main.input.set_text_box_back(std::nullopt, {
.inputType = SDL_TextInputType::SDL_TEXTINPUT_TYPE_TEXT,
.capitalization = SDL_Capitalization::SDL_CAPITALIZE_NONE,
.autocorrect = true,
.multiline = true,
.androidInputType = InputManager::AndroidInputType::ANDROIDTEXT_TYPE_CLASS_TEXT
});
}
bool TextBoxEditTool::edit_update(CanvasComponentContainer::ObjInfo* comp) {
bool TextBoxEditTool::edit_update() {
return true;
}

View file

@ -3,23 +3,29 @@
#include "DrawingProgramEditToolBase.hpp"
#include <Helpers/SCollision.hpp>
#include <any>
#include "../../../RichTextUserInput.hpp"
class DrawingProgram;
class TextBoxEditTool : public DrawingProgramEditToolBase {
public:
TextBoxEditTool(DrawingProgram& initDrawP);
TextBoxEditTool(DrawingProgram& initDrawP, CanvasComponentContainer::ObjInfo* initComp);
virtual void edit_start(EditTool& editTool,CanvasComponentContainer::ObjInfo* comp, std::any& prevData) override;
virtual void commit_edit_updates(CanvasComponentContainer::ObjInfo* comp, std::any& prevData) override;
virtual bool edit_update(CanvasComponentContainer::ObjInfo* comp) override;
virtual void edit_gui(CanvasComponentContainer::ObjInfo* comp) override;
virtual void right_click_popup_gui(CanvasComponentContainer::ObjInfo* comp, Vector2f popupPos) override;
virtual void edit_start(EditTool& editTool, std::any& prevData) override;
virtual void commit_edit_updates(std::any& prevData) override;
virtual bool edit_update() override;
virtual void edit_gui() override;
virtual void right_click_popup_gui(Vector2f popupPos) override;
virtual void input_key_callback(CanvasComponentContainer::ObjInfo* comp, const InputManager::KeyCallbackArgs& key) override;
virtual void input_mouse_button_on_canvas_callback(CanvasComponentContainer::ObjInfo* comp, const InputManager::MouseButtonCallbackArgs& button, bool isDraggingPoint) override;
virtual void input_mouse_motion_callback(CanvasComponentContainer::ObjInfo* comp, const InputManager::MouseMotionCallbackArgs& motion, bool isDraggingPoint) override;
virtual void input_paste_callback(const CustomEvents::PasteEventData& paste) override;
virtual void input_text_key_callback(const InputManager::KeyCallbackArgs& key) override;
virtual void input_text_callback(const InputManager::TextCallbackArgs& text) override;
virtual void input_mouse_button_on_canvas_callback(const InputManager::MouseButtonCallbackArgs& button, bool isDraggingPoint) override;
virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion, bool isDraggingPoint) override;
private:
std::unique_ptr<RichTextUserInput> userInput;
std::optional<unsigned> textboxID;
struct TextBoxEditToolAllData {
TextBoxCanvasComponent::Data textboxData;
RichText::TextData richText;
@ -44,6 +50,9 @@ class TextBoxEditTool : public DrawingProgramEditToolBase {
void hold_undo_data(const std::string& undoName, TextBoxCanvasComponent& a);
void release_undo_data(const std::string& undoName);
void commit_update_func();
void commit_update_and_layout_func();
std::unordered_map<std::string, std::pair<RichText::TextBox::Cursor, RichText::TextData>> undoHeldData;
std::shared_ptr<RichText::TextStyleModifier::ModifierMap> currentModsPtr = std::make_shared<RichText::TextStyleModifier::ModifierMap>();

View file

@ -119,12 +119,16 @@ void GUIHolder::draw(SkCanvas* canvas, bool skiaAA) {
canvas->restore();
}
void GUIHolder::input_paste_callback(const CustomEvents::PasteEventData& paste) {
gui.input_paste_callback(paste);
}
void GUIHolder::input_text_key_callback(const InputManager::KeyCallbackArgs& key) {
gui.input_text_key_callback(key);
}
void GUIHolder::input_text_callback(const std::string& str) {
gui.input_text_callback(str);
void GUIHolder::input_text_callback(const InputManager::TextCallbackArgs& text) {
gui.input_text_callback(text);
}
void GUIHolder::input_key_callback(const InputManager::KeyCallbackArgs& key) {

View file

@ -1,5 +1,6 @@
#pragma once
#include "CustomEvents.hpp"
#include "GUIStuff/GUIManager.hpp"
class MainProgram;
@ -18,8 +19,9 @@ class GUIHolder {
void update();
void draw(SkCanvas* canvas, bool skiaAA);
void input_paste_callback(const CustomEvents::PasteEventData& paste);
void input_text_key_callback(const InputManager::KeyCallbackArgs& key);
void input_text_callback(const std::string& str);
void input_text_callback(const InputManager::TextCallbackArgs& text);
void input_key_callback(const InputManager::KeyCallbackArgs& key);
void input_text_key_callback();
void input_text_input_callback();

View file

@ -14,7 +14,11 @@ namespace GUIStuff { namespace ElementHelpers {
text_label(gui, name);
input_scalar(gui, "textbox", val, min, max, options);
});
gui.element<NumberSlider<T>>("slider", val, min, max, options.onEdit);
gui.element<NumberSlider<T>>("slider", val, min, max, NumberSliderData{
.onChange = options.onEdit,
.onHold = options.onSelect,
.onRelease = options.onDeselect
});
});
}
}}

View file

@ -12,6 +12,8 @@ template <typename T, typename OptT> TextBoxData<T> textbox_options_to_data(cons
toRet.onEnter = options.onEnter;
toRet.onEdit = options.onEdit;
toRet.immutable = options.immutable;
toRet.onSelect = options.onSelect;
toRet.onDeselect = options.onDeselect;
return toRet;
}
@ -20,6 +22,8 @@ struct TextBoxOptions {
bool immutable = false;
std::function<void()> onEnter;
std::function<void()> onEdit;
std::function<void()> onSelect;
std::function<void()> onDeselect;
};
struct TextBoxScalarOptions {
@ -28,6 +32,8 @@ struct TextBoxScalarOptions {
bool immutable = false;
std::function<void()> onEnter;
std::function<void()> onEdit;
std::function<void()> onSelect;
std::function<void()> onDeselect;
};
struct TextBoxPathOptions {
@ -36,6 +42,8 @@ struct TextBoxPathOptions {
bool immutable = false;
std::function<void()> onEnter;
std::function<void()> onEdit;
std::function<void()> onSelect;
std::function<void()> onDeselect;
};
struct TextBoxHexColorOptions {
@ -44,6 +52,8 @@ struct TextBoxHexColorOptions {
bool immutable = false;
std::function<void()> onEnter;
std::function<void()> onEdit;
std::function<void()> onSelect;
std::function<void()> onDeselect;
};
void input_color_component_255(GUIManager& gui, const char* id, float* val, const TextBoxOptions& options = {});

View file

@ -6,8 +6,9 @@ namespace GUIStuff {
void Element::tick_update() {}
void Element::input_paste_callback(const CustomEvents::PasteEventData& paste) { }
void Element::input_text_key_callback(const InputManager::KeyCallbackArgs& key) { }
void Element::input_text_callback(const std::string& str) { }
void Element::input_text_callback(const InputManager::TextCallbackArgs& text) { }
void Element::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) { }
void Element::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) { }
void Element::input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel) { }

View file

@ -24,9 +24,9 @@ namespace GUIStuff {
virtual void tick_update();
// Return true when mouse obstructs what's behind it
virtual void input_paste_callback(const CustomEvents::PasteEventData& paste);
virtual void input_text_key_callback(const InputManager::KeyCallbackArgs& key);
virtual void input_text_callback(const std::string& str);
virtual void input_text_callback(const InputManager::TextCallbackArgs& text);
virtual void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button);
virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion);
virtual void input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel);

View file

@ -4,16 +4,23 @@
namespace GUIStuff {
struct NumberSliderData {
std::function<void()> onChange;
std::function<void()> onHold;
std::function<void()> onRelease;
};
template <typename T> class NumberSlider : public Element {
public:
NumberSlider(GUIManager& gui):
Element(gui) {}
void layout(const Clay_ElementId& id, T* data, T minData, T maxData, const std::function<void()>& onChange) {
void layout(const Clay_ElementId& id, T* data, T minData, T maxData, const NumberSliderData& config) {
this->data = data;
this->minData = minData;
this->maxData = maxData;
this->onChange = onChange;
this->config = config;
CLAY(id, {
.layout = {
@ -74,22 +81,29 @@ template <typename T> class NumberSlider : public Element {
canvas->restore();
}
virtual void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) override {
bool oldIsHeld = isHeld;
isHeld = mouseHovering && button.button == InputManager::MouseButton::LEFT && button.down;
if(isHeld && boundingBox.has_value())
update_slider_pos(button.pos);
if(oldIsHeld && !isHeld) {
gui.set_post_callback_func([&] {
if(config.onRelease) config.onRelease();
});
}
else if(isHeld && boundingBox.has_value())
update_slider_pos(button.pos, true);
}
virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) override {
if(isHeld && boundingBox.has_value())
update_slider_pos(motion.pos);
update_slider_pos(motion.pos, false);
}
private:
void update_slider_pos(const Vector2f& p) {
gui.set_post_callback_func([&, p] {
void update_slider_pos(const Vector2f& p, bool justHeld) {
gui.set_post_callback_func([&, p, justHeld] {
float fracPosOnSlider = (p.x() - boundingBox.value().min.x()) / boundingBox.value().width();
*data = static_cast<T>(std::clamp<double>(std::lerp<double>(minData, maxData, fracPosOnSlider), minData, maxData)); // Clamp as double then cast so that unsigned types dont wrap on clamp
if(onChange) onChange();
if(justHeld && config.onHold) config.onHold();
if(config.onChange) config.onChange();
});
}
@ -97,7 +111,7 @@ template <typename T> class NumberSlider : public Element {
T* data = nullptr;
T minData = 0.0;
T maxData = 1.0;
std::function<void()> onChange;
NumberSliderData config;
float hoverAnimation = 0.0;
float holdAnimation = 0.0;

View file

@ -19,13 +19,15 @@ template <typename T> struct TextBoxData {
InputManager::TextInputProperties textInputProps;
std::function<void()> onEdit;
std::function<void()> onEnter;
std::function<void()> onSelect;
std::function<void()> onDeselect;
};
struct TextEditData {
TextEditData(unsigned initTextboxInputID, const std::shared_ptr<RichText::TextBox>& initTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& initCursor, const std::function<void()>& onTextEdit):
TextEditData(unsigned initTextboxInputID, const std::shared_ptr<RichText::TextBox>& initTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& initCursor):
textboxInputID(initTextboxInputID),
userInput(initTextBox, initCursor, nullptr, onTextEdit)
userInput(initTextBox, initCursor, nullptr)
{}
unsigned textboxInputID;
RichTextUserInput userInput;
@ -37,12 +39,14 @@ template <typename T> class TextBox : public Element {
void layout(const Clay_ElementId& id, const TextBoxData<T>& userInfo);
virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) override;
virtual void input_paste_callback(const CustomEvents::PasteEventData& paste) override;
virtual void input_text_key_callback(const InputManager::KeyCallbackArgs& key) override;
virtual void input_text_callback(const std::string& str) override;
virtual void input_text_callback(const InputManager::TextCallbackArgs& text) override;
virtual void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) override;
virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) override;
~TextBox();
private:
void after_text_input_callback();
void init_textbox(UpdateInputData& io);
void reset_textbox_text();
bool update_data();

View file

@ -65,6 +65,11 @@ template <typename T> bool TextBox<T>::is_selected() const {
return edit.has_value();
}
template <typename T> void TextBox<T>::input_paste_callback(const CustomEvents::PasteEventData& paste) {
if(is_selected() && edit.value().userInput.input_paste_callback(paste))
after_text_input_callback();
}
template <typename T> void TextBox<T>::input_text_key_callback(const InputManager::KeyCallbackArgs& key) {
if(is_selected()) {
if(key.key == InputManager::KEY_GENERIC_ENTER && key.down) {
@ -75,14 +80,27 @@ template <typename T> void TextBox<T>::input_text_key_callback(const InputManage
reset_textbox_text();
});
}
else
edit.value().userInput.input_key_callback(*gui.io.input, key);
else {
if(edit.value().userInput.input_key_callback(*gui.io.input, key).textEdited)
after_text_input_callback();
}
}
}
template <typename T> void TextBox<T>::input_text_callback(const std::string& str) {
if(is_selected())
edit.value().userInput.add_text_to_textbox(str);
template <typename T> void TextBox<T>::after_text_input_callback() {
if(userInfo.immutable)
cur->pos = cur->selectionBeginPos = cur->selectionEndPos = textbox->insert({0, 0}, userInfo.toStr(*userInfo.data));
else {
if(update_data() && userInfo.onEdit)
gui.set_post_callback_func_high_priority(userInfo.onEdit);
}
}
template <typename T> void TextBox<T>::input_text_callback(const InputManager::TextCallbackArgs& text) {
if(is_selected()) {
edit.value().userInput.add_text_to_textbox(text.str);
after_text_input_callback();
}
}
template <typename T> void TextBox<T>::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) {
@ -91,22 +109,23 @@ template <typename T> void TextBox<T>::input_mouse_button_callback(const InputMa
if(button.button == InputManager::MouseButton::LEFT && boundingBox.has_value()) {
if(button.down) {
if(mouseHovering) {
SCollision::AABB<float> rect = {(boundingBox.value().min + io.windowPos) * io.guiScaleMultiplier, (boundingBox.value().max + io.windowPos) * io.guiScaleMultiplier};
unsigned id = gui.io.input->set_text_box_front(rect, userInfo.textInputProps);
if(!is_selected()) {
SCollision::AABB<float> rect = {(boundingBox.value().min + io.windowPos) * io.guiScaleMultiplier, (boundingBox.value().max + io.windowPos) * io.guiScaleMultiplier};
unsigned id = gui.io.input->set_text_box_front(rect, userInfo.textInputProps);
edit = TextEditData(id, textbox, cur);
gui.set_post_callback_func_high_priority([&] {
if(userInfo.onSelect) userInfo.onSelect();
});
}
textbox->process_mouse_left_button(*cur, button.pos - boundingBox.value().min, button.clicks, true, gui.io.input->key(InputManager::KEY_GENERIC_LSHIFT).held);
edit = TextEditData(id, textbox, cur, [&] {
if(userInfo.immutable)
cur->pos = cur->selectionBeginPos = cur->selectionEndPos = textbox->insert({0, 0}, userInfo.toStr(*userInfo.data));
else {
if(update_data() && userInfo.onEdit)
gui.set_post_callback_func_high_priority(userInfo.onEdit);
}
});
}
else if(is_selected()) {
gui.io.input->remove_text_box(edit.value().textboxInputID);
if(update_data())
gui.set_post_callback_func_high_priority(userInfo.onEdit);
gui.set_post_callback_func_high_priority([&] {
if(update_data())
if(userInfo.onEdit) userInfo.onEdit();
if(userInfo.onDeselect) userInfo.onDeselect();
});
reset_textbox_text();
edit = std::nullopt;
}

View file

@ -344,6 +344,13 @@ bool GUIManager::cursor_obstructed() const {
return cursorObstructed;
}
void GUIManager::input_paste_callback(const CustomEvents::PasteEventData& paste) {
for(ElementContainer* e : orderedElements)
e->elem->input_paste_callback(paste);
run_post_callback_func();
layout_if_necessary();
}
void GUIManager::input_text_key_callback(const InputManager::KeyCallbackArgs& key) {
for(ElementContainer* e : orderedElements)
e->elem->input_text_key_callback(key);
@ -351,9 +358,9 @@ void GUIManager::input_text_key_callback(const InputManager::KeyCallbackArgs& ke
layout_if_necessary();
}
void GUIManager::input_text_callback(const std::string& str) {
void GUIManager::input_text_callback(const InputManager::TextCallbackArgs& text) {
for(ElementContainer* e : orderedElements)
e->elem->input_text_callback(str);
e->elem->input_text_callback(text);
run_post_callback_func();
layout_if_necessary();
}

View file

@ -85,8 +85,9 @@ class GUIManager {
DefaultStringArena strArena;
void input_paste_callback(const CustomEvents::PasteEventData& paste);
void input_text_key_callback(const InputManager::KeyCallbackArgs& key);
void input_text_callback(const std::string& str);
void input_text_callback(const InputManager::TextCallbackArgs& text);
void input_key_callback(const InputManager::KeyCallbackArgs& key);
void input_mouse_button_callback(InputManager::MouseButtonCallbackArgs button);
void input_mouse_motion_callback(InputManager::MouseMotionCallbackArgs motion);

View file

@ -1,4 +1,5 @@
#include "InputManager.hpp"
#include "CustomEvents.hpp"
#include <SDL3/SDL_clipboard.h>
#include <SDL3/SDL_keyboard.h>
@ -11,6 +12,7 @@
#include <Helpers/Logger.hpp>
#ifdef _WIN32
#include <include/core/SkStream.h>
#include <include/encode/SkPngEncoder.h>
@ -126,6 +128,12 @@ bool InputManager::Text::is_accepting_input() {
return !textBoxes.empty();
}
std::optional<unsigned> InputManager::Text::current_textbox_editing_id() {
if(textBoxes.empty())
return std::nullopt;
return textBoxes.front().id;
}
void InputManager::Text::update_accepting_input(SDL_Window* window) {
if(!textBoxes.empty()) {
auto& textbox = textBoxes.front();
@ -354,8 +362,13 @@ uint32_t InputManager::make_generic_key_mod(SDL_Keymod m) {
return toRet;
}
void InputManager::backend_paste_event() {
main.input_paste_callback(CustomEvents::get_paste_event_data());
CustomEvents::pop_paste_event_data();
}
void InputManager::backend_input_text_event(const std::string& str) {
main.input_text_callback(str);
main.input_text_callback(TextCallbackArgs{ .str = str });
}
void InputManager::backend_drop_file_event(const SDL_DropEvent& e) {
@ -901,27 +914,35 @@ void InputManager::backend_key_down_update(const SDL_KeyboardEvent& e) {
set_key_down(e, f->second);
}
void InputManager::call_text_paste(const std::function<void(const TextPasteCallbackArgs&)>& pasteCallbackFunc) {
void InputManager::call_paste(CustomEvents::PasteEventDataType type, const std::optional<Vector2f>& pastePosition) {
// Workaround for not being able to copy richtext to system clipboard, this should at least work within the application itself
pasteCallback = pasteCallbackFunc;
#ifdef __EMSCRIPTEN__
emscripten_browser_clipboard::paste_async([](std::string&& pasteData, void* callbackData){
InputManager* inMan = (InputManager*)callbackData;
std::string pData = pasteData;
inMan->process_text_paste(pData);
}, this);
if(type == PasteDataType::TEXT) {
emscripten_browser_clipboard::paste_async([](std::string&& pasteData, void* callbackData){
InputManager* inMan = (InputManager*)callbackData;
std::string pData = pasteData;
inMan->process_text_paste(pData);
}, this);
}
else {
}
#else
process_text_paste(get_clipboard_str_SDL());
switch(type) {
case CustomEvents::PasteEventDataType::TEXT:
process_text_paste(get_clipboard_str_SDL());
break;
case CustomEvents::PasteEventDataType::IMAGE:
break;
}
#endif
}
void InputManager::process_text_paste(const std::string& pasteStr) {
if(lastCopiedRichText.has_value() && lastCopiedRichText.value().get_plain_text() == remove_carriage_returns_from_str(pasteStr)) {
pasteCallback({
.text = pasteStr,
.richText = lastCopiedRichText
});
}
CustomEvents::emit_paste_event({
.type = CustomEvents::PasteEventDataType::TEXT,
.data = pasteStr,
.richText = lastCopiedRichText.has_value() && lastCopiedRichText.value().get_plain_text() == remove_carriage_returns_from_str(pasteStr) ? lastCopiedRichText : std::nullopt
});
}
bool InputManager::ctrl_or_meta_held() {

View file

@ -20,6 +20,8 @@
#include <Helpers/SCollision.hpp>
#include "CustomEvents.hpp"
using namespace Eigen;
class MainProgram;
@ -155,6 +157,7 @@ struct InputManager {
struct Text {
bool is_accepting_input();
std::optional<unsigned> current_textbox_editing_id();
private:
struct TextBoxInfo {
@ -253,6 +256,7 @@ struct InputManager {
void touch_finger_do_mouse_up(const SDL_TouchFingerEvent& f);
void touch_finger_do_mouse_motion(const SDL_TouchFingerEvent& f);
void backend_paste_event();
void backend_input_text_event(const std::string& str);
void backend_drop_file_event(const SDL_DropEvent& e);
void backend_drop_text_event(const SDL_DropEvent& e);
@ -277,13 +281,9 @@ struct InputManager {
std::string get_clipboard_str_SDL();
void get_clipboard_image_data_SDL(const std::function<void(std::string_view data)>& callback);
struct TextPasteCallbackArgs {
std::string text;
std::optional<RichText::TextData> richText;
};
void call_text_paste(const std::function<void(const TextPasteCallbackArgs&)>& pasteCallbackFunc);
void call_paste(CustomEvents::PasteEventDataType type, const std::optional<Vector2f>& pastePosition = std::nullopt);
void process_text_paste(const std::string& pasteStr);
std::function<void(const TextPasteCallbackArgs&)> pasteCallback;
std::optional<RichText::TextData> lastCopiedRichText;
std::string key_assignment_to_str(const Vector2ui32& k) const;
@ -291,6 +291,10 @@ struct InputManager {
const KeyData& key(KeyCode kCode);
struct TextCallbackArgs {
std::string str;
};
struct KeyCallbackArgs {
KeyCode key;
bool down;

View file

@ -317,6 +317,12 @@ sk_sp<SkSurface> MainProgram::create_native_surface(Vector2i resolution, bool is
return nullptr;
}
void MainProgram::input_paste_callback(const CustomEvents::PasteEventData& paste) {
g.input_paste_callback(paste);
if(world)
world->input_paste_callback(paste);
}
bool MainProgram::input_keybind_callback(const Vector2ui32& newKey) {
if(keybindWaiting.has_value()) {
unsigned v = keybindWaiting.value();
@ -374,10 +380,14 @@ void MainProgram::input_key_callback(const InputManager::KeyCallbackArgs& key) {
void MainProgram::input_text_key_callback(const InputManager::KeyCallbackArgs& key) {
g.input_text_key_callback(key);
if(world)
world->input_text_key_callback(key);
}
void MainProgram::input_text_callback(const std::string& str) {
g.input_text_callback(str);
void MainProgram::input_text_callback(const InputManager::TextCallbackArgs& text) {
g.input_text_callback(text);
if(world)
world->input_text_callback(text);
}
void MainProgram::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) {

View file

@ -1,4 +1,5 @@
#pragma once
#include "CustomEvents.hpp"
#include "DrawData.hpp"
#include <SDL3/SDL_render.h>
#include <chrono>
@ -121,13 +122,13 @@ class MainProgram {
GlobalConfig conf;
std::optional<unsigned> keybindWaiting;
void input_paste_callback(const CustomEvents::PasteEventData& paste);
bool input_keybind_callback(const Vector2ui32& newKey);
void input_drop_file_callback(const InputManager::DropCallbackArgs& drop);
void input_drop_text_callback(const InputManager::DropCallbackArgs& drop);
void input_key_callback(const InputManager::KeyCallbackArgs& key);
void input_text_key_callback(const InputManager::KeyCallbackArgs& key);
void input_text_callback(const std::string& str);
void input_text_callback(const InputManager::TextCallbackArgs& text);
void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button);
void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion);
void input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel);

View file

@ -169,9 +169,6 @@ void TextBox::process_key_input(Cursor& cur, InputKey in, bool ctrl, bool shift,
if(in != InputKey::UP && in != InputKey::DOWN)
cur.previousX = std::nullopt;
if(onChange) onChange();
inputChangedTextBox = true;
}
void TextBox::process_mouse_left_button(Cursor& cur, const Vector2f& pos, int clickCount, bool held, bool shift) {
@ -224,9 +221,6 @@ void TextBox::process_mouse_left_button(Cursor& cur, const Vector2f& pos, int cl
}
cur.previousX = std::nullopt;
if((oldCursor != cur) && onChange) onChange();
inputChangedTextBox |= (oldCursor != cur);
}
else
cur.selectionEndPosBeforeHeld = std::nullopt;
@ -241,8 +235,6 @@ std::pair<std::string, TextData> TextBox::process_cut(Cursor& cur) {
if(cur.selectionBeginPos != cur.selectionEndPos) {
cur.selectionEndPos = cur.selectionBeginPos = cur.pos = remove(cur.selectionBeginPos, cur.selectionEndPos);
cur.previousX = std::nullopt;
if(onChange) onChange();
inputChangedTextBox = true;
}
return toRet;
}
@ -253,8 +245,6 @@ void TextBox::process_text_input(Cursor& cur, const std::string& in, const std::
cur.selectionEndPos = cur.selectionBeginPos = cur.pos = remove(cur.selectionBeginPos, cur.selectionEndPos);
cur.selectionEndPos = cur.selectionBeginPos = cur.pos = insert(cur.pos, in, inputModMap);
cur.previousX = std::nullopt;
if(onChange) onChange();
inputChangedTextBox = true;
}
}
@ -264,8 +254,6 @@ void TextBox::process_rich_text_input(Cursor& cur, const TextData& richText) {
cur.selectionEndPos = cur.selectionBeginPos = cur.pos = remove(cur.selectionBeginPos, cur.selectionEndPos);
cur.selectionEndPos = cur.selectionBeginPos = cur.pos = insert_rich_text(cur.pos, richText);
cur.previousX = std::nullopt;
if(onChange) onChange();
inputChangedTextBox = true;
}
}
@ -461,8 +449,6 @@ TextPosition TextBox::insert_rich_text(TextPosition p, const TextData& richText)
paragraphs[pIndex].pStyleData = richText.paragraphs[pIndex - p.fParagraphIndex].pStyleData;
}
if(onChange) onChange();
inputChangedTextBox = true;
needsRebuild = true;
return toRet;
@ -490,8 +476,6 @@ void TextBox::set_rich_text_data(const TextData& richText) {
if(richText.paragraphs.empty())
paragraphs.emplace_back();
tStyleMods = richText.tStyleMods;
if(onChange) onChange();
inputChangedTextBox = true;
needsRebuild = true;
}
@ -526,8 +510,6 @@ std::string TextBox::get_text_between(TextPosition p1, TextPosition p2) {
void TextBox::set_initial_text_style(const skia::textlayout::TextStyle& tStyle) {
if(!tStyle.equals(initialTStyle)) {
initialTStyle = tStyle;
if(onChange) onChange();
inputChangedTextBox = true;
needsRebuild = true;
}
}
@ -598,8 +580,6 @@ void TextBox::set_text_style_modifier_between(TextPosition p1, TextPosition p2,
insert_style_at_pos(start, modifier);
insert_style_at_pos(end, lastModOfThisTypeBeforeEnd); // Even if the end is the literal end of the text (which wont be seen), the end style must still be placed at the end so that it can merge with and delete the start style when the styled text is erased
remove_duplicate_text_style_mods();
if(onChange) onChange();
inputChangedTextBox = true;
needsRebuild = true;
}
}
@ -614,8 +594,6 @@ void TextBox::set_text_alignment_between(size_t paragraphIndex1, size_t paragrap
}
}
if(anythingChanged) {
if(onChange) onChange();
inputChangedTextBox = true;
needsRebuild = true;
}
}
@ -630,8 +608,6 @@ void TextBox::set_text_direction_between(size_t paragraphIndex1, size_t paragrap
}
}
if(anythingChanged) {
if(onChange) onChange();
inputChangedTextBox = true;
needsRebuild = true;
}
}
@ -867,8 +843,6 @@ int TextBox::get_line_number_at_from_byte_text_pos(TextPosition pos) {
void TextBox::set_width(float newWidth) {
if(width != newWidth) {
width = std::max(newWidth, 4.0f);
if(onChange) onChange();
inputChangedTextBox = true;
needsRebuild = true;
}
}
@ -885,8 +859,6 @@ void TextBox::set_allow_newlines(bool allow) {
void TextBox::set_font_data(const std::shared_ptr<FontData>& fD) {
if(fontData != fD) {
fontData = fD;
if(onChange) onChange();
inputChangedTextBox = true;
needsRebuild = true;
}
}
@ -1055,8 +1027,6 @@ TextPosition TextBox::insert(TextPosition pos, std::string_view textToInsert, co
for(const auto& [modType, modifier] : inputModMap.value())
set_text_style_modifier_between(oldPos, pos, modifier);
}
if(onChange) onChange();
inputChangedTextBox = true;
needsRebuild = true;
}
@ -1105,8 +1075,6 @@ TextPosition TextBox::remove(TextPosition p1, TextPosition p2) {
}
remove_duplicate_text_style_mods();
if(onChange) onChange();
inputChangedTextBox = true;
needsRebuild = true;
return start;

View file

@ -66,9 +66,6 @@ class TextBox {
public:
TextBox();
bool inputChangedTextBox = false;
std::function<void()> onChange;
enum class Movement {
NOWHERE,
LEFT,

View file

@ -1,4 +1,5 @@
#include "RichTextUserInput.hpp"
#include "CustomEvents.hpp"
template <typename T> std::optional<T> shared_ptr_to_opt(const std::shared_ptr<T> o) {
if(o)
@ -7,18 +8,29 @@ template <typename T> std::optional<T> shared_ptr_to_opt(const std::shared_ptr<T
return std::nullopt;
}
RichTextUserInput::RichTextUserInput(const std::shared_ptr<RichText::TextBox>& initTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& initCursor, const std::shared_ptr<RichText::TextStyleModifier::ModifierMap>& initModMap, const std::function<void()>& initOnTextEdit):
RichTextUserInput::RichTextUserInput(const std::shared_ptr<RichText::TextBox>& initTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& initCursor, const std::shared_ptr<RichText::TextStyleModifier::ModifierMap>& initModMap):
textBox(initTextBox),
cursor(initCursor),
modMap(initModMap),
onTextEdit(initOnTextEdit)
modMap(initModMap)
{}
bool RichTextUserInput::input_paste_callback(const CustomEvents::PasteEventData& paste) {
if(paste.type == CustomEvents::PasteEventDataType::TEXT) {
do_textbox_operation_with_undo([&]() {
if(paste.richText.has_value())
textBox->process_rich_text_input(*cursor, paste.richText.value());
else
textBox->process_text_input(*cursor, paste.data, shared_ptr_to_opt(modMap));
});
return true;
}
return false;
}
void RichTextUserInput::add_text_to_textbox(const std::string& inputText) {
do_textbox_operation_with_undo([&]() {
textBox->process_text_input(*cursor, inputText, shared_ptr_to_opt(modMap));
});
onTextEdit();
}
void RichTextUserInput::add_textbox_undo(const RichText::TextBox::Cursor& prevCursor, const RichText::TextData& prevRichText) {
@ -26,14 +38,12 @@ void RichTextUserInput::add_textbox_undo(const RichText::TextBox::Cursor& prevCu
textBox->set_rich_text_data_for_undo_redo(prevRichText);
cursor->selectionBeginPos = cursor->selectionEndPos = cursor->pos = std::max(prevCursor.selectionEndPos, prevCursor.selectionBeginPos);
cursor->previousX = std::nullopt;
onTextEdit();
return true;
},
[&, currentCursor = *cursor, currentRichText = textBox->get_rich_text_data()]() {
textBox->set_rich_text_data_for_undo_redo(currentRichText);
cursor->selectionBeginPos = cursor->selectionEndPos = cursor->pos = std::max(currentCursor.selectionEndPos, currentCursor.selectionBeginPos);
cursor->previousX = std::nullopt;
onTextEdit();
return true;
}});
}
@ -43,13 +53,16 @@ void RichTextUserInput::do_textbox_operation_with_undo(const std::function<void(
auto prevCursor = *cursor;
func();
add_textbox_undo(prevCursor, prevRichText);
onTextEdit();
}
void RichTextUserInput::input_key_callback(InputManager& input, const InputManager::KeyCallbackArgs& key) {
RichTextUserInput::Changes RichTextUserInput::input_key_callback(InputManager& input, const InputManager::KeyCallbackArgs& key) {
std::optional<RichText::TextStyleModifier::ModifierMap> modMapOpt = shared_ptr_to_opt(modMap);
Changes toRet;
if(key.down) {
auto oldCursor = *cursor;
switch(key.key) {
case InputManager::KEY_GENERIC_UP:
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::UP, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
@ -67,11 +80,13 @@ void RichTextUserInput::input_key_callback(InputManager& input, const InputManag
do_textbox_operation_with_undo([&] {
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::BACKSPACE, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
});
toRet.textEdited = true;
break;
case InputManager::KEY_TEXT_DELETE:
do_textbox_operation_with_undo([&] {
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::DEL, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
});
toRet.textEdited = true;
break;
case InputManager::KEY_TEXT_HOME:
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::HOME, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
@ -86,38 +101,38 @@ void RichTextUserInput::input_key_callback(InputManager& input, const InputManag
do_textbox_operation_with_undo([&] {
input.set_clipboard_plain_and_richtext_pair(textBox->process_cut(*cursor));
});
toRet.textEdited = true;
break;
case InputManager::KEY_TEXT_PASTE:
do_textbox_operation_with_undo([&]() {
input.call_text_paste([textBox = textBox, cursor = cursor, modMapOpt] (const InputManager::TextPasteCallbackArgs& pasteArgs) {
if(pasteArgs.richText.has_value())
textBox->process_rich_text_input(*cursor, pasteArgs.richText.value());
else
textBox->process_text_input(*cursor, pasteArgs.text, modMapOpt);
});
});
input.call_paste(CustomEvents::PasteEventDataType::TEXT);
break;
case InputManager::KEY_TEXT_SELECTALL:
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::SELECT_ALL, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
break;
case InputManager::KEY_TEXT_UNDO:
textboxUndo.undo();
toRet.textEdited = true;
break;
case InputManager::KEY_TEXT_REDO:
textboxUndo.redo();
toRet.textEdited = true;
break;
case InputManager::KEY_GENERIC_ENTER:
do_textbox_operation_with_undo([&] {
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::ENTER, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
});
toRet.textEdited = true;
break;
case InputManager::KEY_TEXT_TAB:
do_textbox_operation_with_undo([&] {
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::TAB, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
});
toRet.textEdited = true;
break;
default:
break;
return toRet;
}
toRet.cursorChanged = oldCursor != *cursor;
}
return toRet;
}

View file

@ -1,19 +1,24 @@
#pragma once
#include "CustomEvents.hpp"
#include "RichText/TextBox.hpp"
#include "UndoManager.hpp"
#include "InputManager.hpp"
class RichTextUserInput {
public:
RichTextUserInput(const std::shared_ptr<RichText::TextBox>& initTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& initCursor, const std::shared_ptr<RichText::TextStyleModifier::ModifierMap>& initModMap, const std::function<void()>& initOnTextEdit);
void input_key_callback(InputManager& input, const InputManager::KeyCallbackArgs& key);
RichTextUserInput(const std::shared_ptr<RichText::TextBox>& initTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& initCursor, const std::shared_ptr<RichText::TextStyleModifier::ModifierMap>& initModMap);
struct Changes {
bool textEdited = false;
bool cursorChanged = false;
};
Changes input_key_callback(InputManager& input, const InputManager::KeyCallbackArgs& key);
bool input_paste_callback(const CustomEvents::PasteEventData& paste);
void add_text_to_textbox(const std::string& inputText);
private:
void do_textbox_operation_with_undo(const std::function<void()>& func);
void add_textbox_undo(const RichText::TextBox::Cursor& prevCursor, const RichText::TextData& prevRichText);
private:
std::shared_ptr<RichText::TextBox> textBox;
std::shared_ptr<RichText::TextBox::Cursor> cursor;
std::shared_ptr<RichText::TextStyleModifier::ModifierMap> modMap;
UndoManager textboxUndo;
std::function<void()> onTextEdit;
};

View file

@ -244,6 +244,21 @@ void World::on_tab_out() {
rMan.clear_display_cache();
}
void World::input_paste_callback(const CustomEvents::PasteEventData& paste) {
if(!clientStillConnecting)
drawProg.input_paste_callback(paste);
}
void World::input_text_key_callback(const InputManager::KeyCallbackArgs& key) {
if(!clientStillConnecting)
drawProg.input_text_key_callback(key);
}
void World::input_text_callback(const InputManager::TextCallbackArgs& text) {
if(!clientStillConnecting)
drawProg.input_text_callback(text);
}
void World::input_drop_file_callback(const InputManager::DropCallbackArgs& drop) {
if(!clientStillConnecting)
drawProg.input_drop_file_callback(drop);

View file

@ -96,8 +96,11 @@ class World {
std::shared_ptr<NetServer> netServer;
std::shared_ptr<NetClient> netClient;
void input_paste_callback(const CustomEvents::PasteEventData& paste);
void input_drop_file_callback(const InputManager::DropCallbackArgs& drop);
void input_drop_text_callback(const InputManager::DropCallbackArgs& drop);
void input_text_key_callback(const InputManager::KeyCallbackArgs& key);
void input_text_callback(const InputManager::TextCallbackArgs& text);
void input_key_callback(const InputManager::KeyCallbackArgs& key);
void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button);
void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion);

View file

@ -1,3 +1,4 @@
#include "CustomEvents.hpp"
#include "Helpers/SCollision.hpp"
#include "Helpers/StringHelpers.hpp"
#include "Helpers/FileDownloader.hpp"
@ -94,6 +95,7 @@
#include <Helpers/Logger.hpp>
#include "SwitchCWD.hpp"
#include "CustomEvents.hpp"
// Use dedicated graphics card on Windows
#ifdef _WIN32
@ -832,8 +834,11 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) {
break;
case SDL_EVENT_SCREEN_KEYBOARD_HIDDEN:
break;
default:
default: {
if(event->type == CustomEvents::PASTE_EVENT)
mS.m->input.backend_paste_event();
break;
}
}
#ifdef NDEBUG
}