build raylib and raygui manually

Fabien Freling 2023-10-15 23:05:24 +02:00 committed by Fabien Freling
parent ba3836fbfb
commit e21d3689e6
15 changed files with 91 additions and 6384 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build/

6
.gitmodules vendored Normal file
View File

@ -0,0 +1,6 @@
[submodule "3rd-party/raygui"]
path = 3rd-party/raygui
url = https://github.com/raysan5/raygui.git
[submodule "3rd-party/raylib"]
path = 3rd-party/raylib
url = https://github.com/raysan5/raylib.git

5
3rd-party/Tupfile vendored Normal file
View File

@ -0,0 +1,5 @@
BDIR := ../build/raygui
: raygui.c |> clang -c %f -o %o -I../build/raylib/include -Iraygui/src |> $(BDIR)/%B.o
: $(BDIR)/*.o |> ar crs %o %f |> $(BDIR)/libraygui.a

View File

@ -1,738 +0,0 @@
/*******************************************************************************************
*
* Window File Dialog v1.2 - Modal file dialog to open/save files
*
* MODULE USAGE:
* #define GUI_WINDOW_FILE_DIALOG_IMPLEMENTATION
* #include "gui_window_file_dialog.h"
*
* INIT: GuiWindowFileDialogState state = GuiInitWindowFileDialog();
* DRAW: GuiWindowFileDialog(&state);
*
* NOTE: This module depends on some raylib file system functions:
* - LoadDirectoryFiles()
* - UnloadDirectoryFiles()
* - GetWorkingDirectory()
* - DirectoryExists()
* - FileExists()
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2019-2023 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty.
*In no event will the authors be held liable for any damages arising from the
*use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
*including commercial applications, and to alter it and redistribute it freely,
*subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
*claim that you wrote the original software. If you use this software in a
*product, an acknowledgment in the product documentation would be appreciated
*but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not
*be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
*distribution.
*
**********************************************************************************************/
#include "raylib.h"
#ifndef GUI_WINDOW_FILE_DIALOG_H
#define GUI_WINDOW_FILE_DIALOG_H
// Gui file dialog context data
typedef struct {
// Window management variables
bool windowActive;
Rectangle windowBounds;
Vector2 panOffset;
bool dragMode;
bool supportDrag;
// UI variables
bool dirPathEditMode;
char dirPathText[1024];
int filesListScrollIndex;
bool filesListEditMode;
int filesListActive;
bool fileNameEditMode;
char fileNameText[1024];
bool SelectFilePressed;
bool CancelFilePressed;
int fileTypeActive;
int itemFocused;
// Custom state variables
FilePathList dirFiles;
char filterExt[256];
char dirPathTextCopy[1024];
char fileNameTextCopy[1024];
int prevFilesListActive;
bool saveFileMode;
} GuiWindowFileDialogState;
#ifdef __cplusplus
extern "C" { // Prevents name mangling of functions
#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// ...
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
GuiWindowFileDialogState InitGuiWindowFileDialog(const char *initPath);
void GuiWindowFileDialog(GuiWindowFileDialogState *state);
#ifdef __cplusplus
}
#endif
#endif // GUI_WINDOW_FILE_DIALOG_H
/***********************************************************************************
*
* GUI_WINDOW_FILE_DIALOG IMPLEMENTATION
*
************************************************************************************/
#if defined(GUI_WINDOW_FILE_DIALOG_IMPLEMENTATION)
#include "raygui.h"
#include <string.h> // Required for: strcpy()
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define MAX_DIRECTORY_FILES 2048
#define MAX_ICON_PATH_LENGTH 512
#ifdef _WIN32
#define PATH_SEPERATOR "\\"
#else
#define PATH_SEPERATOR "/"
#endif
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
#if defined(USE_CUSTOM_LISTVIEW_FILEINFO)
// Detailed file info type
typedef struct FileInfo {
const char *name;
int size;
int modTime;
int type;
int icon;
} FileInfo;
#else
// Filename only
typedef char *FileInfo; // Files are just a path string
#endif
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
FileInfo *dirFilesIcon = NULL; // Path string + icon (for fancy drawing)
//----------------------------------------------------------------------------------
// Internal Module Functions Definition
//----------------------------------------------------------------------------------
// Read files in new path
static void ReloadDirectoryFiles(GuiWindowFileDialogState *state);
#if defined(USE_CUSTOM_LISTVIEW_FILEINFO)
// List View control for files info with extended parameters
static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count,
int *focus, int *scrollIndex, int active);
#endif
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
GuiWindowFileDialogState InitGuiWindowFileDialog(const char *initPath) {
GuiWindowFileDialogState state = {0};
// Init window data
state.windowBounds = (Rectangle){GetScreenWidth() / 2 - 440 / 2,
GetScreenHeight() / 2 - 310 / 2, 440, 310};
state.windowActive = false;
state.supportDrag = true;
state.dragMode = false;
state.panOffset = (Vector2){0, 0};
// Init path data
state.dirPathEditMode = false;
state.filesListActive = -1;
state.prevFilesListActive = state.filesListActive;
state.filesListScrollIndex = 0;
state.fileNameEditMode = false;
state.SelectFilePressed = false;
state.CancelFilePressed = false;
state.fileTypeActive = 0;
strcpy(state.fileNameText, "\0");
// Custom variables initialization
if (initPath && DirectoryExists(initPath)) {
strcpy(state.dirPathText, initPath);
} else if (initPath && FileExists(initPath)) {
strcpy(state.dirPathText, GetDirectoryPath(initPath));
strcpy(state.fileNameText, GetFileName(initPath));
} else
strcpy(state.dirPathText, GetWorkingDirectory());
// TODO: Why we keep a copy?
strcpy(state.dirPathTextCopy, state.dirPathText);
strcpy(state.fileNameTextCopy, state.fileNameText);
state.filterExt[0] = '\0';
// strcpy(state.filterExt, "all");
state.dirFiles.count = 0;
return state;
}
// Update and draw file dialog
void GuiWindowFileDialog(GuiWindowFileDialogState *state) {
if (state->windowActive) {
// Update window dragging
//----------------------------------------------------------------------------------------
if (state->supportDrag) {
Vector2 mousePosition = GetMousePosition();
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
// Window can be dragged from the top window bar
if (CheckCollisionPointRec(
mousePosition,
(Rectangle){state->windowBounds.x, state->windowBounds.y,
(float)state->windowBounds.width,
RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT})) {
state->dragMode = true;
state->panOffset.x = mousePosition.x - state->windowBounds.x;
state->panOffset.y = mousePosition.y - state->windowBounds.y;
}
}
if (state->dragMode) {
state->windowBounds.x = (mousePosition.x - state->panOffset.x);
state->windowBounds.y = (mousePosition.y - state->panOffset.y);
// Check screen limits to avoid moving out of screen
if (state->windowBounds.x < 0)
state->windowBounds.x = 0;
else if (state->windowBounds.x >
(GetScreenWidth() - state->windowBounds.width))
state->windowBounds.x = GetScreenWidth() - state->windowBounds.width;
if (state->windowBounds.y < 0)
state->windowBounds.y = 0;
else if (state->windowBounds.y >
(GetScreenHeight() - state->windowBounds.height))
state->windowBounds.y =
GetScreenHeight() - state->windowBounds.height;
if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
state->dragMode = false;
}
}
//----------------------------------------------------------------------------------------
// Load dirFilesIcon and state->dirFiles lazily on windows open
// NOTE: They are automatically unloaded at fileDialog closing
//----------------------------------------------------------------------------------------
if (dirFilesIcon == NULL) {
dirFilesIcon = (FileInfo *)RL_CALLOC(
MAX_DIRECTORY_FILES, sizeof(FileInfo)); // Max files to read
for (int i = 0; i < MAX_DIRECTORY_FILES; i++)
dirFilesIcon[i] =
(char *)RL_CALLOC(MAX_ICON_PATH_LENGTH, 1); // Max file name length
}
// Load current directory files
if (state->dirFiles.paths == NULL)
ReloadDirectoryFiles(state);
//----------------------------------------------------------------------------------------
// Draw window and controls
//----------------------------------------------------------------------------------------
state->windowActive =
!GuiWindowBox(state->windowBounds, "#198# Select File Dialog");
// Draw previous directory button + logic
if (GuiButton(
(Rectangle){state->windowBounds.x + state->windowBounds.width - 48,
state->windowBounds.y + 24 + 12, 40, 24},
"< ..")) {
// Move dir path one level up
strcpy(state->dirPathText, GetPrevDirectoryPath(state->dirPathText));
// Reload directory files (frees previous list)
ReloadDirectoryFiles(state);
state->filesListActive = -1;
memset(state->fileNameText, 0, 1024);
memset(state->fileNameTextCopy, 0, 1024);
}
// Draw current directory text box info + path editing logic
if (GuiTextBox((Rectangle){state->windowBounds.x + 8,
state->windowBounds.y + 24 + 12,
state->windowBounds.width - 48 - 16, 24},
state->dirPathText, 1024, state->dirPathEditMode)) {
if (state->dirPathEditMode) {
// Verify if a valid path has been introduced
if (DirectoryExists(state->dirPathText)) {
// Reload directory files (frees previous list)
ReloadDirectoryFiles(state);
strcpy(state->dirPathTextCopy, state->dirPathText);
} else
strcpy(state->dirPathText, state->dirPathTextCopy);
}
state->dirPathEditMode = !state->dirPathEditMode;
}
// List view elements are aligned left
int prevTextAlignment = GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT);
int prevElementsHeight = GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
GuiSetStyle(LISTVIEW, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 24);
#if defined(USE_CUSTOM_LISTVIEW_FILEINFO)
state->filesListActive = GuiListViewFiles(
(Rectangle){state->position.x + 8, state->position.y + 48 + 20,
state->windowBounds.width - 16,
state->windowBounds.height - 60 - 16 - 68},
fileInfo, state->dirFiles.count, &state->itemFocused,
&state->filesListScrollIndex, state->filesListActive);
#else
GuiListViewEx((Rectangle){state->windowBounds.x + 8,
state->windowBounds.y + 48 + 20,
state->windowBounds.width - 16,
state->windowBounds.height - 60 - 16 - 68},
(const char **)dirFilesIcon, state->dirFiles.count,
&state->filesListScrollIndex, &state->filesListActive,
&state->itemFocused);
#endif
GuiSetStyle(LISTVIEW, TEXT_ALIGNMENT, prevTextAlignment);
GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, prevElementsHeight);
// Check if a path has been selected, if it is a directory, move to that
// directory (and reload paths)
if ((state->filesListActive >= 0) &&
(state->filesListActive != state->prevFilesListActive))
//&& (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsKeyPressed(KEY_ENTER) ||
// IsKeyPressed(KEY_DPAD_A)))
{
strcpy(state->fileNameText,
GetFileName(state->dirFiles.paths[state->filesListActive]));
if (DirectoryExists(
TextFormat("%s/%s", state->dirPathText, state->fileNameText))) {
if (TextIsEqual(state->fileNameText, ".."))
strcpy(state->dirPathText, GetPrevDirectoryPath(state->dirPathText));
else
strcpy(state->dirPathText,
TextFormat("%s/%s",
(strcmp(state->dirPathText, "/") == 0)
? ""
: state->dirPathText,
state->fileNameText));
strcpy(state->dirPathTextCopy, state->dirPathText);
// Reload directory files (frees previous list)
ReloadDirectoryFiles(state);
strcpy(state->dirPathTextCopy, state->dirPathText);
state->filesListActive = -1;
strcpy(state->fileNameText, "\0");
strcpy(state->fileNameTextCopy, state->fileNameText);
}
state->prevFilesListActive = state->filesListActive;
}
// Draw bottom controls
//--------------------------------------------------------------------------------------
GuiLabel(
(Rectangle){state->windowBounds.x + 8,
state->windowBounds.y + state->windowBounds.height - 68, 60,
24},
"File name:");
if (GuiTextBox(
(Rectangle){state->windowBounds.x + 72,
state->windowBounds.y + state->windowBounds.height - 68,
state->windowBounds.width - 184, 24},
state->fileNameText, 128, state->fileNameEditMode)) {
if (*state->fileNameText) {
// Verify if a valid filename has been introduced
if (FileExists(
TextFormat("%s/%s", state->dirPathText, state->fileNameText))) {
// Select filename from list view
for (int i = 0; i < state->dirFiles.count; i++) {
if (TextIsEqual(state->fileNameText, state->dirFiles.paths[i])) {
state->filesListActive = i;
strcpy(state->fileNameTextCopy, state->fileNameText);
break;
}
}
} else if (!state->saveFileMode) {
strcpy(state->fileNameText, state->fileNameTextCopy);
}
}
state->fileNameEditMode = !state->fileNameEditMode;
}
GuiLabel((Rectangle){state->windowBounds.x + 8,
state->windowBounds.y + state->windowBounds.height -
24 - 12,
68, 24},
"File filter:");
GuiComboBox((Rectangle){state->windowBounds.x + 72,
state->windowBounds.y + state->windowBounds.height -
24 - 12,
state->windowBounds.width - 184, 24},
"All files", &state->fileTypeActive);
state->SelectFilePressed = GuiButton(
(Rectangle){state->windowBounds.x + state->windowBounds.width - 96 - 8,
state->windowBounds.y + state->windowBounds.height - 68, 96,
24},
"Select");
if (GuiButton(
(Rectangle){
state->windowBounds.x + state->windowBounds.width - 96 - 8,
state->windowBounds.y + state->windowBounds.height - 24 - 12,
96, 24},
"Cancel"))
state->windowActive = false;
//--------------------------------------------------------------------------------------
// Exit on file selected
if (state->SelectFilePressed)
state->windowActive = false;
// File dialog has been closed, free all memory before exit
if (!state->windowActive) {
// Free dirFilesIcon memory
for (int i = 0; i < MAX_DIRECTORY_FILES; i++)
RL_FREE(dirFilesIcon[i]);
RL_FREE(dirFilesIcon);
dirFilesIcon = NULL;
// Unload directory file paths
UnloadDirectoryFiles(state->dirFiles);
// Reset state variables
state->dirFiles.count = 0;
state->dirFiles.capacity = 0;
state->dirFiles.paths = NULL;
}
}
}
// Compare two files from a directory
static inline int FileCompare(const char *d1, const char *d2, const char *dir) {
const bool b1 = DirectoryExists(TextFormat("%s/%s", dir, d1));
const bool b2 = DirectoryExists(TextFormat("%s/%s", dir, d2));
if (b1 && !b2)
return -1;
if (!b1 && b2)
return 1;
if (!FileExists(TextFormat("%s/%s", dir, d1)))
return 1;
if (!FileExists(TextFormat("%s/%s", dir, d2)))
return -1;
return strcmp(d1, d2);
}
// Read files in new path
static void ReloadDirectoryFiles(GuiWindowFileDialogState *state) {
UnloadDirectoryFiles(state->dirFiles);
state->dirFiles = LoadDirectoryFilesEx(
state->dirPathText,
(state->filterExt[0] == '\0') ? NULL : state->filterExt, false);
state->itemFocused = 0;
// Reset dirFilesIcon memory
for (int i = 0; i < MAX_DIRECTORY_FILES; i++)
memset(dirFilesIcon[i], 0, MAX_ICON_PATH_LENGTH);
// Copy paths as icon + fileNames into dirFilesIcon
for (int i = 0; i < state->dirFiles.count; i++) {
if (IsPathFile(state->dirFiles.paths[i])) {
// Path is a file, a file icon for convenience (for some recognized
// extensions)
if (IsFileExtension(state->dirFiles.paths[i],
".png;.bmp;.tga;.gif;.jpg;.jpeg;.psd;.hdr;.qoi;.dds;."
"pkm;.ktx;.pvr;.astc")) {
strcpy(dirFilesIcon[i],
TextFormat("#12#%s", GetFileName(state->dirFiles.paths[i])));
} else if (IsFileExtension(
state->dirFiles.paths[i],
".wav;.mp3;.ogg;.flac;.xm;.mod;.it;.wma;.aiff")) {
strcpy(dirFilesIcon[i],
TextFormat("#11#%s", GetFileName(state->dirFiles.paths[i])));
} else if (IsFileExtension(state->dirFiles.paths[i],
".txt;.info;.md;.nfo;.xml;.json;.c;.cpp;.cs;."
"lua;.py;.glsl;.vs;.fs")) {
strcpy(dirFilesIcon[i],
TextFormat("#10#%s", GetFileName(state->dirFiles.paths[i])));
} else if (IsFileExtension(state->dirFiles.paths[i],
".exe;.bin;.raw;.msi")) {
strcpy(dirFilesIcon[i],
TextFormat("#200#%s", GetFileName(state->dirFiles.paths[i])));
} else
strcpy(dirFilesIcon[i],
TextFormat("#218#%s", GetFileName(state->dirFiles.paths[i])));
} else {
// Path is a directory, add a directory icon
strcpy(dirFilesIcon[i],
TextFormat("#1#%s", GetFileName(state->dirFiles.paths[i])));
}
}
}
#if defined(USE_CUSTOM_LISTVIEW_FILEINFO)
// List View control for files info with extended parameters
static int GuiListViewFiles(Rectangle bounds, FileInfo *files, int count,
int *focus, int *scrollIndex, int *active) {
int result = 0;
GuiState state = guiState;
int itemFocused = (focus == NULL) ? -1 : *focus;
int itemSelected = *active;
// Check if we need a scroll bar
bool useScrollBar = false;
if ((GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) +
GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)) *
count >
bounds.height)
useScrollBar = true;
// Define base item rectangle [0]
Rectangle itemBounds = {0};
itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING);
itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) +
GuiGetStyle(DEFAULT, BORDER_WIDTH);
itemBounds.width = bounds.width -
2 * GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) -
GuiGetStyle(DEFAULT, BORDER_WIDTH);
itemBounds.height = GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
if (useScrollBar)
itemBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH);
// Get items on the list
int visibleItems =
bounds.height / (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) +
GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING));
if (visibleItems > count)
visibleItems = count;
int startIndex = (scrollIndex == NULL) ? 0 : *scrollIndex;
if ((startIndex < 0) || (startIndex > (count - visibleItems)))
startIndex = 0;
int endIndex = startIndex + visibleItems;
// Update control
//--------------------------------------------------------------------
if ((state != GUI_STATE_DISABLED) && !guiLocked) {
Vector2 mousePoint = GetMousePosition();
// Check mouse inside list view
if (CheckCollisionPointRec(mousePoint, bounds)) {
state = GUI_STATE_FOCUSED;
// Check focused and selected item
for (int i = 0; i < visibleItems; i++) {
if (CheckCollisionPointRec(mousePoint, itemBounds)) {
itemFocused = startIndex + i;
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
itemSelected = startIndex + i;
break;
}
// Update item rectangle y position for next item
itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) +
GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING));
}
if (useScrollBar) {
int wheelMove = GetMouseWheelMove();
startIndex -= wheelMove;
if (startIndex < 0)
startIndex = 0;
else if (startIndex > (count - visibleItems))
startIndex = count - visibleItems;
endIndex = startIndex + visibleItems;
if (endIndex > count)
endIndex = count;
}
} else
itemFocused = -1;
// Reset item rectangle y to [0]
itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) +
GuiGetStyle(DEFAULT, BORDER_WIDTH);
}
//--------------------------------------------------------------------
// Draw control
//--------------------------------------------------------------------
DrawRectangleRec(bounds, GetColor(GuiGetStyle(
DEFAULT, BACKGROUND_COLOR))); // Draw background
DrawRectangleLinesEx(
bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH),
Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + state * 3)), guiAlpha));
// TODO: Draw list view header with file sections: icon+name | size | type |
// modTime
// Draw visible items
for (int i = 0; i < visibleItems; i++) {
if (state == GUI_STATE_DISABLED) {
if ((startIndex + i) == itemSelected) {
DrawRectangleRec(
itemBounds,
Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)),
guiAlpha));
DrawRectangleLinesEx(
itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH),
Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)),
guiAlpha));
}
// TODO: Draw full file info line: icon+name | size | type | modTime
GuiDrawText(
files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds),
GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT),
Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED)), guiAlpha));
} else {
if ((startIndex + i) == itemSelected) {
// Draw item selected
DrawRectangleRec(
itemBounds,
Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)),
guiAlpha));
DrawRectangleLinesEx(
itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH),
Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)),
guiAlpha));
GuiDrawText(files[startIndex + i].name,
GetTextBounds(DEFAULT, itemBounds),
GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT),
Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)),
guiAlpha));
} else if ((startIndex + i) == itemFocused) {
// Draw item focused
DrawRectangleRec(
itemBounds,
Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)),
guiAlpha));
DrawRectangleLinesEx(
itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH),
Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)),
guiAlpha));
GuiDrawText(files[startIndex + i].name,
GetTextBounds(DEFAULT, itemBounds),
GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT),
Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)),
guiAlpha));
} else {
// Draw item normal
GuiDrawText(
files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds),
GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT),
Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL)), guiAlpha));
}
}
// Update item rectangle y position for next item
itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) +
GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING));
}
if (useScrollBar) {
Rectangle scrollBarBounds = {
bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) -
GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH),
bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH),
(float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH),
bounds.height - 2 * GuiGetStyle(DEFAULT, BORDER_WIDTH)};
// Calculate percentage of visible items and apply same percentage to
// scrollbar
float percentVisible = (float)(endIndex - startIndex) / count;
float sliderSize = bounds.height * percentVisible;
int prevSliderSize =
GuiGetStyle(SCROLLBAR, SLIDER_WIDTH); // Save default slider size
int prevScrollSpeed =
GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed
GuiSetStyle(SCROLLBAR, SLIDER_WIDTH, sliderSize); // Change slider size
GuiSetStyle(SCROLLBAR, SCROLL_SPEED,
count - visibleItems); // Change scroll speed
startIndex =
GuiScrollBar(scrollBarBounds, startIndex, 0, count - visibleItems);
GuiSetStyle(SCROLLBAR, SCROLL_SPEED,
prevScrollSpeed); // Reset scroll speed to default
GuiSetStyle(SCROLLBAR, SLIDER_WIDTH,
prevSliderSize); // Reset slider size to default
}
//--------------------------------------------------------------------
if (focus != NULL)
*focus = itemFocused;
if (scrollIndex != NULL)
*scrollIndex = startIndex;
*active = itemSelected;
return result;
}
#endif // USE_CUSTOM_LISTVIEW_FILEINFO
#endif // GUI_FILE_DIALOG_IMPLEMENTATION

