From 54703852e72387147ec8597184cf1fec51f2eb0c Mon Sep 17 00:00:00 2001 From: noffie Date: Fri, 10 Jan 2025 14:21:27 +0100 Subject: [PATCH] abbandoning Lua... Error in runtime --- {src => include}/TickSystem.hpp | 7 +- {src => include}/collections.hpp | 2 +- .../modules/gui_window_file_dialog.hpp | 626 ++++++++++++++++++ res/lua/bubble_sortiva.lua | 25 + res/lua/quick_sortiva.lua | 59 ++ src/LuaSortList.hpp | 33 + src/libimpl.cpp | 7 +- src/lua/Future.lua | 16 + src/lua/FutureLua.hpp | 35 + src/main.cpp | 3 +- src/sortiva-update.cpp | 11 - src/sortiva.cpp | 79 --- src/sortiva.hpp | 33 - src/sortiva/GuiFileDialog.cpp | 45 ++ src/sortiva/GuiFileDialog.hpp | 19 + src/{ => sortiva}/sortiva-draw.cpp | 73 +- src/sortiva/sortiva-draw_overlay.cpp | 28 + src/sortiva/sortiva-update.cpp | 22 + src/sortiva/sortiva.cpp | 78 +++ src/sortiva/sortiva.hpp | 82 +++ 20 files changed, 1119 insertions(+), 164 deletions(-) rename {src => include}/TickSystem.hpp (63%) rename {src => include}/collections.hpp (99%) create mode 100644 include/raylibs/modules/gui_window_file_dialog.hpp create mode 100644 res/lua/bubble_sortiva.lua create mode 100644 res/lua/quick_sortiva.lua create mode 100644 src/LuaSortList.hpp create mode 100644 src/lua/Future.lua create mode 100644 src/lua/FutureLua.hpp delete mode 100644 src/sortiva-update.cpp delete mode 100644 src/sortiva.cpp delete mode 100644 src/sortiva.hpp create mode 100644 src/sortiva/GuiFileDialog.cpp create mode 100644 src/sortiva/GuiFileDialog.hpp rename src/{ => sortiva}/sortiva-draw.cpp (77%) create mode 100644 src/sortiva/sortiva-draw_overlay.cpp create mode 100644 src/sortiva/sortiva-update.cpp create mode 100644 src/sortiva/sortiva.cpp create mode 100644 src/sortiva/sortiva.hpp diff --git a/src/TickSystem.hpp b/include/TickSystem.hpp similarity index 63% rename from src/TickSystem.hpp rename to include/TickSystem.hpp index daa1d3d..69cbd32 100644 --- a/src/TickSystem.hpp +++ b/include/TickSystem.hpp @@ -7,10 +7,9 @@ private: std::chrono::duration timer{ 0 }; std::chrono::duration tickRate; - std::function callback; public: - TickSystem(std::chrono::duration tickRateSeconds, std::function func) - : tickRate(tickRateSeconds), callback(func) { + TickSystem(std::chrono::duration tickRateSeconds) + : tickRate(tickRateSeconds) { } bool update(std::chrono::duration deltaTime) { @@ -23,6 +22,4 @@ public: return false; } - - void call() const { callback(); } }; diff --git a/src/collections.hpp b/include/collections.hpp similarity index 99% rename from src/collections.hpp rename to include/collections.hpp index 7cb580f..98caacb 100644 --- a/src/collections.hpp +++ b/include/collections.hpp @@ -122,7 +122,7 @@ struct linked_list next->first = this; return *next; } - next->value = val; + next->put(val); if (first) next->first = first; else diff --git a/include/raylibs/modules/gui_window_file_dialog.hpp b/include/raylibs/modules/gui_window_file_dialog.hpp new file mode 100644 index 0000000..1641852 --- /dev/null +++ b/include/raylibs/modules/gui_window_file_dialog.hpp @@ -0,0 +1,626 @@ +#pragma once +/******************************************************************************************* +* +* Window File Dialog v1.2 - Modal file dialog to open/save files +* +* MODULE USAGE: +* #define GUI_WINDOW_FILE_DIALOG_IMPLEMENTATION +* #include "gui_window_file_dialog.h" +* +* INIT: GuiWindowFileDialogState state = GuiInitWindowFileDialog(); +* DRAW: GuiWindowFileDialog(&state); +* +* NOTE: This module depends on some raylib file system functions: +* - LoadDirectoryFiles() +* - UnloadDirectoryFiles() +* - GetWorkingDirectory() +* - DirectoryExists() +* - FileExists() +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2019-2024 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include + +#ifndef GUI_WINDOW_FILE_DIALOG_H +#define GUI_WINDOW_FILE_DIALOG_H + +// Gui file dialog context data +typedef struct { + + // Window management variables + bool windowActive; + Rectangle windowBounds; + Vector2 panOffset; + bool dragMode; + bool supportDrag; + + // UI variables + bool dirPathEditMode; + char dirPathText[1024]; + + int filesListScrollIndex; + bool filesListEditMode; + int filesListActive; + + bool fileNameEditMode; + char fileNameText[1024]; + bool SelectFilePressed; + bool CancelFilePressed; + int fileTypeActive; + int itemFocused; + + // Custom state variables + FilePathList dirFiles; + char filterExt[256]; + char dirPathTextCopy[1024]; + char fileNameTextCopy[1024]; + + int prevFilesListActive; + + bool saveFileMode; + +} GuiWindowFileDialogState; + +#ifdef __cplusplus +extern "C" { // Prevents name mangling of functions +#endif + + //---------------------------------------------------------------------------------- + // Defines and Macros + //---------------------------------------------------------------------------------- + //... + + //---------------------------------------------------------------------------------- + // Types and Structures Definition + //---------------------------------------------------------------------------------- + // ... + + //---------------------------------------------------------------------------------- + // Global Variables Definition + //---------------------------------------------------------------------------------- + //... + + //---------------------------------------------------------------------------------- + // Module Functions Declaration + //---------------------------------------------------------------------------------- + GuiWindowFileDialogState InitGuiWindowFileDialog(const char* initPath); + void GuiWindowFileDialog(GuiWindowFileDialogState* state); + +#ifdef __cplusplus +} +#endif + +#endif // GUI_WINDOW_FILE_DIALOG_H + +/*********************************************************************************** +* +* GUI_WINDOW_FILE_DIALOG IMPLEMENTATION +* +************************************************************************************/ +#if defined(GUI_WINDOW_FILE_DIALOG_IMPLEMENTATION) + +#include + +#include // Required for: strcpy() + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#define MAX_DIRECTORY_FILES 2048 +#define MAX_ICON_PATH_LENGTH 512 +#ifdef _WIN32 +#define PATH_SEPERATOR "\\" +#else +#define PATH_SEPERATOR "/" +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +#if defined(USE_CUSTOM_LISTVIEW_FILEINFO) +// Detailed file info type +typedef struct FileInfo { + const char* name; + int size; + int modTime; + int type; + int icon; +} FileInfo; +#else +// Filename only +typedef char* FileInfo; // Files are just a path string +#endif + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +FileInfo* dirFilesIcon = NULL; // Path string + icon (for fancy drawing) + +//---------------------------------------------------------------------------------- +// Internal Module Functions Definition +//---------------------------------------------------------------------------------- +// Read files in new path +static void ReloadDirectoryFiles(GuiWindowFileDialogState* state); + +#if defined(USE_CUSTOM_LISTVIEW_FILEINFO) +// List View control for files info with extended parameters +static int GuiListViewFiles(Rectangle bounds, FileInfo* files, int count, int* focus, int* scrollIndex, int active); +#endif + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +GuiWindowFileDialogState InitGuiWindowFileDialog(const char* initPath) +{ + GuiWindowFileDialogState state = { 0 }; + + // Init window data + state.windowBounds = { static_cast(GetScreenWidth()) / 2 - 440 / 2, static_cast(GetScreenHeight()) / 2 - 310 / 2, 440, 310 }; + state.windowActive = false; + state.supportDrag = true; + state.dragMode = false; + state.panOffset = { 0, 0 }; + + // Init path data + state.dirPathEditMode = false; + state.filesListActive = -1; + state.prevFilesListActive = state.filesListActive; + state.filesListScrollIndex = 0; + + state.fileNameEditMode = false; + + state.SelectFilePressed = false; + state.CancelFilePressed = false; + + state.fileTypeActive = 0; + + strcpy(state.fileNameText, "\0"); + + // Custom variables initialization + if (initPath && DirectoryExists(initPath)) + { + strcpy(state.dirPathText, initPath); + } + else if (initPath && FileExists(initPath)) + { + strcpy(state.dirPathText, GetDirectoryPath(initPath)); + strcpy(state.fileNameText, GetFileName(initPath)); + } + else strcpy(state.dirPathText, GetWorkingDirectory()); + + // TODO: Why we keep a copy? + strcpy(state.dirPathTextCopy, state.dirPathText); + strcpy(state.fileNameTextCopy, state.fileNameText); + + state.filterExt[0] = '\0'; + //strcpy(state.filterExt, "all"); + + state.dirFiles.count = 0; + + return state; +} + +// Update and draw file dialog +void GuiWindowFileDialog(GuiWindowFileDialogState* state) +{ + if (state->windowActive) + { + // Update window dragging + //---------------------------------------------------------------------------------------- + if (state->supportDrag) + { + Vector2 mousePosition = GetMousePosition(); + + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + // Window can be dragged from the top window bar + if (CheckCollisionPointRec(mousePosition, { state->windowBounds.x, state->windowBounds.y, (float)state->windowBounds.width, RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT })) + { + state->dragMode = true; + state->panOffset.x = mousePosition.x - state->windowBounds.x; + state->panOffset.y = mousePosition.y - state->windowBounds.y; + } + } + + if (state->dragMode) + { + state->windowBounds.x = (mousePosition.x - state->panOffset.x); + state->windowBounds.y = (mousePosition.y - state->panOffset.y); + + // Check screen limits to avoid moving out of screen + if (state->windowBounds.x < 0) state->windowBounds.x = 0; + else if (state->windowBounds.x > (GetScreenWidth() - state->windowBounds.width)) state->windowBounds.x = GetScreenWidth() - state->windowBounds.width; + + if (state->windowBounds.y < 0) state->windowBounds.y = 0; + else if (state->windowBounds.y > (GetScreenHeight() - state->windowBounds.height)) state->windowBounds.y = GetScreenHeight() - state->windowBounds.height; + + if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) state->dragMode = false; + } + } + //---------------------------------------------------------------------------------------- + + // Load dirFilesIcon and state->dirFiles lazily on windows open + // NOTE: They are automatically unloaded at fileDialog closing + //---------------------------------------------------------------------------------------- + if (dirFilesIcon == NULL) + { + dirFilesIcon = (FileInfo*)RL_CALLOC(MAX_DIRECTORY_FILES, sizeof(FileInfo)); // Max files to read + for (int i = 0; i < MAX_DIRECTORY_FILES; i++) dirFilesIcon[i] = (char*)RL_CALLOC(MAX_ICON_PATH_LENGTH, 1); // Max file name length + } + + // Load current directory files + if (state->dirFiles.paths == NULL) ReloadDirectoryFiles(state); + //---------------------------------------------------------------------------------------- + + // Draw window and controls + //---------------------------------------------------------------------------------------- + state->windowActive = !GuiWindowBox(state->windowBounds, "#198# Select File Dialog"); + + // Draw previous directory button + logic + if (GuiButton({ state->windowBounds.x + state->windowBounds.width - 48, state->windowBounds.y + 24 + 12, 40, 24 }, "< ..")) + { + // Move dir path one level up + strcpy(state->dirPathText, GetPrevDirectoryPath(state->dirPathText)); + + // Reload directory files (frees previous list) + ReloadDirectoryFiles(state); + + state->filesListActive = -1; + memset(state->fileNameText, 0, 1024); + memset(state->fileNameTextCopy, 0, 1024); + } + + // Draw current directory text box info + path editing logic + if (GuiTextBox({ state->windowBounds.x + 8, state->windowBounds.y + 24 + 12, state->windowBounds.width - 48 - 16, 24 }, state->dirPathText, 1024, state->dirPathEditMode)) + { + if (state->dirPathEditMode) + { + // Verify if a valid path has been introduced + if (DirectoryExists(state->dirPathText)) + { + // Reload directory files (frees previous list) + ReloadDirectoryFiles(state); + + strcpy(state->dirPathTextCopy, state->dirPathText); + } + else strcpy(state->dirPathText, state->dirPathTextCopy); + } + + state->dirPathEditMode = !state->dirPathEditMode; + } + + // List view elements are aligned left + int prevTextAlignment = GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT); + int prevElementsHeight = GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT); + GuiSetStyle(LISTVIEW, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 24); +# if defined(USE_CUSTOM_LISTVIEW_FILEINFO) + state->filesListActive = GuiListViewFiles({ state->position.x + 8, state->position.y + 48 + 20, state->windowBounds.width - 16, state->windowBounds.height - 60 - 16 - 68 }, fileInfo, state->dirFiles.count, &state->itemFocused, &state->filesListScrollIndex, state->filesListActive); +# else + GuiListViewEx({ state->windowBounds.x + 8, state->windowBounds.y + 48 + 20, state->windowBounds.width - 16, state->windowBounds.height - 60 - 16 - 68 }, + (const char**)dirFilesIcon, state->dirFiles.count, &state->filesListScrollIndex, &state->filesListActive, &state->itemFocused); +# endif + GuiSetStyle(LISTVIEW, TEXT_ALIGNMENT, prevTextAlignment); + GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, prevElementsHeight); + + // Check if a path has been selected, if it is a directory, move to that directory (and reload paths) + if ((state->filesListActive >= 0) && (state->filesListActive != state->prevFilesListActive)) + //&& (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_DPAD_A))) + { + strcpy(state->fileNameText, GetFileName(state->dirFiles.paths[state->filesListActive])); + + if (DirectoryExists(TextFormat("%s/%s", state->dirPathText, state->fileNameText))) + { + if (TextIsEqual(state->fileNameText, "..")) strcpy(state->dirPathText, GetPrevDirectoryPath(state->dirPathText)); + else strcpy(state->dirPathText, TextFormat("%s/%s", (strcmp(state->dirPathText, "/") == 0) ? "" : state->dirPathText, state->fileNameText)); + + strcpy(state->dirPathTextCopy, state->dirPathText); + + // Reload directory files (frees previous list) + ReloadDirectoryFiles(state); + + strcpy(state->dirPathTextCopy, state->dirPathText); + + state->filesListActive = -1; + strcpy(state->fileNameText, "\0"); + strcpy(state->fileNameTextCopy, state->fileNameText); + } + + state->prevFilesListActive = state->filesListActive; + } + + // Draw bottom controls + //-------------------------------------------------------------------------------------- + GuiLabel({ state->windowBounds.x + 8, state->windowBounds.y + state->windowBounds.height - 68, 60, 24 }, "File name:"); + if (GuiTextBox({ state->windowBounds.x + 72, state->windowBounds.y + state->windowBounds.height - 68, state->windowBounds.width - 184, 24 }, state->fileNameText, 128, state->fileNameEditMode)) + { + if (*state->fileNameText) + { + // Verify if a valid filename has been introduced + if (FileExists(TextFormat("%s/%s", state->dirPathText, state->fileNameText))) + { + // Select filename from list view + for (int i = 0; i < state->dirFiles.count; i++) + { + if (TextIsEqual(state->fileNameText, state->dirFiles.paths[i])) + { + state->filesListActive = i; + strcpy(state->fileNameTextCopy, state->fileNameText); + break; + } + } + } + else if (!state->saveFileMode) + { + strcpy(state->fileNameText, state->fileNameTextCopy); + } + } + + state->fileNameEditMode = !state->fileNameEditMode; + } + + GuiLabel({ state->windowBounds.x + 8, state->windowBounds.y + state->windowBounds.height - 24 - 12, 68, 24 }, "File filter:"); + GuiComboBox({ state->windowBounds.x + 72, state->windowBounds.y + state->windowBounds.height - 24 - 12, state->windowBounds.width - 184, 24 }, "All files", &state->fileTypeActive); + + state->SelectFilePressed = GuiButton({ state->windowBounds.x + state->windowBounds.width - 96 - 8, state->windowBounds.y + state->windowBounds.height - 68, 96, 24 }, "Select"); + + if (GuiButton({ state->windowBounds.x + state->windowBounds.width - 96 - 8, state->windowBounds.y + state->windowBounds.height - 24 - 12, 96, 24 }, "Cancel")) state->windowActive = false; + //-------------------------------------------------------------------------------------- + + // Exit on file selected + if (state->SelectFilePressed) state->windowActive = false; + + // File dialog has been closed, free all memory before exit + if (!state->windowActive) + { + // Free dirFilesIcon memory + for (int i = 0; i < MAX_DIRECTORY_FILES; i++) RL_FREE(dirFilesIcon[i]); + + RL_FREE(dirFilesIcon); + dirFilesIcon = NULL; + + // Unload directory file paths + UnloadDirectoryFiles(state->dirFiles); + + // Reset state variables + state->dirFiles.count = 0; + state->dirFiles.capacity = 0; + state->dirFiles.paths = NULL; + } + } +} + +// Compare two files from a directory +static inline int FileCompare(const char* d1, const char* d2, const char* dir) +{ + const bool b1 = DirectoryExists(TextFormat("%s/%s", dir, d1)); + const bool b2 = DirectoryExists(TextFormat("%s/%s", dir, d2)); + + if (b1 && !b2) return -1; + if (!b1 && b2) return 1; + + if (!FileExists(TextFormat("%s/%s", dir, d1))) return 1; + if (!FileExists(TextFormat("%s/%s", dir, d2))) return -1; + + return strcmp(d1, d2); +} + +// Read files in new path +static void ReloadDirectoryFiles(GuiWindowFileDialogState* state) +{ + UnloadDirectoryFiles(state->dirFiles); + + state->dirFiles = LoadDirectoryFilesEx(state->dirPathText, (state->filterExt[0] == '\0') ? NULL : state->filterExt, false); + state->itemFocused = 0; + + // Reset dirFilesIcon memory + for (int i = 0; i < MAX_DIRECTORY_FILES; i++) memset(dirFilesIcon[i], 0, MAX_ICON_PATH_LENGTH); + + // Copy paths as icon + fileNames into dirFilesIcon + for (int i = 0; i < state->dirFiles.count; i++) + { + if (IsPathFile(state->dirFiles.paths[i])) + { + // Path is a file, a file icon for convenience (for some recognized extensions) + if (IsFileExtension(state->dirFiles.paths[i], ".png;.bmp;.tga;.gif;.jpg;.jpeg;.psd;.hdr;.qoi;.dds;.pkm;.ktx;.pvr;.astc")) + { + strcpy(dirFilesIcon[i], TextFormat("#12#%s", GetFileName(state->dirFiles.paths[i]))); + } + else if (IsFileExtension(state->dirFiles.paths[i], ".wav;.mp3;.ogg;.flac;.xm;.mod;.it;.wma;.aiff")) + { + strcpy(dirFilesIcon[i], TextFormat("#11#%s", GetFileName(state->dirFiles.paths[i]))); + } + else if (IsFileExtension(state->dirFiles.paths[i], ".txt;.info;.md;.nfo;.xml;.json;.c;.cpp;.cs;.lua;.py;.glsl;.vs;.fs")) + { + strcpy(dirFilesIcon[i], TextFormat("#10#%s", GetFileName(state->dirFiles.paths[i]))); + } + else if (IsFileExtension(state->dirFiles.paths[i], ".exe;.bin;.raw;.msi")) + { + strcpy(dirFilesIcon[i], TextFormat("#200#%s", GetFileName(state->dirFiles.paths[i]))); + } + else strcpy(dirFilesIcon[i], TextFormat("#218#%s", GetFileName(state->dirFiles.paths[i]))); + } + else + { + // Path is a directory, add a directory icon + strcpy(dirFilesIcon[i], TextFormat("#1#%s", GetFileName(state->dirFiles.paths[i]))); + } + } +} + +#if defined(USE_CUSTOM_LISTVIEW_FILEINFO) +// List View control for files info with extended parameters +static int GuiListViewFiles(Rectangle bounds, FileInfo* files, int count, int* focus, int* scrollIndex, int* active) +{ + int result = 0; + GuiState state = guiState; + int itemFocused = (focus == NULL) ? -1 : *focus; + int itemSelected = *active; + + // Check if we need a scroll bar + bool useScrollBar = false; + if ((GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)) * count > bounds.height) useScrollBar = true; + + // Define base item rectangle [0] + Rectangle itemBounds = { 0 }; + itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING); + itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); + itemBounds.width = bounds.width - 2 * GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) - GuiGetStyle(DEFAULT, BORDER_WIDTH); + itemBounds.height = GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT); + if (useScrollBar) itemBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH); + + // Get items on the list + int visibleItems = bounds.height / (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)); + if (visibleItems > count) visibleItems = count; + + int startIndex = (scrollIndex == NULL) ? 0 : *scrollIndex; + if ((startIndex < 0) || (startIndex > (count - visibleItems))) startIndex = 0; + int endIndex = startIndex + visibleItems; + + // Update control + //-------------------------------------------------------------------- + if ((state != GUI_STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GetMousePosition(); + + // Check mouse inside list view + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = GUI_STATE_FOCUSED; + + // Check focused and selected item + for (int i = 0; i < visibleItems; i++) + { + if (CheckCollisionPointRec(mousePoint, itemBounds)) + { + itemFocused = startIndex + i; + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) itemSelected = startIndex + i; + break; + } + + // Update item rectangle y position for next item + itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)); + } + + if (useScrollBar) + { + int wheelMove = GetMouseWheelMove(); + startIndex -= wheelMove; + + if (startIndex < 0) startIndex = 0; + else if (startIndex > (count - visibleItems)) startIndex = count - visibleItems; + + endIndex = startIndex + visibleItems; + if (endIndex > count) endIndex = count; + } + } + else itemFocused = -1; + + // Reset item rectangle y to [0] + itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + DrawRectangleRec(bounds, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background + DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + state * 3)), guiAlpha)); + + // TODO: Draw list view header with file sections: icon+name | size | type | modTime + + // Draw visible items + for (int i = 0; i < visibleItems; i++) + { + if (state == GUI_STATE_DISABLED) + { + if ((startIndex + i) == itemSelected) + { + DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)), guiAlpha)); + DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), guiAlpha)); + } + + // TODO: Draw full file info line: icon+name | size | type | modTime + + GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED)), guiAlpha)); + } + else + { + if ((startIndex + i) == itemSelected) + { + // Draw item selected + DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)), guiAlpha)); + DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), guiAlpha)); + + GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)), guiAlpha)); + } + else if ((startIndex + i) == itemFocused) + { + // Draw item focused + DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)), guiAlpha)); + DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), guiAlpha)); + + GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)), guiAlpha)); + } + else + { + // Draw item normal + GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL)), guiAlpha)); + } + } + + // Update item rectangle y position for next item + itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)); + } + + if (useScrollBar) + { + Rectangle scrollBarBounds = { + bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), + bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), + bounds.height - 2 * GuiGetStyle(DEFAULT, BORDER_WIDTH) + }; + + // Calculate percentage of visible items and apply same percentage to scrollbar + float percentVisible = (float)(endIndex - startIndex) / count; + float sliderSize = bounds.height * percentVisible; + + int prevSliderSize = GuiGetStyle(SCROLLBAR, SLIDER_WIDTH); // Save default slider size + int prevScrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed + GuiSetStyle(SCROLLBAR, SLIDER_WIDTH, sliderSize); // Change slider size + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleItems); // Change scroll speed + + startIndex = GuiScrollBar(scrollBarBounds, startIndex, 0, count - visibleItems); + + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, prevScrollSpeed); // Reset scroll speed to default + GuiSetStyle(SCROLLBAR, SLIDER_WIDTH, prevSliderSize); // Reset slider size to default + } + //-------------------------------------------------------------------- + + if (focus != NULL) *focus = itemFocused; + if (scrollIndex != NULL) *scrollIndex = startIndex; + + *active = itemSelected; + return result; +} +#endif // USE_CUSTOM_LISTVIEW_FILEINFO + +#endif // GUI_FILE_DIALOG_IMPLEMENTATION diff --git a/res/lua/bubble_sortiva.lua b/res/lua/bubble_sortiva.lua new file mode 100644 index 0000000..1ecb004 --- /dev/null +++ b/res/lua/bubble_sortiva.lua @@ -0,0 +1,25 @@ + +local bubble_sort = Future:new() + +function bubble_sort:poll(array) + local n = array:size() + self.state[n] = self.state[n] or n + if n == 0 then + return false + end + + local swapped = false + for i = 1, n - 1 do + if array.at(i-1) > array.at(i) then + array.swap(i-1, i) + swapped = true + end + end + self.state.n = self.state.n - 1 + + return not swapped +end + +function make_available(sorter_list) + table.insert(sorter_list, "bubble_sort") +end \ No newline at end of file diff --git a/res/lua/quick_sortiva.lua b/res/lua/quick_sortiva.lua new file mode 100644 index 0000000..654cf6f --- /dev/null +++ b/res/lua/quick_sortiva.lua @@ -0,0 +1,59 @@ +local quick_sort = Future:new() + +function quick_sort:sort(A, lo, hi, i) + if lo >= 0 and lo < hi then + lt, gt = partition(A, lo, hi) -- Multiple return values + + if #self.state["lt"] >= i and #self.state["gt"] >= i then + self:sort(A, lo, self.state["lt"][i] - 1, i+1) + self:sort(A, self.state["gt"][i] + 1, hi, i+1) + else + table.insert(self.state["lt"], lt) + table.insert(self.state["gt"], gt) + return false + end + end + return true +end + +function quick_sort:poll(array) + return self:sort(array, 0, array:size(),0) +end + + +-- Divides array into three partitions +function partition(A, lo, hi) + -- Pivot value + local pivot = A.at((lo + hi) / 2) -- Choose the middle element as the pivot (integer division) + + -- Lesser, equal and greater index + local lt = lo + local eq = lo + local gt = hi + + -- Iterate and compare all elements with the pivot + while eq <= gt do + if A[eq] < pivot then + -- Swap the elements at the equal and lesser indices + A:swap(eq, lt) + -- Increase lesser index + lt = lt + 1 + -- Increase equal index + eq = eq + 1 + elseif A[eq] > pivot then + -- Swap the elements at the equal and greater indices + A:swap(eq, gt) + -- Decrease greater index + gt = gt - 1 + else -- if A[eq] = pivot then + -- Increase equal index + eq = eq + 1 + end + end + -- Return lesser and greater indices + return lt, gt +end + +function make_available(sorter_list) + table.insert(sorter_list, "quick_sort") +end \ No newline at end of file diff --git a/src/LuaSortList.hpp b/src/LuaSortList.hpp new file mode 100644 index 0000000..ee2f44a --- /dev/null +++ b/src/LuaSortList.hpp @@ -0,0 +1,33 @@ +#pragma once +#include + +class LuaSortList +{ +public: + std::vector list; + + void swap(size_t i1, size_t i2) + { + std::swap(list[i1], list[i2]); + } + + size_t size() const + { + return list.size(); + } + + uint16_t at(size_t i) const + { + return list[i]; + } + + bool sorted() const + { + for (int i = 1; i < list.size() + 1; ++i) + { + if (list[i - 1] > list[i]) return false; + } + return true; + } + +}; diff --git a/src/libimpl.cpp b/src/libimpl.cpp index 3052e1a..565a7a9 100644 --- a/src/libimpl.cpp +++ b/src/libimpl.cpp @@ -1,2 +1,7 @@ #define RAYGUI_IMPLEMENTATION -#include \ No newline at end of file +#include + +#undef RAYGUI_IMPLEMENTATION +#define GUI_WINDOW_FILE_DIALOG_IMPLEMENTATION +#define RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT 24 +#include \ No newline at end of file diff --git a/src/lua/Future.lua b/src/lua/Future.lua new file mode 100644 index 0000000..61e9f81 --- /dev/null +++ b/src/lua/Future.lua @@ -0,0 +1,16 @@ +Future = { + state = {} +} + +function Future:new(state) + local f = {} + setmetatable(f, self) + self.__index = self + f["state"] = state or {} + + return f +end + +function Future:pull() + return true +end \ No newline at end of file diff --git a/src/lua/FutureLua.hpp b/src/lua/FutureLua.hpp new file mode 100644 index 0000000..1d2b902 --- /dev/null +++ b/src/lua/FutureLua.hpp @@ -0,0 +1,35 @@ +#pragma once + +/* +static inline const char lua_future_class[] = R"( +Future = { + state = {} +} + +function Future:new(state) + local f = {} + setmetatable(f, self) + self.__index = self + f["state"] = state or {} + + return f +end + +function Future:poll() + return true +end + +function Future.get(t, ...) + return t:poll(unpack(arg)) +end +)"; +*/ + +template +class Future +{ +public: + virtual ~Future() = default; + virtual bool poll() = 0; + virtual T& get() = 0; +}; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 25d6a77..52f1190 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,7 @@ #include -#include "sortiva.hpp" +#include "sortiva/sortiva.hpp" +#undef _DEBUG int main(int argc, char** argv) { printf("Darling, I'm Home!\n"); diff --git a/src/sortiva-update.cpp b/src/sortiva-update.cpp deleted file mode 100644 index ad9f3a5..0000000 --- a/src/sortiva-update.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "sortiva.hpp" - -void Sortiva::update(double dt) { - for (auto& ticker : m_TickSystems) - { - if (ticker.update(std::chrono::milliseconds(static_cast(dt)))) - { - ticker.call(); - } - } -} \ No newline at end of file diff --git a/src/sortiva.cpp b/src/sortiva.cpp deleted file mode 100644 index e5ca1eb..0000000 --- a/src/sortiva.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "sortiva.hpp" - -#include -#include - -#include -#include - - -namespace rl -{ -#include -} - - -Sortiva::Sortiva() -{ - rl::InitWindow(1280, 720, "Sortiva"); - if (!rl::IsWindowReady()) exit(2); - - m_Width = rl::GetRenderWidth(); - m_Height = rl::GetRenderHeight(); - rl::SetWindowMinSize(static_cast(1280 * 0.25f), static_cast(720 * 0.25f)); - rl::SetWindowState(rl::ConfigFlags::FLAG_WINDOW_RESIZABLE | rl::ConfigFlags::FLAG_VSYNC_HINT); - - rl::SetTargetFPS(60); -} - -Sortiva::~Sortiva() -{ - rl::CloseWindow(); -} - -void Sortiva::run() -{ - setup(); - while (m_Running) - { - if (rl::WindowShouldClose()) m_Running = false; - if (rl::IsWindowResized()) - { - m_Width = rl::GetScreenWidth(); - m_Height = rl::GetScreenHeight(); - } - - rl::ClearBackground({ 25, 25, 25, 255 }); - rl::BeginDrawing(); - - update(rl::GetFrameTime()); - draw(); - - rl::EndDrawing(); - } -} - -void Sortiva::setup() -{ - m_Steps.reset(); - m_Steps = std::make_unique(); - - - - m_Steps->emplace_back(); - m_Steps->emplace_back(); - m_Steps->emplace_back(); - - linked_list& list1 = m_Steps->at(0); - list1.value = 1; - list1.put(1).put(3).put(1).put(1); - // - linked_list& list2 = m_Steps->at(1); - list2.value = 3; - list2.put(2).put(1).put(3).put(2); - // - linked_list& list3 = m_Steps->at(2); - list3.value = 2; - list3.put(3).put(2).put(2).put(3); - -} diff --git a/src/sortiva.hpp b/src/sortiva.hpp deleted file mode 100644 index 678baed..0000000 --- a/src/sortiva.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#include -#include -#include "collections.hpp" -#include "TickSystem.hpp" - -class Sortiva final -{ -public: - Sortiva(); - ~Sortiva(); - - void run(); -private: - int m_Width; - int m_Height; - bool m_Running; - - - void draw(); - void update(double deltatime); - - void setup(); - - std::vector m_TickSystems; - - // std::unique_ptr - // -> tree - // -> linked_list - // -> uint16_t - using val_step_diag = std::vector>; - std::unique_ptr m_Steps; -}; diff --git a/src/sortiva/GuiFileDialog.cpp b/src/sortiva/GuiFileDialog.cpp new file mode 100644 index 0000000..5dc3ce5 --- /dev/null +++ b/src/sortiva/GuiFileDialog.cpp @@ -0,0 +1,45 @@ +#include "GuiFileDialog.hpp" +#include +#include + + +Gui_WindowFileDialog::Gui_WindowFileDialog() +{ + fileDialogState = new GuiWindowFileDialogState(InitGuiWindowFileDialog(GetWorkingDirectory())); + fileDialogState->windowBounds = { 10, 10, fileDialogState->windowBounds.height, fileDialogState->windowBounds.height }; +} + +bool Gui_WindowFileDialog::update() +{ + bool file_opened = false; + if (fileDialogState->SelectFilePressed) + { + // Load image file (if supported extension) + if (IsFileExtension(fileDialogState->fileNameText, ".lua")) + { + strcpy(fileNameToLoad, TextFormat("%s/%s", fileDialogState->dirPathText, fileDialogState->fileNameText)); + openedFile = fileNameToLoad; + file_opened = true; + } + + fileDialogState->SelectFilePressed = false; + } + return file_opened; +} + +void Gui_WindowFileDialog::draw() +{ + // raygui: controls drawing + //---------------------------------------------------------------------------------- + if (fileDialogState->windowActive) GuiLock(); + + if (GuiButton({ 20, 20, 140, 30 }, GuiIconText(GuiIconName::ICON_FILE_OPEN, "Open Image"))) fileDialogState->windowActive = true; + + GuiUnlock(); + + // GUI: Dialog Window + //-------------------------------------------------------------------------------- + GuiWindowFileDialog(fileDialogState); + //-------------------------------------------------------------------------------- + +} \ No newline at end of file diff --git a/src/sortiva/GuiFileDialog.hpp b/src/sortiva/GuiFileDialog.hpp new file mode 100644 index 0000000..6f2162a --- /dev/null +++ b/src/sortiva/GuiFileDialog.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + + +class Gui_WindowFileDialog +{ + GuiWindowFileDialogState* fileDialogState; + char fileNameToLoad[512] = { 0 }; +public: + Gui_WindowFileDialog(); + + std::string openedFile; + + bool update(); + + void draw(); +}; diff --git a/src/sortiva-draw.cpp b/src/sortiva/sortiva-draw.cpp similarity index 77% rename from src/sortiva-draw.cpp rename to src/sortiva/sortiva-draw.cpp index 799be76..83e81c9 100644 --- a/src/sortiva-draw.cpp +++ b/src/sortiva/sortiva-draw.cpp @@ -1,13 +1,11 @@ #include "sortiva.hpp" -namespace rl -{ #include -} + #include -constexpr rl::Color sorter_colors[] = { +constexpr Color sorter_colors[] = { { 253, 249, 0, 255 }, // Yellow { 255, 203, 0, 255 }, // Gold { 255, 161, 0, 255 }, // Orange @@ -29,23 +27,23 @@ constexpr rl::Color sorter_colors[] = { { 76, 63, 47, 255 }, // Dark Brown }; -constexpr int sorter_colors_size = sizeof(sorter_colors) / sizeof(rl::Color); +constexpr int sorter_colors_size = sizeof(sorter_colors) / sizeof(Color); -constexpr rl::Color sorter_block_colors[] = { +constexpr Color sorter_block_colors[] = { { 200, 200, 200, 255 }, // Light Gray { 80, 80, 80, 255 }, // Dark Gray }; -constexpr int sorter_block_colors_size = sizeof(sorter_block_colors) / sizeof(rl::Color); +constexpr int sorter_block_colors_size = sizeof(sorter_block_colors) / sizeof(Color); void Sortiva::draw() { - rl::Vector2 margin = { + Vector2 margin = { .x = m_Width * 0.01f, .y = m_Height * 0.01f }; - rl::DrawRectangleV(margin, { m_Width - 2 * margin.x, m_Height - 2 * margin.y }, { 60, 60, 60, 255 }); + DrawRectangleV(margin, { m_Width - 2 * margin.x, m_Height - 2 * margin.y }, { 60, 60, 60, 255 }); margin = { @@ -53,6 +51,21 @@ void Sortiva::draw() .y = m_Height * 0.02f }; + Rectangle plane = { + .x = margin.x, + .y = margin.y, + .width = m_Width - margin.x * 2, + .height = m_Height - margin.y * 2 + }; + + if (m_Steps->empty()) + { + static const char* msg = "Select and run a Sorting algorithm"; + static int width = MeasureText(msg, 20); + DrawText(msg, plane.x + plane.width / 2 - width / 2, plane.y + plane.height / 2 - 10, 20, { 245, 245, 245, 255 }); + return; + } + // +2 for start points and end points; will be removed later in the function size_t cvals = m_Steps->size(); @@ -64,13 +77,6 @@ void Sortiva::draw() steps += 1; - rl::Rectangle plane = { - .x = margin.x, - .y = margin.y, - .width = m_Width - margin.x * 2, - .height = m_Height - margin.y * 2 - }; - // ui distance values int w = static_cast(plane.width / static_cast(steps)); int g = plane.height / static_cast(cvals + 1); @@ -85,7 +91,7 @@ void Sortiva::draw() for (size_t i = 0; i < steps; ++i) { - rl::DrawRectangle( + DrawRectangle( static_cast(i) * w + static_cast(plane.x), plane.y, w, @@ -99,19 +105,18 @@ void Sortiva::draw() int colid = sorter_colors_size / cvals; // font settings - constexpr rl::Color textColor = { 0, 0, 0, 255 }; + constexpr Color textColor = { 0, 0, 0, 255 }; int l3 = static_cast(l * 3); #ifdef _DEBUG - rl::DrawFPS(5, 5); + DrawFPS(5, 5); #endif for (int v = 0; v < cvals; ++v) { linked_list* list = &m_Steps->at(v); - uint16_t value = list->value; - rl::Color col = sorter_colors[(v * colid) % sorter_colors_size]; + Color col = sorter_colors[(v * colid) % sorter_colors_size]; float wf = static_cast(w); @@ -127,7 +132,7 @@ void Sortiva::draw() float yt = plane.y + h + g * (nvalue - 1); - rl::DrawSplineSegmentBezierCubic( + DrawSplineSegmentBezierCubic( { (sf + 1.f) * wf + plane.x - 1, y }, { (sf + 2.f) * wf + plane.x, y }, { (sf + 1.f) * wf + plane.x, yt }, @@ -140,8 +145,8 @@ void Sortiva::draw() float font_size = l * 1.2f; int yd = y - yt < 0 ? -font_size : +font_size; yd *= 2; - rl::DrawText( - rl::TextFormat("%d -> %d", value, nvalue), + DrawText( + TextFormat("%d -> %d", value, nvalue), (sf + 1.f) * wf + plane.x + 10, y + yd, font_size, @@ -152,18 +157,18 @@ void Sortiva::draw() value = list->value; - rl::Vector2 pos = { wf * steps + e + plane.x, h + (value - 1) * g + plane.y }; - rl::DrawCircleV(pos, l3, col); + Vector2 pos = { wf * steps + e + plane.x, h + (value - 1) * g + plane.y }; + DrawCircleV(pos, l3, col); - rl::DrawLineEx( + DrawLineEx( { pos.x - e - 1, pos.y }, pos, l, col ); - const char* strv = rl::TextFormat("%d", v + 1); - rl::DrawText( + const char* strv = TextFormat("%d", v + 1); + DrawText( strv, static_cast(pos.x) + e / 2, static_cast(pos.y) - l3 / 2, @@ -171,11 +176,12 @@ void Sortiva::draw() textColor ); - list = list->first; + if (list->first) + list = list->first->next; value = list->value; pos = { wf - e + plane.x, h + (value - 1) * g + plane.y }; - rl::DrawText( + DrawText( strv, static_cast(pos.x) - e / 2 - l3 / 2, static_cast(pos.y) - l3 / 2, @@ -183,7 +189,7 @@ void Sortiva::draw() textColor ); - rl::DrawRing( + DrawRing( pos, l * 2, l3, @@ -193,11 +199,12 @@ void Sortiva::draw() col ); - rl::DrawLineEx( + DrawLineEx( pos, { pos.x + e, pos.y }, l, col ); } + } \ No newline at end of file diff --git a/src/sortiva/sortiva-draw_overlay.cpp b/src/sortiva/sortiva-draw_overlay.cpp new file mode 100644 index 0000000..1ac86ce --- /dev/null +++ b/src/sortiva/sortiva-draw_overlay.cpp @@ -0,0 +1,28 @@ +#include "sortiva.hpp" + +#include + + +void Sortiva::draw_overlay() +{ + //static bool edit_mode = false; + // + //GuiUnlock(); + // + //static int active = 0; + //if (GuiDropdownBox({ 250,20,200,30 }, m_Lua.SorterListStr.c_str(), &active, edit_mode)) edit_mode = !edit_mode; + // + //if (edit_mode) GuiLock(); + + if (GuiButton({ 450, 20, 100, 40 }, "Run")) + { + setup(); + m_SortingFinished = false; + } + if (GuiButton({ 200, 20, 100, 40 }, "Pause")) + { + if (m_SortingFinished && m_Steps->empty()) return; + m_SortingFinished = !m_SortingFinished; + } + +} diff --git a/src/sortiva/sortiva-update.cpp b/src/sortiva/sortiva-update.cpp new file mode 100644 index 0000000..f4c93c2 --- /dev/null +++ b/src/sortiva/sortiva-update.cpp @@ -0,0 +1,22 @@ +#include "sortiva.hpp" + + +void Sortiva::update(double dt) { + if (m_Ticker.update(std::chrono::duration(dt))) + { + if (!m_SortingFinished) { + if (m_Sorter.poll()) + { + m_SortingFinished = true; + } + else + { + LuaSortList& list = m_Sorter.get(); + for (uint16_t i = 0; i < list.size(); ++i) + { + m_Steps->at(list.at(i) - 1).put(i + 1); + } + } + } + } +} \ No newline at end of file diff --git a/src/sortiva/sortiva.cpp b/src/sortiva/sortiva.cpp new file mode 100644 index 0000000..4df4ea5 --- /dev/null +++ b/src/sortiva/sortiva.cpp @@ -0,0 +1,78 @@ +#include "sortiva.hpp" + +#include + +#include +#include + + +#include + + +Sortiva::Sortiva() : m_Ticker(std::chrono::seconds(1)) +{ + m_Sorter.set(m_List); + + m_Steps = std::make_unique(); + + InitWindow(1280, 720, "Sortiva"); + if (!IsWindowReady()) exit(2); + + m_Width = GetRenderWidth(); + m_Height = GetRenderHeight(); + SetWindowMinSize(static_cast(1280 * 0.25f), static_cast(720 * 0.25f)); + SetWindowState(ConfigFlags::FLAG_WINDOW_RESIZABLE | ConfigFlags::FLAG_VSYNC_HINT); + + SetTargetFPS(60); +} + +Sortiva::~Sortiva() +{ + CloseWindow(); +} + +void Sortiva::run() +{ + while (m_Running) + { + if (WindowShouldClose()) m_Running = false; + if (IsWindowResized()) + { + m_Width = GetScreenWidth(); + m_Height = GetScreenHeight(); + } + + ClearBackground({ 25, 25, 25, 255 }); + BeginDrawing(); + + update(GetFrameTime()); + draw(); + draw_overlay(); + + EndDrawing(); + } +} + +void Sortiva::setup() +{ + m_Steps->clear(); + m_List.list.clear(); + + uint16_t count = 5; + + + for (int i = 1; i <= count; ++i) // 1,2,3,4,5 + { + m_List.list.push_back(i); + } + + std::random_device dev; + std::mt19937 rng(dev()); + + std::ranges::shuffle(m_List.list, rng); // 2,3,1,5,4 + + for (int i = 1; i <= count; ++i) + { + m_Steps->emplace_back().value = m_List.list[i - 1]; + } +} diff --git a/src/sortiva/sortiva.hpp b/src/sortiva/sortiva.hpp new file mode 100644 index 0000000..fbc6c34 --- /dev/null +++ b/src/sortiva/sortiva.hpp @@ -0,0 +1,82 @@ +#pragma once +#include +#include +#include +#include "../lua/FutureLua.hpp" +#include +#include "../LuaSortList.hpp" + +class Bubble_Sorter : Future +{ + LuaSortList* list = nullptr; + struct STATE + { + size_t n = 0; + } state; +public: + Bubble_Sorter() = default; + Bubble_Sorter(LuaSortList& l) : list(&l) {} + + bool poll() override + { + int n = list->size(); + if (n <= 1) { + return true; + } + + state.n = state.n + 1; + + if (state.n >= n) + { + state.n = 1; + } + + if (list->at(state.n - 1) > list->at(state.n)) { + list->swap(state.n - 1, state.n); + return false; + } + return list->sorted(); + } + + LuaSortList& get() override + { + return *list; + } + + void set(LuaSortList& l) + { + list = &l; + } +}; + +class Sortiva final +{ +public: + Sortiva(); + ~Sortiva(); + + void run(); +private: + int m_Width; + int m_Height; + bool m_Running = true; + + void draw(); + void draw_overlay(); + void update(double); + + void setup(); + + bool m_SortingFinished = true; + TickSystem m_Ticker; + Bubble_Sorter m_Sorter; + LuaSortList m_List; + + + // std::unique_ptr + // -> tree + // -> linked_list + // -> uint16_t + using val_step_diag = std::vector>; + std::unique_ptr m_Steps; +};