diff --git a/examples/custom_file_dialog/custom_file_dialog.c b/examples/custom_file_dialog/custom_file_dialog.c index 9a801b0..7e3ea58 100644 --- a/examples/custom_file_dialog/custom_file_dialog.c +++ b/examples/custom_file_dialog/custom_file_dialog.c @@ -35,17 +35,17 @@ int main() //--------------------------------------------------------------------------------------- int screenWidth = 800; int screenHeight = 560; - + InitWindow(screenWidth, screenHeight, "raygui - custom modal dialog"); SetExitKey(0); // Custom file dialog - GuiFileDialogState fileDialogState = InitGuiFileDialog(); + GuiFileDialogState fileDialogState = InitGuiFileDialog(420, 310, GetWorkingDirectory(), false); bool exitWindow = false; char fileNameToLoad[512] = { 0 }; - + Texture texture = { 0 }; SetTargetFPS(60); @@ -57,7 +57,7 @@ int main() // Update //---------------------------------------------------------------------------------- exitWindow = WindowShouldClose(); - + if (fileDialogState.SelectFilePressed) { // Load image file (if supported extension) @@ -67,7 +67,7 @@ int main() UnloadTexture(texture); texture = LoadTexture(fileNameToLoad); } - + fileDialogState.SelectFilePressed = false; } //---------------------------------------------------------------------------------- @@ -77,20 +77,20 @@ int main() BeginDrawing(); ClearBackground(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); - + DrawTexture(texture, GetScreenWidth()/2 - texture.width/2, GetScreenHeight()/2 - texture.height/2 - 5, WHITE); DrawRectangleLines(GetScreenWidth()/2 - texture.width/2, GetScreenHeight()/2 - texture.height/2 - 5, texture.width, texture.height, BLACK); - + DrawText(fileNameToLoad, 208, GetScreenHeight() - 20, 10, GRAY); - + // raygui: controls drawing //---------------------------------------------------------------------------------- if (fileDialogState.fileDialogActive) GuiLock(); if (GuiButton((Rectangle){ 20, 20, 140, 30 }, GuiIconText(RICON_FILE_OPEN, "Open Image"))) fileDialogState.fileDialogActive = true; - + GuiUnlock(); - + // GUI: Dialog Window //-------------------------------------------------------------------------------- GuiFileDialog(&fileDialogState); diff --git a/examples/custom_file_dialog/gui_file_dialog.h b/examples/custom_file_dialog/gui_file_dialog.h index 26e8ce6..ebb0c04 100644 --- a/examples/custom_file_dialog/gui_file_dialog.h +++ b/examples/custom_file_dialog/gui_file_dialog.h @@ -1,6 +1,6 @@ /******************************************************************************************* * -* FileDialog v1.0.0 - Modal file dialog to open/save files +* FileDialog v1.1 - Modal file dialog to open/save files * * MODULE USAGE: * #define GUI_FILE_DIALOG_IMPLEMENTATION @@ -16,13 +16,24 @@ * - DirectoryExists() * - FileExists() * -* LICENSE: Propietary License +* LICENSE: zlib/libpng * -* Copyright (c) 2019 raylib technologies (@raylibtech). All Rights Reserved. +* Copyright (c) 2019-2020 Ramon Santamaria (@raysan5) * -* Unauthorized copying of this file, via any medium is strictly prohibited -* This project is proprietary and confidential unless the owner allows -* usage in any other form by expresely written permission. +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. * **********************************************************************************************/ @@ -37,21 +48,23 @@ typedef struct { Vector2 position; - + Vector2 size; + bool fileDialogActive; - + bool dirPathEditMode; char dirPathText[256]; - + int filesListScrollIndex; bool filesListEditMode; int filesListActive; - + bool fileNameEditMode; char fileNameText[256]; bool SelectFilePressed; bool CancelFilePressed; int fileTypeActive; + int itemFocused; // Custom state variables (depend on development software) // NOTE: This variables should be added manually if required @@ -59,10 +72,10 @@ typedef struct { int dirFilesCount; char filterExt[256]; - + char dirPathTextCopy[256]; char fileNameTextCopy[256]; - + int prevFilesListActive; } GuiFileDialogState; @@ -89,7 +102,7 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- -GuiFileDialogState InitGuiFileDialog(void); +GuiFileDialogState InitGuiFileDialog(int width, int height, const char *initPath, bool active); void GuiFileDialog(GuiFileDialogState *state); #ifdef __cplusplus @@ -128,12 +141,15 @@ typedef struct FileInfo { int type; int icon; } FileInfo; +#else +// Filename only +typedef char *FileInfo; #endif //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -char **dirFilesIcon = NULL; +FileInfo *dirFilesIcon = NULL; //---------------------------------------------------------------------------------- // Internal Module Functions Definition @@ -143,25 +159,28 @@ static char **ReadDirectoryFiles(const char *dir, int *filesCount, char *filterE #if defined(USE_CUSTOM_LISTVIEW_FILEINFO) // List View control for files info with extended parameters -static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count, int *focus, int *scrollIndex, int active) +static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count, int *focus, int *scrollIndex, int active); #endif //---------------------------------------------------------------------------------- // Module Functions Definition //---------------------------------------------------------------------------------- -GuiFileDialogState InitGuiFileDialog(void) +GuiFileDialogState InitGuiFileDialog(int width, int height, const char *initPath, bool active) { GuiFileDialogState state = { 0 }; - state.position = (Vector2){ GetScreenWidth()/2 - 480/2, GetScreenHeight()/2 - 305/2 }; - - state.fileDialogActive = false; + // Default dialog size is 440x310 + state.size.x = width == -1 ? 440 : width; + state.size.y = height == -1 ? 310 : height; + state.position = (Vector2){ GetScreenWidth()/2 - state.size.x/2, GetScreenHeight()/2 - state.size.y/2 }; + + state.fileDialogActive = active; state.dirPathEditMode = false; - + state.filesListActive = -1; state.prevFilesListActive = state.filesListActive; state.filesListScrollIndex = 0; - + state.fileNameEditMode = false; state.SelectFilePressed = false; @@ -169,58 +188,91 @@ GuiFileDialogState InitGuiFileDialog(void) state.fileTypeActive = 0; + strcpy(state.fileNameText, "\0"); + // Custom variables initialization - strcpy(state.dirPathText, GetWorkingDirectory()); + if (initPath && DirectoryExists(initPath)) + { + strcpy(state.dirPathText, initPath); + } + else if (initPath && FileExists(initPath)) + { + strcpy(state.dirPathText, GetDirectoryPath(initPath)); + strcpy(state.fileNameText, GetFileName(initPath)); + } + else strcpy(state.dirPathText, GetWorkingDirectory()); + strcpy(state.dirPathTextCopy, state.dirPathText); - + strcpy(state.fileNameTextCopy, state.fileNameText); + strcpy(state.filterExt, "all"); state.dirFilesCount = 0; state.dirFiles = NULL; // NOTE: Loaded lazily on window active - - strcpy(state.fileNameText, "\0"); - strcpy(state.fileNameTextCopy, state.fileNameText); return state; } +// Read files in new path +static void FD_RELOAD_DIRPATH(GuiFileDialogState *state) +{ + for (int i = 0; i < state->dirFilesCount; i++) RL_FREE(state->dirFiles[i]); + RL_FREE(state->dirFiles); + + state->dirFiles = ReadDirectoryFiles(state->dirPathText, &state->dirFilesCount, state->filterExt); + state->itemFocused = 0; +} + +// Update and draw file dialog void GuiFileDialog(GuiFileDialogState *state) -{ +{ if (state->fileDialogActive) { + const int winWidth = state->size.x; + const int winHeight = state->size.y; + // Load dirFilesIcon and state->dirFiles lazily on windows open // NOTE: they are automatically unloaded at fileDialog closing //------------------------------------------------------------------------------------ if (dirFilesIcon == NULL) { - dirFilesIcon = (char **)RL_MALLOC(MAX_DIRECTORY_FILES*sizeof(char *)); // Max files to read + dirFilesIcon = (FileInfo *)RL_MALLOC(MAX_DIRECTORY_FILES*sizeof(FileInfo)); // Max files to read for (int i = 0; i < MAX_DIRECTORY_FILES; i++) dirFilesIcon[i] = (char *)calloc(MAX_DIR_PATH_LENGTH, 1); // Max file name length } - - if (state->dirFiles == NULL) state->dirFiles = ReadDirectoryFiles(state->dirPathText, &state->dirFilesCount, state->filterExt); + + if (state->dirFiles == NULL) + { + state->dirFiles = ReadDirectoryFiles(state->dirPathText, &state->dirFilesCount, state->filterExt); + + for(int f = 0; f < state->dirFilesCount; f++) + { + if (strcmp(state->fileNameText, state->dirFiles[f]) == 0) + { + if (state->filesListActive != f) state->filesListScrollIndex = state->filesListActive = f; // make it active and visible only on first call + + break; + } + } + } //------------------------------------------------------------------------------------ DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)), 0.85f)); - state->fileDialogActive = !GuiWindowBox((Rectangle){ state->position.x + 0, state->position.y + 0, 480, 310 }, "#198#Select File Dialog"); - - if (GuiButton((Rectangle){ state->position.x + 430, state->position.y + 35, 40, 25 }, "< ..")) + state->fileDialogActive = !GuiWindowBox((Rectangle){ state->position.x + 0, state->position.y + 0, winWidth, winHeight }, "#198#LuaJIT | Select File Dialog"); + + if (GuiButton((Rectangle){ state->position.x + winWidth - 50, state->position.y + 35, 40, 25 }, "< .."))// || IsKeyReleased(KEY_DPAD_Y)) { // Move dir path one level up strcpy(state->dirPathText, GetPrevDirectoryPath(state->dirPathText)); - + // RL_FREE previous dirFiles (reloaded by ReadDirectoryFiles()) - for (int i = 0; i < state->dirFilesCount; i++) RL_FREE(state->dirFiles[i]); - RL_FREE(state->dirFiles); - - // Read files in the new path - state->dirFiles = ReadDirectoryFiles(state->dirPathText, &state->dirFilesCount, state->filterExt); - + FD_RELOAD_DIRPATH(state); + state->filesListActive = -1; strcpy(state->fileNameText, "\0"); strcpy(state->fileNameTextCopy, state->fileNameText); } - - if (GuiTextBox((Rectangle){ state->position.x + 10, state->position.y + 35, 410, 25 }, state->dirPathText, 256, state->dirPathEditMode)) + + if (GuiTextBox((Rectangle){ state->position.x + 10, state->position.y + 35, winWidth - 65, 25 }, state->dirPathText, 256, state->dirPathEditMode)) { if (state->dirPathEditMode) { @@ -228,51 +280,48 @@ void GuiFileDialog(GuiFileDialogState *state) if (DirectoryExists(state->dirPathText)) { // RL_FREE previous dirFiles (reloaded by ReadDirectoryFiles()) - for (int i = 0; i < state->dirFilesCount; i++) RL_FREE(state->dirFiles[i]); - RL_FREE(state->dirFiles); - - // Read files in new path - state->dirFiles = ReadDirectoryFiles(state->dirPathText, &state->dirFilesCount, state->filterExt); - + FD_RELOAD_DIRPATH(state); + strcpy(state->dirPathTextCopy, state->dirPathText); } else strcpy(state->dirPathText, state->dirPathTextCopy); } - + state->dirPathEditMode = !state->dirPathEditMode; } - + int prevTextAlignment = GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT); int prevElementsHeight = GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT); GuiSetStyle(LISTVIEW, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT); GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 24); - + // TODO: ListViewElements should be aligned left - state->filesListActive = GuiListViewEx((Rectangle){ state->position.x + 10, state->position.y + 70, 460, 164 }, (const char **)dirFilesIcon, state->dirFilesCount, NULL, &state->filesListScrollIndex, state->filesListActive); - +# if defined(USE_CUSTOM_LISTVIEW_FILEINFO) + FileInfo fileInfo; + state->filesListActive = GuiListViewFiles((Rectangle){ state->position.x + 10, state->position.y + 70, winWidth - 20, winHeight - 135 }, fileInfo, state->dirFilesCount, &state->itemFocused, &state->filesListScrollIndex, state->filesListActive); +# else + state->filesListActive = GuiListViewEx((Rectangle){ state->position.x + 10, state->position.y + 70, winWidth - 20, winHeight - 135 }, (const char**)dirFilesIcon, state->dirFilesCount, &state->itemFocused, &state->filesListScrollIndex, state->filesListActive); +# endif GuiSetStyle(LISTVIEW, TEXT_ALIGNMENT, prevTextAlignment); GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, prevElementsHeight); - + if ((state->filesListActive >= 0) && (state->filesListActive != state->prevFilesListActive)) + //&& (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_DPAD_A))) { strcpy(state->fileNameText, state->dirFiles[state->filesListActive]); - if (DirectoryExists(TextFormat("%s\\%s", state->dirPathText, state->fileNameText))) + if (DirectoryExists(TextFormat("%s/%s", state->dirPathText, state->fileNameText))) { if (TextIsEqual(state->fileNameText, "..")) strcpy(state->dirPathText, GetPrevDirectoryPath(state->dirPathText)); - else strcpy(state->dirPathText, TextFormat("%s\\%s", state->dirPathText, state->fileNameText)); - + else strcpy(state->dirPathText, TextFormat("%s/%s", strcmp(state->dirPathText, "/")==0 ? "" : state->dirPathText, state->fileNameText)); + strcpy(state->dirPathTextCopy, state->dirPathText); - + // RL_FREE previous dirFiles (reloaded by ReadDirectoryFiles()) - for (int i = 0; i < state->dirFilesCount; i++) RL_FREE(state->dirFiles[i]); - RL_FREE(state->dirFiles); - - // Read files in new path - state->dirFiles = ReadDirectoryFiles(state->dirPathText, &state->dirFilesCount, state->filterExt); - + FD_RELOAD_DIRPATH(state); + strcpy(state->dirPathTextCopy, state->dirPathText); - + state->filesListActive = -1; strcpy(state->fileNameText, "\0"); strcpy(state->fileNameTextCopy, state->fileNameText); @@ -280,12 +329,12 @@ void GuiFileDialog(GuiFileDialogState *state) state->prevFilesListActive = state->filesListActive; } - - GuiLabel((Rectangle){ state->position.x + 10, state->position.y + 245, 68, 25 }, "File name:"); - - if (GuiTextBox((Rectangle){ state->position.x + 75, state->position.y + 245, 275, 25 }, state->fileNameText, 128, state->fileNameEditMode)) + + GuiLabel((Rectangle){ state->position.x + 10, state->position.y + winHeight - 60, 68, 25 }, "File name:"); + + if (GuiTextBox((Rectangle){ state->position.x + 75, state->position.y + winHeight - 60, winWidth - 200, 25 }, state->fileNameText, 128, state->fileNameEditMode)) { - if (state->fileNameText) + if (*state->fileNameText) { // Verify if a valid filename has been introduced if (FileExists(TextFormat("%s/%s", state->dirPathText, state->fileNameText))) @@ -301,37 +350,45 @@ void GuiFileDialog(GuiFileDialogState *state) } } } - else + else { strcpy(state->fileNameText, state->fileNameTextCopy); } } - + state->fileNameEditMode = !state->fileNameEditMode; } - state->fileTypeActive = GuiComboBox((Rectangle){ state->position.x + 75, state->position.y + 275, 275, 25 }, "All files", state->fileTypeActive); - GuiLabel((Rectangle){ state->position.x + 10, state->position.y + 275, 68, 25 }, "File filter:"); - - state->SelectFilePressed = GuiButton((Rectangle){ state->position.x + 360, state->position.y + 245, 110, 25 }, "Select"); - + state->fileTypeActive = GuiComboBox((Rectangle){ state->position.x + 75, state->position.y + winHeight - 30, winWidth - 200, 25 }, "All files", state->fileTypeActive); + GuiLabel((Rectangle){ state->position.x + 10, state->position.y + winHeight - 30, 68, 25 }, "File filter:"); + + state->SelectFilePressed = GuiButton((Rectangle){ state->position.x + winWidth - 120, state->position.y + winHeight - 60, 110, +#ifdef PLATFORM_DESKTOP + 25 +#else + 25+30 +#endif + }, "Select");// || IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_DPAD_A); + if (state->SelectFilePressed) state->fileDialogActive = false; - - if (GuiButton((Rectangle){ state->position.x + 360, state->position.y + 275, 110, 25 }, "Cancel")) state->fileDialogActive = false; + +#ifdef PLATFORM_DESKTOP + if (GuiButton((Rectangle){ state->position.x + winWidth - 120, state->position.y + winHeight - 30, 110, 25 }, "Quit")) state->fileDialogActive = false; +#endif // File dialog has been closed! if (!state->fileDialogActive) { // RL_FREE dirFiles memory - for (int i = 0; i < state->dirFilesCount; i++) + for (int i = 0; i < state->dirFilesCount; i++) { RL_FREE(state->dirFiles[i]); RL_FREE(dirFilesIcon[i]); } - + RL_FREE(state->dirFiles); RL_FREE(dirFilesIcon); - + dirFilesIcon = NULL; state->dirFiles = NULL; } @@ -339,35 +396,81 @@ void GuiFileDialog(GuiFileDialogState *state) } // Read all filenames from directory (supported file types) +static inline int _file_comp(const char *d1, const char *d2, const char *dir) +{ + const bool b1 = DirectoryExists(TextFormat("%s/%s", dir, d1)); + const bool b2 = DirectoryExists(TextFormat("%s/%s", dir, d2)); + + if (b1 && !b2) return -1; + if (!b1 && b2) return 1; + + if (!FileExists(TextFormat("%s/%s", dir, d1))) return 1; + if (!FileExists(TextFormat("%s/%s", dir, d2))) return -1; + + return strcmp(d1, d2); +} static char **ReadDirectoryFiles(const char *dir, int *filesCount, char *filterExt) { int validFilesCount = 0; char **validFiles = (char **)RL_MALLOC(MAX_DIRECTORY_FILES*sizeof(char *)); // Max files to read for (int i = 0; i < MAX_DIRECTORY_FILES; i++) validFiles[i] = (char *)RL_MALLOC(MAX_DIR_PATH_LENGTH); // Max file name length - + int filterExtCount = 0; const char **extensions = GuiTextSplit(filterExt, &filterExtCount, NULL); bool filterExtensions = true; - + int dirFilesCount = 0; char **files = GetDirectoryFiles(dir, &dirFilesCount); - + + // Sort files and directories: dir by name + files by name + // https://en.wikibooks.org/wiki/Algorithm_Implementation/Sorting/Quicksort#C + if (dirFilesCount > 1) + { + const int MAX = 64; + unsigned int left = 0, stack[MAX], pos = 0, seed = rand(), len = dirFilesCount; + + for ( ; ; ) + { + for (; left+1 < len; len++) /* sort left to len-1 */ + { + if (pos == MAX) len = stack[pos = 0]; /* stack overflow, reset */ + char *pivot = files[left+seed%(len-left)]; /* pick random pivot */ + seed = seed*69069+1; /* next pseudorandom number */ + stack[pos++] = len; /* sort right part later */ + + for (unsigned int right = left-1; ; ) /* inner loop: partitioning */ + { + while (_file_comp(files[++right], pivot, dir) < 0);/* look for greater element */ + while (_file_comp(pivot, files[--len], dir) < 0); /* look for smaller element */ + if (right >= len) break; /* partition point found? */ + char *temp = files[right]; + files[right] = files[len]; /* the only swap */ + files[len] = temp; + } /* partitioned, continue left part */ + } + + if (pos == 0) break; /* stack empty? */ + left = len; /* left to right is sorted */ + len = stack[--pos]; /* get next range to sort */ + } + } + if (TextIsEqual(extensions[0], "all")) filterExtensions = false; for (int i = 0; (i < dirFilesCount) && (validFilesCount < MAX_DIRECTORY_FILES); i++) { if (TextIsEqual(files[i], ".")) continue; - + if (!filterExtensions) { - strcpy(validFiles[validFilesCount], files[i]); - + strncpy(validFiles[validFilesCount], files[i], MAX_DIR_PATH_LENGTH); + // Only filter files by extensions, directories should be available - if (DirectoryExists(TextFormat("%s\\%s", dir, files[i]))) strcpy(dirFilesIcon[validFilesCount], TextFormat("#%i#%s", 1, files[i])); - else + if (DirectoryExists(TextFormat("%s/%s", dir, files[i]))) strcpy(dirFilesIcon[validFilesCount], TextFormat("#%i#%s", 1, files[i])); + else { // TODO: Assign custom filetype icons depending on file extension (image, audio, text, video, models...) - + if (IsFileExtension(files[i], ".png")) strcpy(dirFilesIcon[validFilesCount], TextFormat("#%i#%s", 12, files[i])); else strcpy(dirFilesIcon[validFilesCount], TextFormat("#%i#%s", 10, files[i])); } @@ -386,17 +489,15 @@ static char **ReadDirectoryFiles(const char *dir, int *filesCount, char *filterE if (IsFileExtension(files[i], ".png")) strcpy(dirFilesIcon[validFilesCount], TextFormat("#%i#%s", 12, files[i])); else strcpy(dirFilesIcon[validFilesCount], TextFormat("#%i#%s", 10, files[i])); - + validFilesCount++; } } } } - - // TODO: Sort files and directories: dir by name + files by name ClearDirectoryFiles(); - + *filesCount = validFilesCount; return validFiles; } @@ -408,23 +509,23 @@ static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count, int *f GuiControlState state = guiState; int itemFocused = (focus == NULL)? -1 : *focus; int itemSelected = active; - + // Check if we need a scroll bar bool useScrollBar = false; - if ((GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING))*count > bounds.height) useScrollBar = true; - + if ((GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING))*count > bounds.height) useScrollBar = true; + // Define base item rectangle [0] Rectangle itemBounds = { 0 }; - itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING); - itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); - itemBounds.width = bounds.width - 2*GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) - GuiGetStyle(DEFAULT, BORDER_WIDTH); - itemBounds.height = GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT); + itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING); + itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); + itemBounds.width = bounds.width - 2*GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) - GuiGetStyle(DEFAULT, BORDER_WIDTH); + itemBounds.height = GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT); if (useScrollBar) itemBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH); - + // Get items on the list - int visibleItems = bounds.height/(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)); + int visibleItems = bounds.height/(GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)); if (visibleItems > count) visibleItems = count; - + int startIndex = (scrollIndex == NULL)? 0 : *scrollIndex; if ((startIndex < 0) || (startIndex > (count - visibleItems))) startIndex = 0; int endIndex = startIndex + visibleItems; @@ -434,12 +535,12 @@ static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count, int *f if ((state != GUI_STATE_DISABLED) && !guiLocked) { Vector2 mousePoint = GetMousePosition(); - + // Check mouse inside list view if (CheckCollisionPointRec(mousePoint, bounds)) { state = GUI_STATE_FOCUSED; - + // Check focused and selected item for (int i = 0; i < visibleItems; i++) { @@ -449,16 +550,16 @@ static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count, int *f if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) itemSelected = startIndex + i; break; } - + // Update item rectangle y position for next item - itemBounds.y += (GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)); + itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)); } - + if (useScrollBar) { int wheelMove = GetMouseWheelMove(); startIndex -= wheelMove; - + if (startIndex < 0) startIndex = 0; else if (startIndex > (count - visibleItems)) startIndex = count - visibleItems; @@ -467,19 +568,19 @@ static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count, int *f } } else itemFocused = -1; - + // Reset item rectangle y to [0] - itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); + itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); } //-------------------------------------------------------------------- - + // Draw control //-------------------------------------------------------------------- DrawRectangleRec(bounds, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), guiAlpha)); // TODO: Draw list view header with file sections: icon+name | size | type | modTime - + // Draw visible items for (int i = 0; i < visibleItems; i++) { @@ -490,9 +591,9 @@ static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count, int *f DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)), guiAlpha)); DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), guiAlpha)); } - - // TODO: Draw full file info line: icon+name | size | type | modTime - + + // TODO: Draw full file info line: icon+name | size | type | modTime + GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED)), guiAlpha)); } else @@ -502,7 +603,7 @@ static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count, int *f // Draw item selected DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)), guiAlpha)); DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), guiAlpha)); - + GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)), guiAlpha)); } else if ((startIndex + i) == itemFocused) @@ -510,7 +611,7 @@ static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count, int *f // Draw item focused DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)), guiAlpha)); DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), guiAlpha)); - + GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)), guiAlpha)); } else @@ -521,36 +622,36 @@ static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count, int *f } // Update item rectangle y position for next item - itemBounds.y += (GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)); + itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)); } if (useScrollBar) { - Rectangle scrollBarBounds = { - bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), - bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), - bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) + Rectangle scrollBarBounds = { + bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), + bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), + bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) }; // Calculate percentage of visible items and apply same percentage to scrollbar float percentVisible = (float)(endIndex - startIndex)/count; float sliderSize = bounds.height*percentVisible; - int prevSliderSize = GuiGetStyle(SCROLLBAR, SLIDER_SIZE); // Save default slider size + int prevSliderSize = GuiGetStyle(SCROLLBAR, SLIDER_WIDTH); // Save default slider size int prevScrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed - GuiSetStyle(SCROLLBAR, SLIDER_SIZE, sliderSize); // Change slider size + GuiSetStyle(SCROLLBAR, SLIDER_WIDTH, sliderSize); // Change slider size GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleItems); // Change scroll speed startIndex = GuiScrollBar(scrollBarBounds, startIndex, 0, count - visibleItems); GuiSetStyle(SCROLLBAR, SCROLL_SPEED, prevScrollSpeed); // Reset scroll speed to default - GuiSetStyle(SCROLLBAR, SLIDER_SIZE, prevSliderSize); // Reset slider size to default + GuiSetStyle(SCROLLBAR, SLIDER_WIDTH, prevSliderSize); // Reset slider size to default } //-------------------------------------------------------------------- - + if (focus != NULL) *focus = itemFocused; if (scrollIndex != NULL) *scrollIndex = startIndex; - + return itemSelected; } #endif // USE_CUSTOM_LISTVIEW_FILEINFO