Compare commits

...
Sign in to create a new pull request.

15 commits

6 changed files with 1050 additions and 400 deletions

2
.gitignore vendored
View file

@ -1,2 +1,4 @@
*.ini *.ini
*.exe *.exe
*.rdbg
*.pdb

69
README.md Normal file
View file

@ -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.

143
demo/main.cpp Normal file
View file

@ -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;
}

16
demo/unityBuild.h Normal file
View file

@ -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

819
filepicker.hpp Normal file
View file

@ -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 <iostream>
#include <vector>
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#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<wchar_t*> previousPaths;
std::vector<char*> 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<wchar_t*> onPresentPaths;
std::vector<char*> 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 = &currentPath[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<directoriesInfo*> 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<std::wstring> 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<directoriesInfo*> *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<wchar_t*> *dest, , int startingFrom = 0);
if (nextOcurrence == NULL) return 0;
*/
int explodePaths(wchar_t* volumePaths, int volumePathsBufferSize, wchar_t separator, std::vector<wchar_t*> *dest, std::vector<char*> *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<wchar_t*> *onPresentPaths, std::vector<char*> *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<std::wstring> *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();
}
}

399
main.cpp
View file

@ -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 <iostream>
#include <vector>
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
// [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<uint64_t> size;
std::vector<char*> 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<char*> *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, " <DIR>");
} 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<char*> *dest, , int startingFrom = 0);
if (nextOcurrence == NULL) return 0;
*/
int explodePaths(TCHAR* volumePaths, int volumePathsBufferSize, char separator, std::vector<char*> *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<char*> *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<char*> 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 = &currentPath[0];
static int currentItemIdx = -1;
static std::vector<char*> displayContents;
std::vector<char*> 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;
}