1
3rd-party/raygui vendored Submodule

@ -0,0 +1 @@
Subproject commit 499e8bf7b1d9b0a92af8f685e646bc61f13c6dff

2
3rd-party/raygui.c vendored
View File

@ -3,4 +3,4 @@
#undef RAYGUI_IMPLEMENTATION
#define GUI_WINDOW_FILE_DIALOG_IMPLEMENTATION
#include "gui_window_file_dialog.h"
#include "../examples/custom_file_dialog/gui_window_file_dialog.h"

5527
3rd-party/raygui.h vendored

File diff suppressed because it is too large Load Diff

1
3rd-party/raylib vendored Submodule

@ -0,0 +1 @@
Subproject commit 18bedbd0952c27b0eb8bc5df0df4acf589cef181

0
Tupfile.ini Normal file
View File

View File

@ -14,22 +14,23 @@ pub fn build(b: *std.Build) void {
.optimize = optimize,
});
// We cannot directly use modules since v4.5 is not compatible with zig
// v0.11
const raylib_dep = b.dependency("raylib", .{
.target = target,
.optimize = optimize,
});
exe.linkLibrary(raylib_dep.artifact("raylib"));
//
// C dependencies
//
exe.linkLibC();
const cflags = [_][]const u8{};
exe.addCSourceFile(.{
.file = .{
.path = "3rd-party/raygui.c",
},
.flags = &cflags,
});
exe.addIncludePath(.{ .path = "3rd-party/" });
// Raylib
exe.addIncludePath(.{ .path = "build/raylib/include" });
exe.addLibraryPath(.{ .path = "build/raylib" });
exe.linkSystemLibrary("raylib");
// Raygui
exe.addIncludePath(.{ .path = "3rd-party/raygui/src" });
exe.addIncludePath(.{ .path = "3rd-party/raygui" });
exe.addLibraryPath(.{ .path = "build/raygui" });
exe.linkSystemLibrary("raygui");
// SQLite
exe.linkSystemLibrary("sqlite3");
// This declares intent for the executable to be installed into the

View File

@ -1,10 +0,0 @@
.{
.name = "fabapp",
.version = "0.1.0",
.dependencies = .{
.raylib = .{
.url = "https://github.com/raysan5/raylib/archive/bc15c19518968878b68bbfe8eac3fe4297f11770.tar.gz",
.hash = "122093954b8c911e507de32d83a2046e122c6aca64e71f5244d54f9bbb93730c3ab7",
},
},
}

View File

@ -1,21 +1,5 @@
{
"nodes": {
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1673956053,
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
@ -34,21 +18,6 @@
"type": "github"
}
},
"flake-utils": {
"locked": {
"lastModified": 1659877975,
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1696983906,
@ -99,48 +68,11 @@
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1689088367,
"narHash": "sha256-Y2tl2TlKCWEHrOeM9ivjCLlRAKH3qoPUE/emhZECU14=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5c9ddb86679c400d6b7360797b8a22167c2053f8",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "release-23.05",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-parts": "flake-parts",
"nixpkgs": "nixpkgs",
"nixpkgs-unstable": "nixpkgs-unstable",
"zig-overlay": "zig-overlay"
}
},
"zig-overlay": {
"inputs": {
"flake-compat": "flake-compat",
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1697198920,
"narHash": "sha256-dtaoksNoOMC3H+FDF3cK+bP+jYvJokYBAFvzCALLDYk=",
"owner": "mitchellh",
"repo": "zig-overlay",
"rev": "2d779a7657e346323ab048b218994dbdc42655d7",
"type": "github"
},
"original": {
"owner": "mitchellh",
"repo": "zig-overlay",
"type": "github"
"nixpkgs-unstable": "nixpkgs-unstable"
}
}
},

