From 4774f1ee9441fc4f64cc28aa0273c74d727a8011 Mon Sep 17 00:00:00 2001 From: Yousef Khadadeh Date: Wed, 13 May 2026 14:31:35 +0300 Subject: [PATCH] Added more menus to phone version --- src/Bookmarks/BookmarkManager.cpp | 6 +- src/DrawingProgram/DrawingProgram.cpp | 2 +- .../Layers/DrawingProgramLayerManagerGUI.cpp | 4 +- src/DrawingProgram/Tools/GridModifyTool.cpp | 4 +- .../ElementHelpers/TextLabelHelpers.cpp | 26 ++ .../ElementHelpers/TextLabelHelpers.hpp | 3 + src/GUIStuff/Elements/CheckBox.cpp | 3 +- src/GUIStuff/Elements/NumberSlider.hpp | 3 +- src/GUIStuff/Elements/RadioButton.cpp | 3 +- src/GUIStuff/GUIManager.cpp | 2 +- src/GlobalConfig.cpp | 17 +- src/GridManager.cpp | 105 ++++++ src/GridManager.hpp | 7 + src/MainProgram.cpp | 2 + src/Screens/FileSelectScreen.cpp | 344 +++++++++++------- src/Screens/FileSelectScreen.hpp | 47 ++- src/Screens/PhoneDrawingProgramScreen.cpp | 160 +++++++- src/Screens/PhoneDrawingProgramScreen.hpp | 12 +- src/Toolbar.cpp | 158 ++------ src/Toolbar.hpp | 11 +- src/World.cpp | 6 +- src/main.cpp | 14 +- 22 files changed, 633 insertions(+), 306 deletions(-) diff --git a/src/Bookmarks/BookmarkManager.cpp b/src/Bookmarks/BookmarkManager.cpp index 9a37cbc..2cb5aec 100644 --- a/src/Bookmarks/BookmarkManager.cpp +++ b/src/Bookmarks/BookmarkManager.cpp @@ -75,7 +75,7 @@ void BookmarkManager::setup_list_gui() { if(bookmarkListRoot) { auto& gui = world.main.g.gui; if(bookmarkListRoot->get_folder_list()->empty()) - text_label_centered(gui, "No bookmarks yet..."); + text_label_centered(gui, "No bookmarks exist."); else { gui.element("bookmark list", TreeListing::Data { .selectedIndices = &selectedBookmarkIndices, @@ -110,7 +110,7 @@ void BookmarkManager::setup_list_gui() { .childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER} }, }) { - text_label(gui, bookmark->get_name()); + ellipse_wide_paragraph_label(gui, "bookmark name", bookmark->get_name()); } if(!bookmark->is_folder()) { gui.set_z_index_keep_clipping_region(gui.get_z_index() + 1, [&] { @@ -375,7 +375,7 @@ void BookmarkManager::setup_list_gui() { auto editingBookmarkLock = editingBookmark.lock(); if(editingBookmarkLock) { - text_label_centered(gui, editingBookmarkLock->is_folder() ? "Edit Bookmark Folder" : "Edit Bookmark"); + text_label_centered(gui, editingBookmarkLock->is_folder() ? "Edit Folder" : "Edit Bookmark"); input_text_field(gui, "input edit name", "Name", &nameToEdit, { .onEdit = [&] { auto editingBookmarkLock = editingBookmark.lock(); diff --git a/src/DrawingProgram/DrawingProgram.cpp b/src/DrawingProgram/DrawingProgram.cpp index 13e3913..b2e9ea5 100644 --- a/src/DrawingProgram/DrawingProgram.cpp +++ b/src/DrawingProgram/DrawingProgram.cpp @@ -758,7 +758,7 @@ CanvasComponentContainer::ObjInfo* DrawingProgram::add_file_to_canvas_by_data(co } float DrawingProgram::drag_point_radius() { - return 8.0f * world.main.g.final_gui_scale(); + return (world.main.g.gui.io.isTouchDevice ? 10.0f : 8.0f) * world.main.g.final_gui_scale(); } void DrawingProgram::draw_drag_circle(SkCanvas* canvas, const Vector2f& sPos, const SkColor4f& c, const DrawData& drawData, float radiusMultiplier) { diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp b/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp index 82087d8..f96a11c 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp @@ -122,7 +122,7 @@ void DrawingProgramLayerManagerGUI::setup_list_gui() { .childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER} }, }) { - text_label(gui, layer->get_name()); + ellipse_wide_paragraph_label(gui, "layer name", layer->get_name()); } if(!layer->is_folder()) { gui.set_z_index_keep_clipping_region(gui.get_z_index() + 1, [&] { @@ -411,7 +411,7 @@ void DrawingProgramLayerManagerGUI::setup_list_gui() { auto editingLayerLock = editingLayer.lock(); if(editingLayerLock) { - text_label_centered(gui, editingLayerLock->is_folder() ? "Edit Layer Folder" : "Edit Layer"); + text_label_centered(gui, editingLayerLock->is_folder() ? "Edit Folder" : "Edit Layer"); input_text_field(gui, "input edit name", "Name", &nameToEdit, { .onEdit = [&] { auto editingLayerLock = editingLayer.lock(); diff --git a/src/DrawingProgram/Tools/GridModifyTool.cpp b/src/DrawingProgram/Tools/GridModifyTool.cpp index 25da419..67f05f5 100644 --- a/src/DrawingProgram/Tools/GridModifyTool.cpp +++ b/src/DrawingProgram/Tools/GridModifyTool.cpp @@ -45,6 +45,7 @@ void GridModifyTool::set_grid(const NetObjWeakPtr& newGrid) { oldGrid = g; CoordSpaceHelper newCam; newCam.inverseScale = g.size / WorldScalar(WorldGrid::GRID_UNIT_PIXEL_SIZE); + newCam.inverseScale = newCam.inverseScale.divide_double(drawP.world.main.g.final_gui_scale()); newCam.pos = g.offset - drawP.world.main.window.size.cast() * newCam.inverseScale * WorldScalar(0.5); newCam.rotation = 0.0; drawP.world.drawData.cam.smooth_move_to(drawP.world, newCam, drawP.world.main.window.size.cast()); @@ -219,7 +220,8 @@ void GridModifyTool::gui_phone_toolbox(PhoneDrawingProgramScreen& t) { else g.bounds = std::nullopt; }); - checkbox_boolean_field(gui, "Show Coordinates", "Show Coordinates (visible\nwhen canvas isn't rotated)", &g.showCoordinates); + // Very hard to not have a rotated canvas on phone + //checkbox_boolean_field(gui, "Show Coordinates", "Show Coordinates (visible\nwhen canvas isn't rotated)", &g.showCoordinates); } }); } diff --git a/src/GUIStuff/ElementHelpers/TextLabelHelpers.cpp b/src/GUIStuff/ElementHelpers/TextLabelHelpers.cpp index 3a482fd..416a031 100644 --- a/src/GUIStuff/ElementHelpers/TextLabelHelpers.cpp +++ b/src/GUIStuff/ElementHelpers/TextLabelHelpers.cpp @@ -18,6 +18,8 @@ #include "TextLabelHelpers.hpp" #include "../Elements/MutableTextLabel.hpp" +#include "../Elements/TextParagraph.hpp" +#include "../Elements/LayoutElement.hpp" #include "Helpers/ConvertVec.hpp" namespace GUIStuff { namespace ElementHelpers { @@ -65,4 +67,28 @@ void mutable_text_label(GUIManager& gui, const char* id, const std::string& val) gui.element(id, val, textConfig); } +void mutable_text_label_light(GUIManager& gui, const char* id, const std::string& val) { + Clay_TextElementConfig textConfig = CLAY_TEXT_CONFIG({.textColor = convert_vec4(gui.io.theme->frontColor2), .fontSize = gui.io.fontSize }); + gui.element(id, val, textConfig); +} + +void ellipse_wide_paragraph_label(GUIManager& gui, const char* id, const std::string& val) { + gui.element(id, [&](LayoutElement* l, const Clay_ElementId& lId) { + CLAY(lId, { + .layout = {.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIT(0)}} + }) { + if(l->get_bb().has_value()) { + RichText::TextData t; + t.paragraphs.emplace_back(); + t.paragraphs.back().text = val; + gui.element("p", TextParagraph::Data{ + .text = t, + .maxGrowX = l->get_bb().value().width(), + .ellipsis = true + }); + } + } + }); +} + }} diff --git a/src/GUIStuff/ElementHelpers/TextLabelHelpers.hpp b/src/GUIStuff/ElementHelpers/TextLabelHelpers.hpp index a2ee966..6b30748 100644 --- a/src/GUIStuff/ElementHelpers/TextLabelHelpers.hpp +++ b/src/GUIStuff/ElementHelpers/TextLabelHelpers.hpp @@ -29,5 +29,8 @@ void text_label_light_centered(GUIManager& gui, std::string_view val); void text_label_centered(GUIManager& gui, std::string_view val); void mutable_text_label(GUIManager& gui, const char* id, const std::string& val); +void mutable_text_label_light(GUIManager& gui, const char* id, const std::string& val); + +void ellipse_wide_paragraph_label(GUIManager& gui, const char* id, const std::string& val); }} diff --git a/src/GUIStuff/Elements/CheckBox.cpp b/src/GUIStuff/Elements/CheckBox.cpp index 04a58a6..e078443 100644 --- a/src/GUIStuff/Elements/CheckBox.cpp +++ b/src/GUIStuff/Elements/CheckBox.cpp @@ -31,9 +31,10 @@ void CheckBox::layout(const Clay_ElementId& id, const std::function& isT this->isTicked = isTicked; this->onClick = onClick; + float size = gui.io.isTouchDevice ? 25 : 15; CLAY(id, { .layout = { - .sizing = {.width = CLAY_SIZING_FIXED(15), .height = CLAY_SIZING_FIXED(15)} + .sizing = {.width = CLAY_SIZING_FIXED(size), .height = CLAY_SIZING_FIXED(size)} }, .custom = { .customData = this } }) {} diff --git a/src/GUIStuff/Elements/NumberSlider.hpp b/src/GUIStuff/Elements/NumberSlider.hpp index 58554e1..724bfa8 100644 --- a/src/GUIStuff/Elements/NumberSlider.hpp +++ b/src/GUIStuff/Elements/NumberSlider.hpp @@ -43,9 +43,10 @@ template class NumberSlider : public Element { dd.maxData = maxData; this->config = config; + float height = gui.io.isTouchDevice ? 25 : 10; CLAY(id, { .layout = { - .sizing = {.width = CLAY_SIZING_GROW(100), .height = CLAY_SIZING_FIXED(10)} + .sizing = {.width = CLAY_SIZING_GROW(100), .height = CLAY_SIZING_FIXED(height)} }, .custom = { .customData = this } }) { diff --git a/src/GUIStuff/Elements/RadioButton.cpp b/src/GUIStuff/Elements/RadioButton.cpp index fa5ed3e..d88f08e 100644 --- a/src/GUIStuff/Elements/RadioButton.cpp +++ b/src/GUIStuff/Elements/RadioButton.cpp @@ -29,9 +29,10 @@ void RadioButton::layout(const Clay_ElementId& id, const std::function& this->onClick = onClick; this->isTicked = isTicked; + float size = gui.io.isTouchDevice ? 25 : 20; CLAY(id, { .layout = { - .sizing = {.width = CLAY_SIZING_FIXED(20), .height = CLAY_SIZING_FIXED(20)} + .sizing = {.width = CLAY_SIZING_FIXED(size), .height = CLAY_SIZING_FIXED(size)} }, .custom = { .customData = this } }) {} diff --git a/src/GUIStuff/GUIManager.cpp b/src/GUIStuff/GUIManager.cpp index fae87ff..115dede 100644 --- a/src/GUIStuff/GUIManager.cpp +++ b/src/GUIStuff/GUIManager.cpp @@ -574,7 +574,7 @@ void GUIManager::layout_if_necessary() { } void GUIManager::layout() { - constexpr int LAYOUT_RUN_COUNT = 6; + constexpr int LAYOUT_RUN_COUNT = 8; for(int i = 0; i < LAYOUT_RUN_COUNT; i++) single_layout_run(); } diff --git a/src/GlobalConfig.cpp b/src/GlobalConfig.cpp index 2fbb5f5..6b15a04 100644 --- a/src/GlobalConfig.cpp +++ b/src/GlobalConfig.cpp @@ -22,12 +22,13 @@ #include "ResourceDisplay/ImageResourceDisplay.hpp" #include "DrawingProgram/DrawingProgramCache.hpp" #include -#include GlobalConfig::GlobalConfig() { load_default_palette(); displayName = Random::get().alphanumeric_str(10); SDL_GetDateTimeLocalePreferences(&dateFormat, &timeFormat); + if(dateFormat == SDL_DATE_FORMAT_YYYYMMDD) // Can't display this in a friendly way, so changing it for now + dateFormat = SDL_DATE_FORMAT_DDMMYYYY; } nlohmann::json GlobalConfig::get_config_json(const InputManager& input) const { @@ -151,14 +152,12 @@ void GlobalConfig::set_config_json(InputManager& input, const nlohmann::json& j, } void GlobalConfig::save_palettes() { - using json = nlohmann::json; - json j; + nlohmann::json j; auto palettesToSave = palettes; palettesToSave.erase(palettesToSave.begin()); nlohmann::to_json(j, palettesToSave); - std::stringstream f; - f << j; - SDL_SaveFile((configPath / "palettes.json").string().c_str(), f.view().data(), f.view().size()); + std::string saveJson = nlohmann::to_string(j); + SDL_SaveFile((configPath / "palettes.json").string().c_str(), saveJson.c_str(), saveJson.size()); } void GlobalConfig::load_palettes() { @@ -166,9 +165,9 @@ void GlobalConfig::load_palettes() { using json = nlohmann::json; try { json j(nlohmann::json::parse(read_file_to_string(configPath / "palettes.json"))); - std::vector palettes; - j.get_to(palettes); - palettes.insert(palettes.end(), palettes.begin(), palettes.end()); + std::vector p; + j.get_to(p); + palettes.insert(palettes.end(), p.begin(), p.end()); } catch(...) {} } diff --git a/src/GridManager.cpp b/src/GridManager.cpp index 3b92f6b..292c9bf 100644 --- a/src/GridManager.cpp +++ b/src/GridManager.cpp @@ -20,6 +20,15 @@ #include "World.hpp" #include "MainProgram.hpp" #include "WorldUndoManager.hpp" +#include "GUIStuff/ElementHelpers/TextLabelHelpers.hpp" +#include "GUIStuff/ElementHelpers/LayoutHelpers.hpp" +#include "GUIStuff/ElementHelpers/ButtonHelpers.hpp" +#include "GUIStuff/ElementHelpers/TextBoxHelpers.hpp" +#include "GUIStuff/Elements/ManyElementScrollArea.hpp" +#include "GUIStuff/Elements/LayoutElement.hpp" +#include "GUIStuff/Elements/SelectableButton.hpp" +#include +#include "WorldGrid.hpp" #include GridManager::GridManager(World& w): @@ -254,3 +263,99 @@ void GridManager::load_file(cereal::PortableBinaryInputArchive& a, VersionNumber grids->emplace_back_direct(grids, wGrid); } } + +void GridManager::setup_list_gui(const std::function& onStartModify) { + auto& gui = world.main.g.gui; + auto& main = world.main; + + using namespace GUIStuff; + using namespace ElementHelpers; + + auto add_grid = [&, onStartModify] { + if(!gridMenu.newName.empty()) { + main.world->gridMan.add_default_grid(gridMenu.newName); + main.world->drawProg.modify_grid(main.world->gridMan.grids->at(main.world->gridMan.grids->size() - 1)->obj); + if(onStartModify) onStartModify(); + } + }; + + float ENTRY_HEIGHT = 25.0f; + if(main.world->gridMan.grids->empty()) + text_label_centered(gui, "No grids exist."); + gui.element("grid menu entries", ManyElementScrollArea::Options{ + .entryHeight = ENTRY_HEIGHT, + .entryCount = main.world->gridMan.grids->size(), + .clipHorizontal = true, + .elementContent = [&, onStartModify](size_t i) { + auto& grid = main.world->gridMan.grids->at(i)->obj; + bool selectedEntry = gridMenu.selectedGrid == i; + gui.element("elem", [&, onStartModify] (LayoutElement*, const Clay_ElementId& lId2) { + CLAY(lId2, { + .layout = { + .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(ENTRY_HEIGHT)}, + .childGap = 2, + .childAlignment = { .x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER}, + .layoutDirection = CLAY_LEFT_TO_RIGHT + }, + .backgroundColor = selectedEntry ? convert_vec4(gui.io.theme->backColor1) : convert_vec4(gui.io.theme->backColor2) + }) { + text_label(gui, grid->get_display_name()); + CLAY_AUTO_ID({ + .layout = { + .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}, + .childGap = 1, + .childAlignment = {.x = CLAY_ALIGN_X_RIGHT, .y = CLAY_ALIGN_Y_CENTER}, + .layoutDirection = CLAY_LEFT_TO_RIGHT + } + }) { + auto list_button = [&](const char* id, const char* svgPath, const std::function& onClick) { + gui.set_z_index_keep_clipping_region(gui.get_z_index() + 1, [&] { + svg_icon_button(gui, id, svgPath, { + .drawType = SelectableButton::DrawType::TRANSPARENT_ALL, + .size = ENTRY_HEIGHT, + .onClick = onClick + }); + }); + }; + list_button("visibility eye", grid->visible ? "data/icons/eyeopen.svg" : "data/icons/eyeclose.svg", [&] { + grid->visible = !grid->visible; + NetworkingObjects::generic_serialized_class_send_update_to_all(grid); + }); + list_button("edit pencil", "data/icons/pencil.svg", [&, onStartModify] { + main.world->drawProg.modify_grid(grid); + if(onStartModify) onStartModify(); + }); + list_button("delete trash", "data/icons/trash.svg", [&, i] { + main.world->gridMan.remove_grid(i); + }); + } + } + }, LayoutElement::Callbacks { + .onClick = [&, i, onStartModify] (LayoutElement* l, const InputManager::MouseButtonCallbackArgs& button) { + if(l->mouseHovering && button.down && button.button == InputManager::MouseButton::LEFT) { + gridMenu.selectedGrid = i; + if(button.clicks == 2) { + main.world->drawProg.modify_grid(grid); + if(onStartModify) onStartModify(); + } + gui.set_to_layout(); + } + } + }); + } + }); + left_to_right_line_layout(gui, [&]() { + input_text(gui, "grid text input", &gridMenu.newName, { + .onEnter = [add_grid]() { add_grid(); } + }); + svg_icon_button(gui, "grid add button", "data/icons/plusbold.svg", { + .size = SMALL_BUTTON_SIZE, + .onClick = [add_grid] { add_grid(); } + }); + }); +} + +void GridManager::refresh_gui_data() { + gridMenu.newName.clear(); + gridMenu.selectedGrid = std::numeric_limits::max(); +} diff --git a/src/GridManager.hpp b/src/GridManager.hpp index 6b0d695..1917334 100644 --- a/src/GridManager.hpp +++ b/src/GridManager.hpp @@ -56,6 +56,13 @@ class GridManager { void save_file(cereal::PortableBinaryOutputArchive& a) const; void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version); void finalize_grid_modify(const NetworkingObjects::NetObjTemporaryPtr& wGrid, const WorldGrid& oldGridData); + void refresh_gui_data(); + void setup_list_gui(const std::function& onStartModify); + + struct GridMenuGUIData { + std::string newName; + uint32_t selectedGrid = std::numeric_limits::max(); + } gridMenu; NetworkingObjects::NetObjOwnerPtr> grids; World& world; diff --git a/src/MainProgram.cpp b/src/MainProgram.cpp index ba0c0b2..f3890a4 100755 --- a/src/MainProgram.cpp +++ b/src/MainProgram.cpp @@ -127,6 +127,7 @@ void MainProgram::save_config() { std::stringstream f; f << std::setw(4) << j; SDL_SaveFile((conf.configPath / "config.json").string().c_str(), f.view().data(), f.view().size()); + conf.save_palettes(); } @@ -290,6 +291,7 @@ void MainProgram::post_callback() { void MainProgram::input_app_about_to_go_to_background_callback() { screen->input_app_about_to_go_to_background_callback(); + save_config(); post_callback(); } diff --git a/src/Screens/FileSelectScreen.cpp b/src/Screens/FileSelectScreen.cpp index efe48f4..e56d795 100644 --- a/src/Screens/FileSelectScreen.cpp +++ b/src/Screens/FileSelectScreen.cpp @@ -31,12 +31,12 @@ #include "../GUIStuff/ElementHelpers/LayoutHelpers.hpp" #include "../GUIStuff/ElementHelpers/ColorPickerHelpers.hpp" #include "../GUIStuff/ElementHelpers/CheckBoxHelpers.hpp" -#include "../GUIStuff/Elements/PositionAdjustingPopupMenu.hpp" #include "../World.hpp" #include "Helpers/StringHelpers.hpp" #include "PhoneDrawingProgramScreen.hpp" #include #include +#include #define MAIN_MENU_SIZE 300 @@ -44,16 +44,17 @@ using namespace GUIStuff; using namespace ElementHelpers; FileSelectScreen::FileSelectScreen(MainProgram& m): Screen(m) { + main.g.gui.io.isTouchDevice = true; savePath = main.conf.configPath / "saves"; trashPath = main.conf.configPath / "trash"; - trashInfoPath = main.conf.configPath / "trashInfo.json"; + infoPath = main.conf.configPath / "fileSelectInfo.json"; SDL_CreateDirectory(savePath.string().c_str()); SDL_CreateDirectory(trashPath.string().c_str()); try { - nlohmann::json j(nlohmann::json::parse(read_file_to_string(trashInfoPath))); - j.get_to(trashInfo); + nlohmann::json j(nlohmann::json::parse(read_file_to_string(infoPath))); + j.get_to(saveInfo); } catch(...) {} @@ -88,9 +89,9 @@ void FileSelectScreen::update_file_list(std::vector& fL, const std::fi fileInfoToAdd.fileName = p.stem().string(); if(trashUpdate) { - auto it = trashInfo.files.find(fileInfoToAdd.fileName); - if(it == trashInfo.files.end()) { - trashInfo.files[fileInfoToAdd.fileName].trashTime = currentTime; + auto it = saveInfo.trash.files.find(fileInfoToAdd.fileName); + if(it == saveInfo.trash.files.end()) { + saveInfo.trash.files[fileInfoToAdd.fileName].trashTime = currentTime; fileInfoToAdd.lastModifyTime = currentTime; } else @@ -102,7 +103,7 @@ void FileSelectScreen::update_file_list(std::vector& fL, const std::fi // Remove file and thumbnail SDL_RemovePath(fullPath.string().c_str()); SDL_RemovePath((savePath / fileInfoToAdd.fileName / ".jpg").string().c_str()); - trashInfo.files.erase(it); + saveInfo.trash.files.erase(it); continue; } else if(daysSinceMovedToTrash == 29) @@ -129,6 +130,33 @@ void FileSelectScreen::update_file_list(std::vector& fL, const std::fi } else SDL_CreateDirectory(savePath.string().c_str()); + + sort_file_list(fL); +} + +void FileSelectScreen::sort_file_list(std::vector& fL) { + switch(saveInfo.fileSort) { + case SaveInfo::FileSort::ALPHABETICAL_ASCENDING: + std::stable_sort(fL.begin(), fL.end(), [&](const FileInfo& a, const FileInfo& b) { + return std::lexicographical_compare(a.fileName.begin(), a.fileName.end(), b.fileName.begin(), b.fileName.end()); + }); + break; + case SaveInfo::FileSort::ALPHABETICAL_DESCENDING: + std::stable_sort(fL.begin(), fL.end(), [&](const FileInfo& a, const FileInfo& b) { + return std::lexicographical_compare(b.fileName.begin(), b.fileName.end(), a.fileName.begin(), a.fileName.end()); + }); + break; + case SaveInfo::FileSort::TIME_ASCENDING: + std::stable_sort(fL.begin(), fL.end(), [&](const FileInfo& a, const FileInfo& b) { + return b.lastModifyTime < a.lastModifyTime; + }); + break; + case SaveInfo::FileSort::TIME_DESCENDING: + std::stable_sort(fL.begin(), fL.end(), [&](const FileInfo& a, const FileInfo& b) { + return a.lastModifyTime < b.lastModifyTime; + }); + break; + } } void FileSelectScreen::main_display() { @@ -289,12 +317,12 @@ void FileSelectScreen::move_selected_files(const std::filesystem::path& fromPath case TrashMoveType::NONE: break; case TrashMoveType::MOVE_TO_TRASH: - trashInfo.files[newFileName] = TrashInfo::TrashFile{ + saveInfo.trash.files[newFileName] = TrashInfo::TrashFile{ .trashTime = currentTime }; break; case TrashMoveType::MOVE_OUT_OF_TRASH: - trashInfo.files.erase(f.fileName); + saveInfo.trash.files.erase(f.fileName); break; } } @@ -330,7 +358,7 @@ void FileSelectScreen::delete_selected_files_in_trash() { std::filesystem::path thumbnailPath = trashPath / (f.fileName + ".jpg"); SDL_RemovePath(filePath.string().c_str()); SDL_RemovePath(thumbnailPath.string().c_str()); - trashInfo.files.erase(f.fileName); + saveInfo.trash.files.erase(f.fileName); } } } @@ -338,71 +366,71 @@ void FileSelectScreen::delete_selected_files_in_trash() { void FileSelectScreen::edit_action_bar() { auto& gui = main.g.gui; if(actionBarOpenAnim->get_val()) { - gui.set_z_index(gui.get_z_index() + 3, [&] { - CLAY_AUTO_ID({ - .layout = { - .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}, - .layoutDirection = CLAY_TOP_TO_BOTTOM - }, - .floating = { - .zIndex = gui.get_z_index(), - .attachPoints = { - .element = CLAY_ATTACH_POINT_LEFT_TOP, - .parent = CLAY_ATTACH_POINT_LEFT_TOP, - }, - .attachTo = CLAY_ATTACH_TO_PARENT, - } - }) { + gui.set_z_index(gui.get_z_index() + 3, [&] { CLAY_AUTO_ID({ - .layout = { .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}}, - }) {} - gui.element("edit action bar bottom fill", [&](LayoutElement*, const Clay_ElementId& lId) { - CLAY(lId, {}) { - window_fill_side_bar(gui, { - .dir = WindowFillSideBarConfig::Direction::BOTTOM, - .backgroundColor = gui.io.theme->backColor1 - }, [&] { - gui.element("edit action bar", [&](LayoutElement*, const Clay_ElementId& lId) { - CLAY(lId, { - .layout = { - .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(50 * actionBarOpenAnim->get_val())}, - .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER }, - .layoutDirection = CLAY_LEFT_TO_RIGHT, - } - }) { - if(actionBarOpenAnim->is_at_end()) { - if(selectedMenu == SelectedMenu::FILES) { - edit_action_bar_button("trash", "data/icons/trash.svg", "Trash", [&] { - move_selected_files(savePath, trashPath, TrashMoveType::MOVE_TO_TRASH); - update_file_list(fileList, savePath, false); - editMode = false; - }); - edit_action_bar_button("duplicate", "data/icons/RemixIcon/file-copy-line.svg", "Duplicate", [&] { - duplicate_selected_files(savePath); - update_file_list(fileList, savePath, false); - editMode = false; - }); - } - else if(selectedMenu == SelectedMenu::TRASH) { - edit_action_bar_button("restore", "data/icons/RemixIcon/refresh-line.svg", "Restore", [&] { - move_selected_files(trashPath, savePath, TrashMoveType::MOVE_OUT_OF_TRASH); - update_file_list(fileList, trashPath, true); - editMode = false; - }); - edit_action_bar_button("delete", "data/icons/trash.svg", "Delete", [&] { - delete_selected_files_in_trash(); - update_file_list(fileList, trashPath, true); - editMode = false; - }); - } - } - } - }); - }); + .layout = { + .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}, + .layoutDirection = CLAY_TOP_TO_BOTTOM + }, + .floating = { + .zIndex = gui.get_z_index(), + .attachPoints = { + .element = CLAY_ATTACH_POINT_LEFT_TOP, + .parent = CLAY_ATTACH_POINT_LEFT_TOP, + }, + .attachTo = CLAY_ATTACH_TO_PARENT, } - }); - } - }); + }) { + CLAY_AUTO_ID({ + .layout = { .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}}, + }) {} + gui.element("edit action bar bottom fill", [&](LayoutElement*, const Clay_ElementId& lId) { + CLAY(lId, {}) { + window_fill_side_bar(gui, { + .dir = WindowFillSideBarConfig::Direction::BOTTOM, + .backgroundColor = gui.io.theme->backColor1 + }, [&] { + gui.element("edit action bar", [&](LayoutElement*, const Clay_ElementId& lId) { + CLAY(lId, { + .layout = { + .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(50 * actionBarOpenAnim->get_val())}, + .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER }, + .layoutDirection = CLAY_LEFT_TO_RIGHT, + } + }) { + if(actionBarOpenAnim->is_at_end()) { + if(selectedMenu == SelectedMenu::FILES) { + edit_action_bar_button("trash", "data/icons/trash.svg", "Trash", [&] { + move_selected_files(savePath, trashPath, TrashMoveType::MOVE_TO_TRASH); + update_file_list(fileList, savePath, false); + editMode = false; + }); + edit_action_bar_button("duplicate", "data/icons/RemixIcon/file-copy-line.svg", "Duplicate", [&] { + duplicate_selected_files(savePath); + update_file_list(fileList, savePath, false); + editMode = false; + }); + } + else if(selectedMenu == SelectedMenu::TRASH) { + edit_action_bar_button("restore", "data/icons/RemixIcon/refresh-line.svg", "Restore", [&] { + move_selected_files(trashPath, savePath, TrashMoveType::MOVE_OUT_OF_TRASH); + update_file_list(fileList, trashPath, true); + editMode = false; + }); + edit_action_bar_button("delete", "data/icons/trash.svg", "Delete", [&] { + delete_selected_files_in_trash(); + update_file_list(fileList, trashPath, true); + editMode = false; + }); + } + } + } + }); + }); + } + }); + } + }); } } @@ -484,10 +512,19 @@ void FileSelectScreen::title_bar() { }); if(moreButton->get_bb().has_value() && moreOptionsMenu != MoreOptionsMenu::CLOSED) { size_t elemCount = 0; - if(moreOptionsMenu == MoreOptionsMenu::MAIN) - elemCount = 2; - else if(moreOptionsMenu == MoreOptionsMenu::VIEW) - elemCount = 4; + switch(moreOptionsMenu) { + case MoreOptionsMenu::CLOSED: + break; + case MoreOptionsMenu::MAIN: + elemCount = 3; + break; + case MoreOptionsMenu::VIEW: + elemCount = 4; + break; + case MoreOptionsMenu::SORT: + elemCount = 4; + break; + } gui.set_z_index(gui.get_z_index() + 10, [&] { dropdown_many_element_popup_layout(gui, "more options popup", { .button = moreButton, @@ -500,53 +537,98 @@ void FileSelectScreen::title_bar() { .entrySize = {200.0f, 30.0f}, .entryCount = elemCount, .entryLayout = [&] (size_t i) { - if(moreOptionsMenu == MoreOptionsMenu::MAIN) { - switch(i) { - case 0: { - text_transparent_option_button("Edit", "Edit", [&] { - moreOptionsMenu = MoreOptionsMenu::CLOSED; - start_edit_mode(); - }); - break; - } - case 1: { - text_transparent_option_button("View", "View", [&] { - moreOptionsMenu = MoreOptionsMenu::VIEW; - }); - break; + switch(moreOptionsMenu) { + case MoreOptionsMenu::CLOSED: + break; + case MoreOptionsMenu::MAIN: { + switch(i) { + case 0: { + text_transparent_option_button("Edit", "Edit", [&] { + moreOptionsMenu = MoreOptionsMenu::CLOSED; + start_edit_mode(); + }); + break; + } + case 1: { + text_transparent_option_button("View", "View", [&] { + moreOptionsMenu = MoreOptionsMenu::VIEW; + }); + break; + } + case 2: { + text_transparent_option_button("Sort", "Sort", [&] { + moreOptionsMenu = MoreOptionsMenu::SORT; + }); + break; + } } + break; } - } - else if(moreOptionsMenu == MoreOptionsMenu::VIEW) { - switch(i) { - case 0: { - text_transparent_option_button("Large Grid", "Large Grid", [&] { - fileViewType = FileViewType::LARGE_GRID; - moreOptionsMenu = MoreOptionsMenu::CLOSED; - }); - break; + case MoreOptionsMenu::VIEW: { + switch(i) { + case 0: { + text_transparent_option_button("Large Grid", "Large Grid", [&] { + saveInfo.fileViewType = SaveInfo::FileViewType::LARGE_GRID; + moreOptionsMenu = MoreOptionsMenu::CLOSED; + }); + break; + } + case 1: { + text_transparent_option_button("Medium Grid", "Medium Grid", [&] { + saveInfo.fileViewType = SaveInfo::FileViewType::MEDIUM_GRID; + moreOptionsMenu = MoreOptionsMenu::CLOSED; + }); + break; + } + case 2: { + text_transparent_option_button("Small Grid", "Small Grid", [&] { + saveInfo.fileViewType = SaveInfo::FileViewType::SMALL_GRID; + moreOptionsMenu = MoreOptionsMenu::CLOSED; + }); + break; + } + case 3: { + text_transparent_option_button("List", "List", [&] { + saveInfo.fileViewType = SaveInfo::FileViewType::LIST; + moreOptionsMenu = MoreOptionsMenu::CLOSED; + }); + break; + } } - case 1: { - text_transparent_option_button("Medium Grid", "Medium Grid", [&] { - fileViewType = FileViewType::MEDIUM_GRID; - moreOptionsMenu = MoreOptionsMenu::CLOSED; - }); - break; - } - case 2: { - text_transparent_option_button("Small Grid", "Small Grid", [&] { - fileViewType = FileViewType::SMALL_GRID; - moreOptionsMenu = MoreOptionsMenu::CLOSED; - }); - break; - } - case 3: { - text_transparent_option_button("List", "List", [&] { - fileViewType = FileViewType::LIST; - moreOptionsMenu = MoreOptionsMenu::CLOSED; - }); - break; + break; + } + case MoreOptionsMenu::SORT: { + switch(i) { + case 0: { + text_transparent_option_button("Alphabetical Ascending", "Alphabetical ↑", [&] { + saveInfo.fileSort = SaveInfo::FileSort::ALPHABETICAL_ASCENDING; + sort_file_list(fileList); + }); + break; + } + case 1: { + text_transparent_option_button("Alphabetical Descending", "Alphabetical ↓", [&] { + saveInfo.fileSort = SaveInfo::FileSort::ALPHABETICAL_DESCENDING; + sort_file_list(fileList); + }); + break; + } + case 2: { + text_transparent_option_button("Time Ascending", "Date modified ↑", [&] { + saveInfo.fileSort = SaveInfo::FileSort::TIME_ASCENDING; + sort_file_list(fileList); + }); + break; + } + case 3: { + text_transparent_option_button("Time Descending", "Date modified ↓", [&] { + saveInfo.fileSort = SaveInfo::FileSort::TIME_DESCENDING; + sort_file_list(fileList); + }); + break; + } } + break; } } } @@ -679,8 +761,8 @@ void FileSelectScreen::file_view() { .layoutDirection = CLAY_TOP_TO_BOTTOM } }) { - text_label(gui, fileList[i].fileName); - text_label_light(gui, fileList[i].lastModifyDate); + mutable_text_label(gui, "file name label", fileList[i].fileName); + mutable_text_label_light(gui, "last modify date", fileList[i].lastModifyDate); } } } @@ -720,14 +802,14 @@ void FileSelectScreen::file_view() { } } }); - text_label_light(gui, fileList[i].lastModifyDate); + mutable_text_label_light(gui, "last modify date", fileList[i].lastModifyDate); } } } }); }; - if(fileViewType == FileViewType::LIST) { + if(saveInfo.fileViewType == SaveInfo::FileViewType::LIST) { mainViewScrollArea = gui.element("File selector list", ManyElementScrollArea::Options{ .entryHeight = 150.0f, .entryCount = fileList.size(), @@ -741,16 +823,16 @@ void FileSelectScreen::file_view() { else { Vector2f entrySize{0.0f, 0.0f}; Vector2f iconSize{0.0f, 0.0f}; - switch(fileViewType) { - case FileViewType::LARGE_GRID: + switch(saveInfo.fileViewType) { + case SaveInfo::FileViewType::LARGE_GRID: entrySize = {170.0f, 210.0f}; iconSize = {130.0f, 130.0f}; break; - case FileViewType::MEDIUM_GRID: + case SaveInfo::FileViewType::MEDIUM_GRID: entrySize = {140.0f, 180.0f}; iconSize = {100.0f, 100.0f}; break; - case FileViewType::SMALL_GRID: + case SaveInfo::FileViewType::SMALL_GRID: entrySize = {110.0f, 150.0f}; iconSize = {70.0f, 70.0f}; break; @@ -863,9 +945,9 @@ void FileSelectScreen::draw(SkCanvas* canvas) { void FileSelectScreen::save_files() { nlohmann::json j; - nlohmann::to_json(j, trashInfo); + nlohmann::to_json(j, saveInfo); std::string saveJson = nlohmann::to_string(j); - SDL_SaveFile(trashInfoPath.string().c_str(), saveJson.c_str(), saveJson.size()); + SDL_SaveFile(infoPath.string().c_str(), saveJson.c_str(), saveJson.size()); } void FileSelectScreen::input_app_about_to_go_to_background_callback() { diff --git a/src/Screens/FileSelectScreen.hpp b/src/Screens/FileSelectScreen.hpp index bb9a2e5..2f0c4c9 100644 --- a/src/Screens/FileSelectScreen.hpp +++ b/src/Screens/FileSelectScreen.hpp @@ -39,12 +39,29 @@ class FileSelectScreen : public Screen { std::unordered_map files; NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(TrashInfo, files) }; - ~FileSelectScreen(); + struct SaveInfo { + TrashInfo trash; + enum class FileSort { + ALPHABETICAL_ASCENDING, + ALPHABETICAL_DESCENDING, + TIME_ASCENDING, + TIME_DESCENDING + } fileSort = FileSort::ALPHABETICAL_ASCENDING; + enum class FileViewType { + LARGE_GRID, + MEDIUM_GRID, + SMALL_GRID, + LIST + } fileViewType = FileViewType::MEDIUM_GRID; + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(SaveInfo, trash, fileSort, fileViewType) + } saveInfo; + + ~FileSelectScreen(); private: std::filesystem::path savePath; std::filesystem::path trashPath; - std::filesystem::path trashInfoPath; + std::filesystem::path infoPath; void save_files(); @@ -56,8 +73,8 @@ class FileSelectScreen : public Screen { }; void update_file_list(std::vector& fL, const std::filesystem::path& savePath, bool trashUpdate); + void sort_file_list(std::vector& fL); - TrashInfo trashInfo; std::vector fileList; GUIStuff::GUIFloatAnimation* mainMenuOpenAnim = nullptr; @@ -88,17 +105,11 @@ class FileSelectScreen : public Screen { void duplicate_selected_files(const std::filesystem::path& inPath); void delete_selected_files_in_trash(); - enum class FileViewType { - LARGE_GRID, - MEDIUM_GRID, - SMALL_GRID, - LIST - } fileViewType = FileViewType::LARGE_GRID; - enum class MoreOptionsMenu { CLOSED, MAIN, - VIEW + VIEW, + SORT } moreOptionsMenu = MoreOptionsMenu::CLOSED; enum class SelectedMenu { @@ -111,3 +122,17 @@ class FileSelectScreen : public Screen { size_t numberOfSelectedEntries; bool editMode = false; }; + +NLOHMANN_JSON_SERIALIZE_ENUM(FileSelectScreen::SaveInfo::FileSort, { + {FileSelectScreen::SaveInfo::FileSort::ALPHABETICAL_ASCENDING, "Alphabetical Ascending"}, + {FileSelectScreen::SaveInfo::FileSort::ALPHABETICAL_DESCENDING, "Alphabetical Descending"}, + {FileSelectScreen::SaveInfo::FileSort::TIME_ASCENDING, "Time Ascending"}, + {FileSelectScreen::SaveInfo::FileSort::TIME_DESCENDING, "Time Descending"}, +}) + +NLOHMANN_JSON_SERIALIZE_ENUM(FileSelectScreen::SaveInfo::FileViewType, { + {FileSelectScreen::SaveInfo::FileViewType::LARGE_GRID, "Large Grid"}, + {FileSelectScreen::SaveInfo::FileViewType::MEDIUM_GRID, "Medium Grid"}, + {FileSelectScreen::SaveInfo::FileViewType::SMALL_GRID, "Small Grid"}, + {FileSelectScreen::SaveInfo::FileViewType::LIST, "List"}, +}) diff --git a/src/Screens/PhoneDrawingProgramScreen.cpp b/src/Screens/PhoneDrawingProgramScreen.cpp index a6f2151..cc63b55 100644 --- a/src/Screens/PhoneDrawingProgramScreen.cpp +++ b/src/Screens/PhoneDrawingProgramScreen.cpp @@ -42,6 +42,34 @@ void PhoneDrawingProgramScreen::update() { DrawingProgramScreen::update(); } +void PhoneDrawingProgramScreen::center_message(const char* id, const std::string& m) { + auto& gui = main.g.gui; + auto& io = gui.io; + + gui.set_z_index(gui.get_z_index() + 1, [&] { + gui.element(id, [&] (LayoutElement*, const Clay_ElementId& lId) { + CLAY(lId, { + .layout = { + .sizing = {.width = CLAY_SIZING_FIT(0), .height = CLAY_SIZING_FIT(0) }, + .padding = CLAY_PADDING_ALL(io.theme->padding1), + .childGap = io.theme->childGap1, + .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_TOP}, + .layoutDirection = CLAY_TOP_TO_BOTTOM + }, + .backgroundColor = convert_vec4(io.theme->backColor1), + .cornerRadius = CLAY_CORNER_RADIUS(io.theme->windowCorners1), + .floating = { + .zIndex = gui.get_z_index(), + .attachPoints = {.element = CLAY_ATTACH_POINT_CENTER_CENTER, .parent = CLAY_ATTACH_POINT_CENTER_CENTER}, + .attachTo = CLAY_ATTACH_TO_PARENT, + } + }) { + text_label(gui, m); + } + }); + }); +} + void PhoneDrawingProgramScreen::gui_layout_run() { main_display(); } @@ -56,10 +84,105 @@ void PhoneDrawingProgramScreen::main_display() { }, }) { top_toolbar(); + top_toolbar_settings_popup(); CLAY_AUTO_ID({ .layout = {.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}} }) {} bottom_toolbar(); + if(!main.world->drawProg.layerMan.is_a_layer_being_edited()) + center_message("Select layer to edit message", "Select a layer to edit"); + } +} + +void PhoneDrawingProgramScreen::top_toolbar_settings_popup() { + auto& gui = main.g.gui; + auto& io = gui.io; + switch(topToolbarSettingsPopup) { + case TopToolbarSettingsPopup::NONE: + break; + case TopToolbarSettingsPopup::HIDDEN_BUTTONS: + break; + case TopToolbarSettingsPopup::BOOKMARKS: { + gui.set_z_index(gui.get_z_index() + 20, [&] { + gui.element("bookmark menu", [&] (LayoutElement*, const Clay_ElementId& lId) { + Vector2f popupSize = { + std::clamp(gui.io.safeWindowRect.width() - 10.0f, 20.0f, 300.0f), + std::clamp(gui.io.safeWindowRect.height() - 40.0f, 50.0f, 600.0f) + }; + CLAY(lId, { + .layout = { + .sizing = {.width = CLAY_SIZING_FIT(popupSize.x()), .height = CLAY_SIZING_FIT(0, popupSize.y()) }, + .padding = CLAY_PADDING_ALL(io.theme->padding1), + .childGap = io.theme->childGap1, + .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_TOP}, + .layoutDirection = CLAY_TOP_TO_BOTTOM + }, + .backgroundColor = convert_vec4(io.theme->backColor1), + .cornerRadius = CLAY_CORNER_RADIUS(io.theme->windowCorners1), + .floating = {.offset = {.x = 0, .y = static_cast(io.theme->padding1)}, .zIndex = gui.get_z_index(), .attachPoints = {.element = CLAY_ATTACH_POINT_RIGHT_TOP, .parent = CLAY_ATTACH_POINT_RIGHT_BOTTOM}, .attachTo = CLAY_ATTACH_TO_PARENT} + }) { + text_label_centered(gui, "Bookmarks"); + main.world->bMan.setup_list_gui(); + } + }); + }); + break; + } + case TopToolbarSettingsPopup::LAYERS: { + gui.set_z_index(gui.get_z_index() + 20, [&] { + gui.element("layer menu", [&] (LayoutElement*, const Clay_ElementId& lId) { + Vector2f popupSize = { + std::clamp(gui.io.safeWindowRect.width() - 10.0f, 20.0f, 300.0f), + std::clamp(gui.io.safeWindowRect.height() - 40.0f, 50.0f, 600.0f) + }; + CLAY(lId, { + .layout = { + .sizing = {.width = CLAY_SIZING_FIT(popupSize.x()), .height = CLAY_SIZING_FIT(0, popupSize.y()) }, + .padding = CLAY_PADDING_ALL(io.theme->padding1), + .childGap = io.theme->childGap1, + .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_TOP}, + .layoutDirection = CLAY_TOP_TO_BOTTOM + }, + .backgroundColor = convert_vec4(io.theme->backColor1), + .cornerRadius = CLAY_CORNER_RADIUS(io.theme->windowCorners1), + .floating = {.offset = {.x = 0, .y = static_cast(io.theme->padding1)}, .zIndex = gui.get_z_index(), .attachPoints = {.element = CLAY_ATTACH_POINT_RIGHT_TOP, .parent = CLAY_ATTACH_POINT_RIGHT_BOTTOM}, .attachTo = CLAY_ATTACH_TO_PARENT} + }) { + text_label_centered(gui, "Layers"); + main.world->drawProg.layerMan.listGUI.setup_list_gui(); + } + }); + }); + break; + } + case TopToolbarSettingsPopup::GRIDS: { + gui.set_z_index(gui.get_z_index() + 20, [&] { + gui.element("grid menu", [&] (LayoutElement*, const Clay_ElementId& lId) { + Vector2f popupSize = { + std::clamp(gui.io.safeWindowRect.width() - 10.0f, 20.0f, 300.0f), + std::clamp(gui.io.safeWindowRect.height() - 40.0f, 50.0f, 600.0f) + }; + CLAY(lId, { + .layout = { + .sizing = {.width = CLAY_SIZING_FIT(popupSize.x()), .height = CLAY_SIZING_FIT(0, popupSize.y()) }, + .padding = CLAY_PADDING_ALL(io.theme->padding1), + .childGap = io.theme->childGap1, + .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_TOP}, + .layoutDirection = CLAY_TOP_TO_BOTTOM + }, + .backgroundColor = convert_vec4(io.theme->backColor1), + .cornerRadius = CLAY_CORNER_RADIUS(io.theme->windowCorners1), + .floating = {.offset = {.x = 0, .y = static_cast(io.theme->padding1)}, .zIndex = gui.get_z_index(), .attachPoints = {.element = CLAY_ATTACH_POINT_RIGHT_TOP, .parent = CLAY_ATTACH_POINT_RIGHT_BOTTOM}, .attachTo = CLAY_ATTACH_TO_PARENT} + }) { + text_label_centered(gui, "Grids"); + main.world->gridMan.setup_list_gui([&] { + topToolbarSettingsPopup = TopToolbarSettingsPopup::NONE; + settingsMenuPopup = SettingsMenuPopup::SETTINGS; + }); + } + }); + }); + break; + } } } @@ -93,6 +216,7 @@ void PhoneDrawingProgramScreen::top_toolbar() { } }); top_toolbar_remaining_area(); + top_toolbar_settings_popup(); } }); } @@ -116,6 +240,30 @@ void PhoneDrawingProgramScreen::top_toolbar_remaining_area() { main.world->redo_with_checks(); } }, + TopToolbarRemainingAreaButton{ + .name = "Bookmarks", + .svgPath = "data/icons/bookmark.svg", + .isSelected = topToolbarSettingsPopup == TopToolbarSettingsPopup::BOOKMARKS, + .onClick = [&] { + topToolbarSettingsPopup = topToolbarSettingsPopup == TopToolbarSettingsPopup::BOOKMARKS ? TopToolbarSettingsPopup::NONE : TopToolbarSettingsPopup::BOOKMARKS; + } + }, + TopToolbarRemainingAreaButton{ + .name = "Layers", + .svgPath = "data/icons/layer.svg", + .isSelected = topToolbarSettingsPopup == TopToolbarSettingsPopup::LAYERS, + .onClick = [&] { + topToolbarSettingsPopup = topToolbarSettingsPopup == TopToolbarSettingsPopup::LAYERS ? TopToolbarSettingsPopup::NONE : TopToolbarSettingsPopup::LAYERS; + } + }, + TopToolbarRemainingAreaButton{ + .name = "Grids", + .svgPath = "data/icons/grid.svg", + .isSelected = topToolbarSettingsPopup == TopToolbarSettingsPopup::GRIDS, + .onClick = [&] { + topToolbarSettingsPopup = topToolbarSettingsPopup == TopToolbarSettingsPopup::GRIDS ? TopToolbarSettingsPopup::NONE : TopToolbarSettingsPopup::GRIDS; + } + }, }; gui.element("remaining area", [&](LayoutElement* l, const Clay_ElementId& lId) { CLAY(lId, { @@ -152,6 +300,7 @@ void PhoneDrawingProgramScreen::top_toolbar_remaining_area() { gui.new_id(i, [&] { svg_icon_button(gui, "button", listOfTopToolbarButtons.front().svgPath, { .drawType = SelectableButton::DrawType::TRANSPARENT_ALL, + .isSelected = listOfTopToolbarButtons.front().isSelected, .onClick = listOfTopToolbarButtons.front().onClick }); listOfTopToolbarButtons.erase(listOfTopToolbarButtons.begin()); @@ -161,10 +310,10 @@ void PhoneDrawingProgramScreen::top_toolbar_remaining_area() { Element* e = svg_icon_button(gui, "Hidden buttons", "data/icons/RemixIcon/more-2-fill.svg", { .drawType = SelectableButton::DrawType::TRANSPARENT_ALL, .onClick = [&] { - topToolbarButtonPopupOpen = !topToolbarButtonPopupOpen; + topToolbarSettingsPopup = topToolbarSettingsPopup == TopToolbarSettingsPopup::HIDDEN_BUTTONS ? TopToolbarSettingsPopup::NONE : TopToolbarSettingsPopup::HIDDEN_BUTTONS; } }); - if(topToolbarButtonPopupOpen) + if(topToolbarSettingsPopup == TopToolbarSettingsPopup::HIDDEN_BUTTONS) top_toolbar_hidden_button_popup(e, listOfTopToolbarButtons); } } @@ -202,10 +351,10 @@ void PhoneDrawingProgramScreen::top_toolbar_hidden_button_popup(GUIStuff::Elemen } }); - gui.set_z_index(gui.get_z_index() + 1, [&] { + gui.set_z_index(gui.get_z_index() + 20, [&] { dropdown_many_element_popup_layout(gui, "top toolbar hidden button popup", { .button = b, - .clickAwayCallback = [&] { topToolbarButtonPopupOpen = false; }, + .clickAwayCallback = [&] { topToolbarSettingsPopup = TopToolbarSettingsPopup::NONE; }, .entrySize = {150.0f, 30.0f}, .entryCount = l.size(), .entryLayout = [&] (size_t i) { @@ -213,8 +362,9 @@ void PhoneDrawingProgramScreen::top_toolbar_hidden_button_popup(GUIStuff::Elemen gui.element("button", SelectableButton::Data{ .drawType = SelectableButton::DrawType::TRANSPARENT_ALL, .onClick = [&, oC = listItem.onClick] { + if(topToolbarSettingsPopup == TopToolbarSettingsPopup::HIDDEN_BUTTONS) + topToolbarSettingsPopup = TopToolbarSettingsPopup::NONE; oC(); - topToolbarButtonPopupOpen = false; }, .innerContent = [&] (auto&) { CLAY_AUTO_ID({ diff --git a/src/Screens/PhoneDrawingProgramScreen.hpp b/src/Screens/PhoneDrawingProgramScreen.hpp index dadc7bf..a198100 100644 --- a/src/Screens/PhoneDrawingProgramScreen.hpp +++ b/src/Screens/PhoneDrawingProgramScreen.hpp @@ -54,11 +54,11 @@ class PhoneDrawingProgramScreen : public DrawingProgramScreen { void color_settings_popup(Vector4f* color, const ColorSelectorData& d, std::function backOnPaletteButton = nullptr, bool setAlphaToOne = false, bool setToTransparentCancelButton = false); void reset_color_picker_popup_data(); private: - bool topToolbarButtonPopupOpen = false; std::filesystem::path fileOldPath; struct TopToolbarRemainingAreaButton { std::string name; std::string svgPath; + bool isSelected = false; std::function onClick; }; enum class SettingsMenuPopup { @@ -67,15 +67,25 @@ class PhoneDrawingProgramScreen : public DrawingProgramScreen { COLOR_CHANGE } settingsMenuPopup = SettingsMenuPopup::NONE; + enum class TopToolbarSettingsPopup { + NONE, + HIDDEN_BUTTONS, + BOOKMARKS, + LAYERS, + GRIDS + } topToolbarSettingsPopup = TopToolbarSettingsPopup::NONE; + Vector4f backgroundColorTemporary; Vector4f* colorPickerPtr = nullptr; ColorSelectorData colorPickerData; + void center_message(const char* id, const std::string& m); void default_bottom_toolbar(); void bottom_toolbar_gui(); void bottom_extra_toolbar_gui(); void save_files(); void top_toolbar(); + void top_toolbar_settings_popup(); void top_toolbar_remaining_area(); void top_toolbar_hidden_button_popup(GUIStuff::Element* b, std::vector l); void bottom_toolbar(); diff --git a/src/Toolbar.cpp b/src/Toolbar.cpp index e820c07..4dc1506 100644 --- a/src/Toolbar.cpp +++ b/src/Toolbar.cpp @@ -229,11 +229,11 @@ void Toolbar::layout_run() { else if(optionsMenuOpen) options_menu(); else if(main.world->clientStillConnecting) - still_connecting_center_message(); + center_message("Connecting to server message", "Connecting to server..."); else if(playerMenuOpen) player_list(); else if(!main.world->drawProg.layerMan.is_a_layer_being_edited()) - no_layers_being_edited_message(); + center_message("Select layer to edit message", "Select a layer to edit"); if(showPerformance) performance_metrics(); @@ -475,11 +475,11 @@ void Toolbar::top_toolbar() { icon_button_top_toolbar("Menu Redo Button", "data/icons/redo.svg", false, [&] { main.world->redo_with_checks(); }); - Element* gridMenuButton = icon_button_top_toolbar("Grids Button", "data/icons/grid.svg", gridMenu.popupOpen, [&] { - if(gridMenu.popupOpen) + Element* gridMenuButton = icon_button_top_toolbar("Grids Button", "data/icons/grid.svg", gridMenuPopupOpen, [&] { + if(gridMenuPopupOpen) stop_displaying_grid_menu(); else - gridMenu.popupOpen = true; + gridMenuPopupOpen = true; }); Element* layerMenuButton = icon_button_top_toolbar("Layer Menu Button", "data/icons/layer.svg", layerMenuPopupOpen, [&] { if(layerMenuPopupOpen) @@ -494,7 +494,7 @@ void Toolbar::top_toolbar() { bookmarkMenuPopupOpen = true; }); - if(gridMenu.popupOpen) + if(gridMenuPopupOpen) grid_menu(gridMenuButton); if(bookmarkMenuPopupOpen) bookmark_menu(bookmarkMenuButton); @@ -646,44 +646,32 @@ If you like this app, consider downloading the native version for your system)") } } -void Toolbar::still_connecting_center_message() { +void Toolbar::center_message(const char* id, const std::string& m) { auto& gui = main.g.gui; auto& io = gui.io; - CLAY_AUTO_ID({ - .layout = { - .sizing = {.width = CLAY_SIZING_FIT(0), .height = CLAY_SIZING_FIT(0) }, - .padding = CLAY_PADDING_ALL(io.theme->padding1), - .childGap = io.theme->childGap1, - .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_TOP}, - .layoutDirection = CLAY_TOP_TO_BOTTOM - }, - .backgroundColor = convert_vec4(io.theme->backColor1), - .cornerRadius = CLAY_CORNER_RADIUS(io.theme->windowCorners1), - .floating = {.attachPoints = {.element = CLAY_ATTACH_POINT_CENTER_CENTER, .parent = CLAY_ATTACH_POINT_CENTER_CENTER}, .attachTo = CLAY_ATTACH_TO_PARENT} - }) { - text_label(gui, "Connecting to server..."); - } -} - -void Toolbar::no_layers_being_edited_message() { - auto& gui = main.g.gui; - auto& io = gui.io; - - CLAY_AUTO_ID({ - .layout = { - .sizing = {.width = CLAY_SIZING_FIT(0), .height = CLAY_SIZING_FIT(0) }, - .padding = CLAY_PADDING_ALL(io.theme->padding1), - .childGap = io.theme->childGap1, - .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_TOP}, - .layoutDirection = CLAY_TOP_TO_BOTTOM - }, - .backgroundColor = convert_vec4(io.theme->backColor1), - .cornerRadius = CLAY_CORNER_RADIUS(io.theme->windowCorners1), - .floating = {.attachPoints = {.element = CLAY_ATTACH_POINT_CENTER_CENTER, .parent = CLAY_ATTACH_POINT_CENTER_CENTER}, .attachTo = CLAY_ATTACH_TO_PARENT} - }) { - text_label(gui, "Select a layer to edit"); - } + gui.set_z_index(gui.get_z_index() + 1, [&] { + gui.element(id, [&] (LayoutElement*, const Clay_ElementId& lId) { + CLAY(lId, { + .layout = { + .sizing = {.width = CLAY_SIZING_FIT(0), .height = CLAY_SIZING_FIT(0) }, + .padding = CLAY_PADDING_ALL(io.theme->padding1), + .childGap = io.theme->childGap1, + .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_TOP}, + .layoutDirection = CLAY_TOP_TO_BOTTOM + }, + .backgroundColor = convert_vec4(io.theme->backColor1), + .cornerRadius = CLAY_CORNER_RADIUS(io.theme->windowCorners1), + .floating = { + .zIndex = gui.get_z_index(), + .attachPoints = {.element = CLAY_ATTACH_POINT_CENTER_CENTER, .parent = CLAY_ATTACH_POINT_CENTER_CENTER}, + .attachTo = CLAY_ATTACH_TO_PARENT, + } + }) { + text_label(gui, m); + } + }); + }); } #ifndef __EMSCRIPTEN__ @@ -783,80 +771,7 @@ void Toolbar::grid_menu(Element* gridMenuButton) { .floating = {.offset = {.x = 0, .y = static_cast(io.theme->padding1)}, .zIndex = gui.get_z_index(), .attachPoints = {.element = CLAY_ATTACH_POINT_RIGHT_TOP, .parent = CLAY_ATTACH_POINT_RIGHT_BOTTOM}, .attachTo = CLAY_ATTACH_TO_PARENT} }) { text_label_centered(gui, "Grids"); - float ENTRY_HEIGHT = 25.0f; - if(main.world->gridMan.grids->empty()) - text_label_centered(gui, "No grids yet..."); - gui.element("grid menu entries", ManyElementScrollArea::Options{ - .entryHeight = ENTRY_HEIGHT, - .entryCount = main.world->gridMan.grids->size(), - .clipHorizontal = true, - .elementContent = [&](size_t i) { - auto& grid = main.world->gridMan.grids->at(i)->obj; - bool selectedEntry = gridMenu.selectedGrid == i; - gui.element("elem", [&] (LayoutElement*, const Clay_ElementId& lId2) { - CLAY(lId2, { - .layout = { - .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(ENTRY_HEIGHT)}, - .childGap = 2, - .childAlignment = { .x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER}, - .layoutDirection = CLAY_LEFT_TO_RIGHT - }, - .backgroundColor = selectedEntry ? convert_vec4(io.theme->backColor1) : convert_vec4(io.theme->backColor2) - }) { - text_label(gui, grid->get_display_name()); - CLAY_AUTO_ID({ - .layout = { - .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}, - .childGap = 1, - .childAlignment = {.x = CLAY_ALIGN_X_RIGHT, .y = CLAY_ALIGN_Y_CENTER}, - .layoutDirection = CLAY_LEFT_TO_RIGHT - } - }) { - auto list_button = [&](const char* id, const char* svgPath, const std::function& onClick) { - gui.set_z_index_keep_clipping_region(gui.get_z_index() + 1, [&] { - svg_icon_button(gui, id, svgPath, { - .drawType = SelectableButton::DrawType::TRANSPARENT_ALL, - .size = ENTRY_HEIGHT, - .onClick = onClick - }); - }); - }; - list_button("visibility eye", grid->visible ? "data/icons/eyeopen.svg" : "data/icons/eyeclose.svg", [&] { - grid->visible = !grid->visible; - NetworkingObjects::generic_serialized_class_send_update_to_all(grid); - }); - list_button("edit pencil", "data/icons/pencil.svg", [&] { - main.world->drawProg.modify_grid(grid); - stop_displaying_grid_menu(); - }); - list_button("delete trash", "data/icons/trash.svg", [&, i] { - main.world->gridMan.remove_grid(i); - }); - } - } - }, LayoutElement::Callbacks { - .onClick = [&, i] (LayoutElement* l, const InputManager::MouseButtonCallbackArgs& button) { - if(l->mouseHovering && button.down && button.button == InputManager::MouseButton::LEFT) { - gridMenu.selectedGrid = i; - if(button.clicks == 2) { - main.world->drawProg.modify_grid(grid); - stop_displaying_grid_menu(); - } - gui.set_to_layout(); - } - } - }); - } - }); - left_to_right_line_layout(gui, [&]() { - input_text(gui, "grid text input", &gridMenu.newName, { - .onEnter = [&]() { add_grid(); } - }); - svg_icon_button(gui, "grid add button", "data/icons/plusbold.svg", { - .size = SMALL_BUTTON_SIZE, - .onClick = [&] { add_grid(); } - }); - }); + main.world->gridMan.setup_list_gui([&]{stop_displaying_grid_menu();}); } }, LayoutElement::Callbacks { .onClick = [&, gridMenuButton] (LayoutElement* l, const InputManager::MouseButtonCallbackArgs& button) { @@ -868,18 +783,9 @@ void Toolbar::grid_menu(Element* gridMenuButton) { } } -void Toolbar::add_grid() { - if(!gridMenu.newName.empty()) { - main.world->gridMan.add_default_grid(gridMenu.newName); - main.world->drawProg.modify_grid(main.world->gridMan.grids->at(main.world->gridMan.grids->size() - 1)->obj); - stop_displaying_grid_menu(); - } -} - void Toolbar::stop_displaying_grid_menu() { - gridMenu.newName.clear(); - gridMenu.popupOpen = false; - gridMenu.selectedGrid = std::numeric_limits::max(); + gridMenuPopupOpen = false; + main.world->gridMan.refresh_gui_data(); main.g.gui.set_to_layout(); } diff --git a/src/Toolbar.hpp b/src/Toolbar.hpp index 752dfce..20a88ac 100644 --- a/src/Toolbar.hpp +++ b/src/Toolbar.hpp @@ -92,7 +92,6 @@ class Toolbar { void global_log(); void top_toolbar(); void grid_menu(GUIStuff::Element* gridMenuButton); - void add_grid(); void stop_displaying_grid_menu(); void stop_displaying_bookmark_menu(); void stop_displaying_layer_menu(); @@ -110,8 +109,7 @@ class Toolbar { void load_default_theme(); void about_menu_inner_gui(); void web_version_welcome(); - void still_connecting_center_message(); - void no_layers_being_edited_message(); + void center_message(const char* id, const std::string& m); void close_popup_gui(); void add_world_to_close_popup_data(const std::shared_ptr& w); void general_settings_inner_gui(); @@ -190,12 +188,7 @@ class Toolbar { bool bookmarkMenuPopupOpen = false; bool layerMenuPopupOpen = false; - - struct GridMenu { - bool popupOpen = false; - std::string newName; - uint32_t selectedGrid = std::numeric_limits::max(); - } gridMenu; + bool gridMenuPopupOpen = false; struct FilePicker { bool isOpen = false; diff --git a/src/World.cpp b/src/World.cpp index b10013b..08fa560 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -536,8 +536,12 @@ void World::load_empty_canvas(const std::optional& filePa drawProg.server_init_no_file(); canvasTheme.server_init_no_file(); - if(filePathEmptyAutoSaveDir.has_value()) + if(filePathEmptyAutoSaveDir.has_value()) { + bool oldSaveThumbnail = true; + saveThumbnail = false; autosave_to_directory(filePathEmptyAutoSaveDir.value()); + saveThumbnail = oldSaveThumbnail; + } } void World::load_from_file(const std::filesystem::path& filePathToLoadFrom, std::string_view buffer) { diff --git a/src/main.cpp b/src/main.cpp index dd31c7c..a4652b1 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -622,8 +622,12 @@ SDL_AppResult SDL_AppIterate(void *appstate) { #endif mS.m->update(); - if(mS.m->setToQuit) + if(mS.m->setToQuit) { + #ifdef __ANDROID__ + mS.m->input_app_about_to_go_to_background_callback(); + #endif return SDL_APP_SUCCESS; + } if(mS.m->input.hideCursor) { SDL_HideCursor(); @@ -825,7 +829,13 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) { } #endif - return mS.m->setToQuit ? SDL_APP_SUCCESS : SDL_APP_CONTINUE; + if(mS.m->setToQuit) { + #ifdef __ANDROID__ + mS.m->input_app_about_to_go_to_background_callback(); + #endif + return SDL_APP_SUCCESS; + } + return SDL_APP_CONTINUE; } // NOTE: On Android, SDL_AppQuit is triggered by onDestroy. onDestroy may or may not be called, and even if it is, it may only be partially called. You should not rely on it.