diff --git a/assets/data/icons/RemixIcon/settings-3-line.svg b/assets/data/icons/RemixIcon/settings-3-line.svg
new file mode 100644
index 0000000..d28a6b1
--- /dev/null
+++ b/assets/data/icons/RemixIcon/settings-3-line.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/GUIStuff/ElementHelpers/ButtonHelpers.cpp b/src/GUIStuff/ElementHelpers/ButtonHelpers.cpp
index 36366e2..8b1fd09 100644
--- a/src/GUIStuff/ElementHelpers/ButtonHelpers.cpp
+++ b/src/GUIStuff/ElementHelpers/ButtonHelpers.cpp
@@ -1,5 +1,6 @@
#include "ButtonHelpers.hpp"
#include "../Elements/SVGIcon.hpp"
+#include "../Elements/LayoutElement.hpp"
#include "TextLabelHelpers.hpp"
namespace GUIStuff { namespace ElementHelpers {
@@ -26,6 +27,51 @@ void text_button(GUIManager& gui, const char* id, std::string_view text, const T
}
}
+void text_button_with_icon(GUIManager& gui, const char* id, const std::string& svgPath, std::string_view text, const TextButtonOptions& options) {
+ gui.new_id(id, [&] {
+ SelectableButton::Data d = selectable_button_options_to_data(options);
+ d.innerContent = [&gui, svgPath, text, centered = options.centered] (const SelectableButton::InnerContentCallbackParameters&) {
+ gui.element("layoutelem", [&] (LayoutElement* l, const Clay_ElementId& lId) {
+ CLAY(lId, {
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) },
+ .childGap = gui.io.theme->childGap1,
+ .childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER}
+ }
+ }) {
+ if(l->get_bb().has_value()) {
+ float iconSize = l->get_bb().value().height();
+ CLAY_AUTO_ID({
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_FIXED(iconSize), .height = CLAY_SIZING_FIXED(iconSize)},
+ },
+ .aspectRatio = {.aspectRatio = 1.0f}
+ }) {
+ gui.element("icon", svgPath, false);
+ }
+ }
+ CLAY_AUTO_ID({
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) },
+ .childAlignment = {.x = centered ? CLAY_ALIGN_X_CENTER : CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER}
+ }
+ }) {
+ text_label(gui, text);
+ }
+ }
+ });
+ };
+ CLAY_AUTO_ID({
+ .layout = {
+ .sizing = {.width = options.wide ? CLAY_SIZING_GROW(0) : CLAY_SIZING_FIT(0), .height = CLAY_SIZING_FIT(0) },
+ .childAlignment = {.x = options.centered ? CLAY_ALIGN_X_CENTER : CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER}
+ }
+ }) {
+ gui.element("button", d);
+ }
+ });
+}
+
void text_button_sized(GUIManager& gui, const char* id, std::string_view text, Clay_SizingAxis x, Clay_SizingAxis y, const TextButtonOptions& options) {
SelectableButton::Data d = selectable_button_options_to_data(options);
d.innerContent = [&gui, text] (const SelectableButton::InnerContentCallbackParameters&) {
diff --git a/src/GUIStuff/ElementHelpers/ButtonHelpers.hpp b/src/GUIStuff/ElementHelpers/ButtonHelpers.hpp
index 09f46b7..c99312c 100644
--- a/src/GUIStuff/ElementHelpers/ButtonHelpers.hpp
+++ b/src/GUIStuff/ElementHelpers/ButtonHelpers.hpp
@@ -51,6 +51,7 @@ struct FixedSizeColorButtonOptions {
};
void text_button(GUIManager& gui, const char* id, std::string_view text, const TextButtonOptions& options = {});
+void text_button_with_icon(GUIManager& gui, const char* id, const std::string& svgPath, std::string_view text, const TextButtonOptions& options = {});
void text_button_sized(GUIManager& gui, const char* id, std::string_view text, Clay_SizingAxis x, Clay_SizingAxis y, const TextButtonOptions& options = {});
SelectableButton* svg_icon_button(GUIManager& gui, const char* id, const std::string& svgPath, const SVGButtonOptions& options = {});
diff --git a/src/GUIStuff/Elements/GridScrollArea.cpp b/src/GUIStuff/Elements/GridScrollArea.cpp
index b2cece3..35f3731 100644
--- a/src/GUIStuff/Elements/GridScrollArea.cpp
+++ b/src/GUIStuff/Elements/GridScrollArea.cpp
@@ -12,11 +12,13 @@ void GridScrollArea::layout(const Clay_ElementId& id, const Options& o) {
options = o;
+ if(boundingBox.has_value())
+ rowWidth = boundingBox.value().width(); // Use grid element bounding box instead of inner content width because row width will decide whether a scroll bar appears or not, which will change the inner content width (circular dependency)
+
ScrollBarManyEntriesOptions opts;
opts.clipHorizontal = true;
opts.entryHeight = options.entryHeight;
opts.innerContentExtraCallback = [&, extraCallback = options.innerContentExtraCallback] (const ScrollArea::InnerContentParameters& contParams) {
- rowWidth = std::fabs(contParams.containerDimensions.x());
if(extraCallback) extraCallback(contParams);
};
size_t entriesPerRow = std::max(rowWidth / options.entryWidth, 1);
diff --git a/src/GUIStuff/GUIManager.cpp b/src/GUIStuff/GUIManager.cpp
index 0c9eb4b..ac4a49d 100644
--- a/src/GUIStuff/GUIManager.cpp
+++ b/src/GUIStuff/GUIManager.cpp
@@ -258,9 +258,11 @@ void GUIManager::draw(SkCanvas* c, bool skiaAA) {
break;
}
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_END: {
- canvas->restore();
- clipRectStack.pop_back();
- clip_rect_transform(canvas, clipRectStack, clipRect, clipNoDraw);
+ if(!clipRectStack.empty()) {
+ canvas->restore();
+ clipRectStack.pop_back();
+ clip_rect_transform(canvas, clipRectStack, clipRect, clipNoDraw);
+ }
break;
}
case CLAY_RENDER_COMMAND_TYPE_CUSTOM: {
diff --git a/src/Screens/FileSelectScreen.cpp b/src/Screens/FileSelectScreen.cpp
index 27ffbb0..fc180ff 100644
--- a/src/Screens/FileSelectScreen.cpp
+++ b/src/Screens/FileSelectScreen.cpp
@@ -6,75 +6,204 @@
#include "Helpers/ConvertVec.hpp"
#include "../GUIStuff/Elements/GridScrollArea.hpp"
#include "../GUIStuff/Elements/ImageDisplay.hpp"
+#include "../GUIStuff/Elements/LayoutElement.hpp"
#include "../World.hpp"
#include "Helpers/StringHelpers.hpp"
#include
+#define MAIN_MENU_SIZE 300
+
+using namespace GUIStuff;
+using namespace ElementHelpers;
+
FileSelectScreen::FileSelectScreen(MainProgram& m): Screen(m) {}
void FileSelectScreen::gui_layout_run() {
- using namespace GUIStuff;
- using namespace ElementHelpers;
auto& gui = main.g.gui;
-
CLAY_AUTO_ID({
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)},
- .padding = CLAY_PADDING_ALL(gui.io.theme->padding1),
- .childGap = gui.io.theme->childGap1,
- .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_TOP },
- .layoutDirection = CLAY_TOP_TO_BOTTOM,
+ .layoutDirection = CLAY_LEFT_TO_RIGHT
},
}) {
- CLAY_AUTO_ID({
+ if(mainMenuOpen)
+ main_menu();
+ if(!(mainMenuOpen && main_menu_fills_screen())) {
+ CLAY_AUTO_ID({
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_FIXED(gui.io.windowSize.x()), .height = CLAY_SIZING_GROW(0)},
+ .padding = CLAY_PADDING_ALL(gui.io.theme->padding1),
+ .childGap = gui.io.theme->childGap1,
+ .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_TOP },
+ .layoutDirection = CLAY_TOP_TO_BOTTOM,
+ },
+ }) {
+ switch(selectedMenu) {
+ case SelectedMenu::FILES:
+ title_bar("Files");
+ file_view();
+ break;
+ case SelectedMenu::TRASH:
+ title_bar("Trash");
+ file_view();
+ break;
+ case SelectedMenu::SETTINGS:
+ title_bar("Settings");
+ break;
+ }
+ menu_black_box();
+ }
+ }
+ }
+}
+
+bool FileSelectScreen::main_menu_fills_screen() {
+ return main.g.gui.io.windowSize.x() < MAIN_MENU_SIZE + 50;
+}
+
+void FileSelectScreen::title_bar(std::string_view title) {
+ auto& gui = main.g.gui;
+ CLAY_AUTO_ID({
+ .layout = {
+ .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(40)},
+ .childGap = gui.io.theme->childGap1,
+ .childAlignment = { .x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER },
+ .layoutDirection = CLAY_LEFT_TO_RIGHT,
+ }
+ }) {
+ svg_icon_button(gui, "main settings button", "data/icons/menu.svg", {
+ .drawType = SelectableButton::DrawType::TRANSPARENT_ALL,
+ .onClick = [&] {
+ mainMenuOpen = true;
+ }
+ });
+ text_label(gui, title);
+ }
+}
+
+void FileSelectScreen::main_menu() {
+ auto& gui = main.g.gui;
+ gui.element("main menu popup", [&] (LayoutElement*, const Clay_ElementId& lId) {
+ CLAY(lId, {
.layout = {
- .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(40)},
+ .sizing = {.width = CLAY_SIZING_GROW(static_cast(main_menu_fills_screen() ? 0 : 300)), .height = CLAY_SIZING_GROW(0)},
.padding = CLAY_PADDING_ALL(gui.io.theme->padding1),
.childGap = gui.io.theme->childGap1,
- .childAlignment = { .x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER },
- .layoutDirection = CLAY_LEFT_TO_RIGHT,
- }
+ .layoutDirection = CLAY_TOP_TO_BOTTOM,
+ },
}) {
- svg_icon_button(gui, "main settings button", "data/icons/menu.svg", {
- .drawType = SelectableButton::DrawType::TRANSPARENT_ALL
+ text_button_with_icon(gui, "Files", "data/icons/folder.svg", "Files", {
+ .drawType = SelectableButton::DrawType::TRANSPARENT_ALL,
+ .isSelected = selectedMenu == SelectedMenu::FILES,
+ .wide = true,
+ .centered = false,
+ .onClick = [&] {
+ selectedMenu = SelectedMenu::FILES;
+ fileListOptional.reset();
+ mainMenuOpen = false;
+ }
+ });
+ text_button_with_icon(gui, "Trash", "data/icons/trash.svg", "Trash", {
+ .drawType = SelectableButton::DrawType::TRANSPARENT_ALL,
+ .isSelected = selectedMenu == SelectedMenu::TRASH,
+ .wide = true,
+ .centered = false,
+ .onClick = [&] {
+ selectedMenu = SelectedMenu::TRASH;
+ fileListOptional.reset();
+ mainMenuOpen = false;
+ }
+ });
+ text_button_with_icon(gui, "Settings", "data/icons/RemixIcon/settings-3-line.svg", "Settings", {
+ .drawType = SelectableButton::DrawType::TRANSPARENT_ALL,
+ .isSelected = selectedMenu == SelectedMenu::SETTINGS,
+ .wide = true,
+ .centered = false,
+ .onClick = [&] {
+ selectedMenu = SelectedMenu::SETTINGS;
+ mainMenuOpen = false;
+ }
});
- text_label(gui, "File selector");
}
- auto& fileList = get_file_list();
- gui.element("File selector grid", GridScrollArea::Options{
- .entryWidth = 200.0f,
- .childAlignmentX = CLAY_ALIGN_X_LEFT,
- .entryHeight = 220.0f,
- .entryCount = fileList.size(),
- .elementContent = [&](size_t i) {
- CLAY_AUTO_ID({
+ });
+}
+
+void FileSelectScreen::file_view() {
+ auto& gui = main.g.gui;
+ bool isTrash = selectedMenu == SelectedMenu::TRASH;
+ std::string folder = isTrash ? "trash" : "saves";
+ auto& fileList = get_file_list(folder);
+ gui.element("File selector grid", GridScrollArea::Options{
+ .entryWidth = 180.0f,
+ .childAlignmentX = CLAY_ALIGN_X_LEFT,
+ .entryHeight = 200.0f,
+ .entryCount = fileList.size(),
+ .elementContent = [&](size_t i) {
+ gui.element("file button", SelectableButton::Data{
+ .onClick = [&] {
+ },
+ .innerContent = [&](const SelectableButton::InnerContentCallbackParameters& c){
+ CLAY_AUTO_ID({
+ .layout = {
+ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)},
+ .padding = CLAY_PADDING_ALL(gui.io.theme->padding1),
+ .childGap = 6,
+ .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
+ .layoutDirection = CLAY_TOP_TO_BOTTOM
+ }
+ }) {
+ CLAY_AUTO_ID({
+ .layout = { .sizing = {.width = CLAY_SIZING_FIXED(130), .height = CLAY_SIZING_FIXED(130) }},
+ }) {
+ gui.element("ico", ImageDisplay::Data{
+ .imgPath = main.conf.configPath / folder / (fileList[i].fileName + ".jpg"),
+ .radius = 20
+ });
+ }
+ text_label(gui, fileList[i].fileName);
+ text_label_light(gui, fileList[i].lastModifyDate);
+ }
+ }
+ });
+ }
+ });
+}
+
+void FileSelectScreen::menu_black_box() {
+ auto& gui = main.g.gui;
+ if(mainMenuOpen) {
+ gui.set_z_index(gui.get_z_index() + 1, [&] {
+ gui.element("file list disable fill", [&] (LayoutElement* l, const Clay_ElementId& lId) {
+ CLAY(lId, {
.layout = {
- .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)},
- .padding = CLAY_PADDING_ALL(gui.io.theme->padding1),
- .childGap = 6,
- .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
- .layoutDirection = CLAY_TOP_TO_BOTTOM
+ .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)},
+ },
+ .backgroundColor = {0.0f, 0.0f, 0.0f, 0.6f},
+ .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_FIXED(150), .height = CLAY_SIZING_FIXED(150) }},
- }) {
- gui.element("ico", ImageDisplay::Data{
- .imgPath = main.conf.configPath / "saveThumbnails" / (fileList[i].fileName + ".jpg"),
- .radius = 20
- });
- }
- text_label(gui, fileList[i].fileName);
- text_label_light(gui, fileList[i].lastModifyDate);
}
- }
+ }, LayoutElement::Callbacks{
+ .mouseButton = [&] (LayoutElement* l, const InputManager::MouseButtonCallbackArgs& m) {
+ if(m.down && m.button == InputManager::MouseButton::LEFT && l->mouseHovering) {
+ mainMenuOpen = false;
+ gui.set_to_layout();
+ }
+ }
+ });
});
}
}
-const std::vector& FileSelectScreen::get_file_list() {
+const std::vector& FileSelectScreen::get_file_list(const std::string& folder) {
if(!fileListOptional.has_value()) {
- std::filesystem::path savePath = main.conf.configPath / "saves";
+ std::filesystem::path savePath = main.conf.configPath / folder;
fileListOptional = std::vector();
auto& fL = fileListOptional.value();
int globCount;
diff --git a/src/Screens/FileSelectScreen.hpp b/src/Screens/FileSelectScreen.hpp
index c8bbbb4..5fbb029 100644
--- a/src/Screens/FileSelectScreen.hpp
+++ b/src/Screens/FileSelectScreen.hpp
@@ -12,6 +12,19 @@ class FileSelectScreen : public Screen {
SDL_Time lastModifyTime;
std::string lastModifyDate;
};
- const std::vector& get_file_list();
+ const std::vector& get_file_list(const std::string& folder);
std::optional> fileListOptional;
+
+ void main_menu();
+ void file_view();
+ bool main_menu_fills_screen();
+ void menu_black_box();
+ void title_bar(std::string_view title);
+
+ enum class SelectedMenu {
+ FILES,
+ TRASH,
+ SETTINGS
+ } selectedMenu = SelectedMenu::FILES;
+ bool mainMenuOpen = false;
};