diff --git a/.gitignore b/.gitignore index fabee7f..2abc06d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ *.ini -*.exe \ No newline at end of file +*.exe +*.rdbg +*.pdb \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a158a3d --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +Single-header file picker library for ImGui. + +Currently, this library is Windows-only. Support for Linux is planned. + +# How to use + + This library exposes three functions: + +``` +void renderFilePicker(char* userPath, bool* windowOpen, bool* memoryFreed, int windowFlags); +``` + + Call this function within the render loop providing a pre-allocated buffer of MAX_PATH characters in `userPath`, which will be filled with a UTF-8 string. `windowOpen` must be initially set to `true`, and will set itself to `false` when execution is done. If succesful, your buffer will contain a valid path. `memoryFreed` will be set to `true`, and must be checked once the window is closed to free memory resources acquired by this library. You can provide `windowFlags` to customize its appearance. + +### Window customization flags +``` + fp::WindowFlags::FULLSCREEN : Render window in full screen, without decorations. +``` + +``` +void freeMemory(bool* memoryFreed); +``` + + Memory resources will be deallocated alongside miscellaneous internal tasks, and `memoryFreed` will be set to `true`. + +``` +void setDebugInfo(int debugVerbosity); +``` + + When `FPDEBUG` is enabled, this allows you to configure debug granularity. + +### Debug flags + +``` + fp::DebugVerbosity::DIRECTORY + fp::DebugVerbosity::VOLUME + fp::DebugVerbosity::EXTENSION +``` + +# Library dependencies + + - **C++ STL**: This library uses `vector`, `fill` and `w\string`. + +# Demo build instructions + +## Build requirements + + - [**GLFW v3**](https://github.com/glfw/glfw/releases): used as rendering backend. Executable in releases is compiled with version [`3.3.9`](https://github.com/glfw/glfw/releases/tag/3.3.9). + - Developed and tested with `clang` using [**llvm-mingw 20220906**](https://github.com/mstorsjo/llvm-mingw/releases/tag/20220906). Any `MinGW`-backed `clang` compiler should work, but your mileage may vary. + +## How to compile + + Download GLFW and pick your libraries according to your toolchain. Then, call your compiler directly specifying both libs needed and your paths to the necessary header and lib files: + + ``` + clang++ demo/main.cpp -o demo/demo.exe -L C:/pathtollvmmingw/x86_64-w64-mingw32/bin -I C:\pathtollvmmingw\include -L C:/pathtoglfw/lib-mingw-w64 -I C:\pathtoglfw\include -lglfw3 -l libc++ + ``` + + If you want to statically link: + + ``` + clang++ demo/main.cpp -o demo/demo.exe -L C:/pathtoglfw/lib-mingw-w64 -L C:/pathtollvmmingw/x86_64-w64-mingw32/lib -I C:\pathtollvmmingw\include -I C:\pathtoglfw\include -std=c++17 -stdlib=libc++ -rtlib=compiler-rt -static -l glfw3 -l gdi32 -l opengl32 -l user32 -l kernel32 -static-libstdc++ + ``` + +# To-Dos + + - Implement a file watcher to check for changes on the current directory. + - Add Linux support. + - Allow users to provide their own memory allocations as an option. diff --git a/demo/main.cpp b/demo/main.cpp new file mode 100644 index 0000000..19be71e --- /dev/null +++ b/demo/main.cpp @@ -0,0 +1,143 @@ +//Demo executable based on GLFW +#define IMGUI_IMPLEMENTATION +#define GL_SILENCE_DEPRECATION + +#include "unityBuild.h" +#include "../filepicker.hpp" + +static void glfw_error_callback(int error, const char* description) { + fprintf(stderr, "Glfw Error %d: %s\n", error, description); +} + +int main(int, char**) { + // Setup window + glfwSetErrorCallback(glfw_error_callback); + if (!glfwInit()) + return 1; + + // Decide GL+GLSL versions +#if defined(IMGUI_IMPL_OPENGL_ES2) + // GL ES 2.0 + GLSL 100 + const char* glsl_version = "#version 100"; + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); +#elif defined(__APPLE__) + // GL 3.2 + GLSL 150 + const char* glsl_version = "#version 150"; + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac +#else + // GL 3.0 + GLSL 130 + const char* glsl_version = "#version 130"; + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only + //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 3.0+ only +#endif + + // Create window with graphics context + GLFWwindow* window = glfwCreateWindow(1280, 720, "File Picker Demo", NULL, NULL); + if (window == NULL) + return 1; + glfwMakeContextCurrent(window); + glfwSwapInterval(1); // Enable vsync + + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsLight(); + + // Setup Platform/Renderer backends + ImGui_ImplGlfw_InitForOpenGL(window, true); + ImGui_ImplOpenGL3_Init(glsl_version); + ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + + // + bool debugDirectory = true; + bool debugVolume = true; + bool debugExtension = true; + bool debugLogic = true; + + // Our state + char path[MAX_PATH * 4] = "";// = malloc(MAX_PATH * sizeof(char)); + int debugVerbosity = fp::DebugVerbosity::DIRECTORY | fp::DebugVerbosity::VOLUME | fp::DebugVerbosity::EXTENSION | fp::DebugVerbosity::LOGIC; + bool windowOpen = true; + bool memoryFreed = true; + + // Main loop + while (!glfwWindowShouldClose(window)) { + // Poll and handle events (inputs, window resize, etc.) + // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. + glfwPollEvents(); + + // Start the Dear ImGui frame + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + + // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). + + fp::setDebugInfo(debugVerbosity); + if(windowOpen) + fp::renderFilePicker(&path[0], &windowOpen, &memoryFreed, 0); + else if(!memoryFreed) + fp::freeResources(&memoryFreed); + + //if (show_demo_window) + ImGui::SetNextWindowSize(ImVec2(500.0f, 500.0f)); + ImGui::Begin("Values", NULL, 0); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PopStyleVar(1); + ImGui::Text(path); + // debugVerbosity = DEBUG_DIRECTORY | DEBUG_EXTENSION; +// debugVerbosity &= ~DEBUG_DIRECTORY; +// if (debugVerbosity & (DEBUG_DIRECTORY | DEBUG_EXTENSION)); + ImGui::Text("Debug verbosity"); + ImGui::Checkbox("Directory" , &debugDirectory); + ImGui::Checkbox("Volume" , &debugVolume ); + ImGui::Checkbox("Extension" , &debugExtension); + ImGui::Checkbox("Logic" , &debugLogic ); + debugVerbosity = (debugDirectory) ? debugVerbosity | fp::DIRECTORY : debugVerbosity& ~fp::DIRECTORY; + debugVerbosity = (debugVolume) ? debugVerbosity | fp::VOLUME : debugVerbosity& ~fp::VOLUME; + debugVerbosity = (debugExtension) ? debugVerbosity | fp::EXTENSION : debugVerbosity& ~fp::EXTENSION; + debugVerbosity = (debugLogic) ? debugVerbosity | fp::LOGIC : debugVerbosity& ~fp::LOGIC; + + //fp::DebugVerbosity::DIRECTORY | fp::DebugVerbosity::VOLUME | fp::DebugVerbosity::EXTENSION | fp::DebugVerbosity::LOGIC; + if (!windowOpen) + if(ImGui::Button("Open file picker")) { + windowOpen = !windowOpen; + } + //ImGui::Text(std::to_string(state).c_str()); + //ImGui::Text(state); + ImGui::End(); + //ImGui::ShowDemoWindow(&show_demo_window); + + // Rendering + ImGui::Render(); + int display_w, display_h; + glfwGetFramebufferSize(window, &display_w, &display_h); + glViewport(0, 0, display_w, display_h); + glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); + glClear(GL_COLOR_BUFFER_BIT); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + ImGui::EndFrame(); + glfwSwapBuffers(window); + } + + // Cleanup + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); + + glfwDestroyWindow(window); + glfwTerminate(); + + return 0; +} diff --git a/demo/unityBuild.h b/demo/unityBuild.h new file mode 100644 index 0000000..d2a675a --- /dev/null +++ b/demo/unityBuild.h @@ -0,0 +1,16 @@ +#define WIN32_LEAN_AND_MEAN +#define UNICODE +#define _UNICODE +#include "../imgui/imgui.h" + +#ifdef IMGUI_IMPLEMENTATION +#include "../imgui/imgui.cpp" +#include "../imgui/imgui_demo.cpp" +#include "../imgui/imgui_draw.cpp" +#include "../imgui/imgui_tables.cpp" +#include "../imgui/imgui_widgets.cpp" +#include "../imgui/backends/imgui_impl_glfw.h" +#include "../imgui/backends/imgui_impl_opengl3.h" +#include "../imgui/backends/imgui_impl_opengl3.cpp" +#include "../imgui/backends/imgui_impl_glfw.cpp" +#endif diff --git a/filepicker.hpp b/filepicker.hpp new file mode 100644 index 0000000..9b6dbc5 --- /dev/null +++ b/filepicker.hpp @@ -0,0 +1,819 @@ +//DEBUG MACRO +#ifdef FPDEBUG +#define log_debugc(str, ...) do { if (debug) fprintf(stdout, "[DEBUG] (%s:%d): " (str) "\n", __FILE__, __LINE__, ##__VA_ARGS__); } while (0) +#define log_debugcpp(str) do { \ + if (debug) std::cout << "[DEBUG]" << "(" << __FILE__ << ":" << __LINE__ << "): " << str << std::endl; \ + } while (0) +#define log_wdebugcpp(str) do { \ + if (debug) std::wcout << "[DEBUG]" << "(" << __FILE__ << ":" << __LINE__ << "): " << str << std::endl; \ + } while (0) +#define log_directory(str) do { \ + if(debugVerbosity & DIRECTORY) log_debugcpp(str); \ + } while (0) +#define log_volume(str) do { \ + if(debugVerbosity & VOLUME) log_debugcpp(str); \ + } while (0) +#define log_logic(str) do { \ + if(debugVerbosity & LOGIC) log_debugcpp(str); \ + } while (0) +#define log_extension(str) do { \ + if(debugVerbosity & EXTENSION) log_debugcpp(str); \ + } while (0) +#define log_wdirectory(str) do { \ + if(debugVerbosity & DIRECTORY) log_wdebugcpp(str); \ + } while (0) +#define log_wvolume(str) do { \ + if(debugVerbosity & VOLUME) log_wdebugcpp(str); \ + } while (0) +#define log_wextension(str) do { \ + if(debugVerbosity & EXTENSION) log_wdebugcpp(str); \ + } while (0) +#define log_wlogic(str) do { \ + if(debugVerbosity & LOGIC) log_wdebugcpp(str); \ + } while (0) +#else +#define log_debugc(str, ...) +#define log_debugcpp(str) +#define log_wdebugcpp(str) +#define log_directory(str) +#define log_volume(str) +#define log_extension(str) +#define log_wdirectory(str) +#define log_wvolume(str) +#define log_wextension(str) +#define log_logic(str) +#define log_wlogic(str) +#endif + +//PATH MACRO +#define MAX_LISTDIR_PATH_LENGTH (MAX_PATH - 3) +#define MAX_ERRORSTR_LEN 512 + +//HISTORY HANDLING MACRO +#define MIN_HISTORY_POS (history->historyTraversalPos <= 0) +#define MAX_HISTORY_POS (history->historyTraversalPos >= history->historyDepth) + +#include +#include +#include +#include +#include + +#pragma once + +namespace fp { + +typedef struct { + long long size; + //TODO yel spacsio NELLA MEMoria + WCHAR name[MAX_LISTDIR_PATH_LENGTH]; + char nameUTF8[MAX_LISTDIR_PATH_LENGTH * 4]; + SYSTEMTIME createTime; + SYSTEMTIME lastAccessTime; + SYSTEMTIME lastWriteTime; + bool isFile; + bool isHidden; + +} directoriesInfo; + + +struct History { + std::vector previousPaths; + std::vector previousPathsUTF8; + //warnings e 1 cosa + //int historyDepth = -1; + //TODO Limitar historial + //const int maxHistoryDepth = 10000; + //int currentStart = 0; + int historyDepth; + int historyTraversalPos; + bool isAdditionTime; + + History(){ + historyTraversalPos = historyDepth = -1; + isAdditionTime = true; + } + + // wchar* operator[](int idx){ + // if (idx > previousPaths.size()) + // int newPos = idx + currentStart; + + // if (newPos < 0) return previousPaths[maxHistoryDepth - (newPos % maxHistoryDepth)]; + // else return previousPaths[newPos % maxHistoryDepth]; + + // } + + // void push_back(wchar* path){ + // if (previousPaths.size() < maxHistoryDepth) previousPaths.push_back(path); + // else { + // previousPaths[currentStart++] = path; + // } + // } + + +}; + +enum HistoryMovement { + HISTORY_FORWARD = 1, + HISTORY_BACKWARD = 0 +}; + +enum ListDirectoryError { + DIRECTORY_ERROR_PATH_TOO_LONG = -1, + DIRECTORY_ERROR_ACCESSING_CONTENT = -2 +}; + +enum AgnosticDirError { + AGDIR_ERROR_ACCESS_DENIED = 1 +}; + +namespace ErrorMessages { + char addrBarError[] = "Failed to open folder: invalid path"; + char tableElementError[] = "Failed to open folder: access restricted to non-admin users"; + char accessDeniedError[] = "Failed to open folder: access denied"; + char listDirectoryError[] = "Failed to open folder: unknown error"; + char moveUpError[] = "Failed to move up: reached volume root?"; +}; + +namespace Label { + wchar_t saveFileLabel[] = L"Save file: "; + wchar_t loadFileLabel[] = L"Select a file: "; + wchar_t selectDirectoryLabel[] = L"Select a directory: "; +}; + +enum ListFlags { + LIST_DIRECTORY = (1<<0), + LIST_VOLUME = (1<<1) +}; + +enum WindowFlags { + FULLSCREEN = (1<<0), + MODAL = (1<<1), + FILE_LOAD = (1<<2), + FILE_SAVE = (1<<3), + DIRECTORY_SELECT = (1<<4) +}; + +enum ExitFlags { + CONTINUE = (1<<0), + SELECTED = (1<<1), + CLOSED = (1<<2) +}; + +enum DebugVerbosity { + DIRECTORY = (1<<0), + VOLUME = (1<<1), + EXTENSION = (1<<2), + LOGIC = (1<<3) +}; + +//VARS +#ifdef FPDEBUG +bool debug = true; +#else +bool debug = false; +#endif + +// Window open bool +bool windowOpen = true; +bool windowConfigured = false; + +//Flags used to determine: +// window format +//int windowFlags = 0; +// if it's time to load new data +int listFlags = LIST_DIRECTORY | LIST_VOLUME; + +//Array used to display current error +char error[MAX_ERRORSTR_LEN]; +//wchar_t errorUTF8[MAX_ERRORSTR_LEN * 4]; +bool showError = false; + +//Stores found volumes +//TODO onPresentPaths might not be the best name +std::vector onPresentPaths; +std::vector onPresentPathsUTF8; +int numVolumes; + +//currentPath is the one used to retrieve data, then copied to addrBarVal for display. +//addrBarVal is also used as a bacukp in case new currentPath is invalid +//chosenFile stores absolute file path to return +//TODO: hay historial. Coalescer en una sola? +//cursed C momento: necesario ptr en otra var para mandar a wchar_t** de firma +wchar_t currentPath[MAX_PATH]; +//wchar_t* currentPathPtr = ¤tPath[0]; +wchar_t addrBarVal[MAX_LISTDIR_PATH_LENGTH]; +char addrBarValUTF8[MAX_LISTDIR_PATH_LENGTH * 4]; +//wchar_t* addrBarValPtr = &addrBarVal[0]; +wchar_t chosenPath[MAX_PATH]; +char chosenPathUTF8[MAX_PATH * 4]; + +//Stores entires found within a given directory +//static int currentItemIdx = -1; +std::vector directoryContents; +int numFiles = 0; + +//Going one level up needs to be hardcoded like this due to function inputMove needing a wchar_t** +//c pervirtio con unicode std::wstring s(L"←→↑↓"); +wchar_t moveUp[] = L".."; + +bool isListVolumesAdequate = true; +bool isListDirectoriesAdequate = true; + +//RenderTime vars for filtering +bool showHidden = false; +bool filterByExtension = false; +std::vector extensions; + +History* history; + +int debugVerbosity = 0; +/* DEBUG VERBOSITY */ + +void setDebugInfo(int debugFlags) { + debugVerbosity = debugFlags; +} + +/* FILE PICKER MOMENTO */ + +/* DIRECTORIES */ + +bool retrieveCurrentDirectory(wchar_t* currentPath){ + if(GetCurrentDirectory(MAX_PATH, currentPath)) return true; + return false; +} + +bool moveDirectory(wchar_t* currentPath){ + log_directory(currentPath); + if(SetCurrentDirectory(currentPath)) return true; + return false; +} + +int listDirectory(std::wstring path, std::vector *directoryContents){ + HANDLE hFind = INVALID_HANDLE_VALUE; + WIN32_FIND_DATA ffd; + LARGE_INTEGER filesize; + int numFiles = 0; + + if (path.length() > (MAX_LISTDIR_PATH_LENGTH)) return DIRECTORY_ERROR_PATH_TOO_LONG; + path = path + L"\\*"; + hFind = FindFirstFile(path.c_str(), &ffd); + if (INVALID_HANDLE_VALUE == hFind) return DIRECTORY_ERROR_ACCESSING_CONTENT; + do { + if(!wcscmp(ffd.cFileName, L".") || !wcscmp(ffd.cFileName, L"..")) continue; + log_directory("BUCLE listDirectory iteracion " + std::to_string(numFiles)); + + directoriesInfo* itemInfo; + if (directoryContents->size() <= numFiles){ + itemInfo = new directoriesInfo(); + directoryContents->push_back(itemInfo); + } else { + itemInfo = directoryContents->at(numFiles); + } + log_directory("MEMORY ASSIGNES iteration " + std::to_string(numFiles)); + + //A registrar info, fiera + itemInfo->isFile = (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false; + itemInfo->isHidden = (ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? true : false; + //Tamaño + filesize.QuadPart = ((ffd.nFileSizeHigh * (MAXDWORD+1)) + ffd.nFileSizeLow); + itemInfo->size = filesize.QuadPart; + //Fechitssss + FileTimeToSystemTime(&ffd.ftCreationTime, &itemInfo->createTime); + FileTimeToSystemTime(&ffd.ftLastAccessTime, &itemInfo->lastAccessTime); + FileTimeToSystemTime(&ffd.ftLastWriteTime, &itemInfo->lastWriteTime); + //Nombre de la cosita + uint64_t idx = 0; + do { + itemInfo->name[idx] = ffd.cFileName[idx]; + itemInfo->nameUTF8[idx] = ffd.cFileName[idx]; + idx++; + } while (ffd.cFileName[idx]); + itemInfo->name[idx] = '\0'; + itemInfo->nameUTF8[idx] = '\0'; + log_directory("INFORMACION ALMACENADA iteracion " + std::to_string(numFiles)); + + numFiles++; + } while (FindNextFile(hFind, &ffd) != 0); + FindClose(hFind); + return numFiles; +} + +long getLastSystemError(){ + DWORD winLastError = GetLastError(); + switch(winLastError){ + case ERROR_ACCESS_DENIED: + return AGDIR_ERROR_ACCESS_DENIED; + break; + default: + return winLastError; + break; + } +} + +/* VOLUMES */ + +//new wchar_t*[Wchar_TCount * sizeof(WWCHAR_T) +/*idea, si quisiera que empezase en punto X del string + coger el param opcional y crear un puntero a la posicion X del array para empezar desde ahi + int explodePaths(TWCHAR_T* volumePaths, int volumePathLength, int volumePathBufferSize, + wchar_t separator, std::vector *dest, , int startingFrom = 0); + if (nextOcurrence == NULL) return 0; +*/ +int explodePaths(wchar_t* volumePaths, int volumePathsBufferSize, wchar_t separator, std::vector *dest, std::vector *destUTF8, int depth = 1){ + //Por alguna razón, esto que dice acabar con 2 NULL acaba con 3; de locos. + //https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumepathnamesforvolumenamew + + wchar_t* nextOcurrence = wcschr(volumePaths, separator); + + wchar_t* itemPath; + char* itemPathUTF8; + itemPath = (wchar_t*)calloc(2, volumePathsBufferSize); + itemPathUTF8 = (char*)calloc(4, volumePathsBufferSize); + + int pathLengthIdx = 0; + for (; volumePaths[pathLengthIdx] != nextOcurrence[0]; pathLengthIdx++) { + log_volume(volumePaths[0] << " ENTERS " << std::to_string(pathLengthIdx)); + itemPath[pathLengthIdx] = volumePaths[pathLengthIdx]; + } + itemPath[pathLengthIdx + 1] = '\0'; + dest->push_back(itemPath); + WideCharToMultiByte(CP_UTF8, NULL, itemPath, -1, itemPathUTF8, + 4 * volumePathsBufferSize, NULL, NULL); + destUTF8->push_back(itemPathUTF8); + + + log_wvolume(dest->at(dest->size() - 1) << L" EXPLODEPATH"); + log_volume(destUTF8->at(destUTF8->size() - 1) << " EXPLODEPATH"); + + if (nextOcurrence[0] == nextOcurrence[1]) return depth; + depth++; + return explodePaths(nextOcurrence + sizeof(wchar_t), (volumePathsBufferSize - pathLengthIdx), separator, dest, destUTF8, depth); +} + + +int listVolumes(std::vector *onPresentPaths, std::vector *onPresentPathsUTF8){ + HANDLE hFind = INVALID_HANDLE_VALUE; + const wchar_t separator = '\0'; + + int numVolumes = 0; + //Volume name + wchar_t volumeName[MAX_PATH]; + int volumeNameSize = sizeof volumeName / sizeof volumeName[0]; + //Paths + int volumePathsBufferSize = (MAX_PATH + 1) * sizeof(wchar_t); + unsigned long volumePathLength; + wchar_t volumePaths[volumePathsBufferSize]; + std::fill(volumePaths, volumePaths + volumePathsBufferSize, '\0'); + + hFind = FindFirstVolume(volumeName, volumeNameSize); + if (INVALID_HANDLE_VALUE == hFind) return -2; + do { + + if(GetVolumePathNamesForVolumeName(volumeName, volumePaths, volumePathsBufferSize, &volumePathLength)){ + + if (volumePathLength == 1) { + log_volume("Skill Issue"); + continue; + } + log_wvolume(volumeName); + + //DEBUG: pathSchecker + // if (debug && volumePaths[0] == 'E') { + // std::cout << volumePathLength << std::endl; + // /*exit(1);*/ + // for (int i = 0; i < volumePathsBufferSize; i++){ + // std::cout << std::to_string(i) + ": "; + // std::cout << volumePaths[i]; + // std::cout << " | "; + // } + // std::cout << std::endl << "I IA" << std::endl; + // exit(1); + // } + if (debug) { + if(numVolumes += explodePaths(volumePaths, volumePathsBufferSize, separator, onPresentPaths, onPresentPathsUTF8)){ + for (int i = 0; i < onPresentPaths->size(); i++){ + log_wvolume(onPresentPaths->at(i)); + } + } + } + //std::cout << volumePaths << std::endl; + + log_volume(std::to_string(volumePathLength) + "<- VOLUME PATH LENGTH"); + log_volume("THE END"); + } else { + log_volume("no volumes found"); + } + //TODO benchimarqui + std::fill(volumePaths, volumePaths + volumePathsBufferSize, '\0'); + } while (FindNextVolume(hFind, volumeName, volumeNameSize) != 0); + log_volume(std::to_string(onPresentPaths->size()) + " JUST BEFORE MAIN"); + FindVolumeClose(hFind); + return numVolumes; +} + + +/* DISPLAY */ + + +bool compareLastWchar(std::vector *lastCharCandidates, wchar_t* string){ + bool matchingExtension = false; + for (int i = 0; i < lastCharCandidates->size(); i++){ + log_wextension(lastCharCandidates->at(i) << L" <- FILTERING EXTENSION"); + + if(wcslen(string) < lastCharCandidates->at(i).length()) continue; + wchar_t* potentialExtension = &string[wcslen(string) - lastCharCandidates->at(i).length()]; + + log_wextension(potentialExtension << L" LEN " + std::to_wstring(wcslen(potentialExtension)) + L" <- VS -> " + lastCharCandidates->at(i) + L" LEN " + std::to_wstring(lastCharCandidates->at(i).length())); + //+ strlen(potentialExtension) + std::to_string(lastCharCandidates->at(i).length()) + if(!wcscmp(potentialExtension, lastCharCandidates->at(i).c_str())) { + log_extension("VALID EXTENSION"); + matchingExtension = true; + } + } + return matchingExtension; +} + +//TODO huh +// int handleFolderAccessResult(int listFlags, wchar_t* nextPath, bool* error, wchar_t* errorDest, \ + // const wchar_t* errorContent, History* history, wchar_t* currentPath = NULL, wchar_t* addrBarVal = NULL){ + // *error = false; + // if(!moveDirectory(nextPath)) { + // *error = true; + // if(currentPath && addrBarVal) { + // wcscpy(errorDest, errorContent); + // wcscpy(addrBarVal, currentPath); + // } + // return listFlags; + // } + // if(currentPath && addrBarVal) { + // wcscpy(currentPath, addrBarVal); + // history->isAdditionTime = true; + // } + // return (listFlags |= LIST_DIRECTORY); +// } + + +//TODO huh, vale, no pasa por listdirectory por la flag, pero esto se podria hacer mejor manteniendo el no tirar de disco tb? +int handleFolderAccessResult(int listFlags, wchar_t* nextPath, bool* error, char* errorDest, \ + const char* errorContent, History* history, wchar_t* currentPath , wchar_t* addrBarVal){ + *error = false; + if(!moveDirectory(nextPath)) { + *error = true; + strcpy(errorDest, errorContent); + wcscpy(addrBarVal, currentPath); + return listFlags; + } + //wcscpy(currentPath, addrBarVal); + history->isAdditionTime = true; + return (listFlags |= LIST_DIRECTORY); +} + +int handleFolderAccessResult(int listFlags, wchar_t* nextPath, bool* error, char* errorDest, \ + const char* errorContent, History* history, bool isAdditionTime){ + *error = false; + if(!moveDirectory(nextPath)) { + *error = true; + strcpy(errorDest, errorContent); + return listFlags; + } + if (isAdditionTime) history->isAdditionTime = true; + return (listFlags |= LIST_DIRECTORY); +} + +/* HISTORIAL */ + +void addPathToHistory(History *history, wchar_t* pathToAdd){ + wchar_t* path; + char* pathUTF8; + if (history->historyTraversalPos + 1 >= history->previousPaths.size()){ + path = (wchar_t*)calloc(2, MAX_PATH); + history->previousPaths.push_back(path); + pathUTF8 = (char*)calloc(4, MAX_PATH); + WideCharToMultiByte(CP_UTF8, NULL, path, -1, pathUTF8, + 4 * MAX_PATH, NULL, NULL); + history->previousPathsUTF8.push_back(pathUTF8); + } else { + path = history->previousPaths.at(history->historyTraversalPos + 1); + pathUTF8 = history->previousPathsUTF8.at(history->historyTraversalPos + 1); + } + wcsncpy(path, pathToAdd, MAX_PATH); + history->historyTraversalPos++; + history->historyDepth = history->historyTraversalPos; + history->isAdditionTime = false; +} + +wchar_t* moveThroughHistory(History *history, HistoryMovement movement) { + int sign = (movement == HISTORY_BACKWARD ? -1 : 1); + switch(movement){ + case HISTORY_BACKWARD: + if(MIN_HISTORY_POS) + return history->previousPaths.at(history->historyTraversalPos); + break; + case HISTORY_FORWARD: + if(MAX_HISTORY_POS) + return history->previousPaths.at(history->historyDepth); + break; + default: + return history->previousPaths.at(history->historyDepth); + } + history->historyTraversalPos += sign; + return history->previousPaths.at(history->historyTraversalPos); +} + +/* RENDERING */ + +void windowRendering(char*, bool*, bool*, int); +void renderFilePicker(char* userPath, bool* windowOpen, bool* memoryFreed, int windowFlags = 0) { + //TODO filesystem watcher + //TODO let user handle memory management + //TODO use local val to create actual windowFlags when expanding functionality + #ifdef WIN32 + SetConsoleOutputCP(65001); + #endif + + if (!windowConfigured) { + listFlags = LIST_DIRECTORY | LIST_VOLUME; + history = new History(); + if (windowFlags & FULLSCREEN){ + ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f)); + ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize); + windowFlags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize; + } else { + ImGui::SetNextWindowPos(ImVec2(50.0f, 50.0f)); + ImGui::SetNextWindowSize(ImVec2(500.0f, 500.0f)); + windowFlags = ImGuiWindowFlags_None; + //const ImGuiViewport* viewport = ImGui::GetMainViewport(); + } + windowConfigured = true; + *memoryFreed = false; + } else windowFlags = 0; + windowRendering(userPath, windowOpen, memoryFreed, windowFlags); +} + +void freeResources(bool* memoryFreed){ + windowConfigured = false; + for (int i = 0; i < history->previousPaths.size(); i++){ + free(history->previousPaths.at(i)); + } + for (int i = 0; i < onPresentPaths.size(); i++){ + free(onPresentPaths.at(i)); + } + for (int i = 0; i < history->previousPathsUTF8.size(); i++){ + free(history->previousPathsUTF8.at(i)); + } + for (int i = 0; i < onPresentPathsUTF8.size(); i++){ + free(onPresentPathsUTF8.at(i)); + } + onPresentPaths.resize(0); + onPresentPathsUTF8.resize(0); + //previousPaths.resize(0); + delete history; + *memoryFreed = true; +} + +void exitWindow(char* userPath, bool* windowOpen, bool* memoryFreed, int exitFlag){ + if(exitFlag & SELECTED) { + if (chosenPath[0] == '\0') return; + strcpy(userPath, chosenPathUTF8); + *windowOpen = false; + } + freeResources(memoryFreed); + return; +} + +void windowRendering(char* userPath, bool* windowOpen, bool* memoryFreed, int windowFlags = 0){ + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::Begin("File picker", windowOpen, windowFlags); + ImGui::PopStyleVar(1); + //log_debugcpp(*windowOpen); + //Listar UNA VEZ volumenes + if (listFlags & LIST_VOLUME) { + listFlags &= ~LIST_VOLUME; + numVolumes = listVolumes(&onPresentPaths, &onPresentPathsUTF8); + log_volume(std::to_string(numVolumes) + "<- depth MAIN size() ->" + std::to_string(onPresentPaths.size())); + } + + //Listar UNA VEZ directorios + //ImGui::Text("%s PRE DIRECTORY TREATMENTO", currentPath); + if (listFlags & LIST_DIRECTORY) { + listFlags &= ~LIST_DIRECTORY; + chosenPath[0] = '\0'; + log_directory("ADECUADO LISTAR DIRECTORIOS"); + if(!retrieveCurrentDirectory(currentPath)) { + log_directory("NO HABIA DIRECTORIO GetCurrentPath()"); + exit(EXIT_FAILURE); + } + // + //TODO Expand extension filter + + numFiles = listDirectory(std::wstring(currentPath), &directoryContents); + //std::cout << numFiles; + if (numFiles < 0) { + long directoryErrorCode; + log_directory("FALLO LA FUNCION, VALOR NEGATIVO " + std::to_string(numFiles)); + if (numFiles == DIRECTORY_ERROR_ACCESSING_CONTENT) directoryErrorCode = getLastSystemError(); + showError = true; + switch(directoryErrorCode) { + case AGDIR_ERROR_ACCESS_DENIED: + strcpy(error, ErrorMessages::accessDeniedError); + wcscpy(addrBarVal, history->previousPaths.at(history->historyTraversalPos)); + wcscpy(currentPath, history->previousPaths.at(history->historyTraversalPos)); + numFiles = listDirectory(history->previousPaths.at(history->historyTraversalPos), &directoryContents); + break; + default: + strcpy(error, ErrorMessages::listDirectoryError); + wcscpy(currentPath, addrBarVal); + numFiles = listDirectory(std::wstring(currentPath), &directoryContents); + break; + } + history->isAdditionTime = false; + } else { + showError = false; + wcscpy(addrBarVal, currentPath); + if(history->isAdditionTime) addPathToHistory(history, addrBarVal); + } + } + + /* It's renderin' time */ + + if(showError) ImGui::Text(error); + ImGui::Text("Select a file:"); + + //BACK + ImGui::BeginDisabled(MIN_HISTORY_POS); + if(ImGui::Button("Back")) { + wchar_t* interfaceMovementButtonsPath = moveThroughHistory(history, HISTORY_BACKWARD); + listFlags = handleFolderAccessResult(listFlags, interfaceMovementButtonsPath, + &showError, error, ErrorMessages::moveUpError, history, false); + } + ImGui::EndDisabled(); + //FORWARD + ImGui::SameLine(); + ImGui::BeginDisabled(MAX_HISTORY_POS); + if(ImGui::Button("Forward")) { + wchar_t* interfaceMovementButtonsPath = moveThroughHistory(history, HISTORY_FORWARD); + listFlags = handleFolderAccessResult(listFlags, interfaceMovementButtonsPath, + &showError, error, ErrorMessages::moveUpError, history, false); + } + ImGui::EndDisabled(); + + //MOVE UP + ImGui::SameLine(); + if(ImGui::Button("Move Up")) { + listFlags = handleFolderAccessResult(listFlags, moveUp, &showError, + error, ErrorMessages::moveUpError, history, true); + } + + ImGui::SameLine(); + //BARRA DE DIRECCIONES + ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - (ImGui::CalcTextSize("Enter").x + ImGui::GetStyle().ItemSpacing.x * 2) ); + WideCharToMultiByte(CP_UTF8, NULL, addrBarVal, -1, addrBarValUTF8, + 4 * MAX_PATH, NULL, NULL); + if(ImGui::InputText("##addrbar", addrBarValUTF8, IM_ARRAYSIZE(addrBarValUTF8), ImGuiInputTextFlags_EnterReturnsTrue )){ + log_directory(currentPath <<" ADDRBAR INTENTO"); + MultiByteToWideChar(CP_UTF8, NULL, addrBarValUTF8, -1, addrBarVal, 2 * MAX_PATH); + listFlags = handleFolderAccessResult(listFlags, addrBarVal, &showError, error, ErrorMessages::addrBarError, history, currentPath, addrBarVal); + } + ImGui::PopItemWidth(); + ImGui::SameLine(); + if(ImGui::Button("Enter")){ + log_directory(currentPath <<" ADDRBAR INTENTO"); + listFlags = handleFolderAccessResult(listFlags, addrBarVal, &showError, error, ErrorMessages::addrBarError, + history, currentPath, addrBarVal); + } + //ImGui::Text("%s TEMPADDRBAR", currentPath); + + //LA GRAN TABLACIÓN: ACTOR EN LAS SOMBRAS + static ImGuiTableFlags splitterTableFlags = ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV; + if (ImGui::BeginTable("##splitterTable", 2, splitterTableFlags, ImVec2(-FLT_MIN, 0.8f * ImGui::GetTextLineHeightWithSpacing()))){ + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + //VOLUMENES + static ImGuiTableFlags volumesFlags = ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY ; + if (ImGui::BeginTable("##volumesTable", 1, volumesFlags, ImVec2(-FLT_MIN, 20 * ImGui::GetTextLineHeightWithSpacing()))){ + ImGui::TableSetupColumn("Volumes", ImGuiTableColumnFlags_NoHide); + //ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f); + //ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f); + ImGui::TableHeadersRow(); + ImGui::TableNextRow(); + + if (numVolumes > 0) { + for (int i = 0; i < onPresentPaths.size(); i++) { + ImGui::TableNextColumn(); + // ImGui::PushID(i); + ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f)); + if(ImGui::Button(onPresentPathsUTF8.at(i))){ + listFlags = handleFolderAccessResult(listFlags, onPresentPaths.at(i), &showError, error, + ErrorMessages::moveUpError, history, true); + } + ImGui::PopStyleColor(3); + if (i != onPresentPaths.size() - 1) ImGui::TableNextRow(); + // ImGui::PopID(); + } + } + ImGui::EndTable(); + } + + ImGui::TableNextColumn(); + + //DRAW DIRECTORIOS ENCONTRADOS + static ImGuiTableFlags directoriesFlags = ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable |ImGuiTableFlags_ScrollY ; + if (ImGui::BeginTable("##directoriesTable", 3, directoriesFlags, ImVec2(-FLT_MIN, 20 * ImGui::GetTextLineHeightWithSpacing()))){ + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide); + ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_NoHide); + ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_NoHide); + //ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f); + //ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f); + ImGui::TableHeadersRow(); + + int idx = 0; + for (; idx < numFiles; idx++) { + if(directoryContents.at(idx)->isHidden && !showHidden) continue; + if(filterByExtension && !directoryContents.at(idx)->isFile) { + //TODO Expand extensions filter + extensions.clear(); + extensions.push_back(L"exe"); + if (!compareLastWchar(&extensions, directoryContents.at(idx)->name)) continue; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + //NAME + bool isSelected = false; + WideCharToMultiByte(CP_UTF8, NULL, addrBarVal, -1, addrBarValUTF8, + 4 * MAX_PATH, NULL, NULL); + if (ImGui::Selectable(directoryContents.at(idx)->nameUTF8, &isSelected)){ + if(!directoryContents.at(idx)->isFile) { + wcscpy(chosenPath, addrBarVal); + wcscat(chosenPath, L"\\"); + wcscat(chosenPath, directoryContents.at(idx)->name); + log_directory(chosenPath << L" selected"); + } else { + wcscat(addrBarVal, L"\\"); + wcscat(addrBarVal, directoryContents.at(idx)->name); + log_directory("directo selected"); + listFlags = handleFolderAccessResult(listFlags, addrBarVal, &showError, error, + ErrorMessages::tableElementError, history, currentPath, addrBarVal); + } + //currentItemIdx = -1; + } + ImGui::TableNextColumn(); + + //TYPE + if (directoryContents.at(idx)->isFile) ImGui::Text("Folder"); else ImGui::Text("File"); + ImGui::TableNextColumn(); + + //SIZE + if (!directoryContents.at(idx)->isFile) ImGui::Text("%lld bytes", directoryContents.at(idx)->size); + else ImGui::Text(""); + + //ImGui::SetItemDefaultFocus(); + + } + //DISPLAYING ALTERNATIVE INFO + if (!idx) { + ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("Folder is empty"); + } + ImGui::EndTable(); + } + ImGui::EndTable(); + } + + + + //ImGui::TreePop(); + //BOTTOM ROW + ImGui::Checkbox("Show hidden", &showHidden); + ImGui::SameLine(); + ImGui::Checkbox("Filter by .exe", &filterByExtension); + ImGui::SameLine(); + + ImGui::SameLine(); + ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - (ImGui::CalcTextSize("Select").x + ImGui::GetStyle().ItemSpacing.x * 2) ); + + ImGui::BeginDisabled(); + WideCharToMultiByte(CP_UTF8, NULL, chosenPath, -1, chosenPathUTF8, + 4 * MAX_PATH, NULL, NULL); + ImGui::InputText("##chosenbar", chosenPathUTF8, IM_ARRAYSIZE(chosenPathUTF8), ImGuiInputTextFlags_EnterReturnsTrue ); + ImGui::EndDisabled(); + + ImGui::SameLine(); + if(ImGui::Button("Select")) { + log_directory(chosenPath << " TRIED TO RETURN"); + //ImGui::End(); + exitWindow(userPath, windowOpen, memoryFreed, ExitFlags::SELECTED); + } + //listFlags = handleFolderAccessResult(listFlags, addrBarVal, &showError, error, ErrorMessages::addrBarError, history, currentPath, addrBarVal); + + ImGui::End(); +} + + +} + + diff --git a/main.cpp b/main.cpp deleted file mode 100644 index 03123db..0000000 --- a/main.cpp +++ /dev/null @@ -1,399 +0,0 @@ -// Dear ImGui: standalone example application for GLFW + OpenGL 3, using programmable pipeline -// (GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan/Metal graphics context creation, etc.) -// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. -// Read online: https://github.com/ocornut/imgui/tree/master/docs - -#define IMGUI_IMPLEMENTATION -#define GL_SILENCE_DEPRECATION -#include "imgui/misc/single_file/imgui_single_file.h" -#include -#include -#include -#include -#include - -// [Win32] Our example includes a copy of glfw3.lib pre-compiled with VS2010 to maximize ease of testing and compatibility with old VS compilers. -// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma. -// Your own project should not be affected, as you are likely to link with a newer binary of GLFW that is adequate for your version of Visual Studio. -#if defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) -#pragma comment(lib, "legacy_stdio_definitions") -#endif -static void glfw_error_callback(int error, const char* description) -{ - fprintf(stderr, "Glfw Error %d: %s\n", error, description); -} - -bool debug = true; - -typedef struct { - std::vector size; - std::vector name; -} directoriesInfo, volumesInfo; - -//TODO UNICORDEO -/* FILE PICKER MOMENTO */ - -/* DIRECTORIES */ - - -bool retrieveCurrentDirectory(char** currentPath){ - if(GetCurrentDirectory(MAX_PATH, *currentPath)) return true; - return false; -} - -bool moveDirectory(char** currentPath){ - if(SetCurrentDirectory(*currentPath)) return true; - return false; -} - -int listDirectory(std::string path, std::vector *directoryContents){ - HANDLE hFind = INVALID_HANDLE_VALUE; - WIN32_FIND_DATA ffd; - LARGE_INTEGER filesize; - int numFiles = 0; - - if (path.length() > (MAX_PATH - 3)) return -1; - path = path + "\\*"; - hFind = FindFirstFile(path.c_str(), &ffd); - if (INVALID_HANDLE_VALUE == hFind) return -2; - do { - char* itemPath; - if (directoryContents->size() <= numFiles){ - itemPath = (char*)calloc(1, MAX_PATH * sizeof(WCHAR)); - directoryContents->push_back(itemPath); - } else { - itemPath = directoryContents->at(numFiles); - } - - uint64_t idx = 0; - do { - itemPath[idx] = ffd.cFileName[idx]; - idx++; - } while (ffd.cFileName[idx]); - - if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - //strcat(itemPath, " "); - } else { - // filesize.QuadPart = ((ffd.nFileSizeHigh * (MAXDWORD+1)) + ffd.nFileSizeLow); - // char buf[16]; buf[0] = ' '; - // itoa(filesize.QuadPart, buf + 1 , 10 ); - // strcat(itemPath, buf); - } - - numFiles++; - } while (FindNextFile(hFind, &ffd) != 0); - FindClose(hFind); - return numFiles; -} - -/* VOLUMES */ - - -//new char*[CharCount * sizeof(WCHAR) -/*idea, si quisiera que empezase en punto X del string - coger el param opcional y crear un puntero a la posicion X del array para empezar desde ahi - int explodePaths(TCHAR* volumePaths, int volumePathLength, int volumePathBufferSize, - char separator, std::vector *dest, , int startingFrom = 0); - if (nextOcurrence == NULL) return 0; -*/ - -int explodePaths(TCHAR* volumePaths, int volumePathsBufferSize, char separator, std::vector *dest){ - char* nextOcurrence = strchr(volumePaths, separator); - if (nextOcurrence[0] == nextOcurrence[sizeof(TCHAR)]) return 0; - - char* itemPath; - itemPath = (char*)calloc(1, volumePathsBufferSize); - for (int i = 0; &volumePaths[i] == nextOcurrence; i++) { - itemPath[i] = volumePaths[i]; - } - dest->push_back(itemPath); - - - return explodePaths(nextOcurrence, volumePathsBufferSize, separator, dest); -} - - -int listVolumes(std::vector *onPresentPaths){ -//int listVolumes(){ - HANDLE hFind = INVALID_HANDLE_VALUE; - char separator = '\0'; - - int numVolumes = 0; - //Volume name - TCHAR volumeName[MAX_PATH]; - int volumeNameSize = sizeof volumeName / sizeof volumeName[0]; - //Paths - int volumePathsBufferSize = (MAX_PATH + 1) * sizeof(TCHAR); - unsigned long volumePathLength; - TCHAR volumePaths[volumePathsBufferSize]; - - - hFind = FindFirstVolume(volumeName, volumeNameSize); - //if (debug) std::cout << volumeNameSize << std::endl; - if (INVALID_HANDLE_VALUE == hFind) return -2; - do { - //if (debug) std::cout << volumeName << std::endl; - - if(GetVolumePathNamesForVolumeName(volumeName, volumePaths, volumePathsBufferSize, &volumePathLength)){ - - if (volumePathLength == 1) { if (debug) std::cout << "Skill Issue" << std::endl; continue; } - if (debug) std::cout << volumeName; - if (debug) { - if(explodePaths(volumePaths, volumePathsBufferSize, separator, onPresentPaths)){ - if (debug) std::cout << volumePaths << std::endl; - for (int i = 0; i < onPresentPaths->size(); i++){ - std::cout << onPresentPaths->at(i) << std::endl; - } - } - //std::cout << volumePaths << std::endl; - } - if (debug) std::cout << std::to_string(volumePathLength) + " " ; - if (debug) std::cout << "THE END" << std::endl; - - }else{ - if (debug) std::cout << "cagaste" << std::endl; - } - - numVolumes++; - - } while (FindNextVolume(hFind, volumeName, volumeNameSize) != 0); - - FindVolumeClose(hFind); - return numVolumes; -} - -/* FIN FILE PICKER MOMENTO */ - - - -int main(int, char**) -{ - // Setup window - glfwSetErrorCallback(glfw_error_callback); - if (!glfwInit()) - return 1; - - // Decide GL+GLSL versions -#if defined(IMGUI_IMPL_OPENGL_ES2) - // GL ES 2.0 + GLSL 100 - const char* glsl_version = "#version 100"; - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); - glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); -#elif defined(__APPLE__) - // GL 3.2 + GLSL 150 - const char* glsl_version = "#version 150"; - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac -#else - // GL 3.0 + GLSL 130 - const char* glsl_version = "#version 130"; - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); - //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only - //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 3.0+ only -#endif - - // Create window with graphics context - GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+OpenGL3 example", NULL, NULL); - if (window == NULL) - return 1; - glfwMakeContextCurrent(window); - glfwSwapInterval(1); // Enable vsync - - // Setup Dear ImGui context - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); (void)io; - //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls - //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls - - // Setup Dear ImGui style - ImGui::StyleColorsDark(); - //ImGui::StyleColorsLight(); - - // Setup Platform/Renderer backends - ImGui_ImplGlfw_InitForOpenGL(window, true); - ImGui_ImplOpenGL3_Init(glsl_version); - - // Load Fonts - // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. - // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. - // - Read 'docs/FONTS.md' for more instructions and details. - // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); - //IM_ASSERT(font != NULL); - - // Our state - bool show_demo_window = true; - bool show_another_window = false; - ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); - - // Main loop - while (!glfwWindowShouldClose(window)) { - // Poll and handle events (inputs, window resize, etc.) - // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. - // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. - // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. - // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. - glfwPollEvents(); - - // Start the Dear ImGui frame - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). - if (show_demo_window) - ImGui::ShowDemoWindow(&show_demo_window); - - // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window. - { - static float f = 0.0f; - static int counter = 0; - - ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. - - ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) - ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state - ImGui::Checkbox("Another Window", &show_another_window); - - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f - ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color - - if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) - counter++; - ImGui::SameLine(); - ImGui::Text("counter = %d", counter); - - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGui::End(); - } - - { - ImGui::Begin("File Picker in 4K"); - //TODO test listar volumenes - static bool isListVolumesAdequate = true; - if (debug && isListVolumesAdequate) { - isListVolumesAdequate = false; - std::cout << isListVolumesAdequate << std::endl; - std::vector onPresentPaths; - listVolumes(&onPresentPaths); - } - // - - static bool renderListbox = true; - //cursed C momento: necesario ptr en otra var para mandar a char** de firma - static char currentPath[MAX_PATH]; - static char* ptr = ¤tPath[0]; - - static int currentItemIdx = -1; - static std::vector displayContents; - std::vector directoryContents; - static int numFiles = 0; - - if (debug) ImGui::Text("%s primir", currentPath); - - if(renderListbox) { - if (debug) std::cout << "renderiso" << std::endl; - renderListbox = false; - if(!retrieveCurrentDirectory(&ptr)) { - if (debug) std::cout << "pencaste"; - goto filepickerFailure; - } - // - numFiles = (listDirectory(std::string(currentPath), &directoryContents)); - //std::cout << numFiles; - if (numFiles < 0) { - if (debug) std::cout << "pencaste 2 el repencazo"; - goto filepickerFailure; - } - displayContents = std::move(directoryContents); - } - - if(numFiles > 0){ - ImGui::Text("Select a file:"); - if (debug) ImGui::Text("%s %d", currentPath, currentItemIdx); - if (ImGui::BeginListBox("fpLb", ImVec2(-FLT_MIN, 25 * ImGui::GetTextLineHeightWithSpacing()))){ - for (int i = 0; i < numFiles; i++) { - - const bool isSelected = (currentItemIdx == i); - if (ImGui::Selectable(displayContents.at(i), isSelected)) - currentItemIdx = i; - - if (isSelected) { - strcat(currentPath, "\\"); - strcat(currentPath, displayContents.at(i)); - moveDirectory(&ptr); - currentItemIdx = -1; - renderListbox = true; - } - //ImGui::SetItemDefaultFocus(); - - } - ImGui::EndListBox(); - } - } else { - ImGui::Text("cagaste"); - } - //ImGui::TreePop(); - filepickerFailure: - ImGui::End(); - - } - - - // 3. Show another simple window. - if (show_another_window) - { - ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) - ImGui::Text("Hello from another window!"); - if (ImGui::Button("Close Me")) - show_another_window = false; - ImGui::End(); - } - - // Rendering - ImGui::Render(); - int display_w, display_h; - glfwGetFramebufferSize(window, &display_w, &display_h); - glViewport(0, 0, display_w, display_h); - glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); - glClear(GL_COLOR_BUFFER_BIT); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - - glfwSwapBuffers(window); - } - - - - - - - - - - - - - - // Cleanup - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplGlfw_Shutdown(); - ImGui::DestroyContext(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -}