diff --git a/.appveyor.yml b/.appveyor.yml index 5fb0da67..000b8572 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,15 +1,53 @@ -version: "{build}" environment: global: E2D_WITHOUT_AUDIO: true E2D_WITHOUT_GRAPHICS: true + image: - Visual Studio 2017 - Visual Studio 2019 + platform: - - Win32 + - x86 - x64 -build_script: + +configuration: + - Debug + - Release + +for: + +- + matrix: + only: + - platform: x86 + configuration: Debug + build_script: + - scripts\build_debug_x86.bat + +- + matrix: + only: + - platform: x64 + configuration: Debug + build_script: + - scripts\build_debug_x64.bat + +- + matrix: + only: + - platform: x86 + configuration: Release + build_script: + - scripts\build_release_x86.bat + +- + matrix: + only: + - platform: x64 + configuration: Release + build_script: + - scripts\build_release_x64.bat + +before_build: - git submodule update --init --recursive - - scripts\build_release.bat -test: off diff --git a/.travis.yml b/.travis.yml index 19311380..baddf363 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,55 +1,149 @@ language: cpp + env: global: - E2D_WITHOUT_AUDIO=true - E2D_WITHOUT_GRAPHICS=true + matrix: include: + + # + # linux (g++-7) + # + - os: linux - dist: trusty - addons: { apt: { sources: ubuntu-toolchain-r-test, packages: ["xorg-dev", "g++-7"] } } - env: MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" + dist: xenial + stage: linux + name: debug, g++-7 + addons: { apt: { sources: ["ubuntu-toolchain-r-test"], packages: ["libx11-dev", "libgl1-mesa-dev", "xorg-dev", "g++-7"] } } + env: CC=gcc-7 CXX=g++-7 + script: ./scripts/build_debug.sh + - os: linux - dist: trusty - addons: { apt: { sources: ubuntu-toolchain-r-test, packages: ["xorg-dev", "g++-8"] } } - env: MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" + dist: xenial + stage: linux + name: release, g++-7 + addons: { apt: { sources: ["ubuntu-toolchain-r-test"], packages: ["libx11-dev", "libgl1-mesa-dev", "xorg-dev", "g++-7"] } } + env: CC=gcc-7 CXX=g++-7 + script: ./scripts/build_release.sh + + # + # linux (g++-8) + # + - os: linux - dist: trusty - addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-5.0"], packages: ["xorg-dev", "clang-5.0", "g++-7"] } } - env: MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0" + dist: xenial + stage: linux + name: debug, g++-8 + addons: { apt: { sources: ["ubuntu-toolchain-r-test"], packages: ["libx11-dev", "libgl1-mesa-dev", "xorg-dev", "g++-8"] } } + env: CC=gcc-8 CXX=g++-8 + script: ./scripts/build_debug.sh + - os: linux - dist: trusty - addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-6.0"], packages: ["xorg-dev", "clang-6.0", "g++-7"] } } - env: MATRIX_EVAL="CC=clang-6.0 && CXX=clang++-6.0" + dist: xenial + stage: linux + name: release, g++-8 + addons: { apt: { sources: ["ubuntu-toolchain-r-test"], packages: ["libx11-dev", "libgl1-mesa-dev", "xorg-dev", "g++-8"] } } + env: CC=gcc-8 CXX=g++-8 + script: ./scripts/build_release.sh + + # + # linux (clang++-5.0) + # + - os: linux - dist: trusty - addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-7"], packages: ["xorg-dev", "clang-7", "g++-7"] } } - env: MATRIX_EVAL="CC=clang-7 && CXX=clang++-7" + dist: xenial + stage: linux + name: debug, clang++-5.0 + addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-xenial-5.0"], packages: ["libx11-dev", "libgl1-mesa-dev", "xorg-dev", "g++-7", "clang-5.0"] } } + env: CC=clang-5.0 CXX=clang++-5.0 + script: ./scripts/build_debug.sh + - os: linux - dist: trusty - addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-8"], packages: ["xorg-dev", "clang-8", "g++-7"] } } - env: MATRIX_EVAL="CC=clang-8 && CXX=clang++-8" + dist: xenial + stage: linux + name: release, clang++-5.0 + addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-xenial-5.0"], packages: ["libx11-dev", "libgl1-mesa-dev", "xorg-dev", "g++-7", "clang-5.0"] } } + env: CC=clang-5.0 CXX=clang++-5.0 + script: ./scripts/build_release.sh + + # + # linux (clang++-6.0) + # + + - os: linux + dist: xenial + stage: linux + name: debug, clang++-6.0 + addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-xenial-6.0"], packages: ["libx11-dev", "libgl1-mesa-dev", "xorg-dev", "g++-7", "clang-6.0"] } } + env: CC=clang-6.0 CXX=clang++-6.0 + script: ./scripts/build_debug.sh + + - os: linux + dist: xenial + stage: linux + name: release, clang++-6.0 + addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-xenial-6.0"], packages: ["libx11-dev", "libgl1-mesa-dev", "xorg-dev", "g++-7", "clang-6.0"] } } + env: CC=clang-6.0 CXX=clang++-6.0 + script: ./scripts/build_release.sh + + # + # macosx (xcode10) + # + - os: osx osx_image: xcode10 - compiler: clang - addons: { homebrew: { packages: ["lcov"] } } - after_success: ./scripts/upload_coverage.sh + stage: macosx + name: debug, xcode10 + addons: { homebrew: { packages: ["git-lfs"] } } + script: ./scripts/build_debug.sh + + - os: osx + osx_image: xcode10 + stage: macosx + name: release, xcode10 + addons: { homebrew: { packages: ["git-lfs"] } } + script: ./scripts/build_release.sh + + # + # macosx (xcode11) + # + + - os: osx + osx_image: xcode11 + stage: macosx + name: debug, xcode11 + addons: { homebrew: { packages: ["git-lfs"] } } + script: ./scripts/build_debug.sh + + - os: osx + osx_image: xcode11 + stage: macosx + name: release, xcode11 + addons: { homebrew: { packages: ["git-lfs"] } } + script: ./scripts/build_release.sh + + # + # coverage + # + + - os: osx + osx_image: xcode10 + stage: coverage + name: coverage, xcode10 + addons: { homebrew: { packages: ["git-lfs", "lcov"] } } + script: ./scripts/upload_coverage.sh + before_install: - - eval "${MATRIX_EVAL}" - - if [ "$TRAVIS_OS_NAME" == 'osx' ]; then - brew update; - brew upgrade cmake; - brew install git-lfs; - fi - if [ "$TRAVIS_OS_NAME" == 'linux' ]; then mkdir $HOME/cmake; export PATH="$HOME/cmake/bin:$PATH"; travis_retry wget -q https://cmake.org/files/v3.11/cmake-3.11.4-Linux-x86_64.sh; sh cmake-3.11.4-Linux-x86_64.sh --prefix=$HOME/cmake --exclude-subdir --skip-license; fi + before_script: - git submodule update --init --recursive - git lfs install - git lfs pull -script: - - ./scripts/build_release.sh diff --git a/headers/3rdparty/lua/ltests.c b/headers/3rdparty/lua/ltests.c deleted file mode 100644 index bfc102ea..00000000 --- a/headers/3rdparty/lua/ltests.c +++ /dev/null @@ -1,1570 +0,0 @@ -/* -** $Id: ltests.c,v 2.211.1.1 2017/04/19 17:39:34 roberto Exp $ -** Internal Module for Debugging of the Lua Implementation -** See Copyright Notice in lua.h -*/ - -#define ltests_c -#define LUA_CORE - -#include "lprefix.h" - - -#include -#include -#include -#include -#include - -#include "lua.h" - -#include "lapi.h" -#include "lauxlib.h" -#include "lcode.h" -#include "lctype.h" -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lmem.h" -#include "lopcodes.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "lualib.h" - - - -/* -** The whole module only makes sense with LUA_DEBUG on -*/ -#if defined(LUA_DEBUG) - - -void *l_Trick = 0; - - -int islocked = 0; - - -#define obj_at(L,k) (L->ci->func + (k)) - - -static int runC (lua_State *L, lua_State *L1, const char *pc); - - -static void setnameval (lua_State *L, const char *name, int val) { - lua_pushstring(L, name); - lua_pushinteger(L, val); - lua_settable(L, -3); -} - - -static void pushobject (lua_State *L, const TValue *o) { - setobj2s(L, L->top, o); - api_incr_top(L); -} - - -static int tpanic (lua_State *L) { - fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", - lua_tostring(L, -1)); - return (exit(EXIT_FAILURE), 0); /* do not return to Lua */ -} - - -/* -** {====================================================================== -** Controlled version for realloc. -** ======================================================================= -*/ - -#define MARK 0x55 /* 01010101 (a nice pattern) */ - -typedef union Header { - L_Umaxalign a; /* ensures maximum alignment for Header */ - struct { - size_t size; - int type; - } d; -} Header; - - -#if !defined(EXTERNMEMCHECK) - -/* full memory check */ -#define MARKSIZE 16 /* size of marks after each block */ -#define fillmem(mem,size) memset(mem, -MARK, size) - -#else - -/* external memory check: don't do it twice */ -#define MARKSIZE 0 -#define fillmem(mem,size) /* empty */ - -#endif - - -Memcontrol l_memcontrol = - {0L, 0L, 0L, 0L, {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}}; - - -static void freeblock (Memcontrol *mc, Header *block) { - if (block) { - size_t size = block->d.size; - int i; - for (i = 0; i < MARKSIZE; i++) /* check marks after block */ - lua_assert(*(cast(char *, block + 1) + size + i) == MARK); - mc->objcount[block->d.type]--; - fillmem(block, sizeof(Header) + size + MARKSIZE); /* erase block */ - free(block); /* actually free block */ - mc->numblocks--; /* update counts */ - mc->total -= size; - } -} - - -void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) { - Memcontrol *mc = cast(Memcontrol *, ud); - Header *block = cast(Header *, b); - int type; - if (mc->memlimit == 0) { /* first time? */ - char *limit = getenv("MEMLIMIT"); /* initialize memory limit */ - mc->memlimit = limit ? strtoul(limit, NULL, 10) : ULONG_MAX; - } - if (block == NULL) { - type = (oldsize < LUA_NUMTAGS) ? oldsize : 0; - oldsize = 0; - } - else { - block--; /* go to real header */ - type = block->d.type; - lua_assert(oldsize == block->d.size); - } - if (size == 0) { - freeblock(mc, block); - return NULL; - } - else if (size > oldsize && mc->total+size-oldsize > mc->memlimit) - return NULL; /* fake a memory allocation error */ - else { - Header *newblock; - int i; - size_t commonsize = (oldsize < size) ? oldsize : size; - size_t realsize = sizeof(Header) + size + MARKSIZE; - if (realsize < size) return NULL; /* arithmetic overflow! */ - newblock = cast(Header *, malloc(realsize)); /* alloc a new block */ - if (newblock == NULL) return NULL; /* really out of memory? */ - if (block) { - memcpy(newblock + 1, block + 1, commonsize); /* copy old contents */ - freeblock(mc, block); /* erase (and check) old copy */ - } - /* initialize new part of the block with something weird */ - fillmem(cast(char *, newblock + 1) + commonsize, size - commonsize); - /* initialize marks after block */ - for (i = 0; i < MARKSIZE; i++) - *(cast(char *, newblock + 1) + size + i) = MARK; - newblock->d.size = size; - newblock->d.type = type; - mc->total += size; - if (mc->total > mc->maxmem) - mc->maxmem = mc->total; - mc->numblocks++; - mc->objcount[type]++; - return newblock + 1; - } -} - - -/* }====================================================================== */ - - - -/* -** {====================================================== -** Functions to check memory consistency -** ======================================================= -*/ - - -static int testobjref1 (global_State *g, GCObject *f, GCObject *t) { - if (isdead(g,t)) return 0; - if (!issweepphase(g)) - return !(isblack(f) && iswhite(t)); - else return 1; -} - - -static void printobj (global_State *g, GCObject *o) { - printf("||%s(%p)-%c(%02X)||", - ttypename(novariant(o->tt)), (void *)o, - isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', o->marked); -} - - -static int testobjref (global_State *g, GCObject *f, GCObject *t) { - int r1 = testobjref1(g, f, t); - if (!r1) { - printf("%d(%02X) - ", g->gcstate, g->currentwhite); - printobj(g, f); - printf(" -> "); - printobj(g, t); - printf("\n"); - } - return r1; -} - -#define checkobjref(g,f,t) \ - { if (t) lua_longassert(testobjref(g,f,obj2gco(t))); } - - -static void checkvalref (global_State *g, GCObject *f, const TValue *t) { - lua_assert(!iscollectable(t) || - (righttt(t) && testobjref(g, f, gcvalue(t)))); -} - - -static void checktable (global_State *g, Table *h) { - unsigned int i; - Node *n, *limit = gnode(h, sizenode(h)); - GCObject *hgc = obj2gco(h); - checkobjref(g, hgc, h->metatable); - for (i = 0; i < h->sizearray; i++) - checkvalref(g, hgc, &h->array[i]); - for (n = gnode(h, 0); n < limit; n++) { - if (!ttisnil(gval(n))) { - lua_assert(!ttisnil(gkey(n))); - checkvalref(g, hgc, gkey(n)); - checkvalref(g, hgc, gval(n)); - } - } -} - - -/* -** All marks are conditional because a GC may happen while the -** prototype is still being created -*/ -static void checkproto (global_State *g, Proto *f) { - int i; - GCObject *fgc = obj2gco(f); - checkobjref(g, fgc, f->cache); - checkobjref(g, fgc, f->source); - for (i=0; isizek; i++) { - if (ttisstring(f->k + i)) - checkobjref(g, fgc, tsvalue(f->k + i)); - } - for (i=0; isizeupvalues; i++) - checkobjref(g, fgc, f->upvalues[i].name); - for (i=0; isizep; i++) - checkobjref(g, fgc, f->p[i]); - for (i=0; isizelocvars; i++) - checkobjref(g, fgc, f->locvars[i].varname); -} - - - -static void checkCclosure (global_State *g, CClosure *cl) { - GCObject *clgc = obj2gco(cl); - int i; - for (i = 0; i < cl->nupvalues; i++) - checkvalref(g, clgc, &cl->upvalue[i]); -} - - -static void checkLclosure (global_State *g, LClosure *cl) { - GCObject *clgc = obj2gco(cl); - int i; - checkobjref(g, clgc, cl->p); - for (i=0; inupvalues; i++) { - UpVal *uv = cl->upvals[i]; - if (uv) { - if (!upisopen(uv)) /* only closed upvalues matter to invariant */ - checkvalref(g, clgc, uv->v); - lua_assert(uv->refcount > 0); - } - } -} - - -static int lua_checkpc (lua_State *L, CallInfo *ci) { - if (!isLua(ci)) return 1; - else { - /* if function yielded (inside a hook), real 'func' is in 'extra' field */ - StkId f = (L->status != LUA_YIELD || ci != L->ci) - ? ci->func - : restorestack(L, ci->extra); - Proto *p = clLvalue(f)->p; - return p->code <= ci->u.l.savedpc && - ci->u.l.savedpc <= p->code + p->sizecode; - } -} - - -static void checkstack (global_State *g, lua_State *L1) { - StkId o; - CallInfo *ci; - UpVal *uv; - lua_assert(!isdead(g, L1)); - for (uv = L1->openupval; uv != NULL; uv = uv->u.open.next) - lua_assert(upisopen(uv)); /* must be open */ - for (ci = L1->ci; ci != NULL; ci = ci->previous) { - lua_assert(ci->top <= L1->stack_last); - lua_assert(lua_checkpc(L1, ci)); - } - if (L1->stack) { /* complete thread? */ - for (o = L1->stack; o < L1->stack_last + EXTRA_STACK; o++) - checkliveness(L1, o); /* entire stack must have valid values */ - } - else lua_assert(L1->stacksize == 0); -} - - -static void checkobject (global_State *g, GCObject *o, int maybedead) { - if (isdead(g, o)) - lua_assert(maybedead); - else { - lua_assert(g->gcstate != GCSpause || iswhite(o)); - switch (o->tt) { - case LUA_TUSERDATA: { - TValue uservalue; - Table *mt = gco2u(o)->metatable; - checkobjref(g, o, mt); - getuservalue(g->mainthread, gco2u(o), &uservalue); - checkvalref(g, o, &uservalue); - break; - } - case LUA_TTABLE: { - checktable(g, gco2t(o)); - break; - } - case LUA_TTHREAD: { - checkstack(g, gco2th(o)); - break; - } - case LUA_TLCL: { - checkLclosure(g, gco2lcl(o)); - break; - } - case LUA_TCCL: { - checkCclosure(g, gco2ccl(o)); - break; - } - case LUA_TPROTO: { - checkproto(g, gco2p(o)); - break; - } - case LUA_TSHRSTR: - case LUA_TLNGSTR: { - lua_assert(!isgray(o)); /* strings are never gray */ - break; - } - default: lua_assert(0); - } - } -} - - -#define TESTGRAYBIT 7 - -static void checkgraylist (global_State *g, GCObject *o) { - ((void)g); /* better to keep it available if we need to print an object */ - while (o) { - lua_assert(isgray(o)); - lua_assert(!testbit(o->marked, TESTGRAYBIT)); - l_setbit(o->marked, TESTGRAYBIT); - switch (o->tt) { - case LUA_TTABLE: o = gco2t(o)->gclist; break; - case LUA_TLCL: o = gco2lcl(o)->gclist; break; - case LUA_TCCL: o = gco2ccl(o)->gclist; break; - case LUA_TTHREAD: o = gco2th(o)->gclist; break; - case LUA_TPROTO: o = gco2p(o)->gclist; break; - default: lua_assert(0); /* other objects cannot be gray */ - } - } -} - - -/* -** mark all objects in gray lists with the TESTGRAYBIT, so that -** 'checkmemory' can check that all gray objects are in a gray list -*/ -static void markgrays (global_State *g) { - if (!keepinvariant(g)) return; - checkgraylist(g, g->gray); - checkgraylist(g, g->grayagain); - checkgraylist(g, g->weak); - checkgraylist(g, g->ephemeron); - checkgraylist(g, g->allweak); -} - - -static void checkgray (global_State *g, GCObject *o) { - for (; o != NULL; o = o->next) { - if (isgray(o)) { - lua_assert(!keepinvariant(g) || testbit(o->marked, TESTGRAYBIT)); - resetbit(o->marked, TESTGRAYBIT); - } - lua_assert(!testbit(o->marked, TESTGRAYBIT)); - } -} - - -int lua_checkmemory (lua_State *L) { - global_State *g = G(L); - GCObject *o; - int maybedead; - if (keepinvariant(g)) { - lua_assert(!iswhite(g->mainthread)); - lua_assert(!iswhite(gcvalue(&g->l_registry))); - } - lua_assert(!isdead(g, gcvalue(&g->l_registry))); - checkstack(g, g->mainthread); - resetbit(g->mainthread->marked, TESTGRAYBIT); - lua_assert(g->sweepgc == NULL || issweepphase(g)); - markgrays(g); - /* check 'fixedgc' list */ - for (o = g->fixedgc; o != NULL; o = o->next) { - lua_assert(o->tt == LUA_TSHRSTR && isgray(o)); - } - /* check 'allgc' list */ - checkgray(g, g->allgc); - maybedead = (GCSatomic < g->gcstate && g->gcstate <= GCSswpallgc); - for (o = g->allgc; o != NULL; o = o->next) { - checkobject(g, o, maybedead); - lua_assert(!tofinalize(o)); - } - /* check 'finobj' list */ - checkgray(g, g->finobj); - for (o = g->finobj; o != NULL; o = o->next) { - checkobject(g, o, 0); - lua_assert(tofinalize(o)); - lua_assert(o->tt == LUA_TUSERDATA || o->tt == LUA_TTABLE); - } - /* check 'tobefnz' list */ - checkgray(g, g->tobefnz); - for (o = g->tobefnz; o != NULL; o = o->next) { - checkobject(g, o, 0); - lua_assert(tofinalize(o)); - lua_assert(o->tt == LUA_TUSERDATA || o->tt == LUA_TTABLE); - } - return 0; -} - -/* }====================================================== */ - - - -/* -** {====================================================== -** Disassembler -** ======================================================= -*/ - - -static char *buildop (Proto *p, int pc, char *buff) { - Instruction i = p->code[pc]; - OpCode o = GET_OPCODE(i); - const char *name = luaP_opnames[o]; - int line = getfuncline(p, pc); - sprintf(buff, "(%4d) %4d - ", line, pc); - switch (getOpMode(o)) { - case iABC: - sprintf(buff+strlen(buff), "%-12s%4d %4d %4d", name, - GETARG_A(i), GETARG_B(i), GETARG_C(i)); - break; - case iABx: - sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_Bx(i)); - break; - case iAsBx: - sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_sBx(i)); - break; - case iAx: - sprintf(buff+strlen(buff), "%-12s%4d", name, GETARG_Ax(i)); - break; - } - return buff; -} - - -#if 0 -void luaI_printcode (Proto *pt, int size) { - int pc; - for (pc=0; pcmaxstacksize); - setnameval(L, "numparams", p->numparams); - for (pc=0; pcsizecode; pc++) { - char buff[100]; - lua_pushinteger(L, pc+1); - lua_pushstring(L, buildop(p, pc, buff)); - lua_settable(L, -3); - } - return 1; -} - - -static int listk (lua_State *L) { - Proto *p; - int i; - luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), - 1, "Lua function expected"); - p = getproto(obj_at(L, 1)); - lua_createtable(L, p->sizek, 0); - for (i=0; isizek; i++) { - pushobject(L, p->k+i); - lua_rawseti(L, -2, i+1); - } - return 1; -} - - -static int listlocals (lua_State *L) { - Proto *p; - int pc = cast_int(luaL_checkinteger(L, 2)) - 1; - int i = 0; - const char *name; - luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), - 1, "Lua function expected"); - p = getproto(obj_at(L, 1)); - while ((name = luaF_getlocalname(p, ++i, pc)) != NULL) - lua_pushstring(L, name); - return i-1; -} - -/* }====================================================== */ - - - -static void printstack (lua_State *L) { - int i; - int n = lua_gettop(L); - for (i = 1; i <= n; i++) { - printf("%3d: %s\n", i, luaL_tolstring(L, i, NULL)); - lua_pop(L, 1); - } - printf("\n"); -} - - -static int get_limits (lua_State *L) { - lua_createtable(L, 0, 5); - setnameval(L, "BITS_INT", LUAI_BITSINT); - setnameval(L, "MAXARG_Ax", MAXARG_Ax); - setnameval(L, "MAXARG_Bx", MAXARG_Bx); - setnameval(L, "MAXARG_sBx", MAXARG_sBx); - setnameval(L, "BITS_INT", LUAI_BITSINT); - setnameval(L, "LFPF", LFIELDS_PER_FLUSH); - setnameval(L, "NUM_OPCODES", NUM_OPCODES); - return 1; -} - - -static int mem_query (lua_State *L) { - if (lua_isnone(L, 1)) { - lua_pushinteger(L, l_memcontrol.total); - lua_pushinteger(L, l_memcontrol.numblocks); - lua_pushinteger(L, l_memcontrol.maxmem); - return 3; - } - else if (lua_isnumber(L, 1)) { - unsigned long limit = cast(unsigned long, luaL_checkinteger(L, 1)); - if (limit == 0) limit = ULONG_MAX; - l_memcontrol.memlimit = limit; - return 0; - } - else { - const char *t = luaL_checkstring(L, 1); - int i; - for (i = LUA_NUMTAGS - 1; i >= 0; i--) { - if (strcmp(t, ttypename(i)) == 0) { - lua_pushinteger(L, l_memcontrol.objcount[i]); - return 1; - } - } - return luaL_error(L, "unkown type '%s'", t); - } -} - - -static int settrick (lua_State *L) { - if (ttisnil(obj_at(L, 1))) - l_Trick = NULL; - else - l_Trick = gcvalue(obj_at(L, 1)); - return 0; -} - - -static int gc_color (lua_State *L) { - TValue *o; - luaL_checkany(L, 1); - o = obj_at(L, 1); - if (!iscollectable(o)) - lua_pushstring(L, "no collectable"); - else { - GCObject *obj = gcvalue(o); - lua_pushstring(L, isdead(G(L), obj) ? "dead" : - iswhite(obj) ? "white" : - isblack(obj) ? "black" : "grey"); - } - return 1; -} - - -static int gc_state (lua_State *L) { - static const char *statenames[] = {"propagate", "atomic", "sweepallgc", - "sweepfinobj", "sweeptobefnz", "sweepend", "pause", ""}; - static const int states[] = {GCSpropagate, GCSatomic, GCSswpallgc, - GCSswpfinobj, GCSswptobefnz, GCSswpend, GCSpause, -1}; - int option = states[luaL_checkoption(L, 1, "", statenames)]; - if (option == -1) { - lua_pushstring(L, statenames[G(L)->gcstate]); - return 1; - } - else { - global_State *g = G(L); - lua_lock(L); - if (option < g->gcstate) { /* must cross 'pause'? */ - luaC_runtilstate(L, bitmask(GCSpause)); /* run until pause */ - } - luaC_runtilstate(L, bitmask(option)); - lua_assert(G(L)->gcstate == option); - lua_unlock(L); - return 0; - } -} - - -static int hash_query (lua_State *L) { - if (lua_isnone(L, 2)) { - luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected"); - lua_pushinteger(L, tsvalue(obj_at(L, 1))->hash); - } - else { - TValue *o = obj_at(L, 1); - Table *t; - luaL_checktype(L, 2, LUA_TTABLE); - t = hvalue(obj_at(L, 2)); - lua_pushinteger(L, luaH_mainposition(t, o) - t->node); - } - return 1; -} - - -static int stacklevel (lua_State *L) { - unsigned long a = 0; - lua_pushinteger(L, (L->top - L->stack)); - lua_pushinteger(L, (L->stack_last - L->stack)); - lua_pushinteger(L, (unsigned long)&a); - return 3; -} - - -static int table_query (lua_State *L) { - const Table *t; - int i = cast_int(luaL_optinteger(L, 2, -1)); - luaL_checktype(L, 1, LUA_TTABLE); - t = hvalue(obj_at(L, 1)); - if (i == -1) { - lua_pushinteger(L, t->sizearray); - lua_pushinteger(L, allocsizenode(t)); - lua_pushinteger(L, isdummy(t) ? 0 : t->lastfree - t->node); - } - else if ((unsigned int)i < t->sizearray) { - lua_pushinteger(L, i); - pushobject(L, &t->array[i]); - lua_pushnil(L); - } - else if ((i -= t->sizearray) < sizenode(t)) { - if (!ttisnil(gval(gnode(t, i))) || - ttisnil(gkey(gnode(t, i))) || - ttisnumber(gkey(gnode(t, i)))) { - pushobject(L, gkey(gnode(t, i))); - } - else - lua_pushliteral(L, ""); - pushobject(L, gval(gnode(t, i))); - if (gnext(&t->node[i]) != 0) - lua_pushinteger(L, gnext(&t->node[i])); - else - lua_pushnil(L); - } - return 3; -} - - -static int string_query (lua_State *L) { - stringtable *tb = &G(L)->strt; - int s = cast_int(luaL_optinteger(L, 1, 0)) - 1; - if (s == -1) { - lua_pushinteger(L ,tb->size); - lua_pushinteger(L ,tb->nuse); - return 2; - } - else if (s < tb->size) { - TString *ts; - int n = 0; - for (ts = tb->hash[s]; ts != NULL; ts = ts->u.hnext) { - setsvalue2s(L, L->top, ts); - api_incr_top(L); - n++; - } - return n; - } - else return 0; -} - - -static int tref (lua_State *L) { - int level = lua_gettop(L); - luaL_checkany(L, 1); - lua_pushvalue(L, 1); - lua_pushinteger(L, luaL_ref(L, LUA_REGISTRYINDEX)); - lua_assert(lua_gettop(L) == level+1); /* +1 for result */ - return 1; -} - -static int getref (lua_State *L) { - int level = lua_gettop(L); - lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_checkinteger(L, 1)); - lua_assert(lua_gettop(L) == level+1); - return 1; -} - -static int unref (lua_State *L) { - int level = lua_gettop(L); - luaL_unref(L, LUA_REGISTRYINDEX, cast_int(luaL_checkinteger(L, 1))); - lua_assert(lua_gettop(L) == level); - return 0; -} - - -static int upvalue (lua_State *L) { - int n = cast_int(luaL_checkinteger(L, 2)); - luaL_checktype(L, 1, LUA_TFUNCTION); - if (lua_isnone(L, 3)) { - const char *name = lua_getupvalue(L, 1, n); - if (name == NULL) return 0; - lua_pushstring(L, name); - return 2; - } - else { - const char *name = lua_setupvalue(L, 1, n); - lua_pushstring(L, name); - return 1; - } -} - - -static int newuserdata (lua_State *L) { - size_t size = cast(size_t, luaL_checkinteger(L, 1)); - char *p = cast(char *, lua_newuserdata(L, size)); - while (size--) *p++ = '\0'; - return 1; -} - - -static int pushuserdata (lua_State *L) { - lua_Integer u = luaL_checkinteger(L, 1); - lua_pushlightuserdata(L, cast(void *, cast(size_t, u))); - return 1; -} - - -static int udataval (lua_State *L) { - lua_pushinteger(L, cast(long, lua_touserdata(L, 1))); - return 1; -} - - -static int doonnewstack (lua_State *L) { - lua_State *L1 = lua_newthread(L); - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - int status = luaL_loadbuffer(L1, s, l, s); - if (status == LUA_OK) - status = lua_pcall(L1, 0, 0, 0); - lua_pushinteger(L, status); - return 1; -} - - -static int s2d (lua_State *L) { - lua_pushnumber(L, *cast(const double *, luaL_checkstring(L, 1))); - return 1; -} - - -static int d2s (lua_State *L) { - double d = luaL_checknumber(L, 1); - lua_pushlstring(L, cast(char *, &d), sizeof(d)); - return 1; -} - - -static int num2int (lua_State *L) { - lua_pushinteger(L, lua_tointeger(L, 1)); - return 1; -} - - -static int newstate (lua_State *L) { - void *ud; - lua_Alloc f = lua_getallocf(L, &ud); - lua_State *L1 = lua_newstate(f, ud); - if (L1) { - lua_atpanic(L1, tpanic); - lua_pushlightuserdata(L, L1); - } - else - lua_pushnil(L); - return 1; -} - - -static lua_State *getstate (lua_State *L) { - lua_State *L1 = cast(lua_State *, lua_touserdata(L, 1)); - luaL_argcheck(L, L1 != NULL, 1, "state expected"); - return L1; -} - - -static int loadlib (lua_State *L) { - static const luaL_Reg libs[] = { - {"_G", luaopen_base}, - {"coroutine", luaopen_coroutine}, - {"debug", luaopen_debug}, - {"io", luaopen_io}, - {"os", luaopen_os}, - {"math", luaopen_math}, - {"string", luaopen_string}, - {"table", luaopen_table}, - {NULL, NULL} - }; - lua_State *L1 = getstate(L); - int i; - luaL_requiref(L1, "package", luaopen_package, 0); - lua_assert(lua_type(L1, -1) == LUA_TTABLE); - /* 'requiref' should not reload module already loaded... */ - luaL_requiref(L1, "package", NULL, 1); /* seg. fault if it reloads */ - /* ...but should return the same module */ - lua_assert(lua_compare(L1, -1, -2, LUA_OPEQ)); - luaL_getsubtable(L1, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); - for (i = 0; libs[i].name; i++) { - lua_pushcfunction(L1, libs[i].func); - lua_setfield(L1, -2, libs[i].name); - } - return 0; -} - -static int closestate (lua_State *L) { - lua_State *L1 = getstate(L); - lua_close(L1); - return 0; -} - -static int doremote (lua_State *L) { - lua_State *L1 = getstate(L); - size_t lcode; - const char *code = luaL_checklstring(L, 2, &lcode); - int status; - lua_settop(L1, 0); - status = luaL_loadbuffer(L1, code, lcode, code); - if (status == LUA_OK) - status = lua_pcall(L1, 0, LUA_MULTRET, 0); - if (status != LUA_OK) { - lua_pushnil(L); - lua_pushstring(L, lua_tostring(L1, -1)); - lua_pushinteger(L, status); - return 3; - } - else { - int i = 0; - while (!lua_isnone(L1, ++i)) - lua_pushstring(L, lua_tostring(L1, i)); - lua_pop(L1, i-1); - return i-1; - } -} - - -static int int2fb_aux (lua_State *L) { - int b = luaO_int2fb((unsigned int)luaL_checkinteger(L, 1)); - lua_pushinteger(L, b); - lua_pushinteger(L, (unsigned int)luaO_fb2int(b)); - return 2; -} - - -static int log2_aux (lua_State *L) { - unsigned int x = (unsigned int)luaL_checkinteger(L, 1); - lua_pushinteger(L, luaO_ceillog2(x)); - return 1; -} - - -struct Aux { jmp_buf jb; const char *paniccode; lua_State *L; }; - -/* -** does a long-jump back to "main program". -*/ -static int panicback (lua_State *L) { - struct Aux *b; - lua_checkstack(L, 1); /* open space for 'Aux' struct */ - lua_getfield(L, LUA_REGISTRYINDEX, "_jmpbuf"); /* get 'Aux' struct */ - b = (struct Aux *)lua_touserdata(L, -1); - lua_pop(L, 1); /* remove 'Aux' struct */ - runC(b->L, L, b->paniccode); /* run optional panic code */ - longjmp(b->jb, 1); - return 1; /* to avoid warnings */ -} - -static int checkpanic (lua_State *L) { - struct Aux b; - void *ud; - lua_State *L1; - const char *code = luaL_checkstring(L, 1); - lua_Alloc f = lua_getallocf(L, &ud); - b.paniccode = luaL_optstring(L, 2, ""); - b.L = L; - L1 = lua_newstate(f, ud); /* create new state */ - if (L1 == NULL) { /* error? */ - lua_pushnil(L); - return 1; - } - lua_atpanic(L1, panicback); /* set its panic function */ - lua_pushlightuserdata(L1, &b); - lua_setfield(L1, LUA_REGISTRYINDEX, "_jmpbuf"); /* store 'Aux' struct */ - if (setjmp(b.jb) == 0) { /* set jump buffer */ - runC(L, L1, code); /* run code unprotected */ - lua_pushliteral(L, "no errors"); - } - else { /* error handling */ - /* move error message to original state */ - lua_pushstring(L, lua_tostring(L1, -1)); - } - lua_close(L1); - return 1; -} - - - -/* -** {==================================================================== -** function to test the API with C. It interprets a kind of assembler -** language with calls to the API, so the test can be driven by Lua code -** ===================================================================== -*/ - - -static void sethookaux (lua_State *L, int mask, int count, const char *code); - -static const char *const delimits = " \t\n,;"; - -static void skip (const char **pc) { - for (;;) { - if (**pc != '\0' && strchr(delimits, **pc)) (*pc)++; - else if (**pc == '#') { - while (**pc != '\n' && **pc != '\0') (*pc)++; - } - else break; - } -} - -static int getnum_aux (lua_State *L, lua_State *L1, const char **pc) { - int res = 0; - int sig = 1; - skip(pc); - if (**pc == '.') { - res = cast_int(lua_tointeger(L1, -1)); - lua_pop(L1, 1); - (*pc)++; - return res; - } - else if (**pc == '*') { - res = lua_gettop(L1); - (*pc)++; - return res; - } - else if (**pc == '-') { - sig = -1; - (*pc)++; - } - if (!lisdigit(cast_uchar(**pc))) - luaL_error(L, "number expected (%s)", *pc); - while (lisdigit(cast_uchar(**pc))) res = res*10 + (*(*pc)++) - '0'; - return sig*res; -} - -static const char *getstring_aux (lua_State *L, char *buff, const char **pc) { - int i = 0; - skip(pc); - if (**pc == '"' || **pc == '\'') { /* quoted string? */ - int quote = *(*pc)++; - while (**pc != quote) { - if (**pc == '\0') luaL_error(L, "unfinished string in C script"); - buff[i++] = *(*pc)++; - } - (*pc)++; - } - else { - while (**pc != '\0' && !strchr(delimits, **pc)) - buff[i++] = *(*pc)++; - } - buff[i] = '\0'; - return buff; -} - - -static int getindex_aux (lua_State *L, lua_State *L1, const char **pc) { - skip(pc); - switch (*(*pc)++) { - case 'R': return LUA_REGISTRYINDEX; - case 'G': return luaL_error(L, "deprecated index 'G'"); - case 'U': return lua_upvalueindex(getnum_aux(L, L1, pc)); - default: (*pc)--; return getnum_aux(L, L1, pc); - } -} - - -static void pushcode (lua_State *L, int code) { - static const char *const codes[] = {"OK", "YIELD", "ERRRUN", - "ERRSYNTAX", "ERRMEM", "ERRGCMM", "ERRERR"}; - lua_pushstring(L, codes[code]); -} - - -#define EQ(s1) (strcmp(s1, inst) == 0) - -#define getnum (getnum_aux(L, L1, &pc)) -#define getstring (getstring_aux(L, buff, &pc)) -#define getindex (getindex_aux(L, L1, &pc)) - - -static int testC (lua_State *L); -static int Cfunck (lua_State *L, int status, lua_KContext ctx); - -/* -** arithmetic operation encoding for 'arith' instruction -** LUA_OPIDIV -> \ -** LUA_OPSHL -> < -** LUA_OPSHR -> > -** LUA_OPUNM -> _ -** LUA_OPBNOT -> ! -*/ -static const char ops[] = "+-*%^/\\&|~<>_!"; - -static int runC (lua_State *L, lua_State *L1, const char *pc) { - char buff[300]; - int status = 0; - if (pc == NULL) return luaL_error(L, "attempt to runC null script"); - for (;;) { - const char *inst = getstring; - if EQ("") return 0; - else if EQ("absindex") { - lua_pushnumber(L1, lua_absindex(L1, getindex)); - } - else if EQ("append") { - int t = getindex; - int i = lua_rawlen(L1, t); - lua_rawseti(L1, t, i + 1); - } - else if EQ("arith") { - int op; - skip(&pc); - op = strchr(ops, *pc++) - ops; - lua_arith(L1, op); - } - else if EQ("call") { - int narg = getnum; - int nres = getnum; - lua_call(L1, narg, nres); - } - else if EQ("callk") { - int narg = getnum; - int nres = getnum; - int i = getindex; - lua_callk(L1, narg, nres, i, Cfunck); - } - else if EQ("checkstack") { - int sz = getnum; - const char *msg = getstring; - if (*msg == '\0') - msg = NULL; /* to test 'luaL_checkstack' with no message */ - luaL_checkstack(L1, sz, msg); - } - else if EQ("compare") { - const char *opt = getstring; /* EQ, LT, or LE */ - int op = (opt[0] == 'E') ? LUA_OPEQ - : (opt[1] == 'T') ? LUA_OPLT : LUA_OPLE; - int a = getindex; - int b = getindex; - lua_pushboolean(L1, lua_compare(L1, a, b, op)); - } - else if EQ("concat") { - lua_concat(L1, getnum); - } - else if EQ("copy") { - int f = getindex; - lua_copy(L1, f, getindex); - } - else if EQ("func2num") { - lua_CFunction func = lua_tocfunction(L1, getindex); - lua_pushnumber(L1, cast(size_t, func)); - } - else if EQ("getfield") { - int t = getindex; - lua_getfield(L1, t, getstring); - } - else if EQ("getglobal") { - lua_getglobal(L1, getstring); - } - else if EQ("getmetatable") { - if (lua_getmetatable(L1, getindex) == 0) - lua_pushnil(L1); - } - else if EQ("gettable") { - lua_gettable(L1, getindex); - } - else if EQ("gettop") { - lua_pushinteger(L1, lua_gettop(L1)); - } - else if EQ("gsub") { - int a = getnum; int b = getnum; int c = getnum; - luaL_gsub(L1, lua_tostring(L1, a), - lua_tostring(L1, b), - lua_tostring(L1, c)); - } - else if EQ("insert") { - lua_insert(L1, getnum); - } - else if EQ("iscfunction") { - lua_pushboolean(L1, lua_iscfunction(L1, getindex)); - } - else if EQ("isfunction") { - lua_pushboolean(L1, lua_isfunction(L1, getindex)); - } - else if EQ("isnil") { - lua_pushboolean(L1, lua_isnil(L1, getindex)); - } - else if EQ("isnull") { - lua_pushboolean(L1, lua_isnone(L1, getindex)); - } - else if EQ("isnumber") { - lua_pushboolean(L1, lua_isnumber(L1, getindex)); - } - else if EQ("isstring") { - lua_pushboolean(L1, lua_isstring(L1, getindex)); - } - else if EQ("istable") { - lua_pushboolean(L1, lua_istable(L1, getindex)); - } - else if EQ("isudataval") { - lua_pushboolean(L1, lua_islightuserdata(L1, getindex)); - } - else if EQ("isuserdata") { - lua_pushboolean(L1, lua_isuserdata(L1, getindex)); - } - else if EQ("len") { - lua_len(L1, getindex); - } - else if EQ("Llen") { - lua_pushinteger(L1, luaL_len(L1, getindex)); - } - else if EQ("loadfile") { - luaL_loadfile(L1, luaL_checkstring(L1, getnum)); - } - else if EQ("loadstring") { - const char *s = luaL_checkstring(L1, getnum); - luaL_loadstring(L1, s); - } - else if EQ("newmetatable") { - lua_pushboolean(L1, luaL_newmetatable(L1, getstring)); - } - else if EQ("newtable") { - lua_newtable(L1); - } - else if EQ("newthread") { - lua_newthread(L1); - } - else if EQ("newuserdata") { - lua_newuserdata(L1, getnum); - } - else if EQ("next") { - lua_next(L1, -2); - } - else if EQ("objsize") { - lua_pushinteger(L1, lua_rawlen(L1, getindex)); - } - else if EQ("pcall") { - int narg = getnum; - int nres = getnum; - status = lua_pcall(L1, narg, nres, getnum); - } - else if EQ("pcallk") { - int narg = getnum; - int nres = getnum; - int i = getindex; - status = lua_pcallk(L1, narg, nres, 0, i, Cfunck); - } - else if EQ("pop") { - lua_pop(L1, getnum); - } - else if EQ("print") { - int n = getnum; - if (n != 0) { - printf("%s\n", luaL_tolstring(L1, n, NULL)); - lua_pop(L1, 1); - } - else printstack(L1); - } - else if EQ("pushbool") { - lua_pushboolean(L1, getnum); - } - else if EQ("pushcclosure") { - lua_pushcclosure(L1, testC, getnum); - } - else if EQ("pushint") { - lua_pushinteger(L1, getnum); - } - else if EQ("pushnil") { - lua_pushnil(L1); - } - else if EQ("pushnum") { - lua_pushnumber(L1, (lua_Number)getnum); - } - else if EQ("pushstatus") { - pushcode(L1, status); - } - else if EQ("pushstring") { - lua_pushstring(L1, getstring); - } - else if EQ("pushupvalueindex") { - lua_pushinteger(L1, lua_upvalueindex(getnum)); - } - else if EQ("pushvalue") { - lua_pushvalue(L1, getindex); - } - else if EQ("rawgeti") { - int t = getindex; - lua_rawgeti(L1, t, getnum); - } - else if EQ("rawgetp") { - int t = getindex; - lua_rawgetp(L1, t, cast(void *, cast(size_t, getnum))); - } - else if EQ("rawsetp") { - int t = getindex; - lua_rawsetp(L1, t, cast(void *, cast(size_t, getnum))); - } - else if EQ("remove") { - lua_remove(L1, getnum); - } - else if EQ("replace") { - lua_replace(L1, getindex); - } - else if EQ("resume") { - int i = getindex; - status = lua_resume(lua_tothread(L1, i), L, getnum); - } - else if EQ("return") { - int n = getnum; - if (L1 != L) { - int i; - for (i = 0; i < n; i++) - lua_pushstring(L, lua_tostring(L1, -(n - i))); - } - return n; - } - else if EQ("rotate") { - int i = getindex; - lua_rotate(L1, i, getnum); - } - else if EQ("setfield") { - int t = getindex; - lua_setfield(L1, t, getstring); - } - else if EQ("setglobal") { - lua_setglobal(L1, getstring); - } - else if EQ("sethook") { - int mask = getnum; - int count = getnum; - sethookaux(L1, mask, count, getstring); - } - else if EQ("setmetatable") { - lua_setmetatable(L1, getindex); - } - else if EQ("settable") { - lua_settable(L1, getindex); - } - else if EQ("settop") { - lua_settop(L1, getnum); - } - else if EQ("testudata") { - int i = getindex; - lua_pushboolean(L1, luaL_testudata(L1, i, getstring) != NULL); - } - else if EQ("error") { - lua_error(L1); - } - else if EQ("throw") { -#if defined(__cplusplus) -static struct X { int x; } x; - throw x; -#else - luaL_error(L1, "C++"); -#endif - break; - } - else if EQ("tobool") { - lua_pushboolean(L1, lua_toboolean(L1, getindex)); - } - else if EQ("tocfunction") { - lua_pushcfunction(L1, lua_tocfunction(L1, getindex)); - } - else if EQ("tointeger") { - lua_pushinteger(L1, lua_tointeger(L1, getindex)); - } - else if EQ("tonumber") { - lua_pushnumber(L1, lua_tonumber(L1, getindex)); - } - else if EQ("topointer") { - lua_pushnumber(L1, cast(size_t, lua_topointer(L1, getindex))); - } - else if EQ("tostring") { - const char *s = lua_tostring(L1, getindex); - const char *s1 = lua_pushstring(L1, s); - lua_longassert((s == NULL && s1 == NULL) || strcmp(s, s1) == 0); - } - else if EQ("type") { - lua_pushstring(L1, luaL_typename(L1, getnum)); - } - else if EQ("xmove") { - int f = getindex; - int t = getindex; - lua_State *fs = (f == 0) ? L1 : lua_tothread(L1, f); - lua_State *ts = (t == 0) ? L1 : lua_tothread(L1, t); - int n = getnum; - if (n == 0) n = lua_gettop(fs); - lua_xmove(fs, ts, n); - } - else if EQ("yield") { - return lua_yield(L1, getnum); - } - else if EQ("yieldk") { - int nres = getnum; - int i = getindex; - return lua_yieldk(L1, nres, i, Cfunck); - } - else luaL_error(L, "unknown instruction %s", buff); - } - return 0; -} - - -static int testC (lua_State *L) { - lua_State *L1; - const char *pc; - if (lua_isuserdata(L, 1)) { - L1 = getstate(L); - pc = luaL_checkstring(L, 2); - } - else if (lua_isthread(L, 1)) { - L1 = lua_tothread(L, 1); - pc = luaL_checkstring(L, 2); - } - else { - L1 = L; - pc = luaL_checkstring(L, 1); - } - return runC(L, L1, pc); -} - - -static int Cfunc (lua_State *L) { - return runC(L, L, lua_tostring(L, lua_upvalueindex(1))); -} - - -static int Cfunck (lua_State *L, int status, lua_KContext ctx) { - pushcode(L, status); - lua_setglobal(L, "status"); - lua_pushinteger(L, ctx); - lua_setglobal(L, "ctx"); - return runC(L, L, lua_tostring(L, ctx)); -} - - -static int makeCfunc (lua_State *L) { - luaL_checkstring(L, 1); - lua_pushcclosure(L, Cfunc, lua_gettop(L)); - return 1; -} - - -/* }====================================================== */ - - -/* -** {====================================================== -** tests for C hooks -** ======================================================= -*/ - -/* -** C hook that runs the C script stored in registry.C_HOOK[L] -*/ -static void Chook (lua_State *L, lua_Debug *ar) { - const char *scpt; - const char *const events [] = {"call", "ret", "line", "count", "tailcall"}; - lua_getfield(L, LUA_REGISTRYINDEX, "C_HOOK"); - lua_pushlightuserdata(L, L); - lua_gettable(L, -2); /* get C_HOOK[L] (script saved by sethookaux) */ - scpt = lua_tostring(L, -1); /* not very religious (string will be popped) */ - lua_pop(L, 2); /* remove C_HOOK and script */ - lua_pushstring(L, events[ar->event]); /* may be used by script */ - lua_pushinteger(L, ar->currentline); /* may be used by script */ - runC(L, L, scpt); /* run script from C_HOOK[L] */ -} - - -/* -** sets 'registry.C_HOOK[L] = scpt' and sets 'Chook' as a hook -*/ -static void sethookaux (lua_State *L, int mask, int count, const char *scpt) { - if (*scpt == '\0') { /* no script? */ - lua_sethook(L, NULL, 0, 0); /* turn off hooks */ - return; - } - lua_getfield(L, LUA_REGISTRYINDEX, "C_HOOK"); /* get C_HOOK table */ - if (!lua_istable(L, -1)) { /* no hook table? */ - lua_pop(L, 1); /* remove previous value */ - lua_newtable(L); /* create new C_HOOK table */ - lua_pushvalue(L, -1); - lua_setfield(L, LUA_REGISTRYINDEX, "C_HOOK"); /* register it */ - } - lua_pushlightuserdata(L, L); - lua_pushstring(L, scpt); - lua_settable(L, -3); /* C_HOOK[L] = script */ - lua_sethook(L, Chook, mask, count); -} - - -static int sethook (lua_State *L) { - if (lua_isnoneornil(L, 1)) - lua_sethook(L, NULL, 0, 0); /* turn off hooks */ - else { - const char *scpt = luaL_checkstring(L, 1); - const char *smask = luaL_checkstring(L, 2); - int count = cast_int(luaL_optinteger(L, 3, 0)); - int mask = 0; - if (strchr(smask, 'c')) mask |= LUA_MASKCALL; - if (strchr(smask, 'r')) mask |= LUA_MASKRET; - if (strchr(smask, 'l')) mask |= LUA_MASKLINE; - if (count > 0) mask |= LUA_MASKCOUNT; - sethookaux(L, mask, count, scpt); - } - return 0; -} - - -static int coresume (lua_State *L) { - int status; - lua_State *co = lua_tothread(L, 1); - luaL_argcheck(L, co, 1, "coroutine expected"); - status = lua_resume(co, L, 0); - if (status != LUA_OK && status != LUA_YIELD) { - lua_pushboolean(L, 0); - lua_insert(L, -2); - return 2; /* return false + error message */ - } - else { - lua_pushboolean(L, 1); - return 1; - } -} - -/* }====================================================== */ - - - -static const struct luaL_Reg tests_funcs[] = { - {"checkmemory", lua_checkmemory}, - {"closestate", closestate}, - {"d2s", d2s}, - {"doonnewstack", doonnewstack}, - {"doremote", doremote}, - {"gccolor", gc_color}, - {"gcstate", gc_state}, - {"getref", getref}, - {"hash", hash_query}, - {"int2fb", int2fb_aux}, - {"log2", log2_aux}, - {"limits", get_limits}, - {"listcode", listcode}, - {"listk", listk}, - {"listlocals", listlocals}, - {"loadlib", loadlib}, - {"checkpanic", checkpanic}, - {"newstate", newstate}, - {"newuserdata", newuserdata}, - {"num2int", num2int}, - {"pushuserdata", pushuserdata}, - {"querystr", string_query}, - {"querytab", table_query}, - {"ref", tref}, - {"resume", coresume}, - {"s2d", s2d}, - {"sethook", sethook}, - {"stacklevel", stacklevel}, - {"testC", testC}, - {"makeCfunc", makeCfunc}, - {"totalmem", mem_query}, - {"trick", settrick}, - {"udataval", udataval}, - {"unref", unref}, - {"upvalue", upvalue}, - {NULL, NULL} -}; - - -static void checkfinalmem (void) { - lua_assert(l_memcontrol.numblocks == 0); - lua_assert(l_memcontrol.total == 0); -} - - -int luaB_opentests (lua_State *L) { - void *ud; - lua_atpanic(L, &tpanic); - atexit(checkfinalmem); - lua_assert(lua_getallocf(L, &ud) == debug_realloc); - lua_assert(ud == cast(void *, &l_memcontrol)); - lua_setallocf(L, lua_getallocf(L, NULL), ud); - luaL_newlib(L, tests_funcs); - return 1; -} - -#endif - diff --git a/headers/3rdparty/lua/ltests.h b/headers/3rdparty/lua/ltests.h deleted file mode 100644 index 820bc82f..00000000 --- a/headers/3rdparty/lua/ltests.h +++ /dev/null @@ -1,129 +0,0 @@ -/* -** $Id: ltests.h,v 2.50.1.1 2017/04/19 17:20:42 roberto Exp $ -** Internal Header for Debugging of the Lua Implementation -** See Copyright Notice in lua.h -*/ - -#ifndef ltests_h -#define ltests_h - - -#include - -/* test Lua with no compatibility code */ -#undef LUA_COMPAT_MATHLIB -#undef LUA_COMPAT_IPAIRS -#undef LUA_COMPAT_BITLIB -#undef LUA_COMPAT_APIINTCASTS -#undef LUA_COMPAT_FLOATSTRING -#undef LUA_COMPAT_UNPACK -#undef LUA_COMPAT_LOADERS -#undef LUA_COMPAT_LOG10 -#undef LUA_COMPAT_LOADSTRING -#undef LUA_COMPAT_MAXN -#undef LUA_COMPAT_MODULE - - -#define LUA_DEBUG - - -/* turn on assertions */ -#undef NDEBUG -#include -#define lua_assert(c) assert(c) - - -/* to avoid warnings, and to make sure value is really unused */ -#define UNUSED(x) (x=0, (void)(x)) - - -/* test for sizes in 'l_sprintf' (make sure whole buffer is available) */ -#undef l_sprintf -#if !defined(LUA_USE_C89) -#define l_sprintf(s,sz,f,i) (memset(s,0xAB,sz), snprintf(s,sz,f,i)) -#else -#define l_sprintf(s,sz,f,i) (memset(s,0xAB,sz), sprintf(s,f,i)) -#endif - - -/* memory-allocator control variables */ -typedef struct Memcontrol { - unsigned long numblocks; - unsigned long total; - unsigned long maxmem; - unsigned long memlimit; - unsigned long objcount[LUA_NUMTAGS]; -} Memcontrol; - -LUA_API Memcontrol l_memcontrol; - - -/* -** generic variable for debug tricks -*/ -extern void *l_Trick; - - - -/* -** Function to traverse and check all memory used by Lua -*/ -int lua_checkmemory (lua_State *L); - - -/* test for lock/unlock */ - -struct L_EXTRA { int lock; int *plock; }; -#undef LUA_EXTRASPACE -#define LUA_EXTRASPACE sizeof(struct L_EXTRA) -#define getlock(l) cast(struct L_EXTRA*, lua_getextraspace(l)) -#define luai_userstateopen(l) \ - (getlock(l)->lock = 0, getlock(l)->plock = &(getlock(l)->lock)) -#define luai_userstateclose(l) \ - lua_assert(getlock(l)->lock == 1 && getlock(l)->plock == &(getlock(l)->lock)) -#define luai_userstatethread(l,l1) \ - lua_assert(getlock(l1)->plock == getlock(l)->plock) -#define luai_userstatefree(l,l1) \ - lua_assert(getlock(l)->plock == getlock(l1)->plock) -#define lua_lock(l) lua_assert((*getlock(l)->plock)++ == 0) -#define lua_unlock(l) lua_assert(--(*getlock(l)->plock) == 0) - - - -LUA_API int luaB_opentests (lua_State *L); - -LUA_API void *debug_realloc (void *ud, void *block, - size_t osize, size_t nsize); - -#if defined(lua_c) -#define luaL_newstate() lua_newstate(debug_realloc, &l_memcontrol) -#define luaL_openlibs(L) \ - { (luaL_openlibs)(L); \ - luaL_requiref(L, "T", luaB_opentests, 1); \ - lua_pop(L, 1); } -#endif - - - -/* change some sizes to give some bugs a chance */ - -#undef LUAL_BUFFERSIZE -#define LUAL_BUFFERSIZE 23 -#define MINSTRTABSIZE 2 -#define MAXINDEXRK 1 - - -/* make stack-overflow tests run faster */ -#undef LUAI_MAXSTACK -#define LUAI_MAXSTACK 50000 - - -#undef LUAI_USER_ALIGNMENT_T -#define LUAI_USER_ALIGNMENT_T union { char b[sizeof(void*) * 8]; } - - -#define STRCACHE_N 23 -#define STRCACHE_M 5 - -#endif - diff --git a/headers/3rdparty/rapidjson/internal/clzll.h b/headers/3rdparty/rapidjson/internal/clzll.h new file mode 100644 index 00000000..abe44dfc --- /dev/null +++ b/headers/3rdparty/rapidjson/internal/clzll.h @@ -0,0 +1,72 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_CLZLL_H_ +#define RAPIDJSON_CLZLL_H_ + +#include "../rapidjson.h" + +#if defined(_MSC_VER) +#include +#if defined(_WIN64) +#pragma intrinsic(_BitScanReverse64) +#else +#pragma intrinsic(_BitScanReverse) +#endif +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +#if (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll) +#define RAPIDJSON_CLZLL __builtin_clzll +#else + +inline uint32_t clzll(uint64_t x) { + // Passing 0 to __builtin_clzll is UB in GCC and results in an + // infinite loop in the software implementation. + RAPIDJSON_ASSERT(x != 0); + +#if defined(_MSC_VER) + unsigned long r = 0; +#if defined(_WIN64) + _BitScanReverse64(&r, x); +#else + // Scan the high 32 bits. + if (_BitScanReverse(&r, static_cast(x >> 32))) + return 63 - (r + 32); + + // Scan the low 32 bits. + _BitScanReverse(&r, static_cast(x & 0xFFFFFFFF)); +#endif // _WIN64 + + return 63 - r; +#else + uint32_t r; + while (!(x & (static_cast(1) << 63))) { + x <<= 1; + ++r; + } + + return r; +#endif // _MSC_VER +} + +#define RAPIDJSON_CLZLL RAPIDJSON_NAMESPACE::internal::clzll +#endif // (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll) + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_CLZLL_H_ \ No newline at end of file diff --git a/headers/3rdparty/rapidjson/internal/diyfp.h b/headers/3rdparty/rapidjson/internal/diyfp.h index b6c2cf56..f46059a0 100644 --- a/headers/3rdparty/rapidjson/internal/diyfp.h +++ b/headers/3rdparty/rapidjson/internal/diyfp.h @@ -20,11 +20,11 @@ #define RAPIDJSON_DIYFP_H_ #include "../rapidjson.h" +#include "clzll.h" #include #if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) #include -#pragma intrinsic(_BitScanReverse64) #pragma intrinsic(_umul128) #endif @@ -100,22 +100,8 @@ struct DiyFp { } DiyFp Normalize() const { - RAPIDJSON_ASSERT(f != 0); // https://stackoverflow.com/a/26809183/291737 -#if defined(_MSC_VER) && defined(_M_AMD64) - unsigned long index; - _BitScanReverse64(&index, f); - return DiyFp(f << (63 - index), e - (63 - index)); -#elif defined(__GNUC__) && __GNUC__ >= 4 - int s = __builtin_clzll(f); + int s = static_cast(RAPIDJSON_CLZLL(f)); return DiyFp(f << s, e - s); -#else - DiyFp res = *this; - while (!(res.f & (static_cast(1) << 63))) { - res.f <<= 1; - res.e--; - } - return res; -#endif } DiyFp NormalizeBoundary() const { diff --git a/headers/3rdparty/rapidjson/rapidjson.h b/headers/3rdparty/rapidjson/rapidjson.h index 5c638261..b71ea79b 100644 --- a/headers/3rdparty/rapidjson/rapidjson.h +++ b/headers/3rdparty/rapidjson/rapidjson.h @@ -490,6 +490,12 @@ RAPIDJSON_NAMESPACE_END #define RAPIDJSON_VERSION_CODE(x,y,z) \ (((x)*100000) + ((y)*100) + (z)) +#if defined(__has_builtin) +#define RAPIDJSON_HAS_BUILTIN(x) __has_builtin(x) +#else +#define RAPIDJSON_HAS_BUILTIN(x) 0 +#endif + /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF diff --git a/headers/3rdparty/rapidjson/reader.h b/headers/3rdparty/rapidjson/reader.h index 44a6bcd3..13d27c29 100644 --- a/headers/3rdparty/rapidjson/reader.h +++ b/headers/3rdparty/rapidjson/reader.h @@ -20,6 +20,7 @@ #include "allocators.h" #include "stream.h" #include "encodedstream.h" +#include "internal/clzll.h" #include "internal/meta.h" #include "internal/stack.h" #include "internal/strtod.h" @@ -443,16 +444,16 @@ inline const char *SkipWhitespace_SIMD(const char* p) { x = vmvnq_u8(x); // Negate x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract if (low == 0) { if (high != 0) { - int lz =__builtin_clzll(high);; + uint32_t lz = RAPIDJSON_CLZLL(high); return p + 8 + (lz >> 3); } } else { - int lz = __builtin_clzll(low);; + uint32_t lz = RAPIDJSON_CLZLL(low); return p + (lz >> 3); } } @@ -479,16 +480,16 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { x = vmvnq_u8(x); // Negate x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract if (low == 0) { if (high != 0) { - int lz = __builtin_clzll(high); + uint32_t lz = RAPIDJSON_CLZLL(high); return p + 8 + (lz >> 3); } } else { - int lz = __builtin_clzll(low); + uint32_t lz = RAPIDJSON_CLZLL(low); return p + (lz >> 3); } } @@ -1244,19 +1245,19 @@ private: x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract SizeType length = 0; bool escaped = false; if (low == 0) { if (high != 0) { - unsigned lz = (unsigned)__builtin_clzll(high);; + uint32_t lz = RAPIDJSON_CLZLL(high); length = 8 + (lz >> 3); escaped = true; } } else { - unsigned lz = (unsigned)__builtin_clzll(low);; + uint32_t lz = RAPIDJSON_CLZLL(low); length = lz >> 3; escaped = true; } @@ -1314,19 +1315,19 @@ private: x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract SizeType length = 0; bool escaped = false; if (low == 0) { if (high != 0) { - unsigned lz = (unsigned)__builtin_clzll(high); + uint32_t lz = RAPIDJSON_CLZLL(high); length = 8 + (lz >> 3); escaped = true; } } else { - unsigned lz = (unsigned)__builtin_clzll(low); + uint32_t lz = RAPIDJSON_CLZLL(low); length = lz >> 3; escaped = true; } @@ -1370,17 +1371,17 @@ private: x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract if (low == 0) { if (high != 0) { - int lz = __builtin_clzll(high); + uint32_t lz = RAPIDJSON_CLZLL(high); p += 8 + (lz >> 3); break; } } else { - int lz = __builtin_clzll(low); + uint32_t lz = RAPIDJSON_CLZLL(low); p += lz >> 3; break; } @@ -1403,7 +1404,7 @@ private: RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } - RAPIDJSON_FORCEINLINE void Push(char) {} + RAPIDJSON_FORCEINLINE void Push(char) {} size_t Tell() { return is.Tell(); } size_t Length() { return 0; } diff --git a/headers/3rdparty/rapidjson/writer.h b/headers/3rdparty/rapidjson/writer.h index 6f5b6903..ce39e76c 100644 --- a/headers/3rdparty/rapidjson/writer.h +++ b/headers/3rdparty/rapidjson/writer.h @@ -16,6 +16,7 @@ #define RAPIDJSON_WRITER_H_ #include "stream.h" +#include "internal/clzll.h" #include "internal/meta.h" #include "internal/stack.h" #include "internal/strfunc.h" @@ -226,7 +227,7 @@ public: return Key(str.data(), SizeType(str.size())); } #endif - + bool EndObject(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object @@ -668,19 +669,19 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract SizeType len = 0; bool escaped = false; if (low == 0) { if (high != 0) { - unsigned lz = (unsigned)__builtin_clzll(high); + uint32_t lz = RAPIDJSON_CLZLL(high); len = 8 + (lz >> 3); escaped = true; } } else { - unsigned lz = (unsigned)__builtin_clzll(low); + uint32_t lz = RAPIDJSON_CLZLL(low); len = lz >> 3; escaped = true; } diff --git a/modules/catch2 b/modules/catch2 index 7c9f92bc..e1c9d556 160000 --- a/modules/catch2 +++ b/modules/catch2 @@ -1 +1 @@ -Subproject commit 7c9f92bc1c6e82ad5b6af8dff9f97af880fae9c6 +Subproject commit e1c9d5569dc4135babb9c81891d70a8ba8ed938c diff --git a/modules/enum.hpp b/modules/enum.hpp index e3bf360c..3909b3b1 160000 --- a/modules/enum.hpp +++ b/modules/enum.hpp @@ -1 +1 @@ -Subproject commit e3bf360c5c97b994e2e90f68fbaca9647383f963 +Subproject commit 3909b3b1abaa9b63ecb3c9ff8ae29bce4f2bbd4d diff --git a/modules/glew b/modules/glew index 6f770a5b..59a52e57 160000 --- a/modules/glew +++ b/modules/glew @@ -1 +1 @@ -Subproject commit 6f770a5b5b9a904972b9c6974e40106bc3a27b5a +Subproject commit 59a52e570f7d1ea9fa82814adf0889a522b4b93f diff --git a/modules/imgui b/modules/imgui index 6ffee0e7..f60518b4 160000 --- a/modules/imgui +++ b/modules/imgui @@ -1 +1 @@ -Subproject commit 6ffee0e75e8f677c5fd8280dfe544c3fcb325f45 +Subproject commit f60518b430d9d1974949594dec576cf39aac085f diff --git a/modules/miniz b/modules/miniz index 3a00ea8b..f66b3e19 160000 --- a/modules/miniz +++ b/modules/miniz @@ -1 +1 @@ -Subproject commit 3a00ea8b73c57e3e4c636bd7851f230b6968ac26 +Subproject commit f66b3e19017fad1e7f836ce5ecf94c88c0f9d497 diff --git a/modules/rapidjson b/modules/rapidjson index 1a825d24..35e480fc 160000 --- a/modules/rapidjson +++ b/modules/rapidjson @@ -1 +1 @@ -Subproject commit 1a825d24fa322a5fe721624b2ed7a18b6de9b48a +Subproject commit 35e480fc4ddf4ec4f7ad34d96353eef0aabf002d diff --git a/modules/spine b/modules/spine index 45b8125a..9fabc603 160000 --- a/modules/spine +++ b/modules/spine @@ -1 +1 @@ -Subproject commit 45b8125a8eb2f69e692d835b0147e4e4775607a9 +Subproject commit 9fabc6032363b27823110f5d8f7c14706367ccbf diff --git a/modules/stb b/modules/stb index 052dce11..f67165c2 160000 --- a/modules/stb +++ b/modules/stb @@ -1 +1 @@ -Subproject commit 052dce117ed989848a950308bd99eef55525dfb1 +Subproject commit f67165c2bb2af3060ecae7d20d6f731173485ad0 diff --git a/modules/utfcpp b/modules/utfcpp index 170e2d11..c3f9261e 160000 --- a/modules/utfcpp +++ b/modules/utfcpp @@ -1 +1 @@ -Subproject commit 170e2d11f516539d18bf39f552fa204dbf41d9ce +Subproject commit c3f9261eb8e793fa6c6a62309d3a3942ee03486a diff --git a/scripts/build_all.bat b/scripts/build_all.bat index 4d063dc1..9e778dcb 100644 --- a/scripts/build_all.bat +++ b/scripts/build_all.bat @@ -1,7 +1,9 @@ @echo off set SCRIPT_DIR=%~dp0% -call %SCRIPT_DIR%\build_debug.bat || goto :error -call %SCRIPT_DIR%\build_release.bat || goto :error +call %SCRIPT_DIR%\build_debug_x86.bat || goto :error +call %SCRIPT_DIR%\build_debug_x64.bat || goto :error +call %SCRIPT_DIR%\build_release_x86.bat || goto :error +call %SCRIPT_DIR%\build_release_x64.bat || goto :error goto :EOF diff --git a/scripts/build_debug.sh b/scripts/build_debug.sh index 89f4c936..97018eb1 100755 --- a/scripts/build_debug.sh +++ b/scripts/build_debug.sh @@ -1,9 +1,9 @@ #!/bin/bash set -e BUILD_DIR=`dirname "$BASH_SOURCE"`/../build -mkdir -p $BUILD_DIR/debug -cd $BUILD_DIR/debug +mkdir -p $BUILD_DIR/Debug +cd $BUILD_DIR/Debug cmake -DCMAKE_BUILD_TYPE=Debug ../.. -cmake --build . -- -j8 +cmake --build . ctest --verbose cd ../.. diff --git a/scripts/build_debug.bat b/scripts/build_debug_x64.bat similarity index 57% rename from scripts/build_debug.bat rename to scripts/build_debug_x64.bat index 01f8572f..675bd2ad 100644 --- a/scripts/build_debug.bat +++ b/scripts/build_debug_x64.bat @@ -1,11 +1,11 @@ @echo off set BUILD_DIR=%~dp0%\..\build -mkdir %BUILD_DIR%\debug || goto :error -cd %BUILD_DIR%\debug || goto :error -cmake ../.. || goto :error +mkdir %BUILD_DIR%\Debug\x64 || goto :error +cd %BUILD_DIR%\Debug\x64 || goto :error +cmake ..\..\.. -A x64 || goto :error cmake --build . --config Debug || goto :error ctest --verbose || goto :error -cd ..\.. || goto :error +cd ..\..\.. || goto :error goto :EOF diff --git a/scripts/build_debug_x86.bat b/scripts/build_debug_x86.bat new file mode 100644 index 00000000..b6dcd6d4 --- /dev/null +++ b/scripts/build_debug_x86.bat @@ -0,0 +1,14 @@ +@echo off +set BUILD_DIR=%~dp0%\..\build +mkdir %BUILD_DIR%\Debug\x86 || goto :error +cd %BUILD_DIR%\Debug\x86 || goto :error +cmake ..\..\.. -A Win32 || goto :error +cmake --build . --config Debug || goto :error +ctest --verbose || goto :error +cd ..\..\.. || goto :error + +goto :EOF + +:error +echo Failed with error #%errorlevel%. +exit /b %errorlevel% diff --git a/scripts/build_release.sh b/scripts/build_release.sh index 9ab7e235..3a2c5c14 100755 --- a/scripts/build_release.sh +++ b/scripts/build_release.sh @@ -1,9 +1,9 @@ #!/bin/bash set -e BUILD_DIR=`dirname "$BASH_SOURCE"`/../build -mkdir -p $BUILD_DIR/release -cd $BUILD_DIR/release +mkdir -p $BUILD_DIR/Release +cd $BUILD_DIR/Release cmake -DCMAKE_BUILD_TYPE=Release ../.. -cmake --build . -- -j8 +cmake --build . ctest --verbose cd ../.. diff --git a/scripts/build_release.bat b/scripts/build_release_x64.bat similarity index 56% rename from scripts/build_release.bat rename to scripts/build_release_x64.bat index b6bf3624..064e8671 100644 --- a/scripts/build_release.bat +++ b/scripts/build_release_x64.bat @@ -1,11 +1,11 @@ @echo off set BUILD_DIR=%~dp0%\..\build -mkdir %BUILD_DIR%\release || goto :error -cd %BUILD_DIR%\release || goto :error -cmake ../.. || goto :error +mkdir %BUILD_DIR%\Release\x64 || goto :error +cd %BUILD_DIR%\Release\x64 || goto :error +cmake ..\..\.. -A x64 || goto :error cmake --build . --config Release || goto :error ctest --verbose || goto :error -cd ..\.. || goto :error +cd ..\..\.. || goto :error goto :EOF diff --git a/scripts/build_release_x86.bat b/scripts/build_release_x86.bat new file mode 100644 index 00000000..09aa042d --- /dev/null +++ b/scripts/build_release_x86.bat @@ -0,0 +1,14 @@ +@echo off +set BUILD_DIR=%~dp0%\..\build +mkdir %BUILD_DIR%\Release\x86 || goto :error +cd %BUILD_DIR%\Release\x86 || goto :error +cmake ..\..\.. -A Win32 || goto :error +cmake --build . --config Release || goto :error +ctest --verbose || goto :error +cd ..\..\.. || goto :error + +goto :EOF + +:error +echo Failed with error #%errorlevel%. +exit /b %errorlevel% diff --git a/scripts/untest_all_clang.sh b/scripts/untest_all_clang.sh deleted file mode 100755 index f097ee4c..00000000 --- a/scripts/untest_all_clang.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -set -e -SCRIPT_DIR=`dirname "$BASH_SOURCE"` - -$SCRIPT_DIR/build_clear.sh -CC=clang-6.0 CXX=clang++-6.0 $SCRIPT_DIR/build_all.sh - -$SCRIPT_DIR/build_clear.sh -CC=clang-5.0 CXX=clang++-5.0 $SCRIPT_DIR/build_all.sh - -$SCRIPT_DIR/build_clear.sh -CC=clang-4.0 CXX=clang++-4.0 $SCRIPT_DIR/build_all.sh - -$SCRIPT_DIR/build_clear.sh -CC=clang-3.9 CXX=clang++-3.9 $SCRIPT_DIR/build_all.sh - -$SCRIPT_DIR/build_clear.sh -CC=clang-3.8 CXX=clang++-3.8 $SCRIPT_DIR/build_all.sh - -$SCRIPT_DIR/build_clear.sh diff --git a/scripts/untest_all_gcc.sh b/scripts/untest_all_gcc.sh deleted file mode 100755 index 503fb8c7..00000000 --- a/scripts/untest_all_gcc.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -set -e -SCRIPT_DIR=`dirname "$BASH_SOURCE"` - -$SCRIPT_DIR/build_clear.sh -CC=gcc-8 CXX=g++-8 $SCRIPT_DIR/build_all.sh - -$SCRIPT_DIR/build_clear.sh -CC=gcc-7 CXX=g++-7 $SCRIPT_DIR/build_all.sh - -$SCRIPT_DIR/build_clear.sh -CC=gcc-6 CXX=g++-6 $SCRIPT_DIR/build_all.sh - -$SCRIPT_DIR/build_clear.sh -CC=gcc-5 CXX=g++-5 $SCRIPT_DIR/build_all.sh - -$SCRIPT_DIR/build_clear.sh -CC=gcc-4.9 CXX=g++-4.9 $SCRIPT_DIR/build_all.sh - -$SCRIPT_DIR/build_clear.sh diff --git a/scripts/update_modules.sh b/scripts/update_modules.sh index 0158ef9d..2540f416 100755 --- a/scripts/update_modules.sh +++ b/scripts/update_modules.sh @@ -14,9 +14,6 @@ mkdir -p $UNTESTS_DIR mkdir -p $HEADERS_RDPARTY_DIR mkdir -p $SOURCES_RDPARTY_DIR -git submodule update --init --recursive -git submodule update --remote - mkdir -p $UNTESTS_DIR/catch cp -fv $MODULES_DIR/catch2/single_include/catch2/catch.hpp $UNTESTS_DIR/catch/catch.hpp @@ -31,6 +28,66 @@ cp -fv $MODULES_DIR/imgui/imstb_rectpack.h $SOURCES_RDPARTY_DIR/imgui/imstb_rect cp -fv $MODULES_DIR/imgui/imstb_textedit.h $SOURCES_RDPARTY_DIR/imgui/imstb_textedit.h cp -fv $MODULES_DIR/imgui/imstb_truetype.h $SOURCES_RDPARTY_DIR/imgui/imstb_truetype.h +mkdir -p $HEADERS_RDPARTY_DIR/lua +cp -fv $MODULES_DIR/lua/lapi.c $HEADERS_RDPARTY_DIR/lua/lapi.c +cp -fv $MODULES_DIR/lua/lapi.h $HEADERS_RDPARTY_DIR/lua/lapi.h +cp -fv $MODULES_DIR/lua/lauxlib.c $HEADERS_RDPARTY_DIR/lua/lauxlib.c +cp -fv $MODULES_DIR/lua/lauxlib.h $HEADERS_RDPARTY_DIR/lua/lauxlib.h +cp -fv $MODULES_DIR/lua/lbaselib.c $HEADERS_RDPARTY_DIR/lua/lbaselib.c +cp -fv $MODULES_DIR/lua/lbitlib.c $HEADERS_RDPARTY_DIR/lua/lbitlib.c +cp -fv $MODULES_DIR/lua/lcode.c $HEADERS_RDPARTY_DIR/lua/lcode.c +cp -fv $MODULES_DIR/lua/lcode.h $HEADERS_RDPARTY_DIR/lua/lcode.h +cp -fv $MODULES_DIR/lua/lcorolib.c $HEADERS_RDPARTY_DIR/lua/lcorolib.c +cp -fv $MODULES_DIR/lua/lctype.c $HEADERS_RDPARTY_DIR/lua/lctype.c +cp -fv $MODULES_DIR/lua/lctype.h $HEADERS_RDPARTY_DIR/lua/lctype.h +cp -fv $MODULES_DIR/lua/ldblib.c $HEADERS_RDPARTY_DIR/lua/ldblib.c +cp -fv $MODULES_DIR/lua/ldebug.c $HEADERS_RDPARTY_DIR/lua/ldebug.c +cp -fv $MODULES_DIR/lua/ldebug.h $HEADERS_RDPARTY_DIR/lua/ldebug.h +cp -fv $MODULES_DIR/lua/ldo.c $HEADERS_RDPARTY_DIR/lua/ldo.c +cp -fv $MODULES_DIR/lua/ldo.h $HEADERS_RDPARTY_DIR/lua/ldo.h +cp -fv $MODULES_DIR/lua/ldump.c $HEADERS_RDPARTY_DIR/lua/ldump.c +cp -fv $MODULES_DIR/lua/lfunc.c $HEADERS_RDPARTY_DIR/lua/lfunc.c +cp -fv $MODULES_DIR/lua/lfunc.h $HEADERS_RDPARTY_DIR/lua/lfunc.h +cp -fv $MODULES_DIR/lua/lgc.c $HEADERS_RDPARTY_DIR/lua/lgc.c +cp -fv $MODULES_DIR/lua/lgc.h $HEADERS_RDPARTY_DIR/lua/lgc.h +cp -fv $MODULES_DIR/lua/linit.c $HEADERS_RDPARTY_DIR/lua/linit.c +cp -fv $MODULES_DIR/lua/liolib.c $HEADERS_RDPARTY_DIR/lua/liolib.c +cp -fv $MODULES_DIR/lua/llex.c $HEADERS_RDPARTY_DIR/lua/llex.c +cp -fv $MODULES_DIR/lua/llex.h $HEADERS_RDPARTY_DIR/lua/llex.h +cp -fv $MODULES_DIR/lua/llimits.h $HEADERS_RDPARTY_DIR/lua/llimits.h +cp -fv $MODULES_DIR/lua/lmathlib.c $HEADERS_RDPARTY_DIR/lua/lmathlib.c +cp -fv $MODULES_DIR/lua/lmem.c $HEADERS_RDPARTY_DIR/lua/lmem.c +cp -fv $MODULES_DIR/lua/lmem.h $HEADERS_RDPARTY_DIR/lua/lmem.h +cp -fv $MODULES_DIR/lua/loadlib.c $HEADERS_RDPARTY_DIR/lua/loadlib.c +cp -fv $MODULES_DIR/lua/lobject.c $HEADERS_RDPARTY_DIR/lua/lobject.c +cp -fv $MODULES_DIR/lua/lobject.h $HEADERS_RDPARTY_DIR/lua/lobject.h +cp -fv $MODULES_DIR/lua/lopcodes.c $HEADERS_RDPARTY_DIR/lua/lopcodes.c +cp -fv $MODULES_DIR/lua/lopcodes.h $HEADERS_RDPARTY_DIR/lua/lopcodes.h +cp -fv $MODULES_DIR/lua/loslib.c $HEADERS_RDPARTY_DIR/lua/loslib.c +cp -fv $MODULES_DIR/lua/lparser.c $HEADERS_RDPARTY_DIR/lua/lparser.c +cp -fv $MODULES_DIR/lua/lparser.h $HEADERS_RDPARTY_DIR/lua/lparser.h +cp -fv $MODULES_DIR/lua/lprefix.h $HEADERS_RDPARTY_DIR/lua/lprefix.h +cp -fv $MODULES_DIR/lua/lstate.c $HEADERS_RDPARTY_DIR/lua/lstate.c +cp -fv $MODULES_DIR/lua/lstate.h $HEADERS_RDPARTY_DIR/lua/lstate.h +cp -fv $MODULES_DIR/lua/lstring.c $HEADERS_RDPARTY_DIR/lua/lstring.c +cp -fv $MODULES_DIR/lua/lstring.h $HEADERS_RDPARTY_DIR/lua/lstring.h +cp -fv $MODULES_DIR/lua/lstrlib.c $HEADERS_RDPARTY_DIR/lua/lstrlib.c +cp -fv $MODULES_DIR/lua/ltable.c $HEADERS_RDPARTY_DIR/lua/ltable.c +cp -fv $MODULES_DIR/lua/ltable.h $HEADERS_RDPARTY_DIR/lua/ltable.h +cp -fv $MODULES_DIR/lua/ltablib.c $HEADERS_RDPARTY_DIR/lua/ltablib.c +cp -fv $MODULES_DIR/lua/ltm.c $HEADERS_RDPARTY_DIR/lua/ltm.c +cp -fv $MODULES_DIR/lua/ltm.h $HEADERS_RDPARTY_DIR/lua/ltm.h +cp -fv $MODULES_DIR/lua/lua.h $HEADERS_RDPARTY_DIR/lua/lua.h +cp -fv $MODULES_DIR/lua/luaconf.h $HEADERS_RDPARTY_DIR/lua/luaconf.h +cp -fv $MODULES_DIR/lua/lualib.h $HEADERS_RDPARTY_DIR/lua/lualib.h +cp -fv $MODULES_DIR/lua/lundump.c $HEADERS_RDPARTY_DIR/lua/lundump.c +cp -fv $MODULES_DIR/lua/lundump.h $HEADERS_RDPARTY_DIR/lua/lundump.h +cp -fv $MODULES_DIR/lua/lutf8lib.c $HEADERS_RDPARTY_DIR/lua/lutf8lib.c +cp -fv $MODULES_DIR/lua/lvm.c $HEADERS_RDPARTY_DIR/lua/lvm.c +cp -fv $MODULES_DIR/lua/lvm.h $HEADERS_RDPARTY_DIR/lua/lvm.h +cp -fv $MODULES_DIR/lua/lzio.c $HEADERS_RDPARTY_DIR/lua/lzio.c +cp -fv $MODULES_DIR/lua/lzio.h $HEADERS_RDPARTY_DIR/lua/lzio.h + mkdir -p $SOURCES_RDPARTY_DIR/miniz cp -fv $MODULES_DIR/miniz/miniz.c $SOURCES_RDPARTY_DIR/miniz/miniz.c cp -fv $MODULES_DIR/miniz/miniz.h $SOURCES_RDPARTY_DIR/miniz/miniz.h @@ -48,6 +105,9 @@ cp -rfv $MODULES_DIR/pugixml/src/. $HEADERS_RDPARTY_DIR/pugixml/ mkdir -p $HEADERS_RDPARTY_DIR/rapidjson cp -rfv $MODULES_DIR/rapidjson/include/rapidjson/. $HEADERS_RDPARTY_DIR/rapidjson +mkdir -p $HEADERS_RDPARTY_DIR/sol +cp -rfv $MODULES_DIR/sol2/include/sol/. $HEADERS_RDPARTY_DIR/sol + mkdir -p $SOURCES_RDPARTY_DIR/stb cp -fv $MODULES_DIR/stb/stb_image.h $SOURCES_RDPARTY_DIR/stb/stb_image.h cp -fv $MODULES_DIR/stb/stb_image_resize.h $SOURCES_RDPARTY_DIR/stb/stb_image_resize.h diff --git a/scripts/upload_coverage.sh b/scripts/upload_coverage.sh index c49c8de9..a0bd8fd7 100755 --- a/scripts/upload_coverage.sh +++ b/scripts/upload_coverage.sh @@ -5,7 +5,7 @@ BUILD_DIR=`dirname "$BASH_SOURCE"`/../build mkdir -p $BUILD_DIR/coverage cd $BUILD_DIR/coverage cmake -DCMAKE_BUILD_TYPE=Debug -DE2D_BUILD_WITH_COVERAGE=ON ../.. -cmake --build . -- -j8 +cmake --build . lcov -d . -z ctest --verbose diff --git a/sources/3rdparty/imgui/imgui.cpp b/sources/3rdparty/imgui/imgui.cpp index 50dd9647..c2b489ad 100644 --- a/sources/3rdparty/imgui/imgui.cpp +++ b/sources/3rdparty/imgui/imgui.cpp @@ -1,11 +1,11 @@ -// dear imgui, v1.74 WIP +// dear imgui, v1.74 // (main code and documentation) // Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code. // Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase. // Get latest version at https://github.com/ocornut/imgui // Releases change-log at https://github.com/ocornut/imgui/releases -// Technical Support for Getting Started https://discourse.dearimgui.org/c/getting-started +// Technical Support for Getting Started https://github.com/ocornut/imgui/wiki // Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/2847 // Developed by Omar Cornut and every direct or indirect contributors to the GitHub. @@ -29,12 +29,12 @@ DOCUMENTATION - MISSION STATEMENT - END-USER GUIDE - PROGRAMMER GUIDE - - Read first. - - How to update to a newer version of Dear ImGui. - - Getting started with integrating Dear ImGui in your code/engine. - - This is how a simple application may look like (2 variations). - - This is how a simple rendering function may look like. - - Using gamepad/keyboard navigation controls. + - READ FIRST + - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI + - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE + - HOW A SIMPLE APPLICATION MAY LOOK LIKE (2 variations) + - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE + - USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS - API BREAKING CHANGES (read me when you update!) - FREQUENTLY ASKED QUESTIONS (FAQ) - Read all answers online: https://www.dearimgui.org/faq, or in docs/FAQ.md (with a Markdown viewer) @@ -45,7 +45,8 @@ CODE // [SECTION] FORWARD DECLARATIONS // [SECTION] CONTEXT AND MEMORY ALLOCATORS // [SECTION] MAIN USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) -// [SECTION] MISC HELPERS/UTILITIES (Maths, String, Format, Hash, File functions) +// [SECTION] MISC HELPERS/UTILITIES (Geomtry, String, Format, Hash, File functions) +// [SECTION] MISC HELPERS/UTILITIES (File functions) // [SECTION] MISC HELPERS/UTILITIES (ImText* functions) // [SECTION] MISC HELPERS/UTILITIES (Color functions) // [SECTION] ImGuiStorage @@ -54,6 +55,7 @@ CODE // [SECTION] ImGuiListClipper // [SECTION] RENDER HELPERS // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) +// [SECTION] ERROR CHECKING // [SECTION] SCROLLING // [SECTION] TOOLTIPS // [SECTION] POPUPS @@ -117,8 +119,8 @@ CODE PROGRAMMER GUIDE ================ - READ FIRST: - + READ FIRST + ---------- - Remember to read the FAQ (https://www.dearimgui.org/faq) - Your code creates the UI, if your code doesn't run the UI is gone! The UI can be highly dynamic, there are no construction or destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, less bugs. @@ -139,8 +141,8 @@ CODE However, imgui_internal.h can optionally export math operators for ImVec2/ImVec4, which we use in this codebase. - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (avoid using it in your code!). - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI: - + HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI + ---------------------------------------------- - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h) - Or maintain your own branch where you have imconfig.h modified. - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes. @@ -149,8 +151,8 @@ CODE likely be a comment about it. Please report any issue to the GitHub page! - Try to keep your copy of dear imgui reasonably up to date. - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE: - + GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE + --------------------------------------------------------------- - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library. - Add the Dear ImGui source files to your projects or using your preferred build system. It is recommended you build and statically link the .cpp files as part of your project and not as shared library (DLL). @@ -162,7 +164,8 @@ CODE - Refer to the bindings and demo applications in the examples/ folder for instruction on how to setup your code. - If you are running over a standard OS with a common graphics API, you should be able to use unmodified imgui_impl_*** files from the examples/ folder. - HOW A SIMPLE APPLICATION MAY LOOK LIKE: + HOW A SIMPLE APPLICATION MAY LOOK LIKE + -------------------------------------- EXHIBIT 1: USING THE EXAMPLE BINDINGS (imgui_impl_XXX.cpp files from the examples/ folder). // Application init: create a dear imgui context, setup some options, load fonts @@ -198,8 +201,7 @@ CODE ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); - HOW A SIMPLE APPLICATION MAY LOOK LIKE: - EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE. + EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE // Application init: create a dear imgui context, setup some options, load fonts ImGui::CreateContext(); @@ -253,8 +255,8 @@ CODE // Shutdown ImGui::DestroyContext(); - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE: - + HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE + --------------------------------------------- void void MyImGuiRenderFunction(ImDrawData* draw_data) { // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled @@ -291,7 +293,7 @@ CODE MyEngineScissor((int)(pcmd->ClipRect.x - pos.x), (int)(pcmd->ClipRect.y - pos.y), (int)(pcmd->ClipRect.z - pos.x), (int)(pcmd->ClipRect.w - pos.y)); // Render 'pcmd->ElemCount/3' indexed triangles. - // By default the indices ImDrawIdx are 16-bits, you can change them to 32-bits in imconfig.h if your engine doesn't support 16-bits indices. + // By default the indices ImDrawIdx are 16-bit, you can change them to 32-bit in imconfig.h if your engine doesn't support 16-bit indices. MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer); } idx_buffer += pcmd->ElemCount; @@ -306,7 +308,7 @@ CODE - Refer to the FAQ for more information. Amusingly, it is called a FAQ because people frequently run into the same issues! USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS - + ------------------------------------------ - The gamepad/keyboard navigation is fairly functional and keeps being improved. - Gamepad support is particularly useful to use dear imgui on a console system (e.g. PS4, Switch, XB1) without a mouse! - You can ask questions and report issues at https://github.com/ocornut/imgui/issues/787 @@ -351,13 +353,17 @@ CODE When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2019/11/21 (1.74) - ImFontAtlas::AddCustomRectRegular() now requires an ID larger than 0x110000 (instead of 0x10000) to conform with supporting Unicode planes 1-16 in a future update. ID below 0x110000 will now assert. + - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS to IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS for consistency. + - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_MATH_FUNCTIONS to IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS for consistency. + - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017): Begin() (5 arguments signature), IsRootWindowOrAnyChildHovered(), AlignFirstTextHeightToWidgets(), SetNextWindowPosCenter(), ImFont::Glyph. See docs/Changelog.txt or grep this log for details and new names, or see how they were implemented until 1.73. - 2019/10/14 (1.74) - inputs: Fixed a miscalculation in the keyboard/mouse "typematic" repeat delay/rate calculation, used by keys and e.g. repeating mouse buttons as well as the GetKeyPressedAmount() function. if you were using a non-default value for io.KeyRepeatRate (previous default was 0.250), you can add +io.KeyRepeatDelay to it to compensate for the fix. The function was triggering on: 0.0 and (delay+rate*N) where (N>=1). Fixed formula responds to (N>=0). Effectively it made io.KeyRepeatRate behave like it was set to (io.KeyRepeatRate + io.KeyRepeatDelay). If you never altered io.KeyRepeatRate nor used GetKeyPressedAmount() this won't affect you. - 2019/07/15 (1.72) - removed TreeAdvanceToLabelPos() which is rarely used and only does SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()). Kept redirection function (will obsolete). - 2019/07/12 (1.72) - renamed ImFontAtlas::CustomRect to ImFontAtlasCustomRect. Kept redirection typedef (will obsolete). - - 2019/06/14 (1.72) - removed redirecting functions/enums names that were marked obsolete in 1.51 (June 2017): ImGuiCol_Column*, ImGuiSetCond_*, IsItemHoveredRect(), IsPosHoveringAnyWindow(), IsMouseHoveringAnyWindow(), IsMouseHoveringWindow(), IMGUI_ONCE_UPON_A_FRAME. Grep this log for details and new names. + - 2019/06/14 (1.72) - removed redirecting functions/enums names that were marked obsolete in 1.51 (June 2017): ImGuiCol_Column*, ImGuiSetCond_*, IsItemHoveredRect(), IsPosHoveringAnyWindow(), IsMouseHoveringAnyWindow(), IsMouseHoveringWindow(), IMGUI_ONCE_UPON_A_FRAME. Grep this log for details and new names, or see how they were implemented until 1.71. - 2019/06/07 (1.71) - rendering of child window outer decorations (bg color, border, scrollbars) is now performed as part of the parent window. If you have overlapping child windows in a same parent, and relied on their relative z-order to be mapped to their submission order, this will affect your rendering. This optimization is disabled if the parent window has no visual output, because it appears to be the most common situation leading to the creation of overlapping child windows. @@ -468,14 +474,9 @@ CODE - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal. - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore. - If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you. - If your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. - This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color. - ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) - { - float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; - return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a); - } + If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you, otherwise if <1.0f you need tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. + This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color: + ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) { float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a); } If this is confusing, pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color. - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext(). - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection. @@ -745,7 +746,7 @@ CODE Q: How can I easily use icons in my application? Q: How can I load multiple fonts? Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? - >> See https://www.dearimgui.org/faq and misc/fonts/README.txt + >> See https://www.dearimgui.org/faq and docs/FONTS.txt Q&A: Community ============== @@ -837,7 +838,6 @@ static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 2.00f; // Lock static void SetCurrentWindow(ImGuiWindow* window); static void FindHoveredWindow(); static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags); -static void CheckStacksSize(ImGuiWindow* window, bool write); static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges); static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list); @@ -846,9 +846,9 @@ static void AddWindowToSortBuffer(ImVector* out_sorted static ImRect GetViewportRect(); // Settings -static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name); -static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line); -static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf); +static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name); +static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line); +static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf); // Platform Dependents default implementation for IO functions static const char* GetClipboardTextFn_DefaultImpl(void* user_data); @@ -873,6 +873,10 @@ static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_win static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); static int FindWindowFocusIndex(ImGuiWindow* window); +// Error Checking +static void ErrorCheckEndFrame(); +static void ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write); + // Misc static void UpdateMouseInputs(); static void UpdateMouseWheel(); @@ -1058,7 +1062,7 @@ ImGuiIO::ImGuiIO() // - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message void ImGuiIO::AddInputCharacter(unsigned int c) { - if (c > 0 && c < 0x10000) + if (c > 0 && c <= IM_UNICODE_CODEPOINT_MAX) InputQueueCharacters.push_back((ImWchar)c); } @@ -1068,7 +1072,7 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) { unsigned int c = 0; utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL); - if (c > 0 && c < 0x10000) + if (c > 0 && c <= IM_UNICODE_CODEPOINT_MAX) InputQueueCharacters.push_back((ImWchar)c); } } @@ -1079,7 +1083,7 @@ void ImGuiIO::ClearInputCharacters() } //----------------------------------------------------------------------------- -// [SECTION] MISC HELPERS/UTILITIES (Maths, String, Format, Hash, File functions) +// [SECTION] MISC HELPERS/UTILITIES (Geometry, String, Format, Hash, File functions) //----------------------------------------------------------------------------- ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p) @@ -1183,7 +1187,7 @@ const char* ImStrchrRange(const char* str, const char* str_end, char c) int ImStrlenW(const ImWchar* str) { - //return (int)wcslen((const wchar_t*)str); // FIXME-OPT: Could use this when wchar_t are 16-bits + //return (int)wcslen((const wchar_t*)str); // FIXME-OPT: Could use this when wchar_t are 16-bit int n = 0; while (*str++) n++; return n; @@ -1241,15 +1245,26 @@ void ImStrTrimBlanks(char* buf) buf[p - p_start] = 0; // Zero terminate } +const char* ImStrSkipBlank(const char* str) +{ + while (str[0] == ' ' || str[0] == '\t') + str++; + return str; +} + // A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size). // Ideally we would test for only one of those limits at runtime depending on the behavior the vsnprintf(), but trying to deduct it at compile time sounds like a pandora can of worm. // B) When buf==NULL vsnprintf() will return the output size. -#ifndef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS +#ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS +// We support stb_sprintf which is much faster (see: https://github.com/nothings/stb/blob/master/stb_sprintf.h) +// You may set IMGUI_USE_STB_SPRINTF to use our default wrapper, or set IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS +// and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are +// designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.) //#define IMGUI_USE_STB_SPRINTF #ifdef IMGUI_USE_STB_SPRINTF #define STB_SPRINTF_IMPLEMENTATION -#include "imstb_sprintf.h" +#include "stb_sprintf.h" #endif #if defined(_MSC_VER) && !defined(vsnprintf) @@ -1288,7 +1303,7 @@ int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) buf[w] = 0; return w; } -#endif // #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS +#endif // #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // CRC32 needs a 1KB lookup table (not cache friendly) // Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily: @@ -1360,10 +1375,16 @@ ImU32 ImHashStr(const char* data_p, size_t data_size, ImU32 seed) return ~crc; } -FILE* ImFileOpen(const char* filename, const char* mode) +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (File functions) +//----------------------------------------------------------------------------- + +// Default file functions +#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS +ImFileHandle ImFileOpen(const char* filename, const char* mode) { -#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__GNUC__) - // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. Converting both strings from UTF-8 to wchar format (using a single allocation, because we can) +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__) + // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. const int filename_wsize = ImTextCountCharsFromUtf8(filename, NULL) + 1; const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1; ImVector buf; @@ -1376,42 +1397,48 @@ FILE* ImFileOpen(const char* filename, const char* mode) #endif } -// Load file content into memory +// We should in theory be using fseeko()/ftello() with off_t and _fseeki64()/_ftelli64() with __int64, waiting for the PR that does that in a very portable pre-C++11 zero-warnings way. +bool ImFileClose(ImFileHandle f) { return fclose(f) == 0; } +ImU64 ImFileGetSize(ImFileHandle f) { long off = 0, sz = 0; return ((off = ftell(f)) != -1 && !fseek(f, 0, SEEK_END) && (sz = ftell(f)) != -1 && !fseek(f, off, SEEK_SET)) ? (ImU64)sz : (ImU64)-1; } +ImU64 ImFileRead(void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fread(data, (size_t)sz, (size_t)count, f); } +ImU64 ImFileWrite(const void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fwrite(data, (size_t)sz, (size_t)count, f); } +#endif // #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS + +// Helper: Load file content into memory // Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree() -void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size, int padding_bytes) +void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size, int padding_bytes) { - IM_ASSERT(filename && file_open_mode); + IM_ASSERT(filename && mode); if (out_file_size) *out_file_size = 0; - FILE* f; - if ((f = ImFileOpen(filename, file_open_mode)) == NULL) + ImFileHandle f; + if ((f = ImFileOpen(filename, mode)) == NULL) return NULL; - long file_size_signed; - if (fseek(f, 0, SEEK_END) || (file_size_signed = ftell(f)) == -1 || fseek(f, 0, SEEK_SET)) + size_t file_size = (size_t)ImFileGetSize(f); + if (file_size == (size_t)-1) { - fclose(f); + ImFileClose(f); return NULL; } - size_t file_size = (size_t)file_size_signed; void* file_data = IM_ALLOC(file_size + padding_bytes); if (file_data == NULL) { - fclose(f); + ImFileClose(f); return NULL; } - if (fread(file_data, 1, file_size, f) != file_size) + if (ImFileRead(file_data, 1, file_size, f) != file_size) { - fclose(f); + ImFileClose(f); IM_FREE(file_data); return NULL; } if (padding_bytes > 0) memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes); - fclose(f); + ImFileClose(f); if (out_file_size) *out_file_size = file_size; @@ -1422,7 +1449,7 @@ void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_ // [SECTION] MISC HELPERS/UTILITIES (ImText* functions) //----------------------------------------------------------------------------- -// Convert UTF-8 to 32-bits character, process single character input. +// Convert UTF-8 to 32-bit character, process single character input. // Based on stb_from_utf8() from github.com/nothings/stb/ // We handle UTF-8 decoding error by skipping forward. int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end) @@ -1437,7 +1464,7 @@ int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* } if ((*str & 0xe0) == 0xc0) { - *out_char = 0xFFFD; // will be invalid but not end of string + *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string if (in_text_end && in_text_end - (const char*)str < 2) return 1; if (*str < 0xc2) return 2; c = (unsigned int)((*str++ & 0x1f) << 6); @@ -1448,7 +1475,7 @@ int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* } if ((*str & 0xf0) == 0xe0) { - *out_char = 0xFFFD; // will be invalid but not end of string + *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string if (in_text_end && in_text_end - (const char*)str < 3) return 1; if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3; if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below @@ -1462,7 +1489,7 @@ int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* } if ((*str & 0xf8) == 0xf0) { - *out_char = 0xFFFD; // will be invalid but not end of string + *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string if (in_text_end && in_text_end - (const char*)str < 4) return 1; if (*str > 0xf4) return 4; if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4; @@ -1493,7 +1520,7 @@ int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const cha in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); if (c == 0) break; - if (c < 0x10000) // FIXME: Losing characters that don't fit in 2 bytes + if (c <= IM_UNICODE_CODEPOINT_MAX) // FIXME: Losing characters that don't fit in 2 bytes *buf_out++ = (ImWchar)c; } *buf_out = 0; @@ -1511,7 +1538,7 @@ int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end) in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); if (c == 0) break; - if (c < 0x10000) + if (c <= IM_UNICODE_CODEPOINT_MAX) char_count++; } return char_count; @@ -2517,7 +2544,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) LastTimeActive = -1.0f; ItemWidthDefault = 0.0f; FontWindowScale = 1.0f; - SettingsIdx = -1; + SettingsOffset = -1; DrawList = &DrawListInst; DrawList->_OwnerName = Name; @@ -2776,8 +2803,13 @@ void ImGui::ItemSize(const ImVec2& size, float text_baseline_y) if (window->SkipItems) return; + // We increase the height in this function to accommodate for baseline offset. + // In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor, + // but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect. + const float offset_to_match_baseline_y = (text_baseline_y >= 0) ? ImMax(0.0f, window->DC.CurrLineTextBaseOffset - text_baseline_y) : 0.0f; + const float line_height = ImMax(window->DC.CurrLineSize.y, size.y + offset_to_match_baseline_y); + // Always align ourselves on pixel boundaries - const float line_height = ImMax(window->DC.CurrLineSize.y, size.y); //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG] window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x; window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y; @@ -3526,7 +3558,7 @@ void ImGui::NewFrame() } g.Time += g.IO.DeltaTime; - g.FrameScopeActive = true; + g.WithinFrameScope = true; g.FrameCount += 1; g.TooltipOverrideCount = 0; g.WindowsActiveCount = 0; @@ -3700,7 +3732,7 @@ void ImGui::NewFrame() // This fallback is particularly important as it avoid ImGui:: calls from crashing. SetNextWindowSize(ImVec2(400,400), ImGuiCond_FirstUseEver); Begin("Debug##Default"); - g.FrameScopePushedImplicitWindow = true; + g.WithinFrameScopeWithImplicitWindow = true; #ifdef IMGUI_ENABLE_TEST_ENGINE ImGuiTestEngineHook_PostNewFrame(&g); @@ -3738,13 +3770,15 @@ void ImGui::Initialize(ImGuiContext* context) IM_ASSERT(!g.Initialized && !g.SettingsLoaded); // Add .ini handle for ImGuiWindow type - ImGuiSettingsHandler ini_handler; - ini_handler.TypeName = "Window"; - ini_handler.TypeHash = ImHashStr("Window"); - ini_handler.ReadOpenFn = SettingsHandlerWindow_ReadOpen; - ini_handler.ReadLineFn = SettingsHandlerWindow_ReadLine; - ini_handler.WriteAllFn = SettingsHandlerWindow_WriteAll; - g.SettingsHandlers.push_back(ini_handler); + { + ImGuiSettingsHandler ini_handler; + ini_handler.TypeName = "Window"; + ini_handler.TypeHash = ImHashStr("Window"); + ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen; + ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine; + ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll; + g.SettingsHandlers.push_back(ini_handler); + } g.Initialized = true; } @@ -3803,14 +3837,15 @@ void ImGui::Shutdown(ImGuiContext* context) g.PrivateClipboard.clear(); g.InputTextState.ClearFreeMemory(); - for (int i = 0; i < g.SettingsWindows.Size; i++) - IM_DELETE(g.SettingsWindows[i].Name); g.SettingsWindows.clear(); g.SettingsHandlers.clear(); - if (g.LogFile && g.LogFile != stdout) + if (g.LogFile) { - fclose(g.LogFile); +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + if (g.LogFile != stdout) +#endif + ImFileClose(g.LogFile); g.LogFile = NULL; } g.LogBuffer.clear(); @@ -3876,7 +3911,7 @@ static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* d // (A) Handle the ImDrawCmd::VtxOffset value in your renderer back-end, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'. // Most example back-ends already support this from 1.71. Pre-1.71 back-ends won't. // Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them. - // (B) Or handle 32-bits indices in your renderer back-end, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h. + // (B) Or handle 32-bit indices in your renderer back-end, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h. // Most example back-ends already support this. For example, the OpenGL example code detect index size at compile-time: // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); // Your own engine or render API may use different parameters or function calls to specify index sizes. @@ -3969,7 +4004,7 @@ void ImGui::EndFrame() IM_ASSERT(g.Initialized); if (g.FrameCountEnded == g.FrameCount) // Don't process EndFrame() multiple times. return; - IM_ASSERT(g.FrameScopeActive && "Forgot to call ImGui::NewFrame()?"); + IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?"); // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f)) @@ -3978,24 +4013,10 @@ void ImGui::EndFrame() g.PlatformImeLastPos = g.PlatformImePos; } - // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you - // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API). - if (g.CurrentWindowStack.Size != 1) - { - if (g.CurrentWindowStack.Size > 1) - { - IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); - while (g.CurrentWindowStack.Size > 1) // FIXME-ERRORHANDLING - End(); - } - else - { - IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); - } - } + ErrorCheckEndFrame(); // Hide implicit/fallback "Debug" window if it hasn't been used - g.FrameScopePushedImplicitWindow = false; + g.WithinFrameScopeWithImplicitWindow = false; if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed) g.CurrentWindow->Active = false; End(); @@ -4022,7 +4043,7 @@ void ImGui::EndFrame() } // End frame - g.FrameScopeActive = false; + g.WithinFrameScope = false; g.FrameCountEnded = g.FrameCount; // Initiate moving window + handle left-click and right-click focus @@ -4445,6 +4466,12 @@ bool ImGui::IsItemClicked(int mouse_button) return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None); } +bool ImGui::IsItemToggledOpen() +{ + ImGuiContext& g = *GImGui; + return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false; +} + bool ImGui::IsItemToggledSelection() { ImGuiContext& g = *GImGui; @@ -4583,7 +4610,10 @@ void ImGui::EndChild() ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(g.WithinEndChild == false); IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() callss + + g.WithinEndChild = true; if (window->BeginCount > 1) { End(); @@ -4615,6 +4645,7 @@ void ImGui::EndChild() ItemAdd(bb, 0); } } + g.WithinEndChild = false; } // Helper to create a child window / scrolling region that looks like a normal widget frame. @@ -4637,22 +4668,6 @@ void ImGui::EndChildFrame() EndChild(); } -// Save and compare stack sizes on Begin()/End() to detect usage errors -static void CheckStacksSize(ImGuiWindow* window, bool write) -{ - // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) - ImGuiContext& g = *GImGui; - short* p_backup = &window->DC.StackSizesBackup[0]; - { int current = window->IDStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "PushID/PopID or TreeNode/TreePop Mismatch!"); p_backup++; } // Too few or too many PopID()/TreePop() - { int current = window->DC.GroupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!"); p_backup++; } // Too few or too many EndGroup() - { int current = g.BeginPopupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup() - // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them. - { int current = g.ColorModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleColor/PopStyleColor Mismatch!"); p_backup++; } // Too few or too many PopStyleColor() - { int current = g.StyleModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleVar/PopStyleVar Mismatch!"); p_backup++; } // Too few or too many PopStyleVar() - { int current = g.FontStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushFont/PopFont Mismatch!"); p_backup++; } // Too few or too many PopFont() - IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup)); -} - static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled) { window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags); @@ -4690,7 +4705,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID)) { // Retrieve settings from .ini file - window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings); + window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); window->Pos = ImVec2(settings->Pos.x, settings->Pos.y); window->Collapsed = settings->Collapsed; @@ -4741,8 +4756,8 @@ static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size g.NextWindowData.SizeCallback(&data); new_size = data.DesiredSize; } - new_size.x = ImFloor(new_size.x); - new_size.y = ImFloor(new_size.y); + new_size.x = IM_FLOOR(new_size.x); + new_size.y = IM_FLOOR(new_size.y); } // Minimum size @@ -4843,10 +4858,10 @@ struct ImGuiResizeGripDef static const ImGuiResizeGripDef resize_grip_def[4] = { - { ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower right - { ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower left - { ImVec2(0,0), ImVec2(+1,+1), 6, 9 }, // Upper left - { ImVec2(1,0), ImVec2(-1,+1), 9,12 }, // Upper right + { ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower-right + { ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower-left + { ImVec2(0,0), ImVec2(+1,+1), 6, 9 }, // Upper-left (Unused) + { ImVec2(1,0), ImVec2(-1,+1), 9,12 }, // Upper-right (Unused) }; static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness) @@ -4861,6 +4876,17 @@ static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_ return ImRect(); } +// 0..3: corners (Lower-right, Lower-left, Unused, Unused) +// 4..7: borders (Top, Right, Bottom, Left) +ImGuiID ImGui::GetWindowResizeID(ImGuiWindow* window, int n) +{ + IM_ASSERT(n >= 0 && n <= 7); + ImGuiID id = window->ID; + id = ImHashStr("#RESIZE", 0, id); + id = ImHashData(&n, sizeof(int), id); + return id; +} + // Handle resize for: Resize Grips, Borders, Gamepad // Return true when using auto-fit (double click on resize grip) static bool ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]) @@ -4898,7 +4924,7 @@ static bool ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x); if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y); bool hovered, held; - ButtonBehavior(resize_rect, window->GetID((void*)(intptr_t)resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); + ButtonBehavior(resize_rect, window->GetID(resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); //GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255)); if (hovered || held) g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE; @@ -4924,7 +4950,7 @@ static bool ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au { bool hovered, held; ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); - ButtonBehavior(border_rect, window->GetID((void*)(intptr_t)(border_n + 4)), &hovered, &held, ImGuiButtonFlags_FlattenChildren); + ButtonBehavior(border_rect, window->GetID(border_n + 4), &hovered, &held, ImGuiButtonFlags_FlattenChildren); //GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255)); if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held) { @@ -5035,6 +5061,9 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar ImGuiStyle& style = g.Style; ImGuiWindowFlags flags = window->Flags; + // Ensure that ScrollBar doesn't read last frame's SkipItems + window->SkipItems = false; + // Draw window + handle manual resize // As we highlight the title bar when want_focus is set, multiple reappearing windows will have have their title bar highlighted on their reappearing frame. const float window_rounding = window->WindowRounding; @@ -5216,7 +5245,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; IM_ASSERT(name != NULL && name[0] != '\0'); // Window name required - IM_ASSERT(g.FrameScopeActive); // Forgot to call ImGui::NewFrame() + IM_ASSERT(g.WithinFrameScope); // Forgot to call ImGui::NewFrame() IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet // Find or create @@ -5278,7 +5307,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow() g.CurrentWindowStack.push_back(window); g.CurrentWindow = NULL; - CheckStacksSize(window, true); + ErrorCheckBeginEndCompareStacksSize(window, true); if (flags & ImGuiWindowFlags_Popup) { ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; @@ -5523,7 +5552,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Handle manual resize: Resize Grips, Borders, Gamepad int border_held = -1; ImU32 resize_grip_col[4] = {}; - const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // 4 + const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it. const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); if (!window->Collapsed) if (UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0])) @@ -5683,14 +5712,14 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x; window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y; - // [LEGACY] Contents Region - // FIXME-OBSOLETE: window->ContentsRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. + // [LEGACY] Content Region + // FIXME-OBSOLETE: window->ContentRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. // Used by: // - Mouse wheel scrolling + many other things - window->ContentsRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x; - window->ContentsRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height; - window->ContentsRegionRect.Max.x = window->ContentsRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x)); - window->ContentsRegionRect.Max.y = window->ContentsRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y)); + window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x; + window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height; + window->ContentRegionRect.Max.x = window->ContentRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x)); + window->ContentRegionRect.Max.y = window->ContentRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y)); // Setup drawing context // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.) @@ -5814,35 +5843,24 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) return !skip_items; } -// Old Begin() API with 5 parameters, avoid calling this version directly! Use SetNextWindowSize()/SetNextWindowBgAlpha() + Begin() instead. -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_first_use, float bg_alpha_override, ImGuiWindowFlags flags) -{ - // Old API feature: we could pass the initial window size as a parameter. This was misleading because it only had an effect if the window didn't have data in the .ini file. - if (size_first_use.x != 0.0f || size_first_use.y != 0.0f) - SetNextWindowSize(size_first_use, ImGuiCond_FirstUseEver); - - // Old API feature: override the window background alpha with a parameter. - if (bg_alpha_override >= 0.0f) - SetNextWindowBgAlpha(bg_alpha_override); - - return Begin(name, p_open, flags); -} -#endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS - void ImGui::End() { ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; - if (g.CurrentWindowStack.Size <= 1 && g.FrameScopePushedImplicitWindow) + // Error checking: verify that user hasn't called End() too many times! + if (g.CurrentWindowStack.Size <= 1 && g.WithinFrameScopeWithImplicitWindow) { - IM_ASSERT(g.CurrentWindowStack.Size > 1 && "Calling End() too many times!"); - return; // FIXME-ERRORHANDLING + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!"); + return; } IM_ASSERT(g.CurrentWindowStack.Size > 0); - ImGuiWindow* window = g.CurrentWindow; + // Error checking: verify that user doesn't directly call End() on a child window. + if (window->Flags & ImGuiWindowFlags_ChildWindow) + IM_ASSERT_USER_ERROR(g.WithinEndChild, "Must call EndChild() and not End()!"); + // Close anything that is open if (window->DC.CurrentColumns) EndColumns(); PopClipRect(); // Inner window clip rectangle @@ -5855,7 +5873,7 @@ void ImGui::End() g.CurrentWindowStack.pop_back(); if (window->Flags & ImGuiWindowFlags_Popup) g.BeginPopupStack.pop_back(); - CheckStacksSize(window, false); + ErrorCheckBeginEndCompareStacksSize(window, false); SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back()); } @@ -6463,7 +6481,7 @@ void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond con if (size.x > 0.0f) { window->AutoFitFramesX = 0; - window->SizeFull.x = ImFloor(size.x); + window->SizeFull.x = IM_FLOOR(size.x); } else { @@ -6473,7 +6491,7 @@ void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond con if (size.y > 0.0f) { window->AutoFitFramesY = 0; - window->SizeFull.y = ImFloor(size.y); + window->SizeFull.y = IM_FLOOR(size.y); } else { @@ -6609,7 +6627,7 @@ ImVec2 ImGui::GetContentRegionMax() { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - ImVec2 mx = window->ContentsRegionRect.Max - window->Pos; + ImVec2 mx = window->ContentRegionRect.Max - window->Pos; if (window->DC.CurrentColumns) mx.x = window->WorkRect.Max.x - window->Pos.x; return mx; @@ -6620,7 +6638,7 @@ ImVec2 ImGui::GetContentRegionMaxAbs() { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - ImVec2 mx = window->ContentsRegionRect.Max; + ImVec2 mx = window->ContentRegionRect.Max; if (window->DC.CurrentColumns) mx.x = window->WorkRect.Max.x; return mx; @@ -6636,19 +6654,19 @@ ImVec2 ImGui::GetContentRegionAvail() ImVec2 ImGui::GetWindowContentRegionMin() { ImGuiWindow* window = GImGui->CurrentWindow; - return window->ContentsRegionRect.Min - window->Pos; + return window->ContentRegionRect.Min - window->Pos; } ImVec2 ImGui::GetWindowContentRegionMax() { ImGuiWindow* window = GImGui->CurrentWindow; - return window->ContentsRegionRect.Max - window->Pos; + return window->ContentRegionRect.Max - window->Pos; } float ImGui::GetWindowContentRegionWidth() { ImGuiWindow* window = GImGui->CurrentWindow; - return window->ContentsRegionRect.GetWidth(); + return window->ContentRegionRect.GetWidth(); } float ImGui::GetTextLineHeight() @@ -6928,7 +6946,7 @@ void ImGui::EndGroup() } window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. - ItemSize(group_bb.GetSize(), 0.0f); + ItemSize(group_bb.GetSize()); ItemAdd(group_bb, 0); // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group. @@ -7001,6 +7019,54 @@ void ImGui::Unindent(float indent_w) } +//----------------------------------------------------------------------------- +// [SECTION] ERROR CHECKING +//----------------------------------------------------------------------------- + +static void ImGui::ErrorCheckEndFrame() +{ + // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you + // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API). + ImGuiContext& g = *GImGui; + if (g.CurrentWindowStack.Size != 1) + { + if (g.CurrentWindowStack.Size > 1) + { + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); + while (g.CurrentWindowStack.Size > 1) + End(); + } + else + { + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); + } + } + +} + +// Save and compare stack sizes on Begin()/End() to detect usage errors +// Begin() calls this with write=true +// End() calls this with write=false +static void ImGui::ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write) +{ + ImGuiContext& g = *GImGui; + short* p = &window->DC.StackSizesBackup[0]; + + // Window stacks + // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) + { int n = window->IDStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "PushID/PopID or TreeNode/TreePop Mismatch!"); p++; } // Too few or too many PopID()/TreePop() + { int n = window->DC.GroupStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginGroup/EndGroup Mismatch!"); p++; } // Too few or too many EndGroup() + + // Global stacks + // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them. + { int n = g.BeginPopupStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch!"); p++; }// Too few or too many EndMenu()/EndPopup() + { int n = g.ColorModifiers.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleColor/PopStyleColor Mismatch!"); p++; } // Too few or too many PopStyleColor() + { int n = g.StyleModifiers.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleVar/PopStyleVar Mismatch!"); p++; } // Too few or too many PopStyleVar() + { int n = g.FontStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushFont/PopFont Mismatch!"); p++; } // Too few or too many PopFont() + IM_ASSERT(p == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup)); +} + + //----------------------------------------------------------------------------- // [SECTION] SCROLLING //----------------------------------------------------------------------------- @@ -7479,13 +7545,19 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla void ImGui::EndPopup() { ImGuiContext& g = *GImGui; - IM_ASSERT(g.CurrentWindow->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls IM_ASSERT(g.BeginPopupStack.Size > 0); // Make all menus and popups wrap around for now, may need to expose that policy. - NavMoveRequestTryWrapping(g.CurrentWindow, ImGuiNavMoveFlags_LoopY); + NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY); + // Child-popups don't need to be layed out + IM_ASSERT(g.WithinEndChild == false); + if (window->Flags & ImGuiWindowFlags_ChildWindow) + g.WithinEndChild = true; End(); + g.WithinEndChild = false; } bool ImGui::OpenPopupOnItemClick(const char* str_id, int mouse_button) @@ -8163,7 +8235,7 @@ static void ImGui::NavUpdate() g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL); // Process NavCancel input (to close a popup, get back to parent, clear focus) - if (IsNavInputPressed(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed)) + if (IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed)) { if (g.ActiveId != 0) { @@ -8207,14 +8279,14 @@ static void ImGui::NavUpdate() if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) { bool activate_down = IsNavInputDown(ImGuiNavInput_Activate); - bool activate_pressed = activate_down && IsNavInputPressed(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed); + bool activate_pressed = activate_down && IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed); if (g.ActiveId == 0 && activate_pressed) g.NavActivateId = g.NavId; if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down) g.NavActivateDownId = g.NavId; if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed) g.NavActivatePressedId = g.NavId; - if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputPressed(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed)) + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed)) g.NavInputId = g.NavId; } if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) @@ -8235,10 +8307,11 @@ static void ImGui::NavUpdate() g.NavMoveRequestFlags = ImGuiNavMoveFlags_None; if (g.NavWindow && !g.NavWindowingTarget && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) { - if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadLeft, ImGuiNavInput_KeyLeft_, ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Left; } - if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadRight,ImGuiNavInput_KeyRight_,ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Right; } - if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadUp, ImGuiNavInput_KeyUp_, ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Up; } - if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadDown, ImGuiNavInput_KeyDown_, ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Down; } + const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat; + if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && (IsNavInputTest(ImGuiNavInput_DpadLeft, read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_, read_mode))) { g.NavMoveDir = ImGuiDir_Left; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && (IsNavInputTest(ImGuiNavInput_DpadUp, read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_, read_mode))) { g.NavMoveDir = ImGuiDir_Up; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && (IsNavInputTest(ImGuiNavInput_DpadDown, read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_, read_mode))) { g.NavMoveDir = ImGuiDir_Down; } } g.NavMoveClipDir = g.NavMoveDir; } @@ -8277,7 +8350,7 @@ static void ImGui::NavUpdate() { // *Fallback* manual-scroll with Nav directional keys when window has no navigable item ImGuiWindow* window = g.NavWindow; - const float scroll_speed = ImFloor(window->CalcFontSize() * 100 * g.IO.DeltaTime + 0.5f); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. + const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * g.IO.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest) { if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) @@ -8533,7 +8606,7 @@ static void ImGui::NavUpdateWindowing() } // Start CTRL-TAB or Square+L/R window selection - bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputPressed(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed); + bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed); bool start_windowing_with_keyboard = !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard); if (start_windowing_with_gamepad || start_windowing_with_keyboard) if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1)) @@ -8552,7 +8625,7 @@ static void ImGui::NavUpdateWindowing() g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // Select window to focus - const int focus_change_dir = (int)IsNavInputPressed(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputPressed(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow); + const int focus_change_dir = (int)IsNavInputTest(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputTest(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow); if (focus_change_dir != 0) { NavUpdateWindowingHighlightWindow(focus_change_dir); @@ -8584,9 +8657,9 @@ static void ImGui::NavUpdateWindowing() // Keyboard: Press and Release ALT to toggle menu layer // FIXME: We lack an explicit IO variable for "is the imgui window focused", so compare mouse validity to detect the common case of back-end clearing releases all keys on ALT-TAB - if (IsNavInputPressed(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Pressed)) + if (IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Pressed)) g.NavWindowingToggleLayer = true; - if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && g.NavWindowingToggleLayer && IsNavInputPressed(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released)) + if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && g.NavWindowingToggleLayer && IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released)) if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev)) apply_toggle_layer = true; @@ -9003,9 +9076,15 @@ void ImGui::LogText(const char* fmt, ...) va_list args; va_start(args, fmt); if (g.LogFile) - vfprintf(g.LogFile, fmt, args); - else + { + g.LogBuffer.Buf.resize(0); g.LogBuffer.appendfv(fmt, args); + ImFileWrite(g.LogBuffer.c_str(), sizeof(char), (ImU64)g.LogBuffer.size(), g.LogFile); + } + else + { + g.LogBuffer.appendfv(fmt, args); + } va_end(args); } @@ -9082,8 +9161,11 @@ void ImGui::LogToTTY(int auto_open_depth) ImGuiContext& g = *GImGui; if (g.LogEnabled) return; + IM_UNUSED(auto_open_depth); +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS LogBegin(ImGuiLogType_TTY, auto_open_depth); g.LogFile = stdout; +#endif } // Start logging/capturing text output to given file @@ -9100,8 +9182,8 @@ void ImGui::LogToFile(int auto_open_depth, const char* filename) filename = g.IO.LogFilename; if (!filename || !filename[0]) return; - FILE* f = ImFileOpen(filename, "ab"); - if (f == NULL) + ImFileHandle f = ImFileOpen(filename, "ab"); + if (!f) { IM_ASSERT(0); return; @@ -9138,10 +9220,12 @@ void ImGui::LogFinish() switch (g.LogType) { case ImGuiLogType_TTY: +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS fflush(g.LogFile); +#endif break; case ImGuiLogType_File: - fclose(g.LogFile); + ImFileClose(g.LogFile); break; case ImGuiLogType_Buffer: break; @@ -9167,7 +9251,11 @@ void ImGui::LogButtons() ImGuiContext& g = *GImGui; PushID("LogButtons"); +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS const bool log_to_tty = Button("Log To TTY"); SameLine(); +#else + const bool log_to_tty = false; +#endif const bool log_to_file = Button("Log To File"); SameLine(); const bool log_to_clipboard = Button("Log To Clipboard"); SameLine(); PushAllowKeyboardFocus(false); @@ -9207,25 +9295,31 @@ void ImGui::MarkIniSettingsDirty(ImGuiWindow* window) ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) { ImGuiContext& g = *GImGui; - g.SettingsWindows.push_back(ImGuiWindowSettings()); - ImGuiWindowSettings* settings = &g.SettingsWindows.back(); + #if !IMGUI_DEBUG_INI_SETTINGS // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() // Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier. if (const char* p = strstr(name, "###")) name = p; #endif - settings->Name = ImStrdup(name); - settings->ID = ImHashStr(name); + const size_t name_len = strlen(name); + + // Allocate chunk + const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1; + ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size); + IM_PLACEMENT_NEW(settings) ImGuiWindowSettings(); + settings->ID = ImHashStr(name, name_len); + memcpy(settings->GetName(), name, name_len + 1); // Store with zero terminator + return settings; } ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id) { ImGuiContext& g = *GImGui; - for (int i = 0; i != g.SettingsWindows.Size; i++) - if (g.SettingsWindows[i].ID == id) - return &g.SettingsWindows[i]; + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + if (settings->ID == id) + return settings; return NULL; } @@ -9293,18 +9387,12 @@ void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size) line_end[-1] = 0; const char* name_end = line_end - 1; const char* type_start = line + 1; - char* type_end = (char*)(intptr_t)ImStrchrRange(type_start, name_end, ']'); + char* type_end = (char*)(void*)ImStrchrRange(type_start, name_end, ']'); const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL; if (!type_end || !name_start) - { - name_start = type_start; // Import legacy entries that have no type - type_start = "Window"; - } - else - { - *type_end = 0; // Overwrite first ']' - name_start++; // Skip second '[' - } + continue; + *type_end = 0; // Overwrite first ']' + name_start++; // Skip second '[' entry_handler = FindSettingsHandler(type_start); entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL; } @@ -9327,11 +9415,11 @@ void ImGui::SaveIniSettingsToDisk(const char* ini_filename) size_t ini_data_size = 0; const char* ini_data = SaveIniSettingsToMemory(&ini_data_size); - FILE* f = ImFileOpen(ini_filename, "wt"); + ImFileHandle f = ImFileOpen(ini_filename, "wt"); if (!f) return; - fwrite(ini_data, sizeof(char), ini_data_size, f); - fclose(f); + ImFileWrite(ini_data, sizeof(char), ini_data_size, f); + ImFileClose(f); } // Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer @@ -9351,7 +9439,7 @@ const char* ImGui::SaveIniSettingsToMemory(size_t* out_size) return g.SettingsIniData.c_str(); } -static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) +static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) { ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHashStr(name)); if (!settings) @@ -9359,7 +9447,7 @@ static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler* return (void*)settings; } -static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) +static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) { ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry; int x, y; @@ -9369,7 +9457,7 @@ static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, else if (sscanf(line, "Collapsed=%d", &i) == 1) settings->Collapsed = (i != 0); } -static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) +static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) { // Gather data from windows that were active during this session // (if a window wasn't opened in this session we preserve its settings) @@ -9380,11 +9468,11 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl if (window->Flags & ImGuiWindowFlags_NoSavedSettings) continue; - ImGuiWindowSettings* settings = (window->SettingsIdx != -1) ? &g.SettingsWindows[window->SettingsIdx] : ImGui::FindWindowSettings(window->ID); + ImGuiWindowSettings* settings = (window->SettingsOffset != -1) ? g.SettingsWindows.ptr_from_offset(window->SettingsOffset) : ImGui::FindWindowSettings(window->ID); if (!settings) { settings = ImGui::CreateNewWindowSettings(window->Name); - window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings); + window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); } IM_ASSERT(settings->ID == window->ID); settings->Pos = ImVec2ih((short)window->Pos.x, (short)window->Pos.y); @@ -9393,15 +9481,15 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl } // Write to text buffer - buf->reserve(buf->size() + g.SettingsWindows.Size * 96); // ballpark reserve - for (int i = 0; i != g.SettingsWindows.Size; i++) + buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) { - const ImGuiWindowSettings* settings = &g.SettingsWindows[i]; - buf->appendf("[%s][%s]\n", handler->TypeName, settings->Name); + const char* settings_name = settings->GetName(); + buf->appendf("[%s][%s]\n", handler->TypeName, settings_name); buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y); buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y); buf->appendf("Collapsed=%d\n", settings->Collapsed); - buf->appendf("\n"); + buf->append("\n"); } } @@ -9433,6 +9521,10 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl #else #include #endif +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have Win32 functions +#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS +#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS +#endif #elif defined(__APPLE__) #include #endif @@ -9595,6 +9687,20 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {} //----------------------------------------------------------------------------- #ifndef IMGUI_DISABLE_METRICS_WINDOW +// Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds. +static void MetricsHelpMarker(const char* desc) +{ + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted(desc); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } +} + void ImGui::ShowMetricsWindow(bool* p_open) { if (!ImGui::Begin("Dear ImGui Metrics", p_open)) @@ -9604,12 +9710,12 @@ void ImGui::ShowMetricsWindow(bool* p_open) } // State - enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Contents, WRT_ContentsRegionRect, WRT_Count }; // Windows Rect Type - const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Contents", "ContentsRegionRect" }; + enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentRegionRect, WRT_Count }; // Windows Rect Type + const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Content", "ContentRegionRect" }; static bool show_windows_rects = false; static int show_windows_rect_type = WRT_WorkRect; static bool show_windows_begin_order = false; - static bool show_drawcmd_clip_rects = true; + static bool show_drawcmd_details = true; // Basic info ImGuiContext& g = *GImGui; @@ -9636,8 +9742,8 @@ void ImGui::ShowMetricsWindow(bool* p_open) else if (rect_type == WRT_InnerRect) { return window->InnerRect; } else if (rect_type == WRT_InnerClipRect) { return window->InnerClipRect; } else if (rect_type == WRT_WorkRect) { return window->WorkRect; } - else if (rect_type == WRT_Contents) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); } - else if (rect_type == WRT_ContentsRegionRect) { return window->ContentsRegionRect; } + else if (rect_type == WRT_Content) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); } + else if (rect_type == WRT_ContentRegionRect) { return window->ContentRegionRect; } IM_ASSERT(0); return ImRect(); } @@ -9660,9 +9766,9 @@ void ImGui::ShowMetricsWindow(bool* p_open) return; if (window && !window->WasActive) - ImGui::Text("(Note: owning Window is inactive: DrawList is not being rendered!)"); + ImGui::TextDisabled("Warning: owning Window is inactive. This DrawList is not being rendered!"); - int elem_offset = 0; + unsigned int elem_offset = 0; for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++) { if (pcmd->UserCallback == NULL && pcmd->ElemCount == 0) @@ -9672,45 +9778,77 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData); continue; } + ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; char buf[300]; - ImFormatString(buf, IM_ARRAYSIZE(buf), "Draw %4d triangles, tex 0x%p, clip_rect (%4.0f,%4.0f)-(%4.0f,%4.0f)", - pcmd->ElemCount/3, (void*)(intptr_t)pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); + ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd: %4d triangles, Tex 0x%p, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)", + pcmd->ElemCount/3, (void*)(intptr_t)pcmd->TextureId, + pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf); - if (show_drawcmd_clip_rects && fg_draw_list && ImGui::IsItemHovered()) + if (show_drawcmd_details && fg_draw_list && ImGui::IsItemHovered()) { ImRect clip_rect = pcmd->ClipRect; ImRect vtxs_rect; - for (int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++) + for (unsigned int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++) vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos); - clip_rect.Floor(); fg_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,0,255,255)); - vtxs_rect.Floor(); fg_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255,255,0,255)); + fg_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255,0,255,255)); + fg_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(255,255,0,255)); } if (!pcmd_node_open) continue; + // Calculate approximate coverage area (touched pixel count) + // This will be in pixels squared as long there's no post-scaling happening to the renderer output. + float total_area = 0.0f; + for (unsigned int base_idx = elem_offset; base_idx < (elem_offset + pcmd->ElemCount); base_idx += 3) + { + ImVec2 triangle[3]; + for (int n = 0; n < 3; n++) + triangle[n] = draw_list->VtxBuffer[idx_buffer ? idx_buffer[base_idx + n] : (base_idx + n)].pos; + total_area += ImTriangleArea(triangle[0], triangle[1], triangle[2]); + } + + // Display vertex information summary. Hover to get all triangles drawn in wire-frame + ImFormatString(buf, IM_ARRAYSIZE(buf), "Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d, Area: ~%0.f px", pcmd->ElemCount, pcmd->VtxOffset, pcmd->IdxOffset, total_area); + ImGui::Selectable(buf); + if (fg_draw_list && ImGui::IsItemHovered() && show_drawcmd_details) + { + // Draw wire-frame version of everything + ImDrawListFlags backup_flags = fg_draw_list->Flags; + fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. + ImRect clip_rect = pcmd->ClipRect; + fg_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255, 0, 255, 255)); + for (unsigned int base_idx = elem_offset; base_idx < (elem_offset + pcmd->ElemCount); base_idx += 3) + { + ImVec2 triangle[3]; + for (int n = 0; n < 3; n++) + triangle[n] = draw_list->VtxBuffer[idx_buffer ? idx_buffer[base_idx + n] : (base_idx + n)].pos; + fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), true, 1.0f); + } + fg_draw_list->Flags = backup_flags; + } + // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted. - ImGui::Text("ElemCount: %d, ElemCount/3: %d, VtxOffset: +%d, IdxOffset: +%d", pcmd->ElemCount, pcmd->ElemCount/3, pcmd->VtxOffset, pcmd->IdxOffset); ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. while (clipper.Step()) for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) { char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf); - ImVec2 triangles_pos[3]; + ImVec2 triangle[3]; for (int n = 0; n < 3; n++, idx_i++) { - int vtx_i = idx_buffer ? idx_buffer[idx_i] : idx_i; - ImDrawVert& v = draw_list->VtxBuffer[vtx_i]; - triangles_pos[n] = v.pos; + ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[idx_i] : idx_i]; + triangle[n] = v.pos; buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", - (n == 0) ? "elem" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); + (n == 0) ? "Vert:" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); } + ImGui::Selectable(buf, false); if (fg_draw_list && ImGui::IsItemHovered()) { ImDrawListFlags backup_flags = fg_draw_list->Flags; - fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines at is more readable for very large and thin triangles. - fg_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255,255,0,255), true, 1.0f); + fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. + fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255,255,0,255), true, 1.0f); fg_draw_list->Flags = backup_flags; } } @@ -9745,7 +9883,10 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::BulletText("%s: NULL", label); return; } - if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, (window->Active || window->WasActive), window)) + bool open = ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, (window->Active || window->WasActive), window); + if (ImGui::IsItemHovered() && window->WasActive) + ImGui::GetForegroundDrawList()->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); + if (!open) return; ImGuiWindowFlags flags = window->Flags; NodeDrawList(window, window->DrawList, "DrawList"); @@ -9754,7 +9895,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "", (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "", (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : ""); - ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f)", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y); + ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : ""); ImGui::BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1); ImGui::BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems); ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask); @@ -9772,7 +9913,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) NodeColumns(&window->ColumnsStorage[n]); ImGui::TreePop(); } - ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.size_in_bytes()); + NodeStorage(&window->StateStorage, "Storage"); ImGui::TreePop(); } @@ -9791,16 +9932,28 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::PushID(tab); if (ImGui::SmallButton("<")) { TabBarQueueChangeTabOrder(tab_bar, tab, -1); } ImGui::SameLine(0, 2); if (ImGui::SmallButton(">")) { TabBarQueueChangeTabOrder(tab_bar, tab, +1); } ImGui::SameLine(); - ImGui::Text("%02d%c Tab 0x%08X", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID); + ImGui::Text("%02d%c Tab 0x%08X '%s'", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : ""); ImGui::PopID(); } ImGui::TreePop(); } } + + static void NodeStorage(ImGuiStorage* storage, const char* label) + { + if (!ImGui::TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes())) + return; + for (int n = 0; n < storage->Data.Size; n++) + { + const ImGuiStorage::ImGuiStoragePair& p = storage->Data[n]; + ImGui::BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer. + } + ImGui::TreePop(); + } }; Funcs::NodeWindows(g.Windows, "Windows"); - if (ImGui::TreeNode("DrawList", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size)) + if (ImGui::TreeNode("DrawLists", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size)) { for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++) Funcs::NodeDrawList(NULL, g.DrawDataBuilder.Layers[0][i], "DrawList"); @@ -9817,9 +9970,9 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::TreePop(); } - if (ImGui::TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.Data.Size)) + if (ImGui::TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetSize())) { - for (int n = 0; n < g.TabBars.Data.Size; n++) + for (int n = 0; n < g.TabBars.GetSize(); n++) Funcs::NodeTabBar(g.TabBars.GetByIndex(n)); ImGui::TreePop(); } @@ -9832,7 +9985,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) #endif #if 0 - if (ImGui::TreeNode("Tables", "Tables (%d)", g.Tables.Data.Size)) + if (ImGui::TreeNode("Tables", "Tables (%d)", g.Tables.GetSize())) { ImGui::TreePop(); } @@ -9863,6 +10016,8 @@ void ImGui::ShowMetricsWindow(bool* p_open) // The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted. if (ImGui::Button("Item Picker..")) ImGui::DebugStartItemPicker(); + ImGui::SameLine(); + MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash."); ImGui::Checkbox("Show windows begin order", &show_windows_begin_order); ImGui::Checkbox("Show windows rectangles", &show_windows_rects); @@ -9880,7 +10035,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) } ImGui::Unindent(); } - ImGui::Checkbox("Show clipping rectangle when hovering ImDrawCmd node", &show_drawcmd_clip_rects); + ImGui::Checkbox("Show details when hovering ImDrawCmd node", &show_drawcmd_details); ImGui::TreePop(); } diff --git a/sources/3rdparty/imgui/imgui.h b/sources/3rdparty/imgui/imgui.h index 1675fc6c..9fcdaeaa 100644 --- a/sources/3rdparty/imgui/imgui.h +++ b/sources/3rdparty/imgui/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.74 WIP +// dear imgui, v1.74 // (headers) // See imgui.cpp file for documentation. @@ -27,7 +27,7 @@ Index of this file: #pragma once -// Configuration file with compile-time options (edit imconfig.h or define IMGUI_USER_CONFIG to your own filename) +// Configuration file with compile-time options (edit imconfig.h or #define IMGUI_USER_CONFIG to your own filename) #ifdef IMGUI_USER_CONFIG #include IMGUI_USER_CONFIG #endif @@ -39,15 +39,16 @@ Index of this file: // Header mess //----------------------------------------------------------------------------- -#include // FLT_MAX -#include // va_list +// Includes +#include // FLT_MIN, FLT_MAX +#include // va_list, va_start, va_end #include // ptrdiff_t, NULL #include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp // Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) -#define IMGUI_VERSION "1.74 WIP" -#define IMGUI_VERSION_NUM 17301 +#define IMGUI_VERSION "1.74" +#define IMGUI_VERSION_NUM 17400 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) // Define attributes of all API symbols declarations (e.g. for DLL under Windows) @@ -66,19 +67,21 @@ Index of this file: #define IM_ASSERT(_EXPR) assert(_EXPR) // You can override the default assert handler by editing imconfig.h #endif #if defined(__clang__) || defined(__GNUC__) -#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) // Apply printf-style warnings to user functions. +#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) // To apply printf-style warnings to our functions. #define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0))) #else #define IM_FMTARGS(FMT) #define IM_FMTLIST(FMT) #endif -#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR))) // Size of a static C-style array. Don't use on pointers! +#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR) / sizeof(*_ARR))) // Size of a static C-style array. Don't use on pointers! #define IM_UNUSED(_VAR) ((void)_VAR) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds. #if (__cplusplus >= 201100) #define IM_OFFSETOF(_TYPE,_MEMBER) offsetof(_TYPE, _MEMBER) // Offset of _MEMBER within _TYPE. Standardized as offsetof() in C++11 #else #define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Old style macro. #endif +#define IM_UNICODE_CODEPOINT_MAX 0xFFFF // Last Unicode code point supported by this build. +#define IM_UNICODE_CODEPOINT_INVALID 0xFFFD // Standard invalid Unicode code point. // Warnings #if defined(__clang__) @@ -123,7 +126,7 @@ struct ImGuiTextBuffer; // Helper to hold and append into a text buf struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbb][,ccccc]") // Typedefs and Enums/Flags (declared as int for compatibility with old C++, to allow using as flags and to not pollute the top of this file) -// Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. +// Use your programming IDE "Go to definition" facility on the names in the central column below to find the actual flags/enum lists. #ifndef ImTextureID typedef void* ImTextureID; // User data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp) #endif @@ -157,7 +160,7 @@ typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData *data); typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); // Scalar data types -typedef signed char ImS8; // 8-bit signed integer == char +typedef signed char ImS8; // 8-bit signed integer typedef unsigned char ImU8; // 8-bit unsigned integer typedef signed short ImS16; // 16-bit signed integer typedef unsigned short ImU16; // 16-bit unsigned integer @@ -201,14 +204,14 @@ struct ImVec4 //----------------------------------------------------------------------------- // ImGui: Dear ImGui end-user API -// (Inside a namespace so you can add extra functions in your own separate file. Please don't modify imgui.cpp/.h!) +// (Inside a namespace so you can add extra functions in your own separate file. Please don't modify imgui source files!) //----------------------------------------------------------------------------- namespace ImGui { // Context creation and access // Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between imgui contexts. - // All those functions are not reliant on the current context. + // None of those functions is reliant on the current context. IMGUI_API ImGuiContext* CreateContext(ImFontAtlas* shared_font_atlas = NULL); IMGUI_API void DestroyContext(ImGuiContext* ctx = NULL); // NULL = destroy current context IMGUI_API ImGuiContext* GetCurrentContext(); @@ -245,8 +248,9 @@ namespace ImGui // which clicking will set the boolean to false when clicked. // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting // anything to the window. Always call a matching End() for each Begin() call, regardless of its return value! - // [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. - // where the EndXXX call should only be called if the corresponding BeginXXX function returned true.] + // [Important: due to legacy reason, this is inconsistent with most other functions such as BeginMenu/EndMenu, + // BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function + // returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] // - Note that the bottom of window stack always contains a window called "Debug". IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); IMGUI_API void End(); @@ -255,13 +259,13 @@ namespace ImGui // - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child. // - For each independent axis of 'size': ==0.0f: use remaining host window size / >0.0f: fixed size / <0.0f: use remaining window size minus abs(size) / Each axis can use a different mode, e.g. ImVec2(0,400). // - BeginChild() returns false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting anything to the window. - // Always call a matching EndChild() for each BeginChild() call, regardless of its return value [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function returned true.] + // Always call a matching EndChild() for each BeginChild() call, regardless of its return value [as with Begin: this is due to legacy reason and inconsistent with most BeginXXX functions apart from the regular Begin() which behaves like BeginChild().] IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags flags = 0); IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags flags = 0); IMGUI_API void EndChild(); // Windows Utilities - // - "current window" = the window we are appending into while inside a Begin()/End() block. "next window" = next window we will Begin() into. + // - 'current window' = the window we are appending into while inside a Begin()/End() block. 'next window' = next window we will Begin() into. IMGUI_API bool IsWindowAppearing(); IMGUI_API bool IsWindowCollapsed(); IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options. @@ -342,6 +346,7 @@ namespace ImGui // Cursor / Layout // - By "cursor" we mean the current output position. // - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down. + // - You can call SameLine() between widgets to undo the last carriage return and output at the right of the preceeding widget. IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator. IMGUI_API void SameLine(float offset_from_start_x=0.0f, float spacing=-1.0f); // call between widgets or groups to layout them horizontally. X position given in window coordinates. IMGUI_API void NewLine(); // undo a SameLine() or force a new line when in an horizontal-layout context. @@ -383,8 +388,8 @@ namespace ImGui IMGUI_API ImGuiID GetID(const void* ptr_id); // Widgets: Text - IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text. - IMGUI_API void Text(const char* fmt, ...) IM_FMTARGS(1); // simple formatted text + IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text. + IMGUI_API void Text(const char* fmt, ...) IM_FMTARGS(1); // formatted text IMGUI_API void TextV(const char* fmt, va_list args) IM_FMTLIST(1); IMGUI_API void TextColored(const ImVec4& col, const char* fmt, ...) IM_FMTARGS(2); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor(); IMGUI_API void TextColoredV(const ImVec4& col, const char* fmt, va_list args) IM_FMTLIST(2); @@ -399,6 +404,7 @@ namespace ImGui // Widgets: Main // - Most widgets return true when the value has been changed or when pressed/selected + // - You may also use one of the many IsItemXXX functions (e.g. IsItemActive, IsItemHovered, etc.) to query widget state. IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0,0)); // button IMGUI_API bool SmallButton(const char* label); // button with FramePadding=(0,0) to easily embed within text IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size); // button behavior without the visuals, frequently useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.) @@ -413,7 +419,7 @@ namespace ImGui IMGUI_API void Bullet(); // draw a small circle and keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses // Widgets: Combo Box - // - The new BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items. + // - The BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items. // - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose. IMGUI_API bool BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0); IMGUI_API void EndCombo(); // only call EndCombo() if BeginCombo() returns true! @@ -509,7 +515,7 @@ namespace ImGui // Widgets: Selectables // - A selectable highlights when hovered, and can display another color when selected. - // - Neighbors selectable extend their highlight bounds in order to leave no gap between them. + // - Neighbors selectable extend their highlight bounds in order to leave no gap between them. This is so a series of selected Selectable appear contiguous. IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. @@ -535,16 +541,19 @@ namespace ImGui IMGUI_API void Value(const char* prefix, float v, const char* float_format = NULL); // Widgets: Menus - IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar. - IMGUI_API void EndMainMenuBar(); // only call EndMainMenuBar() if BeginMainMenuBar() returns true! + // - Use BeginMenuBar() on a window ImGuiWindowFlags_MenuBar to append to its menu bar. + // - Use BeginMainMenuBar() to create a menu bar at the top of the screen. IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window (requires ImGuiWindowFlags_MenuBar flag set on parent window). IMGUI_API void EndMenuBar(); // only call EndMenuBar() if BeginMenuBar() returns true! + IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar. + IMGUI_API void EndMainMenuBar(); // only call EndMainMenuBar() if BeginMainMenuBar() returns true! IMGUI_API bool BeginMenu(const char* label, bool enabled = true); // create a sub-menu entry. only call EndMenu() if this returns true! IMGUI_API void EndMenu(); // only call EndMenu() if BeginMenu() returns true! IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. shortcuts are displayed for convenience but not processed by ImGui at the moment IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL // Tooltips + // - Tooltip are windows following the mouse which do not take focus away. IMGUI_API void BeginTooltip(); // begin/append a tooltip window. to create full-featured tooltip (with any kind of items). IMGUI_API void EndTooltip(); IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip, typically use with ImGui::IsItemHovered(). override any previous call to SetTooltip(). @@ -556,7 +565,7 @@ namespace ImGui // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE. // - Their visibility state (~bool) is held internally by imgui instead of being held by the programmer as we are used to with regular Begin() calls. // User can manipulate the visibility state by calling OpenPopup(). - // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup. + // (*) You can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup. // Those three properties are connected. The library needs to hold their visibility state because it can close popups at any time. IMGUI_API void OpenPopup(const char* str_id); // call to mark popup as open (don't call every frame!). popups are closed when user click outside, or if CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. By default, Selectable()/MenuItem() are calling CloseCurrentPopup(). Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returns true! @@ -572,6 +581,7 @@ namespace ImGui // Columns // - You can also use SameLine(pos_x) to mimic simplified columns. // - The columns API is work-in-progress and rather lacking (columns are arguably the worst part of dear imgui at the moment!) + // - By end of the 2019 we will expose a new 'Table' api which will replace columns. IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true); IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished IMGUI_API int GetColumnIndex(); // get current column index @@ -582,7 +592,6 @@ namespace ImGui IMGUI_API int GetColumnsCount(); // Tab Bars, Tabs - // [BETA API] API may evolve! IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar IMGUI_API void EndTabBar(); // only call EndTabBar() if BeginTabBar() returns true! IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0);// create a Tab. Returns true if the Tab is selected. @@ -629,6 +638,7 @@ namespace ImGui IMGUI_API bool IsItemActivated(); // was the last item just made active (item was previously inactive). IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active). Useful for Undo/Redo patterns with widgets that requires continuous editing. IMGUI_API bool IsItemDeactivatedAfterEdit(); // was the last item just made inactive and made a value change when it was active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with widgets that requires continuous editing. Note that you may get false positives (some widgets such as Combo()/ListBox()/Selectable() will return true even when clicking an already selected item). + IMGUI_API bool IsItemToggledOpen(); // was the last item open state toggled? set by TreeNode(). IMGUI_API bool IsAnyItemHovered(); // is any item hovered? IMGUI_API bool IsAnyItemActive(); // is any item active? IMGUI_API bool IsAnyItemFocused(); // is any item focused? @@ -950,12 +960,12 @@ enum ImGuiKey_ ImGuiKey_Enter, ImGuiKey_Escape, ImGuiKey_KeyPadEnter, - ImGuiKey_A, // for text edit CTRL+A: select all - ImGuiKey_C, // for text edit CTRL+C: copy - ImGuiKey_V, // for text edit CTRL+V: paste - ImGuiKey_X, // for text edit CTRL+X: cut - ImGuiKey_Y, // for text edit CTRL+Y: redo - ImGuiKey_Z, // for text edit CTRL+Z: undo + ImGuiKey_A, // for text edit CTRL+A: select all + ImGuiKey_C, // for text edit CTRL+C: copy + ImGuiKey_V, // for text edit CTRL+V: paste + ImGuiKey_X, // for text edit CTRL+X: cut + ImGuiKey_Y, // for text edit CTRL+Y: redo + ImGuiKey_Z, // for text edit CTRL+Z: undo ImGuiKey_COUNT }; @@ -1017,7 +1027,7 @@ enum ImGuiBackendFlags_ ImGuiBackendFlags_HasGamepad = 1 << 0, // Back-end Platform supports gamepad and currently has one connected. ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Back-end Platform supports honoring GetMouseCursor() value to change the OS cursor shape. ImGuiBackendFlags_HasSetMousePos = 1 << 2, // Back-end Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if ImGuiConfigFlags_NavEnableSetMousePos is set). - ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3 // Back-end Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bits indices. + ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3 // Back-end Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bit indices. }; // Enumeration for PushStyleColor() / PopStyleColor() @@ -1216,10 +1226,12 @@ template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p //----------------------------------------------------------------------------- // Helper: ImVector<> // Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). -// You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it. -// Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs. -// Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that, -// do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset. +//----------------------------------------------------------------------------- +// - You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our public structures are relying on it. +// - We use std-like naming convention here, which is a little unusual for this codebase. +// - Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs. +// - Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that, +// Do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset. //----------------------------------------------------------------------------- template @@ -1261,6 +1273,7 @@ struct ImVector inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; } inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } + inline void shrink(int new_size) { IM_ASSERT(new_size <= Size); Size = new_size; } inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); IM_FREE(Data); } Data = new_data; Capacity = new_capacity; } // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden. @@ -1571,11 +1584,6 @@ namespace ImGui static inline bool IsRootWindowOrAnyChildFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); } static inline void SetNextWindowContentWidth(float w) { SetNextWindowContentSize(ImVec2(w, 0.0f)); } static inline float GetItemsLineHeightWithSpacing() { return GetFrameHeightWithSpacing(); } - // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017) - IMGUI_API bool Begin(const char* name, bool* p_open, const ImVec2& size_on_first_use, float bg_alpha_override = -1.0f, ImGuiWindowFlags flags = 0); // Use SetNextWindowSize(size, ImGuiCond_FirstUseEver) + SetNextWindowBgAlpha() instead. - static inline bool IsRootWindowOrAnyChildHovered() { return IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); } - static inline void AlignFirstTextHeightToWidgets() { AlignTextToFramePadding(); } - static inline void SetNextWindowPosCenter(ImGuiCond c=0) { ImGuiIO& io = GetIO(); SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f), c, ImVec2(0.5f, 0.5f)); } } typedef ImGuiInputTextCallback ImGuiTextEditCallback; // OBSOLETED in 1.63 (from Aug 2018): made the names consistent typedef ImGuiInputTextCallbackData ImGuiTextEditCallbackData; @@ -1628,11 +1636,11 @@ struct ImGuiTextBuffer IMGUI_API static char EmptyString[1]; ImGuiTextBuffer() { } - inline char operator[](int i) { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; } + inline char operator[](int i) const { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; } const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; } const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator int size() const { return Buf.Size ? Buf.Size - 1 : 0; } - bool empty() { return Buf.Size <= 1; } + bool empty() const { return Buf.Size <= 1; } void clear() { Buf.clear(); } void reserve(int capacity) { Buf.reserve(capacity); } const char* c_str() const { return Buf.Data ? Buf.Data : EmptyString; } @@ -1722,7 +1730,7 @@ struct ImGuiListClipper IMGUI_API void End(); // Automatically called on the last call of Step() that returns false. }; -// Helpers macros to generate 32-bits encoded colors +// Helpers macros to generate 32-bit encoded colors #ifdef IMGUI_USE_BGRA_PACKED_COLOR #define IM_COL32_R_SHIFT 16 #define IM_COL32_G_SHIFT 8 @@ -1786,13 +1794,13 @@ typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* c // Typically, 1 command = 1 GPU draw call (unless command is a callback) // Pre 1.71 back-ends will typically ignore the VtxOffset/IdxOffset fields. When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' -// is enabled, those fields allow us to render meshes larger than 64K vertices while keeping 16-bits indices. +// is enabled, those fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices. struct ImDrawCmd { unsigned int ElemCount; // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. ImVec4 ClipRect; // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates ImTextureID TextureId; // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas. - unsigned int VtxOffset; // Start offset in vertex buffer. Pre-1.71 or without ImGuiBackendFlags_RendererHasVtxOffset: always 0. With ImGuiBackendFlags_RendererHasVtxOffset: may be >0 to support meshes larger than 64K vertices with 16-bits indices. + unsigned int VtxOffset; // Start offset in vertex buffer. Pre-1.71 or without ImGuiBackendFlags_RendererHasVtxOffset: always 0. With ImGuiBackendFlags_RendererHasVtxOffset: may be >0 to support meshes larger than 64K vertices with 16-bit indices. unsigned int IdxOffset; // Start offset in index buffer. Always equal to sum of ElemCount drawn so far. ImDrawCallback UserCallback; // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally. void* UserCallbackData; // The draw callback code can access this. @@ -1801,8 +1809,8 @@ struct ImDrawCmd }; // Vertex index -// (to allow large meshes with 16-bits indices: set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset in the renderer back-end) -// (to use 32-bits indices: override with '#define ImDrawIdx unsigned int' in imconfig.h) +// (to allow large meshes with 16-bit indices: set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset in the renderer back-end) +// (to use 32-bit indices: override with '#define ImDrawIdx unsigned int' in imconfig.h) #ifndef ImDrawIdx typedef unsigned short ImDrawIdx; #endif @@ -1911,7 +1919,7 @@ struct ImDrawList // Primitives // - For rectangular primitives, "p_min" and "p_max" represent the upper-left and lower-right corners. IMGUI_API void AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness = 1.0f); - IMGUI_API void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All, float thickness = 1.0f); // a: upper-left, b: lower-right (== upper-left + size), rounding_corners_flags: 4-bits corresponding to which corner to round + IMGUI_API void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All, float thickness = 1.0f); // a: upper-left, b: lower-right (== upper-left + size), rounding_corners_flags: 4 bits corresponding to which corner to round IMGUI_API void AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); // a: upper-left, b: lower-right (== upper-left + size) IMGUI_API void AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left); IMGUI_API void AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness = 1.0f); @@ -2040,7 +2048,7 @@ struct ImFontGlyphRangesBuilder ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) ImFontGlyphRangesBuilder() { Clear(); } - inline void Clear() { int size_in_bytes = 0x10000 / 8; UsedChars.resize(size_in_bytes / (int)sizeof(ImU32)); memset(UsedChars.Data, 0, (size_t)size_in_bytes); } + inline void Clear() { int size_in_bytes = (IM_UNICODE_CODEPOINT_MAX+1) / 8; UsedChars.resize(size_in_bytes / (int)sizeof(ImU32)); memset(UsedChars.Data, 0, (size_t)size_in_bytes); } inline bool GetBit(int n) const { int off = (n >> 5); ImU32 mask = 1u << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array inline void SetBit(int n) { int off = (n >> 5); ImU32 mask = 1u << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array inline void AddChar(ImWchar c) { SetBit(c); } // Add character @@ -2052,12 +2060,12 @@ struct ImFontGlyphRangesBuilder // See ImFontAtlas::AddCustomRectXXX functions. struct ImFontAtlasCustomRect { - unsigned int ID; // Input // User ID. Use <0x10000 to map into a font glyph, >=0x10000 for other/internal/custom texture data. + unsigned int ID; // Input // User ID. Use < 0x110000 to map into a font glyph, >= 0x110000 for other/internal/custom texture data. unsigned short Width, Height; // Input // Desired rectangle dimension unsigned short X, Y; // Output // Packed position in Atlas - float GlyphAdvanceX; // Input // For custom font glyphs only (ID<0x10000): glyph xadvance - ImVec2 GlyphOffset; // Input // For custom font glyphs only (ID<0x10000): glyph display offset - ImFont* Font; // Input // For custom font glyphs only (ID<0x10000): target font + float GlyphAdvanceX; // Input // For custom font glyphs only (ID < 0x110000): glyph xadvance + ImVec2 GlyphOffset; // Input // For custom font glyphs only (ID < 0x110000): glyph display offset + ImFont* Font; // Input // For custom font glyphs only (ID < 0x110000): target font ImFontAtlasCustomRect() { ID = 0xFFFFFFFF; Width = Height = 0; X = Y = 0xFFFF; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0,0); Font = NULL; } bool IsPacked() const { return X != 0xFFFF; } }; @@ -2109,7 +2117,7 @@ struct ImFontAtlas IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel - bool IsBuilt() { return Fonts.Size > 0 && (TexPixelsAlpha8 != NULL || TexPixelsRGBA32 != NULL); } + bool IsBuilt() const { return Fonts.Size > 0 && (TexPixelsAlpha8 != NULL || TexPixelsRGBA32 != NULL); } void SetTexID(ImTextureID id) { TexID = id; } //------------------------------------------- @@ -2136,13 +2144,13 @@ struct ImFontAtlas // After calling Build(), you can query the rectangle position and render your pixels. // You can also request your rectangles to be mapped as font glyph (given a font + Unicode point), // so you can render e.g. custom colorful icons and use them as regular glyphs. - // Read misc/fonts/README.txt for more details about using colorful icons. - IMGUI_API int AddCustomRectRegular(unsigned int id, int width, int height); // Id needs to be >= 0x10000. Id >= 0x80000000 are reserved for ImGui and ImDrawList - IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0,0)); // Id needs to be < 0x10000 to register a rectangle to map into a specific font. + // Read docs/FONTS.txt for more details about using colorful icons. + IMGUI_API int AddCustomRectRegular(unsigned int id, int width, int height); // Id needs to be >= 0x110000. Id >= 0x80000000 are reserved for ImGui and ImDrawList + IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0,0)); // Id needs to be < 0x110000 to register a rectangle to map into a specific font. const ImFontAtlasCustomRect*GetCustomRectByIndex(int index) const { if (index < 0) return NULL; return &CustomRects[index]; } // [Internal] - IMGUI_API void CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max); + IMGUI_API void CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const; IMGUI_API bool GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]); //------------------------------------------- @@ -2223,10 +2231,6 @@ struct ImFont IMGUI_API void AddGlyph(ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x); IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. IMGUI_API void SetFallbackChar(ImWchar c); - -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - typedef ImFontGlyph Glyph; // OBSOLETED in 1.52+ -#endif }; #if defined(__clang__) diff --git a/sources/3rdparty/imgui/imgui_demo.cpp b/sources/3rdparty/imgui/imgui_demo.cpp index 8e765863..7e475992 100644 --- a/sources/3rdparty/imgui/imgui_demo.cpp +++ b/sources/3rdparty/imgui/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.74 WIP +// dear imgui, v1.74 // (demo code) // Message to the person tempted to delete this file when integrating Dear ImGui into their code base: @@ -100,12 +100,17 @@ Index of this file: // Play it nice with Windows users. Notepad in 2017 still doesn't display text data with Unix-style \n. #ifdef _WIN32 #define IM_NEWLINE "\r\n" -#define snprintf _snprintf -#define vsnprintf _vsnprintf #else #define IM_NEWLINE "\n" #endif +#if defined(_MSC_VER) && !defined(snprintf) +#define snprintf _snprintf +#endif +#if defined(_MSC_VER) && !defined(vsnprintf) +#define vsnprintf _vsnprintf +#endif + //----------------------------------------------------------------------------- // [SECTION] Forward Declarations, Helpers //----------------------------------------------------------------------------- @@ -132,7 +137,7 @@ static void ShowExampleAppCustomRendering(bool* p_open); static void ShowExampleMenuFile(); // Helper to display a little (?) mark which shows a tooltip when hovered. -// In your own code you may want to display an actual icon if you are using a merged icon fonts (see misc/fonts/README.txt) +// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.txt) static void HelpMarker(const char* desc) { ImGui::TextDisabled("(?)"); @@ -152,25 +157,28 @@ void ImGui::ShowUserGuide() ImGuiIO& io = ImGui::GetIO(); ImGui::BulletText("Double-click on title bar to collapse window."); ImGui::BulletText("Click and drag on lower corner to resize window\n(double-click to auto fit window to its contents)."); - if (io.ConfigWindowsMoveFromTitleBarOnly) - ImGui::BulletText("Click and drag on title bar to move window."); - else - ImGui::BulletText("Click and drag on any empty space to move window."); - ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text."); + ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); if (io.FontAllowUserScaling) ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents."); - ImGui::BulletText("Mouse Wheel to scroll."); - ImGui::BulletText("While editing text:\n"); + ImGui::BulletText("While inputing text:\n"); ImGui::Indent(); - ImGui::BulletText("Hold SHIFT or use mouse to select text."); ImGui::BulletText("CTRL+Left/Right to word jump."); ImGui::BulletText("CTRL+A or double-click to select all."); - ImGui::BulletText("CTRL+X,CTRL+C,CTRL+V to use clipboard."); + ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste."); ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo."); ImGui::BulletText("ESCAPE to revert."); ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract."); ImGui::Unindent(); + ImGui::BulletText("With keyboard navigation enabled:"); + ImGui::Indent(); + ImGui::BulletText("Arrow keys to navigate."); + ImGui::BulletText("Space to activate a widget."); + ImGui::BulletText("Return to input text into a widget."); + ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window."); + ImGui::BulletText("Alt to jump to the menu layer of a window."); + ImGui::BulletText("CTRL+Tab to select a window."); + ImGui::Unindent(); } //----------------------------------------------------------------------------- @@ -311,12 +319,20 @@ void ImGui::ShowDemoWindow(bool* p_open) if (ImGui::CollapsingHeader("Help")) { + ImGui::Text("ABOUT THIS DEMO:"); + ImGui::BulletText("Sections below are demonstrating many aspects of the library."); + ImGui::BulletText("The \"Examples\" menu above leads to more demo contents."); + ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" + "and Metrics (general purpose Dear ImGui debugging tool)."); + ImGui::Separator(); + ImGui::Text("PROGRAMMER GUIDE:"); - ImGui::BulletText("Please see the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!"); - ImGui::BulletText("Please see the comments in imgui.cpp."); - ImGui::BulletText("Please see the examples/ application."); - ImGui::BulletText("Enable 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls."); - ImGui::BulletText("Enable 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls."); + ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!"); + ImGui::BulletText("See comments in imgui.cpp."); + ImGui::BulletText("See example applications in the examples/ folder."); + ImGui::BulletText("Read the FAQ at http://www.dearimgui.org/faq/"); + ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls."); + ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls."); ImGui::Separator(); ImGui::Text("USER GUIDE:"); @@ -360,7 +376,7 @@ void ImGui::ShowDemoWindow(bool* p_open) if (ImGui::TreeNode("Backend Flags")) { - HelpMarker("Those flags are set by the back-ends (imgui_impl_xxx files) to specify their capabilities."); + HelpMarker("Those flags are set by the back-ends (imgui_impl_xxx files) to specify their capabilities.\nHere we expose then as read-only fields to avoid breaking interactions with your back-end."); ImGuiBackendFlags backend_flags = io.BackendFlags; // Make a local copy to avoid modifying actual back-end flags. ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasGamepad); ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasMouseCursors); @@ -372,6 +388,7 @@ void ImGui::ShowDemoWindow(bool* p_open) if (ImGui::TreeNode("Style")) { + HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function."); ImGui::ShowStyleEditor(); ImGui::TreePop(); ImGui::Separator(); @@ -753,14 +770,14 @@ static void ShowDemoWindowWidgets() if (ImGui::TreeNode("UTF-8 Text")) { // UTF-8 test with Japanese characters - // (Needs a suitable font, try Noto, or Arial Unicode, or M+ fonts. Read misc/fonts/README.txt for details.) + // (Needs a suitable font, try Noto, or Arial Unicode, or M+ fonts. Read docs/FONTS.txt for details.) // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8 // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. Visual Studio save your file as 'UTF-8 without signature') // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8 CHARACTERS IN THIS SOURCE FILE. // Instead we are encoding a few strings with hexadecimal constants. Don't do this in your application! // Please use u8"text in any language" in your application! // Note that characters values are preserved even by InputText() if the font cannot be displayed, so you can safely copy & paste garbled characters into another application. - ImGui::TextWrapped("CJK text will only appears if the font was loaded with the appropriate CJK character ranges. Call io.Font->AddFontFromFileTTF() manually to load extra character ranges. Read misc/fonts/README.txt for details."); + ImGui::TextWrapped("CJK text will only appears if the font was loaded with the appropriate CJK character ranges. Call io.Font->AddFontFromFileTTF() manually to load extra character ranges. Read docs/FONTS.txt for details."); ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); // Normally we would use u8"blah blah" with the proper characters directly in the string. ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)"); static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; @@ -1608,7 +1625,7 @@ static void ShowDemoWindowWidgets() { // Submit an item (various types available) so we can query their status in the following block. static int item_type = 1; - ImGui::Combo("Item Type", &item_type, "Text\0Button\0Button (w/ repeat)\0Checkbox\0SliderFloat\0InputText\0InputFloat\0InputFloat3\0ColorEdit4\0MenuItem\0TreeNode (w/ double-click)\0ListBox\0"); + ImGui::Combo("Item Type", &item_type, "Text\0Button\0Button (w/ repeat)\0Checkbox\0SliderFloat\0InputText\0InputFloat\0InputFloat3\0ColorEdit4\0MenuItem\0TreeNode\0TreeNode (w/ double-click)\0ListBox\0", 20); ImGui::SameLine(); HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions."); bool ret = false; @@ -1625,8 +1642,9 @@ static void ShowDemoWindowWidgets() if (item_type == 7) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) if (item_type == 8) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) if (item_type == 9) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) - if (item_type == 10){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. - if (item_type == 11){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } + if (item_type == 10){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node + if (item_type == 11){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. + if (item_type == 12){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } // Display the value of IsItemHovered() and other common item state functions. // Note that the ImGuiHoveredFlags_XXX flags can be combined. @@ -1647,6 +1665,7 @@ static void ShowDemoWindowWidgets() "IsItemDeactivatedAfterEdit() = %d\n" "IsItemVisible() = %d\n" "IsItemClicked() = %d\n" + "IsItemToggledOpen() = %d\n" "GetItemRectMin() = (%.1f, %.1f)\n" "GetItemRectMax() = (%.1f, %.1f)\n" "GetItemRectSize() = (%.1f, %.1f)", @@ -1664,6 +1683,7 @@ static void ShowDemoWindowWidgets() ImGui::IsItemDeactivatedAfterEdit(), ImGui::IsItemVisible(), ImGui::IsItemClicked(), + ImGui::IsItemToggledOpen(), ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y, ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y, ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y @@ -2207,7 +2227,7 @@ static void ShowDemoWindowLayout() ImGui::TextUnformatted(names[i]); ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0; - ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(child_w, 200.0f), true, child_flags); + bool window_visible = ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(child_w, 200.0f), true, child_flags); if (ImGui::BeginMenuBar()) { ImGui::TextUnformatted("abc"); @@ -2217,16 +2237,19 @@ static void ShowDemoWindowLayout() ImGui::SetScrollY(scroll_to_off_px); if (scroll_to_pos) ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f); - for (int item = 0; item < 100; item++) + if (window_visible) // Avoid calling SetScrollHereY when running with culled items { - if (enable_track && item == track_item) + for (int item = 0; item < 100; item++) { - ImGui::TextColored(ImVec4(1,1,0,1), "Item %d", item); - ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom - } - else - { - ImGui::Text("Item %d", item); + if (enable_track && item == track_item) + { + ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); + ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom + } + else + { + ImGui::Text("Item %d", item); + } } } float scroll_y = ImGui::GetScrollY(); @@ -2245,23 +2268,26 @@ static void ShowDemoWindowLayout() { float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f; ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0); - ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(-100, child_height), true, child_flags); + bool window_visible = ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(-100, child_height), true, child_flags); if (scroll_to_off) ImGui::SetScrollX(scroll_to_off_px); if (scroll_to_pos) ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f); - for (int item = 0; item < 100; item++) + if (window_visible) // Avoid calling SetScrollHereY when running with culled items { - if (enable_track && item == track_item) + for (int item = 0; item < 100; item++) { - ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); - ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right + if (enable_track && item == track_item) + { + ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); + ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right + } + else + { + ImGui::Text("Item %d", item); + } + ImGui::SameLine(); } - else - { - ImGui::Text("Item %d", item); - } - ImGui::SameLine(); } float scroll_x = ImGui::GetScrollX(); float scroll_max_x = ImGui::GetScrollMaxX(); @@ -3092,11 +3118,17 @@ void ImGui::ShowAboutWindow(bool* p_open) #ifdef IMGUI_DISABLE_WIN32_FUNCTIONS ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS"); #endif -#ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS - ImGui::Text("define: IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS"); +#ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS"); #endif -#ifdef IMGUI_DISABLE_MATH_FUNCTIONS - ImGui::Text("define: IMGUI_DISABLE_MATH_FUNCTIONS"); +#ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_FILE_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS"); #endif #ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS"); @@ -3223,7 +3255,7 @@ void ImGui::ShowFontSelector(const char* label) HelpMarker( "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n" "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n" - "- Read FAQ and documentation in misc/fonts/ for more details.\n" + "- Read FAQ and docs/FONTS.txt for more details.\n" "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame()."); } @@ -3263,7 +3295,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) if (ImGui::Button("Revert Ref")) style = *ref; ImGui::SameLine(); - HelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export Colors\" below to save them somewhere."); + HelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export\" below to save them somewhere."); ImGui::Separator(); @@ -3311,7 +3343,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) { static int output_dest = 0; static bool output_only_modified = true; - if (ImGui::Button("Export Unsaved")) + if (ImGui::Button("Export")) { if (output_dest == 0) ImGui::LogToClipboard(); @@ -3351,7 +3383,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) { // Tips: in a real user application, you may want to merge and use an icon font into the main font, so instead of "Save"/"Revert" you'd use icons. - // Read the FAQ and misc/fonts/README.txt about using icon fonts. It's really easy and super convenient! + // Read the FAQ and docs/FONTS.txt about using icon fonts. It's really easy and super convenient! ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) ref->Colors[i] = style.Colors[i]; ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) style.Colors[i] = ref->Colors[i]; } @@ -3369,7 +3401,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) { ImGuiIO& io = ImGui::GetIO(); ImFontAtlas* atlas = io.Fonts; - HelpMarker("Read FAQ and misc/fonts/README.txt for details on font loading."); + HelpMarker("Read FAQ and docs/FONTS.txt for details on font loading."); ImGui::PushItemWidth(120); for (int i = 0; i < atlas->Fonts.Size; i++) { @@ -3389,17 +3421,17 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::Text("Fallback character: '%c' (U+%04X)", font->FallbackChar, font->FallbackChar); ImGui::Text("Ellipsis character: '%c' (U+%04X)", font->EllipsisChar, font->EllipsisChar); const float surface_sqrt = sqrtf((float)font->MetricsTotalSurface); - ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)surface_sqrt, (int)surface_sqrt); + ImGui::Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, (int)surface_sqrt, (int)surface_sqrt); for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) if (const ImFontConfig* cfg = &font->ConfigData[config_i]) ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH); if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) { // Display all glyphs of the fonts in separate pages of 256 characters - for (int base = 0; base < 0x10000; base += 256) + for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) { int count = 0; - for (int n = 0; n < 256; n++) + for (unsigned int n = 0; n < 256; n++) count += font->FindGlyphNoFallback((ImWchar)(base + n)) ? 1 : 0; if (count > 0 && ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) { @@ -3407,7 +3439,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) float cell_spacing = style.ItemSpacing.y; ImVec2 base_pos = ImGui::GetCursorScreenPos(); ImDrawList* draw_list = ImGui::GetWindowDrawList(); - for (int n = 0; n < 256; n++) + for (unsigned int n = 0; n < 256; n++) { ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); diff --git a/sources/3rdparty/imgui/imgui_draw.cpp b/sources/3rdparty/imgui/imgui_draw.cpp index e2b5ee86..8089bbef 100644 --- a/sources/3rdparty/imgui/imgui_draw.cpp +++ b/sources/3rdparty/imgui/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.74 WIP +// dear imgui, v1.74 // (drawing and font code) /* @@ -1725,7 +1725,8 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed int ImFontAtlas::AddCustomRectRegular(unsigned int id, int width, int height) { - IM_ASSERT(id >= 0x10000); + // Breaking change on 2019/11/21 (1.74): ImFontAtlas::AddCustomRectRegular() now requires an ID >= 0x110000 (instead of >= 0x10000) + IM_ASSERT(id >= 0x110000); IM_ASSERT(width > 0 && width <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF); ImFontAtlasCustomRect r; @@ -1752,7 +1753,7 @@ int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int return CustomRects.Size - 1; // Return index } -void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) +void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const { IM_ASSERT(TexWidth > 0 && TexHeight > 0); // Font atlas needs to be built before we can calculate UV coordinates IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed @@ -1905,7 +1906,7 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1); for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) - for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) + for (unsigned int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) { if (dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option for MergeMode (e.g. MergeOverwrite==true) continue; @@ -2069,7 +2070,7 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1)); ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent); const float font_off_x = cfg.GlyphOffset.x; - const float font_off_y = cfg.GlyphOffset.y + ImFloor(dst_font->Ascent + 0.5f); + const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent); for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) { @@ -2189,7 +2190,7 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas) for (int i = 0; i < atlas->CustomRects.Size; i++) { const ImFontAtlasCustomRect& r = atlas->CustomRects[i]; - if (r.Font == NULL || r.ID > 0x10000) + if (r.Font == NULL || r.ID >= 0x110000) continue; IM_ASSERT(r.Font->ContainerAtlas == atlas); @@ -2453,7 +2454,7 @@ void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end) text += c_len; if (c_len == 0) break; - if (c < 0x10000) + if (c <= IM_UNICODE_CODEPOINT_MAX) AddChar((ImWchar)c); } } @@ -2467,12 +2468,12 @@ void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges) void ImFontGlyphRangesBuilder::BuildRanges(ImVector* out_ranges) { - int max_codepoint = 0x10000; - for (int n = 0; n < max_codepoint; n++) + const int max_codepoint = IM_UNICODE_CODEPOINT_MAX; + for (int n = 0; n <= max_codepoint; n++) if (GetBit(n)) { out_ranges->push_back((ImWchar)n); - while (n < max_codepoint - 1 && GetBit(n + 1)) + while (n < max_codepoint && GetBit(n + 1)) n++; out_ranges->push_back((ImWchar)n); } @@ -2591,7 +2592,7 @@ void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1, glyph.AdvanceX = advance_x + ConfigData->GlyphExtraSpacing.x; // Bake spacing into AdvanceX if (ConfigData->PixelSnapH) - glyph.AdvanceX = IM_FLOOR(glyph.AdvanceX + 0.5f); + glyph.AdvanceX = IM_ROUND(glyph.AdvanceX); // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round) DirtyLookupTables = true; @@ -2601,7 +2602,7 @@ void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1, void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) { IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function. - int index_size = IndexLookup.Size; + unsigned int index_size = (unsigned int)IndexLookup.Size; if (dst < index_size && IndexLookup.Data[dst] == (ImWchar)-1 && !overwrite_dst) // 'dst' already exists return; @@ -3020,9 +3021,9 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col x += char_width; } - // Give back unused vertices - draw_list->VtxBuffer.resize((int)(vtx_write - draw_list->VtxBuffer.Data)); - draw_list->IdxBuffer.resize((int)(idx_write - draw_list->IdxBuffer.Data)); + // Give back unused vertices (clipped ones, blanks) ~ this is essentially a PrimUnreserve() action. + draw_list->VtxBuffer.Size = (int)(vtx_write - draw_list->VtxBuffer.Data); // Same as calling shrink() + draw_list->IdxBuffer.Size = (int)(idx_write - draw_list->IdxBuffer.Data); draw_list->CmdBuffer[draw_list->CmdBuffer.Size-1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size); draw_list->_VtxWritePtr = vtx_write; draw_list->_IdxWritePtr = idx_write; @@ -3201,9 +3202,9 @@ static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, uns { const unsigned long ADLER_MOD = 65521; unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16; - unsigned long blocklen, i; + unsigned long blocklen = buflen % 5552; - blocklen = buflen % 5552; + unsigned long i; while (buflen) { for (i=0; i + 7 < blocklen; i += 8) { s1 += buffer[0], s2 += s1; @@ -3230,10 +3231,9 @@ static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, uns static unsigned int stb_decompress(unsigned char *output, const unsigned char *i, unsigned int /*length*/) { - unsigned int olen; if (stb__in4(0) != 0x57bC0000) return 0; if (stb__in4(4) != 0) return 0; // error! stream is > 4GB - olen = stb_decompress_length(i); + const unsigned int olen = stb_decompress_length(i); stb__barrier_in_b = i; stb__barrier_out_e = output + olen; stb__barrier_out_b = output; diff --git a/sources/3rdparty/imgui/imgui_internal.h b/sources/3rdparty/imgui/imgui_internal.h index feee1036..73880098 100644 --- a/sources/3rdparty/imgui/imgui_internal.h +++ b/sources/3rdparty/imgui/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.74 WIP +// dear imgui, v1.74 // (internal structures/api) // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! @@ -31,7 +31,7 @@ Index of this file: #error Must include imgui.h before imgui_internal.h #endif -#include // FILE* +#include // FILE*, sscanf #include // NULL, malloc, free, qsort, atoi, atof #include // sqrtf, fabsf, fmodf, powf, floorf, ceilf, cosf, sinf #include // INT_MIN, INT_MAX @@ -60,10 +60,19 @@ Index of this file: #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #endif +// Legacy defines +#ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Renamed in 1.74 +#error Use IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS +#endif +#ifdef IMGUI_DISABLE_MATH_FUNCTIONS // Renamed in 1.74 +#error Use IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS +#endif + //----------------------------------------------------------------------------- // Forward declarations //----------------------------------------------------------------------------- +struct ImBoolVector; // Store 1-bit per value struct ImRect; // An axis-aligned rectangle (2 points) struct ImDrawDataBuilder; // Helper to build a ImDrawData instance struct ImDrawListSharedData; // Data shared between all ImDrawList instances @@ -86,7 +95,7 @@ struct ImGuiTabBar; // Storage for a tab bar struct ImGuiTabItem; // Storage for a tab item (within a tab bar) struct ImGuiWindow; // Storage for one window struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame) -struct ImGuiWindowSettings; // Storage for window settings stored in .ini file (we keep one of those even if the actual window wasn't instanced during this session) +struct ImGuiWindowSettings; // Storage for a window .ini settings (we keep one of those even if the actual window wasn't instanced during this session) // Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // Enum: Horizontal or vertical @@ -131,26 +140,48 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #endif //----------------------------------------------------------------------------- -// Generic helpers +// Macros //----------------------------------------------------------------------------- -#define IM_PI 3.14159265358979323846f -#ifdef _WIN32 -#define IM_NEWLINE "\r\n" // Play it nice with Windows users (2018/05 news: Microsoft announced that Notepad will finally display Unix-style carriage returns!) -#else -#define IM_NEWLINE "\n" -#endif -#define IM_TABSIZE (4) -#define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1] -#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose -#define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 -#define IM_FLOOR(_VAL) ((float)(int)(_VAL)) // ImFloor() is not inlined in MSVC debug builds - // Debug Logging #ifndef IMGUI_DEBUG_LOG #define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__) #endif +// Static Asserts +#if (__cplusplus >= 201100) +#define IM_STATIC_ASSERT(_COND) static_assert(_COND, "") +#else +#define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1] +#endif + +// "Paranoid" Debug Asserts are meant to only be enabled during specific debugging/work, otherwise would slow down the code too much. +#define IMGUI_DEBUG_PARANOID 0 +#if IMGUI_DEBUG_PARANOID +#define IM_ASSERT_PARANOID(_EXPR) IM_ASSERT(_EXPR) +#else +#define IM_ASSERT_PARANOID(_EXPR) +#endif + +// Error handling +// Down the line in some frameworks/languages we would like to have a way to redirect those to the programmer and recover from more faults. +#ifndef IM_ASSERT_USER_ERROR +#define IM_ASSERT_USER_ERROR(_EXP,_MSG) IM_ASSERT((_EXP) && (_MSG)) // Recoverable User Error +#endif + +// Misc Macros +#define IM_PI 3.14159265358979323846f +#ifdef _WIN32 +#define IM_NEWLINE "\r\n" // Play it nice with Windows users (Update: since 2018-05, Notepad finally appears to support Unix-style carriage returns!) +#else +#define IM_NEWLINE "\n" +#endif +#define IM_TABSIZE (4) +#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose +#define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 +#define IM_FLOOR(_VAL) ((float)(int)(_VAL)) // ImFloor() is not inlined in MSVC debug builds +#define IM_ROUND(_VAL) ((float)(int)((_VAL) + 0.5f)) // + // Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall #ifdef _MSC_VER #define IMGUI_CDECL __cdecl @@ -158,36 +189,34 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #define IMGUI_CDECL #endif -// Helpers: UTF-8 <> wchar -IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count -IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // read one character. return input UTF-8 bytes count -IMGUI_API int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count -IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count) -IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); // return number of bytes to express one char in UTF-8 -IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8 +//----------------------------------------------------------------------------- +// Generic helpers +//----------------------------------------------------------------------------- +// - Helpers: Misc +// - Helpers: Bit manipulation +// - Helpers: String, Formatting +// - Helpers: UTF-8 <> wchar conversions +// - Helpers: ImVec2/ImVec4 operators +// - Helpers: Maths +// - Helpers: Geometry +// - Helper: ImBoolVector +// - Helper: ImPool<> +// - Helper: ImChunkStream<> +//----------------------------------------------------------------------------- // Helpers: Misc +#define ImQsort qsort IMGUI_API ImU32 ImHashData(const void* data, size_t data_size, ImU32 seed = 0); IMGUI_API ImU32 ImHashStr(const char* data, size_t data_size = 0, ImU32 seed = 0); -IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size = NULL, int padding_bytes = 0); -IMGUI_API FILE* ImFileOpen(const char* filename, const char* file_open_mode); -static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } -static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } -static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; } -static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } -#define ImQsort qsort #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS static inline ImU32 ImHash(const void* data, int size, ImU32 seed = 0) { return size ? ImHashData(data, (size_t)size, seed) : ImHashStr((const char*)data, 0, seed); } // [moved to ImHashStr/ImHashData in 1.68] #endif -// Helpers: Geometry -IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p); -IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); -IMGUI_API ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); -IMGUI_API void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w); -IMGUI_API ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy); +// Helpers: Bit manipulation +static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; } +static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } -// Helpers: String +// Helpers: String, Formatting IMGUI_API int ImStricmp(const char* str1, const char* str2); IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count); IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count); @@ -199,12 +228,23 @@ IMGUI_API const char* ImStreolRange(const char* str, const char* str_end); IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end); IMGUI_API void ImStrTrimBlanks(char* str); +IMGUI_API const char* ImStrSkipBlank(const char* str); IMGUI_API int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) IM_FMTARGS(3); IMGUI_API int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3); IMGUI_API const char* ImParseFormatFindStart(const char* format); IMGUI_API const char* ImParseFormatFindEnd(const char* format); IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, size_t buf_size); IMGUI_API int ImParseFormatPrecision(const char* format, int default_value); +static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } +static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } + +// Helpers: UTF-8 <> wchar conversions +IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count +IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // read one character. return input UTF-8 bytes count +IMGUI_API int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count +IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count) +IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); // return number of bytes to express one char in UTF-8 +IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8 // Helpers: ImVec2/ImVec4 operators // We are keeping those disabled by default so they don't leak in user space, to allow user enabling implicit cast operators between ImVec2 and their own types (using IM_VEC2_CLASS_EXTRA etc.) @@ -225,9 +265,35 @@ static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x*rhs.x, lhs.y*rhs.y, lhs.z*rhs.z, lhs.w*rhs.w); } #endif +// Helpers: File System +#if defined(__EMSCRIPTEN__) && !defined(IMGUI_DISABLE_FILE_FUNCTIONS) +#define IMGUI_DISABLE_FILE_FUNCTIONS +#endif +#ifdef IMGUI_DISABLE_FILE_FUNCTIONS +#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS +typedef void* ImFileHandle; +static inline ImFileHandle ImFileOpen(const char*, const char*) { return NULL; } +static inline bool ImFileClose(ImFileHandle) { return false; } +static inline ImU64 ImFileGetSize(ImFileHandle) { return (ImU64)-1; } +static inline ImU64 ImFileRead(void*, ImU64, ImU64, ImFileHandle) { return 0; } +static inline ImU64 ImFileWrite(const void*, ImU64, ImU64, ImFileHandle) { return 0; } +#endif + +#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS +typedef FILE* ImFileHandle; +IMGUI_API ImFileHandle ImFileOpen(const char* filename, const char* mode); +IMGUI_API bool ImFileClose(ImFileHandle file); +IMGUI_API ImU64 ImFileGetSize(ImFileHandle file); +IMGUI_API ImU64 ImFileRead(void* data, ImU64 size, ImU64 count, ImFileHandle file); +IMGUI_API ImU64 ImFileWrite(const void* data, ImU64 size, ImU64 count, ImFileHandle file); +#else +#define IMGUI_DISABLE_TTY_FUNCTIONS // Can't use stdout, fflush if we are not using default file functions +#endif +IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size = NULL, int padding_bytes = 0); + // Helpers: Maths // - Wrapper for standard libs functions. (Note that imgui_demo.cpp does _not_ use them to keep the code easy to copy) -#ifndef IMGUI_DISABLE_MATH_FUNCTIONS +#ifndef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS static inline float ImFabs(float x) { return fabsf(x); } static inline float ImSqrt(float x) { return sqrtf(x); } static inline float ImPow(float x, float y) { return powf(x, y); } @@ -262,17 +328,25 @@ static inline float ImSaturate(float f) static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; } static inline float ImLengthSqr(const ImVec4& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z + lhs.w*lhs.w; } static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = lhs.x*lhs.x + lhs.y*lhs.y; if (d > 0.0f) return 1.0f / ImSqrt(d); return fail_value; } -static inline float ImFloor(float f) { return (float)(int)f; } -static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)v.x, (float)(int)v.y); } +static inline float ImFloor(float f) { return (float)(int)(f); } +static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)(v.x), (float)(int)(v.y)); } static inline int ImModPositive(int a, int b) { return (a + b) % b; } static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; } static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } -// Helper: ImBoolVector. Store 1-bit per value. -// Note that Resize() currently clears the whole vector. -struct ImBoolVector +// Helpers: Geometry +IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p); +IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); +IMGUI_API ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); +IMGUI_API void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w); +inline float ImTriangleArea(const ImVec2& a, const ImVec2& b, const ImVec2& c) { return ImFabs((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) * 0.5f; } +IMGUI_API ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy); + +// Helper: ImBoolVector +// Store 1-bit per value. Note that Resize() currently clears the whole vector. +struct IMGUI_API ImBoolVector { ImVector Storage; ImBoolVector() { } @@ -282,29 +356,52 @@ struct ImBoolVector void SetBit(int n, bool v) { int off = (n >> 5); int mask = 1 << (n & 31); if (v) Storage[off] |= mask; else Storage[off] &= ~mask; } }; -// Helper: ImPool<>. Basic keyed storage for contiguous instances, slow/amortized insertion, O(1) indexable, O(Log N) queries by ID over a dense/hot buffer, +// Helper: ImPool<> +// Basic keyed storage for contiguous instances, slow/amortized insertion, O(1) indexable, O(Log N) queries by ID over a dense/hot buffer, // Honor constructor/destructor. Add/remove invalidate all pointers. Indexes have the same lifetime as the associated object. typedef int ImPoolIdx; template struct IMGUI_API ImPool { - ImVector Data; // Contiguous data + ImVector Buf; // Contiguous data ImGuiStorage Map; // ID->Index ImPoolIdx FreeIdx; // Next free idx to use ImPool() { FreeIdx = 0; } ~ImPool() { Clear(); } - T* GetByKey(ImGuiID key) { int idx = Map.GetInt(key, -1); return (idx != -1) ? &Data[idx] : NULL; } - T* GetByIndex(ImPoolIdx n) { return &Data[n]; } - ImPoolIdx GetIndex(const T* p) const { IM_ASSERT(p >= Data.Data && p < Data.Data + Data.Size); return (ImPoolIdx)(p - Data.Data); } - T* GetOrAddByKey(ImGuiID key) { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Data[*p_idx]; *p_idx = FreeIdx; return Add(); } - bool Contains(const T* p) const { return (p >= Data.Data && p < Data.Data + Data.Size); } - void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Data[idx].~T(); } Map.Clear(); Data.clear(); FreeIdx = 0; } - T* Add() { int idx = FreeIdx; if (idx == Data.Size) { Data.resize(Data.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Data[idx]; } IM_PLACEMENT_NEW(&Data[idx]) T(); return &Data[idx]; } + T* GetByKey(ImGuiID key) { int idx = Map.GetInt(key, -1); return (idx != -1) ? &Buf[idx] : NULL; } + T* GetByIndex(ImPoolIdx n) { return &Buf[n]; } + ImPoolIdx GetIndex(const T* p) const { IM_ASSERT(p >= Buf.Data && p < Buf.Data + Buf.Size); return (ImPoolIdx)(p - Buf.Data); } + T* GetOrAddByKey(ImGuiID key) { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Buf[*p_idx]; *p_idx = FreeIdx; return Add(); } + bool Contains(const T* p) const { return (p >= Buf.Data && p < Buf.Data + Buf.Size); } + void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Buf[idx].~T(); } Map.Clear(); Buf.clear(); FreeIdx = 0; } + T* Add() { int idx = FreeIdx; if (idx == Buf.Size) { Buf.resize(Buf.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Buf[idx]; } IM_PLACEMENT_NEW(&Buf[idx]) T(); return &Buf[idx]; } void Remove(ImGuiID key, const T* p) { Remove(key, GetIndex(p)); } - void Remove(ImGuiID key, ImPoolIdx idx) { Data[idx].~T(); *(int*)&Data[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); } - void Reserve(int capacity) { Data.reserve(capacity); Map.Data.reserve(capacity); } - int GetSize() const { return Data.Size; } + void Remove(ImGuiID key, ImPoolIdx idx) { Buf[idx].~T(); *(int*)&Buf[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); } + void Reserve(int capacity) { Buf.reserve(capacity); Map.Data.reserve(capacity); } + int GetSize() const { return Buf.Size; } +}; + +// Helper: ImChunkStream<> +// Build and iterate a contiguous stream of variable-sized structures. +// This is used by Settings to store persistent data while reducing allocation count. +// We store the chunk size first, and align the final size on 4 bytes boundaries (this what the '(X + 3) & ~3' statement is for) +// The tedious/zealous amount of casting is to avoid -Wcast-align warnings. +template +struct IMGUI_API ImChunkStream +{ + ImVector Buf; + + void clear() { Buf.clear(); } + bool empty() const { return Buf.Size == 0; } + int size() const { return Buf.Size; } + T* alloc_chunk(size_t sz) { size_t HDR_SZ = 4; sz = ((HDR_SZ + sz) + 3u) & ~3u; int off = Buf.Size; Buf.resize(off + (int)sz); ((int*)(void*)(Buf.Data + off))[0] = (int)sz; return (T*)(void*)(Buf.Data + off + (int)HDR_SZ); } + T* begin() { size_t HDR_SZ = 4; if (!Buf.Data) return NULL; return (T*)(void*)(Buf.Data + HDR_SZ); } + T* next_chunk(T* p) { size_t HDR_SZ = 4; IM_ASSERT(p >= begin() && p < end()); p = (T*)(void*)((char*)(void*)p + chunk_size(p)); if (p == (T*)(void*)((char*)end() + HDR_SZ)) return (T*)0; IM_ASSERT(p < end()); return p; } + int chunk_size(const T* p) { return ((const int*)p)[-1]; } + T* end() { return (T*)(void*)(Buf.Data + Buf.Size); } + int offset_from_ptr(const T* p) { IM_ASSERT(p >= begin() && p < end()); const ptrdiff_t off = (const char*)p - Buf.Data; return (int)off; } + T* ptr_from_offset(int off) { IM_ASSERT(off >= 4 && off < Buf.Size); return (T*)(void*)(Buf.Data + off); } }; //----------------------------------------------------------------------------- @@ -324,7 +421,7 @@ enum ImGuiButtonFlags_ ImGuiButtonFlags_DontClosePopups = 1 << 7, // disable automatically closing parent popup on press // [UNUSED] ImGuiButtonFlags_Disabled = 1 << 8, // disable interactions ImGuiButtonFlags_AlignTextBaseLine = 1 << 9, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine - ImGuiButtonFlags_NoKeyModifiers = 1 << 10, // disable interaction if a key modifier is held + ImGuiButtonFlags_NoKeyModifiers = 1 << 10, // disable mouse interaction if a key modifier is held ImGuiButtonFlags_NoHoldingActiveID = 1 << 11, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only) ImGuiButtonFlags_PressedOnDragDropHold = 1 << 12, // press when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) ImGuiButtonFlags_NoNavFocus = 1 << 13, // don't override navigation focus when activated @@ -403,8 +500,9 @@ enum ImGuiItemStatusFlags_ ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, ImGuiItemStatusFlags_Edited = 1 << 2, // Value exposed by item was edited in the current frame (should match the bool return value of most widgets) ImGuiItemStatusFlags_ToggledSelection = 1 << 3, // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected" because reporting the change allows us to handle clipping with less issues. - ImGuiItemStatusFlags_HasDeactivated = 1 << 4, // Set if the widget/group is able to provide data for the ImGuiItemStatusFlags_Deactivated flag. - ImGuiItemStatusFlags_Deactivated = 1 << 5 // Only valid if ImGuiItemStatusFlags_HasDeactivated is set. + ImGuiItemStatusFlags_ToggledOpen = 1 << 4, // Set when TreeNode() reports toggling their open state. + ImGuiItemStatusFlags_HasDeactivated = 1 << 5, // Set if the widget/group is able to provide data for the ImGuiItemStatusFlags_Deactivated flag. + ImGuiItemStatusFlags_Deactivated = 1 << 6 // Only valid if ImGuiItemStatusFlags_HasDeactivated is set. #ifdef IMGUI_ENABLE_TEST_ENGINE , // [imgui_tests only] @@ -623,7 +721,7 @@ struct IMGUI_API ImGuiMenuColumns ImGuiMenuColumns(); void Update(int count, float spacing, bool clear); float DeclColumns(float w0, float w1, float w2); - float CalcExtraSpace(float avail_w); + float CalcExtraSpace(float avail_w) const; }; // Internal state of the currently focused/edited text input box @@ -661,15 +759,17 @@ struct IMGUI_API ImGuiInputTextState }; // Windows data saved in imgui.ini file +// Because we never destroy or rename ImGuiWindowSettings, we can store the names in a separate buffer easily. +// (this is designed to be stored in a ImChunkStream buffer, with the variable-length Name following our structure) struct ImGuiWindowSettings { - char* Name; ImGuiID ID; ImVec2ih Pos; ImVec2ih Size; bool Collapsed; - ImGuiWindowSettings() { Name = NULL; ID = 0; Pos = Size = ImVec2ih(0, 0); Collapsed = false; } + ImGuiWindowSettings() { ID = 0; Pos = Size = ImVec2ih(0, 0); Collapsed = false; } + char* GetName() { return (char*)(this + 1); } }; struct ImGuiSettingsHandler @@ -859,9 +959,7 @@ struct ImGuiPtrOrIndex struct ImGuiContext { bool Initialized; - bool FrameScopeActive; // Set by NewFrame(), cleared by EndFrame() - bool FrameScopePushedImplicitWindow; // Set by NewFrame(), cleared by EndFrame() - bool FontAtlasOwnedByContext; // Io.Fonts-> is owned by the ImGuiContext and will be destructed along with it. + bool FontAtlasOwnedByContext; // IO.Fonts-> is owned by the ImGuiContext and will be destructed along with it. ImGuiIO IO; ImGuiStyle Style; ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back() @@ -872,19 +970,22 @@ struct ImGuiContext int FrameCount; int FrameCountEnded; int FrameCountRendered; + bool WithinFrameScope; // Set by NewFrame(), cleared by EndFrame() + bool WithinFrameScopeWithImplicitWindow; // Set by NewFrame(), cleared by EndFrame() when the implicit debug window has been pushed + bool WithinEndChild; // Set within EndChild() // Windows state ImVector Windows; // Windows, sorted in display order, back to front ImVector WindowsFocusOrder; // Windows, sorted in focus order, back to front ImVector WindowsSortBuffer; ImVector CurrentWindowStack; - ImGuiStorage WindowsById; - int WindowsActiveCount; - ImGuiWindow* CurrentWindow; // Being drawn into + ImGuiStorage WindowsById; // Map window's ImGuiID to ImGuiWindow* + int WindowsActiveCount; // Number of unique windows submitted by frame + ImGuiWindow* CurrentWindow; // Window being drawn into ImGuiWindow* HoveredWindow; // Will catch mouse inputs ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only) ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow. - ImGuiWindow* WheelingWindow; + ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window. ImVec2 WheelingWindowRefMousePos; float WheelingWindowTimer; @@ -912,7 +1013,6 @@ struct ImGuiContext bool ActiveIdPreviousFrameIsAlive; bool ActiveIdPreviousFrameHasBeenEditedBefore; ImGuiWindow* ActiveIdPreviousFrameWindow; - ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation. float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation. @@ -1000,7 +1100,7 @@ struct ImGuiContext ImGuiID DragDropAcceptIdPrev; // Target item id from previous frame (we need to store this to allow for overlapping drag and drop targets) int DragDropAcceptFrameCount; // Last time a target expressed a desire to accept the source ImVector DragDropPayloadBufHeap; // We don't expose the ImVector<> directly - unsigned char DragDropPayloadBufLocal[8]; // Local buffer for small payloads + unsigned char DragDropPayloadBufLocal[16]; // Local buffer for small payloads // Tab bars ImGuiTabBar* CurrentTabBar; @@ -1014,9 +1114,9 @@ struct ImGuiContext ImFont InputTextPasswordFont; ImGuiID TempInputTextId; // Temporary text input when CTRL+clicking on a slider, etc. ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets - float ColorEditLastHue; + float ColorEditLastHue; // Backup of last Hue associated to LastColor[3], so we can restore Hue in lossy RGB<>HSV round trips float ColorEditLastColor[3]; - ImVec4 ColorPickerRef; + ImVec4 ColorPickerRef; // Initial/reference color at the time of opening the color picker. bool DragCurrentAccumDirty; float DragCurrentAccum; // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio @@ -1033,16 +1133,16 @@ struct ImGuiContext ImVec2 PlatformImeLastPos; // Settings - bool SettingsLoaded; - float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero - ImGuiTextBuffer SettingsIniData; // In memory .ini settings - ImVector SettingsHandlers; // List of .ini settings handlers - ImVector SettingsWindows; // ImGuiWindow .ini settings entries (parsed from the last loaded .ini file and maintained on saving) + bool SettingsLoaded; + float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero + ImGuiTextBuffer SettingsIniData; // In memory .ini settings + ImVector SettingsHandlers; // List of .ini settings handlers + ImChunkStream SettingsWindows; // ImGuiWindow .ini settings entries - // Logging + // Capture/Logging bool LogEnabled; ImGuiLogType LogType; - FILE* LogFile; // If != NULL log to stdout/ file + ImFileHandle LogFile; // If != NULL log to stdout/ file ImGuiTextBuffer LogBuffer; // Accumulation buffer when log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators. float LogLinePosY; bool LogLineFirstItem; @@ -1066,7 +1166,6 @@ struct ImGuiContext ImGuiContext(ImFontAtlas* shared_font_atlas) : BackgroundDrawList(&DrawListSharedData), ForegroundDrawList(&DrawListSharedData) { Initialized = false; - FrameScopeActive = FrameScopePushedImplicitWindow = false; Font = NULL; FontSize = FontBaseSize = 0.0f; FontAtlasOwnedByContext = shared_font_atlas ? false : true; @@ -1074,6 +1173,7 @@ struct ImGuiContext Time = 0.0f; FrameCount = 0; FrameCountEnded = FrameCountRendered = -1; + WithinFrameScope = WithinFrameScopeWithImplicitWindow = WithinEndChild = false; WindowsActiveCount = 0; CurrentWindow = NULL; @@ -1101,12 +1201,10 @@ struct ImGuiContext ActiveIdClickOffset = ImVec2(-1,-1); ActiveIdWindow = NULL; ActiveIdSource = ImGuiInputSource_None; - ActiveIdPreviousFrame = 0; ActiveIdPreviousFrameIsAlive = false; ActiveIdPreviousFrameHasBeenEditedBefore = false; ActiveIdPreviousFrameWindow = NULL; - LastActiveId = 0; LastActiveIdTimer = 0.0f; @@ -1337,9 +1435,9 @@ struct IMGUI_API ImGuiWindow ImRect OuterRectClipped; // == Window->Rect() just after setup in Begin(). == window->Rect() for root window. ImRect InnerRect; // Inner rectangle (omit title bar, menu bar, scroll bar) ImRect InnerClipRect; // == InnerRect shrunk by WindowPadding*0.5f on each side, clipped within viewport or parent clip rect. - ImRect WorkRect; // Cover the whole scrolling region, shrunk by WindowPadding*1.0f on each side. This is meant to replace ContentsRegionRect over time (from 1.71+ onward). + ImRect WorkRect; // Cover the whole scrolling region, shrunk by WindowPadding*1.0f on each side. This is meant to replace ContentRegionRect over time (from 1.71+ onward). ImRect ClipRect; // Current clipping/scissoring rectangle, evolve as we are using PushClipRect(), etc. == DrawList->clip_rect_stack.back(). - ImRect ContentsRegionRect; // FIXME: This is currently confusing/misleading. It is essentially WorkRect but not handling of scrolling. We currently rely on it as right/bottom aligned sizing operation need some size to rely on. + ImRect ContentRegionRect; // FIXME: This is currently confusing/misleading. It is essentially WorkRect but not handling of scrolling. We currently rely on it as right/bottom aligned sizing operation need some size to rely on. int LastFrameActive; // Last frame number the window was Active. float LastTimeActive; // Last timestamp the window was Active (using float as we don't need high precision there) @@ -1348,7 +1446,7 @@ struct IMGUI_API ImGuiWindow ImGuiStorage StateStorage; ImVector ColumnsStorage; float FontWindowScale; // User scale multiplier per-window, via SetWindowFontScale() - int SettingsIdx; // Index into SettingsWindow[] (indices are always valid as we only grow the array from the back) + int SettingsOffset; // Offset into SettingsWindows[] (offsets are always valid as we only grow the array from the back) ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer) ImDrawList DrawListInst; @@ -1414,7 +1512,7 @@ enum ImGuiTabBarFlagsPrivate_ // Extend ImGuiTabItemFlags_ enum ImGuiTabItemFlagsPrivate_ { - ImGuiTabItemFlags_NoCloseButton = 1 << 20 // Store whether p_open is set or not, which we need to recompute WidthContents during layout. + ImGuiTabItemFlags_NoCloseButton = 1 << 20 // Store whether p_open is set or not, which we need to recompute ContentWidth during layout. }; // Storage for one active tab item (sizeof() 26~32 bytes) @@ -1427,9 +1525,9 @@ struct ImGuiTabItem int NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames float Offset; // Position relative to beginning of tab float Width; // Width currently displayed - float WidthContents; // Width of actual contents, stored during BeginTabItem() call + float ContentWidth; // Width of actual contents, stored during BeginTabItem() call - ImGuiTabItem() { ID = Flags = 0; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = WidthContents = 0.0f; } + ImGuiTabItem() { ID = 0; Flags = 0; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = ContentWidth = 0.0f; } }; // Storage for a tab bar (sizeof() 92~96 bytes) @@ -1543,8 +1641,8 @@ namespace ImGui IMGUI_API void PushOverrideID(ImGuiID id); // Basic Helpers for widget code - IMGUI_API void ItemSize(const ImVec2& size, float text_baseline_y = 0.0f); - IMGUI_API void ItemSize(const ImRect& bb, float text_baseline_y = 0.0f); + IMGUI_API void ItemSize(const ImVec2& size, float text_baseline_y = -1.0f); + IMGUI_API void ItemSize(const ImRect& bb, float text_baseline_y = -1.0f); IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL); IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id); IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged); @@ -1595,8 +1693,7 @@ namespace ImGui IMGUI_API bool IsMouseDragPastThreshold(int button, float lock_threshold = -1.0f); inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { ImGuiContext& g = *GImGui; const int key_index = g.IO.KeyMap[key]; return (key_index >= 0) ? IsKeyPressed(key_index, repeat) : false; } inline bool IsNavInputDown(ImGuiNavInput n) { ImGuiContext& g = *GImGui; return g.IO.NavInputs[n] > 0.0f; } - inline bool IsNavInputPressed(ImGuiNavInput n, ImGuiInputReadMode mode) { return GetNavInputAmount(n, mode) > 0.0f; } - inline bool IsNavInputPressedAnyOfTwo(ImGuiNavInput n1, ImGuiNavInput n2, ImGuiInputReadMode mode) { return (GetNavInputAmount(n1, mode) + GetNavInputAmount(n2, mode)) > 0.0f; } + inline bool IsNavInputTest(ImGuiNavInput n, ImGuiInputReadMode rm) { return (GetNavInputAmount(n, rm) > 0.0f); } // Drag and Drop IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id); @@ -1662,7 +1759,8 @@ namespace ImGui IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags); IMGUI_API void Scrollbar(ImGuiAxis axis); IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* p_scroll_v, float avail_v, float contents_v, ImDrawCornerFlags rounding_corners); - IMGUI_API ImGuiID GetScrollbarID(ImGuiWindow* window, ImGuiAxis axis); + IMGUI_API ImGuiID GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis); + IMGUI_API ImGuiID GetWindowResizeID(ImGuiWindow* window, int n); // 0..3: corners, 4..7: borders IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags); // Widgets low-level behaviors diff --git a/sources/3rdparty/imgui/imgui_widgets.cpp b/sources/3rdparty/imgui/imgui_widgets.cpp index d223f147..ec6f51a9 100644 --- a/sources/3rdparty/imgui/imgui_widgets.cpp +++ b/sources/3rdparty/imgui/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.74 WIP +// dear imgui, v1.74 // (widgets code) /* @@ -213,7 +213,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) text_size.y = (pos - text_pos).y; ImRect bb(text_pos, text_pos + text_size); - ItemSize(text_size); + ItemSize(text_size, 0.0f); ItemAdd(bb, 0); } else @@ -222,7 +222,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width); ImRect bb(text_pos, text_pos + text_size); - ItemSize(text_size); + ItemSize(text_size, 0.0f); if (!ItemAdd(bb, 0)) return; @@ -359,17 +359,18 @@ void ImGui::BulletTextV(const char* fmt, va_list args) const char* text_begin = g.TempBuffer; const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); const ImVec2 label_size = CalcTextSize(text_begin, text_end, false); - const float text_base_offset_y = ImMax(0.0f, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it - const float line_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize); - const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x*2) : 0.0f), ImMax(line_height, label_size.y))); // Empty text doesn't add padding - ItemSize(bb); + const ImVec2 total_size = ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x * 2) : 0.0f), label_size.y); // Empty text doesn't add padding + ImVec2 pos = window->DC.CursorPos; + pos.y += window->DC.CurrLineTextBaseOffset; + ItemSize(total_size, 0.0f); + const ImRect bb(pos, pos + total_size); if (!ItemAdd(bb, 0)) return; // Render ImU32 text_col = GetColorU32(ImGuiCol_Text); - RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f), text_col); - RenderText(bb.Min+ImVec2(g.FontSize + style.FramePadding.x*2, text_base_offset_y), text_begin, text_end, false); + RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, g.FontSize*0.5f), text_col); + RenderText(bb.Min + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0f), text_begin, text_end, false); } //------------------------------------------------------------------------- @@ -548,7 +549,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if (g.NavActivateDownId == id) { bool nav_activated_by_code = (g.NavActivateId == id); - bool nav_activated_by_inputs = IsNavInputPressed(ImGuiNavInput_Activate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiInputReadMode_Repeat : ImGuiInputReadMode_Pressed); + bool nav_activated_by_inputs = IsNavInputTest(ImGuiNavInput_Activate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiInputReadMode_Repeat : ImGuiInputReadMode_Pressed); if (nav_activated_by_code || nav_activated_by_inputs) pressed = true; if (nav_activated_by_code || nav_activated_by_inputs || g.ActiveId == id) @@ -691,7 +692,7 @@ bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiBu const ImGuiID id = window->GetID(str_id); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); const float default_size = GetFrameHeight(); - ItemSize(size, (size.y >= default_size) ? g.Style.FramePadding.y : 0.0f); + ItemSize(size, (size.y >= default_size) ? g.Style.FramePadding.y : -1.0f); if (!ItemAdd(bb, id)) return false; @@ -773,7 +774,7 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) return pressed; } -ImGuiID ImGui::GetScrollbarID(ImGuiWindow* window, ImGuiAxis axis) +ImGuiID ImGui::GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis) { return window->GetIDNoKeepAlive(axis == ImGuiAxis_X ? "#SCROLLX" : "#SCROLLY"); } @@ -851,7 +852,7 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, floa // Apply scroll // It is ok to modify Scroll here because we are being called in Begin() after the calculation of ContentSize and before setting up our starting position const float scroll_v_norm = ImSaturate((clicked_v_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm * 0.5f) / (1.0f - grab_h_norm)); - *p_scroll_v = IM_FLOOR(0.5f + scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v)); + *p_scroll_v = IM_ROUND(scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v)); // Update values for rendering scroll_ratio = ImSaturate(*p_scroll_v / scroll_max); @@ -880,7 +881,7 @@ void ImGui::Scrollbar(ImGuiAxis axis) ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - const ImGuiID id = GetScrollbarID(window, axis); + const ImGuiID id = GetWindowScrollbarID(window, axis); KeepAliveID(id); // Calculate scrollbar bounding box @@ -1057,8 +1058,8 @@ bool ImGui::RadioButton(const char* label, bool active) return false; ImVec2 center = check_bb.GetCenter(); - center.x = IM_FLOOR(center.x + 0.5f); - center.y = IM_FLOOR(center.y + 0.5f); + center.x = IM_ROUND(center.x); + center.y = IM_ROUND(center.y); const float radius = (square_sz - 1.0f) * 0.5f; bool hovered, held; @@ -1347,7 +1348,7 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float // Render const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : (hovered && g.HoveredIdTimer >= hover_visibility_delay) ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); - window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, col, g.Style.FrameRounding); + window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, col, 0.0f); return held; } @@ -2473,7 +2474,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ return value_changed; } -// For 32-bits and larger types, slider bounds are limited to half the natural type range. +// For 32-bit and larger types, slider bounds are limited to half the natural type range. // So e.g. an integer Slider between INT_MAX-10 and INT_MAX will fail, but an integer Slider between INT_MAX/2-10 and INT_MAX/2 will be ok. // It would be possible to lift that limitation with some work but it doesn't seem to be worth it for sliders. bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb) @@ -3156,7 +3157,7 @@ namespace ImStb static int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return obj->CurLenW; } static ImWchar STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING* obj, int idx) { return obj->TextW[idx]; } static float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *GImGui; return g.Font->GetCharAdvance(c) * (g.FontSize / g.Font->FontSize); } -static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x10000 ? 0 : key; } +static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x200000 ? 0 : key; } static ImWchar STB_TEXTEDIT_NEWLINE = '\n'; static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* obj, int line_start_idx) { @@ -3339,6 +3340,10 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f if (c >= 0xE000 && c <= 0xF8FF) return false; + // Filter Unicode ranges we are not handling in this build. + if (c > IM_UNICODE_CODEPOINT_MAX) + return false; + // Generic named filters if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific)) { @@ -3463,8 +3468,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const bool user_clicked = hovered && io.MouseClicked[0]; const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_NavKeyboard)); - const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetScrollbarID(draw_window, ImGuiAxis_Y); - const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetScrollbarID(draw_window, ImGuiAxis_Y); + const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); + const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); bool clear_active_id = false; bool select_all = (g.ActiveId != id) && ((flags & ImGuiInputTextFlags_AutoSelectAll) != 0 || user_nav_input_start) && (!is_multiline); @@ -3762,7 +3767,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ s += ImTextCharFromUtf8(&c, s, NULL); if (c == 0) break; - if (c >= 0x10000 || !InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data)) continue; clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c; } @@ -3986,7 +3991,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter. searches_remaining += is_multiline ? 1 : 0; int line_count = 0; - //for (const ImWchar* s = text_begin; (s = (const ImWchar*)wcschr((const wchar_t*)s, (wchar_t)'\n')) != NULL; s++) // FIXME-OPT: Could use this when wchar_t are 16-bits + //for (const ImWchar* s = text_begin; (s = (const ImWchar*)wcschr((const wchar_t*)s, (wchar_t)'\n')) != NULL; s++) // FIXME-OPT: Could use this when wchar_t are 16-bit for (const ImWchar* s = text_begin; *s != 0; s++) if (*s == '\n') { @@ -4063,7 +4068,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ break; if (rect_pos.y < clip_rect.y) { - //p = (const ImWchar*)wmemchr((const wchar_t*)p, '\n', text_selected_end - p); // FIXME-OPT: Could use this when wchar_t are 16-bits + //p = (const ImWchar*)wmemchr((const wchar_t*)p, '\n', text_selected_end - p); // FIXME-OPT: Could use this when wchar_t are 16-bit //p = p ? p + 1 : text_selected_end; while (p < text_selected_end) if (*p++ == '\n') @@ -4784,7 +4789,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl draw_list->PrimVtx(trb, uv_white, hue_color32); draw_list->PrimVtx(trc, uv_white, col_white); draw_list->PrimVtx(tra, uv_white, 0); - draw_list->PrimVtx(trb, uv_white, col_white); + draw_list->PrimVtx(trb, uv_white, col_black); draw_list->PrimVtx(trc, uv_white, 0); draw_list->AddTriangle(tra, trb, trc, col_midgrey, 1.5f); sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V)); @@ -4795,13 +4800,13 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), col_white, hue_color32, hue_color32, col_white); draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0, 0, col_black, col_black); RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0.0f); - sv_cursor_pos.x = ImClamp(IM_FLOOR(picker_pos.x + ImSaturate(S) * sv_picker_size + 0.5f), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2); // Sneakily prevent the circle to stick out too much - sv_cursor_pos.y = ImClamp(IM_FLOOR(picker_pos.y + ImSaturate(1 - V) * sv_picker_size + 0.5f), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2); + sv_cursor_pos.x = ImClamp(IM_ROUND(picker_pos.x + ImSaturate(S) * sv_picker_size), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2); // Sneakily prevent the circle to stick out too much + sv_cursor_pos.y = ImClamp(IM_ROUND(picker_pos.y + ImSaturate(1 - V) * sv_picker_size), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2); // Render Hue Bar for (int i = 0; i < 6; ++i) draw_list->AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), col_hues[i], col_hues[i], col_hues[i + 1], col_hues[i + 1]); - float bar0_line_y = IM_FLOOR(picker_pos.y + H * sv_picker_size + 0.5f); + float bar0_line_y = IM_ROUND(picker_pos.y + H * sv_picker_size); RenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0f); RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha); } @@ -4819,7 +4824,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl ImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size); RenderColorRectWithAlphaCheckerboard(bar1_bb.Min, bar1_bb.Max, 0, bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f)); draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, user_col32_striped_of_alpha, user_col32_striped_of_alpha, user_col32_striped_of_alpha & ~IM_COL32_A_MASK, user_col32_striped_of_alpha & ~IM_COL32_A_MASK); - float bar1_line_y = IM_FLOOR(picker_pos.y + (1.0f - alpha) * sv_picker_size + 0.5f); + float bar1_line_y = IM_ROUND(picker_pos.y + (1.0f - alpha) * sv_picker_size); RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f); RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha); } @@ -4876,7 +4881,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl bb_inner.Expand(off); if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb.w < 1.0f) { - float mid_x = IM_FLOOR((bb_inner.Min.x + bb_inner.Max.x) * 0.5f + 0.5f); + float mid_x = IM_ROUND((bb_inner.Min.x + bb_inner.Max.x) * 0.5f); RenderColorRectWithAlphaCheckerboard(ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawCornerFlags_TopRight| ImDrawCornerFlags_BotRight); window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotLeft); } @@ -5211,7 +5216,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0; - const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, 0.0f); + const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, ImMin(window->DC.CurrLineTextBaseOffset, style.FramePadding.y)); if (!label_end) label_end = FindRenderedTextEnd(label); @@ -5236,7 +5241,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const float text_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x*2 : 0.0f); // Include collapser ImVec2 text_pos(window->DC.CursorPos.x + text_offset_x, window->DC.CursorPos.y + text_offset_y); - ItemSize(ImVec2(text_width, frame_height), text_offset_y); + ItemSize(ImVec2(text_width, frame_height), padding.y); // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing ImRect interact_bb = frame_bb; @@ -5268,7 +5273,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // - OpenOnDoubleClick .............. double-click anywhere to open // - OpenOnArrow .................... single-click on arrow to open // - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open - ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers; + ImGuiButtonFlags button_flags = 0; if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) button_flags |= ImGuiButtonFlags_AllowItemOverlap; if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) @@ -5276,23 +5281,31 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (!is_leaf) button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; + // We allow clicking on the arrow section with keyboard modifiers held, in order to easily + // allow browsing a tree while preserving selection with code implementing multi-selection patterns. + // When clicking on the rest of the tree node we always disallow keyboard modifiers. + const float hit_padding_x = style.TouchExtraPadding.x; + const float arrow_hit_x1 = (text_pos.x - text_offset_x) - hit_padding_x; + const float arrow_hit_x2 = (text_pos.x - text_offset_x) + (g.FontSize + padding.x * 2.0f) + hit_padding_x; + if (window != g.HoveredWindow || !(g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2)) + button_flags |= ImGuiButtonFlags_NoKeyModifiers; + bool selected = (flags & ImGuiTreeNodeFlags_Selected) != 0; const bool was_selected = selected; bool hovered, held; bool pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags); - bool toggled = false; if (!is_leaf) { + bool toggled = false; if (pressed) { - const float arrow_x1 = text_pos.x - text_offset_x; - const float arrow_x2 = arrow_x1 + g.FontSize + padding.x * 2.0f; - toggled = !(flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) || (g.NavActivateId == id); + if ((flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) == 0 || (g.NavActivateId == id)) + toggled = true; if (flags & ImGuiTreeNodeFlags_OpenOnArrow) - toggled |= IsMouseHoveringRect(ImVec2(arrow_x1, interact_bb.Min.y), ImVec2(arrow_x2, interact_bb.Max.y)) && (!g.NavDisableMouseHover); - if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) - toggled |= g.IO.MouseDoubleClicked[0]; + toggled |= (g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2) && (!g.NavDisableMouseHover); // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job + if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseDoubleClicked[0]) + toggled = true; if (g.DragDropActive && is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again. toggled = false; } @@ -5312,6 +5325,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l { is_open = !is_open; window->DC.StateStorage->SetInt(id, is_open); + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledOpen; } } if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) @@ -5507,7 +5521,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl ImVec2 pos = window->DC.CursorPos; pos.y += window->DC.CurrLineTextBaseOffset; ImRect bb_inner(pos, pos + size); - ItemSize(size); + ItemSize(size, 0.0f); // Fill horizontal space. ImVec2 window_padding = window->WindowPadding; @@ -5943,10 +5957,10 @@ void ImGui::Value(const char* prefix, float v, const char* float_format) // [SECTION] MenuItem, BeginMenu, EndMenu, etc. //------------------------------------------------------------------------- // - ImGuiMenuColumns [Internal] -// - BeginMainMenuBar() -// - EndMainMenuBar() // - BeginMenuBar() // - EndMenuBar() +// - BeginMainMenuBar() +// - EndMainMenuBar() // - BeginMenu() // - EndMenu() // - MenuItem() @@ -5989,45 +6003,11 @@ float ImGuiMenuColumns::DeclColumns(float w0, float w1, float w2) // not using v return ImMax(Width, NextWidth); } -float ImGuiMenuColumns::CalcExtraSpace(float avail_w) +float ImGuiMenuColumns::CalcExtraSpace(float avail_w) const { return ImMax(0.0f, avail_w - Width); } -// For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set. -bool ImGui::BeginMainMenuBar() -{ - ImGuiContext& g = *GImGui; - g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f)); - SetNextWindowPos(ImVec2(0.0f, 0.0f)); - SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.NextWindowData.MenuBarOffsetMinVal.y + g.FontBaseSize + g.Style.FramePadding.y)); - PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); - PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0,0)); - ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar; - bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar(); - PopStyleVar(2); - g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); - if (!is_open) - { - End(); - return false; - } - return true; //-V1020 -} - -void ImGui::EndMainMenuBar() -{ - EndMenuBar(); - - // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window - // FIXME: With this strategy we won't be able to restore a NULL focus. - ImGuiContext& g = *GImGui; - if (g.CurrentWindow == g.NavWindow && g.NavLayer == 0 && !g.NavAnyRequest) - FocusTopMostWindowUnderOne(g.NavWindow, NULL); - - End(); -} - // FIXME: Provided a rectangle perhaps e.g. a BeginMenuBarEx() could be used anywhere.. // Currently the main responsibility of this function being to setup clip-rect + horizontal layout + menu navigation layer. // Ideally we also want this to be responsible for claiming space out of the main window scrolling rectangle, in which case ImGuiWindowFlags_MenuBar will become unnecessary. @@ -6047,7 +6027,7 @@ bool ImGui::BeginMenuBar() // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect. // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy. ImRect bar_rect = window->MenuBarRect(); - ImRect clip_rect(ImFloor(bar_rect.Min.x + 0.5f), ImFloor(bar_rect.Min.y + window->WindowBorderSize + 0.5f), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - window->WindowRounding) + 0.5f), ImFloor(bar_rect.Max.y + 0.5f)); + ImRect clip_rect(IM_ROUND(bar_rect.Min.x), IM_ROUND(bar_rect.Min.y + window->WindowBorderSize), IM_ROUND(ImMax(bar_rect.Min.x, bar_rect.Max.x - window->WindowRounding)), IM_ROUND(bar_rect.Max.y)); clip_rect.ClipWith(window->OuterRectClipped); PushClipRect(clip_rect.Min, clip_rect.Max, false); @@ -6101,6 +6081,40 @@ void ImGui::EndMenuBar() window->DC.MenuBarAppending = false; } +// For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set. +bool ImGui::BeginMainMenuBar() +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f)); + SetNextWindowPos(ImVec2(0.0f, 0.0f)); + SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.NextWindowData.MenuBarOffsetMinVal.y + g.FontBaseSize + g.Style.FramePadding.y)); + PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar; + bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar(); + PopStyleVar(2); + g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); + if (!is_open) + { + End(); + return false; + } + return true; //-V1020 +} + +void ImGui::EndMainMenuBar() +{ + EndMenuBar(); + + // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window + // FIXME: With this strategy we won't be able to restore a NULL focus. + ImGuiContext& g = *GImGui; + if (g.CurrentWindow == g.NavWindow && g.NavLayer == 0 && !g.NavAnyRequest) + FocusTopMostWindowUnderOne(g.NavWindow, NULL); + + End(); +} + bool ImGui::BeginMenu(const char* label, bool enabled) { ImGuiWindow* window = GetCurrentWindow(); @@ -6438,15 +6452,15 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG tab_bar->FramePadding = g.Style.FramePadding; // Layout - ItemSize(ImVec2(tab_bar->OffsetMaxIdeal, tab_bar->BarRect.GetHeight())); + ItemSize(ImVec2(tab_bar->OffsetMaxIdeal, tab_bar->BarRect.GetHeight()), tab_bar->FramePadding.y); window->DC.CursorPos.x = tab_bar->BarRect.Min.x; // Draw separator const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive); const float y = tab_bar->BarRect.Max.y - 1.0f; { - const float separator_min_x = tab_bar->BarRect.Min.x - ImFloor(window->WindowPadding.x * 0.5f); - const float separator_max_x = tab_bar->BarRect.Max.x + ImFloor(window->WindowPadding.x * 0.5f); + const float separator_min_x = tab_bar->BarRect.Min.x - IM_FLOOR(window->WindowPadding.x * 0.5f); + const float separator_max_x = tab_bar->BarRect.Max.x + IM_FLOOR(window->WindowPadding.x * 0.5f); window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f); } return true; @@ -6462,8 +6476,8 @@ void ImGui::EndTabBar() ImGuiTabBar* tab_bar = g.CurrentTabBar; if (tab_bar == NULL) { - IM_ASSERT(tab_bar != NULL && "Mismatched BeginTabBar()/EndTabBar()!"); - return; // FIXME-ERRORHANDLING + IM_ASSERT_USER_ERROR(tab_bar != NULL, "Mismatched BeginTabBar()/EndTabBar()!"); + return; } if (tab_bar->WantLayout) TabBarLayout(tab_bar); @@ -6565,13 +6579,13 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) // and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window. const char* tab_name = tab_bar->GetTabName(tab); const bool has_close_button = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) ? false : true; - tab->WidthContents = TabItemCalcSize(tab_name, has_close_button).x; + tab->ContentWidth = TabItemCalcSize(tab_name, has_close_button).x; - width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->WidthContents; + width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->ContentWidth; // Store data so we can build an array sorted by width if we need to shrink tabs down g.ShrinkWidthBuffer[tab_n].Index = tab_n; - g.ShrinkWidthBuffer[tab_n].Width = tab->WidthContents; + g.ShrinkWidthBuffer[tab_n].Width = tab->ContentWidth; } // Compute width @@ -6591,7 +6605,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) { ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; - tab->Width = ImMin(tab->WidthContents, tab_max_width); + tab->Width = ImMin(tab->ContentWidth, tab_max_width); IM_ASSERT(tab->Width > 0.0f); } } @@ -6607,7 +6621,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) if (scroll_track_selected_tab_id == 0 && g.NavJustMovedToId == tab->ID) scroll_track_selected_tab_id = tab->ID; offset_x += tab->Width + g.Style.ItemInnerSpacing.x; - offset_x_ideal += tab->WidthContents + g.Style.ItemInnerSpacing.x; + offset_x_ideal += tab->ContentWidth + g.Style.ItemInnerSpacing.x; } tab_bar->OffsetMax = ImMax(offset_x - g.Style.ItemInnerSpacing.x, 0.0f); tab_bar->OffsetMaxIdeal = ImMax(offset_x_ideal - g.Style.ItemInnerSpacing.x, 0.0f); @@ -6859,8 +6873,8 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f ImGuiTabBar* tab_bar = g.CurrentTabBar; if (tab_bar == NULL) { - IM_ASSERT(tab_bar && "Needs to be called between BeginTabBar() and EndTabBar()!"); - return false; // FIXME-ERRORHANDLING + IM_ASSERT_USER_ERROR(tab_bar, "BeginTabItem() Needs to be called between BeginTabBar() and EndTabBar()!"); + return false; } bool ret = TabItemEx(tab_bar, label, p_open, flags); if (ret && !(flags & ImGuiTabItemFlags_NoPushId)) @@ -6928,7 +6942,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, tab_is_new = true; } tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_ptr(tab); - tab->WidthContents = size.x; + tab->ContentWidth = size.x; if (p_open == NULL) flags |= ImGuiTabItemFlags_NoCloseButton; @@ -7039,10 +7053,10 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, } #if 0 - if (hovered && g.HoveredIdNotActiveTimer > 0.50f && bb.GetWidth() < tab->WidthContents) + if (hovered && g.HoveredIdNotActiveTimer > 0.50f && bb.GetWidth() < tab->ContentWidth) { // Enlarge tab display when hovering - bb.Max.x = bb.Min.x + IM_FLOOR(ImLerp(bb.GetWidth(), tab->WidthContents, ImSaturate((g.HoveredIdNotActiveTimer - 0.40f) * 6.0f))); + bb.Max.x = bb.Min.x + IM_FLOOR(ImLerp(bb.GetWidth(), tab->ContentWidth, ImSaturate((g.HoveredIdNotActiveTimer - 0.40f) * 6.0f))); display_draw_list = GetForegroundDrawList(window); TabItemBackground(display_draw_list, bb, flags, GetColorU32(ImGuiCol_TitleBgActive)); } @@ -7442,8 +7456,8 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag { // Compute clipping rectangle ImGuiColumnData* column = &columns->Columns[n]; - float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n)); - float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n + 1) - 1.0f); + float clip_x1 = IM_ROUND(window->Pos.x + GetColumnOffset(n)); + float clip_x2 = IM_ROUND(window->Pos.x + GetColumnOffset(n + 1) - 1.0f); column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX); column->ClipRect.ClipWith(window->ClipRect); } diff --git a/sources/3rdparty/imgui/imstb_textedit.h b/sources/3rdparty/imgui/imstb_textedit.h index d7fcbd62..2077d02a 100644 --- a/sources/3rdparty/imgui/imstb_textedit.h +++ b/sources/3rdparty/imgui/imstb_textedit.h @@ -1,4 +1,4 @@ -// [DEAR IMGUI] +// [DEAR IMGUI] // This is a slightly modified version of stb_textedit.h 1.13. // Those changes would need to be pushed into nothings/stb: // - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321) diff --git a/sources/3rdparty/imgui/imstb_truetype.h b/sources/3rdparty/imgui/imstb_truetype.h index c1cdb180..193338af 100644 --- a/sources/3rdparty/imgui/imstb_truetype.h +++ b/sources/3rdparty/imgui/imstb_truetype.h @@ -1,4 +1,4 @@ -// [DEAR IMGUI] +// [DEAR IMGUI] // This is a slightly modified version of stb_truetype.h 1.20. // Mostly fixing for compiler and static analyzer warnings. // Grep for [DEAR IMGUI] to find the changes. diff --git a/sources/3rdparty/miniz/miniz_zip.c b/sources/3rdparty/miniz/miniz_zip.c index e4877d20..6dfe8076 100644 --- a/sources/3rdparty/miniz/miniz_zip.c +++ b/sources/3rdparty/miniz/miniz_zip.c @@ -1941,7 +1941,7 @@ mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) { /* Decompression required, therefore intermediate read buffer required */ - pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); + pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); diff --git a/sources/enduro2d/core/render.cpp b/sources/enduro2d/core/render.cpp index 93b08eda..9e9a7c9c 100644 --- a/sources/enduro2d/core/render.cpp +++ b/sources/enduro2d/core/render.cpp @@ -21,39 +21,39 @@ namespace }; const pixel_type_description pixel_type_descriptions[] = { - {2, false, true, false, pixel_declaration::pixel_type::depth16, false, v2u(1,1)}, - {3, false, true, false, pixel_declaration::pixel_type::depth24, false, v2u(1,1)}, - {4, false, true, true, pixel_declaration::pixel_type::depth24_stencil8, false, v2u(1,1)}, + {2, false, true, false, pixel_declaration::pixel_type::depth16, false, v2u(1,1)}, + {3, false, true, false, pixel_declaration::pixel_type::depth24, false, v2u(1,1)}, + {4, false, true, true, pixel_declaration::pixel_type::depth24_stencil8, false, v2u(1,1)}, - {1, true, false, false, pixel_declaration::pixel_type::a8, false, v2u(1,1)}, - {1, true, false, false, pixel_declaration::pixel_type::l8, false, v2u(1,1)}, - {2, true, false, false, pixel_declaration::pixel_type::la8, false, v2u(1,1)}, - {3, true, false, false, pixel_declaration::pixel_type::rgb8, false, v2u(1,1)}, - {4, true, false, false, pixel_declaration::pixel_type::rgba8, false, v2u(1,1)}, + {1, true, false, false, pixel_declaration::pixel_type::a8, false, v2u(1,1)}, + {1, true, false, false, pixel_declaration::pixel_type::l8, false, v2u(1,1)}, + {2, true, false, false, pixel_declaration::pixel_type::la8, false, v2u(1,1)}, + {3, true, false, false, pixel_declaration::pixel_type::rgb8, false, v2u(1,1)}, + {4, true, false, false, pixel_declaration::pixel_type::rgba8, false, v2u(1,1)}, - {8, true, false, false, pixel_declaration::pixel_type::rgba_dxt1, true, v2u(4,4)}, - {6, true, false, false, pixel_declaration::pixel_type::rgba_dxt3, true, v2u(4,4)}, - {6, true, false, false, pixel_declaration::pixel_type::rgba_dxt5, true, v2u(4,4)}, + {8, true, false, false, pixel_declaration::pixel_type::rgba_dxt1, true, v2u(4,4)}, + {16, true, false, false, pixel_declaration::pixel_type::rgba_dxt3, true, v2u(4,4)}, + {16, true, false, false, pixel_declaration::pixel_type::rgba_dxt5, true, v2u(4,4)}, - {8, true, false, false, pixel_declaration::pixel_type::rgb_etc1, true, v2u(4,4)}, - {8, true, false, false, pixel_declaration::pixel_type::rgb_etc2, true, v2u(4,4)}, - {6, true, false, false, pixel_declaration::pixel_type::rgba_etc2, true, v2u(4,4)}, - {8, true, false, false, pixel_declaration::pixel_type::rgb_a1_etc2, true, v2u(4,4)}, + {8, true, false, false, pixel_declaration::pixel_type::rgb_etc1, true, v2u(4,4)}, + {8, true, false, false, pixel_declaration::pixel_type::rgb_etc2, true, v2u(4,4)}, + {16, true, false, false, pixel_declaration::pixel_type::rgba_etc2, true, v2u(4,4)}, + {8, true, false, false, pixel_declaration::pixel_type::rgb_a1_etc2, true, v2u(4,4)}, - {6, true, false, false, pixel_declaration::pixel_type::rgba_astc4x4, true, v2u(4,4)}, - {6, true, false, false, pixel_declaration::pixel_type::rgba_astc5x5, true, v2u(5,5)}, - {6, true, false, false, pixel_declaration::pixel_type::rgba_astc6x6, true, v2u(6,6)}, - {6, true, false, false, pixel_declaration::pixel_type::rgba_astc8x8, true, v2u(8,8)}, - {6, true, false, false, pixel_declaration::pixel_type::rgba_astc10x10, true, v2u(10,10)}, - {6, true, false, false, pixel_declaration::pixel_type::rgba_astc12x12, true, v2u(12,12)}, + {16, true, false, false, pixel_declaration::pixel_type::rgba_astc4x4, true, v2u(4,4)}, + {16, true, false, false, pixel_declaration::pixel_type::rgba_astc5x5, true, v2u(5,5)}, + {16, true, false, false, pixel_declaration::pixel_type::rgba_astc6x6, true, v2u(6,6)}, + {16, true, false, false, pixel_declaration::pixel_type::rgba_astc8x8, true, v2u(8,8)}, + {16, true, false, false, pixel_declaration::pixel_type::rgba_astc10x10, true, v2u(10,10)}, + {16, true, false, false, pixel_declaration::pixel_type::rgba_astc12x12, true, v2u(12,12)}, - {8, true, false, false, pixel_declaration::pixel_type::rgb_pvrtc2, true, v2u(8,4)}, - {8, true, false, false, pixel_declaration::pixel_type::rgb_pvrtc4, true, v2u(4,4)}, - {8, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc2, true, v2u(8,4)}, - {8, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc4, true, v2u(4,4)}, + {8, true, false, false, pixel_declaration::pixel_type::rgb_pvrtc2, true, v2u(8,4)}, + {8, true, false, false, pixel_declaration::pixel_type::rgb_pvrtc4, true, v2u(4,4)}, + {8, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc2, true, v2u(8,4)}, + {8, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc4, true, v2u(4,4)}, - {8, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc2_v2, true, v2u(8,4)}, - {8, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc4_v2, true, v2u(4,4)} + {8, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc2_v2, true, v2u(8,4)}, + {8, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc4_v2, true, v2u(4,4)} }; const pixel_type_description& get_pixel_type_description(pixel_declaration::pixel_type type) noexcept { diff --git a/untests/catch/catch.hpp b/untests/catch/catch.hpp index 391db530..b4eccfc1 100644 --- a/untests/catch/catch.hpp +++ b/untests/catch/catch.hpp @@ -1,6 +1,6 @@ /* - * Catch v2.10.0 - * Generated: 2019-10-13 22:24:46.755734 + * Catch v2.11.0 + * Generated: 2019-11-15 15:01:56.628356 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2019 Two Blue Cubes Ltd. All rights reserved. @@ -14,7 +14,7 @@ #define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 10 +#define CATCH_VERSION_MINOR 11 #define CATCH_VERSION_PATCH 0 #ifdef __clang__ @@ -136,32 +136,33 @@ namespace Catch { # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS #endif -#ifdef __clang__ +// We have to avoid both ICC and Clang, because they try to mask themselves +// as gcc, and we want only GCC in this block +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) +#endif -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ - _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") -# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic pop" ) +#if defined(__clang__) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic pop" ) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \ - _Pragma( "clang diagnostic pop" ) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS \ - _Pragma( "clang diagnostic pop" ) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) + +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) #endif // __clang__ @@ -220,7 +221,10 @@ namespace Catch { //////////////////////////////////////////////////////////////////////////////// // Visual C++ -#ifdef _MSC_VER +#if defined(_MSC_VER) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) # if _MSC_VER >= 1900 // Visual Studio 2015 or newer # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS @@ -392,21 +396,35 @@ namespace Catch { # define CATCH_CONFIG_GLOBAL_NEXTAFTER #endif +// Even if we do not think the compiler has that warning, we still have +// to provide a macro that can be used by the code. +#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS +#endif + +#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#elif defined(__clang__) && (__clang_major__ < 5) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) @@ -512,9 +530,10 @@ namespace Catch { } // end namespace Catch #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION // end catch_tag_alias_autoregistrar.h // start catch_test_registry.h @@ -560,49 +579,24 @@ namespace Catch { /// A non-owning string class (similar to the forthcoming std::string_view) /// Note that, because a StringRef may be a substring of another string, - /// it may not be null terminated. c_str() must return a null terminated - /// string, however, and so the StringRef will internally take ownership - /// (taking a copy), if necessary. In theory this ownership is not externally - /// visible - but it does mean (substring) StringRefs should not be shared between - /// threads. + /// it may not be null terminated. class StringRef { public: using size_type = std::size_t; using const_iterator = const char*; private: - friend struct StringRefTestAccess; - - char const* m_start; - size_type m_size; - - char* m_data = nullptr; - - void takeOwnership(); - static constexpr char const* const s_empty = ""; - public: // construction/ assignment - StringRef() noexcept - : StringRef( s_empty, 0 ) - {} + char const* m_start = s_empty; + size_type m_size = 0; - StringRef( StringRef const& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ) - {} - - StringRef( StringRef&& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ), - m_data( other.m_data ) - { - other.m_data = nullptr; - } + public: // construction + constexpr StringRef() noexcept = default; StringRef( char const* rawChars ) noexcept; - StringRef( char const* rawChars, size_type size ) noexcept + constexpr StringRef( char const* rawChars, size_type size ) noexcept : m_start( rawChars ), m_size( size ) {} @@ -612,27 +606,15 @@ namespace Catch { m_size( stdString.size() ) {} - ~StringRef() noexcept { - delete[] m_data; - } - - auto operator = ( StringRef const &other ) noexcept -> StringRef& { - delete[] m_data; - m_data = nullptr; - m_start = other.m_start; - m_size = other.m_size; - return *this; - } - explicit operator std::string() const { return std::string(m_start, m_size); } - void swap( StringRef& other ) noexcept; - public: // operators auto operator == ( StringRef const& other ) const noexcept -> bool; - auto operator != ( StringRef const& other ) const noexcept -> bool; + auto operator != (StringRef const& other) const noexcept -> bool { + return !(*this == other); + } auto operator[] ( size_type index ) const noexcept -> char { assert(index < m_size); @@ -640,41 +622,44 @@ namespace Catch { } public: // named queries - auto empty() const noexcept -> bool { + constexpr auto empty() const noexcept -> bool { return m_size == 0; } - auto size() const noexcept -> size_type { + constexpr auto size() const noexcept -> size_type { return m_size; } + // Returns the current start pointer. If the StringRef is not + // null-terminated, throws std::domain_exception auto c_str() const -> char const*; public: // substrings and searches - auto substr( size_type start, size_type size ) const noexcept -> StringRef; + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, size()). + // If start > size(), then the substring is empty. + auto substr( size_type start, size_type length ) const noexcept -> StringRef; - // Returns the current start pointer. - // Note that the pointer can change when if the StringRef is a substring - auto currentData() const noexcept -> char const*; + // Returns the current start pointer. May not be null-terminated. + auto data() const noexcept -> char const*; + + constexpr auto isNullTerminated() const noexcept -> bool { + return m_start[m_size] == '\0'; + } public: // iterators - const_iterator begin() const { return m_start; } - const_iterator end() const { return m_start + m_size; } - - private: // ownership queries - may not be consistent between calls - auto isOwned() const noexcept -> bool; - auto isSubstring() const noexcept -> bool; + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } }; auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; - inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { return StringRef( rawChars, size ); } - } // namespace Catch -inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { +constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { return Catch::StringRef( rawChars, size ); } @@ -775,35 +760,49 @@ inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noex template struct TypeList {};\ template\ constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ + template class...> struct TemplateTypeList{};\ + template class...Cs>\ + constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ + template\ + struct append;\ + template\ + struct rewrap;\ + template class, typename...>\ + struct create;\ + template class, typename>\ + struct convert;\ \ - template class L1, typename...E1, template class L2, typename...E2> \ - constexpr auto append(L1, L2) noexcept -> L1 { return {}; }\ + template \ + struct append { using type = T; };\ template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ - constexpr auto append(L1, L2, Rest...) noexcept -> decltype(append(L1{}, Rest{}...)) { return {}; }\ + struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ template< template class L1, typename...E1, typename...Rest>\ - constexpr auto append(L1, TypeList, Rest...) noexcept -> L1 { return {}; }\ + struct append, TypeList, Rest...> { using type = L1; };\ \ template< template class Container, template class List, typename...elems>\ - constexpr auto rewrap(List) noexcept -> TypeList> { return {}; }\ + struct rewrap, List> { using type = TypeList>; };\ template< template class Container, template class List, class...Elems, typename...Elements>\ - constexpr auto rewrap(List,Elements...) noexcept -> decltype(append(TypeList>{}, rewrap(Elements{}...))) { return {}; }\ + struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ \ template