mirror of
https://github.com/Relintai/sfw.git
synced 2024-12-20 21:06:49 +01:00
Grab the ui framework from FWK. (Nuklear).
This commit is contained in:
parent
0358ef62de
commit
8e23bf198c
30372
sfw/render_gui/3rd_nuklear.h
Normal file
30372
sfw/render_gui/3rd_nuklear.h
Normal file
File diff suppressed because it is too large
Load Diff
483
sfw/render_gui/3rd_nuklear_filebrowser.h
Normal file
483
sfw/render_gui/3rd_nuklear_filebrowser.h
Normal file
@ -0,0 +1,483 @@
|
|||||||
|
// file browser for nuklear, based on https://github.com/vurtun/nuklear/blob/master/example/file_browser.c (public domain)
|
||||||
|
// - rlyeh, public domain
|
||||||
|
//
|
||||||
|
// changelog:
|
||||||
|
// - ported to FWK api
|
||||||
|
// - namespaced symbols
|
||||||
|
// - diverse win32 fixes
|
||||||
|
// - adaptive cols/rows
|
||||||
|
// - removed nk_begin()/nk_end() pairs
|
||||||
|
// - dangling nk_group_begin/end() pairs
|
||||||
|
// - simplified file<->media_group concept
|
||||||
|
// - minor cosmetics
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <direct.h> // _getcwd()
|
||||||
|
#else
|
||||||
|
#include <unistd.h> // getcwd()
|
||||||
|
#include <pwd.h> // getpwuid()
|
||||||
|
#define _popen popen
|
||||||
|
#define _pclose pclose
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char** old_file_list(const char *cwd, const char *masks) {
|
||||||
|
ASSERT(strend(cwd, "/"), "Error: dirs like '%s' must end with slash", cwd);
|
||||||
|
|
||||||
|
static __thread array(char*) list = 0;
|
||||||
|
const char *arg0 = cwd; // app_path();
|
||||||
|
int larg0 = strlen(arg0);
|
||||||
|
|
||||||
|
for( int i = 0; i < array_count(list); ++i ) {
|
||||||
|
FREE(list[i]);
|
||||||
|
}
|
||||||
|
array_resize(list, 0);//array_free(list);
|
||||||
|
|
||||||
|
for each_substring(masks,";",it) {
|
||||||
|
int recurse = !!strstr(it, "**");
|
||||||
|
#if is(win32)
|
||||||
|
char *glob = va("dir %s/b/o:n \"%s\\%s\" 2> NUL", recurse ? "/s":"", cwd, it);
|
||||||
|
#else // linux, osx
|
||||||
|
char *glob = va("find %s %s -name \"%s\" | sort", cwd, !recurse ? "-maxdepth 1":"-type f", it);
|
||||||
|
#endif
|
||||||
|
for( FILE *in = _popen(glob, "r"); in; _pclose(in), in = 0) {
|
||||||
|
char buf[1024], *line = buf;
|
||||||
|
while( fgets(buf, sizeof(buf), in) ) {
|
||||||
|
// clean up
|
||||||
|
if( strstr(line, arg0) ) line = buf + larg0;
|
||||||
|
if( !memcmp(line, "./", 2) ) line += 2;
|
||||||
|
int len = strlen(line); while( len > 0 && line[len-1] < 32 ) line[--len] = 0;
|
||||||
|
if( line[0] == '\0' ) continue;
|
||||||
|
// do not insert system folders/files
|
||||||
|
for(int i = 0; i < len; ++i ) if(line[i] == '\\') line[i] = '/';
|
||||||
|
if( line[0] == '.' ) if( !strcmp(line,".git") || !strcmp(line,".vs") || !strcmp(line,".") || !strcmp(line,"..") ) continue;
|
||||||
|
if( strstr(line, "/.") ) continue;
|
||||||
|
// insert copy
|
||||||
|
#if is(win32)
|
||||||
|
char *copy = STRDUP(line); // full path already provided
|
||||||
|
#else
|
||||||
|
// while(line[0] == '/') ++line;
|
||||||
|
char *copy = STRDUP(va("%s%s", cwd, line)); // need to prepend path
|
||||||
|
#endif
|
||||||
|
array_push(list, copy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
array_push(list, 0); // terminator
|
||||||
|
return (const char**)list;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
#define BROWSER_PRINTF(...) do {} while(0)
|
||||||
|
#else
|
||||||
|
#define BROWSER_PRINTF printf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum browser_groups {
|
||||||
|
BROWSER_FOLDER,
|
||||||
|
BROWSER_HOME,
|
||||||
|
BROWSER_DESKTOP,
|
||||||
|
BROWSER_COMPUTER,
|
||||||
|
BROWSER_PROJECT,
|
||||||
|
BROWSER_MAXFOLDERS,
|
||||||
|
|
||||||
|
BROWSER_MAXTYPES = 64,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct browser_media_group {
|
||||||
|
unsigned icon;
|
||||||
|
const char *extensions;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct browser_media {
|
||||||
|
int font;
|
||||||
|
int icon_sheet;
|
||||||
|
struct nk_image custom_folders[BROWSER_MAXFOLDERS];
|
||||||
|
struct nk_image custom_files[BROWSER_MAXTYPES];
|
||||||
|
struct browser_media_group group[BROWSER_MAXTYPES];
|
||||||
|
} media = {0};
|
||||||
|
|
||||||
|
void browser_config_dir(struct nk_image icon, unsigned counter) {
|
||||||
|
if( counter < BROWSER_MAXFOLDERS ) {
|
||||||
|
media.custom_folders[ counter ] = icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void browser_config_type(struct nk_image icon, const char *extensions) {
|
||||||
|
static int counter = 0;
|
||||||
|
if( counter < BROWSER_MAXTYPES ) {
|
||||||
|
media.custom_files[ counter ] = icon;
|
||||||
|
media.group[ counter ].icon = counter;
|
||||||
|
media.group[ counter ].extensions = extensions;
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BROWSER_MAX_PATH 512
|
||||||
|
struct browser {
|
||||||
|
/* path */
|
||||||
|
char file[BROWSER_MAX_PATH]; // selection
|
||||||
|
char directory[BROWSER_MAX_PATH]; // current cwd while browsing
|
||||||
|
|
||||||
|
char home[BROWSER_MAX_PATH];
|
||||||
|
char desktop[BROWSER_MAX_PATH];
|
||||||
|
char computer[BROWSER_MAX_PATH];
|
||||||
|
char project[BROWSER_MAX_PATH]; // cwd when first invoked
|
||||||
|
|
||||||
|
/* directory content */
|
||||||
|
array(char*) files;
|
||||||
|
array(char*) directories;
|
||||||
|
size_t file_count;
|
||||||
|
size_t dir_count;
|
||||||
|
|
||||||
|
/* filtered directory content */
|
||||||
|
array(char*) ffiles;
|
||||||
|
array(char*) fdirectories;
|
||||||
|
|
||||||
|
/* view mode */
|
||||||
|
bool listing;
|
||||||
|
float zooming;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct nk_image* media_icon_for_file(const char *file) {
|
||||||
|
/* extract extension .xxx from file */
|
||||||
|
char *ext = strrchr(file, '.');
|
||||||
|
if( ext && strlen(ext) < 16 ) {
|
||||||
|
char ext_dot[16+1];
|
||||||
|
snprintf(ext_dot, 16, "%s.", ext);
|
||||||
|
/* check for all file definition of all groups for fitting extension. skip first group (default) */
|
||||||
|
for (int i = 1; i < BROWSER_MAXTYPES && media.group[i].extensions; ++i) {
|
||||||
|
if( strstri(media.group[i].extensions, ext_dot) ) {
|
||||||
|
return &media.custom_files[ media.group[i].icon ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return first (default) group
|
||||||
|
return &media.custom_files[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void browser_reload_directory_content(struct browser *browser, const char *path) {
|
||||||
|
if(path[0] == '\0') path = va("./");
|
||||||
|
if(!strend(path, "/")) path = va("%s/", path);
|
||||||
|
|
||||||
|
for(int i = 0; i < array_count(browser->files); ++i) FREE(browser->files[i]);
|
||||||
|
for(int i = 0; i < array_count(browser->directories); ++i) FREE(browser->directories[i]);
|
||||||
|
|
||||||
|
array_resize(browser->files, 0);
|
||||||
|
array_resize(browser->directories, 0);
|
||||||
|
|
||||||
|
BROWSER_PRINTF("searching at %s\n", path);
|
||||||
|
|
||||||
|
const char** list = old_file_list(path, "*");
|
||||||
|
for( int i = 0; list[i]; ++i ) {
|
||||||
|
|
||||||
|
char *absolute = file_pathabs(ifndef(win32, list[i], va("%s/%s", path, list[i]))); // ../dir/./file.ext -> c:/prj/dir/file.ext
|
||||||
|
BROWSER_PRINTF("%s->%s %d->", list[i], absolute, file_directory(absolute) );
|
||||||
|
|
||||||
|
if( file_directory(absolute) ) {
|
||||||
|
// remove last '/' if present. ok to overwrite absolute var, file_*() API returns writeable strings.
|
||||||
|
char *dir = absolute; if( dir[ strlen(dir) - 1 ] == '/' ) dir[ strlen(dir) - 1 ] = '\0';
|
||||||
|
|
||||||
|
dir = file_name(dir); // /home/rlyeh/prj/fwk/art -> art
|
||||||
|
BROWSER_PRINTF("%s\n", dir);
|
||||||
|
|
||||||
|
if( dir[0] != '.' ) // skip special files, folders and internal files like .git or .art.zip
|
||||||
|
array_push(browser->directories, STRDUP(dir));
|
||||||
|
} else {
|
||||||
|
const char *fname = file_name(absolute);
|
||||||
|
|
||||||
|
BROWSER_PRINTF("%s\n", fname);
|
||||||
|
|
||||||
|
if( fname[0] != '.' ) // skip special files, folders and internal files like .git or .art.zip
|
||||||
|
array_push(browser->files, STRDUP(fname));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
browser->file_count = array_count(browser->files);
|
||||||
|
browser->dir_count = array_count(browser->directories);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void browser_chdir_and_reload_directory_content(struct browser *browser, const char *path) {
|
||||||
|
if( path != browser->directory ) strncpy(browser->directory, path, BROWSER_MAX_PATH);
|
||||||
|
browser_reload_directory_content(browser, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void browser_init(struct browser *browser) {
|
||||||
|
memset(browser, 0, sizeof(*browser));
|
||||||
|
{
|
||||||
|
/* load files and sub-directory list */
|
||||||
|
const char *home = getenv("HOME");
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (!home) home = getenv("USERPROFILE");
|
||||||
|
#else
|
||||||
|
if (!home) home = getpwuid(getuid())->pw_dir;
|
||||||
|
#endif
|
||||||
|
snprintf(browser->home, BROWSER_MAX_PATH, "%s/", home);
|
||||||
|
snprintf(browser->desktop, BROWSER_MAX_PATH, "%s/Desktop/", home);
|
||||||
|
snprintf(browser->computer, BROWSER_MAX_PATH, "%s", ifdef(win32, va("%.*s", 3, getenv("windir")), "/"));
|
||||||
|
{
|
||||||
|
ifdef(win32, _getcwd, getcwd)(browser->project, sizeof(browser->project) - 1); // -1 == room for '/'
|
||||||
|
strcat(browser->project, "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
BROWSER_PRINTF("%s\n", browser->home);
|
||||||
|
BROWSER_PRINTF("%s\n", browser->desktop);
|
||||||
|
BROWSER_PRINTF("%s\n", browser->computer);
|
||||||
|
BROWSER_PRINTF("%s\n", browser->project);
|
||||||
|
|
||||||
|
browser_chdir_and_reload_directory_content(browser, browser->project);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void browser_free(struct browser *browser) {
|
||||||
|
for(int i = 0; i < array_count(browser->files); ++i) FREE(browser->files[i]);
|
||||||
|
for(int i = 0; i < array_count(browser->directories); ++i) FREE(browser->directories[i]);
|
||||||
|
array_free(browser->files);
|
||||||
|
array_free(browser->directories);
|
||||||
|
array_free(browser->ffiles);
|
||||||
|
array_free(browser->fdirectories);
|
||||||
|
|
||||||
|
memset(browser, 0, sizeof(*browser));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int browser_run(struct nk_context *ctx, struct browser *browser, int windowed, struct nk_rect total_space) {
|
||||||
|
int clicked = 0;
|
||||||
|
|
||||||
|
static float ratio[] = {0.25f, NK_UNDEFINED};
|
||||||
|
|
||||||
|
float spacing_x = ctx->style.window.spacing.x;
|
||||||
|
|
||||||
|
/* output path directory selector in the menubar */
|
||||||
|
ctx->style.window.spacing.x = 0;
|
||||||
|
if( windowed ) nk_menubar_begin(ctx);
|
||||||
|
{
|
||||||
|
char *d = browser->directory;
|
||||||
|
#ifdef _WIN32
|
||||||
|
char *begin = d;
|
||||||
|
#else
|
||||||
|
char *begin = d + 1;
|
||||||
|
#endif
|
||||||
|
nk_layout_row_template_begin(ctx, 25);
|
||||||
|
nk_layout_row_template_push_variable(ctx, 40);
|
||||||
|
nk_layout_row_template_push_variable(ctx, 40);
|
||||||
|
nk_layout_row_template_push_variable(ctx, 40);
|
||||||
|
nk_layout_row_template_end(ctx);
|
||||||
|
|
||||||
|
if (nk_button_label(ctx, !browser->listing ? ICON_MD_LIST : ICON_MD_GRID_VIEW)) {
|
||||||
|
browser->listing ^= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*d++) {
|
||||||
|
if (*d == '/') {
|
||||||
|
*d = '\0';
|
||||||
|
if (nk_button_label(ctx, va("%s" ICON_MD_ARROW_RIGHT, file_name(begin)))) {
|
||||||
|
*d++ = '/'; *d = '\0';
|
||||||
|
browser_chdir_and_reload_directory_content(browser, browser->directory);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*d = '/';
|
||||||
|
begin = d + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( windowed ) nk_menubar_end(ctx);
|
||||||
|
ctx->style.window.spacing.x = spacing_x;
|
||||||
|
|
||||||
|
if(nk_window_has_focus(ctx)) {
|
||||||
|
browser->zooming = clampf( browser->zooming + (input(KEY_LCTRL) || input(KEY_RCTRL)) * input_diff(MOUSE_W) * 0.1, 1, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compact = 0, tiny = browser->listing; // compact, no left panel. tiny, no large icons
|
||||||
|
size_t cols = total_space.w / (100 * browser->zooming);
|
||||||
|
int icon_height = (67 * browser->zooming) * (tiny ? 0.33 : 1.); // icon height (96) + button padding (??). originally: 135
|
||||||
|
/**/ if( tiny ) cols = (int)cols+1.5, cols /= 2, compact = total_space.w < 500; // cols <= 2;
|
||||||
|
else cols = (int)cols+1, compact = total_space.w < 500; // cols <= 5;
|
||||||
|
if( cols < 1 ) cols=1;
|
||||||
|
|
||||||
|
/* window layout */
|
||||||
|
nk_layout_row(ctx, NK_DYNAMIC, total_space.h, compact ? 1 : 2, compact ? ratio+1 : ratio);
|
||||||
|
if( !compact )
|
||||||
|
if( nk_group_begin(ctx, "Special", NK_WINDOW_NO_SCROLLBAR) ) {
|
||||||
|
nk_layout_row_dynamic(ctx, 40, 1);
|
||||||
|
|
||||||
|
if (nk_button_image_label(ctx,media.custom_folders[BROWSER_HOME],"Home",NK_TEXT_RIGHT))
|
||||||
|
browser_chdir_and_reload_directory_content(browser, browser->home);
|
||||||
|
|
||||||
|
if (nk_button_image_label(ctx,media.custom_folders[BROWSER_DESKTOP],"Desktop",NK_TEXT_RIGHT))
|
||||||
|
browser_chdir_and_reload_directory_content(browser, browser->desktop);
|
||||||
|
|
||||||
|
if (nk_button_image_label(ctx,media.custom_folders[BROWSER_COMPUTER],"Computer",NK_TEXT_RIGHT))
|
||||||
|
browser_chdir_and_reload_directory_content(browser, browser->computer);
|
||||||
|
|
||||||
|
if (nk_button_image_label(ctx,media.custom_folders[BROWSER_PROJECT],"Project",NK_TEXT_RIGHT))
|
||||||
|
browser_chdir_and_reload_directory_content(browser, browser->project);
|
||||||
|
|
||||||
|
nk_group_end(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* output directory content window */
|
||||||
|
if(nk_group_begin(ctx, "Content", windowed ? NK_WINDOW_NO_SCROLLBAR : 0)) {
|
||||||
|
|
||||||
|
array(char*) *directories = &browser->directories;
|
||||||
|
array(char*) *files = &browser->files;
|
||||||
|
|
||||||
|
if( ui_filter && ui_filter[0] ) {
|
||||||
|
array_resize(browser->fdirectories, 0);
|
||||||
|
array_resize(browser->ffiles, 0);
|
||||||
|
|
||||||
|
for each_array(browser->directories,char*,k)
|
||||||
|
if( strstri(k, ui_filter) )
|
||||||
|
array_push(browser->fdirectories, k);
|
||||||
|
|
||||||
|
for each_array(browser->files,char*,k)
|
||||||
|
if( strstri(k, ui_filter) )
|
||||||
|
array_push(browser->ffiles, k);
|
||||||
|
|
||||||
|
directories = &browser->fdirectories;
|
||||||
|
files = &browser->ffiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dir_count = array_count(*directories);
|
||||||
|
int file_count = array_count(*files);
|
||||||
|
|
||||||
|
int index = -1;
|
||||||
|
size_t i = 0, j = 0, k = 0;
|
||||||
|
size_t rows = 0;
|
||||||
|
size_t count = dir_count + file_count;
|
||||||
|
|
||||||
|
rows = count / cols;
|
||||||
|
for (i = 0; i <= rows; i += 1) {
|
||||||
|
if(!tiny)
|
||||||
|
{size_t n = j + cols;
|
||||||
|
nk_layout_row_dynamic(ctx, icon_height, (int)cols);
|
||||||
|
for (; j < count && j < n; ++j) {
|
||||||
|
size_t t = j-dir_count;
|
||||||
|
|
||||||
|
/* draw one row of icons */
|
||||||
|
if (j < dir_count) {
|
||||||
|
/* draw and execute directory buttons */
|
||||||
|
if (nk_button_image(ctx,media.custom_folders[BROWSER_FOLDER]))
|
||||||
|
index = (int)j;
|
||||||
|
} else {
|
||||||
|
/* draw and execute files buttons */
|
||||||
|
struct nk_image *icon;
|
||||||
|
size_t fileIndex = ((size_t)j - dir_count);
|
||||||
|
icon = media_icon_for_file((*files)[fileIndex]);
|
||||||
|
if (nk_button_image(ctx, *icon)) {
|
||||||
|
snprintf(browser->file, BROWSER_MAX_PATH, "%s%s", browser->directory, browser->files[fileIndex]);
|
||||||
|
clicked = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
if(!tiny)
|
||||||
|
{size_t n = k + cols;
|
||||||
|
nk_layout_row_dynamic(ctx, 20, (int)cols);
|
||||||
|
for (; k < count && k < n; k++) {
|
||||||
|
size_t t = k-dir_count;
|
||||||
|
|
||||||
|
/* draw one row of labels */
|
||||||
|
if (k < dir_count) {
|
||||||
|
nk_label(ctx, (*directories)[k], NK_TEXT_CENTERED);
|
||||||
|
} else {
|
||||||
|
nk_label(ctx, (*files)[t], NK_TEXT_CENTERED);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
if(tiny)
|
||||||
|
{size_t n = j + cols;
|
||||||
|
nk_layout_row_dynamic(ctx, icon_height, (int)cols);
|
||||||
|
for (; j < count && j < n; ++j) {
|
||||||
|
size_t t = j-dir_count;
|
||||||
|
|
||||||
|
/* draw one row of icons */
|
||||||
|
if (j < dir_count) {
|
||||||
|
/* draw and execute directory buttons */
|
||||||
|
if (nk_button_image_label(ctx,media.custom_folders[BROWSER_FOLDER], (*directories)[j], NK_TEXT_RIGHT))
|
||||||
|
index = (int)j;
|
||||||
|
} else {
|
||||||
|
/* draw and execute files buttons */
|
||||||
|
struct nk_image *icon;
|
||||||
|
size_t fileIndex = ((size_t)j - dir_count);
|
||||||
|
icon = media_icon_for_file((*files)[fileIndex]);
|
||||||
|
if (nk_button_image_label(ctx, *icon, (*files)[t],NK_TEXT_RIGHT)) {
|
||||||
|
snprintf(browser->file, BROWSER_MAX_PATH, "%s%s", browser->directory, browser->files[fileIndex]);
|
||||||
|
clicked = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
bool has_focus = nk_window_has_focus(ctx); // @fixme: move out of loop
|
||||||
|
bool has_popups = ui_popups(); // @fixme: move out of loop
|
||||||
|
if( !has_popups && has_focus ) {
|
||||||
|
struct nk_rect bounds = nk_widget_bounds(ctx);
|
||||||
|
if (nk_input_is_mouse_hovering_rect(&ctx->input, bounds) ) {
|
||||||
|
|
||||||
|
char *name = j < dir_count ? (*directories)[j] : (*files)[j-dir_count];
|
||||||
|
|
||||||
|
char fullpath[PATH_MAX];
|
||||||
|
snprintf(fullpath, PATH_MAX, "%s%s", browser->directory, name);
|
||||||
|
|
||||||
|
struct stat t = {0};
|
||||||
|
if( stat( fullpath, &t ) != -1 ) {
|
||||||
|
char tooltip[256];
|
||||||
|
snprintf(tooltip, 256,
|
||||||
|
"Path: %s\n"
|
||||||
|
"Type: %lld\n" // file type and mode
|
||||||
|
"Size: %lld\n" // file size
|
||||||
|
"Owner: %lld\n" // user ID of file owner
|
||||||
|
"Modified: %s (%lld)", // last modification date
|
||||||
|
name, (int64_t)t.st_mode, (int64_t)t.st_size, (int64_t)t.st_uid, ctime(&t.st_mtime), (int64_t)t.st_mtime
|
||||||
|
);
|
||||||
|
nk_tooltip(ctx, tooltip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index != -1) {
|
||||||
|
BROWSER_PRINTF("%s + %s = ", browser->directory, browser->directories[index]);
|
||||||
|
size_t n = strlen(browser->directory);
|
||||||
|
snprintf(browser->directory + n, BROWSER_MAX_PATH - n, "%s/", browser->directories[index]);
|
||||||
|
BROWSER_PRINTF("%s\n", browser->directory);
|
||||||
|
browser_chdir_and_reload_directory_content(browser, browser->directory);
|
||||||
|
}
|
||||||
|
nk_group_end(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return clicked;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct nk_image icon_load(const char *filename) {
|
||||||
|
texture_t t = texture(filename, 0);
|
||||||
|
return nk_image_id((int)t.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct nk_image icon_load_rect(unsigned id, unsigned w, unsigned h, unsigned wcell, unsigned hcell, unsigned col, unsigned row) {
|
||||||
|
return nk_subimage_id((int)id, w, h, (struct nk_rect){ wcell * col, hcell * row, wcell, hcell });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* demo:
|
||||||
|
|
||||||
|
struct browser browser = {0};
|
||||||
|
browser_init(&browser);
|
||||||
|
browser_config_dir(nk_image, BROWSER_HOME);
|
||||||
|
browser_config_dir(nk_image, BROWSER_PROJECT);
|
||||||
|
// [...]
|
||||||
|
browser_config_type(nk_image, ".ext1.ext2.ext3.");
|
||||||
|
browser_config_type(nk_image, ".ext1.ext2.ext3.");
|
||||||
|
browser_config_type(nk_image, ".ext1.ext2.ext3.");
|
||||||
|
// [...]
|
||||||
|
|
||||||
|
[...]
|
||||||
|
|
||||||
|
if( nk_begin(ctx, "window", ...) ) {
|
||||||
|
struct nk_rect total_space = nk_window_get_content_region(ctx);
|
||||||
|
if( browser_run(ctx, &browser, 0, total_space) ) {
|
||||||
|
puts( browser->directory );
|
||||||
|
puts( browser->file );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nk_end();
|
||||||
|
*/
|
552
sfw/render_gui/3rd_nuklear_glfw_gl3.h
Normal file
552
sfw/render_gui/3rd_nuklear_glfw_gl3.h
Normal file
@ -0,0 +1,552 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* Nuklear - 1.32.0 - public domain
|
||||||
|
* no warrenty implied; use at your own risk.
|
||||||
|
* authored from 2015-2016 by Micha Mettke
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* ==============================================================
|
||||||
|
*
|
||||||
|
* API
|
||||||
|
*
|
||||||
|
* ===============================================================
|
||||||
|
*/
|
||||||
|
#ifndef NK_GLFW_GL3_H_
|
||||||
|
#define NK_GLFW_GL3_H_
|
||||||
|
|
||||||
|
//#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
enum nk_glfw_init_state{
|
||||||
|
NK_GLFW3_DEFAULT=0,
|
||||||
|
NK_GLFW3_INSTALL_CALLBACKS
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef NK_GLFW_TEXT_MAX
|
||||||
|
#define NK_GLFW_TEXT_MAX 256
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct nk_glfw_device {
|
||||||
|
struct nk_buffer cmds;
|
||||||
|
struct nk_draw_null_texture null;
|
||||||
|
GLuint vbo, vao, ebo;
|
||||||
|
GLuint prog;
|
||||||
|
GLuint vert_shdr;
|
||||||
|
GLuint frag_shdr;
|
||||||
|
GLint attrib_pos;
|
||||||
|
GLint attrib_uv;
|
||||||
|
GLint attrib_col;
|
||||||
|
GLint uniform_tex;
|
||||||
|
GLint uniform_proj;
|
||||||
|
GLuint font_tex;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nk_glfw {
|
||||||
|
GLFWwindow *win;
|
||||||
|
int width, height;
|
||||||
|
int display_width, display_height;
|
||||||
|
struct nk_glfw_device ogl;
|
||||||
|
struct nk_context ctx;
|
||||||
|
struct nk_font_atlas atlas;
|
||||||
|
struct nk_vec2 fb_scale;
|
||||||
|
unsigned int text[NK_GLFW_TEXT_MAX];
|
||||||
|
int text_len;
|
||||||
|
struct nk_vec2 scroll, scroll_bak; //< @r-lyeh, added scroll_bak
|
||||||
|
double last_button_click;
|
||||||
|
int is_double_click_down;
|
||||||
|
struct nk_vec2 double_click_pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
NK_API struct nk_context* nk_glfw3_init(struct nk_glfw* glfw, GLFWwindow *win, enum nk_glfw_init_state);
|
||||||
|
NK_API void nk_glfw3_shutdown(struct nk_glfw* glfw);
|
||||||
|
NK_API void nk_glfw3_font_stash_begin(struct nk_glfw* glfw, struct nk_font_atlas **atlas);
|
||||||
|
NK_API void nk_glfw3_font_stash_end(struct nk_glfw* glfw);
|
||||||
|
NK_API void nk_glfw3_new_frame(struct nk_glfw* glfw);
|
||||||
|
NK_API void nk_glfw3_render(struct nk_glfw* glfw, enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer);
|
||||||
|
|
||||||
|
NK_API void nk_glfw3_device_destroy(struct nk_glfw* glfw);
|
||||||
|
NK_API void nk_glfw3_device_create(struct nk_glfw* glfw);
|
||||||
|
|
||||||
|
NK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint);
|
||||||
|
NK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff);
|
||||||
|
NK_API void nk_glfw3_mouse_button_callback(GLFWwindow *win, int button, int action, int mods);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ==============================================================
|
||||||
|
*
|
||||||
|
* IMPLEMENTATION
|
||||||
|
*
|
||||||
|
* ===============================================================
|
||||||
|
*/
|
||||||
|
#ifdef NK_GLFW_GL3_IMPLEMENTATION
|
||||||
|
|
||||||
|
#ifndef NK_GLFW_DOUBLE_CLICK_LO
|
||||||
|
#define NK_GLFW_DOUBLE_CLICK_LO 0.02
|
||||||
|
#endif
|
||||||
|
#ifndef NK_GLFW_DOUBLE_CLICK_HI
|
||||||
|
#define NK_GLFW_DOUBLE_CLICK_HI 0.2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct nk_glfw_vertex {
|
||||||
|
float position[2];
|
||||||
|
float uv[2];
|
||||||
|
nk_byte col[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
#define NK_SHADER_VERSION "#version 100\n"
|
||||||
|
#else
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#define NK_SHADER_VERSION "#version 150\n"
|
||||||
|
#else
|
||||||
|
#define NK_SHADER_VERSION "#version 300 es\n"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NK_API void
|
||||||
|
nk_glfw3_device_create(struct nk_glfw* glfw)
|
||||||
|
{
|
||||||
|
GLint status;
|
||||||
|
static const GLchar *vertex_shader =
|
||||||
|
NK_SHADER_VERSION
|
||||||
|
"uniform mat4 ProjMtx;\n"
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
"attribute vec2 Position;\n"
|
||||||
|
"attribute vec2 TexCoord;\n"
|
||||||
|
"attribute vec4 Color;\n"
|
||||||
|
"varying vec2 Frag_UV;\n"
|
||||||
|
"varying vec4 Frag_Color;\n"
|
||||||
|
#else
|
||||||
|
"in vec2 Position;\n"
|
||||||
|
"in vec2 TexCoord;\n"
|
||||||
|
"in vec4 Color;\n"
|
||||||
|
"out vec2 Frag_UV;\n"
|
||||||
|
"out vec4 Frag_Color;\n"
|
||||||
|
#endif
|
||||||
|
"void main() {\n"
|
||||||
|
" Frag_UV = TexCoord;\n"
|
||||||
|
" Frag_Color = Color;\n"
|
||||||
|
" gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
|
||||||
|
"}\n";
|
||||||
|
static const GLchar *fragment_shader =
|
||||||
|
NK_SHADER_VERSION
|
||||||
|
"precision mediump float;\n"
|
||||||
|
"uniform sampler2D Texture;\n"
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
"varying vec2 Frag_UV;\n"
|
||||||
|
"varying vec4 Frag_Color;\n"
|
||||||
|
#else
|
||||||
|
"in vec2 Frag_UV;\n"
|
||||||
|
"in vec4 Frag_Color;\n"
|
||||||
|
"out vec4 Out_Color;\n"
|
||||||
|
#endif
|
||||||
|
"void main(){\n"
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
" gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV);\n"
|
||||||
|
#else
|
||||||
|
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||||
|
#endif
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
struct nk_glfw_device *dev = &glfw->ogl;
|
||||||
|
nk_buffer_init_default(&dev->cmds);
|
||||||
|
dev->prog = glCreateProgram();
|
||||||
|
dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
|
||||||
|
glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
|
||||||
|
glCompileShader(dev->vert_shdr);
|
||||||
|
glCompileShader(dev->frag_shdr);
|
||||||
|
glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
|
||||||
|
assert(status == GL_TRUE);
|
||||||
|
glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
|
||||||
|
assert(status == GL_TRUE);
|
||||||
|
glAttachShader(dev->prog, dev->vert_shdr);
|
||||||
|
glAttachShader(dev->prog, dev->frag_shdr);
|
||||||
|
glLinkProgram(dev->prog);
|
||||||
|
glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
|
||||||
|
assert(status == GL_TRUE);
|
||||||
|
|
||||||
|
dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
|
||||||
|
dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
|
||||||
|
dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
|
||||||
|
dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
|
||||||
|
dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
|
||||||
|
|
||||||
|
{
|
||||||
|
/* buffer setup */
|
||||||
|
GLsizei vs = sizeof(struct nk_glfw_vertex);
|
||||||
|
size_t vp = offsetof(struct nk_glfw_vertex, position);
|
||||||
|
size_t vt = offsetof(struct nk_glfw_vertex, uv);
|
||||||
|
size_t vc = offsetof(struct nk_glfw_vertex, col);
|
||||||
|
|
||||||
|
glGenBuffers(1, &dev->vbo);
|
||||||
|
glGenBuffers(1, &dev->ebo);
|
||||||
|
glGenVertexArrays(1, &dev->vao);
|
||||||
|
|
||||||
|
glBindVertexArray(dev->vao);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray((GLuint)dev->attrib_pos);
|
||||||
|
glEnableVertexAttribArray((GLuint)dev->attrib_uv);
|
||||||
|
glEnableVertexAttribArray((GLuint)dev->attrib_col);
|
||||||
|
|
||||||
|
glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
|
||||||
|
glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
|
||||||
|
glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
glBindVertexArray(0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
NK_INTERN void
|
||||||
|
nk_glfw3_device_upload_atlas(struct nk_glfw* glfw, const void *image, int width, int height)
|
||||||
|
{
|
||||||
|
struct nk_glfw_device *dev = &glfw->ogl;
|
||||||
|
glGenTextures(1, &dev->font_tex);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, dev->font_tex);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
|
||||||
|
GL_RGBA, GL_UNSIGNED_BYTE, image);
|
||||||
|
}
|
||||||
|
|
||||||
|
NK_API void
|
||||||
|
nk_glfw3_device_destroy(struct nk_glfw* glfw)
|
||||||
|
{
|
||||||
|
struct nk_glfw_device *dev = &glfw->ogl;
|
||||||
|
glDetachShader(dev->prog, dev->vert_shdr);
|
||||||
|
glDetachShader(dev->prog, dev->frag_shdr);
|
||||||
|
glDeleteShader(dev->vert_shdr);
|
||||||
|
glDeleteShader(dev->frag_shdr);
|
||||||
|
glDeleteProgram(dev->prog);
|
||||||
|
glDeleteTextures(1, &dev->font_tex);
|
||||||
|
glDeleteBuffers(1, &dev->vbo);
|
||||||
|
glDeleteBuffers(1, &dev->ebo);
|
||||||
|
nk_buffer_free(&dev->cmds);
|
||||||
|
}
|
||||||
|
|
||||||
|
NK_API void
|
||||||
|
nk_glfw3_render(struct nk_glfw* glfw, enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
|
||||||
|
{
|
||||||
|
struct nk_glfw_device *dev = &glfw->ogl;
|
||||||
|
GLfloat ortho[4][4] = {
|
||||||
|
{2.0f, 0.0f, 0.0f, 0.0f},
|
||||||
|
{0.0f,-2.0f, 0.0f, 0.0f},
|
||||||
|
{0.0f, 0.0f,-1.0f, 0.0f},
|
||||||
|
{-1.0f,1.0f, 0.0f, 1.0f},
|
||||||
|
};
|
||||||
|
ortho[0][0] /= (GLfloat)glfw->width;
|
||||||
|
ortho[1][1] /= (GLfloat)glfw->height;
|
||||||
|
|
||||||
|
/* setup global state */
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendEquation(GL_FUNC_ADD);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
/* setup program */
|
||||||
|
glUseProgram(dev->prog);
|
||||||
|
glUniform1i(dev->uniform_tex, 0);
|
||||||
|
glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
|
||||||
|
glViewport(0,0,(GLsizei)glfw->display_width,(GLsizei)glfw->display_height);
|
||||||
|
{
|
||||||
|
/* convert from command queue into draw list and draw to screen */
|
||||||
|
const struct nk_draw_command *cmd = NULL;
|
||||||
|
void *vertices, *elements;
|
||||||
|
const nk_draw_index *offset = NULL;
|
||||||
|
|
||||||
|
/* allocate vertex and element buffer */
|
||||||
|
glBindVertexArray(dev->vao);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
|
||||||
|
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);
|
||||||
|
|
||||||
|
/* load draw vertices & elements directly into vertex + element buffer */
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
|
||||||
|
elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
|
||||||
|
#else
|
||||||
|
vertices = malloc((size_t)max_vertex_buffer);
|
||||||
|
elements = malloc((size_t)max_element_buffer);
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/* fill convert configuration */
|
||||||
|
struct nk_convert_config config;
|
||||||
|
static const struct nk_draw_vertex_layout_element vertex_layout[] = {
|
||||||
|
{NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},
|
||||||
|
{NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},
|
||||||
|
{NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},
|
||||||
|
{NK_VERTEX_LAYOUT_END}
|
||||||
|
};
|
||||||
|
NK_MEMSET(&config, 0, sizeof(config));
|
||||||
|
config.vertex_layout = vertex_layout;
|
||||||
|
config.vertex_size = sizeof(struct nk_glfw_vertex);
|
||||||
|
config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);
|
||||||
|
config.null = dev->null;
|
||||||
|
config.circle_segment_count = 22;
|
||||||
|
config.curve_segment_count = 22;
|
||||||
|
config.arc_segment_count = 22;
|
||||||
|
config.global_alpha = 1.0f;
|
||||||
|
config.shape_AA = AA;
|
||||||
|
config.line_AA = AA;
|
||||||
|
|
||||||
|
/* setup buffers to load vertices and elements */
|
||||||
|
{struct nk_buffer vbuf, ebuf;
|
||||||
|
nk_buffer_init_fixed(&vbuf, vertices, (size_t)max_vertex_buffer);
|
||||||
|
nk_buffer_init_fixed(&ebuf, elements, (size_t)max_element_buffer);
|
||||||
|
nk_convert(&glfw->ctx, &dev->cmds, &vbuf, &ebuf, &config);}
|
||||||
|
}
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, (size_t)max_vertex_buffer, vertices);
|
||||||
|
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, (size_t)max_element_buffer, elements);
|
||||||
|
free(vertices);
|
||||||
|
free(elements);
|
||||||
|
#else
|
||||||
|
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||||
|
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* iterate over and execute each draw command */
|
||||||
|
nk_draw_foreach(cmd, &glfw->ctx, &dev->cmds)
|
||||||
|
if(glfw->height > 0) //< @r-lyeh: fix opengl/scissor error when win is minimized (h==0)
|
||||||
|
{
|
||||||
|
if (!cmd->elem_count) continue;
|
||||||
|
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
|
||||||
|
glScissor(
|
||||||
|
(GLint)(cmd->clip_rect.x * glfw->fb_scale.x),
|
||||||
|
(GLint)((glfw->height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * glfw->fb_scale.y),
|
||||||
|
(GLint)(cmd->clip_rect.w * glfw->fb_scale.x),
|
||||||
|
(GLint)(cmd->clip_rect.h * glfw->fb_scale.y));
|
||||||
|
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
|
||||||
|
offset += cmd->elem_count;
|
||||||
|
}
|
||||||
|
nk_clear(&glfw->ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* default OpenGL state */
|
||||||
|
glUseProgram(0);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
glBindVertexArray(0);
|
||||||
|
#endif
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glDisable(GL_SCISSOR_TEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
NK_API void
|
||||||
|
nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint)
|
||||||
|
{
|
||||||
|
if(glfwGetInputMode(win, GLFW_CURSOR) != GLFW_CURSOR_NORMAL) return; //< @r-lyeh: do not grab input when mouse is hidden (fps cam)
|
||||||
|
|
||||||
|
struct nk_glfw* glfw = glfwGetWindowUserPointer(win);
|
||||||
|
if (glfw->text_len < NK_GLFW_TEXT_MAX)
|
||||||
|
glfw->text[glfw->text_len++] = codepoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
NK_API void
|
||||||
|
nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff)
|
||||||
|
{
|
||||||
|
if(glfwGetInputMode(win, GLFW_CURSOR) != GLFW_CURSOR_NORMAL) return; //< @r-lyeh: do not grab input when mouse is hidden (fps cam)
|
||||||
|
|
||||||
|
struct nk_glfw* glfw = glfwGetWindowUserPointer(win);
|
||||||
|
glfw->scroll.x += (float)xoff;
|
||||||
|
glfw->scroll.y += (float)yoff;
|
||||||
|
glfw->scroll_bak.x += (float)xoff; //< @r-lyeh
|
||||||
|
glfw->scroll_bak.y += (float)yoff; //< @r-lyeh
|
||||||
|
}
|
||||||
|
|
||||||
|
NK_API void
|
||||||
|
nk_glfw3_mouse_button_callback(GLFWwindow* win, int button, int action, int mods)
|
||||||
|
{
|
||||||
|
if(glfwGetInputMode(win, GLFW_CURSOR) != GLFW_CURSOR_NORMAL) return; //< @r-lyeh: do not grab input when mouse is hidden (fps cam)
|
||||||
|
|
||||||
|
double x, y;
|
||||||
|
if (button != GLFW_MOUSE_BUTTON_LEFT) return;
|
||||||
|
struct nk_glfw* glfw = glfwGetWindowUserPointer(win);
|
||||||
|
glfwGetCursorPos(win, &x, &y);
|
||||||
|
if (action == GLFW_PRESS) {
|
||||||
|
double dt = glfwGetTime() - glfw->last_button_click;
|
||||||
|
if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) {
|
||||||
|
glfw->is_double_click_down = nk_true;
|
||||||
|
glfw->double_click_pos = nk_vec2((float)x, (float)y);
|
||||||
|
}
|
||||||
|
glfw->last_button_click = glfwGetTime();
|
||||||
|
} else glfw->is_double_click_down = nk_false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NK_INTERN void
|
||||||
|
nk_glfw3_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)
|
||||||
|
{
|
||||||
|
(void)usr;
|
||||||
|
struct nk_glfw* glfw = glfwGetWindowUserPointer(window_handle()); // @rlyeh < struct nk_glfw* glfw = usr.ptr;
|
||||||
|
|
||||||
|
const char *text = glfwGetClipboardString(glfw->win);
|
||||||
|
if (text) nk_textedit_paste(edit, text, nk_strlen(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
NK_INTERN void
|
||||||
|
nk_glfw3_clipboard_copy(nk_handle usr, const char *text, int len)
|
||||||
|
{
|
||||||
|
(void)usr;
|
||||||
|
struct nk_glfw* glfw = glfwGetWindowUserPointer(window_handle()); // @rlyeh < struct nk_glfw* glfw = usr.ptr;
|
||||||
|
|
||||||
|
char *str = 0;
|
||||||
|
if (!len) return;
|
||||||
|
str = (char*)malloc((size_t)len+1);
|
||||||
|
if (!str) return;
|
||||||
|
memcpy(str, text, (size_t)len);
|
||||||
|
str[len] = '\0';
|
||||||
|
glfwSetClipboardString(glfw->win, str);
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
NK_API struct nk_context*
|
||||||
|
nk_glfw3_init(struct nk_glfw* glfw, GLFWwindow *win, enum nk_glfw_init_state init_state)
|
||||||
|
{
|
||||||
|
glfwSetWindowUserPointer(win, glfw);
|
||||||
|
|
||||||
|
glfw->win = win;
|
||||||
|
if (init_state == NK_GLFW3_INSTALL_CALLBACKS) {
|
||||||
|
glfwSetScrollCallback(win, nk_gflw3_scroll_callback);
|
||||||
|
glfwSetCharCallback(win, nk_glfw3_char_callback);
|
||||||
|
glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_callback);
|
||||||
|
}
|
||||||
|
nk_init_default(&glfw->ctx, 0);
|
||||||
|
glfw->ctx.clip.copy = nk_glfw3_clipboard_copy;
|
||||||
|
glfw->ctx.clip.paste = nk_glfw3_clipboard_paste;
|
||||||
|
glfw->ctx.clip.userdata = nk_handle_ptr(0);
|
||||||
|
glfw->last_button_click = 0;
|
||||||
|
nk_glfw3_device_create(glfw);
|
||||||
|
|
||||||
|
glfw->is_double_click_down = nk_false;
|
||||||
|
glfw->double_click_pos = nk_vec2(0, 0);
|
||||||
|
|
||||||
|
return &glfw->ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
NK_API void
|
||||||
|
nk_glfw3_font_stash_begin(struct nk_glfw* glfw, struct nk_font_atlas **atlas)
|
||||||
|
{
|
||||||
|
nk_font_atlas_init_default(&glfw->atlas);
|
||||||
|
nk_font_atlas_begin(&glfw->atlas);
|
||||||
|
*atlas = &glfw->atlas;
|
||||||
|
}
|
||||||
|
|
||||||
|
NK_API void
|
||||||
|
nk_glfw3_font_stash_end(struct nk_glfw* glfw)
|
||||||
|
{
|
||||||
|
const void *image; int w, h;
|
||||||
|
image = nk_font_atlas_bake(&glfw->atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
|
||||||
|
nk_glfw3_device_upload_atlas(glfw, image, w, h);
|
||||||
|
nk_font_atlas_end(&glfw->atlas, nk_handle_id((int)glfw->ogl.font_tex), &glfw->ogl.null);
|
||||||
|
if (glfw->atlas.default_font)
|
||||||
|
nk_style_set_font(&glfw->ctx, &glfw->atlas.default_font->handle);
|
||||||
|
|
||||||
|
nk_style_load_all_cursors(&glfw->ctx, glfw->atlas.cursors); //< @r-lyeh
|
||||||
|
nk_style_hide_cursor(&glfw->ctx); //< @r-lyeh
|
||||||
|
}
|
||||||
|
|
||||||
|
NK_API void
|
||||||
|
nk_glfw3_new_frame(struct nk_glfw* glfw)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double x, y;
|
||||||
|
struct nk_context *ctx = &glfw->ctx;
|
||||||
|
struct GLFWwindow *win = glfw->win;
|
||||||
|
|
||||||
|
glfwGetWindowSize(win, &glfw->width, &glfw->height);
|
||||||
|
glfwGetFramebufferSize(win, &glfw->display_width, &glfw->display_height);
|
||||||
|
glfw->fb_scale.x = (float)glfw->display_width/(float)glfw->width;
|
||||||
|
glfw->fb_scale.y = (float)glfw->display_height/(float)glfw->height;
|
||||||
|
|
||||||
|
nk_input_begin(ctx);
|
||||||
|
for (i = 0; i < glfw->text_len; ++i)
|
||||||
|
nk_input_unicode(ctx, glfw->text[i]);
|
||||||
|
|
||||||
|
#if NK_GLFW_GL3_MOUSE_GRABBING
|
||||||
|
/* optional grabbing behavior */
|
||||||
|
if (ctx->input.mouse.grab)
|
||||||
|
glfwSetInputMode(glfw->win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||||
|
else if (ctx->input.mouse.ungrab)
|
||||||
|
glfwSetInputMode(glfw->win, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_SCROLL_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_SCROLL_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_SCROLL_DOWN, glfwGetKey(win, GLFW_KEY_PAGE_DOWN) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_SCROLL_UP, glfwGetKey(win, GLFW_KEY_PAGE_UP) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS||
|
||||||
|
glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS);
|
||||||
|
|
||||||
|
if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
|
||||||
|
glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {
|
||||||
|
nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_V) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_TEXT_UNDO, glfwGetKey(win, GLFW_KEY_Z) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_TEXT_REDO, glfwGetKey(win, GLFW_KEY_R) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_TEXT_LINE_START, glfwGetKey(win, GLFW_KEY_B) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_TEXT_LINE_END, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);
|
||||||
|
} else {
|
||||||
|
nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
|
||||||
|
nk_input_key(ctx, NK_KEY_COPY, 0);
|
||||||
|
nk_input_key(ctx, NK_KEY_PASTE, 0);
|
||||||
|
nk_input_key(ctx, NK_KEY_CUT, 0);
|
||||||
|
nk_input_key(ctx, NK_KEY_SHIFT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(glfwGetInputMode(win, GLFW_CURSOR) == GLFW_CURSOR_NORMAL) { //< @r-lyeh: do not grab input when mouse is hidden (fps cam)
|
||||||
|
glfwGetCursorPos(win, &x, &y);
|
||||||
|
nk_input_motion(ctx, (int)x, (int)y);
|
||||||
|
#if NK_GLFW_GL3_MOUSE_GRABBING
|
||||||
|
if (ctx->input.mouse.grabbed) {
|
||||||
|
glfwSetCursorPos(glfw->win, ctx->input.mouse.prev.x, ctx->input.mouse.prev.y);
|
||||||
|
ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
|
||||||
|
ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
|
||||||
|
nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
|
||||||
|
nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
|
||||||
|
nk_input_button(ctx, NK_BUTTON_DOUBLE, glfw->double_click_pos.x, glfw->double_click_pos.y, glfw->is_double_click_down);
|
||||||
|
} //< @r-lyeh
|
||||||
|
nk_input_scroll(ctx, glfw->scroll);
|
||||||
|
nk_input_end(&glfw->ctx);
|
||||||
|
glfw->text_len = 0;
|
||||||
|
glfw->scroll = nk_vec2(0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
NK_API
|
||||||
|
void nk_glfw3_shutdown(struct nk_glfw* glfw)
|
||||||
|
{
|
||||||
|
nk_font_atlas_clear(&glfw->atlas);
|
||||||
|
nk_free(&glfw->ctx);
|
||||||
|
nk_glfw3_device_destroy(glfw);
|
||||||
|
memset(glfw, 0, sizeof(*glfw));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
2943
sfw/render_gui/fwk_ui.c
Normal file
2943
sfw/render_gui/fwk_ui.c
Normal file
File diff suppressed because it is too large
Load Diff
96
sfw/render_gui/fwk_ui.h
Normal file
96
sfw/render_gui/fwk_ui.h
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// immediate ui framework
|
||||||
|
// - rlyeh, public domain
|
||||||
|
//
|
||||||
|
// @todo: logger/console
|
||||||
|
// @todo: surround-adaptive window resizing. ie, surrounding windows adapting theirselves to fit dragged active window
|
||||||
|
|
||||||
|
enum PANEL_FLAGS {
|
||||||
|
PANEL_OPEN = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
API int ui_notify(const char *title, const char *body);
|
||||||
|
API int ui_window(const char *title, int *enabled);
|
||||||
|
API int ui_panel(const char *title, int flags); // may be embedded inside a window, or standalone
|
||||||
|
API int ui_collapse(const char *label, const char *id);
|
||||||
|
API int ui_collapseo(const char *label, const char *id);
|
||||||
|
API int ui_contextual();
|
||||||
|
API int ui_section(const char *title);
|
||||||
|
API int ui_int(const char *label, int *value);
|
||||||
|
API int ui_bool(const char *label, bool *value);
|
||||||
|
API int ui_short(const char *label, short *value);
|
||||||
|
API int ui_float_(const char *label, float *value, float step);
|
||||||
|
API int ui_float2_(const char *label, float value[2], float step);
|
||||||
|
API int ui_float3_(const char *label, float value[3], float step);
|
||||||
|
API int ui_float4_(const char *label, float value[4], float step);
|
||||||
|
API int ui_float(const char *label, float *value);
|
||||||
|
API int ui_float2(const char *label, float value[2]);
|
||||||
|
API int ui_float3(const char *label, float value[3]);
|
||||||
|
API int ui_float4(const char *label, float value[4]);
|
||||||
|
API int ui_mat33(const char *label, float mat33[9]);
|
||||||
|
API int ui_mat34(const char *label, float mat34[12]);
|
||||||
|
API int ui_mat44(const char *label, float mat44[16]);
|
||||||
|
API int ui_double(const char *label, double *value);
|
||||||
|
API int ui_buffer(const char *label, char *buffer, int buflen);
|
||||||
|
API int ui_string(const char *label, char **string);
|
||||||
|
API int ui_color3(const char *label, unsigned *color); //[0..255]
|
||||||
|
API int ui_color3f(const char *label, float color[3]); //[0..1]
|
||||||
|
API int ui_color4(const char *label, unsigned *color); //[0..255]
|
||||||
|
API int ui_color4f(const char *label, float color[4]); //[0..1]
|
||||||
|
API int ui_unsigned(const char *label, unsigned *value);
|
||||||
|
API int ui_unsigned2(const char *label, unsigned *value);
|
||||||
|
API int ui_unsigned3(const char *label, unsigned *value);
|
||||||
|
API int ui_button(const char *label);
|
||||||
|
API int ui_button_transparent(const char *label);
|
||||||
|
API int ui_buttons(int buttons, /*labels*/...);
|
||||||
|
API int ui_toolbar(const char *options); // int choice = ui_toolbar("A;B;C;D");
|
||||||
|
API int ui_submenu(const char *options); // int choice = ui_submenu("A;B;C;D");
|
||||||
|
API int ui_browse(const char **outfile, bool *inlined); // may be embedded inside a window or inside a panel
|
||||||
|
API int ui_toggle(const char *label, bool *value);
|
||||||
|
API int ui_dialog(const char *title, const char *text, int choices, bool *show); // @fixme: return
|
||||||
|
API int ui_list(const char *label, const char **items, int num_items, int *selector);
|
||||||
|
API int ui_radio(const char *label, const char **items, int num_items, int *selector);
|
||||||
|
API int ui_texture(const char *label, texture_t t);
|
||||||
|
API int ui_subtexture(const char *label, texture_t t, unsigned x, unsigned y, unsigned w, unsigned h);
|
||||||
|
API int ui_image(const char *label, handle id, unsigned w, unsigned h); //(w,h) can be 0
|
||||||
|
API int ui_subimage(const char *label, handle id, unsigned iw, unsigned ih, unsigned sx, unsigned sy, unsigned sw, unsigned sh);
|
||||||
|
API int ui_colormap(const char *label, colormap_t *cm); // returns num member changed: 1 for color, 2 for texture map
|
||||||
|
API int ui_separator();
|
||||||
|
API int ui_bitmask8(const char *label, uint8_t *bits);
|
||||||
|
API int ui_bitmask16(const char *label, uint16_t *bits);
|
||||||
|
API int ui_console();
|
||||||
|
API int ui_clampf_(const char *label, float *value, float minf, float maxf, float step);
|
||||||
|
API int ui_clampf(const char *label, float *value, float minf, float maxf);
|
||||||
|
API int ui_label(const char *label);
|
||||||
|
API int ui_label2(const char *label, const char *caption);
|
||||||
|
API int ui_label2_bool(const char *label, bool enabled);
|
||||||
|
API int ui_label2_float(const char *label, float value);
|
||||||
|
API int ui_label2_toolbar(const char *label, const char *icons);
|
||||||
|
API int ui_slider(const char *label, float *value);
|
||||||
|
API int ui_slider2(const char *label, float *value, const char *caption);
|
||||||
|
API int ui_contextual_end(int close);
|
||||||
|
API int ui_collapse_clicked();
|
||||||
|
API int ui_collapse_end();
|
||||||
|
API int ui_panel_end();
|
||||||
|
API int ui_window_end();
|
||||||
|
|
||||||
|
API int ui_show(const char *panel_or_window_title, int enabled);
|
||||||
|
API int ui_dims(const char *panel_or_window_title, float width, float height);
|
||||||
|
API int ui_visible(const char *panel_or_window_title); // @todo: include ui_collapse() items that are open as well?
|
||||||
|
API vec2 ui_get_dims();
|
||||||
|
|
||||||
|
API int ui_enable();
|
||||||
|
API int ui_enabled();
|
||||||
|
API int ui_disable();
|
||||||
|
|
||||||
|
API int ui_has_menubar();
|
||||||
|
API int ui_menu(const char *items); // semicolon-separated or comma-separated items
|
||||||
|
API int ui_menu_editbox(char *buf, int bufcap);
|
||||||
|
API int ui_item();
|
||||||
|
|
||||||
|
API int ui_popups(); // ui_any_popup()? ui_has_popups()?
|
||||||
|
API int ui_hover(); // ui_is_hover()?
|
||||||
|
API int ui_active(); // ui_is_active()?
|
||||||
|
|
||||||
|
API int ui_demo(int do_windows);
|
||||||
|
API void *ui_handle();
|
1160
sfw/render_gui/fwk_window.c
Normal file
1160
sfw/render_gui/fwk_window.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user