View File

@ -4,27 +4,24 @@
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-23.05";
nixpkgs-unstable.url = "github:nixos/nixpkgs/nixpkgs-unstable";
zig-overlay.url = "github:mitchellh/zig-overlay";
flake-parts.url = "github:hercules-ci/flake-parts";
};
outputs = inputs@{ flake-parts, nixpkgs, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
flake = {
# Put your original flake attributes here.
};
flake = { };
systems = [ "x86_64-linux" ];
# https://flake.parts/module-arguments.html#persystem-module-parameters
perSystem = { pkgs, system, ... }: {
# We need unstable for Zig
_module.args.pkgs = import inputs.nixpkgs-unstable {
inherit system;
# https://flake.parts/overlays
overlays = [
inputs.zig-overlay.overlays.default
];
# NOTE: zig overlay triggers issues with X11/GL libraries
# This might be misconfiguration on my end
overlays = [ ];
config = { };
};
@ -32,24 +29,41 @@
devShells.default = with pkgs;
mkShell {
# EM_CONFIG = pkgs.writeText ".emscripten" ''
# EMSCRIPTEN_ROOT = '${pkgs.emscripten}/share/emscripten'
# LLVM_ROOT = '${pkgs.emscripten.llvmEnv}/bin'
# BINARYEN_ROOT = '${pkgs.binaryen}'
# NODE_JS = '${pkgs.nodejs-18_x}/bin/node'
# CACHE = '${toString ./.cache}'
# '';
nativeBuildInputs = [ clang cmake just ninja tup ];
buildInputs = [
sqlite
# Zig / webAssembly impl.
zig
# zigpkgs."master" # Issue with X11/GL libraries
zls
emscripten
# Linux graphical deps
## X11
xorg.libX11
xorg.libXcursor
xorg.libXi
xorg.libXext
xorg.libXrandr
xorg.libXinerama
xorg.libxcb
libGL
# xorg.libXcursor
# xorg.libXi
# xorg.libXext
# xorg.libXrandr
# xorg.libXinerama
# libGLU
libGLU
pkg-config
## Wayland
wayland-protocols
wayland
libxkbcommon
];
};

View File

@ -1,14 +1,31 @@
cpp_build_dir := justfile_directory() / "build"
alias b := build
alias r := run
alias t := test
alias fmt := format
build:
zig build
pre-build:
git submodule update --init --recursive
web-build:
raylib: pre-build
mkdir -p {{ cpp_build_dir }}
cmake -B {{ cpp_build_dir }} -S {{ justfile_directory() }}/3rd-party/raylib \
-DBUILD_EXAMPLES=OFF
cmake --build {{ cpp_build_dir }}
raygui: raylib
tup
build: raylib raygui
zig build -Doptimize=Debug
# zig build -Doptimize=Debug -Dtarget=x86_64-linux-gnu.2.30
# zig build -Doptimize=Debug -Dtarget=native-native-musl #--search-prefix /nix/store/n12a68qch9s85k6ni4m4r4xxr8lwys1i-sqlite-3.41.2/lib
web-build: pre-build
# zig build-lib src/main.zig -target wasm32-freestanding -dynamic -rdynamic
zig build -Dtarget=wasm32-emscripten --sysroot /nix/store/zll7a6ns3avx509kgx0jjghz8g89l2g0-emscripten-3.1.45
zig build -Dtarget=wasm32-emscripten --sysroot /nix/store/lszbak7w3k1jmx3cm3qb2qzillsib71v-emscripten-3.1.24/bin/emcc
# zig build -Dtarget=wasm32-emscripten
run: build
nixGL zig build run
@ -20,7 +37,11 @@ format:
fd -e zig -X zig fmt {}
fd -e nix -X nix fmt {}
update-deps:
# We cannot easily add header-only C library with package manager
curl https://raw.githubusercontent.com/raysan5/raygui/master/src/raygui.h --remote-name --output-dir 3rd-party/
curl https://raw.githubusercontent.com/raysan5/raygui/master/examples/custom_file_dialog/gui_window_file_dialog.h --remote-name --output-dir 3rd-party/
# update-deps:
# # We cannot easily add header-only C library with package manager
# curl https://raw.githubusercontent.com/raysan5/raygui/master/src/raygui.h --remote-name --output-dir 3rd-party/
# curl https://raw.githubusercontent.com/raysan5/raygui/master/examples/custom_file_dialog/gui_window_file_dialog.h --remote-name --output-dir 3rd-party/
envrc:
echo "use flake ."
echo "export CMAKE_GENERATOR=Ninja"

View File

@ -1,5 +1,5 @@
pub usingnamespace @cImport({
@cInclude("raylib.h");
@cInclude("raygui.h");
@cInclude("gui_window_file_dialog.h");
@cInclude("examples/custom_file_dialog/gui_window_file_dialog.h");
});