123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- /*
- * src/widgets.c
- * https://gitlab.com/bztsrc/smgui
- *
- * Copyright (C) 2024 bzt (bztsrc@gitlab), MIT license
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
- * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
- * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * @brief State-Mode GUI widgets demo program
- */
- #ifdef SKIN
- /* load stb_image to decode png if skin enabled */
- #define STB_IMAGE_IMPLEMENTATION
- #define STBI_NO_STDIO
- #define STBI_NO_LINEAR
- #define STBI_ONLY_PNG
- #include "stb_image.h"
- #endif
- /* test SSFN fonts */
- /*#include <ui_ssfn.h>*/
- /* test custom widgets */
- #include <ui_textosk.h>
- #include <ui_file.h>
- #define UI_IMPLEMENTATION
- #include <ui.h>
- int main(int argc, char **argv)
- {
- /* strings are gathered into an array so that you can change the language on-the-fly */
- enum { WINDOW_TITLE, FILEMENU, LANGMENU, POPUPMENU, NEWITEM, OPENITEM, SAVEITEM, SAVEASITEM, INAITEM, FULLITEM, EXITITEM,
- ENG, HUN, PRESSME, ITEM1, ITEM2, LABELS, INPUTS, ACTIVE, INACTIVE, BUTTONS, FILENAME, FILESIZE, FILEDATE };
- char *eng[] = { "Widgets demo", "File", "Language", "Popups", "New", "Open", "Save", "Save As...", "Inactive", "Fullscreen",
- "Exit", "English", "Hungarian", "Press Me", "Item1", "Item2", "Labels", "Inputs", "Active", "Inactive", "Buttons",
- "Name", "Size", "Modified", "just now", "mins ago", "an hour ago", "hours ago", "yesterday" };
- char *hun[] = { "Vackik demo", "Fajl", "Nyelv", "Ablakok", "Uj", "Megnyitas", "Mentes", "Mentes mint...", "Inaktiv", "Teljeskepernyo",
- "Kilepes", "Angol", "Magyar", "Kattints", "Elem1", "Elem2", "Cimkek", "Bemenetek", "Aktiv", "Inaktiv", "Gombok",
- "Nev", "Meret", "Modositva", "most", "perce", "egy oraja", "oraja", "tegnap" };
- /* variables to store game states */
- int menu_option = 0, button_option = 0, checkbox_option = 0, radio_option = 0;
- int intval = 31, optval = 0;
- int64_t pbarcur = 42;
- float fval = 3.1415;
- char strbuf[64] = { 0 }, *opts[] = { "one", "two", "three" }, pathbuf[PATH_MAX] = { 0 };
- uint32_t color = 0xcf775533;
- /* a hacked image. These should actually be RGBA pixels, but -1U is 0xffffffff, which is full opaque white */
- uint32_t imgbuf[] = {
- 0, 0,-1,-1,-1, 0, 0, 0,
- 0,-1,-1,-1,-1,-1, 0, 0,
- -1,-1, 0,-1, 0,-1,-1, 0,
- -1,-1,-1,-1,-1,-1,-1, 0,
- -1, 0,-1,-1,-1, 0,-1, 0,
- 0,-1, 0, 0, 0,-1, 0, 0,
- 0, 0,-1,-1,-1, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- };
- ui_image_t img = { .w = 8, .h = 8, .p = 8 * 4, .buf = (uint8_t*)&imgbuf };
- /* form referencing those variables */
- ui_event_t *evt;
- ui_t ctx;
- ui_form_t popup[] = {
- { .type = UI_BUTTON, .ptr = &button_option, .m = -1, .value = 1, .label = PRESSME },
- { .type = UI_BUTTON, .flags=UI_DISABLED, .ptr = &button_option, .m = -1, .value = 2, .label = PRESSME },
- { .type = UI_END }
- };
- ui_form_t menu1[] = {
- { .type = UI_RADIO, .flags = UI_NOBULLET, .ptr = &menu_option, .value = 1, .label = NEWITEM },
- { .type = UI_RADIO, .flags = UI_NOBULLET, .ptr = &menu_option, .value = 2, .label = OPENITEM },
- { .type = UI_RADIO, .flags = UI_NOBULLET, .ptr = &menu_option, .value = 3, .label = SAVEITEM },
- { .type = UI_RADIO, .flags = UI_NOBULLET, .ptr = &menu_option, .value = 4, .label = SAVEASITEM },
- { .type = UI_RADIO, .flags = UI_NOBULLET|UI_DISABLED, .label = INAITEM },
- { .type = UI_RADIO, .flags = UI_NOBULLET, .ptr = &menu_option, .value = 5, .label = FULLITEM },
- { .type = UI_RADIO, .flags = UI_NOBULLET, .ptr = &menu_option, .value = 6, .label = EXITITEM },
- { .type = UI_END }
- };
- ui_form_t menu2[] = {
- { .type = UI_RADIO, .flags = UI_NOBULLET, .ptr = &menu_option, .value = 7, .label = ENG },
- { .type = UI_RADIO, .flags = UI_NOBULLET, .ptr = &menu_option, .value = 8, .label = HUN },
- { .type = UI_END }
- };
- ui_form_t menu3[] = {
- { .type = UI_TOGGLE, .flags = UI_NOBULLET, .value = 0, .label = ITEM1 },
- { .type = UI_TOGGLE, .flags = UI_NOBULLET, .value = 1, .label = ITEM2 },
- { .type = UI_END }
- };
- ui_form_t div1[] = { /* labels */
- { .type = UI_LABEL, .label = ITEM1 },
- { .type = UI_DEC32, .w = 20, .ptr = &intval },
- { .type = UI_HEX32, .w = 20, .ptr = &intval },
- { .type = UI_PBAR, .x = 10, .w = 100, .max = 100, .ptr = &pbarcur },
- { .type = UI_DEC_FLOAT, .w = 80, .ptr = &fval },
- { .type = UI_IMAGE, .x = 10, .w = 16, .h = 16, .icon = &img },
- { .type = UI_END }
- };
- ui_form_t div2[] = { /* active inputs */
- { .type = UI_TEXT, .w = UI_PERCENT(20), .ptr = &strbuf, .max = sizeof(strbuf) },
- { .type = UI_SELECT, .x = 10, .m = 17, .ptr = &optval, .optc = sizeof(opts)/sizeof(opts[0]), .optv = opts },
- { .type = UI_OPTION, .x = 10, .m = 17, .ptr = &optval, .optc = sizeof(opts)/sizeof(opts[0]), .optv = opts },
- { .type = UI_INT32, .x = 10, .m = 17, .ptr = &intval, .min = 1, .max = 32 },
- { .type = UI_FLOAT, .x = 10, .m = 17, .ptr = &fval, .fmin = 1.0, .fmax = 32.0, .finc = 0.25 },
- { .type = UI_SLIDER, .x = 10, .ptr = &intval, .w = 60, .min = 1, .max = 32 },
- { .type = UI_VSCRBAR, .x = 10, .ptr = &pbarcur, .h = 60, .max = 100 },
- { .type = UI_HSCRBAR, .x = 10, .ptr = &pbarcur, .w = 60, .max = 100 },
- { .type = UI_COLOR, .x = 10, .ptr = &color },
- { .type = UI_FILE, .w = UI_PERCENT(50), .ptr = &pathbuf, .max = sizeof(pathbuf), .str = FILENAME },
- { .type = UI_END }
- };
- ui_form_t div3[] = { /* inactive inputs */
- { .type = UI_TEXT, .flags = UI_DISABLED, .w = UI_PERCENT(20), .ptr = &strbuf, .max = sizeof(strbuf) },
- { .type = UI_SELECT, .flags = UI_DISABLED, .x = 10, .m = 17, .ptr = &optval, .optc = sizeof(opts)/sizeof(opts[0]), .optv = opts },
- { .type = UI_OPTION, .flags = UI_DISABLED, .x = 10, .m = 17, .ptr = &optval, .optc = sizeof(opts)/sizeof(opts[0]), .optv = opts },
- { .type = UI_INT32, .flags = UI_DISABLED, .x = 10, .m = 17, .ptr = &intval, .min = 1, .max = 32 },
- { .type = UI_FLOAT, .flags = UI_DISABLED, .x = 10, .m = 17, .ptr = &fval, .fmin = 1.0, .fmax = 32.0, .finc = 0.25 },
- { .type = UI_SLIDER, .flags = UI_DISABLED, .x = 10, .ptr = &intval, .w = 60, .min = 1, .max = 32 },
- { .type = UI_VSCRBAR, .flags = UI_DISABLED, .x = 10, .ptr = &pbarcur, .h = 60, .max = 100 },
- { .type = UI_HSCRBAR, .flags = UI_DISABLED, .x = 10, .ptr = &pbarcur, .w = 60, .max = 100 },
- { .type = UI_COLOR, .flags = UI_DISABLED, .x = 10, .ptr = &color },
- { .type = UI_FILE, .flags = UI_DISABLED, .w = UI_PERCENT(50), .ptr = &pathbuf, .max = sizeof(pathbuf), .str = FILENAME },
- { .type = UI_END }
- };
- ui_form_t div4[] = { /* inputs div */
- { .type = UI_TOGGLE, .flags = UI_FORCEBR, .label = ACTIVE },
- { .type = UI_DIV, .flags = UI_FORCEBR, .w = UI_PERCENT(100), .ptr = &div2 },
- { .type = UI_TOGGLE, .flags = UI_FORCEBR, .label = INACTIVE },
- { .type = UI_DIV, .flags = UI_FORCEBR, .w = UI_PERCENT(100), .ptr = &div3 },
- { .type = UI_END }
- };
- ui_form_t div5[] = { /* active buttons */
- { .type = UI_CHECK, .ptr = &checkbox_option, .value = 1, .label = ITEM1 },
- { .type = UI_RADIO, .ptr = &radio_option, .x = 10, .value = 0, .label = ITEM1 },
- { .type = UI_RADIO, .ptr = &radio_option, .value = 1, .label = ITEM2 },
- { .type = UI_BTNTGL, .value = 0, .x = 10, .m = -1, .icon = &img, .label = ITEM1 },
- { .type = UI_BTNICN, .ptr = &checkbox_option, .value = 1, .x = 10, .icon = &img },
- { .type = UI_END }
- };
- ui_form_t div6[] = { /* inactive buttons */
- { .type = UI_CHECK, .flags = UI_DISABLED, .ptr = &checkbox_option, .value = 1, .label = ITEM1 },
- { .type = UI_RADIO, .flags = UI_DISABLED, .ptr = &radio_option, .x = 10, .value = 0, .label = ITEM1 },
- { .type = UI_RADIO, .flags = UI_DISABLED, .ptr = &radio_option, .value = 1, .label = ITEM2 },
- { .type = UI_BTNTGL, .flags = UI_DISABLED, .value = 0, .x = 10, .m = -1, .icon = &img, .label = ITEM1 },
- { .type = UI_BTNICN, .flags = UI_DISABLED, .ptr = &checkbox_option, .value = 1, .x = 10, .icon = &img },
- { .type = UI_END }
- };
- ui_form_t div7[] = { /* buttons div */
- { .type = UI_TOGGLE, .flags = UI_FORCEBR, .label = ACTIVE },
- { .type = UI_DIV, .flags = UI_FORCEBR, .w = UI_PERCENT(100), .ptr = &div5 },
- { .type = UI_TOGGLE, .flags = UI_FORCEBR, .label = INACTIVE },
- { .type = UI_DIV, .flags = UI_FORCEBR, .w = UI_PERCENT(100), .ptr = &div6 },
- { .type = UI_END }
- };
- ui_form_t form[] = {
- /* arbitrary popups (controlled from menu3) */
- { .type = UI_POPUP, .flags = UI_HIDDEN | UI_DRAGGABLE | UI_RESIZABLE | UI_SCROLL,
- .align = UI_CENTER | UI_MIDDLE, .x = UI_PERCENT(50), .y = UI_PERCENT(50),
- .m = 10, .p = 10, .ptr = &popup },
- { .type = UI_POPUP, .flags = UI_HIDDEN | UI_DRAGGABLE | UI_RESIZABLE | UI_ALTSKIN,
- .x = UI_ABS(100), .y = UI_ABS(100), .w = 32, .m = 10 },
- /* menus, toggle fields in normal flow, menu containers are not */
- { .type = UI_TOGGLE, .flags = UI_NOBULLET | UI_ALTSKIN, .x = 10, .m = 8, .label = FILEMENU },
- { .type = UI_MENU, .m = 4, .ptr = &menu1 },
- { .type = UI_TOGGLE, .flags = UI_NOBULLET | UI_ALTSKIN, .x = 10, .m = 8, .label = LANGMENU },
- { .type = UI_MENU, .m = 4, .ptr = &menu2 },
- { .type = UI_TOGGLE, .flags = UI_NOBULLET | UI_ALTSKIN | UI_FORCEBR, .x = 10, .m = 8, .label = POPUPMENU },
- { .type = UI_MENU, .m = 4, .ptr = &menu3 },
- /* main content, "tree" with toggles and divs */
- { .type = UI_TOGGLE, .flags = UI_FORCEBR, .label = LABELS },
- { .type = UI_DIV, .flags = UI_FORCEBR, .w = UI_PERCENT(100), .ptr = &div1 },
- { .type = UI_TOGGLE, .flags = UI_FORCEBR, .label = INPUTS },
- { .type = UI_DIV, .flags = UI_FORCEBR, .w = UI_PERCENT(100), .ptr = &div4 },
- { .type = UI_TOGGLE, .flags = UI_FORCEBR, .label = BUTTONS },
- { .type = UI_DIV, .flags = UI_FORCEBR, .w = UI_PERCENT(100), .ptr = &div7 },
- { .type = UI_END }
- };
- #ifdef SSFN_IMPLEMENTATION
- ssfn_t fnt = { 0 };
- #endif
- #if defined(SKIN) || defined(SSFN_IMPLEMENTATION)
- FILE *f;
- uint8_t *buf = NULL;
- int size = 0;
- #endif
- #ifdef SKIN
- /* load png */
- if((f = fopen("skin.png", "rb"))) {
- fseek(f, 0, SEEK_END); size = (int)ftell(f); fseek(f, 0, SEEK_SET);
- if((buf = malloc(size))) fread(buf, 1, size, f);
- fclose(f);
- }
- #endif
- /* initialize the UI context, pass it the string array, the window size and icon */
- ui_init(&ctx, sizeof(eng)/sizeof(eng[0]), eng, 640, 480, NULL);
- #ifdef SKIN
- /* decode png and load skin into UI context */
- if(buf) {
- ui_pngskin(&ctx, buf, size);
- free(buf);
- }
- #endif
- #ifdef SSFN_IMPLEMENTATION
- /* load SSFN font */
- if((f = fopen(argv[1] ? argv[1] : "unifont.sfn.gz", "rb"))) {
- fseek(f, 0, SEEK_END); size = (int)ftell(f); fseek(f, 0, SEEK_SET);
- if((buf = malloc(size))) fread(buf, 1, size, f);
- fclose(f);
- }
- if(buf) {
- ssfn_load(&fnt, buf);
- free(buf);
- ssfn_select(&fnt, SSFN_FAMILY_ANY, NULL, SSFN_STYLE_REGULAR, 16);
- ui_font(&ctx, &fnt);
- }
- #endif
- while(1) {
- /* "draw" something on screen */
- glClearColor(0.0, 0.0, 0.25, 1.0);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- /* get events and exit if user closed the window or pressed Esc (should be '\e', but not all compilers like that) */
- if(!(evt = ui_event(&ctx, form)) || (evt->type == UI_EVT_KEY && evt->key[0] == 0x1b)) break;
- /* handle menus */
- if(menu_option) {
- printf("menu option %d selected\n", menu_option);
- switch(menu_option) {
- case 5: ui_fullscreen(&ctx); break;
- case 7: ui_settxt(&ctx, eng); break;
- case 8: ui_settxt(&ctx, hun); break;
- }
- menu_option = 0;
- /* no need to refresh, menu is closed automatically */
- }
- /* handle buttons */
- if(button_option) {
- printf("button option %d clicked\n", button_option);
- /* do processing stuff, the button is left pressed */
- /*...*/
- /* assume we have finished, unpress the button */
- button_option = 0;
- ui_refresh(&ctx);
- }
- }
- /* destroy window, free resources */
- ui_free(&ctx);
- (void)argc; (void)argv;
- return 0;
- }
- #if defined(__WIN32__) && defined(SDL_h_)
- int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
- {
- char *argv[] = { "widgets.exe", NULL };
- (void)hInstance; (void)hPrevInstance; (void)lpCmdLine; (void)nCmdShow;
- return main(1, argv);
- }
- #endif
|