Start work on touchscreen support

This commit is contained in:
Yousef Khadadeh 2026-02-27 16:16:51 +03:00
parent 815737ce3e
commit ae88521b32
14 changed files with 171 additions and 76 deletions

View file

@ -120,7 +120,8 @@ void DrawingProgram::send_transforms_for(const std::vector<CanvasComponentContai
void DrawingProgram::toolbar_gui() {
Toolbar& t = world.main.toolbar;
t.gui.push_id("Drawing Program Toolbar GUI");
CLAY_AUTO_ID({
Clay_ElementId localID = CLAY_ID_LOCAL("Drawing program toolbar GUI");
CLAY(localID, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(0), .height = CLAY_SIZING_FIT(0)},
.padding = CLAY_PADDING_ALL(static_cast<uint16_t>(t.io->theme->padding1 / 2)),
@ -131,7 +132,7 @@ void DrawingProgram::toolbar_gui() {
.backgroundColor = convert_vec4<Clay_Color>(t.io->theme->backColor1),
.cornerRadius = CLAY_CORNER_RADIUS(t.io->theme->windowCorners1)
}) {
t.gui.obstructing_window();
t.gui.obstructing_window(localID);
if(t.gui.svg_icon_button_transparent("Brush Toolbar Button", "data/icons/brush.svg", drawTool->get_type() == DrawingProgramToolType::BRUSH)) { switch_to_tool(DrawingProgramToolType::BRUSH); }
if(t.gui.svg_icon_button_transparent("Eraser Toolbar Button", "data/icons/eraser.svg", drawTool->get_type() == DrawingProgramToolType::ERASER)) { switch_to_tool(DrawingProgramToolType::ERASER); }
if(t.gui.svg_icon_button_transparent("Line Toolbar Button", "data/icons/line.svg", drawTool->get_type() == DrawingProgramToolType::LINE)) { switch_to_tool(DrawingProgramToolType::LINE); }
@ -214,7 +215,8 @@ bool DrawingProgram::right_click_popup_gui(Vector2f popupPos) {
void DrawingProgram::tool_options_gui() {
Toolbar& t = world.main.toolbar;
float minGUIWidth = drawTool->get_type() == DrawingProgramToolType::SCREENSHOT ? 300 : 200;
CLAY_AUTO_ID({
Clay_ElementId localID = CLAY_ID_LOCAL("Drawing program tool options gui");
CLAY(localID, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(minGUIWidth), .height = CLAY_SIZING_FIT(0)},
.padding = CLAY_PADDING_ALL(t.io->theme->padding1),
@ -225,7 +227,7 @@ void DrawingProgram::tool_options_gui() {
.backgroundColor = convert_vec4<Clay_Color>(t.io->theme->backColor1),
.cornerRadius = CLAY_CORNER_RADIUS(t.io->theme->windowCorners1)
}) {
t.gui.obstructing_window();
t.gui.obstructing_window(localID);
drawTool->gui_toolbox();
}
}
@ -239,7 +241,14 @@ void DrawingProgram::modify_grid(const NetworkingObjects::NetObjWeakPtr<WorldGri
void DrawingProgram::update() {
tool_temporary_switch_update();
controls.cursorHoveringOverCanvas = !world.main.toolbar.io->hoverObstructed;
{
controls.cursorHoveringOverCanvas = true;
Vector2f mousePosGUI = world.main.input.mouse.pos / world.main.toolbar.final_gui_scale();
for(auto& aabb : world.main.toolbar.io->hoverObstructingAABBs)
controls.cursorHoveringOverCanvas &= !SCollision::collide(mousePosGUI, aabb);
for(auto& circle : world.main.toolbar.io->hoverObstructingCircles)
controls.cursorHoveringOverCanvas &= !SCollision::collide(mousePosGUI, circle);
}
controls.middleClick = controls.cursorHoveringOverCanvas && (world.main.input.mouse.middleClicks || world.main.input.pen.buttons[world.main.toolbar.tabletOptions.middleClickButton].pressed);
bool middleHeld = world.main.input.mouse.middleDown || world.main.input.pen.buttons[world.main.toolbar.tabletOptions.middleClickButton].held;

View file

@ -191,7 +191,7 @@ bool BrushTool::prevent_undo_or_redo() {
}
void BrushTool::draw(SkCanvas* canvas, const DrawData& drawData) {
if(!drawData.main->toolbar.io->hoverObstructed) {
if(drawData.main->world->drawProg.controls.cursorHoveringOverCanvas) {
auto relativeWidthResult = drawP.world.main.toolConfig.get_relative_width_stroke_size(drawP, drawP.world.drawData.cam.c.inverseScale);
if(relativeWidthResult.first.has_value()) {
SkPaint linePaint;

View file

@ -96,7 +96,7 @@ bool EraserTool::prevent_undo_or_redo() {
}
void EraserTool::draw(SkCanvas* canvas, const DrawData& drawData) {
if(!drawData.main->toolbar.io->hoverObstructed) {
if(drawData.main->world->drawProg.controls.cursorHoveringOverCanvas) {
auto relativeWidthResult = drawP.world.main.toolConfig.get_relative_width_stroke_size(drawP, drawP.world.drawData.cam.c.inverseScale);
if(relativeWidthResult.first.has_value()) {
float width = relativeWidthResult.first.value() * 0.5f;

View file

@ -102,6 +102,8 @@ struct UpdateInputData {
std::string textInput;
bool hoverObstructed = false;
std::vector<SCollision::AABB<float>> hoverObstructingAABBs;
std::vector<SCollision::Circle<float>> hoverObstructingCircles;
bool acceptingTextInput = false;
float deltaTime = 0.0f;

View file

@ -78,7 +78,8 @@ bool GUIStuff::FontPicker::update(UpdateInputData& io, std::string* fontName, GU
clickedOut = false;
}
if(dropdownOpen) {
CLAY_AUTO_ID({
Clay_ElementId localID = CLAY_ID_LOCAL("Font picker floating element");
CLAY(localID, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIXED(250), .height = CLAY_SIZING_FIT(0, 300)},
.layoutDirection = CLAY_TOP_TO_BOTTOM
@ -100,7 +101,7 @@ bool GUIStuff::FontPicker::update(UpdateInputData& io, std::string* fontName, GU
.width = CLAY_BORDER_OUTSIDE(1)
}
}) {
gui->obstructing_window();
gui->obstructing_window(localID);
if(Clay_Hovered())
clickedOut = false;
gui->scroll_bar_many_entries_area("Font Selector", ENTRY_HEIGHT, sortedFontList.size(), true, [fontName, gui, &fontChangedFromSelection, &sortedFontList = sortedFontList, val, &io = io](size_t i, bool listHovered) {

View file

@ -1,6 +1,7 @@
#include "PaintCircleMenu.hpp"
#include "Helpers/ConvertVec.hpp"
#include <include/core/SkPathBuilder.h>
#include "../GUIManager.hpp"
namespace GUIStuff {
@ -10,7 +11,8 @@ constexpr float CIRCLE_END = 150.0f;
constexpr double ROTATE_BAR_SNAP_DISTANCE = 0.2;
constexpr double ROTATE_BAR_SNAP_DISTRIBUTION = std::numbers::pi * 0.25;
void PaintCircleMenu::update(UpdateInputData& io, const Data& data, const std::function<void()>& elemUpdate) {
void PaintCircleMenu::update(GUIManager& gui, const Data& data, const std::function<void()>& elemUpdate) {
auto& io = *gui.io;
CLAY_AUTO_ID({.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}
},
@ -19,7 +21,6 @@ void PaintCircleMenu::update(UpdateInputData& io, const Data& data, const std::f
bool isHoveredNoObstruction = Clay_Hovered() && !io.hoverObstructed;
Vector2f vecFromCenter = (io.mouse.pos - bb.center()).normalized();
float distFromCenter = vec_distance(io.mouse.pos, bb.center());
bool rotateHovered = false;
if(data.newRotationAngle) {
rotateBarSelect.update(isHoveredNoObstruction && distFromCenter > ROTATE_START && distFromCenter < CIRCLE_END, io.mouse.leftClick, io.mouse.leftHeld);
if(rotateBarSelect.held) {
@ -38,9 +39,7 @@ void PaintCircleMenu::update(UpdateInputData& io, const Data& data, const std::f
}
else
*data.newRotationAngle = data.currentRotationAngle;
rotateHovered = rotateBarSelect.hovered;
}
bool colorHovered = false;
if(!data.palette.empty() && data.selectedColor) {
colorBarSelect.update(isHoveredNoObstruction && distFromCenter > PALETTE_START && distFromCenter < ROTATE_START, io.mouse.leftClick, io.mouse.leftHeld);
if(colorBarSelect.hovered) {
@ -54,9 +53,9 @@ void PaintCircleMenu::update(UpdateInputData& io, const Data& data, const std::f
selectedColor.z() = data.palette[colorSelectionIndex].z();
}
}
colorHovered = colorBarSelect.hovered;
}
if(rotateHovered || colorHovered)
io.hoverObstructingCircles.emplace_back(bb.center() + gui.windowPos, CIRCLE_END);
if(SCollision::collide(io.hoverObstructingCircles.back(), io.mouse.pos))
io.hoverObstructed = true;
if(elemUpdate)
elemUpdate();
@ -72,6 +71,9 @@ void PaintCircleMenu::clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_Rend
draw_rotate_bar(canvas, io);
draw_palette_bar(canvas, io);
SkPaint p;
p.setColor4f(color_mul_alpha(io.theme->backColor1, 0.5f));
canvas->drawCircle(0.0f, 0.0f, PALETTE_START, p);
canvas->restore();
}

View file

@ -3,6 +3,8 @@
namespace GUIStuff {
class GUIManager;
class PaintCircleMenu : public Element {
public:
struct Data {
@ -11,7 +13,7 @@ class PaintCircleMenu : public Element {
Vector4f* selectedColor = nullptr;
std::vector<Vector3f> palette;
};
void update(UpdateInputData& io, const Data& data, const std::function<void()>& elemUpdate);
void update(GUIManager& gui, const Data& data, const std::function<void()>& elemUpdate);
virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command) override;
private:
void draw_rotate_bar(SkCanvas* canvas, UpdateInputData& io);

View file

@ -246,8 +246,8 @@ void GUIManager::draw(SkCanvas* canvas) {
canvas->restore();
}
void GUIManager::top_to_bottom_window_popup_layout(Clay_SizingAxis x, Clay_SizingAxis y, const std::function<void()>& elemUpdate) {
CLAY_AUTO_ID({.layout = {
void GUIManager::top_to_bottom_window_popup_layout(const Clay_ElementId& windowLocalID, Clay_SizingAxis x, Clay_SizingAxis y, const std::function<void()>& elemUpdate) {
CLAY(windowLocalID, {.layout = {
.sizing = {.width = x, .height = y },
.padding = CLAY_PADDING_ALL(io->theme->padding1),
.childGap = io->theme->childGap1,
@ -258,8 +258,7 @@ void GUIManager::top_to_bottom_window_popup_layout(Clay_SizingAxis x, Clay_Sizin
.floating = { .attachTo = CLAY_ATTACH_TO_PARENT },
.border = {.color = convert_vec4<Clay_Color>(io->theme->fillColor2), .width = CLAY_BORDER_OUTSIDE(1)}
}) {
if(Clay_Hovered())
io->hoverObstructed = true;
obstructing_window(windowLocalID);
elemUpdate();
}
}
@ -623,7 +622,7 @@ void GUIManager::dropdown_select(const char* id, size_t* val, const std::vector<
.width = CLAY_BORDER_OUTSIDE(1)
}
}) {
obstructing_window();
obstructing_window(localID);
scroll_bar_many_entries_area("dropdown scroll area", 18.0f, selections.size(), true, [&](size_t i, bool) {
bool selectedEntry = *val == i;
@ -851,7 +850,7 @@ void GUIManager::paint_circle_popup_menu(const char* id, const Vector2f& centerP
}
}) {
PaintCircleMenu* e = insert_element<PaintCircleMenu>();
e->update(*io, val, elemUpdate);
e->update(*this, val, elemUpdate);
}
pop_id();
}
@ -890,7 +889,7 @@ void GUIManager::list_popup_menu(const char* id, Vector2f popupPos, const std::f
.attachTo = CLAY_ATTACH_TO_ROOT
}
}) {
obstructing_window();
obstructing_window(localID);
push_id(1);
elemUpdate();
pop_id();
@ -905,9 +904,11 @@ void GUIManager::tree_listing(const char* id, NetworkingObjects::NetObjID rootOb
pop_id();
}
void GUIManager::obstructing_window() {
void GUIManager::obstructing_window(const Clay_ElementId& elementID) {
if(Clay_Hovered())
io->hoverObstructed = true;
const Clay_ElementData& elemData = Clay_GetElementData(elementID);
io->hoverObstructingAABBs.emplace_back(SCollision::AABB<float>{Vector2f{elemData.boundingBox.x, elemData.boundingBox.y} + windowPos, Vector2f{elemData.boundingBox.x + elemData.boundingBox.width, elemData.boundingBox.y + elemData.boundingBox.height} + windowPos});
}
void GUIManager::clay_error_handler(Clay_ErrorData errorData) {

View file

@ -69,7 +69,7 @@ class GUIManager {
bool rotate_wheel(const char* id, double* angle, float size = BIG_BUTTON_SIZE, const std::function<void()>& elemUpdate = nullptr);
void top_to_bottom_window_popup_layout(Clay_SizingAxis x, Clay_SizingAxis y, const std::function<void()>& elemUpdate);
void top_to_bottom_window_popup_layout(const Clay_ElementId& localID, Clay_SizingAxis x, Clay_SizingAxis y, const std::function<void()>& elemUpdate);
void left_to_right_layout(Clay_SizingAxis x, Clay_SizingAxis y, const std::function<void()>& elemUpdate);
void left_to_right_line_layout(const std::function<void()>& elemUpdate);
void left_to_right_line_centered_layout(const std::function<void()>& elemUpdate);
@ -104,7 +104,7 @@ class GUIManager {
void tree_listing(const char* id, NetworkingObjects::NetObjID rootObjID, const TreeListing::DisplayData& displayData, TreeListing::SelectionData& selectionData);
void obstructing_window();
void obstructing_window(const Clay_ElementId& elementID);
template <typename NewElement> NewElement* insert_element() {
auto [it, inserted] = elements.emplace(idStack, ElementContainer());
@ -317,7 +317,7 @@ class GUIManager {
if(clicked)
isOpen = true;
if(isOpen) {
top_to_bottom_window_popup_layout(CLAY_SIZING_FIT(300), CLAY_SIZING_FIT(0), [&]() {
top_to_bottom_window_popup_layout(CLAY_ID_LOCAL("COLOR PICKER"), CLAY_SIZING_FIT(300), CLAY_SIZING_FIT(0), [&]() {
isUpdating = color_picker_items("c", val, selectAlpha);
if(io->mouse.leftClick && !Clay_Hovered() && !clicked)
isOpen = false;

View file

@ -72,6 +72,12 @@ struct InputManager {
friend struct InputManager;
} mouse;
struct Touch {
bool isDown = false;
int leftClicksSaved = 0;
std::chrono::steady_clock::time_point lastLeftClickTime;
} touch;
struct Pen {
bool inProximity = false;
bool isDown = false;

View file

@ -33,6 +33,7 @@
#endif
#include <Helpers/Logger.hpp>
#include "DrawCollision.hpp"
MainProgram::MainProgram():
fonts(std::make_shared<FontData>()),

View file

@ -494,7 +494,8 @@ void Toolbar::close_popup_gui() {
std::erase_if(closePopupData.worldsToClose, [](auto& wPair) {
return wPair.w.expired();
});
CLAY_AUTO_ID({
Clay_ElementId localId = CLAY_ID_LOCAL("INFINIPAINT CLOSE POPUP");
CLAY(localId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(0), .height = CLAY_SIZING_FIT(0, 600) },
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -506,7 +507,7 @@ void Toolbar::close_popup_gui() {
.cornerRadius = CLAY_CORNER_RADIUS(io->theme->windowCorners1),
.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.obstructing_window(localId);
gui.push_id("Close single file popup gui");
gui.text_label("Files may contain unsaved changes");
gui.scroll_bar_area("close file popup gui scroll area", false, [&](float, float, float &) {
@ -614,7 +615,8 @@ void Toolbar::paint_popup(Vector2f popupPos) {
}
void Toolbar::top_toolbar() {
CLAY_AUTO_ID({
Clay_ElementId localId = CLAY_ID_LOCAL("INFINIPAINT TOP TOOLBAR");
CLAY(localId, {
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIT(0) },
.padding = CLAY_PADDING_ALL(static_cast<uint16_t>(io->theme->padding1 / 2)),
@ -625,7 +627,7 @@ void Toolbar::top_toolbar() {
.backgroundColor = convert_vec4<Clay_Color>(io->theme->backColor1),
.cornerRadius = CLAY_CORNER_RADIUS(io->theme->windowCorners1)
}) {
gui.obstructing_window();
gui.obstructing_window(localId);
gui.push_id("menu top toolbar");
global_log();
bool menuPopUpJustOpen = false;
@ -701,7 +703,8 @@ void Toolbar::top_toolbar() {
layer_menu(layerMenuPopUpJustOpen);
}
if(menuPopUpOpen) {
CLAY_AUTO_ID({
Clay_ElementId menuPopupId = CLAY_ID_LOCAL("Menu Popup");
CLAY(menuPopupId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(100), .height = CLAY_SIZING_FIT(0) },
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -713,7 +716,7 @@ void Toolbar::top_toolbar() {
.cornerRadius = CLAY_CORNER_RADIUS(io->theme->windowCorners1),
.floating = {.offset = {.x = 0, .y = static_cast<float>(io->theme->padding1)}, .attachPoints = {.element = CLAY_ATTACH_POINT_LEFT_TOP, .parent = CLAY_ATTACH_POINT_LEFT_BOTTOM}, .attachTo = CLAY_ATTACH_TO_PARENT}
}) {
gui.obstructing_window();
gui.obstructing_window(menuPopupId);
if(gui.text_button_left_transparent("new file local", "New File")) {
main.new_tab({
.isClient = false
@ -796,7 +799,8 @@ void Toolbar::top_toolbar() {
}
void Toolbar::web_version_welcome() {
CLAY_AUTO_ID({
Clay_ElementId localId = CLAY_ID_LOCAL("Web version welcome");
CLAY(localId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIXED(700), .height = CLAY_SIZING_FIT(0) },
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -808,7 +812,7 @@ void Toolbar::web_version_welcome() {
.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}
}) {
gui.obstructing_window();
gui.obstructing_window(localId);
gui.push_id("web version welcome gui");
gui.text_label_centered("Welcome to the web version of InfiniPaint!");
gui.text_label(
@ -905,7 +909,8 @@ void Toolbar::update_notification_check() {
}
void Toolbar::update_notification_gui() {
CLAY_AUTO_ID({
Clay_ElementId localId = CLAY_ID_LOCAL("UPDATE NOTIFICATION GUI");
CLAY(localId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIXED(700), .height = CLAY_SIZING_FIT(0) },
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -917,7 +922,7 @@ void Toolbar::update_notification_gui() {
.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}
}) {
gui.obstructing_window();
gui.obstructing_window(localId);
gui.push_id("update notification gui");
gui.text_label_centered("Update v" + updateCheckerData.newVersionStr + " available!");
if(gui.text_button_wide("download", "Open download page in web browser")) {
@ -938,7 +943,8 @@ void Toolbar::update_notification_gui() {
void Toolbar::grid_menu(bool justOpened) {
if(main.world->gridMan.grids) {
gui.push_id("grid menu");
CLAY_AUTO_ID({
Clay_ElementId localId = CLAY_ID_LOCAL("INFINIPAINT GRID MENU");
CLAY(localId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(300), .height = CLAY_SIZING_FIT(0, 600) },
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -950,7 +956,7 @@ void Toolbar::grid_menu(bool justOpened) {
.cornerRadius = CLAY_CORNER_RADIUS(io->theme->windowCorners1),
.floating = {.offset = {.x = 0, .y = static_cast<float>(io->theme->padding1)}, .attachPoints = {.element = CLAY_ATTACH_POINT_RIGHT_TOP, .parent = CLAY_ATTACH_POINT_RIGHT_BOTTOM}, .attachTo = CLAY_ATTACH_TO_PARENT}
}) {
gui.obstructing_window();
gui.obstructing_window(localId);
gui.text_label_centered("Grids");
float entryHeight = 25.0f;
if(main.world->gridMan.grids->empty())
@ -1032,7 +1038,8 @@ void Toolbar::stop_displaying_grid_menu() {
void Toolbar::bookmark_menu(bool justOpened) {
gui.push_id("bookmark menu");
CLAY_AUTO_ID({
Clay_ElementId localId = CLAY_ID_LOCAL("INFINIPAINT BOOKMARK MENU");
CLAY(localId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(300), .height = CLAY_SIZING_FIT(0, 600) },
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -1044,7 +1051,7 @@ void Toolbar::bookmark_menu(bool justOpened) {
.cornerRadius = CLAY_CORNER_RADIUS(io->theme->windowCorners1),
.floating = {.offset = {.x = 0, .y = static_cast<float>(io->theme->padding1)}, .attachPoints = {.element = CLAY_ATTACH_POINT_RIGHT_TOP, .parent = CLAY_ATTACH_POINT_RIGHT_BOTTOM}, .attachTo = CLAY_ATTACH_TO_PARENT}
}) {
gui.obstructing_window();
gui.obstructing_window(localId);
gui.text_label_centered("Bookmarks");
main.world->bMan.setup_list_gui("bookmark menu list");
if(io->mouse.leftClick && !Clay_Hovered() && !justOpened) {
@ -1057,7 +1064,8 @@ void Toolbar::bookmark_menu(bool justOpened) {
void Toolbar::layer_menu(bool justOpened) {
gui.push_id("layer menu");
CLAY_AUTO_ID({
Clay_ElementId localId = CLAY_ID_LOCAL("INFINIPAINT LAYER MENU");
CLAY(localId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(300), .height = CLAY_SIZING_FIT(0, 600) },
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -1069,7 +1077,7 @@ void Toolbar::layer_menu(bool justOpened) {
.cornerRadius = CLAY_CORNER_RADIUS(io->theme->windowCorners1),
.floating = {.offset = {.x = 0, .y = static_cast<float>(io->theme->padding1)}, .attachPoints = {.element = CLAY_ATTACH_POINT_RIGHT_TOP, .parent = CLAY_ATTACH_POINT_RIGHT_BOTTOM}, .attachTo = CLAY_ATTACH_TO_PARENT}
}) {
gui.obstructing_window();
gui.obstructing_window(localId);
gui.text_label_centered("Layers");
bool hoveringOverDropdown = false;
main.world->drawProg.layerMan.listGUI.setup_list_gui("layer menu list", hoveringOverDropdown);
@ -1111,13 +1119,14 @@ std::unique_ptr<skia::textlayout::Paragraph> Toolbar::build_paragraph_from_chat_
void Toolbar::chat_box() {
constexpr float CHATBOX_WIDTH = 700;
if(main.world->netObjMan.is_connected()) {
CLAY_AUTO_ID({
Clay_ElementId localId = CLAY_ID_LOCAL("INFINIPAINT CHAT BOX OPEN BUTTON");
CLAY(localId, {
.layout = {
.layoutDirection = CLAY_LEFT_TO_RIGHT
},
.floating = {.offset = {static_cast<float>(io->theme->padding1), -static_cast<float>(io->theme->padding1)}, .attachPoints = {.element = CLAY_ATTACH_POINT_LEFT_BOTTOM, .parent = CLAY_ATTACH_POINT_LEFT_BOTTOM}, .attachTo = CLAY_ATTACH_TO_PARENT}
}) {
gui.obstructing_window();
gui.obstructing_window(localId);
gui.push_id("chat box open button");
if(gui.svg_icon_button("Chat Open Button", "data/icons/chat.svg", chatBoxState != CHATBOXSTATE_CLOSE)) {
if(chatBoxState == CHATBOXSTATE_CLOSE)
@ -1128,7 +1137,8 @@ void Toolbar::chat_box() {
gui.pop_id();
}
}
CLAY_AUTO_ID({
Clay_ElementId localId = CLAY_ID_LOCAL("INFINIPAINT CHAT BOX OPEN");
CLAY(localId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIXED(CHATBOX_WIDTH), .height = CLAY_SIZING_FIT(0) },
.childGap = 0,
@ -1137,7 +1147,7 @@ void Toolbar::chat_box() {
},
.floating = {.offset = {60 + static_cast<float>(io->theme->padding1), -static_cast<float>(io->theme->padding1)}, .attachPoints = {.element = CLAY_ATTACH_POINT_LEFT_BOTTOM, .parent = CLAY_ATTACH_POINT_LEFT_BOTTOM}, .attachTo = CLAY_ATTACH_TO_PARENT}
}) {
gui.obstructing_window();
gui.obstructing_window(localId);
gui.push_id("chat box");
if(chatBoxState == CHATBOXSTATE_JUSTOPEN || chatBoxState == CHATBOXSTATE_OPEN) {
gui.push_id("messages");
@ -1196,7 +1206,8 @@ void Toolbar::chat_box() {
chatMessage.time.update_time_since();
if(chatMessage.time < DISPLAY_TIME) {
float a = 1.0f - lerp_time<float>(chatMessage.time, DISPLAY_TIME, FADE_START_TIME);
CLAY_AUTO_ID({
Clay_ElementId elemId = CLAY_IDI_LOCAL("CHAT MESSAGE ID", id);
CLAY(elemId, {
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIT(0) },
.padding = CLAY_PADDING_ALL(0),
@ -1207,7 +1218,7 @@ void Toolbar::chat_box() {
.backgroundColor = convert_vec4<Clay_Color>(color_mul_alpha(io->theme->backColor1, a)),
}) {
gui.push_id(id);
gui.obstructing_window();
gui.obstructing_window(elemId);
gui.text_paragraph("text", build_paragraph_from_chat_message(chatMessage, a), CHATBOX_WIDTH);
gui.pop_id();
}
@ -1236,7 +1247,8 @@ void Toolbar::global_log() {
logM.time.update_time_since();
if(logM.time < DISPLAY_TIME) {
float a = 1.0f - lerp_time<float>(logM.time, DISPLAY_TIME, FADE_START_TIME);
CLAY_AUTO_ID({
Clay_ElementId elemId = CLAY_ID_LOCAL("GLOBAL LOG");
CLAY(elemId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(300), .height = CLAY_SIZING_FIT(0) },
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -1247,7 +1259,7 @@ void Toolbar::global_log() {
.backgroundColor = convert_vec4<Clay_Color>(color_mul_alpha(io->theme->backColor1, a)),
.cornerRadius = CLAY_CORNER_RADIUS(io->theme->windowCorners1)
}) {
gui.obstructing_window();
gui.obstructing_window(elemId);
SkColor4f c{0, 0, 0, 0};
switch(logM.color) {
case LogMessage::COLOR_NORMAL:
@ -1283,7 +1295,8 @@ void Toolbar::drawing_program_gui() {
.padding = {.top = 40, .bottom = 40}
}
}) {
CLAY_AUTO_ID({
auto localId = CLAY_ID_LOCAL("Drawing program gui color picker left");
CLAY(localId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(300), .height = CLAY_SIZING_FIT(0)},
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -1294,7 +1307,7 @@ void Toolbar::drawing_program_gui() {
.backgroundColor = convert_vec4<Clay_Color>(io->theme->backColor1),
.cornerRadius = CLAY_CORNER_RADIUS(io->theme->windowCorners1)
}) {
gui.obstructing_window();
gui.obstructing_window(localId);
isUpdatingColorLeft |= gui.color_picker_items("colorpickerleft", colorLeft, true, 300.0f - io->theme->padding1 * 2.0f);
bool hoveringOnDropdown = false;
isUpdatingColorLeft |= color_palette("colorpickerleftpalette", colorLeft, hoveringOnDropdown);
@ -1314,7 +1327,8 @@ void Toolbar::drawing_program_gui() {
.padding = {.top = 40, .bottom = 40}
}
}) {
CLAY_AUTO_ID({
auto localID = CLAY_ID_LOCAL("Drawing program gui color picker right");
CLAY(localID, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(300), .height = CLAY_SIZING_FIT(0)},
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -1325,7 +1339,7 @@ void Toolbar::drawing_program_gui() {
.backgroundColor = convert_vec4<Clay_Color>(io->theme->backColor1),
.cornerRadius = CLAY_CORNER_RADIUS(io->theme->windowCorners1)
}) {
gui.obstructing_window();
gui.obstructing_window(localID);
isUpdatingColorRight |= gui.color_picker_items("colorpickerright", colorRight, true, 300.0f - io->theme->padding1 * 2.0f);
bool hoveringOnDropdown = false;
isUpdatingColorRight |= color_palette("colorpickerrightpalette", colorRight, hoveringOnDropdown);
@ -1506,7 +1520,8 @@ void Toolbar::performance_metrics() {
}
void Toolbar::player_list() {
CLAY_AUTO_ID({
Clay_ElementId elemId = CLAY_ID_LOCAL("INFINIPAINT PLAYER LIST");
CLAY(elemId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(500), .height = CLAY_SIZING_FIT(0) },
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -1518,7 +1533,7 @@ void Toolbar::player_list() {
.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}
}) {
gui.obstructing_window();
gui.obstructing_window(elemId);
gui.push_id("client list");
gui.text_label_centered("Player List");
if(!main.world->clientStillConnecting) {
@ -1599,7 +1614,8 @@ void Toolbar::options_menu() {
switch(optionsMenuType) {
case HOST_MENU:
case CONNECT_MENU: {
CLAY_AUTO_ID({
Clay_ElementId elemId = CLAY_ID_LOCAL("INFINIPAINT CONNECT MENU");
CLAY(elemId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(650), .height = CLAY_SIZING_FIT(0) },
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -1611,7 +1627,7 @@ void Toolbar::options_menu() {
.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}
}) {
gui.obstructing_window();
gui.obstructing_window(elemId);
if(optionsMenuType == HOST_MENU) {
gui.push_id("host menu");
std::string oldS = serverToConnectTo;
@ -1666,7 +1682,8 @@ void Toolbar::options_menu() {
.floating = {.attachPoints = {.element = CLAY_ATTACH_POINT_CENTER_CENTER, .parent = CLAY_ATTACH_POINT_CENTER_CENTER}, .attachTo = CLAY_ATTACH_TO_PARENT}
}) {
gui.push_id("gsettings");
CLAY_AUTO_ID({
Clay_ElementId elemId = CLAY_ID_LOCAL("INFINIPAINT GENERAL SETTINGS MENU");
CLAY(elemId, {
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)},
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -1675,7 +1692,7 @@ void Toolbar::options_menu() {
.layoutDirection = CLAY_LEFT_TO_RIGHT
}
}) {
gui.obstructing_window();
gui.obstructing_window(elemId);
CLAY_AUTO_ID({
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(150), .height = CLAY_SIZING_GROW(0) },
@ -1913,7 +1930,8 @@ void Toolbar::options_menu() {
break;
}
case LOBBY_INFO_MENU: {
CLAY_AUTO_ID({
Clay_ElementId elemId = CLAY_ID_LOCAL("INFINIPAINT LOBBY INFO MENU");
CLAY(elemId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(650), .height = CLAY_SIZING_FIT(0) },
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -1926,7 +1944,7 @@ void Toolbar::options_menu() {
.floating = {.attachPoints = {.element = CLAY_ATTACH_POINT_CENTER_CENTER, .parent = CLAY_ATTACH_POINT_CENTER_CENTER}, .attachTo = CLAY_ATTACH_TO_PARENT}
}) {
gui.push_id("lobby info menu");
gui.obstructing_window();
gui.obstructing_window(elemId);
if(!main.world || !main.world->netObjMan.is_connected())
optionsMenuOpen = false;
else {
@ -1945,7 +1963,8 @@ void Toolbar::options_menu() {
break;
}
case CANVAS_SETTINGS_MENU: {
CLAY_AUTO_ID({
Clay_ElementId elemId = CLAY_ID_LOCAL("INFINIPAINT CANVAS SETTINGS MENU");
CLAY(elemId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(500), .height = CLAY_SIZING_FIT(0) },
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -1958,7 +1977,7 @@ void Toolbar::options_menu() {
.floating = {.attachPoints = {.element = CLAY_ATTACH_POINT_CENTER_CENTER, .parent = CLAY_ATTACH_POINT_CENTER_CENTER}, .attachTo = CLAY_ATTACH_TO_PARENT}
}) {
gui.push_id("canvas settings menu");
gui.obstructing_window();
gui.obstructing_window(elemId);
SkColor4f newColorToSet = main.world->canvasTheme.get_back_color();
gui.color_picker_button_field("canvasColor", "Canvas Color", &newColorToSet, false);
main.world->canvasTheme.set_back_color(convert_vec3<Vector3f>(newColorToSet));
@ -1969,7 +1988,8 @@ void Toolbar::options_menu() {
break;
}
case SET_DOWNLOAD_NAME: {
CLAY_AUTO_ID({
Clay_ElementId elemId = CLAY_ID_LOCAL("INFINIPAINT DOWNLOAD NAME MENU");
CLAY(elemId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(500), .height = CLAY_SIZING_FIT(0) },
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -1982,7 +2002,7 @@ void Toolbar::options_menu() {
.floating = {.attachPoints = {.element = CLAY_ATTACH_POINT_CENTER_CENTER, .parent = CLAY_ATTACH_POINT_CENTER_CENTER}, .attachTo = CLAY_ATTACH_TO_PARENT}
}) {
gui.push_id("set download name menu");
gui.obstructing_window();
gui.obstructing_window(elemId);
if(!main.world)
optionsMenuOpen = false;
gui.input_text_field("file name", "File Name", &downloadNameSet);
@ -2006,7 +2026,8 @@ void Toolbar::options_menu() {
}
void Toolbar::about_menu_gui() {
CLAY_AUTO_ID({
Clay_ElementId elemId = CLAY_ID_LOCAL("INFINIPAINT ABOUT MENU");
CLAY(elemId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIXED(700), .height = CLAY_SIZING_FIXED(600) },
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -2019,7 +2040,7 @@ void Toolbar::about_menu_gui() {
.floating = {.attachPoints = {.element = CLAY_ATTACH_POINT_CENTER_CENTER, .parent = CLAY_ATTACH_POINT_CENTER_CENTER}, .attachTo = CLAY_ATTACH_TO_PARENT}
}) {
gui.push_id("about menu popup");
gui.obstructing_window();
gui.obstructing_window(elemId);
gui.left_to_right_line_layout([&]() {
gui.push_id("Menu Selector");
CLAY_AUTO_ID({
@ -2088,8 +2109,9 @@ void Toolbar::reload_theme_list() {
void Toolbar::file_picker_gui() {
gui.push_id("filepicker");
Clay_ElementId elemId = CLAY_ID_LOCAL("INFINIPAINT FILE PICKER MENU");
bool isDoneByDoubleClick = false;
CLAY_AUTO_ID({
CLAY(elemId, {
.layout = {
.sizing = {.width = CLAY_SIZING_FIXED(700), .height = CLAY_SIZING_FIXED(500) },
.padding = CLAY_PADDING_ALL(io->theme->padding1),
@ -2101,7 +2123,7 @@ void Toolbar::file_picker_gui() {
.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}
}) {
gui.obstructing_window();
gui.obstructing_window(elemId);
gui.text_label_centered(filePicker.filePickerWindowName);
gui.left_to_right_line_layout([&]() {
if(gui.svg_icon_button("file picker back button", "data/icons/backarrow.svg", false, 30.0f)) {
@ -2274,6 +2296,8 @@ void Toolbar::start_gui() {
}
gui.io = io;
io->hoverObstructed = false;
io->hoverObstructingAABBs.clear();
io->hoverObstructingCircles.clear();
gui.begin();
}

View file

@ -165,6 +165,9 @@ void World::init_client(const std::string& serverFullID) {
}
void World::focus_update() {
mousePreviousWorldVec = drawData.cam.c.from_space(main.input.mouse.pos);
mouseWorldMove = drawData.cam.c.from_space(main.input.mouse.move);
connection_update();
if(setToDestroy)
return;
@ -189,9 +192,6 @@ void World::focus_update() {
rMan.update();
mousePreviousWorldVec = drawData.cam.c.from_space(main.input.mouse.pos);
mouseWorldMove = drawData.cam.c.from_space(main.input.mouse.move);
if(main.input.key(InputManager::KEY_UNDO).repeat)
undo_with_checks();
else if(main.input.key(InputManager::KEY_REDO).repeat)

View file

@ -197,6 +197,8 @@ void get_refresh_rate(MainStruct& mS) {
void initialize_sdl(MainStruct& mS, int wWidth, int wHeight) {
SDL_SetHint(SDL_HINT_APP_NAME, "InfiniPaint");
SDL_SetHint(SDL_HINT_PEN_MOUSE_EVENTS, "0");
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
SDL_SetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT, "#canvas"); // Ensures that SDL only grabs input when browser is focused on canvas
if(!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD))
@ -602,6 +604,24 @@ void attempt_redraw_and_swap_buffers(MainStruct& mS) {
}
}
void regular_draw(MainStruct& mS) {
mS.lastRenderTimePoint = std::chrono::steady_clock::now();
mS.intermediateCanvas->save();
mS.m->draw(mS.intermediateCanvas, mS.m->world, mS.m->world->drawData);
mS.intermediateCanvas->restore();
#ifdef USE_BACKEND_VULKAN
mS.vulkanWindowContext->getBackbufferSurface()->getCanvas()->drawImage(mS.intermediateSurface->makeTemporaryImage(), 0, 0);
mS.ctx->flushAndSubmit();
mS.vulkanWindowContext->swapBuffers();
#elif USE_BACKEND_OPENGL
mS.canvas->drawImage(mS.intermediateSurface->makeTemporaryImage(), 0, 0);
mS.ctx->flushAndSubmit();
SDL_GL_SwapWindow(mS.window);
#endif
}
SDL_AppResult SDL_AppIterate(void *appstate) {
std::chrono::steady_clock::time_point frameTimeStart = std::chrono::steady_clock::now();
@ -645,8 +665,9 @@ SDL_AppResult SDL_AppIterate(void *appstate) {
SDL_StopTextInput(mS.window);
mS.m->input.text.lastAcceptingTextInputVal = mS.m->input.text.get_accepting_input();
cpu_save_sleep(mS);
attempt_redraw_and_swap_buffers(mS);
//cpu_save_sleep(mS);
//attempt_redraw_and_swap_buffers(mS);
regular_draw(mS);
mS.m->input.frame_reset(mS.m->window.size);
#ifdef NDEBUG
@ -815,6 +836,32 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) {
//mS.m->input.mouse.set_pos({event->pbutton.x, event->pbutton.y});
break;
}
case SDL_EVENT_FINGER_DOWN: {
mS.m->update_scale_and_density();
mS.m->input.touch.isDown = true;
mS.m->input.mouse.leftDown = true;
if((std::chrono::steady_clock::now() - mS.m->input.touch.lastLeftClickTime) > std::chrono::milliseconds(300))
mS.m->input.touch.leftClicksSaved = 0;
mS.m->input.touch.leftClicksSaved++;
mS.m->input.mouse.leftClicks = mS.m->input.touch.leftClicksSaved;
mS.m->input.touch.lastLeftClickTime = std::chrono::steady_clock::now();
mS.m->input.mouse.set_pos({event->tfinger.x * mS.m->window.size.x() * mS.m->window.density, event->tfinger.y * mS.m->window.size.y() * mS.m->window.density});
mS.m->input.mouse.move = Vector2f{0.0f, 0.0f};
break;
}
case SDL_EVENT_FINGER_UP: {
mS.m->update_scale_and_density();
mS.m->input.touch.isDown = false;
mS.m->input.mouse.leftDown = false;
mS.m->input.mouse.set_pos({-1.0f, -1.0f});
mS.m->input.mouse.move = Vector2f{0.0f, 0.0f};
break;
}
case SDL_EVENT_FINGER_MOTION: {
mS.m->update_scale_and_density();
mS.m->input.mouse.set_pos({event->tfinger.x * mS.m->window.size.x() * mS.m->window.density, event->tfinger.y * mS.m->window.size.y() * mS.m->window.density});
break;
}
case SDL_EVENT_DISPLAY_ORIENTATION:
case SDL_EVENT_DISPLAY_ADDED:
case SDL_EVENT_DISPLAY_REMOVED: