From 45c46f5ae728d2b0b8da9f3b573f857d81dfbdd2 Mon Sep 17 00:00:00 2001 From: Fabio Pellacini Date: Thu, 5 Aug 2021 14:25:03 +0200 Subject: [PATCH] Update ImGui and STB dependencies. (#1267) --- libs/yocto/ext/stb_image.h | 270 +++-- libs/yocto/ext/stb_image_resize.h | 21 +- libs/yocto/ext/stb_image_write.h | 80 +- libs/yocto_gui/ext/imgui/imgui.cpp | 1005 ++++++++++------- libs/yocto_gui/ext/imgui/imgui.h | 281 +++-- libs/yocto_gui/ext/imgui/imgui_demo.cpp | 368 +++--- libs/yocto_gui/ext/imgui/imgui_draw.cpp | 360 ++++-- libs/yocto_gui/ext/imgui/imgui_impl_glfw.cpp | 13 +- .../ext/imgui/imgui_impl_opengl2.cpp | 4 +- .../ext/imgui/imgui_impl_opengl3.cpp | 20 +- libs/yocto_gui/ext/imgui/imgui_internal.h | 346 ++++-- libs/yocto_gui/ext/imgui/imgui_tables.cpp | 254 +++-- libs/yocto_gui/ext/imgui/imgui_widgets.cpp | 516 +++++---- libs/yocto_gui/yocto_imgui.cpp | 2 +- tests/arealights1/arealights1.json | 126 +-- tests/environments1/environments1.json | 108 +- tests/environments2/environments2.json | 108 +- tests/features1/features1.json | 130 +-- tests/furnace1/furnace1.json | 24 +- tests/furnace2/furnace2.json | 10 +- tests/materials1/materials1.json | 182 +-- tests/materials3/materials3.json | 186 +-- 22 files changed, 2716 insertions(+), 1698 deletions(-) diff --git a/libs/yocto/ext/stb_image.h b/libs/yocto/ext/stb_image.h index accef4839..0f8459a79 100644 --- a/libs/yocto/ext/stb_image.h +++ b/libs/yocto/ext/stb_image.h @@ -1,4 +1,4 @@ -/* stb_image - v2.26 - public domain image loader - http://nothings.org/stb +/* stb_image - v2.27 - public domain image loader - http://nothings.org/stb no warranty implied; use at your own risk Do this: @@ -48,6 +48,7 @@ LICENSE RECENT REVISION HISTORY: + 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes 2.26 (2020-07-13) many minor fixes 2.25 (2020-02-02) fix warnings 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically @@ -89,7 +90,7 @@ RECENT REVISION HISTORY: Jeremy Sawicki (handle all ImageNet JPGs) Optimizations & bugfixes Mikhail Morozov (1-bit BMP) Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) - Arseny Kapoulkine + Arseny Kapoulkine Simon Breuss (16-bit PNM) John-Mark Allen Carmelo J Fdez-Aguera @@ -102,7 +103,7 @@ RECENT REVISION HISTORY: Thomas Ruf Ronny Chevalier github:rlyeh Janez Zemva John Bartholomew Michal Cichon github:romigrou Jonathan Blow Ken Hamada Tero Hanninen github:svdijk - Laurent Gomila Cort Stratton github:snagar + Eugene Golushkov Laurent Gomila Cort Stratton github:snagar Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex Cass Everitt Ryamond Barbiero github:grim210 Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw @@ -110,11 +111,13 @@ RECENT REVISION HISTORY: Josh Tobin Matthew Gregan github:poppolopoppo Julian Raschke Gregory Mullen Christian Floisand github:darealshinji Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 - Brad Weinberger Matvey Cherevko [reserved] + Brad Weinberger Matvey Cherevko github:mosra Luca Sas Alexander Veselov Zack Middleton [reserved] Ryan C. Gordon [reserved] [reserved] DO NOT ADD YOUR NAME HERE + Jacko Dirks + To add your name to the credits, pick a random blank space in the middle and fill it. 80% of merge conflicts on stb PRs are due to people adding their name at the end of the credits. @@ -176,6 +179,32 @@ RECENT REVISION HISTORY: // // Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. // +// To query the width, height and component count of an image without having to +// decode the full file, you can use the stbi_info family of functions: +// +// int x,y,n,ok; +// ok = stbi_info(filename, &x, &y, &n); +// // returns ok=1 and sets x, y, n if image is a supported format, +// // 0 otherwise. +// +// Note that stb_image pervasively uses ints in its public API for sizes, +// including sizes of memory buffers. This is now part of the API and thus +// hard to change without causing breakage. As a result, the various image +// loaders all have certain limits on image size; these differ somewhat +// by format but generally boil down to either just under 2GB or just under +// 1GB. When the decoded image would be larger than this, stb_image decoding +// will fail. +// +// Additionally, stb_image will reject image files that have any of their +// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, +// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, +// the only way to have an image with such dimensions load correctly +// is for it to have a rather extreme aspect ratio. Either way, the +// assumption here is that such larger images are likely to be malformed +// or malicious. If you do need to load an image with individual dimensions +// larger than that, and it still fits in the overall size limit, you can +// #define STBI_MAX_DIMENSIONS on your own to be something larger. +// // =========================================================================== // // UNICODE: @@ -281,11 +310,10 @@ RECENT REVISION HISTORY: // // iPhone PNG support: // -// By default we convert iphone-formatted PNGs back to RGB, even though -// they are internally encoded differently. You can disable this conversion -// by calling stbi_convert_iphone_png_to_rgb(0), in which case -// you will always just get the native iphone "format" through (which -// is BGR stored in RGB). +// We optionally support converting iPhone-formatted PNGs (which store +// premultiplied BGRA) back to RGB, even though they're internally encoded +// differently. To enable this conversion, call +// stbi_convert_iphone_png_to_rgb(1). // // Call stbi_set_unpremultiply_on_load(1) as well to force a divide per // pixel to remove any premultiplied alpha *only* if the image file explicitly @@ -489,6 +517,8 @@ STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); // as above, but only applies to images loaded on the thread that calls the function // this function is only available if your compiler supports thread-local variables; // calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); // ZLIB client - used by PNG, available for other purposes @@ -634,7 +664,7 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #ifdef STBI_HAS_LROTL #define stbi_lrot(x,y) _lrotl(x,y) #else - #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) #endif #if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) @@ -748,9 +778,12 @@ static int stbi__sse2_available(void) #ifdef STBI_NEON #include -// assume GCC or Clang on ARM targets +#ifdef _MSC_VER +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name +#else #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) #endif +#endif #ifndef STBI_SIMD_ALIGN #define STBI_SIMD_ALIGN(type, name) type name @@ -924,6 +957,7 @@ static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__pnm_test(stbi__context *s); static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_is16(stbi__context *s); #endif static @@ -1087,9 +1121,8 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order ri->num_channels = 0; - #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); - #endif + // test the formats with a very explicit header first (at least a FOURCC + // or distinctive magic number first) #ifndef STBI_NO_PNG if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); #endif @@ -1107,6 +1140,13 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re #ifndef STBI_NO_PIC if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); #endif + + // then the formats that can end up attempting to load with just 1 or 2 + // bytes matching expectations; these are prone to false positives, so + // try them later + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif #ifndef STBI_NO_PNM if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); #endif @@ -1262,12 +1302,12 @@ static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, in #ifndef STBI_NO_STDIO -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); #endif -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) { return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); @@ -1277,16 +1317,16 @@ STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wch static FILE *stbi__fopen(char const *filename, char const *mode) { FILE *f; -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) wchar_t wMode[64]; wchar_t wFilename[1024]; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) return 0; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) return 0; -#if _MSC_VER >= 1400 +#if defined(_MSC_VER) && _MSC_VER >= 1400 if (0 != _wfopen_s(&f, wFilename, wMode)) f = 0; #else @@ -1662,7 +1702,8 @@ static int stbi__get16le(stbi__context *s) static stbi__uint32 stbi__get32le(stbi__context *s) { stbi__uint32 z = stbi__get16le(s); - return z + (stbi__get16le(s) << 16); + z += (stbi__uint32)stbi__get16le(s) << 16; + return z; } #endif @@ -2090,13 +2131,12 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) int sgn; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); - sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) k = stbi_lrot(j->code_buffer, n); - if (n < 0 || n >= (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))) return 0; j->code_buffer = k & ~stbi__bmask[n]; k &= stbi__bmask[n]; j->code_bits -= n; - return k + (stbi__jbias[n] & ~sgn); + return k + (stbi__jbias[n] & (sgn - 1)); } // get some unsigned bits @@ -2146,7 +2186,7 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); // 0 all the ac values now so we can do it 32-bits at a time memset(data,0,64*sizeof(data[0])); @@ -2203,12 +2243,12 @@ static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__ // first scan for DC coefficient, must be first memset(data,0,64*sizeof(data[0])); // 0 all the ac values now t = stbi__jpeg_huff_decode(j, hdc); - if (t == -1) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); diff = t ? stbi__extend_receive(j, t) : 0; dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc << j->succ_low); + data[0] = (short) (dc * (1 << j->succ_low)); } else { // refinement scan for DC coefficient if (stbi__jpeg_get_bit(j)) @@ -2245,7 +2285,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ j->code_buffer <<= s; j->code_bits -= s; zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) << shift); + data[zig] = (short) ((r >> 8) * (1 << shift)); } else { int rs = stbi__jpeg_huff_decode(j, hac); if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); @@ -2263,7 +2303,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ } else { k += r; zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) << shift); + data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); } } } while (k <= j->spec_end); @@ -3782,6 +3822,10 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp else decode_n = z->s->img_n; + // nothing to do if no components requested; check this now to avoid + // accessing uninitialized coutput[0] later + if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } + // resample and color-convert { int k; @@ -3924,6 +3968,7 @@ static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int re { unsigned char* result; stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__errpuc("outofmem", "Out of memory"); STBI_NOTUSED(ri); j->s = s; stbi__setup_jpeg(j); @@ -3936,6 +3981,7 @@ static int stbi__jpeg_test(stbi__context *s) { int r; stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__err("outofmem", "Out of memory"); j->s = s; stbi__setup_jpeg(j); r = stbi__decode_jpeg_header(j, STBI__SCAN_type); @@ -3960,6 +4006,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) { int result; stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + if (!j) return stbi__err("outofmem", "Out of memory"); j->s = s; result = stbi__jpeg_info_raw(j, x, y, comp); STBI_FREE(j); @@ -3979,6 +4026,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) // fast-way is faster to check than jpeg huffman, but slow way is slower #define STBI__ZFAST_BITS 9 // accelerate all cases in default tables #define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet // zlib-style huffman encoding // (jpegs packs from left, zlib from right, so can't share code) @@ -3988,8 +4036,8 @@ typedef struct stbi__uint16 firstcode[16]; int maxcode[17]; stbi__uint16 firstsymbol[16]; - stbi_uc size[288]; - stbi__uint16 value[288]; + stbi_uc size[STBI__ZNSYMS]; + stbi__uint16 value[STBI__ZNSYMS]; } stbi__zhuffman; stbi_inline static int stbi__bitreverse16(int n) @@ -4120,7 +4168,7 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) if (s >= 16) return -1; // invalid code! // code size is s, so: b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - if (b >= sizeof (z->size)) return -1; // some data was corrupt somewhere! + if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. a->code_buffer >>= s; a->num_bits -= s; @@ -4317,7 +4365,7 @@ static int stbi__parse_zlib_header(stbi__zbuf *a) return 1; } -static const stbi_uc stbi__zdefault_length[288] = +static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = { 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, @@ -4363,7 +4411,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) } else { if (type == 1) { // use fixed code lengths - if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; } else { if (!stbi__compute_huffman_codes(a)) return 0; @@ -4759,6 +4807,7 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3 // de-interlacing final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + if (!final) return stbi__err("outofmem", "Out of memory"); for (p=0; p < 7; ++p) { int xorig[] = { 0,4,0,2,0,1,0 }; int yorig[] = { 0,0,4,0,2,0,1 }; @@ -4879,19 +4928,46 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int return 1; } -static int stbi__unpremultiply_on_load = 0; -static int stbi__de_iphone_flag = 0; +static int stbi__unpremultiply_on_load_global = 0; +static int stbi__de_iphone_flag_global = 0; STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) { - stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; } STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) { - stbi__de_iphone_flag = flag_true_if_should_convert; + stbi__de_iphone_flag_global = flag_true_if_should_convert; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global +#define stbi__de_iphone_flag stbi__de_iphone_flag_global +#else +static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; +static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; + +STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_set = 1; } +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_local = flag_true_if_should_convert; + stbi__de_iphone_flag_set = 1; +} + +#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ + ? stbi__unpremultiply_on_load_local \ + : stbi__unpremultiply_on_load_global) +#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ + ? stbi__de_iphone_flag_local \ + : stbi__de_iphone_flag_global) +#endif // STBI_THREAD_LOCAL + static void stbi__de_iphone(stbi__png *z) { stbi__context *s = z->s; @@ -5272,6 +5348,32 @@ typedef struct int extra_read; } stbi__bmp_data; +static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) +{ + // BI_BITFIELDS specifies masks explicitly, don't override + if (compress == 3) + return 1; + + if (compress == 0) { + if (info->bpp == 16) { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } else if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + // otherwise, use defaults, which is all-0 + info->mr = info->mg = info->mb = info->ma = 0; + } + return 1; + } + return 0; // error +} + static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) { int hsz; @@ -5299,6 +5401,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) if (hsz != 12) { int compress = stbi__get32le(s); if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes + if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel stbi__get32le(s); // discard sizeof stbi__get32le(s); // discard hres stbi__get32le(s); // discard vres @@ -5313,17 +5417,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) } if (info->bpp == 16 || info->bpp == 32) { if (compress == 0) { - if (info->bpp == 32) { - info->mr = 0xffu << 16; - info->mg = 0xffu << 8; - info->mb = 0xffu << 0; - info->ma = 0xffu << 24; - info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 - } else { - info->mr = 31u << 10; - info->mg = 31u << 5; - info->mb = 31u << 0; - } + stbi__bmp_set_mask_defaults(info, compress); } else if (compress == 3) { info->mr = stbi__get32le(s); info->mg = stbi__get32le(s); @@ -5338,6 +5432,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) return stbi__errpuc("bad BMP", "bad BMP"); } } else { + // V4/V5 header int i; if (hsz != 108 && hsz != 124) return stbi__errpuc("bad BMP", "bad BMP"); @@ -5345,6 +5440,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) info->mg = stbi__get32le(s); info->mb = stbi__get32le(s); info->ma = stbi__get32le(s); + if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs + stbi__bmp_set_mask_defaults(info, compress); stbi__get32le(s); // discard color space for (i=0; i < 12; ++i) stbi__get32le(s); // discard color space parameters @@ -5394,8 +5491,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req psize = (info.offset - info.extra_read - info.hsz) >> 2; } if (psize == 0) { - STBI_ASSERT(info.offset == s->callback_already_read + (int) (s->img_buffer - s->img_buffer_original)); - if (info.offset != s->callback_already_read + (s->img_buffer - s->buffer_start)) { + if (info.offset != s->callback_already_read + (s->img_buffer - s->img_buffer_original)) { return stbi__errpuc("bad offset", "Corrupt BMP"); } } @@ -6342,6 +6438,7 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c // intermediate buffer is RGBA result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + if (!result) return stbi__errpuc("outofmem", "Out of memory"); memset(result, 0xff, x*y*4); if (!stbi__pic_load_core(s,x,y,comp, result)) { @@ -6457,6 +6554,7 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) { stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!g) return stbi__err("outofmem", "Out of memory"); if (!stbi__gif_header(s, g, comp, 1)) { STBI_FREE(g); stbi__rewind( s ); @@ -6766,6 +6864,17 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i } } +static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) +{ + STBI_FREE(g->out); + STBI_FREE(g->history); + STBI_FREE(g->background); + + if (out) STBI_FREE(out); + if (delays && *delays) STBI_FREE(*delays); + return stbi__errpuc("outofmem", "Out of memory"); +} + static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { if (stbi__gif_test(s)) { @@ -6777,6 +6886,10 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int stride; int out_size = 0; int delays_size = 0; + + STBI_NOTUSED(out_size); + STBI_NOTUSED(delays_size); + memset(&g, 0, sizeof(g)); if (delays) { *delays = 0; @@ -6794,26 +6907,29 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, if (out) { void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); - if (NULL == tmp) { - STBI_FREE(g.out); - STBI_FREE(g.history); - STBI_FREE(g.background); - return stbi__errpuc("outofmem", "Out of memory"); - } + if (!tmp) + return stbi__load_gif_main_outofmem(&g, out, delays); else { out = (stbi_uc*) tmp; out_size = layers * stride; } if (delays) { - *delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + if (!new_delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + *delays = new_delays; delays_size = layers * sizeof(int); } } else { out = (stbi_uc*)stbi__malloc( layers * stride ); + if (!out) + return stbi__load_gif_main_outofmem(&g, out, delays); out_size = layers * stride; if (delays) { *delays = (int*) stbi__malloc( layers * sizeof(int) ); + if (!*delays) + return stbi__load_gif_main_outofmem(&g, out, delays); delays_size = layers * sizeof(int); } } @@ -7138,9 +7254,10 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) info.all_a = 255; p = stbi__bmp_parse_header(s, &info); - stbi__rewind( s ); - if (p == NULL) + if (p == NULL) { + stbi__rewind( s ); return 0; + } if (x) *x = s->img_x; if (y) *y = s->img_y; if (comp) { @@ -7206,8 +7323,8 @@ static int stbi__psd_is16(stbi__context *s) stbi__rewind( s ); return 0; } - (void) stbi__get32be(s); - (void) stbi__get32be(s); + STBI_NOTUSED(stbi__get32be(s)); + STBI_NOTUSED(stbi__get32be(s)); depth = stbi__get16be(s); if (depth != 16) { stbi__rewind( s ); @@ -7286,7 +7403,6 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) // Known limitations: // Does not support comments in the header section // Does not support ASCII image data (formats P2 and P3) -// Does not support 16-bit-per-channel #ifndef STBI_NO_PNM @@ -7307,7 +7423,8 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req stbi_uc *out; STBI_NOTUSED(ri); - if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); + if (ri->bits_per_channel == 0) return 0; if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); @@ -7317,12 +7434,12 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req *y = s->img_y; if (comp) *comp = s->img_n; - if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) return stbi__errpuc("too large", "PNM too large"); - out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); + out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); if (!out) return stbi__errpuc("outofmem", "Out of memory"); - stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8)); if (req_comp && req_comp != s->img_n) { out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); @@ -7398,11 +7515,19 @@ static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) stbi__pnm_skip_whitespace(s, &c); maxv = stbi__pnm_getinteger(s, &c); // read max value - - if (maxv > 255) - return stbi__err("max value > 255", "PPM image not 8-bit"); + if (maxv > 65535) + return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); + else if (maxv > 255) + return 16; else - return 1; + return 8; +} + +static int stbi__pnm_is16(stbi__context *s) +{ + if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) + return 1; + return 0; } #endif @@ -7458,6 +7583,9 @@ static int stbi__is_16_main(stbi__context *s) if (stbi__psd_is16(s)) return 1; #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_is16(s)) return 1; + #endif return 0; } diff --git a/libs/yocto/ext/stb_image_resize.h b/libs/yocto/ext/stb_image_resize.h index 42a8efb13..ef9e6fe87 100644 --- a/libs/yocto/ext/stb_image_resize.h +++ b/libs/yocto/ext/stb_image_resize.h @@ -1,4 +1,4 @@ -/* stb_image_resize - v0.96 - public domain image resizing +/* stb_image_resize - v0.97 - public domain image resizing by Jorge L Rodriguez (@VinoBS) - 2014 http://github.com/nothings/stb @@ -1064,7 +1064,11 @@ static void stbir__calculate_coefficients_upsample(stbir_filter filter, float sc total_filter += coefficient_group[i]; } - STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0); + // NOTE(fg): Not actually true in general, nor is there any reason to expect it should be. + // It would be true in exact math but is at best approximately true in floating-point math, + // and it would not make sense to try and put actual bounds on this here because it depends + // on the image aspect ratio which can get pretty extreme. + //STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0); STBIR_ASSERT(total_filter > 0.9); STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off. @@ -1089,7 +1093,7 @@ static void stbir__calculate_coefficients_downsample(stbir_filter filter, float { int i; - STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical. + STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical. contributor->n0 = out_first_pixel; contributor->n1 = out_last_pixel; @@ -1103,7 +1107,11 @@ static void stbir__calculate_coefficients_downsample(stbir_filter filter, float coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio; } - STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0); + // NOTE(fg): Not actually true in general, nor is there any reason to expect it should be. + // It would be true in exact math but is at best approximately true in floating-point math, + // and it would not make sense to try and put actual bounds on this here because it depends + // on the image aspect ratio which can get pretty extreme. + //STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0); for (i = out_last_pixel - out_first_pixel; i >= 0; i--) { @@ -1552,7 +1560,6 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float { int out_pixel_index = k * 1; float coefficient = horizontal_coefficients[coefficient_group + k - n0]; - STBIR_ASSERT(coefficient != 0); output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; } } @@ -1573,7 +1580,6 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float { int out_pixel_index = k * 2; float coefficient = horizontal_coefficients[coefficient_group + k - n0]; - STBIR_ASSERT(coefficient != 0); output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; } @@ -1595,7 +1601,6 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float { int out_pixel_index = k * 3; float coefficient = horizontal_coefficients[coefficient_group + k - n0]; - STBIR_ASSERT(coefficient != 0); output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; @@ -1618,7 +1623,6 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float { int out_pixel_index = k * 4; float coefficient = horizontal_coefficients[coefficient_group + k - n0]; - STBIR_ASSERT(coefficient != 0); output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; @@ -1643,7 +1647,6 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float int c; int out_pixel_index = k * channels; float coefficient = horizontal_coefficients[coefficient_group + k - n0]; - STBIR_ASSERT(coefficient != 0); for (c = 0; c < channels; c++) output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient; } diff --git a/libs/yocto/ext/stb_image_write.h b/libs/yocto/ext/stb_image_write.h index 95943eb60..e4b32ed1b 100644 --- a/libs/yocto/ext/stb_image_write.h +++ b/libs/yocto/ext/stb_image_write.h @@ -1,4 +1,4 @@ -/* stb_image_write - v1.15 - public domain - http://nothings.org/stb +/* stb_image_write - v1.16 - public domain - http://nothings.org/stb writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 no warranty implied; use at your own risk @@ -140,6 +140,7 @@ Ivan Tikhonov github:ignotion Adam Schackart + Andrew Kensler LICENSE @@ -166,9 +167,9 @@ LICENSE #endif #ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations -extern int stbi_write_tga_with_rle; -extern int stbi_write_png_compression_level; -extern int stbi_write_force_png_filter; +STBIWDEF int stbi_write_tga_with_rle; +STBIWDEF int stbi_write_png_compression_level; +STBIWDEF int stbi_write_force_png_filter; #endif #ifndef STBI_WRITE_NO_STDIO @@ -178,7 +179,7 @@ STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); -#ifdef STBI_WINDOWS_UTF8 +#ifdef STBIW_WINDOWS_UTF8 STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); #endif #endif @@ -285,7 +286,7 @@ static void stbi__stdio_write(void *context, void *data, int size) fwrite(data,1,size,(FILE*) context); } -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) #ifdef __cplusplus #define STBIW_EXTERN extern "C" #else @@ -296,25 +297,25 @@ STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned in STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) { - return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); } #endif static FILE *stbiw__fopen(char const *filename, char const *mode) { FILE *f; -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) wchar_t wMode[64]; wchar_t wFilename[1024]; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) return 0; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) return 0; -#if _MSC_VER >= 1400 - if (0 != _wfopen_s(&f, wFilename, wMode)) - f = 0; +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; #else f = _wfopen(wFilename, wMode); #endif @@ -397,7 +398,7 @@ static void stbiw__putc(stbi__write_context *s, unsigned char c) static void stbiw__write1(stbi__write_context *s, unsigned char a) { - if (s->buf_used + 1 > sizeof(s->buffer)) + if ((size_t)s->buf_used + 1 > sizeof(s->buffer)) stbiw__write_flush(s); s->buffer[s->buf_used++] = a; } @@ -405,7 +406,7 @@ static void stbiw__write1(stbi__write_context *s, unsigned char a) static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) { int n; - if (s->buf_used + 3 > sizeof(s->buffer)) + if ((size_t)s->buf_used + 3 > sizeof(s->buffer)) stbiw__write_flush(s); n = s->buf_used; s->buf_used = n+3; @@ -490,11 +491,22 @@ static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) { - int pad = (-x*3) & 3; - return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, - "11 4 22 4" "4 44 22 444444", - 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header - 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header + if (comp != 4) { + // write RGB bitmap + int pad = (-x*3) & 3; + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, + "11 4 22 4" "4 44 22 444444", + 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header + 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header + } else { + // RGBA bitmaps need a v4 header + // use BI_BITFIELDS mode with 32bpp and alpha mask + // (straight BI_RGB with alpha mask doesn't work in most readers) + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0, + "11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444", + 'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header + 108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header + } } STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) @@ -622,6 +634,8 @@ STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const #define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) +#ifndef STBI_WRITE_NO_STDIO + static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) { int exponent; @@ -756,7 +770,7 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; s->func(s->context, header, sizeof(header)-1); -#ifdef __STDC_WANT_SECURE_LIB__ +#ifdef __STDC_LIB_EXT1__ len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #else len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); @@ -777,7 +791,6 @@ STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, return stbi_write_hdr_core(&s, x, y, comp, (float *) data); } -#ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) { stbi__write_context s = { 0 }; @@ -968,6 +981,23 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i (void) stbiw__sbfree(hash_table[i]); STBIW_FREE(hash_table); + // store uncompressed instead if compression was worse + if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) { + stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1 + for (j = 0; j < data_len;) { + int blocklen = data_len - j; + if (blocklen > 32767) blocklen = 32767; + stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression + stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN + stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN + stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8)); + memcpy(out+stbiw__sbn(out), data+j, blocklen); + stbiw__sbn(out) += blocklen; + j += blocklen; + } + } + { // compute adler32 on input unsigned int s1=1, s2=0; @@ -1598,6 +1628,10 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const #endif // STB_IMAGE_WRITE_IMPLEMENTATION /* Revision history + 1.16 (2021-07-11) + make Deflate code emit uncompressed blocks when it would otherwise expand + support writing BMPs with alpha channel + 1.15 (2020-07-13) unknown 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels 1.13 1.12 @@ -1635,7 +1669,7 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const add HDR output fix monochrome BMP 0.95 (2014-08-17) - add monochrome TGA output + add monochrome TGA output 0.94 (2014-05-31) rename private functions to avoid conflicts with stb_image.h 0.93 (2014-05-27) diff --git a/libs/yocto_gui/ext/imgui/imgui.cpp b/libs/yocto_gui/ext/imgui/imgui.cpp index 0e401332d..d08f819c2 100644 --- a/libs/yocto_gui/ext/imgui/imgui.cpp +++ b/libs/yocto_gui/ext/imgui/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.81 +// dear imgui, v1.83 // (main code and documentation) // Help: @@ -11,15 +11,16 @@ // - FAQ http://dearimgui.org/faq // - Homepage & latest https://github.com/ocornut/imgui // - Releases & changelog https://github.com/ocornut/imgui/releases -// - Gallery https://github.com/ocornut/imgui/issues/3488 (please post your screenshots/video there!) +// - Gallery https://github.com/ocornut/imgui/issues/3793 (please post your screenshots/video there!) +// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there) // - Glossary https://github.com/ocornut/imgui/wiki/Glossary -// - Wiki https://github.com/ocornut/imgui/wiki // - Issues & support https://github.com/ocornut/imgui/issues +// - Discussions https://github.com/ocornut/imgui/discussions // Developed by Omar Cornut and every direct or indirect contributors to the GitHub. // See LICENSE.txt for copyright and licensing details (standard MIT License). // This library is free but needs your support to sustain development and maintenance. -// Businesses: you can support continued development via invoiced technical support, maintenance and sponsoring contracts. Please reach out to "contact AT dearimgui.org". +// Businesses: you can support continued development via invoiced technical support, maintenance and sponsoring contracts. Please reach out to "contact AT dearimgui.com". // Individuals: you can support continued development via donations. See docs/README or web page. // It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library. @@ -133,17 +134,17 @@ CODE 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. + - Remember to check the wonderful Wiki (https://github.com/ocornut/imgui/wiki) + - 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, fewer bugs. - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features. - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build. - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori). - You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in the FAQ. + You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in Wiki. - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances. - For every application frame your UI code will be called only once. This is in contrast to e.g. Unity's own implementation of an IMGUI, + For every application frame, your UI code will be called only once. This is in contrast to e.g. Unity's implementation of an IMGUI, where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches. - - Our origin are on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right. + - Our origin is on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right. - This codebase is also optimized to yield decent performances with typical "Debug" builds settings. - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected). If you get an assert, read the messages and comments around the assert. @@ -156,8 +157,8 @@ CODE 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 as a top-most commit which you can regularly rebase over master. + - Overwrite all the sources files except for imconfig.h (if you have modified your copy of imconfig.h) + - Or maintain your own branch where you have imconfig.h modified as a top-most commit which you can regularly rebase over "master". - You can also use '#define IMGUI_USER_CONFIG "my_config_file.h" to redirect configuration to your own file. - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes. If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed @@ -172,12 +173,12 @@ CODE - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library. - In the majority of cases you should be able to use unmodified backends files available in the backends/ folder. - Add the Dear ImGui source files + selected backend 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). + It is recommended you build and statically link the .cpp files as part of your project and NOT as a shared library (DLL). - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating Dear ImGui types with your own maths types. - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them. - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide. Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" - phases of your own application. All rendering information are stored into command-lists that you will retrieve after calling ImGui::Render(). + phases of your own application. All rendering information is stored into command-lists that you will retrieve after calling ImGui::Render(). - Refer to the backends 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. @@ -185,7 +186,7 @@ CODE HOW A SIMPLE APPLICATION MAY LOOK LIKE -------------------------------------- EXHIBIT 1: USING THE EXAMPLE BACKENDS (= imgui_impl_XXX.cpp files from the backends/ folder). - The sub-folders in examples/ contains examples applications following this structure. + The sub-folders in examples/ contain examples applications following this structure. // Application init: create a dear imgui context, setup some options, load fonts ImGui::CreateContext(); @@ -235,7 +236,7 @@ CODE unsigned char* pixels = NULL; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); - // At this point you've got the texture data and you need to upload that your your graphic system: + // At this point you've got the texture data and you need to upload that to your graphic system: // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'. // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID. MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32) @@ -254,7 +255,7 @@ CODE io.MouseDown[1] = my_mouse_buttons[1]; // Call NewFrame(), after this point you can use ImGui::* functions anytime - // (So you want to try calling NewFrame() as early as you can in your mainloop to be able to use Dear ImGui everywhere) + // (So you want to try calling NewFrame() as early as you can in your main loop to be able to use Dear ImGui everywhere) ImGui::NewFrame(); // Most of your application code here @@ -274,14 +275,14 @@ CODE // Shutdown ImGui::DestroyContext(); - To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest your application, + To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest of your application, you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! Please read the FAQ and example applications for details about this! HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE --------------------------------------------- - The backends in impl_impl_XXX.cpp files contains many working implementations of a rendering function. + The backends in impl_impl_XXX.cpp files contain many working implementations of a rendering function. void void MyImGuiRenderFunction(ImDrawData* draw_data) { @@ -303,11 +304,11 @@ CODE } else { - // The texture for the draw call is specified by pcmd->TextureId. + // The texture for the draw call is specified by pcmd->GetTexID(). // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization. - MyEngineBindTexture((MyTexture*)pcmd->TextureId); + MyEngineBindTexture((MyTexture*)pcmd->GetTexID()); - // We are using scissoring to clip some objects. All low-level graphics API should supports it. + // We are using scissoring to clip some objects. All low-level graphics API should support it. // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches // (some elements visible outside their bounds) but you can fix that once everything else works! // - Clipping coordinates are provided in imgui coordinates space: @@ -350,7 +351,7 @@ CODE Note that io.NavInputs[] is cleared by EndFrame(). - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values: 0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks. - - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone. + - We use a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone. Your code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.). - You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://dearimgui.org/controls_sheets - If you need to share inputs between your game and the imgui parts, the easiest approach is to go all-or-nothing, with a buttons combo @@ -362,7 +363,7 @@ CODE Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements. When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved. When that happens your backend NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the backends in examples/ do that. - (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, imgui will misbehave as it will see your mouse as moving back and forth!) + (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, imgui will misbehave as it will see your mouse moving back and forth!) (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want to set a boolean to ignore your other external mouse positions until the external source is moved again.) @@ -372,9 +373,31 @@ CODE Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix. Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some 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. + When you are not sure about an 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. + - 2021/05/19 (1.83) - backends: obsoleted direct access to ImDrawCmd::TextureId in favor of calling ImDrawCmd::GetTexID(). + - if you are using official backends from the source tree: you have nothing to do. + - if you have copied old backend code or using your own: change access to draw_cmd->TextureId to draw_cmd->GetTexID(). + - 2021/03/12 (1.82) - upgraded ImDrawList::AddRect(), AddRectFilled(), PathRect() to use ImDrawFlags instead of ImDrawCornersFlags. + - ImDrawCornerFlags_TopLeft -> use ImDrawFlags_RoundCornersTopLeft + - ImDrawCornerFlags_BotRight -> use ImDrawFlags_RoundCornersBottomRight + - ImDrawCornerFlags_None -> use ImDrawFlags_RoundCornersNone etc. + flags now sanely defaults to 0 instead of 0x0F, consistent with all other flags in the API. + breaking: the default with rounding > 0.0f is now "round all corners" vs old implicit "round no corners": + - rounding == 0.0f + flags == 0 --> meant no rounding --> unchanged (common use) + - rounding > 0.0f + flags != 0 --> meant rounding --> unchanged (common use) + - rounding == 0.0f + flags != 0 --> meant no rounding --> unchanged (unlikely use) + - rounding > 0.0f + flags == 0 --> meant no rounding --> BREAKING (unlikely use): will now round all corners --> use ImDrawFlags_RoundCornersNone or rounding == 0.0f. + this ONLY matters for hard coded use of 0 + rounding > 0.0f. Use of named ImDrawFlags_RoundCornersNone (new) or ImDrawCornerFlags_None (old) are ok. + the old ImDrawCornersFlags used awkward default values of ~0 or 0xF (4 lower bits set) to signify "round all corners" and we sometimes encouraged using them as shortcuts. + legacy path still support use of hard coded ~0 or any value from 0x1 or 0xF. They will behave the same with legacy paths enabled (will assert otherwise). + - 2021/03/11 (1.82) - removed redirecting functions/enums names that were marked obsolete in 1.66 (September 2018): + - ImGui::SetScrollHere() -> use ImGui::SetScrollHereY() + - 2021/03/11 (1.82) - clarified that ImDrawList::PathArcTo(), ImDrawList::PathArcToFast() won't render with radius < 0.0f. Previously it sorts of accidentally worked but would generally lead to counter-clockwise paths and have an effect on anti-aliasing. + - 2021/03/10 (1.82) - upgraded ImDrawList::AddPolyline() and PathStroke() "bool closed" parameter to "ImDrawFlags flags". The matching ImDrawFlags_Closed value is guaranteed to always stay == 1 in the future. + - 2021/02/22 (1.82) - win32+mingw: Re-enabled IME functions by default even under MinGW. In July 2016, issue #738 had me incorrectly disable those default functions for MinGW. MinGW users should: either link with -limm32, either set their imconfig file with '#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS'. + - 2021/02/17 (1.82) - renamed rarely used style.CircleSegmentMaxError (old default = 1.60f) to style.CircleTessellationMaxError (new default = 0.30f) as the meaning of the value changed. - 2021/02/03 (1.81) - renamed ListBoxHeader(const char* label, ImVec2 size) to BeginListBox(). Kept inline redirection function (will obsolete). - removed ListBoxHeader(const char* label, int items_count, int height_in_items = -1) in favor of specifying size. Kept inline redirection function (will obsolete). - renamed ListBoxFooter() to EndListBox(). Kept inline redirection function (will obsolete). @@ -404,7 +427,7 @@ CODE - 2020/09/25 (1.79) - renamed ImGuiSliderFlags_ClampOnInput to ImGuiSliderFlags_AlwaysClamp. Kept redirection enum (will obsolete sooner because previous name was added recently). - 2020/09/25 (1.79) - renamed style.TabMinWidthForUnselectedCloseButton to style.TabMinWidthForCloseButton. - 2020/09/21 (1.79) - renamed OpenPopupContextItem() back to OpenPopupOnItemClick(), reverting the change from 1.77. For varieties of reason this is more self-explanatory. - - 2020/09/21 (1.79) - removed return value from OpenPopupOnItemClick() - returned true on mouse release on item - because it is inconsistent with other popup APIs and makes others misleading. It's also and unnecessary: you can use IsWindowAppearing() after BeginPopup() for a similar result. + - 2020/09/21 (1.79) - removed return value from OpenPopupOnItemClick() - returned true on mouse release on an item - because it is inconsistent with other popup APIs and makes others misleading. It's also and unnecessary: you can use IsWindowAppearing() after BeginPopup() for a similar result. - 2020/09/17 (1.79) - removed ImFont::DisplayOffset in favor of ImFontConfig::GlyphOffset. DisplayOffset was applied after scaling and not very meaningful/useful outside of being needed by the default ProggyClean font. If you scaled this value after calling AddFontDefault(), this is now done automatically. It was also getting in the way of better font scaling, so let's get rid of it now! - 2020/08/17 (1.78) - obsoleted use of the trailing 'float power=1.0f' parameter for DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN(), VSliderFloat() and VSliderScalar(). replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags). @@ -413,7 +436,7 @@ CODE - if you set the 'power' parameter to 1.0f (same as previous default value): 1/ your compiler may warn on float>int conversion, 2/ everything else will work. 3/ you can replace the 1.0f value with 0 to fix the warning, and be technically correct. - if you set the 'power' parameter to >1.0f (to enable non-linear editing): 1/ your compiler may warn on float>int conversion, 2/ code will assert at runtime, 3/ in case asserts are disabled, the code will not crash and enable the _Logarithmic flag. 4/ you can replace the >1.0f value with ImGuiSliderFlags_Logarithmic to fix the warning/assert and get a _similar_ effect as previous uses of power >1.0f. see https://github.com/ocornut/imgui/issues/3361 for all details. - kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version were removed directly as they were most unlikely ever used. + kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version was removed directly as they were most unlikely ever used. for shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`. - obsoleted use of v_min > v_max in DragInt, DragFloat, DragScalar to lock edits (introduced in 1.73, was not demoed nor documented very), will be replaced by a more generic ReadOnly feature. You may use the ImGuiSliderFlags_ReadOnly internal flag in the meantime. - 2020/06/23 (1.77) - removed BeginPopupContextWindow(const char*, int mouse_button, bool also_over_items) in favor of BeginPopupContextWindow(const char*, ImGuiPopupFlags flags) with ImGuiPopupFlags_NoOverItems. @@ -433,7 +456,7 @@ CODE - ImGuiStyleVar_ChildWindowRounding -> use ImGuiStyleVar_ChildRounding - ImGuiTreeNodeFlags_AllowOverlapMode -> use ImGuiTreeNodeFlags_AllowItemOverlap - IMGUI_DISABLE_TEST_WINDOWS -> use IMGUI_DISABLE_DEMO_WINDOWS - - 2019/12/08 (1.75) - obsoleted calling ImDrawList::PrimReserve() with a negative count (which was the vaguely documented and rarely if ever used). Instead we added an explicit PrimUnreserve() API. + - 2019/12/08 (1.75) - obsoleted calling ImDrawList::PrimReserve() with a negative count (which was vaguely documented and rarely if ever used). Instead, we added an explicit PrimUnreserve() API. - 2019/12/06 (1.75) - removed implicit default parameter to IsMouseDragging(int button = 0) to be consistent with other mouse functions (none of the other functions have it). - 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. @@ -461,7 +484,7 @@ CODE - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete). - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete). - 2019/02/26 (1.69) - renamed ImGuiColorEditFlags_RGB/ImGuiColorEditFlags_HSV/ImGuiColorEditFlags_HEX to ImGuiColorEditFlags_DisplayRGB/ImGuiColorEditFlags_DisplayHSV/ImGuiColorEditFlags_DisplayHex. Kept redirection enums (will obsolete). - - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with an arbitrary small value! + - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with an arbitrarily small value! - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already). - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete). @@ -556,12 +579,12 @@ CODE - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset. - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity. - - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() and use it instead of passing string to BeginChild(). + - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetID() and use it instead of passing string to BeginChild(). - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it. - 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/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, 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. + 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 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 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. @@ -569,7 +592,7 @@ CODE - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection. - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen). - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDrawList::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer. - - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref github issue #337). + - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref GitHub issue #337). - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337) - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert. @@ -600,7 +623,7 @@ CODE - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete). - 2015/07/02 (1.42) - renamed GetScrollPosY() to GetScrollY(). Necessary to reduce confusion along with other scrolling functions, because positions (e.g. cursor position) are not equivalent to scrolling amount. - 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence - - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely be used. Sorry! + - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely used. Sorry! - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete). - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons. @@ -655,7 +678,7 @@ CODE =========== Q: Where is the documentation? - A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++. + A: This library is poorly documented at the moment and expects the user to be acquainted with C/C++. - Run the examples/ and explore them. - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. - The demo covers most features of Dear ImGui, so you can read the code and see its output. @@ -665,7 +688,7 @@ CODE - The Wiki (https://github.com/ocornut/imgui/wiki) has many resources and links. - The Glossary (https://github.com/ocornut/imgui/wiki/Glossary) page also may be useful. - Your programming IDE is your friend, find the type or function declaration to find comments - associated to it. + associated with it. Q: What is this library called? Q: Which version should I get? @@ -678,15 +701,15 @@ CODE Q: How to get started? A: Read 'PROGRAMMER GUIDE' above. Read examples/README.txt. - Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or to my application? + Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application? A: You should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! - >> See https://www.dearimgui.org/faq for fully detailed answer. You really want to read this. + >> See https://www.dearimgui.org/faq for a fully detailed answer. You really want to read this. Q. How can I enable keyboard controls? Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display) - Q: I integrated Dear ImGui in my engine and little squares are showing instead of text.. - Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. - Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries.. + Q: I integrated Dear ImGui in my engine and little squares are showing instead of text... + Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around... + Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries... >> See https://www.dearimgui.org/faq Q&A: Usage @@ -724,16 +747,16 @@ CODE ============== Q: How can I help? - A: - Businesses: please reach out to "contact AT dearimgui.org" if you work in a place using Dear ImGui! + A: - Businesses: please reach out to "contact AT dearimgui.com" if you work in a place using Dear ImGui! We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts. - This is among the most useful thing you can do for Dear ImGui. With increased funding we can hire more people working on this project. + This is among the most useful thing you can do for Dear ImGui. With increased funding, we can hire more people working on this project. - Individuals: you can support continued development via PayPal donations. See README. - - If you are experienced with Dear ImGui and C++, look at the github issues, look at the Wiki, read docs/TODO.txt + - If you are experienced with Dear ImGui and C++, look at the GitHub issues, look at the Wiki, read docs/TODO.txt and see how you want to help and can help! - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc. - You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/3488). Visuals are ideal as they inspire other programmers. - But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions. - - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on github or privately). + You may post screenshot or links in the gallery threads. Visuals are ideal as they inspire other programmers. + But even without visuals, disclosing your use of dear imgui helps the library grow credibility, and help other teams and programmers with taking decisions. + - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on GitHub or privately). */ @@ -796,6 +819,9 @@ CODE #if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later #pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types #endif +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6). +#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). #endif // Clang/GCC warnings with -Weverything @@ -838,7 +864,7 @@ static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear // Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by backend) -static const float WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS = 4.0f; // Extend outside and inside windows. Affect FindHoveredWindow(). +static const float WINDOWS_HOVER_PADDING = 4.0f; // Extend outside window for hovering/resizing (maxxed with TouchPadding) and inside windows for borders. Affect FindHoveredWindow(). static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time. static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 2.00f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved. @@ -877,12 +903,13 @@ static void NavUpdateInitResult(); static float NavUpdatePageUpPageDown(); static inline void NavUpdateAnyRequestFlag(); static void NavEndFrame(); -static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand); -static void NavApplyItemToResult(ImGuiNavMoveResult* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel); +static bool NavScoreItem(ImGuiNavItemData* result, ImRect cand); +static void NavApplyItemToResult(ImGuiNavItemData* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel); static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id); static ImVec2 NavCalcPreferredRefPos(); static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window); static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); +static void NavRestoreLayer(ImGuiNavLayer layer); static int FindWindowFocusIndex(ImGuiWindow* window); // Error Checking @@ -909,27 +936,33 @@ static void UpdateViewportsNewFrame(); // [SECTION] CONTEXT AND MEMORY ALLOCATORS //----------------------------------------------------------------------------- +// DLL users: +// - Heaps and globals are not shared across DLL boundaries! +// - You will need to call SetCurrentContext() + SetAllocatorFunctions() for each static/DLL boundary you are calling from. +// - Same applies for hot-reloading mechanisms that are reliant on reloading DLL (note that many hot-reloading mechanisms work without DLL). +// - Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. +// - Confused? In a debugger: add GImGui to your watch window and notice how its value changes depending on your current location (which DLL boundary you are in). + // Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL. -// ImGui::CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext(). -// 1) Important: globals are not shared across DLL boundaries! If you use DLLs or any form of hot-reloading: you will need to call -// SetCurrentContext() (with the pointer you got from CreateContext) from each unique static/DLL boundary, and after each hot-reloading. -// In your debugger, add GImGui to your watch window and notice how its value changes depending on which location you are currently stepping into. -// 2) Important: Dear ImGui functions are not thread-safe because of this pointer. -// If you want thread-safety to allow N threads to access N different contexts, you can: -// - Change this variable to use thread local storage so each thread can refer to a different context, in imconfig.h: -// struct ImGuiContext; -// extern thread_local ImGuiContext* MyImGuiTLS; -// #define GImGui MyImGuiTLS -// And then define MyImGuiTLS in one of your cpp file. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword. -// - Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586 -// - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from different namespace. +// - ImGui::CreateContext() will automatically set this pointer if it is NULL. +// Change to a different context by calling ImGui::SetCurrentContext(). +// - Important: Dear ImGui functions are not thread-safe because of this pointer. +// If you want thread-safety to allow N threads to access N different contexts: +// - Change this variable to use thread local storage so each thread can refer to a different context, in your imconfig.h: +// struct ImGuiContext; +// extern thread_local ImGuiContext* MyImGuiTLS; +// #define GImGui MyImGuiTLS +// And then define MyImGuiTLS in one of your cpp files. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword. +// - Future development aims to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586 +// - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from a different namespace. +// - DLL users: read comments above. #ifndef GImGui ImGuiContext* GImGui = NULL; #endif // Memory Allocator functions. Use SetAllocatorFunctions() to change them. -// If you use DLL hotreloading you might need to call SetAllocatorFunctions() after reloading code from this file. -// Otherwise, you probably don't want to modify them mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction. +// - You probably don't want to modify that mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction. +// - DLL users: read comments above. #ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); } static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); free(ptr); } @@ -937,10 +970,9 @@ static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_d static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; } static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); } #endif - -static void* (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper; -static void (*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper; -static void* GImAllocatorUserData = NULL; +static ImGuiMemAllocFunc GImAllocatorAllocFunc = MallocWrapper; +static ImGuiMemFreeFunc GImAllocatorFreeFunc = FreeWrapper; +static void* GImAllocatorUserData = NULL; //----------------------------------------------------------------------------- // [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) @@ -986,7 +1018,7 @@ ImGuiStyle::ImGuiStyle() AntiAliasedLinesUseTex = true; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering. AntiAliasedFill = true; // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.). CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. - CircleSegmentMaxError = 1.60f; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. + CircleTessellationMaxError = 0.30f; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. // Default theme ImGui::StyleColorsDark(this); @@ -1107,11 +1139,18 @@ void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c) if (InputQueueSurrogate != 0) { if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate + { InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID); - else if (IM_UNICODE_CODEPOINT_MAX == (0xFFFF)) // Codepoint will not fit in ImWchar (extra parenthesis around 0xFFFF somehow fixes -Wunreachable-code with Clang) - cp = IM_UNICODE_CODEPOINT_INVALID; + } else + { +#if IM_UNICODE_CODEPOINT_MAX == 0xFFFF + cp = IM_UNICODE_CODEPOINT_INVALID; // Codepoint will not fit in ImWchar +#else cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000); +#endif + } + InputQueueSurrogate = 0; } InputQueueCharacters.push_back(cp); @@ -2800,8 +2839,8 @@ void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, const float border_size = g.Style.FrameBorderSize; if (border && border_size > 0.0f) { - window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); - window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); + window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size); + window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size); } } @@ -2812,8 +2851,8 @@ void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding) const float border_size = g.Style.FrameBorderSize; if (border_size > 0.0f) { - window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); - window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); + window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size); + window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size); } } @@ -2839,13 +2878,13 @@ void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFl bool fully_visible = window->ClipRect.Contains(display_rect); if (!fully_visible) window->DrawList->PushClipRect(display_rect.Min, display_rect.Max); - window->DrawList->AddRect(display_rect.Min + ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), display_rect.Max - ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), GetColorU32(ImGuiCol_NavHighlight), rounding, ImDrawCornerFlags_All, THICKNESS); + window->DrawList->AddRect(display_rect.Min + ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), display_rect.Max - ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), GetColorU32(ImGuiCol_NavHighlight), rounding, 0, THICKNESS); if (!fully_visible) window->DrawList->PopClipRect(); } if (flags & ImGuiNavHighlightFlags_TypeThin) { - window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, ~0, 1.0f); + window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, 0, 1.0f); } } @@ -3016,6 +3055,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) g.ActiveIdTimer = 0.0f; g.ActiveIdHasBeenPressedBefore = false; g.ActiveIdHasBeenEditedBefore = false; + g.ActiveIdMouseButton = -1; if (id != 0) { g.LastActiveId = id; @@ -3114,20 +3154,22 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) return IsItemFocused(); // Test for bounding box overlap, as updated as ItemAdd() - if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect)) + ImGuiItemStatusFlags status_flags = window->DC.LastItemStatusFlags; + if (!(status_flags & ImGuiItemStatusFlags_HoveredRect)) return false; IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0); // Flags not supported by this function // Test if we are hovering the right window (our window could be behind another window) - // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable to use IsItemHovered() after EndChild() itself. - // Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was the test that has been running for a long while. - //if (g.HoveredWindow != window) - // return false; - if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped)) - return false; + // [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851) + // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable + // to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was + // the test that has been running for a long while. + if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0) + if ((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0) + return false; // Test if another item is active (e.g. being dragged) - if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0) if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) return false; @@ -3137,7 +3179,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) return false; // Test if the item is disabled - if ((window->DC.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) + if ((g.CurrentItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) return false; // Special handling for calling after Begin() which represent the title bar or tab. @@ -3163,7 +3205,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) return false; if (g.NavDisableMouseHover) return false; - if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None) || (window->DC.ItemFlags & ImGuiItemFlags_Disabled)) + if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None) || (g.CurrentItemFlags & ImGuiItemFlags_Disabled)) { g.HoveredIdDisabled = true; return false; @@ -3210,47 +3252,49 @@ void ImGui::SetLastItemData(ImGuiWindow* window, ImGuiID item_id, ImGuiItemStatu } // Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out. -bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id) +void ImGui::ItemFocusable(ImGuiWindow* window, ImGuiID id) { ImGuiContext& g = *GImGui; + IM_ASSERT(id != 0 && id == window->DC.LastItemId); // Increment counters - const bool is_tab_stop = (window->DC.ItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0; + // FIXME: ImGuiItemFlags_Disabled should disable more. + const bool is_tab_stop = (g.CurrentItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0; window->DC.FocusCounterRegular++; if (is_tab_stop) + { window->DC.FocusCounterTabStop++; + if (g.NavId == id) + g.NavIdTabCounter = window->DC.FocusCounterTabStop; + } // Process TAB/Shift-TAB to tab *OUT* of the currently focused item. // (Note that we can always TAB out of a widget that doesn't allow tabbing in) - if (g.ActiveId == id && g.FocusTabPressed && !IsActiveIdUsingKey(ImGuiKey_Tab) && g.FocusRequestNextWindow == NULL) + if (g.ActiveId == id && g.TabFocusPressed && !IsActiveIdUsingKey(ImGuiKey_Tab) && g.TabFocusRequestNextWindow == NULL) { - g.FocusRequestNextWindow = window; - g.FocusRequestNextCounterTabStop = window->DC.FocusCounterTabStop + (g.IO.KeyShift ? (is_tab_stop ? -1 : 0) : +1); // Modulo on index will be applied at the end of frame once we've got the total counter of items. + g.TabFocusRequestNextWindow = window; + g.TabFocusRequestNextCounterTabStop = window->DC.FocusCounterTabStop + (g.IO.KeyShift ? (is_tab_stop ? -1 : 0) : +1); // Modulo on index will be applied at the end of frame once we've got the total counter of items. } // Handle focus requests - if (g.FocusRequestCurrWindow == window) + if (g.TabFocusRequestCurrWindow == window) { - if (window->DC.FocusCounterRegular == g.FocusRequestCurrCounterRegular) - return true; - if (is_tab_stop && window->DC.FocusCounterTabStop == g.FocusRequestCurrCounterTabStop) + if (window->DC.FocusCounterRegular == g.TabFocusRequestCurrCounterRegular) + { + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_FocusedByCode; + return; + } + if (is_tab_stop && window->DC.FocusCounterTabStop == g.TabFocusRequestCurrCounterTabStop) { g.NavJustTabbedId = id; - return true; + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_FocusedByTabbing; + return; } // If another item is about to be focused, we clear our own active id if (g.ActiveId == id) ClearActiveID(); } - - return false; -} - -void ImGui::FocusableItemUnregister(ImGuiWindow* window) -{ - window->DC.FocusCounterRegular--; - window->DC.FocusCounterTabStop--; } float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) @@ -3282,7 +3326,7 @@ void* ImGui::MemAlloc(size_t size) { if (ImGuiContext* ctx = GImGui) ctx->IO.MetricsActiveAllocations++; - return GImAllocatorAllocFunc(size, GImAllocatorUserData); + return (*GImAllocatorAllocFunc)(size, GImAllocatorUserData); } // IM_FREE() == ImGui::MemFree() @@ -3291,7 +3335,7 @@ void ImGui::MemFree(void* ptr) if (ptr) if (ImGuiContext* ctx = GImGui) ctx->IO.MetricsActiveAllocations--; - return GImAllocatorFreeFunc(ptr, GImAllocatorUserData); + return (*GImAllocatorFreeFunc)(ptr, GImAllocatorUserData); } const char* ImGui::GetClipboardText() @@ -3328,13 +3372,21 @@ void ImGui::SetCurrentContext(ImGuiContext* ctx) #endif } -void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data) +void ImGui::SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void* user_data) { GImAllocatorAllocFunc = alloc_func; GImAllocatorFreeFunc = free_func; GImAllocatorUserData = user_data; } +// This is provided to facilitate copying allocators from one static/DLL boundary to another (e.g. retrieve default allocator of your executable address space) +void ImGui::GetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func, ImGuiMemFreeFunc* p_free_func, void** p_user_data) +{ + *p_alloc_func = GImAllocatorAllocFunc; + *p_free_func = GImAllocatorFreeFunc; + *p_user_data = GImAllocatorUserData; +} + ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas) { ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas); @@ -3539,7 +3591,7 @@ void ImGui::UpdateMouseMovingWindowEndFrame() { // Handle the edge case of a popup being closed while clicking in its empty space. // If we try to focus it, FocusWindow() > ClosePopupsOverWindow() will accidentally close any parent popups because they are not linked together any more. - ImGuiWindow* root_window = g.HoveredRootWindow; + ImGuiWindow* root_window = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL; const bool is_closed_popup = root_window && (root_window->Flags & ImGuiWindowFlags_Popup) && !IsPopupOpen(root_window->PopupId, ImGuiPopupFlags_AnyPopupLevel); if (root_window != NULL && !is_closed_popup) @@ -3682,7 +3734,7 @@ void ImGui::UpdateMouseWheel() const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f); const float scale = new_font_scale / window->FontWindowScale; window->FontWindowScale = new_font_scale; - if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) + if (window == window->RootWindow) { const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size; SetWindowPos(window, window->Pos + offset, 0); @@ -3694,10 +3746,17 @@ void ImGui::UpdateMouseWheel() // Mouse wheel scrolling // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent + if (g.IO.KeyCtrl) + return; + + // As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead + // (we avoid doing it on OSX as it the OS input layer handles this already) + const bool swap_axis = g.IO.KeyShift && !g.IO.ConfigMacOSXBehaviors; + const float wheel_y = swap_axis ? 0.0f : g.IO.MouseWheel; + const float wheel_x = swap_axis ? g.IO.MouseWheel : g.IO.MouseWheelH; // Vertical Mouse Wheel scrolling - const float wheel_y = (g.IO.MouseWheel != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f; - if (wheel_y != 0.0f && !g.IO.KeyCtrl) + if (wheel_y != 0.0f) { StartLockWheelingWindow(window); while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) @@ -3711,8 +3770,7 @@ void ImGui::UpdateMouseWheel() } // Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held - const float wheel_x = (g.IO.MouseWheelH != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheelH : (g.IO.MouseWheel != 0.0f && g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f; - if (wheel_x != 0.0f && !g.IO.KeyCtrl) + if (wheel_x != 0.0f) { StartLockWheelingWindow(window); while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) @@ -3731,32 +3789,34 @@ void ImGui::UpdateTabFocus() ImGuiContext& g = *GImGui; // Pressing TAB activate widget focus - g.FocusTabPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab)); - if (g.ActiveId == 0 && g.FocusTabPressed) - { - // Note that SetKeyboardFocusHere() sets the Next fields mid-frame. To be consistent we also - // manipulate the Next fields even, even though they will be turned into Curr fields by the code below. - g.FocusRequestNextWindow = g.NavWindow; - g.FocusRequestNextCounterRegular = INT_MAX; + g.TabFocusPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab)); + if (g.ActiveId == 0 && g.TabFocusPressed) + { + // - This path is only taken when no widget are active/tabbed-into yet. + // Subsequent tabbing will be processed by FocusableItemRegister() + // - Note that SetKeyboardFocusHere() sets the Next fields mid-frame. To be consistent we also + // manipulate the Next fields here even though they will be turned into Curr fields below. + g.TabFocusRequestNextWindow = g.NavWindow; + g.TabFocusRequestNextCounterRegular = INT_MAX; if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX) - g.FocusRequestNextCounterTabStop = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1); + g.TabFocusRequestNextCounterTabStop = g.NavIdTabCounter + (g.IO.KeyShift ? -1 : 0); else - g.FocusRequestNextCounterTabStop = g.IO.KeyShift ? -1 : 0; + g.TabFocusRequestNextCounterTabStop = g.IO.KeyShift ? -1 : 0; } // Turn queued focus request into current one - g.FocusRequestCurrWindow = NULL; - g.FocusRequestCurrCounterRegular = g.FocusRequestCurrCounterTabStop = INT_MAX; - if (g.FocusRequestNextWindow != NULL) + g.TabFocusRequestCurrWindow = NULL; + g.TabFocusRequestCurrCounterRegular = g.TabFocusRequestCurrCounterTabStop = INT_MAX; + if (g.TabFocusRequestNextWindow != NULL) { - ImGuiWindow* window = g.FocusRequestNextWindow; - g.FocusRequestCurrWindow = window; - if (g.FocusRequestNextCounterRegular != INT_MAX && window->DC.FocusCounterRegular != -1) - g.FocusRequestCurrCounterRegular = ImModPositive(g.FocusRequestNextCounterRegular, window->DC.FocusCounterRegular + 1); - if (g.FocusRequestNextCounterTabStop != INT_MAX && window->DC.FocusCounterTabStop != -1) - g.FocusRequestCurrCounterTabStop = ImModPositive(g.FocusRequestNextCounterTabStop, window->DC.FocusCounterTabStop + 1); - g.FocusRequestNextWindow = NULL; - g.FocusRequestNextCounterRegular = g.FocusRequestNextCounterTabStop = INT_MAX; + ImGuiWindow* window = g.TabFocusRequestNextWindow; + g.TabFocusRequestCurrWindow = window; + if (g.TabFocusRequestNextCounterRegular != INT_MAX && window->DC.FocusCounterRegular != -1) + g.TabFocusRequestCurrCounterRegular = ImModPositive(g.TabFocusRequestNextCounterRegular, window->DC.FocusCounterRegular + 1); + if (g.TabFocusRequestNextCounterTabStop != INT_MAX && window->DC.FocusCounterTabStop != -1) + g.TabFocusRequestCurrCounterTabStop = ImModPositive(g.TabFocusRequestNextCounterTabStop, window->DC.FocusCounterTabStop + 1); + g.TabFocusRequestNextWindow = NULL; + g.TabFocusRequestNextCounterRegular = g.TabFocusRequestNextCounterTabStop = INT_MAX; } g.NavIdTabCounter = INT_MAX; @@ -3766,6 +3826,7 @@ void ImGui::UpdateTabFocus() void ImGui::UpdateHoveredWindowAndCaptureFlags() { ImGuiContext& g = *GImGui; + g.WindowsHoverPadding = ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_HOVER_PADDING, WINDOWS_HOVER_PADDING)); // Find the window hovered by mouse: // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow. @@ -3776,7 +3837,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags() // Modal windows prevents mouse from hovering behind them. ImGuiWindow* modal_window = GetTopMostPopupModal(); - if (modal_window && g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window)) + if (modal_window && g.HoveredWindow && !IsWindowChildOf(g.HoveredWindow->RootWindow, modal_window)) clear_hovered_windows = true; // Disabled mouse? @@ -3804,7 +3865,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags() clear_hovered_windows = true; if (clear_hovered_windows) - g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL; + g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL; // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to Dear ImGui + app) if (g.WantCaptureMouseNextFrame != -1) @@ -3839,7 +3900,7 @@ void ImGui::NewFrame() { IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); ImGuiContext& g = *GImGui; - + // Remove pending delete hooks before frame start. // This deferred removal avoid issues of removal while iterating the hook vector for (int n = g.Hooks.Size - 1; n >= 0; n--) @@ -3865,7 +3926,8 @@ void ImGui::NewFrame() g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx]; g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime; g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame); - g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX; + g.FramerateSecPerFrameCount = ImMin(g.FramerateSecPerFrameCount + 1, IM_ARRAYSIZE(g.FramerateSecPerFrame)); + g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)g.FramerateSecPerFrameCount)) : FLT_MAX; UpdateViewportsNewFrame(); @@ -3878,7 +3940,7 @@ void ImGui::NewFrame() virtual_space.Add(g.Viewports[n]->GetMainRect()); g.DrawListSharedData.ClipRectFullscreen = virtual_space.ToVec4(); g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol; - g.DrawListSharedData.SetCircleSegmentMaxError(g.Style.CircleSegmentMaxError); + g.DrawListSharedData.SetCircleTessellationMaxError(g.Style.CircleTessellationMaxError); g.DrawListSharedData.InitialFlags = ImDrawListFlags_None; if (g.Style.AntiAliasedLines) g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines; @@ -3983,7 +4045,7 @@ void ImGui::NewFrame() UpdateTabFocus(); // Mark all windows as not visible and compact unused memory. - IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size); + IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size); const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer; for (int i = 0; i != g.Windows.Size; i++) { @@ -4002,6 +4064,9 @@ void ImGui::NewFrame() for (int i = 0; i < g.TablesLastTimeActive.Size; i++) if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time) TableGcCompactTransientBuffers(g.Tables.GetByIndex(i)); + for (int i = 0; i < g.TablesTempDataStack.Size; i++) + if (g.TablesTempDataStack[i].LastTimeActive >= 0.0f && g.TablesTempDataStack[i].LastTimeActive < memory_compact_start_time) + TableGcCompactTransientBuffers(&g.TablesTempDataStack[i]); if (g.GcCompactAll) GcCompactTransientMiscBuffers(); g.GcCompactAll = false; @@ -4015,7 +4080,7 @@ void ImGui::NewFrame() g.CurrentWindowStack.resize(0); g.BeginPopupStack.resize(0); g.ItemFlagsStack.resize(0); - g.ItemFlagsStack.push_back(ImGuiItemFlags_Default_); + g.ItemFlagsStack.push_back(ImGuiItemFlags_None); g.GroupStack.resize(0); ClosePopupsOverWindow(g.NavWindow, false); @@ -4041,20 +4106,20 @@ void ImGui::UpdateDebugToolItemPicker() if (g.DebugItemPickerActive) { const ImGuiID hovered_id = g.HoveredIdPreviousFrame; - ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); - if (ImGui::IsKeyPressedMap(ImGuiKey_Escape)) + SetMouseCursor(ImGuiMouseCursor_Hand); + if (IsKeyPressedMap(ImGuiKey_Escape)) g.DebugItemPickerActive = false; - if (ImGui::IsMouseClicked(0) && hovered_id) + if (IsMouseClicked(0) && hovered_id) { g.DebugItemPickerBreakId = hovered_id; g.DebugItemPickerActive = false; } - ImGui::SetNextWindowBgAlpha(0.60f); - ImGui::BeginTooltip(); - ImGui::Text("HoveredId: 0x%08X", hovered_id); - ImGui::Text("Press ESC to abort picking."); - ImGui::TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!"); - ImGui::EndTooltip(); + SetNextWindowBgAlpha(0.60f); + BeginTooltip(); + Text("HoveredId: 0x%08X", hovered_id); + Text("Press ESC to abort picking."); + TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!"); + EndTooltip(); } } @@ -4076,10 +4141,8 @@ void ImGui::Initialize(ImGuiContext* context) g.SettingsHandlers.push_back(ini_handler); } -#ifdef IMGUI_HAS_TABLE // Add .ini handle for ImGuiTable type TableSettingsInstallHandler(context); -#endif // #ifdef IMGUI_HAS_TABLE // Create default viewport ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)(); @@ -4128,7 +4191,7 @@ void ImGui::Shutdown(ImGuiContext* context) g.CurrentWindowStack.clear(); g.WindowsById.Clear(); g.NavWindow = NULL; - g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL; + g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL; g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL; g.MovingWindow = NULL; g.ColorStack.clear(); @@ -4146,7 +4209,9 @@ void ImGui::Shutdown(ImGuiContext* context) g.ShrinkWidthBuffer.clear(); g.Tables.Clear(); - g.CurrentTableStack.clear(); + for (int i = 0; i < g.TablesTempDataStack.Size; i++) + g.TablesTempDataStack[i].~ImGuiTableTempData(); + g.TablesTempDataStack.clear(); g.DrawChannelsTempMergeBuffer.clear(); g.ClipboardHandlerData.clear(); @@ -4422,6 +4487,7 @@ void ImGui::Render() for (int n = 0; n != g.Windows.Size; n++) { ImGuiWindow* window = g.Windows[n]; + IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'" if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1]) AddRootWindowToDrawData(window); } @@ -4495,10 +4561,11 @@ static void FindHoveredWindow() hovered_window = g.MovingWindow; ImVec2 padding_regular = g.Style.TouchExtraPadding; - ImVec2 padding_for_resize_from_edges = g.IO.ConfigWindowsResizeFromEdges ? ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS)) : padding_regular; + ImVec2 padding_for_resize = g.IO.ConfigWindowsResizeFromEdges ? g.WindowsHoverPadding : padding_regular; for (int i = g.Windows.Size - 1; i >= 0; i--) { ImGuiWindow* window = g.Windows[i]; + IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer. if (!window->Active || window->Hidden) continue; if (window->Flags & ImGuiWindowFlags_NoMouseInputs) @@ -4509,7 +4576,7 @@ static void FindHoveredWindow() if (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) bb.Expand(padding_regular); else - bb.Expand(padding_for_resize_from_edges); + bb.Expand(padding_for_resize); if (!bb.Contains(g.IO.MousePos)) continue; @@ -4525,6 +4592,7 @@ static void FindHoveredWindow() if (hovered_window == NULL) hovered_window = window; + IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer. if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindow != g.MovingWindow->RootWindow)) hovered_window_ignoring_moving_window = window; if (hovered_window && hovered_window_ignoring_moving_window) @@ -4532,7 +4600,6 @@ static void FindHoveredWindow() } g.HoveredWindow = hovered_window; - g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL; g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window; } @@ -4810,6 +4877,8 @@ bool ImGui::IsItemFocused() return true; } +// Important: this can be useful but it is NOT equivalent to the behavior of e.g.Button()! +// Most widgets have specific reactions based on mouse-up/down state, mouse position etc. bool ImGui::IsItemClicked(ImGuiMouseButton mouse_button) { return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None); @@ -4937,7 +5006,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, b parent_window->DC.CursorPos = child_window->Pos; // Process navigation-in immediately so NavInit can run on first frame - if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll)) + if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavHasScroll)) { FocusWindow(child_window); NavInitWindow(child_window, false); @@ -4984,13 +5053,13 @@ void ImGui::EndChild() ImGuiWindow* parent_window = g.CurrentWindow; ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz); ItemSize(sz); - if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened)) + if ((window->DC.NavLayersActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened)) { ItemAdd(bb, window->ChildId); RenderNavHighlight(bb, window->ChildId); // When browsing a window that has no activable items (scroll only) we keep a highlight on the child - if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow) + if (window->DC.NavLayersActiveMask == 0 && window == g.NavWindow) RenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_TypeThin); } else @@ -4998,6 +5067,8 @@ void ImGui::EndChild() // Not navigable into ItemAdd(bb, 0); } + if (g.HoveredWindow == window) + parent_window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredWindow; } g.WithinEndChild = false; g.LogLinePosY = -FLT_MAX; // To enforce a carriage return @@ -5089,7 +5160,12 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0); } - g.WindowsFocusOrder.push_back(window); + if (!(flags & ImGuiWindowFlags_ChildWindow)) + { + g.WindowsFocusOrder.push_back(window); + window->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1); + } + if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus) g.Windows.push_front(window); // Quite slow but rare and only once else @@ -5097,9 +5173,10 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) return window; } -static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size) +static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, const ImVec2& size_desired) { ImGuiContext& g = *GImGui; + ImVec2 new_size = size_desired; if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) { // Using -1,-1 on either X/Y axis to preserve the current size. @@ -5124,8 +5201,9 @@ static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize))) { ImGuiWindow* window_for_height = window; + const float decoration_up_height = window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight(); new_size = ImMax(new_size, g.Style.WindowMinSize); - new_size.y = ImMax(new_size.y, window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows + new_size.y = ImMax(new_size.y, decoration_up_height + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows } return new_size; } @@ -5154,9 +5232,9 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont { ImGuiContext& g = *GImGui; ImGuiStyle& style = g.Style; - ImVec2 size_decorations = ImVec2(0.0f, window->TitleBarHeight() + window->MenuBarHeight()); + const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); ImVec2 size_pad = window->WindowPadding * 2.0f; - ImVec2 size_desired = size_contents + size_pad + size_decorations; + ImVec2 size_desired = size_contents + size_pad + ImVec2(0.0f, decoration_up_height); if (window->Flags & ImGuiWindowFlags_Tooltip) { // Tooltip always resize @@ -5178,8 +5256,8 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont // When the window cannot fit all contents (either because of constraints, either because screen is too small), // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding. ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit); - bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - size_decorations.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar); - bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - size_decorations.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar); + bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - 0.0f < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar); + bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - decoration_up_height < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar); if (will_have_scrollbar_x) size_auto_fit.y += style.ScrollbarSize; if (will_have_scrollbar_y) @@ -5221,53 +5299,64 @@ static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& co *out_size = size_constrained; } +// Data for resizing from corner struct ImGuiResizeGripDef { ImVec2 CornerPosN; ImVec2 InnerDir; int AngleMin12, AngleMax12; }; - 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 (Unused) - { ImVec2(1, 0), ImVec2(-1, +1), 9, 12 }, // Upper-right (Unused) + { 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) }; +// Data for resizing from borders struct ImGuiResizeBorderDef { ImVec2 InnerDir; - ImVec2 CornerPosN1, CornerPosN2; + ImVec2 SegmentN1, SegmentN2; float OuterAngle; }; - static const ImGuiResizeBorderDef resize_border_def[4] = { - { ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f }, // Top + { ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f }, // Left { ImVec2(-1, 0), ImVec2(1, 0), ImVec2(1, 1), IM_PI * 0.00f }, // Right - { ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f }, // Bottom - { ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f } // Left + { ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f }, // Up + { ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f } // Down }; static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness) { ImRect rect = window->Rect(); - if (thickness == 0.0f) rect.Max -= ImVec2(1, 1); - if (border_n == 0) { return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); } // Top - if (border_n == 1) { return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); } // Right - if (border_n == 2) { return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); } // Bottom - if (border_n == 3) { return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); } // Left + if (thickness == 0.0f) + rect.Max -= ImVec2(1, 1); + if (border_n == ImGuiDir_Left) { return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); } + if (border_n == ImGuiDir_Right) { return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); } + if (border_n == ImGuiDir_Up) { return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); } + if (border_n == ImGuiDir_Down) { return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); } IM_ASSERT(0); 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) +ImGuiID ImGui::GetWindowResizeCornerID(ImGuiWindow* window, int n) +{ + IM_ASSERT(n >= 0 && n < 4); + ImGuiID id = window->ID; + id = ImHashStr("#RESIZE", 0, id); + id = ImHashData(&n, sizeof(int), id); + return id; +} + +// Borders (Left, Right, Up, Down) +ImGuiID ImGui::GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir) { - IM_ASSERT(n >= 0 && n <= 7); + IM_ASSERT(dir >= 0 && dir < 4); + int n = (int)dir + 4; ImGuiID id = window->ID; id = ImHashStr("#RESIZE", 0, id); id = ImHashData(&n, sizeof(int), id); @@ -5290,7 +5379,7 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0; const float grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); const float grip_hover_inner_size = IM_FLOOR(grip_draw_size * 0.75f); - const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS : 0.0f; + const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_HOVER_PADDING : 0.0f; ImVec2 pos_target(FLT_MAX, FLT_MAX); ImVec2 size_target(FLT_MAX, FLT_MAX); @@ -5302,15 +5391,16 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s PushID("#RESIZE"); for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) { - const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; - const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); + const ImGuiResizeGripDef& def = resize_grip_def[resize_grip_n]; + const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, def.CornerPosN); // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window - ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size); + bool hovered, held; + ImRect resize_rect(corner - def.InnerDir * grip_hover_outer_size, corner + def.InnerDir * grip_hover_inner_size); 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(resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); + ImGuiID resize_grip_id = window->GetID(resize_grip_n); // == GetWindowResizeCornerID() + ButtonBehavior(resize_rect, resize_grip_id, &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; @@ -5326,39 +5416,41 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s { // Resize from any of the four corners // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position - ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPosN); // Corner of the window corresponding to our corner grip - ImVec2 clamp_min = ImVec2(grip.CornerPosN.x == 1.0f ? visibility_rect.Min.x : -FLT_MAX, grip.CornerPosN.y == 1.0f ? visibility_rect.Min.y : -FLT_MAX); - ImVec2 clamp_max = ImVec2(grip.CornerPosN.x == 0.0f ? visibility_rect.Max.x : +FLT_MAX, grip.CornerPosN.y == 0.0f ? visibility_rect.Max.y : +FLT_MAX); + ImVec2 clamp_min = ImVec2(def.CornerPosN.x == 1.0f ? visibility_rect.Min.x : -FLT_MAX, def.CornerPosN.y == 1.0f ? visibility_rect.Min.y : -FLT_MAX); + ImVec2 clamp_max = ImVec2(def.CornerPosN.x == 0.0f ? visibility_rect.Max.x : +FLT_MAX, def.CornerPosN.y == 0.0f ? visibility_rect.Max.y : +FLT_MAX); + ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(def.InnerDir * grip_hover_outer_size, def.InnerDir * -grip_hover_inner_size, def.CornerPosN); // Corner of the window corresponding to our corner grip corner_target = ImClamp(corner_target, clamp_min, clamp_max); - CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPosN, &pos_target, &size_target); + CalcResizePosSizeFromAnyCorner(window, corner_target, def.CornerPosN, &pos_target, &size_target); } + + // Only lower-left grip is visible before hovering/activating if (resize_grip_n == 0 || held || hovered) resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); } for (int border_n = 0; border_n < resize_border_count; border_n++) { + const ImGuiResizeBorderDef& def = resize_border_def[border_n]; + const ImGuiAxis axis = (border_n == ImGuiDir_Left || border_n == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y; + 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(border_n + 4), &hovered, &held, ImGuiButtonFlags_FlattenChildren); + ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_HOVER_PADDING); + ImGuiID border_id = window->GetID(border_n + 4); // == GetWindowResizeBorderID() + ButtonBehavior(border_rect, border_id, &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) { - g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; + g.MouseCursor = (axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; if (held) *border_held = border_n; } if (held) { + ImVec2 clamp_min(border_n == ImGuiDir_Right ? visibility_rect.Min.x : -FLT_MAX, border_n == ImGuiDir_Down ? visibility_rect.Min.y : -FLT_MAX); + ImVec2 clamp_max(border_n == ImGuiDir_Left ? visibility_rect.Max.x : +FLT_MAX, border_n == ImGuiDir_Up ? visibility_rect.Max.y : +FLT_MAX); ImVec2 border_target = window->Pos; - ImVec2 border_posn; - if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Top - if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Right - if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Bottom - if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Left - ImVec2 clamp_min = ImVec2(border_n == 1 ? visibility_rect.Min.x : -FLT_MAX, border_n == 2 ? visibility_rect.Min.y : -FLT_MAX); - ImVec2 clamp_max = ImVec2(border_n == 3 ? visibility_rect.Max.x : +FLT_MAX, border_n == 0 ? visibility_rect.Max.y : +FLT_MAX); + border_target[axis] = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + WINDOWS_HOVER_PADDING; border_target = ImClamp(border_target, clamp_min, clamp_max); - CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target); + CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target); } } PopID(); @@ -5370,9 +5462,9 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s if (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window) { ImVec2 nav_resize_delta; - if (g.NavInputSource == ImGuiInputSource_NavKeyboard && g.IO.KeyShift) + if (g.NavInputSource == ImGuiInputSource_Keyboard && g.IO.KeyShift) nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down); - if (g.NavInputSource == ImGuiInputSource_NavGamepad) + if (g.NavInputSource == ImGuiInputSource_Gamepad) nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down); if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f) { @@ -5418,16 +5510,16 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) float rounding = window->WindowRounding; float border_size = window->WindowBorderSize; if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground)) - window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); + window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, 0, border_size); int border_held = window->ResizeBorderHeld; if (border_held != -1) { const ImGuiResizeBorderDef& def = resize_border_def[border_held]; ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f); - window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25f, def.OuterAngle); - window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f); - window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), false, ImMax(2.0f, border_size)); // Thicker than usual + window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25f, def.OuterAngle); + window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f); + window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), 0, ImMax(2.0f, border_size)); // Thicker than usual } if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) { @@ -5476,14 +5568,14 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar } if (override_alpha) bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT); - window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot); + window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom); } // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) { ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); - window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top); + window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawFlags_RoundCornersTop); } // Menu bar @@ -5491,7 +5583,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar { ImRect menu_bar_rect = window->MenuBarRect(); menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them. - window->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top); + window->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawFlags_RoundCornersTop); if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y) window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); } @@ -5532,8 +5624,8 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None); // Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer) - const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; - window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus; + const ImGuiItemFlags item_flags_backup = g.CurrentItemFlags; + g.CurrentItemFlags |= ImGuiItemFlags_NoNavDefaultFocus; window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; // Layout buttons @@ -5570,7 +5662,7 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl *p_open = false; window->DC.NavLayerCurrent = ImGuiNavLayer_Main; - window->DC.ItemFlags = item_flags_backup; + g.CurrentItemFlags = item_flags_backup; // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker) // FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code.. @@ -5654,14 +5746,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Update the Appearing flag bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on - const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0); if (flags & ImGuiWindowFlags_Popup) { ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed window_just_activated_by_user |= (window != popup_ref.Window); } - window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize); + window->Appearing = window_just_activated_by_user; if (window->Appearing) SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true); @@ -5703,9 +5794,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->PopupId = popup_ref.PopupId; } - if (window_just_appearing_after_hidden_for_resize && !(flags & ImGuiWindowFlags_ChildWindow)) - window->NavLastIds[0] = 0; - // Update ->RootWindow and others pointers (before any possible call to FocusWindow) if (first_begin_of_the_frame) UpdateWindowParentAndRootLinks(window, flags, parent_window); @@ -5791,6 +5879,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS // Update contents size from last frame for auto-fitting (or use explicit size) + const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0); CalcWindowContentSizes(window, &window->ContentSize, &window->ContentSizeIdeal); if (window->HiddenFramesCanSkipItems > 0) window->HiddenFramesCanSkipItems--; @@ -5848,7 +5937,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { window->Collapsed = !window->Collapsed; MarkIniSettingsDirty(window); - FocusWindow(window); } } else @@ -6111,7 +6199,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) bb.Expand(-g.FontSize - 1.0f); rounding = window->WindowRounding; } - window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f); + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, 0, 3.0f); } // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING) @@ -6154,8 +6242,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; window->DC.NavLayerCurrent = ImGuiNavLayer_Main; - window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext; - window->DC.NavLayerActiveMaskNext = 0x00; + window->DC.NavLayersActiveMask = window->DC.NavLayersActiveMaskNext; + window->DC.NavLayersActiveMaskNext = 0x00; window->DC.NavHideHighlightOneFrame = false; window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f); @@ -6184,7 +6272,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if (want_focus) { FocusWindow(window); - NavInitWindow(window, false); + NavInitWindow(window, false); // <-- this is in the way for us to be able to defer and sort reappearing FocusWindow() calls } // Title bar @@ -6220,7 +6308,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) } // Pull/inherit current state - window->DC.ItemFlags = g.ItemFlagsStack.back(); // Inherit from shared stack + g.CurrentItemFlags = g.ItemFlagsStack.back(); // Inherit from shared stack window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : 0; // Inherit from parent only // -V595 PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true); @@ -6257,6 +6345,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Update the Hidden flag window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0) || (window->HiddenFramesForRenderOnly > 0); + // Disable inputs for requested number of frames + if (window->DisableInputsFrames > 0) + { + window->DisableInputsFrames--; + window->Flags |= ImGuiWindowFlags_NoInputs; + } + // Update the SkipItems flag, used to early out of all items functions (no layout required) bool skip_items = false; if (window->Collapsed || !window->Active || window->Hidden) @@ -6305,15 +6400,22 @@ void ImGui::End() void ImGui::BringWindowToFocusFront(ImGuiWindow* window) { ImGuiContext& g = *GImGui; + IM_ASSERT(window == window->RootWindow); + + const int cur_order = window->FocusOrder; + IM_ASSERT(g.WindowsFocusOrder[cur_order] == window); if (g.WindowsFocusOrder.back() == window) return; - for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the top-most window - if (g.WindowsFocusOrder[i] == window) - { - memmove(&g.WindowsFocusOrder[i], &g.WindowsFocusOrder[i + 1], (size_t)(g.WindowsFocusOrder.Size - i - 1) * sizeof(ImGuiWindow*)); - g.WindowsFocusOrder[g.WindowsFocusOrder.Size - 1] = window; - break; - } + + const int new_order = g.WindowsFocusOrder.Size - 1; + for (int n = cur_order; n < new_order; n++) + { + g.WindowsFocusOrder[n] = g.WindowsFocusOrder[n + 1]; + g.WindowsFocusOrder[n]->FocusOrder--; + IM_ASSERT(g.WindowsFocusOrder[n]->FocusOrder == n); + } + g.WindowsFocusOrder[new_order] = window; + window->FocusOrder = (short)new_order; } void ImGui::BringWindowToDisplayFront(ImGuiWindow* window) @@ -6355,11 +6457,12 @@ void ImGui::FocusWindow(ImGuiWindow* window) g.NavWindow = window; if (window && g.NavDisableMouseHover) g.NavMousePosDirty = true; - g.NavInitRequest = false; g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId g.NavFocusScopeId = 0; g.NavIdIsAlive = false; g.NavLayer = ImGuiNavLayer_Main; + g.NavInitRequest = g.NavMoveRequest = false; + NavUpdateAnyRequestFlag(); //IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL); } @@ -6392,18 +6495,13 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind { ImGuiContext& g = *GImGui; - int start_idx = g.WindowsFocusOrder.Size - 1; - if (under_this_window != NULL) - { - int under_this_window_idx = FindWindowFocusIndex(under_this_window); - if (under_this_window_idx != -1) - start_idx = under_this_window_idx - 1; - } + const int start_idx = ((under_this_window != NULL) ? FindWindowFocusIndex(under_this_window) : g.WindowsFocusOrder.Size) - 1; for (int i = start_idx; i >= 0; i--) { // We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user. ImGuiWindow* window = g.WindowsFocusOrder[i]; - if (window != ignore_window && window->WasActive && !(window->Flags & ImGuiWindowFlags_ChildWindow)) + IM_ASSERT(window == window->RootWindow); + if (window != ignore_window && window->WasActive) if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) { ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window); @@ -6414,6 +6512,7 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind FocusWindow(NULL); } +// Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only. void ImGui::SetCurrentFont(ImFont* font) { ImGuiContext& g = *GImGui; @@ -6451,24 +6550,22 @@ void ImGui::PopFont() void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - ImGuiItemFlags item_flags = window->DC.ItemFlags; + ImGuiItemFlags item_flags = g.CurrentItemFlags; IM_ASSERT(item_flags == g.ItemFlagsStack.back()); if (enabled) item_flags |= option; else item_flags &= ~option; - window->DC.ItemFlags = item_flags; + g.CurrentItemFlags = item_flags; g.ItemFlagsStack.push_back(item_flags); } void ImGui::PopItemFlag() { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; IM_ASSERT(g.ItemFlagsStack.Size > 1); // Too many calls to PopItemFlag() - we always leave a 0 at the bottom of the stack. g.ItemFlagsStack.pop_back(); - window->DC.ItemFlags = g.ItemFlagsStack.back(); + g.CurrentItemFlags = g.ItemFlagsStack.back(); } // FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system. @@ -6537,30 +6634,28 @@ bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags) { IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0); // Flags not supported by this function ImGuiContext& g = *GImGui; + if (g.HoveredWindow == NULL) + return false; - if (flags & ImGuiHoveredFlags_AnyWindow) - { - if (g.HoveredWindow == NULL) - return false; - } - else + if ((flags & ImGuiHoveredFlags_AnyWindow) == 0) { + ImGuiWindow* window = g.CurrentWindow; switch (flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) { case ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows: - if (g.HoveredRootWindow != g.CurrentWindow->RootWindow) + if (g.HoveredWindow->RootWindow != window->RootWindow) return false; break; case ImGuiHoveredFlags_RootWindow: - if (g.HoveredWindow != g.CurrentWindow->RootWindow) + if (g.HoveredWindow != window->RootWindow) return false; break; case ImGuiHoveredFlags_ChildWindows: - if (g.HoveredWindow == NULL || !IsWindowChildOf(g.HoveredWindow, g.CurrentWindow)) + if (!IsWindowChildOf(g.HoveredWindow, window)) return false; break; default: - if (g.HoveredWindow != g.CurrentWindow) + if (g.HoveredWindow != window) return false; break; } @@ -6886,9 +6981,9 @@ void ImGui::SetKeyboardFocusHere(int offset) IM_ASSERT(offset >= -1); // -1 is allowed but not below ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - g.FocusRequestNextWindow = window; - g.FocusRequestNextCounterRegular = window->DC.FocusCounterRegular + 1 + offset; - g.FocusRequestNextCounterTabStop = INT_MAX; + g.TabFocusRequestNextWindow = window; + g.TabFocusRequestNextCounterRegular = window->DC.FocusCounterRegular + 1 + offset; + g.TabFocusRequestNextCounterTabStop = INT_MAX; } void ImGui::SetItemDefaultFocus() @@ -6897,11 +6992,11 @@ void ImGui::SetItemDefaultFocus() ImGuiWindow* window = g.CurrentWindow; if (!window->Appearing) return; - if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent) + if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == window->DC.NavLayerCurrent) { g.NavInitRequest = false; - g.NavInitResultId = g.NavWindow->DC.LastItemId; - g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos); + g.NavInitResultId = window->DC.LastItemId; + g.NavInitResultRectRel = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos); NavUpdateAnyRequestFlag(); if (!IsItemVisible()) SetScrollHereY(); @@ -7039,7 +7134,7 @@ static void ImGui::ErrorCheckNewFrameSanityChecks() ImGuiContext& g = *GImGui; // Check user IM_ASSERT macro - // (IF YOU GET A WARNING OR COMPILE ERROR HERE: it means you assert macro is incorrectly defined! + // (IF YOU GET A WARNING OR COMPILE ERROR HERE: it means your assert macro is incorrectly defined! // If your macro uses multiple statements, it NEEDS to be surrounded by a 'do { ... } while (0)' block. // This is a common C/C++ idiom to allow multiple statements macros to be used in control flow blocks.) // #define IM_ASSERT(EXPR) if (SomeCode(EXPR)) SomeMoreCode(); // Wrong! @@ -7055,7 +7150,7 @@ static void ImGui::ErrorCheckNewFrameSanityChecks() IM_ASSERT(g.IO.Fonts->Fonts.Size > 0 && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()?"); IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded() && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()?"); IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!"); - IM_ASSERT(g.Style.CircleSegmentMaxError > 0.0f && "Invalid style setting!"); + IM_ASSERT(g.Style.CircleTessellationMaxError > 0.0f && "Invalid style setting!"); IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting!"); // Allows us to avoid a few clamps in color computations IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting."); IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right); @@ -7118,13 +7213,11 @@ void ImGui::ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, voi ImGuiContext& g = *GImGui; while (g.CurrentWindowStack.Size > 0) { -#ifdef IMGUI_HAS_TABLE while (g.CurrentTable && (g.CurrentTable->OuterWindow == g.CurrentWindow || g.CurrentTable->InnerWindow == g.CurrentWindow)) { if (log_callback) log_callback(user_data, "Recovered from missing EndTable() in '%s'", g.CurrentTable->OuterWindow->Name); EndTable(); } -#endif ImGuiWindow* window = g.CurrentWindow; IM_ASSERT(window != NULL); while (g.CurrentTabBar != NULL) //-V1044 @@ -7294,7 +7387,7 @@ void ImGui::ItemSize(const ImRect& bb, float text_baseline_y) // Declare item bounding box for clipping and interaction. // Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface // declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction. -bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) +bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGuiItemAddFlags flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; @@ -7310,7 +7403,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) // to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick). // We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null. // If we crash on a NULL g.NavWindow we need to fix the bug elsewhere. - window->DC.NavLayerActiveMaskNext |= (1 << window->DC.NavLayerCurrent); + window->DC.NavLayersActiveMaskNext |= (1 << window->DC.NavLayerCurrent); if (g.NavId == id || g.NavAnyRequest) if (g.NavWindow->RootWindowForNav == window->RootWindowForNav) if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened)) @@ -7343,6 +7436,11 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) return false; //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG] + // Tab stop handling (previously was using internal ItemFocusable() api) + // FIXME-NAV: We would now want to move this above the clipping test, but this would require being able to scroll and currently this would mean an extra frame. (#4079, #343) + if (flags & ImGuiItemAddFlags_Focusable) + ItemFocusable(window, id); + // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them) if (IsMouseHoveringRect(bb.Min, bb.Max)) window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect; @@ -7628,6 +7726,7 @@ void ImGui::BeginGroup() group_data.BackupCurrLineSize = window->DC.CurrLineSize; group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset; group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive; + group_data.BackupHoveredIdIsAlive = g.HoveredId != 0; group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive; group_data.EmitItem = true; @@ -7681,6 +7780,11 @@ void ImGui::EndGroup() window->DC.LastItemId = g.ActiveIdPreviousFrame; window->DC.LastItemRect = group_bb; + // Forward Hovered flag + const bool group_contains_curr_hovered_id = (group_data.BackupHoveredIdIsAlive == false) && g.HoveredId != 0; + if (group_contains_curr_hovered_id) + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredWindow; + // Forward Edited flag if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame) window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; @@ -7717,24 +7821,29 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window) ImVec2 scroll = window->Scroll; if (window->ScrollTarget.x < FLT_MAX) { + float decoration_total_width = window->ScrollbarSizes.x; float center_x_ratio = window->ScrollTargetCenterRatio.x; float scroll_target_x = window->ScrollTarget.x; - float snap_x_min = 0.0f; - float snap_x_max = window->ScrollMax.x + window->Size.x; if (window->ScrollTargetEdgeSnapDist.x > 0.0f) + { + float snap_x_min = 0.0f; + float snap_x_max = window->ScrollMax.x + window->SizeFull.x - decoration_total_width; scroll_target_x = CalcScrollEdgeSnap(scroll_target_x, snap_x_min, snap_x_max, window->ScrollTargetEdgeSnapDist.x, center_x_ratio); - scroll.x = scroll_target_x - center_x_ratio * (window->SizeFull.x - window->ScrollbarSizes.x); + } + scroll.x = scroll_target_x - center_x_ratio * (window->SizeFull.x - decoration_total_width); } if (window->ScrollTarget.y < FLT_MAX) { - float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); + float decoration_total_height = window->TitleBarHeight() + window->MenuBarHeight() + window->ScrollbarSizes.y; float center_y_ratio = window->ScrollTargetCenterRatio.y; float scroll_target_y = window->ScrollTarget.y; - float snap_y_min = 0.0f; - float snap_y_max = window->ScrollMax.y + window->Size.y - decoration_up_height; if (window->ScrollTargetEdgeSnapDist.y > 0.0f) + { + float snap_y_min = 0.0f; + float snap_y_max = window->ScrollMax.y + window->SizeFull.y - decoration_total_height; scroll_target_y = CalcScrollEdgeSnap(scroll_target_y, snap_y_min, snap_y_max, window->ScrollTargetEdgeSnapDist.y, center_y_ratio); - scroll.y = scroll_target_y - center_y_ratio * (window->SizeFull.y - window->ScrollbarSizes.y - decoration_up_height); + } + scroll.y = scroll_target_y - center_y_ratio * (window->SizeFull.y - decoration_total_height); } scroll.x = IM_FLOOR(ImMax(scroll.x, 0.0f)); scroll.y = IM_FLOOR(ImMax(scroll.y, 0.0f)); @@ -7847,7 +7956,8 @@ void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio) { IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); - local_y -= window->TitleBarHeight() + window->MenuBarHeight(); // FIXME: Would be nice to have a more standardized access to our scrollable/client rect + const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); // FIXME: Would be nice to have a more standardized access to our scrollable/client rect; + local_y -= decoration_up_height; window->ScrollTarget.y = IM_FLOOR(local_y + window->Scroll.y); // Convert local position to scroll offset window->ScrollTargetCenterRatio.y = center_y_ratio; window->ScrollTargetEdgeSnapDist.y = 0.0f; @@ -7870,7 +7980,7 @@ void ImGui::SetScrollHereX(float center_x_ratio) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - float spacing_x = g.Style.ItemSpacing.x; + float spacing_x = ImMax(window->WindowPadding.x, g.Style.ItemSpacing.x); float target_pos_x = ImLerp(window->DC.LastItemRect.Min.x - spacing_x, window->DC.LastItemRect.Max.x + spacing_x, center_x_ratio); SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); // Convert from absolute to local pos @@ -7883,7 +7993,7 @@ void ImGui::SetScrollHereY(float center_y_ratio) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - float spacing_y = g.Style.ItemSpacing.y; + float spacing_y = ImMax(window->WindowPadding.y, g.Style.ItemSpacing.y); float target_pos_y = ImLerp(window->DC.CursorPosPrevLine.y - spacing_y, window->DC.CursorPosPrevLine.y + window->DC.PrevLineSize.y + spacing_y, center_y_ratio); SetScrollFromPosY(window, target_pos_y - window->Pos.y, center_y_ratio); // Convert from absolute to local pos @@ -8014,6 +8124,11 @@ void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags) OpenPopupEx(g.CurrentWindow->GetID(str_id), popup_flags); } +void ImGui::OpenPopup(ImGuiID id, ImGuiPopupFlags popup_flags) +{ + OpenPopupEx(id, popup_flags); +} + // Mark popup as open (toggle toward open state). // Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. // Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). @@ -8273,10 +8388,21 @@ void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags } // This is a helper to handle the simplest case of associating one named popup to one given widget. -// - You can pass a NULL str_id to use the identifier of the last item. -// - You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters). -// - This is essentially the same as calling OpenPopupOnItemClick() + BeginPopup() but written to avoid -// computing the ID twice because BeginPopupContextXXX functions may be called very frequently. +// - To create a popup associated to the last item, you generally want to pass a NULL value to str_id. +// - To create a popup with a specific identifier, pass it in str_id. +// - This is useful when using using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call. +// - This is useful when multiple code locations may want to manipulate/open the same popup, given an explicit id. +// - You may want to handle the whole on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters). +// This is essentially the same as: +// id = str_id ? GetID(str_id) : GetItemID(); +// OpenPopupOnItemClick(str_id); +// return BeginPopup(id); +// Which is essentially the same as: +// id = str_id ? GetID(str_id) : GetItemID(); +// if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right)) +// OpenPopup(id); +// return BeginPopup(id); +// The main difference being that this is tweaked to avoid computing the ID twice. bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags) { ImGuiWindow* window = GImGui->CurrentWindow; @@ -8450,26 +8576,19 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) // [SECTION] KEYBOARD/GAMEPAD NAVIGATION //----------------------------------------------------------------------------- -// FIXME-NAV: The existence of SetNavID vs SetNavIDWithRectRel vs SetFocusID is incredibly messy and confusing, -// and needs some explanation or serious refactoring. -void ImGui::SetNavID(ImGuiID id, int nav_layer, ImGuiID focus_scope_id) +// FIXME-NAV: The existence of SetNavID vs SetFocusID properly needs to be clarified/reworked. +void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel) { ImGuiContext& g = *GImGui; - IM_ASSERT(g.NavWindow); - IM_ASSERT(nav_layer == 0 || nav_layer == 1); + IM_ASSERT(g.NavWindow != NULL); + IM_ASSERT(nav_layer == ImGuiNavLayer_Main || nav_layer == ImGuiNavLayer_Menu); g.NavId = id; + g.NavLayer = nav_layer; g.NavFocusScopeId = focus_scope_id; g.NavWindow->NavLastIds[nav_layer] = id; -} - -void ImGui::SetNavIDWithRectRel(ImGuiID id, int nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel) -{ - ImGuiContext& g = *GImGui; - SetNavID(id, nav_layer, focus_scope_id); g.NavWindow->NavRectRel[nav_layer] = rect_rel; - g.NavMousePosDirty = true; - g.NavDisableHighlight = false; - g.NavDisableMouseHover = true; + //g.NavDisableHighlight = false; + //g.NavDisableMouseHover = g.NavMousePosDirty = true; } void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) @@ -8527,7 +8646,7 @@ static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect } // Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057 -static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand) +static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; @@ -8658,7 +8777,7 @@ static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand) return new_best; } -static void ImGui::NavApplyItemToResult(ImGuiNavMoveResult* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel) +static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel) { result->Window = window; result->ID = id; @@ -8673,7 +8792,7 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con //if (!g.IO.NavActive) // [2017/10/06] Removed this possibly redundant test but I am not sure of all the side-effects yet. Some of the feature here will need to work regardless of using a _NoNavInputs flag. // return; - const ImGuiItemFlags item_flags = window->DC.ItemFlags; + const ImGuiItemFlags item_flags = g.CurrentItemFlags; const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos); // Process Init Request @@ -8696,7 +8815,7 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy) if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNav))) { - ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; + ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; #if IMGUI_DEBUG_NAV_SCORING // [DEBUG] Score all items in NavWindow at all times if (!g.NavMoveRequest) @@ -8723,7 +8842,6 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con g.NavLayer = window->DC.NavLayerCurrent; g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent; g.NavIdIsAlive = true; - g.NavIdTabCounter = window->DC.FocusCounterTabStop; window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel; // Store item bounding box (relative to window position) } } @@ -8768,7 +8886,7 @@ void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags mov static void ImGui::NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window) { ImGuiWindow* parent = nav_window; - while (parent && (parent->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) + while (parent && parent->RootWindow != parent && (parent->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) parent = parent->ParentWindow; if (parent && parent != nav_window) parent->NavLastChildNavWindow = nav_window; @@ -8783,17 +8901,23 @@ static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window) return window; } -static void NavRestoreLayer(ImGuiNavLayer layer) +void ImGui::NavRestoreLayer(ImGuiNavLayer layer) { ImGuiContext& g = *GImGui; - g.NavLayer = layer; - if (layer == 0) - g.NavWindow = ImGui::NavRestoreLastChildNavWindow(g.NavWindow); + if (layer == ImGuiNavLayer_Main) + g.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow); ImGuiWindow* window = g.NavWindow; - if (layer == 0 && window->NavLastIds[0] != 0) - ImGui::SetNavIDWithRectRel(window->NavLastIds[0], layer, 0, window->NavRectRel[0]); + if (window->NavLastIds[layer] != 0) + { + SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); + g.NavDisableHighlight = false; + g.NavDisableMouseHover = g.NavMousePosDirty = true; + } else - ImGui::NavInitWindow(window, true); + { + g.NavLayer = layer; + NavInitWindow(window, true); + } } static inline void ImGui::NavUpdateAnyRequestFlag() @@ -8809,14 +8933,20 @@ void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) { ImGuiContext& g = *GImGui; IM_ASSERT(window == g.NavWindow); + + if (window->Flags & ImGuiWindowFlags_NoNavInputs) + { + g.NavId = g.NavFocusScopeId = 0; + return; + } + bool init_for_nav = false; - if (!(window->Flags & ImGuiWindowFlags_NoNavInputs)) - if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit) - init_for_nav = true; + if (window == window->RootWindow || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit) + init_for_nav = true; IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer); if (init_for_nav) { - SetNavID(0, g.NavLayer, 0); + SetNavID(0, g.NavLayer, 0, ImRect()); g.NavInitRequest = true; g.NavInitRequestFromMove = false; g.NavInitResultId = 0; @@ -8904,17 +9034,17 @@ static void ImGui::NavUpdate() // (do it before we map Keyboard input!) bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; - if (nav_gamepad_active && g.NavInputSource != ImGuiInputSource_NavGamepad) + if (nav_gamepad_active && g.NavInputSource != ImGuiInputSource_Gamepad) { if (io.NavInputs[ImGuiNavInput_Activate] > 0.0f || io.NavInputs[ImGuiNavInput_Input] > 0.0f || io.NavInputs[ImGuiNavInput_Cancel] > 0.0f || io.NavInputs[ImGuiNavInput_Menu] > 0.0f || io.NavInputs[ImGuiNavInput_DpadLeft] > 0.0f || io.NavInputs[ImGuiNavInput_DpadRight] > 0.0f || io.NavInputs[ImGuiNavInput_DpadUp] > 0.0f || io.NavInputs[ImGuiNavInput_DpadDown] > 0.0f) - g.NavInputSource = ImGuiInputSource_NavGamepad; + g.NavInputSource = ImGuiInputSource_Gamepad; } // Update Keyboard->Nav inputs mapping if (nav_keyboard_active) { - #define NAV_MAP_KEY(_KEY, _NAV_INPUT) do { if (IsKeyDown(io.KeyMap[_KEY])) { io.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; } } while (0) + #define NAV_MAP_KEY(_KEY, _NAV_INPUT) do { if (IsKeyDown(io.KeyMap[_KEY])) { io.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_Keyboard; } } while (0) NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate ); NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input ); NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel ); @@ -8926,8 +9056,16 @@ static void ImGui::NavUpdate() io.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f; if (io.KeyShift) io.NavInputs[ImGuiNavInput_TweakFast] = 1.0f; - if (io.KeyAlt && !io.KeyCtrl) // AltGR is Alt+Ctrl, also even on keyboards without AltGR we don't want Alt+Ctrl to open menu. + + // AltGR is normally Alt+Ctrl but we can't reliably detect it (not all backends/systems/layout emit it as Alt+Ctrl) + // But also even on keyboards without AltGR we don't want Alt+Ctrl to open menu anyway. + if (io.KeyAlt && !io.KeyCtrl) io.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f; + + // We automatically cancel toggling nav layer when any text has been typed while holding Alt. (See #370) + if (io.KeyAlt && !io.KeyCtrl && g.NavWindowingToggleLayer && io.InputQueueCharacters.Size > 0) + g.NavWindowingToggleLayer = false; + #undef NAV_MAP_KEY } memcpy(io.NavInputsDownDurationPrev, io.NavInputsDownDuration, sizeof(io.NavInputsDownDuration)); @@ -8935,7 +9073,7 @@ static void ImGui::NavUpdate() io.NavInputsDownDuration[i] = (io.NavInputs[i] > 0.0f) ? (io.NavInputsDownDuration[i] < 0.0f ? 0.0f : io.NavInputsDownDuration[i] + io.DeltaTime) : -1.0f; // Process navigation init request (select first/default focus) - if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove)) + if (g.NavInitResultId != 0) NavUpdateInitResult(); g.NavInitRequest = false; g.NavInitRequestFromMove = false; @@ -8960,13 +9098,11 @@ static void ImGui::NavUpdate() { // Set mouse position given our knowledge of the navigated item position from last frame if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos)) - { if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow) { io.MousePos = io.MousePosPrev = NavCalcPreferredRefPos(); io.WantSetMousePos = true; } - } g.NavMousePosDirty = false; } g.NavIdIsAlive = false; @@ -8995,18 +9131,20 @@ static void ImGui::NavUpdate() if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel)) ClearActiveID(); } - else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow) + else if (g.NavLayer != ImGuiNavLayer_Main) + { + // Leave the "menu" layer + NavRestoreLayer(ImGuiNavLayer_Main); + } + else if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow) { // Exit child window ImGuiWindow* child_window = g.NavWindow; ImGuiWindow* parent_window = g.NavWindow->ParentWindow; IM_ASSERT(child_window->ChildId != 0); + ImRect child_rect = child_window->Rect(); FocusWindow(parent_window); - SetNavID(child_window->ChildId, 0, 0); - // Reassigning with same value, we're being explicit here. - g.NavIdIsAlive = false; // -V1048 - if (g.NavDisableMouseHover) - g.NavMousePosDirty = true; + SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, ImRect(child_rect.Min - parent_window->Pos, child_rect.Max - parent_window->Pos)); } else if (g.OpenPopupStack.Size > 0) { @@ -9014,11 +9152,6 @@ static void ImGui::NavUpdate() if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal)) ClosePopupToLevel(g.OpenPopupStack.Size - 1, true); } - else if (g.NavLayer != ImGuiNavLayer_Main) - { - // Leave the "menu" layer - NavRestoreLayer(ImGuiNavLayer_Main); - } else { // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were @@ -9108,7 +9241,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 = IM_ROUND(window->CalcFontSize() * 100 * 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 (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest) { if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed)); @@ -9133,7 +9266,7 @@ static void ImGui::NavUpdate() // When using gamepad, we project the reference nav bounding box into window visible area. // This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad every movements are relative // (can't focus a visible object like we can with the mouse). - if (g.NavMoveRequest && g.NavInputSource == ImGuiInputSource_NavGamepad && g.NavLayer == ImGuiNavLayer_Main) + if (g.NavMoveRequest && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main) { ImGuiWindow* window = g.NavWindow; ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1)); @@ -9148,7 +9281,7 @@ static void ImGui::NavUpdate() } // For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items) - ImRect nav_rect_rel = g.NavWindow ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0); + ImRect nav_rect_rel = g.NavWindow && !g.NavWindow->NavRectRel[g.NavLayer].IsInverted() ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0); g.NavScoringRect = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : ImRect(0, 0, 0, 0); g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y); g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x); @@ -9174,12 +9307,14 @@ static void ImGui::NavUpdateInitResult() return; // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called) + // FIXME-NAV: On _NavFlattened windows, g.NavWindow will only be updated during subsequent frame. Not a problem currently. IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name); + SetNavID(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel); if (g.NavInitRequestFromMove) - SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel); - else - SetNavID(g.NavInitResultId, g.NavLayer, 0); - g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel; + { + g.NavDisableHighlight = false; + g.NavDisableMouseHover = g.NavMousePosDirty = true; + } } // Apply result from previous frame navigation directional move request @@ -9198,7 +9333,7 @@ static void ImGui::NavUpdateMoveResult() } // Select which result to use - ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; + ImGuiNavItemData* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page. if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) @@ -9242,7 +9377,9 @@ static void ImGui::NavUpdateMoveResult() g.NavJustMovedToKeyMods = g.NavMoveRequestKeyMods; } IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name); - SetNavIDWithRectRel(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel); + SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel); + g.NavDisableHighlight = false; + g.NavDisableMouseHover = g.NavMousePosDirty = true; } // Handle PageUp/PageDown/Home/End keys @@ -9263,7 +9400,7 @@ static float ImGui::NavUpdatePageUpPageDown() const bool end_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End); if (page_up_held != page_down_held || home_pressed != end_pressed) // If either (not both) are pressed { - if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll) + if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll) { // Fallback manual-scroll when window has no navigable item if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true)) @@ -9381,13 +9518,13 @@ static void ImGui::NavEndFrame() } } -static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) // FIXME-OPT O(N) +static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) { ImGuiContext& g = *GImGui; - for (int i = g.WindowsFocusOrder.Size - 1; i >= 0; i--) - if (g.WindowsFocusOrder[i] == window) - return i; - return -1; + IM_UNUSED(g); + int order = window->FocusOrder; + IM_ASSERT(g.WindowsFocusOrder[order] == window); + return order; } static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N) @@ -9446,12 +9583,12 @@ static void ImGui::NavUpdateWindowing() g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; // FIXME-DOCK: Will need to use RootWindowDockStop g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f; g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true; - g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad; + g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_Keyboard : ImGuiInputSource_Gamepad; } // Gamepad update g.NavWindowingTimer += g.IO.DeltaTime; - if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavGamepad) + if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Gamepad) { // Highlight only appears after a brief time holding the button, so that a fast tap on PadMenu (to toggle NavLayer) doesn't add visual noise g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); @@ -9477,7 +9614,7 @@ static void ImGui::NavUpdateWindowing() } // Keyboard: Focus - if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavKeyboard) + if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Keyboard) { // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f @@ -9499,9 +9636,9 @@ static void ImGui::NavUpdateWindowing() if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove)) { ImVec2 move_delta; - if (g.NavInputSource == ImGuiInputSource_NavKeyboard && !g.IO.KeyShift) + if (g.NavInputSource == ImGuiInputSource_Keyboard && !g.IO.KeyShift) move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down); - if (g.NavInputSource == ImGuiInputSource_NavGamepad) + if (g.NavInputSource == ImGuiInputSource_Gamepad) move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down); if (move_delta.x != 0.0f || move_delta.y != 0.0f) { @@ -9526,8 +9663,14 @@ static void ImGui::NavUpdateWindowing() if (apply_focus_window->NavLastIds[0] == 0) NavInitWindow(apply_focus_window, false); - // If the window only has a menu layer, select it directly - if (apply_focus_window->DC.NavLayerActiveMask == (1 << ImGuiNavLayer_Menu)) + // If the window has ONLY a menu layer (no main layer), select it directly + // Use NavLayersActiveMaskNext since windows didn't have a chance to be Begin()-ed on this frame, + // so CTRL+Tab where the keys are only held for 1 frame will be able to use correct layers mask since + // the target window as already been previewed once. + // FIXME-NAV: This should be done in NavInit.. or in FocusWindow... However in both of those cases, + // we won't have a guarantee that windows has been visible before and therefore NavLayersActiveMask* + // won't be valid. + if (apply_focus_window->DC.NavLayersActiveMaskNext == (1 << ImGuiNavLayer_Menu)) g.NavLayer = ImGuiNavLayer_Menu; } if (apply_focus_window) @@ -9536,10 +9679,12 @@ static void ImGui::NavUpdateWindowing() // Apply menu/layer toggle if (apply_toggle_layer && g.NavWindow) { + ClearActiveID(); + // Move to parent menu if necessary ImGuiWindow* new_nav_window = g.NavWindow; while (new_nav_window->ParentWindow - && (new_nav_window->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) == 0 + && (new_nav_window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) == 0 && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) new_nav_window = new_nav_window->ParentWindow; @@ -9552,8 +9697,10 @@ static void ImGui::NavUpdateWindowing() g.NavDisableHighlight = false; g.NavDisableMouseHover = true; - // When entering a regular menu bar with the Alt key, we always reinitialize the navigation ID. - const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main; + // Reinitialize navigation when entering menu bar with the Alt key. + const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main; + if (new_nav_layer == ImGuiNavLayer_Menu) + g.NavWindow->NavLastIds[new_nav_layer] = 0; NavRestoreLayer(new_nav_layer); } } @@ -9587,6 +9734,7 @@ void ImGui::NavUpdateWindowingOverlay() for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--) { ImGuiWindow* window = g.WindowsFocusOrder[n]; + IM_ASSERT(window != NULL); // Fix static analyzers if (!IsWindowNavFocusable(window)) continue; const char* label = window->Name; @@ -9617,27 +9765,45 @@ void ImGui::ClearDragDrop() memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); } -// Call when current ID is active. // When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource() +// If the item has an identifier: +// - This assume/require the item to be activated (typically via ButtonBehavior). +// - Therefore if you want to use this with a mouse button other than left mouse button, it is up to the item itself to activate with another button. +// - We then pull and use the mouse button that was used to activate the item and use it to carry on the drag. +// If the item has no identifier: +// - Currently always assume left mouse button. bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; + // FIXME-DRAGDROP: While in the common-most "drag from non-zero active id" case we can tell the mouse button, + // in both SourceExtern and id==0 cases we may requires something else (explicit flags or some heuristic). + ImGuiMouseButton mouse_button = ImGuiMouseButton_Left; + bool source_drag_active = false; ImGuiID source_id = 0; ImGuiID source_parent_id = 0; - ImGuiMouseButton mouse_button = ImGuiMouseButton_Left; if (!(flags & ImGuiDragDropFlags_SourceExtern)) { source_id = window->DC.LastItemId; - if (source_id != 0 && g.ActiveId != source_id) // Early out for most common case - return false; - if (g.IO.MouseDown[mouse_button] == false) - return false; - - if (source_id == 0) + if (source_id != 0) + { + // Common path: items with ID + if (g.ActiveId != source_id) + return false; + if (g.ActiveIdMouseButton != -1) + mouse_button = g.ActiveIdMouseButton; + if (g.IO.MouseDown[mouse_button] == false) + return false; + g.ActiveIdAllowOverlap = false; + } + else { + // Uncommon path: items without ID + if (g.IO.MouseDown[mouse_button] == false) + return false; + // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to: // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride. if (!(flags & ImGuiDragDropFlags_SourceAllowNullID)) @@ -9664,10 +9830,6 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker. g.ActiveIdAllowOverlap = is_hovered; } - else - { - g.ActiveIdAllowOverlap = false; - } if (g.ActiveId != source_id) return false; source_parent_id = window->IDStack.back(); @@ -9870,11 +10032,11 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that lives for 1 frame) if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview) { - // FIXME-DRAG: Settle on a proper default visuals for drop target. + // FIXME-DRAGDROP: Settle on a proper default visuals for drop target. r.Expand(3.5f); bool push_clip_rect = !window->ClipRect.Contains(r); if (push_clip_rect) window->DrawList->PushClipRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1)); - window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ~0, 2.0f); + window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, 0, 2.0f); if (push_clip_rect) window->DrawList->PopClipRect(); } @@ -9909,14 +10071,8 @@ void ImGui::EndDragDropTarget() //----------------------------------------------------------------------------- // Pass text data straight to log (without being displayed) -void ImGui::LogText(const char* fmt, ...) +static inline void LogTextV(ImGuiContext& g, const char* fmt, va_list args) { - ImGuiContext& g = *GImGui; - if (!g.LogEnabled) - return; - - va_list args; - va_start(args, fmt); if (g.LogFile) { g.LogBuffer.Buf.resize(0); @@ -9927,9 +10083,29 @@ void ImGui::LogText(const char* fmt, ...) { g.LogBuffer.appendfv(fmt, args); } +} + +void ImGui::LogText(const char* fmt, ...) +{ + ImGuiContext& g = *GImGui; + if (!g.LogEnabled) + return; + + va_list args; + va_start(args, fmt); + LogTextV(g, fmt, args); va_end(args); } +void ImGui::LogTextV(const char* fmt, va_list args) +{ + ImGuiContext& g = *GImGui; + if (!g.LogEnabled) + return; + + LogTextV(g, fmt, args); +} + // Internal version that takes a position to decide on newline placement and pad items according to their depth. // We split text into individual lines to add current tree level padding // FIXME: This code is a little complicated perhaps, considering simplifying the whole system. @@ -10475,9 +10651,9 @@ static void ImGui::UpdateViewportsNewFrame() ImGuiViewportP* viewport = g.Viewports[n]; // Lock down space taken by menu bars and status bars, reset the offset for fucntions like BeginMainMenuBar() to alter them again. - viewport->WorkOffsetMin = viewport->CurrWorkOffsetMin; - viewport->WorkOffsetMax = viewport->CurrWorkOffsetMax; - viewport->CurrWorkOffsetMin = viewport->CurrWorkOffsetMax = ImVec2(0.0f, 0.0f); + viewport->WorkOffsetMin = viewport->BuildWorkOffsetMin; + viewport->WorkOffsetMax = viewport->BuildWorkOffsetMax; + viewport->BuildWorkOffsetMin = viewport->BuildWorkOffsetMax = ImVec2(0.0f, 0.0f); viewport->UpdateWorkRect(); } } @@ -10620,7 +10796,7 @@ static void SetClipboardTextFn_DefaultImpl(void*, const char* text) #endif // Win32 API IME support (for Asian languages, etc.) -#if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) #include #ifdef _MSC_VER @@ -10734,6 +10910,10 @@ static void MetricsHelpMarker(const char* desc) } } +#ifndef IMGUI_DISABLE_DEMO_WINDOWS +namespace ImGui { void ShowFontAtlas(ImFontAtlas* atlas); } +#endif + void ImGui::ShowMetricsWindow(bool* p_open) { if (!Begin("Dear ImGui Metrics/Debugger", p_open)) @@ -10844,7 +11024,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) BulletText("Table 0x%08X (%d columns, in '%s')", table->ID, table->ColumnsCount, table->OuterWindow->Name); if (IsItemHovered()) - GetForegroundDrawList()->AddRect(table->OuterRect.Min - ImVec2(1, 1), table->OuterRect.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, ~0, 2.0f); + GetForegroundDrawList()->AddRect(table->OuterRect.Min - ImVec2(1, 1), table->OuterRect.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f); Indent(); char buf[128]; for (int rect_n = 0; rect_n < TRT_Count; rect_n++) @@ -10859,7 +11039,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImFormatString(buf, IM_ARRAYSIZE(buf), "(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) Col %d %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), column_n, trt_rects_names[rect_n]); Selectable(buf); if (IsItemHovered()) - GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, ~0, 2.0f); + GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f); } } else @@ -10868,7 +11048,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImFormatString(buf, IM_ARRAYSIZE(buf), "(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), trt_rects_names[rect_n]); Selectable(buf); if (IsItemHovered()) - GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, ~0, 2.0f); + GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f); } } Unindent(); @@ -10929,14 +11109,22 @@ void ImGui::ShowMetricsWindow(bool* p_open) } // Details for Tables -#ifdef IMGUI_HAS_TABLE if (TreeNode("Tables", "Tables (%d)", g.Tables.GetSize())) { for (int n = 0; n < g.Tables.GetSize(); n++) DebugNodeTable(g.Tables.GetByIndex(n)); TreePop(); } -#endif // #ifdef IMGUI_HAS_TABLE + + // Details for Fonts +#ifndef IMGUI_DISABLE_DEMO_WINDOWS + ImFontAtlas* atlas = g.IO.Fonts; + if (TreeNode("Fonts", "Fonts (%d)", atlas->Fonts.Size)) + { + ShowFontAtlas(atlas); + TreePop(); + } +#endif // Details for Docking #ifdef IMGUI_HAS_DOCK @@ -10976,14 +11164,12 @@ void ImGui::ShowMetricsWindow(bool* p_open) TreePop(); } -#ifdef IMGUI_HAS_TABLE if (TreeNode("SettingsTables", "Settings packed data: Tables: %d bytes", g.SettingsTables.size())) { for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) DebugNodeTableSettings(settings); TreePop(); } -#endif // #ifdef IMGUI_HAS_TABLE #ifdef IMGUI_HAS_DOCK #endif // #ifdef IMGUI_HAS_DOCK @@ -10999,12 +11185,12 @@ void ImGui::ShowMetricsWindow(bool* p_open) // Misc Details if (TreeNode("Internal state")) { - const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT); + const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Nav", "Clipboard" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT); Text("WINDOWING"); Indent(); Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL"); - Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL"); + Text("HoveredWindow->Root: '%s'", g.HoveredWindow ? g.HoveredWindow->RootWindow->Name : "NULL"); Text("HoveredWindowUnderMovingWindow: '%s'", g.HoveredWindowUnderMovingWindow ? g.HoveredWindowUnderMovingWindow->Name : "NULL"); Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL"); Unindent(); @@ -11057,7 +11243,6 @@ void ImGui::ShowMetricsWindow(bool* p_open) } } -#ifdef IMGUI_HAS_TABLE // Overlay: Display Tables Rectangles if (cfg->ShowTablesRects) { @@ -11074,7 +11259,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, column_n); ImU32 col = (table->HoveredColumnBody == column_n) ? IM_COL32(255, 255, 128, 255) : IM_COL32(255, 0, 128, 255); float thickness = (table->HoveredColumnBody == column_n) ? 3.0f : 1.0f; - draw_list->AddRect(r.Min, r.Max, col, 0.0f, ~0, thickness); + draw_list->AddRect(r.Min, r.Max, col, 0.0f, 0, thickness); } } else @@ -11084,7 +11269,6 @@ void ImGui::ShowMetricsWindow(bool* p_open) } } } -#endif // #ifdef IMGUI_HAS_TABLE #ifdef IMGUI_HAS_DOCK // Overlay: Display Docking info @@ -11192,7 +11376,7 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, { 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. - fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), true, 1.0f); + fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f); fg_draw_list->Flags = backup_flags; } } @@ -11219,7 +11403,7 @@ void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, co for (int n = 0; n < 3; n++, idx_n++) vtxs_rect.Add((triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos)); if (show_mesh) - out_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), true, 1.0f); // In yellow: mesh triangles + out_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f); // In yellow: mesh triangles } // Draw bounding boxes if (show_aabb) @@ -11289,7 +11473,7 @@ void ImGui::DebugNodeViewport(ImGuiViewportP* viewport) viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y, viewport->WorkOffsetMin.x, viewport->WorkOffsetMin.y, viewport->WorkOffsetMax.x, viewport->WorkOffsetMax.y); BulletText("Flags: 0x%04X =%s%s%s", viewport->Flags, - (flags & ImGuiViewportFlags_IsPlatformWindow) ? " IsPlatformWindow" : "", + (flags & ImGuiViewportFlags_IsPlatformWindow) ? " IsPlatformWindow" : "", (flags & ImGuiViewportFlags_IsPlatformMonitor) ? " IsPlatformMonitor" : "", (flags & ImGuiViewportFlags_OwnedByApp) ? " OwnedByApp" : ""); for (int layer_i = 0; layer_i < IM_ARRAYSIZE(viewport->DrawDataBuilder.Layers); layer_i++) @@ -11331,12 +11515,19 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label) 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" : ""); BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1); BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems); - BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask); - BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL"); - if (!window->NavRectRel[0].IsInverted()) - BulletText("NavRectRel[0]: (%.1f,%.1f)(%.1f,%.1f)", window->NavRectRel[0].Min.x, window->NavRectRel[0].Min.y, window->NavRectRel[0].Max.x, window->NavRectRel[0].Max.y); - else - BulletText("NavRectRel[0]: "); + for (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++) + { + ImRect r = window->NavRectRel[layer]; + if (r.Min.x >= r.Max.y && r.Min.y >= r.Max.y) + { + BulletText("NavLastIds[%d]: 0x%08X", layer, window->NavLastIds[layer]); + continue; + } + BulletText("NavLastIds[%d]: 0x%08X at +(%.1f,%.1f)(%.1f,%.1f)", layer, window->NavLastIds[layer], r.Min.x, r.Min.y, r.Max.x, r.Max.y); + if (IsItemHovered()) + GetForegroundDrawList(window)->AddRect(r.Min + window->Pos, r.Max + window->Pos, IM_COL32(255, 255, 0, 255)); + } + BulletText("NavLayersActiveMask: %X, NavLastChildNavWindow: %s", window->DC.NavLayersActiveMask, window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL"); if (window->RootWindow != window) { DebugNodeWindow(window->RootWindow, "RootWindow"); } if (window->ParentWindow != NULL) { DebugNodeWindow(window->ParentWindow, "ParentWindow"); } if (window->DC.ChildWindows.Size > 0) { DebugNodeWindowsList(&window->DC.ChildWindows, "ChildWindows"); } diff --git a/libs/yocto_gui/ext/imgui/imgui.h b/libs/yocto_gui/ext/imgui/imgui.h index 408969ad4..06a610d40 100644 --- a/libs/yocto_gui/ext/imgui/imgui.h +++ b/libs/yocto_gui/ext/imgui/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.81 +// dear imgui, v1.83 // (headers) // Help: @@ -11,10 +11,11 @@ // - FAQ http://dearimgui.org/faq // - Homepage & latest https://github.com/ocornut/imgui // - Releases & changelog https://github.com/ocornut/imgui/releases -// - Gallery https://github.com/ocornut/imgui/issues/3488 (please post your screenshots/video there!) +// - Gallery https://github.com/ocornut/imgui/issues/3793 (please post your screenshots/video there!) +// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there) // - Glossary https://github.com/ocornut/imgui/wiki/Glossary -// - Wiki https://github.com/ocornut/imgui/wiki // - Issues & support https://github.com/ocornut/imgui/issues +// - Discussions https://github.com/ocornut/imgui/discussions /* @@ -27,11 +28,11 @@ Index of this file: // [SECTION] ImGuiStyle // [SECTION] ImGuiIO // [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs) -// [SECTION] Obsolete functions // [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) -// [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData) +// [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData) // [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) // [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport) +// [SECTION] Obsolete functions and types */ @@ -59,8 +60,8 @@ Index of this file: // 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.81" -#define IMGUI_VERSION_NUM 18100 +#define IMGUI_VERSION "1.83" +#define IMGUI_VERSION_NUM 18300 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) #define IMGUI_HAS_TABLE @@ -99,7 +100,20 @@ Index of this file: #define IM_FMTLIST(FMT) #endif +// Disable some of MSVC most aggressive Debug runtime checks in function header/footer (used in some simple/low-level functions) +#if defined(_MSC_VER) && !defined(__clang__) && !defined(IMGUI_DEBUG_PARANOID) +#define IM_MSVC_RUNTIME_CHECKS_OFF __pragma(runtime_checks("",off)) __pragma(check_stack(off)) __pragma(strict_gs_check(push,off)) +#define IM_MSVC_RUNTIME_CHECKS_RESTORE __pragma(runtime_checks("",restore)) __pragma(check_stack()) __pragma(strict_gs_check(pop)) +#else +#define IM_MSVC_RUNTIME_CHECKS_OFF +#define IM_MSVC_RUNTIME_CHECKS_RESTORE +#endif + // Warnings +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6). +#endif #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wold-style-cast" @@ -161,8 +175,8 @@ typedef int ImGuiMouseCursor; // -> enum ImGuiMouseCursor_ // Enum: A typedef int ImGuiSortDirection; // -> enum ImGuiSortDirection_ // Enum: A sorting direction (ascending or descending) typedef int ImGuiStyleVar; // -> enum ImGuiStyleVar_ // Enum: A variable identifier for styling typedef int ImGuiTableBgTarget; // -> enum ImGuiTableBgTarget_ // Enum: A color target for TableSetBgColor() -typedef int ImDrawCornerFlags; // -> enum ImDrawCornerFlags_ // Flags: for ImDrawList::AddRect(), AddRectFilled() etc. -typedef int ImDrawListFlags; // -> enum ImDrawListFlags_ // Flags: for ImDrawList +typedef int ImDrawFlags; // -> enum ImDrawFlags_ // Flags: for ImDrawList functions +typedef int ImDrawListFlags; // -> enum ImDrawListFlags_ // Flags: for ImDrawList instance typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: for ImFontAtlas build typedef int ImGuiBackendFlags; // -> enum ImGuiBackendFlags_ // Flags: for io.BackendFlags typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for InvisibleButton() @@ -193,6 +207,8 @@ typedef void* ImTextureID; // User data for rendering backend to identi typedef unsigned int ImGuiID; // A unique ID used by widgets, typically hashed from a stack of string. typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); // Callback function for ImGui::InputText() typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); // Callback function for ImGui::SetNextWindowSizeConstraints() +typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() +typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() // Character types // (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display) @@ -224,6 +240,7 @@ typedef unsigned long long ImU64; // 64-bit unsigned integer (post C++11) #endif // 2D vector (often used to store positions or sizes) +IM_MSVC_RUNTIME_CHECKS_OFF struct ImVec2 { float x, y; @@ -246,6 +263,7 @@ struct ImVec4 IM_VEC4_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec4. #endif }; +IM_MSVC_RUNTIME_CHECKS_RESTORE //----------------------------------------------------------------------------- // [SECTION] Dear ImGui end-user API functions @@ -255,8 +273,9 @@ struct ImVec4 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. - // None of those functions is reliant on the current context. + // - Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between contexts. + // - DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() + // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for details. IMGUI_API ImGuiContext* CreateContext(ImFontAtlas* shared_font_atlas = NULL); IMGUI_API void DestroyContext(ImGuiContext* ctx = NULL); // NULL = destroy current context IMGUI_API ImGuiContext* GetCurrentContext(); @@ -372,7 +391,7 @@ namespace ImGui IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); // modify a style float variable. always use this if you modify the style after NewFrame(). IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); // modify a style ImVec2 variable. always use this if you modify the style after NewFrame(). IMGUI_API void PopStyleVar(int count = 1); - IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets + IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); // == tab stop enable. Allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets IMGUI_API void PopAllowKeyboardFocus(); IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame. IMGUI_API void PopButtonRepeat(); @@ -503,8 +522,8 @@ namespace ImGui IMGUI_API bool DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); IMGUI_API bool DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); IMGUI_API bool DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", const char* format_max = NULL, ImGuiSliderFlags flags = 0); - IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0); - IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0); + IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed = 1.0f, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0); + IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed = 1.0f, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0); // Widgets: Regular Sliders // - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped and can go off-bounds. @@ -610,13 +629,14 @@ namespace ImGui // - 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 and append to it. // - Use BeginMenu() to create a menu. You can call BeginMenu() multiple time with the same identifier to append more items to it. + // - Not that MenuItem() keyboardshortcuts are displayed as a convenience but _not processed_ by Dear ImGui at the moment. 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 = NULL, bool selected = false, bool enabled = true); // return true when activated. 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 @@ -646,18 +666,20 @@ namespace ImGui // - CloseCurrentPopup(): use inside the BeginPopup()/EndPopup() scope to close manually. // - CloseCurrentPopup() is called by default by Selectable()/MenuItem() when activated (FIXME: need some options). // - Use ImGuiPopupFlags_NoOpenOverExistingPopup to avoid opening a popup if there's already one at the same level. This is equivalent to e.g. testing for !IsAnyPopupOpen() prior to OpenPopup(). + // - Use IsWindowAppearing() after BeginPopup() to tell if a window just opened. IMGUI_API void OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags = 0); // call to mark popup as open (don't call every frame!). - IMGUI_API void OpenPopupOnItemClick(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // helper to open popup when clicked on last item. return true when just opened. (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors) + IMGUI_API void OpenPopup(ImGuiID id, ImGuiPopupFlags popup_flags = 0); // id overload to facilitate calling from nested stacks + IMGUI_API void OpenPopupOnItemClick(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // helper to open popup when clicked on last item. Default to ImGuiPopupFlags_MouseButtonRight == 1. (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors) IMGUI_API void CloseCurrentPopup(); // manually close the popup we have begin-ed into. // Popups: open+begin combined functions helpers // - Helpers to do OpenPopup+BeginPopup where the Open action is triggered by e.g. hovering an item and right-clicking. // - They are convenient to easily create context menus, hence the name. // - IMPORTANT: Notice that BeginPopupContextXXX takes ImGuiPopupFlags just like OpenPopup() and unlike BeginPopup(). For full consistency, we may add ImGuiWindowFlags to the BeginPopupContextXXX functions in the future. // - IMPORTANT: we exceptionally default their flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter, so if you add other flags remember to re-add the ImGuiPopupFlags_MouseButtonRight. - IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked on last item. if you can pass a NULL str_id only if the previous item had an id. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp! + IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked on last item. Use str_id==NULL to associate the popup to previous item. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp! IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1);// open+begin popup when clicked on current window. IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked in void (where there are no windows). - // Popups: test function + // Popups: query functions // - IsPopupOpen(): return true if the popup is open at the current BeginPopup() level of the popup stack. // - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId: return true if any popup is open at the current BeginPopup() level of the popup stack. // - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId + ImGuiPopupFlags_AnyPopupLevel: return true if any popup is open. @@ -701,7 +723,7 @@ namespace ImGui // - You may manually submit headers using TableNextRow() + TableHeader() calls, but this is only useful in // some advanced use cases (e.g. adding custom widgets in header row). // - Use TableSetupScrollFreeze() to lock columns/rows so they stay visible when scrolled. - IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = 0.0f, ImU32 user_id = 0); + IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = 0.0f, ImGuiID user_id = 0); IMGUI_API void TableSetupScrollFreeze(int cols, int rows); // lock columns/rows so they stay visible when scrolled. IMGUI_API void TableHeadersRow(); // submit all headers cells based on data provided to TableSetupColumn() + submit context menu IMGUI_API void TableHeader(const char* label); // submit one header cell manually (rarely used) @@ -711,7 +733,7 @@ namespace ImGui // since last call, or the first time. Make sure to set 'SpecsDirty = false' after sorting, else you may // wastefully sort your data every frame! // - Lifetime: don't hold on this pointer over multiple frames or past any subsequent call to BeginTable(). - IMGUI_API ImGuiTableSortSpecs* TableGetSortSpecs(); // get latest sort specs for the table (NULL if not sorting). + IMGUI_API ImGuiTableSortSpecs* TableGetSortSpecs(); // get latest sort specs for the table (NULL if not sorting). // Tables: Miscellaneous functions // - Functions args 'int column_n' treat the default value of -1 as the same as passing the current column index. IMGUI_API int TableGetColumnCount(); // return number of columns (value passed to BeginTable) @@ -719,6 +741,7 @@ namespace ImGui IMGUI_API int TableGetRowIndex(); // return current row index. IMGUI_API const char* TableGetColumnName(int column_n = -1); // return "" if column didn't have a name declared by TableSetupColumn(). Pass -1 to use current column. IMGUI_API ImGuiTableColumnFlags TableGetColumnFlags(int column_n = -1); // return column flags so you can query their Enabled/Visible/Sorted/Hovered status flags. Pass -1 to use current column. + IMGUI_API void TableSetColumnEnabled(int column_n, bool v);// change enabled/disabled state of a column, set to false to hide the column. Note that end-user can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody) IMGUI_API void TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n = -1); // change the color of a cell, row, or column. See ImGuiTableBgTarget_ flags for details. // Legacy Columns API (2020: prefer using Tables!) @@ -748,10 +771,14 @@ namespace ImGui IMGUI_API void LogFinish(); // stop logging (close file, etc.) IMGUI_API void LogButtons(); // helper to display buttons for logging to tty/file/clipboard IMGUI_API void LogText(const char* fmt, ...) IM_FMTARGS(1); // pass text data straight to log (without being displayed) + IMGUI_API void LogTextV(const char* fmt, va_list args) IM_FMTLIST(1); // Drag and Drop - // - If you stop calling BeginDragDropSource() the payload is preserved however it won't have a preview tooltip (we currently display a fallback "..." tooltip as replacement) - IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); // call when the current item is active. If this return true, you can call SetDragDropPayload() + EndDragDropSource() + // - On source items, call BeginDragDropSource(), if it returns true also call SetDragDropPayload() + EndDragDropSource(). + // - On target candidates, call BeginDragDropTarget(), if it returns true also call AcceptDragDropPayload() + EndDragDropTarget(). + // - If you stop calling BeginDragDropSource() the payload is preserved however it won't have a preview tooltip (we currently display a fallback "..." tooltip, see #1725) + // - An item can be both drag source and drop target. + IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); // call after submitting an item which may be dragged. when this return true, you can call SetDragDropPayload() + EndDragDropSource() IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t sz, ImGuiCond cond = 0); // type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. IMGUI_API void EndDragDropSource(); // only call EndDragDropSource() if BeginDragDropSource() returns true! IMGUI_API bool BeginDragDropTarget(); // call after submitting an item that may receive a payload. If this returns true, you can call AcceptDragDropPayload() + EndDragDropTarget() @@ -769,13 +796,13 @@ namespace ImGui IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a window. IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget. - // Item/Widgets Utilities - // - Most of the functions are referring to the last/previous item we submitted. + // Item/Widgets Utilities and Query Functions + // - Most of the functions are referring to the previous Item that has been submitted. // - See Demo Window under "Widgets->Querying Status" for an interactive visualization of most of those functions. IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags = 0); // is the last item hovered? (and usable, aka not blocked by a popup, etc.). See ImGuiHoveredFlags for more options. IMGUI_API bool IsItemActive(); // is the last item active? (e.g. button being held, text field being edited. This will continuously return true while holding mouse button on an item. Items that don't interact will always return false) IMGUI_API bool IsItemFocused(); // is the last item focused for keyboard/gamepad navigation? - IMGUI_API bool IsItemClicked(ImGuiMouseButton mouse_button = 0); // is the last item clicked? (e.g. button/node just clicked on) == IsMouseClicked(mouse_button) && IsItemHovered() + IMGUI_API bool IsItemClicked(ImGuiMouseButton mouse_button = 0); // is the last item hovered and mouse clicked on? (**) == IsMouseClicked(mouse_button) && IsItemHovered()Important. (**) this it NOT equivalent to the behavior of e.g. Button(). Read comments in function definition. IMGUI_API bool IsItemVisible(); // is the last item visible? (items may be out of sight because of clipping/scrolling) IMGUI_API bool IsItemEdited(); // did the last item modify its underlying value this frame? or was pressed? This is generally the same as the "bool" return value of many widgets. IMGUI_API bool IsItemActivated(); // was the last item just made active (item was previously inactive). @@ -794,7 +821,7 @@ namespace ImGui // - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows. // - In 'docking' branch with multi-viewport enabled, we extend this concept to have multiple active viewports. // - In the future we will extend this concept further to also represent Platform Monitor and support a "no main platform window" operation mode. - IMGUI_API ImGuiViewport* GetMainViewport(); // return primary/default viewport. + IMGUI_API ImGuiViewport* GetMainViewport(); // return primary/default viewport. This can never be NULL. // Miscellaneous Utilities IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped. @@ -864,12 +891,15 @@ namespace ImGui IMGUI_API const char* SaveIniSettingsToMemory(size_t* out_ini_size = NULL); // return a zero-terminated string with the .ini data which you can save by your own mean. call when io.WantSaveIniSettings is set, then save data by your own mean and clear io.WantSaveIniSettings. // Debug Utilities + // - This is used by the IMGUI_CHECKVERSION() macro. IMGUI_API bool DebugCheckVersionAndDataLayout(const char* version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert, size_t sz_drawidx); // This is called by IMGUI_CHECKVERSION() macro. // Memory Allocators - // - All those functions are not reliant on the current context. - // - If you reload the contents of imgui.cpp at runtime, you may need to call SetCurrentContext() + SetAllocatorFunctions() again because we use global storage for those. - IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL); + // - Those functions are not reliant on the current context. + // - DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() + // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. + IMGUI_API void SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void* user_data = NULL); + IMGUI_API void GetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func, ImGuiMemFreeFunc* p_free_func, void** p_user_data); IMGUI_API void* MemAlloc(size_t size); IMGUI_API void MemFree(void* ptr); @@ -936,16 +966,18 @@ enum ImGuiInputTextFlags_ ImGuiInputTextFlags_AllowTabInput = 1 << 10, // Pressing TAB input a '\t' character into the text field ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11, // In multi-line mode, unfocus with Enter, add new line with Ctrl+Enter (default is opposite: unfocus with Ctrl+Enter, add line with Enter). ImGuiInputTextFlags_NoHorizontalScroll = 1 << 12, // Disable following the cursor horizontally - ImGuiInputTextFlags_AlwaysInsertMode = 1 << 13, // Insert mode + ImGuiInputTextFlags_AlwaysOverwrite = 1 << 13, // Overwrite mode ImGuiInputTextFlags_ReadOnly = 1 << 14, // Read-only mode ImGuiInputTextFlags_Password = 1 << 15, // Password mode, display all characters as '*' ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID(). ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input) ImGuiInputTextFlags_CallbackResize = 1 << 18, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) - ImGuiInputTextFlags_CallbackEdit = 1 << 19, // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) - // [Internal] - ImGuiInputTextFlags_Multiline = 1 << 20, // For internal use by InputTextMultiline() - ImGuiInputTextFlags_NoMarkEdited = 1 << 21 // For internal use by functions using InputText() before reformatting data + ImGuiInputTextFlags_CallbackEdit = 1 << 19 // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) + + // Obsolete names (will be removed soon) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiInputTextFlags_AlwaysInsertMode = ImGuiInputTextFlags_AlwaysOverwrite // [renamed in 1.82] name was not matching behavior +#endif }; // Flags for ImGui::TreeNodeEx(), ImGui::CollapsingHeader*() @@ -1616,6 +1648,7 @@ template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p // 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. //----------------------------------------------------------------------------- +IM_MSVC_RUNTIME_CHECKS_OFF template struct ImVector { @@ -1674,6 +1707,7 @@ struct ImVector inline bool find_erase_unsorted(const T& v) { const T* it = find(v); if (it < Data + Size) { erase_unsorted(it); return true; } return false; } inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; return (int)off; } }; +IM_MSVC_RUNTIME_CHECKS_RESTORE //----------------------------------------------------------------------------- // [SECTION] ImGuiStyle @@ -1723,7 +1757,7 @@ struct ImGuiStyle bool AntiAliasedLinesUseTex; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering. Latched at the beginning of the frame (copied to ImDrawList). bool AntiAliasedFill; // Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.). Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList). float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. - float CircleSegmentMaxError; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. + float CircleTessellationMaxError; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. ImVec4 Colors[ImGuiCol_COUNT]; IMGUI_API ImGuiStyle(); @@ -1830,7 +1864,7 @@ struct ImGuiIO bool WantSaveIniSettings; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. Important: clear io.WantSaveIniSettings yourself after saving! bool NavActive; // Keyboard/Gamepad navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag. bool NavVisible; // Keyboard/Gamepad navigation is visible and allowed (will handle ImGuiKey_NavXXX events). - float Framerate; // Application framerate estimate, in frame per second. Solely for convenience. Rolling average estimation based on io.DeltaTime over 120 frames. + float Framerate; // Rough estimate of application framerate, in frame per second. Solely for convenience. Rolling average estimation based on io.DeltaTime over 120 frames. int MetricsRenderVertices; // Vertices output during last call to Render() int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3 int MetricsRenderWindows; // Number of visible windows @@ -1964,51 +1998,6 @@ struct ImGuiTableSortSpecs ImGuiTableSortSpecs() { memset(this, 0, sizeof(*this)); } }; -//----------------------------------------------------------------------------- -// [SECTION] Obsolete functions -// (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details) -// Please keep your copy of dear imgui up to date! Occasionally set '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in imconfig.h to stay ahead. -//----------------------------------------------------------------------------- - -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -namespace ImGui -{ - // OBSOLETED in 1.81 (from February 2021) - IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // Helper to calculate size from items_count and height_in_items - static inline bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)) { return BeginListBox(label, size); } - static inline void ListBoxFooter() { EndListBox(); } - // OBSOLETED in 1.79 (from August 2020) - static inline void OpenPopupContextItem(const char* str_id = NULL, ImGuiMouseButton mb = 1) { OpenPopupOnItemClick(str_id, mb); } // Bool return value removed. Use IsWindowAppearing() in BeginPopup() instead. Renamed in 1.77, renamed back in 1.79. Sorry! - // OBSOLETED in 1.78 (from June 2020) - // Old drag/sliders functions that took a 'float power = 1.0' argument instead of flags. - // For shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`. - IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power); - IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power); - static inline bool DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); } - static inline bool DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power); } - static inline bool DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); } - static inline bool DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power); } - IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power); - IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format, float power); - static inline bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power) { return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); } - static inline bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); } - static inline bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); } - static inline bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); } - // OBSOLETED in 1.77 (from June 2020) - static inline bool BeginPopupContextWindow(const char* str_id, ImGuiMouseButton mb, bool over_items) { return BeginPopupContextWindow(str_id, mb | (over_items ? 0 : ImGuiPopupFlags_NoOpenOverItems)); } - // OBSOLETED in 1.72 (from April 2019) - static inline void TreeAdvanceToLabelPos() { SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()); } - // OBSOLETED in 1.71 (from June 2019) - static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); } - // OBSOLETED in 1.70 (from May 2019) - static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; } - // OBSOLETED in 1.69 (from Mar 2019) - static inline ImDrawList* GetOverlayDrawList() { return GetForegroundDrawList(); } - // OBSOLETED in 1.66 (from Sep 2018) - static inline void SetScrollHere(float center_ratio=0.5f){ SetScrollHereY(center_ratio); } -} -#endif - //----------------------------------------------------------------------------- // [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) //----------------------------------------------------------------------------- @@ -2254,6 +2243,9 @@ struct ImDrawCmd void* UserCallbackData; // 4-8 // The draw callback code can access this. ImDrawCmd() { memset(this, 0, sizeof(*this)); } // Also ensure our padding fields are zeroed + + // Since 1.83: returns ImTextureID associated with this draw call. Warning: DO NOT assume this is always same as 'TextureId' (we will change this function for an upcoming feature) + inline ImTextureID GetTexID() const { return TextureId; } }; // Vertex index, default to 16-bit @@ -2312,21 +2304,27 @@ struct ImDrawListSplitter IMGUI_API void SetCurrentChannel(ImDrawList* draw_list, int channel_idx); }; -enum ImDrawCornerFlags_ +// Flags for ImDrawList functions +// (Legacy: bit 0 must always correspond to ImDrawFlags_Closed to be backward compatible with old API using a bool. Bits 1..3 must be unused) +enum ImDrawFlags_ { - ImDrawCornerFlags_None = 0, - ImDrawCornerFlags_TopLeft = 1 << 0, // 0x1 - ImDrawCornerFlags_TopRight = 1 << 1, // 0x2 - ImDrawCornerFlags_BotLeft = 1 << 2, // 0x4 - ImDrawCornerFlags_BotRight = 1 << 3, // 0x8 - ImDrawCornerFlags_Top = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_TopRight, // 0x3 - ImDrawCornerFlags_Bot = ImDrawCornerFlags_BotLeft | ImDrawCornerFlags_BotRight, // 0xC - ImDrawCornerFlags_Left = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft, // 0x5 - ImDrawCornerFlags_Right = ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight, // 0xA - ImDrawCornerFlags_All = 0xF // In your function calls you may use ~0 (= all bits sets) instead of ImDrawCornerFlags_All, as a convenience + ImDrawFlags_None = 0, + ImDrawFlags_Closed = 1 << 0, // PathStroke(), AddPolyline(): specify that shape should be closed (Important: this is always == 1 for legacy reason) + ImDrawFlags_RoundCornersTopLeft = 1 << 4, // AddRect(), AddRectFilled(), PathRect(): enable rounding top-left corner only (when rounding > 0.0f, we default to all corners). Was 0x01. + ImDrawFlags_RoundCornersTopRight = 1 << 5, // AddRect(), AddRectFilled(), PathRect(): enable rounding top-right corner only (when rounding > 0.0f, we default to all corners). Was 0x02. + ImDrawFlags_RoundCornersBottomLeft = 1 << 6, // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-left corner only (when rounding > 0.0f, we default to all corners). Was 0x04. + ImDrawFlags_RoundCornersBottomRight = 1 << 7, // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-right corner only (when rounding > 0.0f, we default to all corners). Wax 0x08. + ImDrawFlags_RoundCornersNone = 1 << 8, // AddRect(), AddRectFilled(), PathRect(): disable rounding on all corners (when rounding > 0.0f). This is NOT zero, NOT an implicit flag! + ImDrawFlags_RoundCornersTop = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight, + ImDrawFlags_RoundCornersBottom = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, + ImDrawFlags_RoundCornersLeft = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersTopLeft, + ImDrawFlags_RoundCornersRight = ImDrawFlags_RoundCornersBottomRight | ImDrawFlags_RoundCornersTopRight, + ImDrawFlags_RoundCornersAll = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, + ImDrawFlags_RoundCornersDefault_ = ImDrawFlags_RoundCornersAll, // Default to ALL corners if none of the _RoundCornersXX flags are specified. + ImDrawFlags_RoundCornersMask_ = ImDrawFlags_RoundCornersAll | ImDrawFlags_RoundCornersNone }; -// Flags for ImDrawList. Those are set automatically by ImGui:: functions from ImGuiIO settings, and generally not manipulated directly. +// Flags for ImDrawList instance. Those are set automatically by ImGui:: functions from ImGuiIO settings, and generally not manipulated directly. // It is however possible to temporarily alter flags between calls to ImDrawList:: functions. enum ImDrawListFlags_ { @@ -2386,8 +2384,8 @@ struct ImDrawList // In future versions we will use textures to provide cheaper and higher-quality circles. // Use AddNgon() and AddNgonFilled() functions if you need to guaranteed a specific number of sides. 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 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 AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0, float thickness = 1.0f); // a: upper-left, b: lower-right (== upper-left + size) + IMGUI_API void AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0); // 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); IMGUI_API void AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col); @@ -2399,7 +2397,7 @@ struct ImDrawList IMGUI_API void AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments); IMGUI_API void AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL); IMGUI_API void AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL); - IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, bool closed, float thickness); + IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness); IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col); // Note: Anti-aliased filling requires points to be in clockwise order. IMGUI_API void AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0); // Cubic Bezier (4 control points) IMGUI_API void AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments = 0); // Quadratic Bezier (3 control points) @@ -2410,19 +2408,19 @@ struct ImDrawList // - "uv_min" and "uv_max" represent the normalized texture coordinates to use for those corners. Using (0,0)->(1,1) texture coordinates will generally display the entire texture. IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min = ImVec2(0, 0), const ImVec2& uv_max = ImVec2(1, 1), ImU32 col = IM_COL32_WHITE); IMGUI_API void AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1 = ImVec2(0, 0), const ImVec2& uv2 = ImVec2(1, 0), const ImVec2& uv3 = ImVec2(1, 1), const ImVec2& uv4 = ImVec2(0, 1), ImU32 col = IM_COL32_WHITE); - IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); + IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags = 0); // Stateful path API, add points then finish with PathFillConvex() or PathStroke() inline void PathClear() { _Path.Size = 0; } inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); } inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size - 1], &pos, 8) != 0) _Path.push_back(pos); } inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; } // Note: Anti-aliased filling requires points to be in clockwise order. - inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); _Path.Size = 0; } - IMGUI_API void PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments = 10); + inline void PathStroke(ImU32 col, ImDrawFlags flags = 0, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, flags, thickness); _Path.Size = 0; } + IMGUI_API void PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments = 0); IMGUI_API void PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle IMGUI_API void PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0); // Cubic Bezier (4 control points) IMGUI_API void PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments = 0); // Quadratic Bezier (3 control points) - IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); + IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawFlags flags = 0); // Advanced IMGUI_API void AddCallback(ImDrawCallback callback, void* callback_data); // Your rendering function must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles. @@ -2463,6 +2461,9 @@ struct ImDrawList IMGUI_API void _OnChangedClipRect(); IMGUI_API void _OnChangedTextureID(); IMGUI_API void _OnChangedVtxOffset(); + IMGUI_API int _CalcCircleAutoSegmentCount(float radius) const; + IMGUI_API void _PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step); + IMGUI_API void _PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments); }; // All draw data to render a Dear ImGui frame @@ -2631,11 +2632,12 @@ struct ImFontAtlas //------------------------------------------- // You can request arbitrary rectangles to be packed into the atlas, for your own purposes. - // 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 docs/FONTS.md for more details about using colorful icons. - // Note: this API may be redesigned later in order to support multi-monitor varying DPI settings. + // - After calling Build(), you can query the rectangle position and render your pixels. + // - If you render colored output, set 'atlas->TexPixelsUseColors = true' as this may help some backends decide of prefered texture format. + // - 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 docs/FONTS.md for more details about using colorful icons. + // - Note: this API may be redesigned later in order to support multi-monitor varying DPI settings. IMGUI_API int AddCustomRectRegular(int width, int height); IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); ImFontAtlasCustomRect* GetCustomRectByIndex(int index) { IM_ASSERT(index >= 0); return &CustomRects[index]; } @@ -2648,14 +2650,15 @@ struct ImFontAtlas // Members //------------------------------------------- - bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0. + bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. // [Internal] // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you. + bool TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format. unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 int TexWidth; // Texture width calculated during Build(). @@ -2757,7 +2760,7 @@ enum ImGuiViewportFlags_ struct ImGuiViewport { ImGuiViewportFlags Flags; // See ImGuiViewportFlags_ - ImVec2 Pos; // Main Area: Position of the viewport (Dear Imgui coordinates are the same as OS desktop/native coordinates) + ImVec2 Pos; // Main Area: Position of the viewport (Dear ImGui coordinates are the same as OS desktop/native coordinates) ImVec2 Size; // Main Area: Size of the viewport. ImVec2 WorkPos; // Work Area: Position of the viewport minus task bars, menus bars, status bars (>= Pos) ImVec2 WorkSize; // Work Area: Size of the viewport minus task bars, menu bars, status bars (<= Size) @@ -2769,6 +2772,66 @@ struct ImGuiViewport ImVec2 GetWorkCenter() const { return ImVec2(WorkPos.x + WorkSize.x * 0.5f, WorkPos.y + WorkSize.y * 0.5f); } }; +//----------------------------------------------------------------------------- +// [SECTION] Obsolete functions and types +// (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details) +// Please keep your copy of dear imgui up to date! Occasionally set '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in imconfig.h to stay ahead. +//----------------------------------------------------------------------------- + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +namespace ImGui +{ + // OBSOLETED in 1.81 (from February 2021) + IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // Helper to calculate size from items_count and height_in_items + static inline bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)) { return BeginListBox(label, size); } + static inline void ListBoxFooter() { EndListBox(); } + // OBSOLETED in 1.79 (from August 2020) + static inline void OpenPopupContextItem(const char* str_id = NULL, ImGuiMouseButton mb = 1) { OpenPopupOnItemClick(str_id, mb); } // Bool return value removed. Use IsWindowAppearing() in BeginPopup() instead. Renamed in 1.77, renamed back in 1.79. Sorry! + // OBSOLETED in 1.78 (from June 2020) + // Old drag/sliders functions that took a 'float power = 1.0' argument instead of flags. + // For shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`. + IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power); + IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power); + static inline bool DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); } + static inline bool DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power); } + static inline bool DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); } + static inline bool DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power); } + IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power); + IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format, float power); + static inline bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power) { return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); } + static inline bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); } + static inline bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); } + static inline bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); } + // OBSOLETED in 1.77 (from June 2020) + static inline bool BeginPopupContextWindow(const char* str_id, ImGuiMouseButton mb, bool over_items) { return BeginPopupContextWindow(str_id, mb | (over_items ? 0 : ImGuiPopupFlags_NoOpenOverItems)); } + // OBSOLETED in 1.72 (from April 2019) + static inline void TreeAdvanceToLabelPos() { SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()); } + // OBSOLETED in 1.71 (from June 2019) + static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); } + // OBSOLETED in 1.70 (from May 2019) + static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; } + // OBSOLETED in 1.69 (from Mar 2019) + static inline ImDrawList* GetOverlayDrawList() { return GetForegroundDrawList(); } +} + +// OBSOLETED in 1.82 (from Mars 2021): flags for AddRect(), AddRectFilled(), AddImageRounded(), PathRect() +typedef ImDrawFlags ImDrawCornerFlags; +enum ImDrawCornerFlags_ +{ + ImDrawCornerFlags_None = ImDrawFlags_RoundCornersNone, // Was == 0 prior to 1.82, this is now == ImDrawFlags_RoundCornersNone which is != 0 and not implicit + ImDrawCornerFlags_TopLeft = ImDrawFlags_RoundCornersTopLeft, // Was == 0x01 (1 << 0) prior to 1.82. Order matches ImDrawFlags_NoRoundCorner* flag (we exploit this internally). + ImDrawCornerFlags_TopRight = ImDrawFlags_RoundCornersTopRight, // Was == 0x02 (1 << 1) prior to 1.82. + ImDrawCornerFlags_BotLeft = ImDrawFlags_RoundCornersBottomLeft, // Was == 0x04 (1 << 2) prior to 1.82. + ImDrawCornerFlags_BotRight = ImDrawFlags_RoundCornersBottomRight, // Was == 0x08 (1 << 3) prior to 1.82. + ImDrawCornerFlags_All = ImDrawFlags_RoundCornersAll, // Was == 0x0F prior to 1.82 + ImDrawCornerFlags_Top = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_TopRight, + ImDrawCornerFlags_Bot = ImDrawCornerFlags_BotLeft | ImDrawCornerFlags_BotRight, + ImDrawCornerFlags_Left = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft, + ImDrawCornerFlags_Right = ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight +}; + +#endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + //----------------------------------------------------------------------------- #if defined(__clang__) @@ -2777,6 +2840,10 @@ struct ImGuiViewport #pragma GCC diagnostic pop #endif +#ifdef _MSC_VER +#pragma warning (pop) +#endif + // Include imgui_user.h at the end of imgui.h (convenient for user to only explicitly include vanilla imgui.h) #ifdef IMGUI_INCLUDE_IMGUI_USER_H #include "imgui_user.h" diff --git a/libs/yocto_gui/ext/imgui/imgui_demo.cpp b/libs/yocto_gui/ext/imgui/imgui_demo.cpp index 90e91aa05..543730121 100644 --- a/libs/yocto_gui/ext/imgui/imgui_demo.cpp +++ b/libs/yocto_gui/ext/imgui/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.81 +// dear imgui, v1.83 // (demo code) // Help: @@ -6,9 +6,9 @@ // - Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. // - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. // Read imgui.cpp for more details, documentation and comments. -// Get latest version at https://github.com/ocornut/imgui +// Get the latest version at https://github.com/ocornut/imgui -// Message to the person tempted to delete this file when integrating Dear ImGui into their code base: +// Message to the person tempted to delete this file when integrating Dear ImGui into their codebase: // Do NOT remove this file from your project! Think again! It is the most useful reference code that you and other // coders will want to refer to and call. Have the ImGui::ShowDemoWindow() function wired in an always-available // debug menu of your game/app! Removing this file from your project is hindering access to documentation for everyone @@ -16,19 +16,19 @@ // Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow(). // If you want to link core Dear ImGui in your shipped builds but want a thorough guarantee that the demo will not be // linked, you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty. -// In other situation, whenever you have Dear ImGui available you probably want this to be available for reference. +// In another situation, whenever you have Dear ImGui available you probably want this to be available for reference. // Thank you, // -Your beloved friend, imgui_demo.cpp (which you won't delete) // Message to beginner C/C++ programmers about the meaning of the 'static' keyword: -// In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls, +// In this demo code, we frequently use 'static' variables inside functions. A static variable persists across calls, // so it is essentially like a global variable but declared inside the scope of the function. We do this as a way to // gather code and data in the same place, to make the demo source code faster to read, faster to write, and smaller // in size. It also happens to be a convenient way of storing simple UI related information as long as your function // doesn't need to be reentrant or used in multiple threads. This might be a pattern you will want to use in your code, // but most of the real data you would be editing is likely going to be stored outside your functions. -// The Demo code in this file is designed to be easy to copy-and-paste in into your application! +// The Demo code in this file is designed to be easy to copy-and-paste into your application! // Because of this: // - We never omit the ImGui:: prefix when calling functions, even though most code here is in the same namespace. // - We try to declare static variables in the local scope, as close as possible to the code using them. @@ -54,6 +54,7 @@ Index of this file: // - sub section: ShowDemoWindowTables() // - sub section: ShowDemoWindowMisc() // [SECTION] About Window / ShowAboutWindow() +// [SECTION] Font Viewer / ShowFontAtlas() // [SECTION] Style Editor / ShowStyleEditor() // [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() // [SECTION] Example App: Debug Console / ShowExampleAppConsole() @@ -92,7 +93,8 @@ Index of this file: // Visual Studio warnings #ifdef _MSC_VER -#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). #endif // Clang/GCC warnings with -Weverything @@ -135,6 +137,16 @@ Index of this file: #define vsnprintf _vsnprintf #endif +// Format specifiers, printing 64-bit hasn't been decently standardized... +// In a real application you should be using PRId64 and PRIu64 from (non-windows) and on Windows define them yourself. +#ifdef _MSC_VER +#define IM_PRId64 "I64d" +#define IM_PRIu64 "I64u" +#else +#define IM_PRId64 "lld" +#define IM_PRIu64 "llu" +#endif + // Helpers macros // We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste, // but making an exception here as those are largely simplifying code... @@ -913,7 +925,7 @@ static void ShowDemoWindowWidgets() // 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. " + "Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. " "Read docs/FONTS.md 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)"); @@ -1543,7 +1555,7 @@ static void ShowDemoWindowWidgets() // Plot/Graph widgets are not very good. // Consider writing your own, or using a third-party one, see: // - ImPlot https://github.com/epezent/implot - // - others https://github.com/ocornut/imgui/wiki/Useful-Widgets + // - others https://github.com/ocornut/imgui/wiki/Useful-Extensions if (ImGui::TreeNode("Plots Widgets")) { static bool animate = true; @@ -1592,7 +1604,7 @@ static void ShowDemoWindowWidgets() }; static int func_type = 0, display_count = 70; ImGui::Separator(); - ImGui::SetNextItemWidth(100); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); ImGui::Combo("func", &func_type, "Sin\0Saw\0"); ImGui::SameLine(); ImGui::SliderInt("Sample count", &display_count, 1, 400); @@ -1918,12 +1930,12 @@ static void ShowDemoWindowWidgets() ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u"); ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u"); ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u"); - ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%I64d"); - ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%I64d"); - ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%I64d"); - ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%I64u ms"); - ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%I64u ms"); - ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%I64u ms"); + ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%" IM_PRId64); + ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" IM_PRId64); + ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" IM_PRId64); + ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" IM_PRIu64 " ms"); + ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" IM_PRIu64 " ms"); + ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" IM_PRIu64 " ms"); ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one); ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic); ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e"); @@ -1932,12 +1944,12 @@ static void ShowDemoWindowWidgets() ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams"); ImGui::Text("Sliders (reverse)"); - ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d"); - ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u"); + ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d"); + ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u"); ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d"); ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u"); - ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%I64d"); - ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%I64u ms"); + ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%" IM_PRId64); + ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" IM_PRIu64 " ms"); static bool inputs_step = true; ImGui::Text("Inputs"); @@ -2382,7 +2394,7 @@ static void ShowDemoWindowLayout() // the POV of the parent window). See 'Demo->Querying Status (Active/Focused/Hovered etc.)' for details. { static int offset_x = 0; - ImGui::SetNextItemWidth(100); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x); @@ -2404,15 +2416,15 @@ static void ShowDemoWindowLayout() if (ImGui::TreeNode("Widgets Width")) { + static float f = 0.0f; + static bool show_indented_items = true; + ImGui::Checkbox("Show indented items", &show_indented_items); + // Use SetNextItemWidth() to set the width of a single upcoming item. // Use PushItemWidth()/PopItemWidth() to set the width of a group of items. // In real code use you'll probably want to choose width values that are proportional to your font size // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc. - static float f = 0.0f; - static bool show_indented_items = true; - ImGui::Checkbox("Show indented items", &show_indented_items); - ImGui::Text("SetNextItemWidth/PushItemWidth(100)"); ImGui::SameLine(); HelpMarker("Fixed width."); ImGui::PushItemWidth(100); @@ -2828,6 +2840,8 @@ static void ShowDemoWindowLayout() { for (int item = 0; item < 100; item++) { + if (item > 0) + ImGui::SameLine(); if (enable_track && item == track_item) { ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); @@ -2837,7 +2851,6 @@ static void ShowDemoWindowLayout() { ImGui::Text("Item %d", item); } - ImGui::SameLine(); } } float scroll_x = ImGui::GetScrollX(); @@ -3181,46 +3194,84 @@ static void ShowDemoWindowPopups() if (ImGui::TreeNode("Context menus")) { + HelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier."); + // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: - // if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right)) - // OpenPopup(id); - // return BeginPopup(id); - // For more advanced uses you may want to replicate and customize this code. - // See details in BeginPopupContextItem(). - static float value = 0.5f; - ImGui::Text("Value = %.3f (<-- right-click here)", value); - if (ImGui::BeginPopupContextItem("item context menu")) - { - if (ImGui::Selectable("Set to zero")) value = 0.0f; - if (ImGui::Selectable("Set to PI")) value = 3.1415f; - ImGui::SetNextItemWidth(-FLT_MIN); - ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f); - ImGui::EndPopup(); + // if (id == 0) + // id = GetItemID(); // Use last item id + // if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right)) + // OpenPopup(id); + // return BeginPopup(id); + // For advanced advanced uses you may want to replicate and customize this code. + // See more details in BeginPopupContextItem(). + + // Example 1 + // When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(), + // and BeginPopupContextItem() will use the last item ID as the popup ID. + { + const char* names[5] = { "Label1", "Label2", "Label3", "Label4", "Label5" }; + for (int n = 0; n < 5; n++) + { + ImGui::Selectable(names[n]); + if (ImGui::BeginPopupContextItem()) // <-- use last item id as popup id + { + ImGui::Text("This a popup for \"%s\"!", names[n]); + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Right-click to open popup"); + } } - // We can also use OpenPopupOnItemClick() which is the same as BeginPopupContextItem() but without the - // Begin() call. So here we will make it that clicking on the text field with the right mouse button (1) - // will toggle the visibility of the popup above. - ImGui::Text("(You can also right-click me to open the same popup as above.)"); - ImGui::OpenPopupOnItemClick("item context menu", 1); - - // When used after an item that has an ID (e.g.Button), we can skip providing an ID to BeginPopupContextItem(). - // BeginPopupContextItem() will use the last item ID as the popup ID. - // In addition here, we want to include your editable label inside the button label. - // We use the ### operator to override the ID (read FAQ about ID for details) - static char name[32] = "Label1"; - char buf[64]; - sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label - ImGui::Button(buf); - if (ImGui::BeginPopupContextItem()) + // Example 2 + // Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem(). + // Using an explicit identifier is also convenient if you want to activate the popups from different locations. { - ImGui::Text("Edit name:"); - ImGui::InputText("##edit", name, IM_ARRAYSIZE(name)); - if (ImGui::Button("Close")) - ImGui::CloseCurrentPopup(); - ImGui::EndPopup(); + HelpMarker("Text() elements don't have stable identifiers so we need to provide one."); + static float value = 0.5f; + ImGui::Text("Value = %.3f <-- (1) right-click this value", value); + if (ImGui::BeginPopupContextItem("my popup")) + { + if (ImGui::Selectable("Set to zero")) value = 0.0f; + if (ImGui::Selectable("Set to PI")) value = 3.1415f; + ImGui::SetNextItemWidth(-FLT_MIN); + ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f); + ImGui::EndPopup(); + } + + // We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup. + // Here we make it that right-clicking this other text element opens the same popup as above. + // The popup itself will be submitted by the code above. + ImGui::Text("(2) Or right-click this text"); + ImGui::OpenPopupOnItemClick("my popup", ImGuiPopupFlags_MouseButtonRight); + + // Back to square one: manually open the same popup. + if (ImGui::Button("(3) Or click this button")) + ImGui::OpenPopup("my popup"); + } + + // Example 3 + // When using BeginPopupContextItem() with an implicit identifier (NULL == use last item ID), + // we need to make sure your item identifier is stable. + // In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ). + { + HelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator."); + static char name[32] = "Label1"; + char buf[64]; + sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label + ImGui::Button(buf); + if (ImGui::BeginPopupContextItem()) + { + ImGui::Text("Edit name:"); + ImGui::InputText("##edit", name, IM_ARRAYSIZE(name)); + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + ImGui::SameLine(); ImGui::Text("(<-- right-click here)"); } - ImGui::SameLine(); ImGui::Text("(<-- right-click here)"); ImGui::TreePop(); } @@ -4856,6 +4907,9 @@ static void ShowDemoWindowTables() ImGui::TreePop(); } + // In this example we'll expose most table flags and settings. + // For specific flags and settings refer to the corresponding section for more detailed explanation. + // This section is mostly useful to experiment with combining certain flags or settings with each others. //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // [DEBUG] if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); @@ -4994,7 +5048,7 @@ static void ShowDemoWindowTables() ImGui::TreePop(); } - // Recreate/reset item list if we changed the number of items + // Update item list if we changed the number of items static ImVector items; static ImVector selection; static bool items_need_sort = false; @@ -5016,6 +5070,7 @@ static void ShowDemoWindowTables() ImVec2 table_scroll_cur, table_scroll_max; // For debug display const ImDrawList* table_draw_list = NULL; // " + // Submit table const float inner_width_to_use = (flags & ImGuiTableFlags_ScrollX) ? inner_width_with_scroll : 0.0f; if (ImGui::BeginTable("table_advanced", 6, flags, outer_size_enabled ? outer_size_value : ImVec2(0, 0), inner_width_to_use)) { @@ -5074,9 +5129,9 @@ static void ShowDemoWindowTables() const bool item_is_selected = selection.contains(item->ID); ImGui::PushID(item->ID); ImGui::TableNextRow(ImGuiTableRowFlags_None, row_min_height); - ImGui::TableNextColumn(); // For the demo purpose we can select among different type of items submitted in the first column + ImGui::TableSetColumnIndex(0); char label[32]; sprintf(label, "%04d", item->ID); if (contents_type == CT_Text) @@ -5107,14 +5162,14 @@ static void ShowDemoWindowTables() } } - if (ImGui::TableNextColumn()) + if (ImGui::TableSetColumnIndex(1)) ImGui::TextUnformatted(item->Name); // Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity, // and we are currently sorting on the column showing the Quantity. // To avoid triggering a sort while holding the button, we only trigger it when the button has been released. // You will probably need a more advanced system in your code if you want to automatically sort when a specific entry changes. - if (ImGui::TableNextColumn()) + if (ImGui::TableSetColumnIndex(2)) { if (ImGui::SmallButton("Chop")) { item->Quantity += 1; } if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; } @@ -5123,16 +5178,16 @@ static void ShowDemoWindowTables() if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; } } - if (ImGui::TableNextColumn()) + if (ImGui::TableSetColumnIndex(3)) ImGui::Text("%d", item->Quantity); - ImGui::TableNextColumn(); + ImGui::TableSetColumnIndex(4); if (show_wrapped_text) ImGui::TextWrapped("Lorem ipsum dolor sit amet"); else ImGui::Text("Lorem ipsum dolor sit amet"); - if (ImGui::TableNextColumn()) + if (ImGui::TableSetColumnIndex(5)) ImGui::Text("1234"); ImGui::PopID(); @@ -5399,29 +5454,34 @@ static void ShowDemoWindowMisc() ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos); ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible); - // Display Keyboard/Mouse state - if (ImGui::TreeNode("Keyboard, Mouse & Navigation State")) + // Display Mouse state + if (ImGui::TreeNode("Mouse State")) { if (ImGui::IsMousePosValid()) ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); else ImGui::Text("Mouse pos: "); ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); - ImGui::Text("Mouse down:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } - ImGui::Text("Mouse clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } - ImGui::Text("Mouse dblclick:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDoubleClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } - ImGui::Text("Mouse released:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } + ImGui::Text("Mouse down:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } + ImGui::Text("Mouse clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } + ImGui::Text("Mouse dblclick:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDoubleClicked(i)){ ImGui::SameLine(); ImGui::Text("b%d", i); } + ImGui::Text("Mouse released:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); + ImGui::Text("Pen Pressure: %.1f", io.PenPressure); // Note: currently unused + ImGui::TreePop(); + } - ImGui::Text("Keys down:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (io.KeysDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("%d (0x%X) (%.02f secs)", i, i, io.KeysDownDuration[i]); } - ImGui::Text("Keys pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } - ImGui::Text("Keys release:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } + // Display Keyboard/Mouse state + if (ImGui::TreeNode("Keyboard & Navigation State")) + { + ImGui::Text("Keys down:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyDown(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X) (%.02f secs)", i, i, io.KeysDownDuration[i]); } + ImGui::Text("Keys pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } + ImGui::Text("Keys release:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); - ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. + ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. - ImGui::Text("NavInputs down:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputs[i]); } + ImGui::Text("NavInputs down:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f (%.02f secs)", i, io.NavInputs[i], io.NavInputsDownDuration[i]); } ImGui::Text("NavInputs pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] == 0.0f) { ImGui::SameLine(); ImGui::Text("[%d]", i); } - ImGui::Text("NavInputs duration:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputsDownDuration[i]); } ImGui::Button("Hovering me sets the\nkeyboard capture flag"); if (ImGui::IsItemHovered()) @@ -5430,7 +5490,6 @@ static void ShowDemoWindowMisc() ImGui::Button("Holding me clears the\nthe keyboard capture flag"); if (ImGui::IsItemActive()) ImGui::CaptureKeyboardFromApp(false); - ImGui::TreePop(); } @@ -5443,7 +5502,7 @@ static void ShowDemoWindowMisc() ImGui::InputText("3", buf, IM_ARRAYSIZE(buf)); ImGui::PushAllowKeyboardFocus(false); ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf)); - //ImGui::SameLine(); HelpMarker("Use ImGui::PushAllowKeyboardFocus(bool) to disable tabbing through certain widgets."); + ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab."); ImGui::PopAllowKeyboardFocus(); ImGui::InputText("5", buf, IM_ARRAYSIZE(buf)); ImGui::TreePop(); @@ -5469,6 +5528,7 @@ static void ShowDemoWindowMisc() if (focus_3) ImGui::SetKeyboardFocusHere(); ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf)); if (ImGui::IsItemActive()) has_focus = 3; + ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab."); ImGui::PopAllowKeyboardFocus(); if (has_focus) @@ -5684,31 +5744,15 @@ void ImGui::ShowAboutWindow(bool* p_open) } //----------------------------------------------------------------------------- -// [SECTION] Style Editor / ShowStyleEditor() +// [SECTION] Font viewer / ShowFontAtlas() //----------------------------------------------------------------------------- -// - ShowStyleSelector() // - ShowFontSelector() -// - ShowStyleEditor() +// - ShowFont() +// - ShowFontAtlas() //----------------------------------------------------------------------------- -// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. -// Here we use the simplified Combo() api that packs items into a single literal string. -// Useful for quick combo boxes where the choices are known locally. -bool ImGui::ShowStyleSelector(const char* label) -{ - static int style_idx = -1; - if (ImGui::Combo(label, &style_idx, "Dark\0Light\0Classic\0")) - { - switch (style_idx) - { - case 0: ImGui::StyleColorsDark(); break; - case 1: ImGui::StyleColorsLight(); break; - case 2: ImGui::StyleColorsClassic(); break; - } - return true; - } - return false; -} +// This isn't worth putting in public API but we want Metrics to use it +namespace ImGui { void ShowFontAtlas(ImFontAtlas* atlas); } // Demo helper function to select among loaded fonts. // Here we use the regular BeginCombo()/EndCombo() api which is more the more flexible one. @@ -5737,7 +5781,7 @@ void ImGui::ShowFontSelector(const char* label) } // [Internal] Display details for a single font, called by ShowStyleEditor(). -static void NodeFont(ImFont* font) +static void ShowFont(ImFont* font) { ImGuiIO& io = ImGui::GetIO(); ImGuiStyle& style = ImGui::GetStyle(); @@ -5747,9 +5791,13 @@ static void NodeFont(ImFont* font) if (!font_details_opened) return; + // Display preview text ImGui::PushFont(font); ImGui::Text("The quick brown fox jumps over the lazy dog"); ImGui::PopFont(); + + // Display details + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font ImGui::SameLine(); HelpMarker( "Note than the default embedded font is NOT meant to be scaled.\n\n" @@ -5767,9 +5815,10 @@ static void NodeFont(ImFont* font) if (const ImFontConfig* cfg = &font->ConfigData[config_i]) ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y); + + // Display all glyphs of the fonts in separate pages of 256 characters if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) { - // Display all glyphs of the fonts in separate pages of 256 characters const ImU32 glyph_col = ImGui::GetColorU32(ImGuiCol_Text); for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) { @@ -5824,6 +5873,50 @@ static void NodeFont(ImFont* font) ImGui::TreePop(); } +void ImGui::ShowFontAtlas(ImFontAtlas* atlas) +{ + for (int i = 0; i < atlas->Fonts.Size; i++) + { + ImFont* font = atlas->Fonts[i]; + ImGui::PushID(font); + ShowFont(font); + ImGui::PopID(); + } + if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) + { + ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); + ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); + ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), tint_col, border_col); + ImGui::TreePop(); + } +} + +//----------------------------------------------------------------------------- +// [SECTION] Style Editor / ShowStyleEditor() +//----------------------------------------------------------------------------- +// - ShowStyleSelector() +// - ShowStyleEditor() +//----------------------------------------------------------------------------- + +// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. +// Here we use the simplified Combo() api that packs items into a single literal string. +// Useful for quick combo boxes where the choices are known locally. +bool ImGui::ShowStyleSelector(const char* label) +{ + static int style_idx = -1; + if (ImGui::Combo(label, &style_idx, "Dark\0Light\0Classic\0")) + { + switch (style_idx) + { + case 0: ImGui::StyleColorsDark(); break; + case 1: ImGui::StyleColorsLight(); break; + case 2: ImGui::StyleColorsClassic(); break; + } + return true; + } + return false; +} + void ImGui::ShowStyleEditor(ImGuiStyle* ref) { // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to @@ -5980,21 +6073,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGuiIO& io = ImGui::GetIO(); ImFontAtlas* atlas = io.Fonts; HelpMarker("Read FAQ and docs/FONTS.md for details on font loading."); - ImGui::PushItemWidth(120); - for (int i = 0; i < atlas->Fonts.Size; i++) - { - ImFont* font = atlas->Fonts[i]; - ImGui::PushID(font); - NodeFont(font); - ImGui::PopID(); - } - if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) - { - ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); - ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); - ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), tint_col, border_col); - ImGui::TreePop(); - } + ImGui::ShowFontAtlas(atlas); // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below. // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds). @@ -6006,6 +6085,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n" "Using those settings here will give you poor quality results."); static float window_scale = 1.0f; + ImGui::PushItemWidth(ImGui::GetFontSize() * 8); if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window ImGui::SetWindowFontScale(window_scale); ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything @@ -6025,27 +6105,47 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering)."); ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill); - ImGui::PushItemWidth(100); + ImGui::PushItemWidth(ImGui::GetFontSize() * 8); ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f"); if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f; // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles. - ImGui::DragFloat("Circle Segment Max Error", &style.CircleSegmentMaxError, 0.01f, 0.10f, 10.0f, "%.2f"); + ImGui::DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp); if (ImGui::IsItemActive()) { ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos()); ImGui::BeginTooltip(); - ImVec2 p = ImGui::GetCursorScreenPos(); + ImGui::TextUnformatted("(R = radius, N = number of segments)"); + ImGui::Spacing(); ImDrawList* draw_list = ImGui::GetWindowDrawList(); - float RAD_MIN = 10.0f, RAD_MAX = 80.0f; - float off_x = 10.0f; - for (int n = 0; n < 7; n++) + const float min_widget_width = ImGui::CalcTextSize("N: MMM\nR: MMM").x; + for (int n = 0; n < 8; n++) { - const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (7.0f - 1.0f); - draw_list->AddCircle(ImVec2(p.x + off_x + rad, p.y + RAD_MAX), rad, ImGui::GetColorU32(ImGuiCol_Text), 0); - off_x += 10.0f + rad * 2.0f; + const float RAD_MIN = 5.0f; + const float RAD_MAX = 70.0f; + const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (8.0f - 1.0f); + + ImGui::BeginGroup(); + + ImGui::Text("R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(rad)); + + const float canvas_width = IM_MAX(min_widget_width, rad * 2.0f); + const float offset_x = floorf(canvas_width * 0.5f); + const float offset_y = floorf(RAD_MAX); + + const ImVec2 p1 = ImGui::GetCursorScreenPos(); + draw_list->AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text)); + ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2)); + + /* + const ImVec2 p2 = ImGui::GetCursorScreenPos(); + draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text)); + ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2)); + */ + + ImGui::EndGroup(); + ImGui::SameLine(); } - ImGui::Dummy(ImVec2(off_x, RAD_MAX * 2.0f)); ImGui::EndTooltip(); } ImGui::SameLine(); @@ -7167,9 +7267,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) const ImVec2 p = ImGui::GetCursorScreenPos(); const ImU32 col = ImColor(colf); const float spacing = 10.0f; - const ImDrawCornerFlags corners_none = 0; - const ImDrawCornerFlags corners_all = ImDrawCornerFlags_All; - const ImDrawCornerFlags corners_tl_br = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight; + const ImDrawFlags corners_tl_br = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomRight; const float rounding = sz / 5.0f; const int circle_segments = circle_segments_override ? circle_segments_override_v : 0; const int curve_segments = curve_segments_override ? curve_segments_override_v : 0; @@ -7181,8 +7279,8 @@ static void ShowExampleAppCustomRendering(bool* p_open) float th = (n == 0) ? 1.0f : thickness; draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle - draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, corners_none, th); x += sz + spacing; // Square - draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_all, th); x += sz + spacing; // Square with all rounded corners + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, ImDrawFlags_None, th); x += sz + spacing; // Square + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, ImDrawFlags_None, th); x += sz + spacing; // Square with all rounded corners draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners draw_list->AddTriangle(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col, th);x += sz + spacing; // Triangle //draw_list->AddTriangle(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col, th);x+= sz*0.4f + spacing; // Thin triangle diff --git a/libs/yocto_gui/ext/imgui/imgui_draw.cpp b/libs/yocto_gui/ext/imgui/imgui_draw.cpp index 5c11a5b32..54490ed1a 100644 --- a/libs/yocto_gui/ext/imgui/imgui_draw.cpp +++ b/libs/yocto_gui/ext/imgui/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.81 +// dear imgui, v1.83 // (drawing and font code) /* @@ -54,9 +54,12 @@ Index of this file: // Visual Studio warnings #ifdef _MSC_VER -#pragma warning (disable: 4127) // condition expression is constant -#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) -#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#pragma warning (disable: 6255) // [Static Analyzer] _alloca indicates failure by raising a stack overflow exception. Consider using _malloca instead. +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). [MSVC Static Analyzer) #endif // Clang/GCC warnings with -Weverything @@ -105,6 +108,9 @@ namespace IMGUI_STB_NAMESPACE #ifdef _MSC_VER #pragma warning (push) #pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration +#pragma warning (disable: 6011) // (stb_rectpack) Dereferencing NULL pointer 'cur->next'. +#pragma warning (disable: 6385) // (stb_truetype) Reading invalid data from 'buffer': the readable size is '_Old_3`kernel_width' bytes, but '3' bytes may be read. +#pragma warning (disable: 28182) // (stb_rectpack) Dereferencing NULL pointer. 'cur' contains the same NULL value as 'cur->next' did. #endif #if defined(__clang__) @@ -145,7 +151,7 @@ namespace IMGUI_STB_NAMESPACE #define STBTT_sqrt(x) ImSqrt(x) #define STBTT_pow(x,y) ImPow(x,y) #define STBTT_fabs(x) ImFabs(x) -#define STBTT_ifloor(x) ((int)ImFloorStd(x)) +#define STBTT_ifloor(x) ((int)ImFloorSigned(x)) #define STBTT_iceil(x) ((int)ImCeil(x)) #define STBTT_STATIC #define STB_TRUETYPE_IMPLEMENTATION @@ -374,19 +380,22 @@ ImDrawListSharedData::ImDrawListSharedData() const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(ArcFastVtx); ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a)); } + ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError); } -void ImDrawListSharedData::SetCircleSegmentMaxError(float max_error) +void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error) { if (CircleSegmentMaxError == max_error) return; + + IM_ASSERT(max_error > 0.0f); CircleSegmentMaxError = max_error; for (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++) { const float radius = (float)i; - const int segment_count = (i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError) : 0; - CircleSegmentCounts[i] = (ImU8)ImMin(segment_count, 255); + CircleSegmentCounts[i] = (ImU8)((i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError) : 0); } + ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError); } // Initialize before use in a new frame. We always have a command ready in the buffer. @@ -543,6 +552,16 @@ void ImDrawList::_OnChangedVtxOffset() curr_cmd->VtxOffset = _CmdHeader.VtxOffset; } +int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const +{ + // Automatic segment count + const int radius_idx = (int)(radius + 0.999999f); // ceil to never reduce accuracy + if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts)) + return _Data->CircleSegmentCounts[radius_idx]; // Use cached value + else + return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError); +} + // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect) { @@ -675,16 +694,18 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c // On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to optimize debug/non-inlined builds. // Those macros expects l-values. -#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = 1.0f / ImSqrt(d2); VX *= inv_len; VY *= inv_len; } } while (0) -#define IM_FIXNORMAL2F(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 < 0.5f) d2 = 0.5f; float inv_lensq = 1.0f / d2; VX *= inv_lensq; VY *= inv_lensq; } while (0) +#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = ImRsqrt(d2); VX *= inv_len; VY *= inv_len; } } while (0) +#define IM_FIXNORMAL2F_MAX_INVLEN2 100.0f // 500.0f (see #4053, #3366) +#define IM_FIXNORMAL2F(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 > 0.000001f) { float inv_len2 = 1.0f / d2; if (inv_len2 > IM_FIXNORMAL2F_MAX_INVLEN2) inv_len2 = IM_FIXNORMAL2F_MAX_INVLEN2; VX *= inv_len2; VY *= inv_len2; } } while (0) // TODO: Thickness anti-aliased lines cap are missing their AA fringe. // We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds. -void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness) +void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, ImDrawFlags flags, float thickness) { if (points_count < 2) return; + const bool closed = (flags & ImDrawFlags_Closed) != 0; const ImVec2 opaque_uv = _Data->TexUvWhitePixel; const int count = closed ? points_count : points_count - 1; // The number of line segments we need to draw const bool thick_line = (thickness > _FringeScale); @@ -1016,38 +1037,105 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun } } -void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12) +void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step) { - if (radius == 0.0f) + if (radius <= 0.0f) { _Path.push_back(center); return; } - IM_ASSERT(a_min_of_12 <= a_max_of_12); - // For legacy reason the PathArcToFast() always takes angles where 2*PI is represented by 12, - // but it is possible to set IM_DRAWLIST_ARCFAST_TESSELATION_MULTIPLIER to a higher value. This should compile to a no-op otherwise. -#if IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER != 1 - a_min_of_12 *= IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER; - a_max_of_12 *= IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER; -#endif + // Calculate arc auto segment step size + if (a_step <= 0) + a_step = IM_DRAWLIST_ARCFAST_SAMPLE_MAX / _CalcCircleAutoSegmentCount(radius); + + // Make sure we never do steps larger than one quarter of the circle + a_step = ImClamp(a_step, 1, IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4); + + const int sample_range = ImAbs(a_max_sample - a_min_sample); + const int a_next_step = a_step; + + int samples = sample_range + 1; + bool extra_max_sample = false; + if (a_step > 1) + { + samples = sample_range / a_step + 1; + const int overstep = sample_range % a_step; + + if (overstep > 0) + { + extra_max_sample = true; + samples++; + + // When we have overstep to avoid awkwardly looking one long line and one tiny one at the end, + // distribute first step range evenly between them by reducing first step size. + if (sample_range > 0) + a_step -= (a_step - overstep) / 2; + } + } + + _Path.resize(_Path.Size + samples); + ImVec2* out_ptr = _Path.Data + (_Path.Size - samples); + + int sample_index = a_min_sample; + if (sample_index < 0 || sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX) + { + sample_index = sample_index % IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + if (sample_index < 0) + sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + } - _Path.reserve(_Path.Size + (a_max_of_12 - a_min_of_12 + 1)); - for (int a = a_min_of_12; a <= a_max_of_12; a++) + if (a_max_sample >= a_min_sample) + { + for (int a = a_min_sample; a <= a_max_sample; a += a_step, sample_index += a_step, a_step = a_next_step) + { + // a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more + if (sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX) + sample_index -= IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + + const ImVec2 s = _Data->ArcFastVtx[sample_index]; + out_ptr->x = center.x + s.x * radius; + out_ptr->y = center.y + s.y * radius; + out_ptr++; + } + } + else { - const ImVec2& c = _Data->ArcFastVtx[a % IM_ARRAYSIZE(_Data->ArcFastVtx)]; - _Path.push_back(ImVec2(center.x + c.x * radius, center.y + c.y * radius)); + for (int a = a_min_sample; a >= a_max_sample; a -= a_step, sample_index -= a_step, a_step = a_next_step) + { + // a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more + if (sample_index < 0) + sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + + const ImVec2 s = _Data->ArcFastVtx[sample_index]; + out_ptr->x = center.x + s.x * radius; + out_ptr->y = center.y + s.y * radius; + out_ptr++; + } } + + if (extra_max_sample) + { + int normalized_max_sample = a_max_sample % IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + if (normalized_max_sample < 0) + normalized_max_sample += IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + + const ImVec2 s = _Data->ArcFastVtx[normalized_max_sample]; + out_ptr->x = center.x + s.x * radius; + out_ptr->y = center.y + s.y * radius; + out_ptr++; + } + + IM_ASSERT_PARANOID(_Path.Data + _Path.Size == out_ptr); } -void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments) +void ImDrawList::_PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments) { - if (radius == 0.0f) + if (radius <= 0.0f) { _Path.push_back(center); return; } - IM_ASSERT(a_min <= a_max); // Note that we are adding a point at both a_min and a_max. // If you are trying to draw a full closed circle you don't want the overlapping points! @@ -1059,6 +1147,67 @@ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, floa } } +// 0: East, 3: South, 6: West, 9: North, 12: East +void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12) +{ + if (radius <= 0.0f) + { + _Path.push_back(center); + return; + } + _PathArcToFastEx(center, radius, a_min_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, a_max_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, 0); +} + +void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments) +{ + if (radius <= 0.0f) + { + _Path.push_back(center); + return; + } + + if (num_segments > 0) + { + _PathArcToN(center, radius, a_min, a_max, num_segments); + return; + } + + // Automatic segment count + if (radius <= _Data->ArcFastRadiusCutoff) + { + const bool a_is_reverse = a_max < a_min; + + // We are going to use precomputed values for mid samples. + // Determine first and last sample in lookup table that belong to the arc. + const float a_min_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_min / (IM_PI * 2.0f); + const float a_max_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_max / (IM_PI * 2.0f); + + const int a_min_sample = a_is_reverse ? (int)ImFloorSigned(a_min_sample_f) : (int)ImCeil(a_min_sample_f); + const int a_max_sample = a_is_reverse ? (int)ImCeil(a_max_sample_f) : (int)ImFloorSigned(a_max_sample_f); + const int a_mid_samples = a_is_reverse ? ImMax(a_min_sample - a_max_sample, 0) : ImMax(a_max_sample - a_min_sample, 0); + + const float a_min_segment_angle = a_min_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + const float a_max_segment_angle = a_max_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + const bool a_emit_start = (a_min_segment_angle - a_min) != 0.0f; + const bool a_emit_end = (a_max - a_max_segment_angle) != 0.0f; + + _Path.reserve(_Path.Size + (a_mid_samples + 1 + (a_emit_start ? 1 : 0) + (a_emit_end ? 1 : 0))); + if (a_emit_start) + _Path.push_back(ImVec2(center.x + ImCos(a_min) * radius, center.y + ImSin(a_min) * radius)); + if (a_mid_samples > 0) + _PathArcToFastEx(center, radius, a_min_sample, a_max_sample, 0); + if (a_emit_end) + _Path.push_back(ImVec2(center.x + ImCos(a_max) * radius, center.y + ImSin(a_max) * radius)); + } + else + { + const float arc_length = ImAbs(a_max - a_min); + const int circle_segment_count = _CalcCircleAutoSegmentCount(radius); + const int arc_segment_count = ImMax((int)ImCeil(circle_segment_count * arc_length / (IM_PI * 2.0f)), (int)(2.0f * IM_PI / arc_length)); + _PathArcToN(center, radius, a_min, a_max, arc_segment_count); + } +} + ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t) { float u = 1.0f - t; @@ -1152,12 +1301,47 @@ void ImDrawList::PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, } } -void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawCornerFlags rounding_corners) +IM_STATIC_ASSERT(ImDrawFlags_RoundCornersTopLeft == (1 << 4)); +static inline ImDrawFlags FixRectCornerFlags(ImDrawFlags flags) +{ +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + // Legacy Support for hard coded ~0 (used to be a suggested equivalent to ImDrawCornerFlags_All) + // ~0 --> ImDrawFlags_RoundCornersAll or 0 + if (flags == ~0) + return ImDrawFlags_RoundCornersAll; + + // Legacy Support for hard coded 0x01 to 0x0F (matching 15 out of 16 old flags combinations) + // 0x01 --> ImDrawFlags_RoundCornersTopLeft (VALUE 0x01 OVERLAPS ImDrawFlags_Closed but ImDrawFlags_Closed is never valid in this path!) + // 0x02 --> ImDrawFlags_RoundCornersTopRight + // 0x03 --> ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight + // 0x04 --> ImDrawFlags_RoundCornersBotLeft + // 0x05 --> ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBotLeft + // ... + // 0x0F --> ImDrawFlags_RoundCornersAll or 0 + // (See all values in ImDrawCornerFlags_) + if (flags >= 0x01 && flags <= 0x0F) + return (flags << 4); + + // We cannot support hard coded 0x00 with 'float rounding > 0.0f' --> replace with ImDrawFlags_RoundCornersNone or use 'float rounding = 0.0f' +#endif + + // If this triggers, please update your code replacing hardcoded values with new ImDrawFlags_RoundCorners* values. + // Note that ImDrawFlags_Closed (== 0x01) is an invalid flag for AddRect(), AddRectFilled(), PathRect() etc... + IM_ASSERT((flags & 0x0F) == 0 && "Misuse of legacy hardcoded ImDrawCornerFlags values!"); + + if ((flags & ImDrawFlags_RoundCornersMask_) == 0) + flags |= ImDrawFlags_RoundCornersAll; + + return flags; +} + +void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawFlags flags) { - rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((rounding_corners & ImDrawCornerFlags_Top) == ImDrawCornerFlags_Top) || ((rounding_corners & ImDrawCornerFlags_Bot) == ImDrawCornerFlags_Bot) ? 0.5f : 1.0f ) - 1.0f); - rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((rounding_corners & ImDrawCornerFlags_Left) == ImDrawCornerFlags_Left) || ((rounding_corners & ImDrawCornerFlags_Right) == ImDrawCornerFlags_Right) ? 0.5f : 1.0f ) - 1.0f); + flags = FixRectCornerFlags(flags); + rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f ) - 1.0f); + rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f ) - 1.0f); - if (rounding <= 0.0f || rounding_corners == 0) + if (rounding <= 0.0f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) { PathLineTo(a); PathLineTo(ImVec2(b.x, a.y)); @@ -1166,10 +1350,10 @@ void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDr } else { - const float rounding_tl = (rounding_corners & ImDrawCornerFlags_TopLeft) ? rounding : 0.0f; - const float rounding_tr = (rounding_corners & ImDrawCornerFlags_TopRight) ? rounding : 0.0f; - const float rounding_br = (rounding_corners & ImDrawCornerFlags_BotRight) ? rounding : 0.0f; - const float rounding_bl = (rounding_corners & ImDrawCornerFlags_BotLeft) ? rounding : 0.0f; + const float rounding_tl = (flags & ImDrawFlags_RoundCornersTopLeft) ? rounding : 0.0f; + const float rounding_tr = (flags & ImDrawFlags_RoundCornersTopRight) ? rounding : 0.0f; + const float rounding_br = (flags & ImDrawFlags_RoundCornersBottomRight) ? rounding : 0.0f; + const float rounding_bl = (flags & ImDrawFlags_RoundCornersBottomLeft) ? rounding : 0.0f; PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9); PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12); PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3); @@ -1183,35 +1367,35 @@ void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float th return; PathLineTo(p1 + ImVec2(0.5f, 0.5f)); PathLineTo(p2 + ImVec2(0.5f, 0.5f)); - PathStroke(col, false, thickness); + PathStroke(col, 0, thickness); } // p_min = upper-left, p_max = lower-right // Note we don't render 1 pixels sized rectangles properly. -void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners, float thickness) +void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags, float thickness) { if ((col & IM_COL32_A_MASK) == 0) return; if (Flags & ImDrawListFlags_AntiAliasedLines) - PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.50f, 0.50f), rounding, rounding_corners); + PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.50f, 0.50f), rounding, flags); else - PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.49f, 0.49f), rounding, rounding_corners); // Better looking lower-right corner and rounded non-AA shapes. - PathStroke(col, true, thickness); + PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.49f, 0.49f), rounding, flags); // Better looking lower-right corner and rounded non-AA shapes. + PathStroke(col, ImDrawFlags_Closed, thickness); } -void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners) +void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags) { if ((col & IM_COL32_A_MASK) == 0) return; - if (rounding > 0.0f) + if (rounding <= 0.0f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) { - PathRect(p_min, p_max, rounding, rounding_corners); - PathFillConvex(col); + PrimReserve(6, 4); + PrimRect(p_min, p_max, col); } else { - PrimReserve(6, 4); - PrimRect(p_min, p_max, col); + PathRect(p_min, p_max, rounding, flags); + PathFillConvex(col); } } @@ -1240,7 +1424,7 @@ void ImDrawList::AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, c PathLineTo(p2); PathLineTo(p3); PathLineTo(p4); - PathStroke(col, true, thickness); + PathStroke(col, ImDrawFlags_Closed, thickness); } void ImDrawList::AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col) @@ -1263,7 +1447,7 @@ void ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p PathLineTo(p1); PathLineTo(p2); PathLineTo(p3); - PathStroke(col, true, thickness); + PathStroke(col, ImDrawFlags_Closed, thickness); } void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col) @@ -1286,11 +1470,7 @@ void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int nu if (num_segments <= 0) { // Automatic segment count - const int radius_idx = (int)radius; - if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts)) - num_segments = _Data->CircleSegmentCounts[radius_idx]; // Use cached value - else - num_segments = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError); + num_segments = _CalcCircleAutoSegmentCount(radius); } else { @@ -1304,7 +1484,7 @@ void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int nu PathArcToFast(center, radius - 0.5f, 0, 12 - 1); else PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1); - PathStroke(col, true, thickness); + PathStroke(col, ImDrawFlags_Closed, thickness); } void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) @@ -1316,11 +1496,7 @@ void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, if (num_segments <= 0) { // Automatic segment count - const int radius_idx = (int)radius; - if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts)) - num_segments = _Data->CircleSegmentCounts[radius_idx]; // Use cached value - else - num_segments = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError); + num_segments = _CalcCircleAutoSegmentCount(radius); } else { @@ -1346,7 +1522,7 @@ void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_ // Because we are filling a closed shape we remove 1 from the count of segments/points const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1); - PathStroke(col, true, thickness); + PathStroke(col, ImDrawFlags_Closed, thickness); } // Guaranteed to honor 'num_segments' @@ -1369,7 +1545,7 @@ void ImDrawList::AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2 PathLineTo(p1); PathBezierCubicCurveTo(p2, p3, p4, num_segments); - PathStroke(col, false, thickness); + PathStroke(col, 0, thickness); } // Quadratic Bezier takes 3 controls points @@ -1380,7 +1556,7 @@ void ImDrawList::AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const Im PathLineTo(p1); PathBezierQuadraticCurveTo(p2, p3, num_segments); - PathStroke(col, false, thickness); + PathStroke(col, 0, thickness); } void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect) @@ -1449,23 +1625,24 @@ void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, con PopTextureID(); } -void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners) +void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags) { if ((col & IM_COL32_A_MASK) == 0) return; - if (rounding <= 0.0f || (rounding_corners & ImDrawCornerFlags_All) == 0) + flags = FixRectCornerFlags(flags); + if (rounding <= 0.0f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) { AddImage(user_texture_id, p_min, p_max, uv_min, uv_max, col); return; } - const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); + const bool push_texture_id = user_texture_id != _CmdHeader.TextureId; if (push_texture_id) PushTextureID(user_texture_id); int vert_start_idx = VtxBuffer.Size; - PathRect(p_min, p_max, rounding, rounding_corners); + PathRect(p_min, p_max, rounding, flags); PathFillConvex(col); int vert_end_idx = VtxBuffer.Size; ImGui::ShadeVertsLinearUV(this, vert_start_idx, vert_end_idx, p_min, p_max, uv_min, uv_max, true); @@ -1823,6 +2000,7 @@ void ImFontAtlas::ClearTexData() IM_FREE(TexPixelsRGBA32); TexPixelsAlpha8 = NULL; TexPixelsRGBA32 = NULL; + TexPixelsUseColors = false; } void ImFontAtlas::ClearFonts() @@ -2532,7 +2710,7 @@ static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas) unsigned char* write_ptr = &atlas->TexPixelsAlpha8[r->X + ((r->Y + y) * atlas->TexWidth)]; for (unsigned int i = 0; i < pad_left; i++) *(write_ptr + i) = 0x00; - + for (unsigned int i = 0; i < line_width; i++) *(write_ptr + pad_left + i) = 0xFF; @@ -2544,7 +2722,7 @@ static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas) unsigned int* write_ptr = &atlas->TexPixelsRGBA32[r->X + ((r->Y + y) * atlas->TexWidth)]; for (unsigned int i = 0; i < pad_left; i++) *(write_ptr + i) = IM_COL32_BLACK_TRANS; - + for (unsigned int i = 0; i < line_width; i++) *(write_ptr + pad_left + i) = IM_COL32_WHITE; @@ -3313,6 +3491,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons return text_size; } +// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const { const ImFontGlyph* glyph = FindGlyph(c); @@ -3327,6 +3506,7 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col draw_list->PrimRectUV(ImVec2(pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2(pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col); } +// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const { if (!text_end) @@ -3582,7 +3762,7 @@ void ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float draw_list->PathLineTo(ImVec2(bx - third, by - third)); draw_list->PathLineTo(ImVec2(bx, by)); draw_list->PathLineTo(ImVec2(bx + third * 2.0f, by - third * 2.0f)); - draw_list->PathStroke(col, false, thickness); + draw_list->PathStroke(col, 0, thickness); } void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow) @@ -3596,7 +3776,7 @@ void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, Im if (font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2])) { pos -= offset; - const ImTextureID tex_id = font_atlas->TexID; + ImTextureID tex_id = font_atlas->TexID; draw_list->PushTextureID(tex_id); draw_list->AddImage(tex_id, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow); draw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow); @@ -3694,27 +3874,29 @@ void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect const bool fill_R = (inner.Max.x < outer.Max.x); const bool fill_U = (inner.Min.y > outer.Min.y); const bool fill_D = (inner.Max.y < outer.Max.y); - if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawCornerFlags_TopLeft) | (fill_D ? 0 : ImDrawCornerFlags_BotLeft)); - if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawCornerFlags_TopRight) | (fill_D ? 0 : ImDrawCornerFlags_BotRight)); - if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, (fill_L ? 0 : ImDrawCornerFlags_TopLeft) | (fill_R ? 0 : ImDrawCornerFlags_TopRight)); - if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, (fill_L ? 0 : ImDrawCornerFlags_BotLeft) | (fill_R ? 0 : ImDrawCornerFlags_BotRight)); - if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawCornerFlags_TopLeft); - if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawCornerFlags_TopRight); - if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawCornerFlags_BotLeft); - if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawCornerFlags_BotRight); + if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomLeft)); + if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawFlags_RoundCornersTopRight) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomRight)); + if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, (fill_L ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersTopRight)); + if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, (fill_L ? 0 : ImDrawFlags_RoundCornersBottomLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersBottomRight)); + if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopLeft); + if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopRight); + if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomLeft); + if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomRight); } // Helper for ColorPicker4() // NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that. // Spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding altogether. // FIXME: uses ImGui::GetColorU32 -void ImGui::RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, int rounding_corners_flags) +void ImGui::RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, ImDrawFlags flags) { + if ((flags & ImDrawFlags_RoundCornersMask_) == 0) + flags = ImDrawFlags_RoundCornersDefault_; if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF) { - ImU32 col_bg1 = ImGui::GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col)); - ImU32 col_bg2 = ImGui::GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col)); - draw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, rounding_corners_flags); + ImU32 col_bg1 = GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col)); + ImU32 col_bg2 = GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col)); + draw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, flags); int yi = 0; for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++) @@ -3727,17 +3909,19 @@ void ImGui::RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x); if (x2 <= x1) continue; - int rounding_corners_flags_cell = 0; - if (y1 <= p_min.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopRight; } - if (y2 >= p_max.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotRight; } - rounding_corners_flags_cell &= rounding_corners_flags; - draw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding_corners_flags_cell ? rounding : 0.0f, rounding_corners_flags_cell); + ImDrawFlags cell_flags = ImDrawFlags_RoundCornersNone; + if (y1 <= p_min.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersTopLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersTopRight; } + if (y2 >= p_max.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersBottomLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersBottomRight; } + + // Combine flags + cell_flags = (flags == ImDrawFlags_RoundCornersNone || cell_flags == ImDrawFlags_RoundCornersNone) ? ImDrawFlags_RoundCornersNone : (cell_flags & flags); + draw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding, cell_flags); } } } else { - draw_list->AddRectFilled(p_min, p_max, col, rounding, rounding_corners_flags); + draw_list->AddRectFilled(p_min, p_max, col, rounding, flags); } } diff --git a/libs/yocto_gui/ext/imgui/imgui_impl_glfw.cpp b/libs/yocto_gui/ext/imgui/imgui_impl_glfw.cpp index fbc167d65..971686b09 100644 --- a/libs/yocto_gui/ext/imgui/imgui_impl_glfw.cpp +++ b/libs/yocto_gui/ext/imgui/imgui_impl_glfw.cpp @@ -113,10 +113,13 @@ void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int a g_PrevUserCallbackKey(window, key, scancode, action, mods); ImGuiIO& io = ImGui::GetIO(); - if (action == GLFW_PRESS) - io.KeysDown[key] = true; - if (action == GLFW_RELEASE) - io.KeysDown[key] = false; + if (key >= 0 && key < IM_ARRAYSIZE(io.KeysDown)) + { + if (action == GLFW_PRESS) + io.KeysDown[key] = true; + if (action == GLFW_RELEASE) + io.KeysDown[key] = false; + } // Modifiers are not reliable across systems io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL]; @@ -149,7 +152,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) io.BackendPlatformName = "imgui_impl_glfw"; - // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. + // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array. io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; diff --git a/libs/yocto_gui/ext/imgui/imgui_impl_opengl2.cpp b/libs/yocto_gui/ext/imgui/imgui_impl_opengl2.cpp index 1419e2d85..e2c36bef9 100644 --- a/libs/yocto_gui/ext/imgui/imgui_impl_opengl2.cpp +++ b/libs/yocto_gui/ext/imgui/imgui_impl_opengl2.cpp @@ -18,6 +18,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) // 2021-01-03: OpenGL: Backup, setup and restore GL_SHADE_MODEL state, disable GL_STENCIL_TEST and disable GL_NORMAL_ARRAY client state to increase compatibility with legacy OpenGL applications. // 2020-01-23: OpenGL: Backup, setup and restore GL_TEXTURE_ENV to increase compatibility with legacy OpenGL applications. // 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. @@ -81,6 +82,7 @@ static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_wid // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill. glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // In order to composite our output buffer we need to preserve alpha glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); @@ -183,7 +185,7 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y)); // Bind texture, Draw - glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); + glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID()); glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer); } } diff --git a/libs/yocto_gui/ext/imgui/imgui_impl_opengl3.cpp b/libs/yocto_gui/ext/imgui/imgui_impl_opengl3.cpp index f3b2a937b..643affe95 100644 --- a/libs/yocto_gui/ext/imgui/imgui_impl_opengl3.cpp +++ b/libs/yocto_gui/ext/imgui/imgui_impl_opengl3.cpp @@ -13,6 +13,9 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) +// 2021-04-06: OpenGL: Don't try to read GL_CLIP_ORIGIN unless we're OpenGL 4.5 or greater. +// 2021-02-18: OpenGL: Change blending equation to preserve alpha in output buffer. // 2021-01-03: OpenGL: Backup, setup and restore GL_STENCIL_TEST state. // 2020-10-23: OpenGL: Backup, setup and restore GL_PRIMITIVE_RESTART state. // 2020-10-15: OpenGL: Use glGetString(GL_VERSION) instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x) @@ -247,7 +250,7 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); @@ -261,11 +264,14 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid #endif // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT) -#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__) +#if defined(GL_CLIP_ORIGIN) bool clip_origin_lower_left = true; - GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin); - if (current_clip_origin == GL_UPPER_LEFT) - clip_origin_lower_left = false; + if (g_GlVersion >= 450) + { + GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin); + if (current_clip_origin == GL_UPPER_LEFT) + clip_origin_lower_left = false; + } #endif // Setup viewport, orthographic projection matrix @@ -275,7 +281,7 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; float T = draw_data->DisplayPos.y; float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; -#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__) +#if defined(GL_CLIP_ORIGIN) if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left #endif const float ortho_projection[4][4] = @@ -402,7 +408,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y)); // Bind texture, Draw - glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); + glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID()); #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET if (g_GlVersion >= 320) glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset); diff --git a/libs/yocto_gui/ext/imgui/imgui_internal.h b/libs/yocto_gui/ext/imgui/imgui_internal.h index 39caf6b63..8006246b6 100644 --- a/libs/yocto_gui/ext/imgui/imgui_internal.h +++ b/libs/yocto_gui/ext/imgui/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.81 +// dear imgui, v1.83 // (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! @@ -51,10 +51,19 @@ Index of this file: #include // sqrtf, fabsf, fmodf, powf, floorf, ceilf, cosf, sinf #include // INT_MIN, INT_MAX +// Enable SSE intrinsics if available +#if defined __SSE__ || defined __x86_64__ || defined _M_X64 +#define IMGUI_ENABLE_SSE +#include +#endif + // Visual Studio warnings #ifdef _MSC_VER #pragma warning (push) -#pragma warning (disable: 4251) // class 'xxx' needs to have dll-interface to be used by clients of struct 'xxx' // when IMGUI_API is set to__declspec(dllexport) +#pragma warning (disable: 4251) // class 'xxx' needs to have dll-interface to be used by clients of struct 'xxx' // when IMGUI_API is set to__declspec(dllexport) +#pragma warning (disable: 26812) // The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). [MSVC Static Analyzer) +#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6). + #endif // Clang/GCC warnings with -Weverything @@ -64,6 +73,7 @@ Index of this file: #pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' #endif #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok, for ImFloorSigned() #pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h #pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h #pragma clang diagnostic ignored "-Wold-style-cast" @@ -106,7 +116,7 @@ struct ImGuiGroupData; // Stacked storage data for BeginGroup()/End struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box struct ImGuiLastItemDataBackup; // Backup and restore IsItemHovered() internal data struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only -struct ImGuiNavMoveResult; // Result of a gamepad/keyboard directional navigation move query result +struct ImGuiNavItemData; // Result of a gamepad/keyboard directional navigation move query result struct ImGuiMetricsConfig; // Storage for ShowMetricsWindow() and DebugNodeXXX() functions struct ImGuiNextWindowData; // Storage for SetNextWindow** functions struct ImGuiNextItemData; // Storage for SetNextItem** functions @@ -120,15 +130,17 @@ struct ImGuiTabBar; // Storage for a tab bar struct ImGuiTabItem; // Storage for a tab item (within a tab bar) struct ImGuiTable; // Storage for a table struct ImGuiTableColumn; // Storage for one column of a table +struct ImGuiTableTempData; // Temporary storage for one table (one per table in the stack), shared between tables. struct ImGuiTableSettings; // Storage for a table .ini settings struct ImGuiTableColumnsSettings; // Storage for a column .ini settings 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 ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame, in practice we currently keep it for each window) 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 typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag() +typedef int ImGuiItemAddFlags; // -> enum ImGuiItemAddFlags_ // Flags: for ItemAdd() typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for DC.LastItemStatusFlags typedef int ImGuiOldColumnFlags; // -> enum ImGuiOldColumnFlags_ // Flags: for BeginColumns() typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight() @@ -214,6 +226,7 @@ namespace ImStb #define IM_NEWLINE "\n" #endif #define IM_TABSIZE (4) +#define IM_MEMALIGN(_OFF,_ALIGN) (((_OFF) + (_ALIGN - 1)) & ~(_ALIGN - 1)) // Memory align e.g. IM_ALIGN(0,4)=0, IM_ALIGN(1,4)=4, IM_ALIGN(4,4)=4, IM_ALIGN(5,4)=8 #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 @@ -226,6 +239,13 @@ namespace ImStb #define IMGUI_CDECL #endif +// Warnings +#if defined(_MSC_VER) && !defined(__clang__) +#define IM_MSVC_WARNING_SUPPRESS(XXXX) __pragma(warning(suppress: XXXX)) +#else +#define IM_MSVC_WARNING_SUPPRESS(XXXX) +#endif + // Debug Tools // Use 'Metrics->Tools->Item Picker' to break into the call-stack of a specific item. #ifndef IM_DEBUG_BREAK @@ -313,6 +333,7 @@ IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, cons // 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.) // We unfortunately don't have a unary- operator for ImVec2 because this would needs to be defined inside the class itself. #ifdef IMGUI_DEFINE_MATH_OPERATORS +IM_MSVC_RUNTIME_CHECKS_OFF static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } @@ -328,6 +349,7 @@ static inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& 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); } 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); } 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); } +IM_MSVC_RUNTIME_CHECKS_RESTORE #endif // Helpers: File System @@ -353,6 +375,7 @@ IMGUI_API ImU64 ImFileWrite(const void* data, ImU64 size, ImU64 coun IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size = NULL, int padding_bytes = 0); // Helpers: Maths +IM_MSVC_RUNTIME_CHECKS_OFF // - Wrapper for standard libs functions. (Note that imgui_demo.cpp does _not_ use them to keep the code easy to copy) #ifndef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS #define ImFabs(X) fabsf(X) @@ -363,16 +386,23 @@ IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* #define ImAcos(X) acosf(X) #define ImAtan2(Y, X) atan2f((Y), (X)) #define ImAtof(STR) atof(STR) -#define ImFloorStd(X) floorf(X) // We already uses our own ImFloor() { return (float)(int)v } internally so the standard one wrapper is named differently (it's used by e.g. stb_truetype) +//#define ImFloorStd(X) floorf(X) // We use our own, see ImFloor() and ImFloorSigned() #define ImCeil(X) ceilf(X) static inline float ImPow(float x, float y) { return powf(x, y); } // DragBehaviorT/SliderBehaviorT uses ImPow with either float/double and need the precision static inline double ImPow(double x, double y) { return pow(x, y); } static inline float ImLog(float x) { return logf(x); } // DragBehaviorT/SliderBehaviorT uses ImLog with either float/double and need the precision static inline double ImLog(double x) { return log(x); } +static inline int ImAbs(int x) { return x < 0 ? -x : x; } static inline float ImAbs(float x) { return fabsf(x); } static inline double ImAbs(double x) { return fabs(x); } static inline float ImSign(float x) { return (x < 0.0f) ? -1.0f : ((x > 0.0f) ? 1.0f : 0.0f); } // Sign operator - returns -1, 0 or 1 based on sign of argument static inline double ImSign(double x) { return (x < 0.0) ? -1.0 : ((x > 0.0) ? 1.0 : 0.0); } +#ifdef IMGUI_ENABLE_SSE +static inline float ImRsqrt(float x) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x))); } +#else +static inline float ImRsqrt(float x) { return 1.0f / sqrtf(x); } +#endif +static inline double ImRsqrt(double x) { return 1.0 / sqrt(x); } #endif // - ImMin/ImMax/ImClamp/ImLerp/ImSwap are used by widgets which support variety of types: signed/unsigned int/long long float/double // (Exceptionally using templates here but we could also redefine them for those types) @@ -393,14 +423,16 @@ static inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t) static inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : 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 ImInvLength(const ImVec2& lhs, float fail_value) { float d = (lhs.x * lhs.x) + (lhs.y * lhs.y); if (d > 0.0f) return ImRsqrt(d); return fail_value; } static inline float ImFloor(float f) { return (float)(int)(f); } +static inline float ImFloorSigned(float f) { return (float)((f >= 0 || (int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf() 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); } +IM_MSVC_RUNTIME_CHECKS_RESTORE // Helpers: Geometry IMGUI_API ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t); @@ -416,6 +448,7 @@ IMGUI_API ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy); // Helper: ImVec1 (1D vector) // (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches) +IM_MSVC_RUNTIME_CHECKS_OFF struct ImVec1 { float x; @@ -448,6 +481,7 @@ struct IMGUI_API ImRect ImVec2 GetSize() const { return ImVec2(Max.x - Min.x, Max.y - Min.y); } float GetWidth() const { return Max.x - Min.x; } float GetHeight() const { return Max.y - Min.y; } + float GetArea() const { return (Max.x - Min.x) * (Max.y - Min.y); } ImVec2 GetTL() const { return Min; } // Top-left ImVec2 GetTR() const { return ImVec2(Max.x, Min.y); } // Top-right ImVec2 GetBL() const { return ImVec2(Min.x, Max.y); } // Bottom-left @@ -468,6 +502,7 @@ struct IMGUI_API ImRect bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; } ImVec4 ToVec4() const { return ImVec4(Min.x, Min.y, Max.x, Max.y); } }; +IM_MSVC_RUNTIME_CHECKS_RESTORE // Helper: ImBitArray inline bool ImBitArrayTestBit(const ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); return (arr[n >> 5] & mask) != 0; } @@ -487,12 +522,12 @@ inline void ImBitArraySetBitRange(ImU32* arr, int n, int n2) // Works on ran } // Helper: ImBitArray class (wrapper over ImBitArray functions) -// Store 1-bit per value. NOT CLEARED by constructor. +// Store 1-bit per value. template struct IMGUI_API ImBitArray { ImU32 Storage[(BITCOUNT + 31) >> 5]; - ImBitArray() { } + ImBitArray() { ClearAllBits(); } void ClearAllBits() { memset(Storage, 0, sizeof(Storage)); } void SetAllBits() { memset(Storage, 255, sizeof(Storage)); } bool TestBit(int n) const { IM_ASSERT(n < BITCOUNT); return ImBitArrayTestBit(Storage, n); } @@ -544,20 +579,22 @@ struct ImSpan // Helper: ImSpanAllocator<> // Facilitate storing multiple chunks into a single large block (the "arena") +// - Usage: call Reserve() N times, allocate GetArenaSizeInBytes() worth, pass it to SetArenaBasePtr(), call GetSpan() N times to retrieve the aligned ranges. template struct ImSpanAllocator { char* BasePtr; - int TotalSize; - int CurrSpan; + int CurrOff; + int CurrIdx; int Offsets[CHUNKS]; + int Sizes[CHUNKS]; ImSpanAllocator() { memset(this, 0, sizeof(*this)); } - inline void ReserveBytes(int n, size_t sz) { IM_ASSERT(n == CurrSpan && n < CHUNKS); IM_UNUSED(n); Offsets[CurrSpan++] = TotalSize; TotalSize += (int)sz; } - inline int GetArenaSizeInBytes() { return TotalSize; } + inline void Reserve(int n, size_t sz, int a=4) { IM_ASSERT(n == CurrIdx && n < CHUNKS); CurrOff = IM_MEMALIGN(CurrOff, a); Offsets[n] = CurrOff; Sizes[n] = (int)sz; CurrIdx++; CurrOff += (int)sz; } + inline int GetArenaSizeInBytes() { return CurrOff; } inline void SetArenaBasePtr(void* base_ptr) { BasePtr = (char*)base_ptr; } - inline void* GetSpanPtrBegin(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrSpan == CHUNKS); return (void*)(BasePtr + Offsets[n]); } - inline void* GetSpanPtrEnd(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrSpan == CHUNKS); return (n + 1 < CHUNKS) ? BasePtr + Offsets[n + 1] : (void*)(BasePtr + TotalSize); } + inline void* GetSpanPtrBegin(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrIdx == CHUNKS); return (void*)(BasePtr + Offsets[n]); } + inline void* GetSpanPtrEnd(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrIdx == CHUNKS); return (void*)(BasePtr + Offsets[n] + Sizes[n]); } template inline void GetSpan(int n, ImSpan* span) { span->set((T*)GetSpanPtrBegin(n), (T*)GetSpanPtrEnd(n)); } }; @@ -591,7 +628,7 @@ struct IMGUI_API ImPool // 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) +// We store the chunk size first, and align the final size on 4 bytes boundaries. // The tedious/zealous amount of casting is to avoid -Wcast-align warnings. template struct IMGUI_API ImChunkStream @@ -601,7 +638,7 @@ struct IMGUI_API ImChunkStream 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* alloc_chunk(size_t sz) { size_t HDR_SZ = 4; sz = IM_MEMALIGN(HDR_SZ + sz, 4u); 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]; } @@ -617,15 +654,30 @@ struct IMGUI_API ImChunkStream //----------------------------------------------------------------------------- // ImDrawList: Helper function to calculate a circle's segment count given its radius and a "maximum error" value. -// FIXME: the minimum number of auto-segment may be undesirably high for very small radiuses (e.g. 1.0f) -#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN 12 +// Estimation of number of circle segment based on error is derived using method described in https://stackoverflow.com/a/2244088/15194693 +// Number of segments (N) is calculated using equation: +// N = ceil ( pi / acos(1 - error / r) ) where r > 0, error <= r +// Our equation is significantly simpler that one in the post thanks for choosing segment that is +// perpendicular to X axis. Follow steps in the article from this starting condition and you will +// will get this result. +// +// Rendering circles with an odd number of segments, while mathematically correct will produce +// asymmetrical results on the raster grid. Therefore we're rounding N to next even number (7->8, 8->8, 9->10 etc.) +// +#define IM_ROUNDUP_TO_EVEN(_V) ((((_V) + 1) / 2) * 2) +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN 4 #define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX 512 -#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(_RAD,_MAXERROR) ImClamp((int)((IM_PI * 2.0f) / ImAcos(((_RAD) - (_MAXERROR)) / (_RAD))), IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX) +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(_RAD,_MAXERROR) ImClamp(IM_ROUNDUP_TO_EVEN((int)ImCeil(IM_PI / ImAcos(1 - ImMin((_MAXERROR), (_RAD)) / (_RAD)))), IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX) + +// Raw equation from IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC rewritten for 'r' and 'error'. +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(_N,_MAXERROR) ((_MAXERROR) / (1 - ImCos(IM_PI / ImMax((float)(_N), IM_PI)))) +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_ERROR(_N,_RAD) ((1 - ImCos(IM_PI / ImMax((float)(_N), IM_PI))) / (_RAD)) -// ImDrawList: You may set this to higher values (e.g. 2 or 3) to increase tessellation of fast rounded corners path. -#ifndef IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER -#define IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER 1 +// ImDrawList: Lookup table size for adaptive arc drawing, cover full circle. +#ifndef IM_DRAWLIST_ARCFAST_TABLE_SIZE +#define IM_DRAWLIST_ARCFAST_TABLE_SIZE 48 // Number of samples in lookup table. #endif +#define IM_DRAWLIST_ARCFAST_SAMPLE_MAX IM_DRAWLIST_ARCFAST_TABLE_SIZE // Sample index _PathArcToFastEx() for 360 angle. // Data shared between all ImDrawList instances // You may want to create your own instance of this if you want to use ImDrawList completely without ImGui. In that case, watch out for future changes to this structure. @@ -640,12 +692,13 @@ struct IMGUI_API ImDrawListSharedData ImDrawListFlags InitialFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards) // [Internal] Lookup tables - ImVec2 ArcFastVtx[12 * IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER]; // FIXME: Bake rounded corners fill/borders in atlas + ImVec2 ArcFastVtx[IM_DRAWLIST_ARCFAST_TABLE_SIZE]; // Sample points on the quarter of the circle. + float ArcFastRadiusCutoff; // Cutoff radius after which arc drawing will fallback to slower PathArcTo() ImU8 CircleSegmentCounts[64]; // Precomputed segment count for given radius before we calculate it dynamically (to avoid calculation overhead) const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas ImDrawListSharedData(); - void SetCircleSegmentMaxError(float max_error); + void SetCircleTessellationMaxError(float max_error); }; struct ImDrawDataBuilder @@ -674,31 +727,51 @@ enum ImGuiItemFlags_ ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets) - ImGuiItemFlags_ReadOnly = 1 << 7, // false // [ALPHA] Allow hovering interactions but underlying value is not changed. - ImGuiItemFlags_Default_ = 0 + ImGuiItemFlags_ReadOnly = 1 << 7 // false // [ALPHA] Allow hovering interactions but underlying value is not changed. +}; + +// Flags for ItemAdd() +// FIXME-NAV: _Focusable is _ALMOST_ what you would expect to be called '_TabStop' but because SetKeyboardFocusHere() works on items with no TabStop we distinguish Focusable from TabStop. +enum ImGuiItemAddFlags_ +{ + ImGuiItemAddFlags_None = 0, + ImGuiItemAddFlags_Focusable = 1 << 0 // FIXME-NAV: In current/legacy scheme, Focusable+TabStop support are opt-in by widgets. We will transition it toward being opt-out, so this flag is expected to eventually disappear. }; // Storage for LastItem data enum ImGuiItemStatusFlags_ { ImGuiItemStatusFlags_None = 0, - ImGuiItemStatusFlags_HoveredRect = 1 << 0, - ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, + ImGuiItemStatusFlags_HoveredRect = 1 << 0, // Mouse position is within item rectangle (does NOT mean that the window is in correct z-order and can be hovered!, this is only one part of the most-common IsItemHovered test) + ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, // window->DC.LastItemDisplayRect is valid 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_ToggledSelection = 1 << 3, // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected", only state changes, in order to easily handle clipping with less issues. 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. + ImGuiItemStatusFlags_Deactivated = 1 << 6, // Only valid if ImGuiItemStatusFlags_HasDeactivated is set. + ImGuiItemStatusFlags_HoveredWindow = 1 << 7, // Override the HoveredWindow test to allow cross-window hover testing. + ImGuiItemStatusFlags_FocusedByCode = 1 << 8, // Set when the Focusable item just got focused from code. + ImGuiItemStatusFlags_FocusedByTabbing = 1 << 9, // Set when the Focusable item just got focused by Tabbing. + ImGuiItemStatusFlags_Focused = ImGuiItemStatusFlags_FocusedByCode | ImGuiItemStatusFlags_FocusedByTabbing #ifdef IMGUI_ENABLE_TEST_ENGINE , // [imgui_tests only] - ImGuiItemStatusFlags_Openable = 1 << 10, // - ImGuiItemStatusFlags_Opened = 1 << 11, // - ImGuiItemStatusFlags_Checkable = 1 << 12, // - ImGuiItemStatusFlags_Checked = 1 << 13 // + ImGuiItemStatusFlags_Openable = 1 << 20, // + ImGuiItemStatusFlags_Opened = 1 << 21, // + ImGuiItemStatusFlags_Checkable = 1 << 22, // + ImGuiItemStatusFlags_Checked = 1 << 23 // #endif }; +// Extend ImGuiInputTextFlags_ +enum ImGuiInputTextFlagsPrivate_ +{ + // [Internal] + ImGuiInputTextFlags_Multiline = 1 << 26, // For internal use by InputTextMultiline() + ImGuiInputTextFlags_NoMarkEdited = 1 << 27, // For internal use by functions using InputText() before reformatting data + ImGuiInputTextFlags_MergedItem = 1 << 28 // For internal use by TempInputText(), will skip calling ItemAdd(). Require bounding-box to strictly match. +}; + // Extend ImGuiButtonFlags_ enum ImGuiButtonFlagsPrivate_ { @@ -803,9 +876,10 @@ enum ImGuiInputSource { ImGuiInputSource_None = 0, ImGuiInputSource_Mouse, - ImGuiInputSource_Nav, - ImGuiInputSource_NavKeyboard, // Only used occasionally for storage, not tested/handled by most code - ImGuiInputSource_NavGamepad, // " + ImGuiInputSource_Keyboard, + ImGuiInputSource_Gamepad, + ImGuiInputSource_Nav, // Stored in g.ActiveIdSource only + ImGuiInputSource_Clipboard, // Currently only used by InputText() ImGuiInputSource_COUNT }; @@ -910,7 +984,7 @@ struct ImGuiStyleMod }; // Stacked storage data for BeginGroup()/EndGroup() -struct ImGuiGroupData +struct IMGUI_API ImGuiGroupData { ImGuiID WindowID; ImVec2 BackupCursorPos; @@ -921,6 +995,7 @@ struct ImGuiGroupData float BackupCurrLineTextBaseOffset; ImGuiID BackupActiveIdIsAlive; bool BackupActiveIdPreviousFrameIsAlive; + bool BackupHoveredIdIsAlive; bool EmitItem; }; @@ -954,7 +1029,7 @@ struct IMGUI_API ImGuiInputTextState bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!) bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection bool Edited; // edited this frame - ImGuiInputTextFlags UserFlags; // Temporarily set while we call user's callback + ImGuiInputTextFlags Flags; // copy of InputText() flags ImGuiInputTextCallback UserCallback; // " void* UserCallbackData; // " @@ -987,18 +1062,18 @@ struct ImGuiPopupData ImGuiPopupData() { memset(this, 0, sizeof(*this)); OpenFrameCount = -1; } }; -struct ImGuiNavMoveResult +struct ImGuiNavItemData { - ImGuiWindow* Window; // Best candidate window - ImGuiID ID; // Best candidate ID - ImGuiID FocusScopeId; // Best candidate focus scope ID - float DistBox; // Best candidate box distance to current NavId - float DistCenter; // Best candidate center distance to current NavId - float DistAxial; - ImRect RectRel; // Best candidate bounding box in window relative space + ImGuiWindow* Window; // Init,Move // Best candidate window (result->ItemWindow->RootWindowForNav == request->Window) + ImGuiID ID; // Init,Move // Best candidate item ID + ImGuiID FocusScopeId; // Init,Move // Best candidate focus scope ID + ImRect RectRel; // Init,Move // Best candidate bounding box in window relative space + float DistBox; // Move // Best candidate box distance to current NavId + float DistCenter; // Move // Best candidate center distance to current NavId + float DistAxial; // Move // Best candidate axial distance to current NavId - ImGuiNavMoveResult() { Clear(); } - void Clear() { Window = NULL; ID = FocusScopeId = 0; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); } + ImGuiNavItemData() { Clear(); } + void Clear() { Window = NULL; ID = FocusScopeId = 0; RectRel = ImRect(); DistBox = DistCenter = DistAxial = FLT_MAX; } }; enum ImGuiNextWindowDataFlags_ @@ -1158,14 +1233,21 @@ struct ImGuiViewportP : public ImGuiViewport ImVec2 WorkOffsetMin; // Work Area: Offset from Pos to top-left corner of Work Area. Generally (0,0) or (0,+main_menu_bar_height). Work Area is Full Area but without menu-bars/status-bars (so WorkArea always fit inside Pos/Size!) ImVec2 WorkOffsetMax; // Work Area: Offset from Pos+Size to bottom-right corner of Work Area. Generally (0,0) or (0,-status_bar_height). - ImVec2 CurrWorkOffsetMin; // Work Area: Offset being built/increased during current frame - ImVec2 CurrWorkOffsetMax; // Work Area: Offset being built/decreased during current frame + ImVec2 BuildWorkOffsetMin; // Work Area: Offset being built during current frame. Generally >= 0.0f. + ImVec2 BuildWorkOffsetMax; // Work Area: Offset being built during current frame. Generally <= 0.0f. - ImGuiViewportP() { DrawListsLastFrame[0] = DrawListsLastFrame[1] = -1; DrawLists[0] = DrawLists[1] = NULL; } - ~ImGuiViewportP() { if (DrawLists[0]) IM_DELETE(DrawLists[0]); if (DrawLists[1]) IM_DELETE(DrawLists[1]); } - ImRect GetMainRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } - ImRect GetWorkRect() const { return ImRect(WorkPos.x, WorkPos.y, WorkPos.x + WorkSize.x, WorkPos.y + WorkSize.y); } - void UpdateWorkRect() { WorkPos = ImVec2(Pos.x + WorkOffsetMin.x, Pos.y + WorkOffsetMin.y); WorkSize = ImVec2(ImMax(0.0f, Size.x - WorkOffsetMin.x + WorkOffsetMax.x), ImMax(0.0f, Size.y - WorkOffsetMin.y + WorkOffsetMax.y)); } + ImGuiViewportP() { DrawListsLastFrame[0] = DrawListsLastFrame[1] = -1; DrawLists[0] = DrawLists[1] = NULL; } + ~ImGuiViewportP() { if (DrawLists[0]) IM_DELETE(DrawLists[0]); if (DrawLists[1]) IM_DELETE(DrawLists[1]); } + + // Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect) + ImVec2 CalcWorkRectPos(const ImVec2& off_min) const { return ImVec2(Pos.x + off_min.x, Pos.y + off_min.y); } + ImVec2 CalcWorkRectSize(const ImVec2& off_min, const ImVec2& off_max) const { return ImVec2(ImMax(0.0f, Size.x - off_min.x + off_max.x), ImMax(0.0f, Size.y - off_min.y + off_max.y)); } + void UpdateWorkRect() { WorkPos = CalcWorkRectPos(WorkOffsetMin); WorkSize = CalcWorkRectSize(WorkOffsetMin, WorkOffsetMax); } // Update public fields + + // Helpers to retrieve ImRect (we don't need to store BuildWorkRect as every access tend to change it, hence the code asymmetry) + ImRect GetMainRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } + ImRect GetWorkRect() const { return ImRect(WorkPos.x, WorkPos.y, WorkPos.x + WorkSize.x, WorkPos.y + WorkSize.y); } + ImRect GetBuildWorkRect() const { ImVec2 pos = CalcWorkRectPos(BuildWorkOffsetMin); ImVec2 size = CalcWorkRectSize(BuildWorkOffsetMin, BuildWorkOffsetMax); return ImRect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); } }; //----------------------------------------------------------------------------- @@ -1289,14 +1371,14 @@ struct ImGuiContext // Windows state ImVector Windows; // Windows, sorted in display order, back to front - ImVector WindowsFocusOrder; // Windows, sorted in focus order, back to front. (FIXME: We could only store root windows here! Need to sort out the Docking equivalent which is RootWindowDockStop and is unfortunately a little more dynamic) + ImVector WindowsFocusOrder; // Root windows, sorted in focus order, back to front. ImVector WindowsTempSortBuffer; // Temporary buffer used in EndFrame() to reorder windows so parents are kept before their child ImVector CurrentWindowStack; ImGuiStorage WindowsById; // Map window's ImGuiID to ImGuiWindow* int WindowsActiveCount; // Number of unique windows submitted by frame + ImVec2 WindowsHoverPadding; // Padding around resizable windows for which hovering on counts as hovering the window == ImMax(style.TouchExtraPadding, WINDOWS_HOVER_PADDING) ImGuiWindow* CurrentWindow; // Window being drawn into ImGuiWindow* HoveredWindow; // Window the mouse is hovering. Will typically catch mouse inputs. - ImGuiWindow* HoveredRootWindow; // == HoveredWindow ? HoveredWindow->RootWindow : NULL, merely a shortcut to avoid null test in some situation. ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set. ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindow. 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. @@ -1304,6 +1386,7 @@ struct ImGuiContext float WheelingWindowTimer; // Item/widgets state and tracking information + ImGuiItemFlags CurrentItemFlags; // == g.ItemFlagsStack.back() ImGuiID HoveredId; // Hovered widget, filled during the frame ImGuiID HoveredIdPreviousFrame; bool HoveredIdAllowOverlap; @@ -1386,9 +1469,9 @@ struct ImGuiContext ImGuiKeyModFlags NavMoveRequestKeyMods; ImGuiDir NavMoveDir, NavMoveDirLast; // Direction of the move request (left/right/up/down), direction of the previous move request ImGuiDir NavMoveClipDir; // FIXME-NAV: Describe the purpose of this better. Might want to rename? - ImGuiNavMoveResult NavMoveResultLocal; // Best move request candidate within NavWindow - ImGuiNavMoveResult NavMoveResultLocalVisibleSet; // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag) - ImGuiNavMoveResult NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag) + ImGuiNavItemData NavMoveResultLocal; // Best move request candidate within NavWindow + ImGuiNavItemData NavMoveResultLocalVisibleSet; // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag) + ImGuiNavItemData NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag) ImGuiWindow* NavWrapRequestWindow; // Window which requested trying nav wrap-around. ImGuiNavMoveFlags NavWrapRequestFlags; // Wrap-around operation flags. @@ -1401,13 +1484,13 @@ struct ImGuiContext bool NavWindowingToggleLayer; // Legacy Focus/Tabbing system (older than Nav, active even if Nav is disabled, misnamed. FIXME-NAV: This needs a redesign!) - ImGuiWindow* FocusRequestCurrWindow; // - ImGuiWindow* FocusRequestNextWindow; // - int FocusRequestCurrCounterRegular; // Any item being requested for focus, stored as an index (we on layout to be stable between the frame pressing TAB and the next frame, semi-ouch) - int FocusRequestCurrCounterTabStop; // Tab item being requested for focus, stored as an index - int FocusRequestNextCounterRegular; // Stored for next frame - int FocusRequestNextCounterTabStop; // " - bool FocusTabPressed; // + ImGuiWindow* TabFocusRequestCurrWindow; // + ImGuiWindow* TabFocusRequestNextWindow; // + int TabFocusRequestCurrCounterRegular; // Any item being requested for focus, stored as an index (we on layout to be stable between the frame pressing TAB and the next frame, semi-ouch) + int TabFocusRequestCurrCounterTabStop; // Tab item being requested for focus, stored as an index + int TabFocusRequestNextCounterRegular; // Stored for next frame + int TabFocusRequestNextCounterTabStop; // " + bool TabFocusPressed; // Set in NewFrame() when user pressed Tab // Render float DimBgRatio; // 0.0..1.0 animation when fading in a dimming background (for modal window and CTRL+TAB list) @@ -1434,8 +1517,9 @@ struct ImGuiContext // Table ImGuiTable* CurrentTable; + int CurrentTableStackIdx; ImPool Tables; - ImVector CurrentTableStack; + ImVector TablesTempDataStack; ImVector TablesLastTimeActive; // Last used timestamp of each tables (SOA, for efficient GC) ImVector DrawChannelsTempMergeBuffer; @@ -1502,6 +1586,7 @@ struct ImGuiContext // Misc float FramerateSecPerFrame[120]; // Calculate estimate of framerate for user over the last 2 seconds. int FramerateSecPerFrameIdx; + int FramerateSecPerFrameCount; float FramerateSecPerFrameAccum; int WantCaptureMouseNextFrame; // Explicit capture via CaptureKeyboardFromApp()/CaptureMouseFromApp() sets those flags int WantCaptureKeyboardNextFrame; @@ -1527,12 +1612,12 @@ struct ImGuiContext WindowsActiveCount = 0; CurrentWindow = NULL; HoveredWindow = NULL; - HoveredRootWindow = NULL; HoveredWindowUnderMovingWindow = NULL; MovingWindow = NULL; WheelingWindow = NULL; WheelingWindowTimer = 0.0f; + CurrentItemFlags = ImGuiItemFlags_None; HoveredId = HoveredIdPreviousFrame = 0; HoveredIdAllowOverlap = false; HoveredIdUsingMouseWheel = HoveredIdPreviousFrameUsingMouseWheel = false; @@ -1554,7 +1639,7 @@ struct ImGuiContext ActiveIdClickOffset = ImVec2(-1, -1); ActiveIdWindow = NULL; ActiveIdSource = ImGuiInputSource_None; - ActiveIdMouseButton = 0; + ActiveIdMouseButton = -1; ActiveIdPreviousFrame = 0; ActiveIdPreviousFrameIsAlive = false; ActiveIdPreviousFrameHasBeenEditedBefore = false; @@ -1591,10 +1676,10 @@ struct ImGuiContext NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f; NavWindowingToggleLayer = false; - FocusRequestCurrWindow = FocusRequestNextWindow = NULL; - FocusRequestCurrCounterRegular = FocusRequestCurrCounterTabStop = INT_MAX; - FocusRequestNextCounterRegular = FocusRequestNextCounterTabStop = INT_MAX; - FocusTabPressed = false; + TabFocusRequestCurrWindow = TabFocusRequestNextWindow = NULL; + TabFocusRequestCurrCounterRegular = TabFocusRequestCurrCounterTabStop = INT_MAX; + TabFocusRequestNextCounterRegular = TabFocusRequestNextCounterTabStop = INT_MAX; + TabFocusPressed = false; DimBgRatio = 0.0f; MouseCursor = ImGuiMouseCursor_Arrow; @@ -1612,6 +1697,7 @@ struct ImGuiContext memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal)); CurrentTable = NULL; + CurrentTableStackIdx = -1; CurrentTabBar = NULL; LastValidMousePos = ImVec2(0.0f, 0.0f); @@ -1648,7 +1734,7 @@ struct ImGuiContext DebugItemPickerBreakId = 0; memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame)); - FramerateSecPerFrameIdx = 0; + FramerateSecPerFrameIdx = FramerateSecPerFrameCount = 0; FramerateSecPerFrameAccum = 0.0f; WantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1; memset(TempBuffer, 0, sizeof(TempBuffer)); @@ -1686,8 +1772,8 @@ struct IMGUI_API ImGuiWindowTempData // Keyboard/Gamepad navigation ImGuiNavLayer NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1) - int NavLayerActiveMask; // Which layers have been written to (result from previous frame) - int NavLayerActiveMaskNext; // Which layers have been written to (accumulator for current frame) + short NavLayersActiveMask; // Which layers have been written to (result from previous frame) + short NavLayersActiveMaskNext;// Which layers have been written to (accumulator for current frame) ImGuiID NavFocusScopeIdCurrent; // Current focus scope ID while appending bool NavHideHighlightOneFrame; bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f) @@ -1709,7 +1795,6 @@ struct IMGUI_API ImGuiWindowTempData // Local parameters stacks // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. - ImGuiItemFlags ItemFlags; // == g.ItemFlagsStack.back() float ItemWidth; // Current item width (>0.0: width in pixels, <0.0: align xx pixels to the right of window). float TextWrapPos; // Current text wrap pos. ImVector ItemWidthStack; // Store item widths to restore (attention: .back() is not == ItemWidth) @@ -1754,8 +1839,9 @@ struct IMGUI_API ImGuiWindow bool HasCloseButton; // Set when the window has a close button (p_open != NULL) signed char ResizeBorderHeld; // Current border being held for resize (-1: none, otherwise 0-3) short BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) - short BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0. - short BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues. + short BeginOrderWithinParent; // Begin() order within immediate parent window, if we are a child window. Otherwise 0. + short BeginOrderWithinContext; // Begin() order within entire imgui context. This is mostly used for debugging submission order related issues. + short FocusOrder; // Order within WindowsFocusOrder[], altered when windows are focused. ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling) ImS8 AutoFitFramesX, AutoFitFramesY; ImS8 AutoFitChildAxises; @@ -1764,6 +1850,7 @@ struct IMGUI_API ImGuiWindow ImS8 HiddenFramesCanSkipItems; // Hide the window for N frames ImS8 HiddenFramesCannotSkipItems; // Hide the window for N frames while allowing items to be submitted so we can measure their size ImS8 HiddenFramesForRenderOnly; // Hide the window until frame N at Render() time only + ImS8 DisableInputsFrames; // Disable window interactions for N frames ImGuiCond SetWindowPosAllowFlags : 8; // store acceptable condition flags for SetNextWindowPos() use. ImGuiCond SetWindowSizeAllowFlags : 8; // store acceptable condition flags for SetNextWindowSize() use. ImGuiCond SetWindowCollapsedAllowFlags : 8; // store acceptable condition flags for SetNextWindowCollapsed() use. @@ -1857,6 +1944,7 @@ enum ImGuiTabBarFlagsPrivate_ // Extend ImGuiTabItemFlags_ enum ImGuiTabItemFlagsPrivate_ { + ImGuiTabItemFlags_SectionMask_ = ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing, ImGuiTabItemFlags_NoCloseButton = 1 << 20, // Track whether p_open was set or not (we'll need this info on the next frame to recompute ContentWidth during layout) ImGuiTabItemFlags_Button = 1 << 21 // Used by TabItemButton, change the tab item behavior to mimic a button }; @@ -1886,7 +1974,7 @@ struct ImGuiTabBar ImGuiTabBarFlags Flags; ImGuiID ID; // Zero for tab-bars used by docking ImGuiID SelectedTabId; // Selected tab/window - ImGuiID NextSelectedTabId; + ImGuiID NextSelectedTabId; // Next selected tab/window. Will also trigger a scrolling animation ImGuiID VisibleTabId; // Can occasionally be != SelectedTabId (e.g. when previewing contents for CTRL+TAB preview) int CurrFrameVisible; int PrevFrameVisible; @@ -1902,7 +1990,7 @@ struct ImGuiTabBar float ScrollingRectMinX; float ScrollingRectMaxX; ImGuiID ReorderRequestTabId; - ImS8 ReorderRequestDir; + ImS16 ReorderRequestOffset; ImS8 BeginCount; bool WantLayout; bool VisibleTabWasSubmitted; @@ -1927,8 +2015,6 @@ struct ImGuiTabBar // [SECTION] Table support //----------------------------------------------------------------------------- -#ifdef IMGUI_HAS_TABLE - #define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color. #define IMGUI_TABLE_MAX_COLUMNS 64 // sizeof(ImU64) * 8. This is solely because we frequently encode columns set in a ImU64. #define IMGUI_TABLE_MAX_DRAW_CHANNELS (4 + 64 * 2) // See TableSetupDrawChannels() @@ -2005,12 +2091,13 @@ struct ImGuiTableCellData ImGuiTableColumnIdx Column; // Column number }; -// FIXME-TABLE: transient data could be stored in a per-stacked table structure: DrawSplitter, SortSpecs, incoming RowData +// FIXME-TABLE: more transient data could be stored in a per-stacked table structure: DrawSplitter, SortSpecs, incoming RowData struct ImGuiTable { ImGuiID ID; ImGuiTableFlags Flags; void* RawData; // Single allocation to hold Columns[], DisplayOrderToIndex[] and RowCellData[] + ImGuiTableTempData* TempData; // Transient data while table is active. Point within g.CurrentTableStack[] ImSpan Columns; // Point within RawData[] ImSpan DisplayOrderToIndex; // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1) ImSpan RowCellData; // Point within RawData[]. Store cells background requests for current row. @@ -2062,22 +2149,11 @@ struct ImGuiTable ImRect Bg0ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG0/1 channel. This tends to be == OuterWindow->ClipRect at BeginTable() because output in BG0/BG1 is cpu-clipped ImRect Bg2ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG2 channel. This tends to be a correct, tight-fit, because output to BG2 are done by widgets relying on regular ClipRect. ImRect HostClipRect; // This is used to check if we can eventually merge our columns draw calls into the current draw call of the current window. - ImRect HostBackupWorkRect; // Backup of InnerWindow->WorkRect at the end of BeginTable() - ImRect HostBackupParentWorkRect; // Backup of InnerWindow->ParentWorkRect at the end of BeginTable() ImRect HostBackupInnerClipRect; // Backup of InnerWindow->ClipRect during PushTableBackground()/PopTableBackground() - ImVec2 HostBackupPrevLineSize; // Backup of InnerWindow->DC.PrevLineSize at the end of BeginTable() - ImVec2 HostBackupCurrLineSize; // Backup of InnerWindow->DC.CurrLineSize at the end of BeginTable() - ImVec2 HostBackupCursorMaxPos; // Backup of InnerWindow->DC.CursorMaxPos at the end of BeginTable() - ImVec2 UserOuterSize; // outer_size.x passed to BeginTable() - ImVec1 HostBackupColumnsOffset; // Backup of OuterWindow->DC.ColumnsOffset at the end of BeginTable() - float HostBackupItemWidth; // Backup of OuterWindow->DC.ItemWidth at the end of BeginTable() - int HostBackupItemWidthStackSize;// Backup of OuterWindow->DC.ItemWidthStack.Size at the end of BeginTable() ImGuiWindow* OuterWindow; // Parent window for the table ImGuiWindow* InnerWindow; // Window holding the table data (== OuterWindow or a child window) ImGuiTextBuffer ColumnsNames; // Contiguous buffer holding columns names - ImDrawListSplitter DrawSplitter; // We carry our own ImDrawList splitter to allow recursion (FIXME: could be stored outside, worst case we need 1 splitter per recursing table) - ImGuiTableColumnSortSpecs SortSpecsSingle; - ImVector SortSpecsMulti; // FIXME-OPT: Using a small-vector pattern would work be good. + ImDrawListSplitter* DrawSplitter; // Shortcut to TempData->DrawSplitter while in table. Isolate draw commands per columns to avoid switching clip rect constantly ImGuiTableSortSpecs SortSpecs; // Public facing sorts specs, this is what we return in TableGetSortSpecs() ImGuiTableColumnIdx SortSpecsCount; ImGuiTableColumnIdx ColumnsEnabledCount; // Number of enabled columns (<= ColumnsCount) @@ -2091,9 +2167,10 @@ struct ImGuiTable ImGuiTableColumnIdx HeldHeaderColumn; // Index of column header being held. ImGuiTableColumnIdx ReorderColumn; // Index of column being reordered. (not cleared) ImGuiTableColumnIdx ReorderColumnDir; // -1 or +1 + ImGuiTableColumnIdx LeftMostEnabledColumn; // Index of left-most non-hidden column. + ImGuiTableColumnIdx RightMostEnabledColumn; // Index of right-most non-hidden column. ImGuiTableColumnIdx LeftMostStretchedColumn; // Index of left-most stretched column. ImGuiTableColumnIdx RightMostStretchedColumn; // Index of right-most stretched column. - ImGuiTableColumnIdx RightMostEnabledColumn; // Index of right-most non-hidden column. ImGuiTableColumnIdx ContextPopupColumn; // Column right-clicked on, of -1 if opening context menu from a neutral/empty spot ImGuiTableColumnIdx FreezeRowsRequest; // Requested frozen rows count ImGuiTableColumnIdx FreezeRowsCount; // Actual frozen row count (== FreezeRowsRequest, or == 0 when no scrolling offset) @@ -2123,6 +2200,32 @@ struct ImGuiTable IMGUI_API ~ImGuiTable() { IM_FREE(RawData); } }; +// Transient data that are only needed between BeginTable() and EndTable(), those buffers are shared (1 per level of stacked table). +// - Accessing those requires chasing an extra pointer so for very frequently used data we leave them in the main table structure. +// - We also leave out of this structure data that tend to be particularly useful for debugging/metrics. +// FIXME-TABLE: more transient data could be stored here: DrawSplitter, incoming RowData? +struct ImGuiTableTempData +{ + int TableIndex; // Index in g.Tables.Buf[] pool + float LastTimeActive; // Last timestamp this structure was used + + ImVec2 UserOuterSize; // outer_size.x passed to BeginTable() + ImDrawListSplitter DrawSplitter; + ImGuiTableColumnSortSpecs SortSpecsSingle; + ImVector SortSpecsMulti; // FIXME-OPT: Using a small-vector pattern would be good. + + ImRect HostBackupWorkRect; // Backup of InnerWindow->WorkRect at the end of BeginTable() + ImRect HostBackupParentWorkRect; // Backup of InnerWindow->ParentWorkRect at the end of BeginTable() + ImVec2 HostBackupPrevLineSize; // Backup of InnerWindow->DC.PrevLineSize at the end of BeginTable() + ImVec2 HostBackupCurrLineSize; // Backup of InnerWindow->DC.CurrLineSize at the end of BeginTable() + ImVec2 HostBackupCursorMaxPos; // Backup of InnerWindow->DC.CursorMaxPos at the end of BeginTable() + ImVec1 HostBackupColumnsOffset; // Backup of OuterWindow->DC.ColumnsOffset at the end of BeginTable() + float HostBackupItemWidth; // Backup of OuterWindow->DC.ItemWidth at the end of BeginTable() + int HostBackupItemWidthStackSize;//Backup of OuterWindow->DC.ItemWidthStack.Size at the end of BeginTable() + + IMGUI_API ImGuiTableTempData() { memset(this, 0, sizeof(*this)); LastTimeActive = -1.0f; } +}; + // sizeof() ~ 12 struct ImGuiTableColumnSettings { @@ -2161,8 +2264,6 @@ struct ImGuiTableSettings ImGuiTableColumnSettings* GetColumnSettings() { return (ImGuiTableColumnSettings*)(this + 1); } }; -#endif // #ifdef IMGUI_HAS_TABLE - //----------------------------------------------------------------------------- // [SECTION] ImGui internal API // No guarantee of forward compatibility here! @@ -2241,7 +2342,7 @@ namespace ImGui inline ImGuiItemStatusFlags GetItemStatusFlags() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemStatusFlags; } inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; } inline ImGuiID GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; } - inline ImGuiItemFlags GetItemsFlags() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.ItemFlags; } + inline ImGuiItemFlags GetItemFlags() { ImGuiContext& g = *GImGui; return g.CurrentItemFlags; } IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); IMGUI_API void SetFocusID(ImGuiID id, ImGuiWindow* window); IMGUI_API void ClearActiveID(); @@ -2255,12 +2356,11 @@ namespace ImGui // Basic Helpers for widget code 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 ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL, ImGuiItemAddFlags flags = 0); IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id); + IMGUI_API void ItemFocusable(ImGuiWindow* window, ImGuiID id); IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged); IMGUI_API void SetLastItemData(ImGuiWindow* window, ImGuiID item_id, ImGuiItemStatusFlags status_flags, const ImRect& item_rect); - IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id); // Return true if focus is requested - IMGUI_API void FocusableItemUnregister(ImGuiWindow* window); IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h); IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); IMGUI_API void PushMultiItemsWidths(int components, float width_full); @@ -2270,6 +2370,15 @@ namespace ImGui IMGUI_API ImVec2 GetContentRegionMaxAbs(); IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + // If you have old/custom copy-and-pasted widgets that used FocusableItemRegister(): + // (Old) IMGUI_VERSION_NUM < 18209: using 'ItemAdd(....)' and 'bool focused = FocusableItemRegister(...)' + // (New) IMGUI_VERSION_NUM >= 18209: using 'ItemAdd(..., ImGuiItemAddFlags_Focusable)' and 'bool focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_Focused) != 0' + // Widget code are simplified as there's no need to call FocusableItemUnregister() while managing the transition from regular widget to TempInputText() + inline bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id) { IM_ASSERT(0); IM_UNUSED(window); IM_UNUSED(id); return false; } // -> pass ImGuiItemAddFlags_Focusable flag to ItemAdd() + inline void FocusableItemUnregister(ImGuiWindow* window) { IM_ASSERT(0); IM_UNUSED(window); } // -> unnecessary: TempInputText() uses ImGuiInputTextFlags_MergedItem +#endif + // Logging/Capture IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. IMGUI_API void LogToBuffer(int auto_open_depth = -1); // Start logging/capturing to internal buffer @@ -2287,6 +2396,7 @@ namespace ImGui IMGUI_API ImGuiWindow* GetTopMostPopupModal(); IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window); IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy); + IMGUI_API bool BeginViewportSideBar(const char* name, ImGuiViewport* viewport, ImGuiDir dir, float size, ImGuiWindowFlags window_flags); // Gamepad/Keyboard Navigation IMGUI_API void NavInitWindow(ImGuiWindow* window, bool force_reinit); @@ -2298,8 +2408,7 @@ namespace ImGui IMGUI_API ImVec2 GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f); IMGUI_API int CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate); IMGUI_API void ActivateItem(ImGuiID id); // Remotely activate a button, checkbox, tree node etc. given its unique ID. activation is queued and processed on the next frame when the item is encountered again. - IMGUI_API void SetNavID(ImGuiID id, int nav_layer, ImGuiID focus_scope_id); - IMGUI_API void SetNavIDWithRectRel(ImGuiID id, int nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel); + IMGUI_API void SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel); // Focus Scope (WIP) // This is generally used to identify a selection set (multiple of which may be in the same window), as selection @@ -2340,7 +2449,6 @@ namespace ImGui // Tables: Candidates for public API IMGUI_API void TableOpenContextMenu(int column_n = -1); - IMGUI_API void TableSetColumnEnabled(int column_n, bool enabled); IMGUI_API void TableSetColumnWidth(int column_n, float width); IMGUI_API void TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs); IMGUI_API int TableGetHoveredColumn(); // May use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead. Return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. @@ -2349,6 +2457,7 @@ namespace ImGui IMGUI_API void TablePopBackgroundChannel(); // Tables: Internals + inline ImGuiTable* GetCurrentTable() { ImGuiContext& g = *GImGui; return g.CurrentTable; } IMGUI_API ImGuiTable* TableFindByID(ImGuiID id); IMGUI_API bool BeginTableEx(const char* name, ImGuiID id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0, 0), float inner_width = 0.0f); IMGUI_API void TableBeginInitMemory(ImGuiTable* table, int columns_count); @@ -2377,6 +2486,7 @@ namespace ImGui IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table); IMGUI_API void TableRemove(ImGuiTable* table); IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable* table); + IMGUI_API void TableGcCompactTransientBuffers(ImGuiTableTempData* table); IMGUI_API void TableGcCompactSettings(); // Tables: Settings @@ -2393,7 +2503,8 @@ namespace ImGui IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id); IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id); IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); - IMGUI_API void TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir); + IMGUI_API void TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int offset); + IMGUI_API void TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, ImVec2 mouse_pos); IMGUI_API bool TabBarProcessReorder(ImGuiTabBar* tab_bar); IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags); IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button); @@ -2410,7 +2521,7 @@ namespace ImGui IMGUI_API void RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f); - IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, int rounding_corners_flags = ~0); + IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, ImDrawFlags flags = 0); IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_TypeDefault); // Navigation highlight IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. @@ -2436,11 +2547,12 @@ namespace ImGui IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos); IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0); 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 bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* p_scroll_v, float avail_v, float contents_v, ImDrawFlags flags); IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec2& padding, const ImVec4& bg_col, const ImVec4& tint_col); IMGUI_API ImRect GetWindowScrollbarRect(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 ImGuiID GetWindowResizeCornerID(ImGuiWindow* window, int n); // 0..3: corners + IMGUI_API ImGuiID GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir); IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags); IMGUI_API bool CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value); IMGUI_API bool CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value); @@ -2543,11 +2655,11 @@ IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table //----------------------------------------------------------------------------- #ifdef IMGUI_ENABLE_TEST_ENGINE -extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id); -extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags); -extern void ImGuiTestEngineHook_IdInfo(ImGuiContext* ctx, ImGuiDataType data_type, ImGuiID id, const void* data_id); -extern void ImGuiTestEngineHook_IdInfo(ImGuiContext* ctx, ImGuiDataType data_type, ImGuiID id, const void* data_id, const void* data_id_end); -extern void ImGuiTestEngineHook_Log(ImGuiContext* ctx, const char* fmt, ...); +extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id); +extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags); +extern void ImGuiTestEngineHook_IdInfo(ImGuiContext* ctx, ImGuiDataType data_type, ImGuiID id, const void* data_id); +extern void ImGuiTestEngineHook_IdInfo(ImGuiContext* ctx, ImGuiDataType data_type, ImGuiID id, const void* data_id, const void* data_id_end); +extern void ImGuiTestEngineHook_Log(ImGuiContext* ctx, const char* fmt, ...); #define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemAdd(&g, _BB, _ID) // Register item bounding box #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register item label and status flags (optional) #define IMGUI_TEST_ENGINE_LOG(_FMT,...) if (g.TestEngineHookItems) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log diff --git a/libs/yocto_gui/ext/imgui/imgui_tables.cpp b/libs/yocto_gui/ext/imgui/imgui_tables.cpp index 61a84f9f6..593e3b030 100644 --- a/libs/yocto_gui/ext/imgui/imgui_tables.cpp +++ b/libs/yocto_gui/ext/imgui/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.81 +// dear imgui, v1.83 // (tables and columns code) /* @@ -8,6 +8,7 @@ Index of this file: // [SECTION] Commentary // [SECTION] Header mess // [SECTION] Tables: Main code +// [SECTION] Tables: Simple accessors // [SECTION] Tables: Row changes // [SECTION] Tables: Columns changes // [SECTION] Tables: Columns width management @@ -73,7 +74,7 @@ Index of this file: // (Read carefully because this is subtle but it does make sense!) //----------------------------------------------------------------------------- // About 'outer_size': -// Its meaning needs to differ slightly depending of if we are using ScrollX/ScrollY flags. +// Its meaning needs to differ slightly depending on if we are using ScrollX/ScrollY flags. // Default value is ImVec2(0.0f, 0.0f). // X // - outer_size.x <= 0.0f -> Right-align from window/work-rect right-most edge. With -FLT_MIN or 0.0f will align exactly on right-most edge. @@ -90,7 +91,7 @@ Index of this file: // Outer size is also affected by the NoHostExtendX/NoHostExtendY flags. // Important to that note how the two flags have slightly different behaviors! // - ImGuiTableFlags_NoHostExtendX -> Make outer width auto-fit to columns (overriding outer_size.x value). Only available when ScrollX/ScrollY are disabled and Stretch columns are not used. -// - ImGuiTableFlags_NoHostExtendY -> Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit). Only available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible. +// - ImGuiTableFlags_NoHostExtendY -> Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit). Only available when ScrollX/ScrollY is disabled. Data below the limit will be clipped and not visible. // In theory ImGuiTableFlags_NoHostExtendY could be the default and any non-scrolling tables with outer_size.y != 0.0f would use exact height. // This would be consistent but perhaps less useful and more confusing (as vertically clipped items are not easily noticeable) //----------------------------------------------------------------------------- @@ -132,7 +133,7 @@ Index of this file: // - the typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns. // - using mixed policies with ScrollX does not make much sense, as using Stretch columns with ScrollX does not make much sense in the first place! // that is, unless 'inner_width' is passed to BeginTable() to explicitly provide a total width to layout columns in. -// - when using ImGuiTableFlags_SizingFixedSame with mixed columns, only the Fixed/Auto columns will match their widths to the maximum contents width. +// - when using ImGuiTableFlags_SizingFixedSame with mixed columns, only the Fixed/Auto columns will match their widths to the width of the maximum contents. // - when using ImGuiTableFlags_SizingStretchSame with mixed columns, only the Stretch columns will match their weight/widths. //----------------------------------------------------------------------------- // About using column width: @@ -140,9 +141,9 @@ Index of this file: // - you may use GetContentRegionAvail().x to query the width available in a given column. // - right-side alignment features such as SetNextItemWidth(-x) or PushItemWidth(-x) will rely on this width. // If the column is not resizable and has no width specified with TableSetupColumn(): -// - its width will be automatic and be the set to the max of items submitted. +// - its width will be automatic and be set to the max of items submitted. // - therefore you generally cannot have ALL items of the columns use e.g. SetNextItemWidth(-FLT_MIN). -// - but if the column has one or more item of known/fixed size, this will become the reference width used by SetNextItemWidth(-FLT_MIN). +// - but if the column has one or more items of known/fixed size, this will become the reference width used by SetNextItemWidth(-FLT_MIN). //----------------------------------------------------------------------------- @@ -161,18 +162,18 @@ Index of this file: // - Both TableSetColumnIndex() and TableNextColumn() return true when the column is visible or performing // width measurements. Otherwise, you may skip submitting the contents of a cell/column, BUT ONLY if you know // it is not going to contribute to row height. -// In many situations, you may skip submitting contents for every columns but one (e.g. the first one). +// In many situations, you may skip submitting contents for every column but one (e.g. the first one). // - Case A: column is not hidden by user, and at least partially in sight (most common case). // - Case B: column is clipped / out of sight (because of scrolling or parent ClipRect): TableNextColumn() return false as a hint but we still allow layout output. // - Case C: column is hidden explicitly by the user (e.g. via the context menu, or _DefaultHide column flag, etc.). // -// [A] [B] [C] +// [A] [B] [C] // TableNextColumn(): true false false -> [userland] when TableNextColumn() / TableSetColumnIndex() return false, user can skip submitting items but only if the column doesn't contribute to row height. // SkipItems: false false true -> [internal] when SkipItems is true, most widgets will early out if submitted, resulting is no layout output. // ClipRect: normal zero-width zero-width -> [internal] when ClipRect is zero, ItemAdd() will return false and most widgets will early out mid-way. // ImDrawList output: normal dummy dummy -> [internal] when using the dummy channel, ImDrawList submissions (if any) will be wasted (because cliprect is zero-width anyway). // -// - We need distinguish those cases because non-hidden columns that are clipped outside of scrolling bounds should still contribute their height to the row. +// - We need to distinguish those cases because non-hidden columns that are clipped outside of scrolling bounds should still contribute their height to the row. // However, in the majority of cases, the contribution to row height is the same for all columns, or the tallest cells are known by the programmer. //----------------------------------------------------------------------------- // About clipping/culling of whole Tables: @@ -209,6 +210,8 @@ Index of this file: #if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later #pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types #endif +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). #endif // Clang/GCC warnings with -Weverything @@ -235,6 +238,19 @@ Index of this file: //----------------------------------------------------------------------------- // [SECTION] Tables: Main code //----------------------------------------------------------------------------- +// - TableFixFlags() [Internal] +// - TableFindByID() [Internal] +// - BeginTable() +// - BeginTableEx() [Internal] +// - TableBeginInitMemory() [Internal] +// - TableBeginApplyRequests() [Internal] +// - TableSetupColumnFlags() [Internal] +// - TableUpdateLayout() [Internal] +// - TableUpdateBorders() [Internal] +// - EndTable() +// - TableSetupColumn() +// - TableSetupScrollFreeze() +//----------------------------------------------------------------------------- // Configuration static const int TABLE_DRAW_CHANNEL_BG0 = 0; @@ -327,6 +343,16 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG if (instance_no > 0) IM_ASSERT(table->ColumnsCount == columns_count && "BeginTable(): Cannot change columns count mid-frame while preserving same ID"); + // Acquire temporary buffers + const int table_idx = g.Tables.GetIndex(table); + g.CurrentTableStackIdx++; + if (g.CurrentTableStackIdx + 1 > g.TablesTempDataStack.Size) + g.TablesTempDataStack.resize(g.CurrentTableStackIdx + 1, ImGuiTableTempData()); + ImGuiTableTempData* temp_data = table->TempData = &g.TablesTempDataStack[g.CurrentTableStackIdx]; + temp_data->TableIndex = table_idx; + table->DrawSplitter = &table->TempData->DrawSplitter; + table->DrawSplitter->Clear(); + // Fix flags table->IsDefaultSizingPolicy = (flags & ImGuiTableFlags_SizingMask_) == 0; flags = TableFixFlags(flags, outer_window); @@ -340,7 +366,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG table->ColumnsCount = columns_count; table->IsLayoutLocked = false; table->InnerWidth = inner_width; - table->UserOuterSize = outer_size; + temp_data->UserOuterSize = outer_size; // When not using a child window, WorkRect.Max will grow as we append contents. if (use_child_window) @@ -389,14 +415,14 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG table->HostIndentX = inner_window->DC.Indent.x; table->HostClipRect = inner_window->ClipRect; table->HostSkipItems = inner_window->SkipItems; - table->HostBackupWorkRect = inner_window->WorkRect; - table->HostBackupParentWorkRect = inner_window->ParentWorkRect; - table->HostBackupColumnsOffset = outer_window->DC.ColumnsOffset; - table->HostBackupPrevLineSize = inner_window->DC.PrevLineSize; - table->HostBackupCurrLineSize = inner_window->DC.CurrLineSize; - table->HostBackupCursorMaxPos = inner_window->DC.CursorMaxPos; - table->HostBackupItemWidth = outer_window->DC.ItemWidth; - table->HostBackupItemWidthStackSize = outer_window->DC.ItemWidthStack.Size; + temp_data->HostBackupWorkRect = inner_window->WorkRect; + temp_data->HostBackupParentWorkRect = inner_window->ParentWorkRect; + temp_data->HostBackupColumnsOffset = outer_window->DC.ColumnsOffset; + temp_data->HostBackupPrevLineSize = inner_window->DC.PrevLineSize; + temp_data->HostBackupCurrLineSize = inner_window->DC.CurrLineSize; + temp_data->HostBackupCursorMaxPos = inner_window->DC.CursorMaxPos; + temp_data->HostBackupItemWidth = outer_window->DC.ItemWidth; + temp_data->HostBackupItemWidthStackSize = outer_window->DC.ItemWidthStack.Size; inner_window->DC.PrevLineSize = inner_window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); // Padding and Spacing @@ -439,8 +465,6 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG table->BorderColorLight = GetColorU32(ImGuiCol_TableBorderLight); // Make table current - const int table_idx = g.Tables.GetIndex(table); - g.CurrentTableStack.push_back(ImGuiPtrOrIndex(table_idx)); g.CurrentTable = table; outer_window->DC.CurrentTableIdx = table_idx; if (inner_window != outer_window) // So EndChild() within the inner window can restore the table properly. @@ -453,13 +477,18 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG if (table_idx >= g.TablesLastTimeActive.Size) g.TablesLastTimeActive.resize(table_idx + 1, -1.0f); g.TablesLastTimeActive[table_idx] = (float)g.Time; + temp_data->LastTimeActive = (float)g.Time; table->MemoryCompacted = false; // Setup memory buffer (clear data if columns count changed) - const int stored_size = table->Columns.size(); - if (stored_size != 0 && stored_size != columns_count) - { - IM_FREE(table->RawData); + ImGuiTableColumn* old_columns_to_preserve = NULL; + void* old_columns_raw_data = NULL; + const int old_columns_count = table->Columns.size(); + if (old_columns_count != 0 && old_columns_count != columns_count) + { + // Attempt to preserve width on column count change (#4046) + old_columns_to_preserve = table->Columns.Data; + old_columns_raw_data = table->RawData; table->RawData = NULL; } if (table->RawData == NULL) @@ -482,14 +511,24 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG for (int n = 0; n < columns_count; n++) { ImGuiTableColumn* column = &table->Columns[n]; - float width_auto = column->WidthAuto; - *column = ImGuiTableColumn(); - column->WidthAuto = width_auto; - column->IsPreserveWidthAuto = true; // Preserve WidthAuto when reinitializing a live table: not technically necessary but remove a visible flicker + if (old_columns_to_preserve && n < old_columns_count) + { + // FIXME: We don't attempt to preserve column order in this path. + *column = old_columns_to_preserve[n]; + } + else + { + float width_auto = column->WidthAuto; + *column = ImGuiTableColumn(); + column->WidthAuto = width_auto; + column->IsPreserveWidthAuto = true; // Preserve WidthAuto when reinitializing a live table: not technically necessary but remove a visible flicker + column->IsEnabled = column->IsEnabledNextFrame = true; + } column->DisplayOrder = table->DisplayOrderToIndex[n] = (ImGuiTableColumnIdx)n; - column->IsEnabled = column->IsEnabledNextFrame = true; } } + if (old_columns_raw_data) + IM_FREE(old_columns_raw_data); // Load settings if (table->IsSettingsRequestLoad) @@ -538,9 +577,9 @@ void ImGui::TableBeginInitMemory(ImGuiTable* table, int columns_count) { // Allocate single buffer for our arrays ImSpanAllocator<3> span_allocator; - span_allocator.ReserveBytes(0, columns_count * sizeof(ImGuiTableColumn)); - span_allocator.ReserveBytes(1, columns_count * sizeof(ImGuiTableColumnIdx)); - span_allocator.ReserveBytes(2, columns_count * sizeof(ImGuiTableCellData)); + span_allocator.Reserve(0, columns_count * sizeof(ImGuiTableColumn)); + span_allocator.Reserve(1, columns_count * sizeof(ImGuiTableColumnIdx)); + span_allocator.Reserve(2, columns_count * sizeof(ImGuiTableCellData), 4); table->RawData = IM_ALLOC(span_allocator.GetArenaSizeInBytes()); memset(table->RawData, 0, span_allocator.GetArenaSizeInBytes()); span_allocator.SetArenaBasePtr(table->RawData); @@ -635,7 +674,7 @@ static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, I { IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_WidthMask_)); // Check that only 1 of each set is used. } - + // Resize if ((table->Flags & ImGuiTableFlags_Resizable) == 0) flags |= ImGuiTableColumnFlags_NoResize; @@ -687,13 +726,14 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) table->ColumnsEnabledCount = 0; table->EnabledMaskByIndex = 0x00; table->EnabledMaskByDisplayOrder = 0x00; + table->LeftMostEnabledColumn = -1; table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE // [Part 1] Apply/lock Enabled and Order states. Calculate auto/ideal width for columns. Count fixed/stretch columns. // Process columns in their visible orders as we are building the Prev/Next indices. int count_fixed = 0; // Number of columns that have fixed sizing policies int count_stretch = 0; // Number of columns that have stretch sizing policies - int last_visible_column_idx = -1; + int prev_visible_column_idx = -1; bool has_auto_fit_request = false; bool has_resizable = false; float stretch_sum_width_auto = 0.0f; @@ -741,14 +781,16 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) } // Mark as enabled and link to previous/next enabled column - column->PrevEnabledColumn = (ImGuiTableColumnIdx)last_visible_column_idx; + column->PrevEnabledColumn = (ImGuiTableColumnIdx)prev_visible_column_idx; column->NextEnabledColumn = -1; - if (last_visible_column_idx != -1) - table->Columns[last_visible_column_idx].NextEnabledColumn = (ImGuiTableColumnIdx)column_n; + if (prev_visible_column_idx != -1) + table->Columns[prev_visible_column_idx].NextEnabledColumn = (ImGuiTableColumnIdx)column_n; + else + table->LeftMostEnabledColumn = (ImGuiTableColumnIdx)column_n; column->IndexWithinEnabledSet = table->ColumnsEnabledCount++; table->EnabledMaskByIndex |= (ImU64)1 << column_n; table->EnabledMaskByDisplayOrder |= (ImU64)1 << column->DisplayOrder; - last_visible_column_idx = column_n; + prev_visible_column_idx = column_n; IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder); // Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping) @@ -778,8 +820,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) } if ((table->Flags & ImGuiTableFlags_Sortable) && table->SortSpecsCount == 0 && !(table->Flags & ImGuiTableFlags_SortTristate)) table->IsSortSpecsDirty = true; - table->RightMostEnabledColumn = (ImGuiTableColumnIdx)last_visible_column_idx; - IM_ASSERT(table->RightMostEnabledColumn >= 0); + table->RightMostEnabledColumn = (ImGuiTableColumnIdx)prev_visible_column_idx; + IM_ASSERT(table->LeftMostEnabledColumn >= 0 && table->RightMostEnabledColumn >= 0); // [Part 2] Disable child window clipping while fitting columns. This is not strictly necessary but makes it possible // to avoid the column fitting having to wait until the first visible frame of the child container (may or not be a good thing). @@ -805,7 +847,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // Apply same widths policy float width_auto = column->WidthAuto; if (table_sizing_policy == ImGuiTableFlags_SizingFixedSame && (column->AutoFitQueue != 0x00 || !column_is_resizable)) - width_auto = fixed_max_width_auto; + width_auto = fixed_max_width_auto; // Apply automatic width // Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!) @@ -1084,7 +1126,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // Initial state ImGuiWindow* inner_window = table->InnerWindow; if (table->Flags & ImGuiTableFlags_NoClip) - table->DrawSplitter.SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP); + table->DrawSplitter->SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP); else inner_window->DrawList->PushClipRect(inner_window->ClipRect.Min, inner_window->ClipRect.Max, false); } @@ -1172,6 +1214,7 @@ void ImGui::EndTable() const ImGuiTableFlags flags = table->Flags; ImGuiWindow* inner_window = table->InnerWindow; ImGuiWindow* outer_window = table->OuterWindow; + ImGuiTableTempData* temp_data = table->TempData; IM_ASSERT(inner_window == g.CurrentWindow); IM_ASSERT(outer_window == inner_window || outer_window == inner_window->ParentWindow); @@ -1184,9 +1227,9 @@ void ImGui::EndTable() TableOpenContextMenu((int)table->HoveredColumnBody); // Finalize table height - inner_window->DC.PrevLineSize = table->HostBackupPrevLineSize; - inner_window->DC.CurrLineSize = table->HostBackupCurrLineSize; - inner_window->DC.CursorMaxPos = table->HostBackupCursorMaxPos; + inner_window->DC.PrevLineSize = temp_data->HostBackupPrevLineSize; + inner_window->DC.CurrLineSize = temp_data->HostBackupCurrLineSize; + inner_window->DC.CursorMaxPos = temp_data->HostBackupCursorMaxPos; const float inner_content_max_y = table->RowPosY2; IM_ASSERT(table->RowPosY2 == inner_window->DC.CursorPos.y); if (inner_window != outer_window) @@ -1233,10 +1276,11 @@ void ImGui::EndTable() #endif // Flatten channels and merge draw calls - table->DrawSplitter.SetCurrentChannel(inner_window->DrawList, 0); + ImDrawListSplitter* splitter = table->DrawSplitter; + splitter->SetCurrentChannel(inner_window->DrawList, 0); if ((table->Flags & ImGuiTableFlags_NoClip) == 0) TableMergeDrawChannels(table); - table->DrawSplitter.Merge(inner_window->DrawList); + splitter->Merge(inner_window->DrawList); // Update ColumnsAutoFitWidth to get us ahead for host using our size to auto-resize without waiting for next BeginTable() const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1); @@ -1278,18 +1322,18 @@ void ImGui::EndTable() // Pop from id stack IM_ASSERT_USER_ERROR(inner_window->IDStack.back() == table->ID + table->InstanceCurrent, "Mismatching PushID/PopID!"); - IM_ASSERT_USER_ERROR(outer_window->DC.ItemWidthStack.Size >= table->HostBackupItemWidthStackSize, "Too many PopItemWidth!"); + IM_ASSERT_USER_ERROR(outer_window->DC.ItemWidthStack.Size >= temp_data->HostBackupItemWidthStackSize, "Too many PopItemWidth!"); PopID(); // Restore window data that we modified const ImVec2 backup_outer_max_pos = outer_window->DC.CursorMaxPos; - inner_window->WorkRect = table->HostBackupWorkRect; - inner_window->ParentWorkRect = table->HostBackupParentWorkRect; + inner_window->WorkRect = temp_data->HostBackupWorkRect; + inner_window->ParentWorkRect = temp_data->HostBackupParentWorkRect; inner_window->SkipItems = table->HostSkipItems; outer_window->DC.CursorPos = table->OuterRect.Min; - outer_window->DC.ItemWidth = table->HostBackupItemWidth; - outer_window->DC.ItemWidthStack.Size = table->HostBackupItemWidthStackSize; - outer_window->DC.ColumnsOffset = table->HostBackupColumnsOffset; + outer_window->DC.ItemWidth = temp_data->HostBackupItemWidth; + outer_window->DC.ItemWidthStack.Size = temp_data->HostBackupItemWidthStackSize; + outer_window->DC.ColumnsOffset = temp_data->HostBackupColumnsOffset; // Layout in outer window // (FIXME: To allow auto-fit and allow desirable effect of SameLine() we dissociate 'used' vs 'ideal' size by overriding @@ -1312,20 +1356,20 @@ void ImGui::EndTable() IM_ASSERT((table->Flags & ImGuiTableFlags_ScrollX) == 0); outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth); } - else if (table->UserOuterSize.x <= 0.0f) + else if (temp_data->UserOuterSize.x <= 0.0f) { const float decoration_size = (table->Flags & ImGuiTableFlags_ScrollX) ? inner_window->ScrollbarSizes.x : 0.0f; - outer_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth + decoration_size - table->UserOuterSize.x); + outer_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth + decoration_size - temp_data->UserOuterSize.x); outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table->OuterRect.Max.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth)); } else { outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, table->OuterRect.Max.x); } - if (table->UserOuterSize.y <= 0.0f) + if (temp_data->UserOuterSize.y <= 0.0f) { const float decoration_size = (table->Flags & ImGuiTableFlags_ScrollY) ? inner_window->ScrollbarSizes.y : 0.0f; - outer_window->DC.IdealMaxPos.y = ImMax(outer_window->DC.IdealMaxPos.y, inner_content_max_y + decoration_size - table->UserOuterSize.y); + outer_window->DC.IdealMaxPos.y = ImMax(outer_window->DC.IdealMaxPos.y, inner_content_max_y + decoration_size - temp_data->UserOuterSize.y); outer_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, ImMin(table->OuterRect.Max.y, inner_content_max_y)); } else @@ -1341,8 +1385,15 @@ void ImGui::EndTable() // Clear or restore current table, if any IM_ASSERT(g.CurrentWindow == outer_window && g.CurrentTable == table); - g.CurrentTableStack.pop_back(); - g.CurrentTable = g.CurrentTableStack.Size ? g.Tables.GetByIndex(g.CurrentTableStack.back().Index) : NULL; + IM_ASSERT(g.CurrentTableStackIdx >= 0); + g.CurrentTableStackIdx--; + temp_data = g.CurrentTableStackIdx >= 0 ? &g.TablesTempDataStack[g.CurrentTableStackIdx] : NULL; + g.CurrentTable = temp_data ? g.Tables.GetByIndex(temp_data->TableIndex) : NULL; + if (g.CurrentTable) + { + g.CurrentTable->TempData = temp_data; + g.CurrentTable->DrawSplitter = &temp_data->DrawSplitter; + } outer_window->DC.CurrentTableIdx = g.CurrentTable ? g.Tables.GetIndex(g.CurrentTable) : -1; } @@ -1432,6 +1483,20 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows) table->IsUnfrozenRows = (table->FreezeRowsCount == 0); // Make sure this is set before TableUpdateLayout() so ImGuiListClipper can benefit from it.b } +//----------------------------------------------------------------------------- +// [SECTION] Tables: Simple accessors +//----------------------------------------------------------------------------- +// - TableGetColumnCount() +// - TableGetColumnName() +// - TableGetColumnName() [Internal] +// - TableSetColumnEnabled() [Internal] +// - TableGetColumnFlags() +// - TableGetCellBgRect() [Internal] +// - TableGetColumnResizeID() [Internal] +// - TableGetHoveredColumn() [Internal] +// - TableSetBgColor() +//----------------------------------------------------------------------------- + int ImGui::TableGetColumnCount() { ImGuiContext& g = *GImGui; @@ -1460,6 +1525,9 @@ const char* ImGui::TableGetColumnName(const ImGuiTable* table, int column_n) return &table->ColumnsNames.Buf[column->NameOffset]; } +// Request enabling/disabling a column (often perceived as "showing/hiding" from users point of view) +// Note that end-user can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody) +// Request will be applied during next layout, which happens on the first call to TableNextRow() after BeginTable() // For the getter you can use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsEnabled) void ImGui::TableSetColumnEnabled(int column_n, bool enabled) { @@ -1698,7 +1766,7 @@ void ImGui::TableEndRow(ImGuiTable* table) // always followed by a change of clipping rectangle we perform the smallest overwrite possible here. if ((table->Flags & ImGuiTableFlags_NoClip) == 0) window->DrawList->_CmdHeader.ClipRect = table->Bg0ClipRectForDrawCmd.ToVec4(); - table->DrawSplitter.SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_BG0); + table->DrawSplitter->SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_BG0); } // Draw row background @@ -1770,7 +1838,7 @@ void ImGui::TableEndRow(ImGuiTable* table) // Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y SetWindowClipRectBeforeSetChannel(window, table->Columns[0].ClipRect); - table->DrawSplitter.SetCurrentChannel(window->DrawList, table->Columns[0].DrawChannelCurrent); + table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[0].DrawChannelCurrent); } if (!(table->RowFlags & ImGuiTableRowFlags_Headers)) @@ -1885,14 +1953,14 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n) if (table->Flags & ImGuiTableFlags_NoClip) { // FIXME: if we end up drawing all borders/bg in EndTable, could remove this and just assert that channel hasn't changed. - table->DrawSplitter.SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP); + table->DrawSplitter->SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP); //IM_ASSERT(table->DrawSplitter._Current == TABLE_DRAW_CHANNEL_NOCLIP); } else { // FIXME-TABLE: Could avoid this if draw channel is dummy channel? SetWindowClipRectBeforeSetChannel(window, column->ClipRect); - table->DrawSplitter.SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); + table->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); } // Logging @@ -2140,7 +2208,7 @@ void ImGui::TablePushBackgroundChannel() // Optimization: avoid SetCurrentChannel() + PushClipRect() table->HostBackupInnerClipRect = window->ClipRect; SetWindowClipRectBeforeSetChannel(window, table->Bg2ClipRectForDrawCmd); - table->DrawSplitter.SetCurrentChannel(window->DrawList, table->Bg2DrawChannelCurrent); + table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Bg2DrawChannelCurrent); } void ImGui::TablePopBackgroundChannel() @@ -2152,7 +2220,7 @@ void ImGui::TablePopBackgroundChannel() // Optimization: avoid PopClipRect() + SetCurrentChannel() SetWindowClipRectBeforeSetChannel(window, table->HostBackupInnerClipRect); - table->DrawSplitter.SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); + table->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); } // Allocate draw channels. Called by TableUpdateLayout() @@ -2178,7 +2246,7 @@ void ImGui::TableSetupDrawChannels(ImGuiTable* table) const int channels_for_bg = 1 + 1 * freeze_row_multiplier; const int channels_for_dummy = (table->ColumnsEnabledCount < table->ColumnsCount || table->VisibleMaskByIndex != table->EnabledMaskByIndex) ? +1 : 0; const int channels_total = channels_for_bg + (channels_for_row * freeze_row_multiplier) + channels_for_dummy; - table->DrawSplitter.Split(table->InnerWindow->DrawList, channels_total); + table->DrawSplitter->Split(table->InnerWindow->DrawList, channels_total); table->DummyDrawChannel = (ImGuiTableDrawChannelIdx)((channels_for_dummy > 0) ? channels_total - 1 : -1); table->Bg2DrawChannelCurrent = TABLE_DRAW_CHANNEL_BG2_FROZEN; table->Bg2DrawChannelUnfrozen = (ImGuiTableDrawChannelIdx)((table->FreezeRowsCount > 0) ? 2 + channels_for_row : TABLE_DRAW_CHANNEL_BG2_FROZEN); @@ -2242,7 +2310,7 @@ void ImGui::TableSetupDrawChannels(ImGuiTable* table) void ImGui::TableMergeDrawChannels(ImGuiTable* table) { ImGuiContext& g = *GImGui; - ImDrawListSplitter* splitter = &table->DrawSplitter; + ImDrawListSplitter* splitter = table->DrawSplitter; const bool has_freeze_v = (table->FreezeRowsCount > 0); const bool has_freeze_h = (table->FreezeColumnsCount > 0); IM_ASSERT(splitter->_Current == 0); @@ -2253,10 +2321,11 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table) ImRect ClipRect; int ChannelsCount; ImBitArray ChannelsMask; + + MergeGroup() { ChannelsCount = 0; } }; int merge_group_mask = 0x00; MergeGroup merge_groups[4]; - memset(merge_groups, 0, sizeof(merge_groups)); // 1. Scan channels and take note of those which can be merged for (int column_n = 0; column_n < table->ColumnsCount; column_n++) @@ -2334,7 +2403,6 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table) g.DrawChannelsTempMergeBuffer.resize(splitter->_Count - LEADING_DRAW_CHANNELS); // Use shared temporary storage so the allocation gets amortized ImDrawChannel* dst_tmp = g.DrawChannelsTempMergeBuffer.Data; ImBitArray remaining_mask; // We need 132-bit of storage - remaining_mask.ClearAllBits(); remaining_mask.SetBitRange(LEADING_DRAW_CHANNELS, splitter->_Count); remaining_mask.ClearBit(table->Bg2DrawChannelUnfrozen); IM_ASSERT(has_freeze_v == false || table->Bg2DrawChannelUnfrozen != TABLE_DRAW_CHANNEL_BG2_FROZEN); @@ -2364,7 +2432,7 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table) if ((merge_group_n & 2) != 0 && (table->Flags & ImGuiTableFlags_NoHostExtendY) == 0) merge_clip_rect.Max.y = ImMax(merge_clip_rect.Max.y, host_rect.Max.y); #if 0 - GetOverlayDrawList()->AddRect(merge_group->ClipRect.Min, merge_group->ClipRect.Max, IM_COL32(255, 0, 0, 200), 0.0f, ~0, 1.0f); + GetOverlayDrawList()->AddRect(merge_group->ClipRect.Min, merge_group->ClipRect.Max, IM_COL32(255, 0, 0, 200), 0.0f, 0, 1.0f); GetOverlayDrawList()->AddLine(merge_group->ClipRect.Min, merge_clip_rect.Min, IM_COL32(255, 100, 0, 200)); GetOverlayDrawList()->AddLine(merge_group->ClipRect.Max, merge_clip_rect.Max, IM_COL32(255, 100, 0, 200)); #endif @@ -2413,7 +2481,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table) return; ImDrawList* inner_drawlist = inner_window->DrawList; - table->DrawSplitter.SetCurrentChannel(inner_drawlist, TABLE_DRAW_CHANNEL_BG0); + table->DrawSplitter->SetCurrentChannel(inner_drawlist, TABLE_DRAW_CHANNEL_BG0); inner_drawlist->PushClipRect(table->Bg0ClipRectForDrawCmd.Min, table->Bg0ClipRectForDrawCmd.Max, false); // Draw inner border and resizing feedback @@ -2477,7 +2545,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table) const ImU32 outer_col = table->BorderColorStrong; if ((table->Flags & ImGuiTableFlags_BordersOuter) == ImGuiTableFlags_BordersOuter) { - inner_drawlist->AddRect(outer_border.Min, outer_border.Max, outer_col, 0.0f, ~0, border_size); + inner_drawlist->AddRect(outer_border.Min, outer_border.Max, outer_col, 0.0f, 0, border_size); } else if (table->Flags & ImGuiTableFlags_BordersOuterV) { @@ -2673,20 +2741,22 @@ void ImGui::TableSortSpecsBuild(ImGuiTable* table) TableSortSpecsSanitize(table); // Write output - table->SortSpecsMulti.resize(table->SortSpecsCount <= 1 ? 0 : table->SortSpecsCount); - ImGuiTableColumnSortSpecs* sort_specs = (table->SortSpecsCount == 0) ? NULL : (table->SortSpecsCount == 1) ? &table->SortSpecsSingle : table->SortSpecsMulti.Data; - for (int column_n = 0; column_n < table->ColumnsCount; column_n++) - { - ImGuiTableColumn* column = &table->Columns[column_n]; - if (column->SortOrder == -1) - continue; - IM_ASSERT(column->SortOrder < table->SortSpecsCount); - ImGuiTableColumnSortSpecs* sort_spec = &sort_specs[column->SortOrder]; - sort_spec->ColumnUserID = column->UserID; - sort_spec->ColumnIndex = (ImGuiTableColumnIdx)column_n; - sort_spec->SortOrder = (ImGuiTableColumnIdx)column->SortOrder; - sort_spec->SortDirection = column->SortDirection; - } + ImGuiTableTempData* temp_data = table->TempData; + temp_data->SortSpecsMulti.resize(table->SortSpecsCount <= 1 ? 0 : table->SortSpecsCount); + ImGuiTableColumnSortSpecs* sort_specs = (table->SortSpecsCount == 0) ? NULL : (table->SortSpecsCount == 1) ? &temp_data->SortSpecsSingle : temp_data->SortSpecsMulti.Data; + if (sort_specs != NULL) + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->SortOrder == -1) + continue; + IM_ASSERT(column->SortOrder < table->SortSpecsCount); + ImGuiTableColumnSortSpecs* sort_spec = &sort_specs[column->SortOrder]; + sort_spec->ColumnUserID = column->UserID; + sort_spec->ColumnIndex = (ImGuiTableColumnIdx)column_n; + sort_spec->SortOrder = (ImGuiTableColumnIdx)column->SortOrder; + sort_spec->SortDirection = column->SortDirection; + } table->SortSpecs.Specs = sort_specs; table->SortSpecs.SpecsCount = table->SortSpecsCount; table->SortSpecs.SpecsDirty = true; // Mark as dirty for user @@ -3315,6 +3385,9 @@ static void TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandle for (int column_n = 0; column_n < settings->ColumnsCount; column_n++, column++) { // "Column 0 UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v" + bool save_column = column->UserID != 0 || save_size || save_visible || save_order || (save_sort && column->SortOrder != -1); + if (!save_column) + continue; buf->appendf("Column %-2d", column_n); if (column->UserID != 0) buf->appendf(" UserID=%08X", column->UserID); if (save_size && column->IsStretch) buf->appendf(" Weight=%.4f", column->WidthOrWeight); @@ -3368,8 +3441,6 @@ void ImGui::TableGcCompactTransientBuffers(ImGuiTable* table) //IMGUI_DEBUG_LOG("TableGcCompactTransientBuffers() id=0x%08X\n", table->ID); ImGuiContext& g = *GImGui; IM_ASSERT(table->MemoryCompacted == false); - table->DrawSplitter.ClearFreeMemory(); - table->SortSpecsMulti.clear(); table->SortSpecs.Specs = NULL; table->IsSortSpecsDirty = true; table->ColumnsNames.clear(); @@ -3379,6 +3450,13 @@ void ImGui::TableGcCompactTransientBuffers(ImGuiTable* table) g.TablesLastTimeActive[g.Tables.GetIndex(table)] = -1.0f; } +void ImGui::TableGcCompactTransientBuffers(ImGuiTableTempData* temp_data) +{ + temp_data->DrawSplitter.ClearFreeMemory(); + temp_data->SortSpecsMulti.clear(); + temp_data->LastTimeActive = -1.0f; +} + // Compact and remove unused settings data (currently only used by TestEngine) void ImGui::TableGcCompactSettings() { diff --git a/libs/yocto_gui/ext/imgui/imgui_widgets.cpp b/libs/yocto_gui/ext/imgui/imgui_widgets.cpp index d2a4d1dca..46d2174fe 100644 --- a/libs/yocto_gui/ext/imgui/imgui_widgets.cpp +++ b/libs/yocto_gui/ext/imgui/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.81 +// dear imgui, v1.83 // (widgets code) /* @@ -59,6 +59,8 @@ Index of this file: #if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later #pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types #endif +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). #endif // Clang/GCC warnings with -Weverything @@ -122,7 +124,7 @@ static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1); //------------------------------------------------------------------------- // For InputTextEx() -static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data); +static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source); static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end); static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); @@ -350,17 +352,20 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) const ImGuiStyle& style = g.Style; const float w = CalcItemWidth(); + const char* value_text_begin = &g.TempBuffer[0]; + const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + const ImVec2 value_size = CalcTextSize(value_text_begin, value_text_end, false); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2)); - const ImRect total_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + (label_size.x > 0.0f ? style.ItemInnerSpacing.x : 0.0f), style.FramePadding.y * 2) + label_size); + + const ImVec2 pos = window->DC.CursorPos; + const ImRect value_bb(pos, pos + ImVec2(w, value_size.y + style.FramePadding.y * 2)); + const ImRect total_bb(pos, pos + ImVec2(w + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), ImMax(value_size.y, label_size.y) + style.FramePadding.y * 2)); ItemSize(total_bb, style.FramePadding.y); if (!ItemAdd(total_bb, 0)) return; // Render - const char* value_text_begin = &g.TempBuffer[0]; - const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); - RenderTextClipped(value_bb.Min, value_bb.Max, value_text_begin, value_text_end, NULL, ImVec2(0.0f, 0.5f)); + RenderTextClipped(value_bb.Min + style.FramePadding, value_bb.Max, value_text_begin, value_text_end, &value_size, ImVec2(0.0f, 0.0f)); if (label_size.x > 0.0f) RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label); } @@ -500,7 +505,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool flags |= ImGuiButtonFlags_PressedOnDefault_; ImGuiWindow* backup_hovered_window = g.HoveredWindow; - const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window; + const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindow == window; if (flatten_hovered_children) g.HoveredWindow = window; @@ -683,7 +688,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags if (!ItemAdd(bb, id)) return false; - if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat) + if (g.CurrentItemFlags & ImGuiItemFlags_ButtonRepeat) flags |= ImGuiButtonFlags_Repeat; bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); @@ -759,7 +764,7 @@ bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiBu if (!ItemAdd(bb, id)) return false; - if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat) + if (g.CurrentItemFlags & ImGuiItemFlags_ButtonRepeat) flags |= ImGuiButtonFlags_Repeat; bool hovered, held; @@ -782,22 +787,30 @@ bool ImGui::ArrowButton(const char* str_id, ImGuiDir dir) } // Button to close a window -bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos)//, float size) +bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - // We intentionally allow interaction when clipped so that a mechanical Alt,Right,Validate sequence close a window. - // (this isn't the regular behavior of buttons, but it doesn't affect the user much because navigation tends to keep items visible). + // Tweak 1: Shrink hit-testing area if button covers an abnormally large proportion of the visible region. That's in order to facilitate moving the window away. (#3825) + // This may better be applied as a general hit-rect reduction mechanism for all widgets to ensure the area to move window is always accessible? const ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f); - bool is_clipped = !ItemAdd(bb, id); + ImRect bb_interact = bb; + const float area_to_visible_ratio = window->OuterRectClipped.GetArea() / bb.GetArea(); + if (area_to_visible_ratio < 1.5f) + bb_interact.Expand(ImFloor(bb_interact.GetSize() * -0.25f)); + + // Tweak 2: We intentionally allow interaction when clipped so that a mechanical Alt,Right,Activate sequence can always close a window. + // (this isn't the regular behavior of buttons, but it doesn't affect the user much because navigation tends to keep items visible). + bool is_clipped = !ItemAdd(bb_interact, id); bool hovered, held; - bool pressed = ButtonBehavior(bb, id, &hovered, &held); + bool pressed = ButtonBehavior(bb_interact, id, &hovered, &held); if (is_clipped) return pressed; // Render + // FIXME: Clarify this mess ImU32 col = GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered); ImVec2 center = bb.GetCenter(); if (hovered) @@ -866,19 +879,19 @@ void ImGui::Scrollbar(ImGuiAxis axis) // Calculate scrollbar bounding box ImRect bb = GetWindowScrollbarRect(window, axis); - ImDrawCornerFlags rounding_corners = 0; + ImDrawFlags rounding_corners = ImDrawFlags_RoundCornersNone; if (axis == ImGuiAxis_X) { - rounding_corners |= ImDrawCornerFlags_BotLeft; + rounding_corners |= ImDrawFlags_RoundCornersBottomLeft; if (!window->ScrollbarY) - rounding_corners |= ImDrawCornerFlags_BotRight; + rounding_corners |= ImDrawFlags_RoundCornersBottomRight; } else { if ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) - rounding_corners |= ImDrawCornerFlags_TopRight; + rounding_corners |= ImDrawFlags_RoundCornersTopRight; if (!window->ScrollbarX) - rounding_corners |= ImDrawCornerFlags_BotRight; + rounding_corners |= ImDrawFlags_RoundCornersBottomRight; } float size_avail = window->InnerRect.Max[axis] - window->InnerRect.Min[axis]; float size_contents = window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f; @@ -891,7 +904,7 @@ void ImGui::Scrollbar(ImGuiAxis axis) // - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar // - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal. // Still, the code should probably be made simpler.. -bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, float* p_scroll_v, float size_avail_v, float size_contents_v, ImDrawCornerFlags rounding_corners) +bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, float* p_scroll_v, float size_avail_v, float size_contents_v, ImDrawFlags flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; @@ -971,7 +984,7 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, floa // Render const ImU32 bg_col = GetColorU32(ImGuiCol_ScrollbarBg); const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab, alpha); - window->DrawList->AddRectFilled(bb_frame.Min, bb_frame.Max, bg_col, window->WindowRounding, rounding_corners); + window->DrawList->AddRectFilled(bb_frame.Min, bb_frame.Max, bg_col, window->WindowRounding, flags); ImRect grab_rect; if (axis == ImGuiAxis_X) grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, bb.Max.y); @@ -1070,7 +1083,7 @@ bool ImGui::Checkbox(const char* label, bool* v) ItemSize(total_bb, style.FramePadding.y); if (!ItemAdd(total_bb, id)) { - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); return false; } @@ -1086,7 +1099,7 @@ bool ImGui::Checkbox(const char* label, bool* v) RenderNavHighlight(total_bb, id); RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); ImU32 check_col = GetColorU32(ImGuiCol_CheckMark); - bool mixed_value = (window->DC.ItemFlags & ImGuiItemFlags_MixedValue) != 0; + bool mixed_value = (g.CurrentItemFlags & ImGuiItemFlags_MixedValue) != 0; if (mixed_value) { // Undocumented tristate/mixed/indeterminate checkbox (#2644) @@ -1106,7 +1119,7 @@ bool ImGui::Checkbox(const char* label, bool* v) if (label_size.x > 0.0f) RenderText(label_pos, label); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); return pressed; } @@ -1118,11 +1131,11 @@ bool ImGui::CheckboxFlagsT(const char* label, T* flags, T flags_value) bool pressed; if (!all_on && any_on) { - ImGuiWindow* window = GetCurrentWindow(); - ImGuiItemFlags backup_item_flags = window->DC.ItemFlags; - window->DC.ItemFlags |= ImGuiItemFlags_MixedValue; + ImGuiContext& g = *GImGui; + ImGuiItemFlags backup_item_flags = g.CurrentItemFlags; + g.CurrentItemFlags |= ImGuiItemFlags_MixedValue; pressed = Checkbox(label, &all_on); - window->DC.ItemFlags = backup_item_flags; + g.CurrentItemFlags = backup_item_flags; } else { @@ -1208,7 +1221,7 @@ bool ImGui::RadioButton(const char* label, bool active) if (label_size.x > 0.0f) RenderText(label_pos, label); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); return pressed; } @@ -1420,10 +1433,10 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; - window->DC.ItemFlags |= ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus; + const ImGuiItemFlags item_flags_backup = g.CurrentItemFlags; + g.CurrentItemFlags |= ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus; bool item_add = ItemAdd(bb, id); - window->DC.ItemFlags = item_flags_backup; + g.CurrentItemFlags = item_flags_backup; if (!item_add) return false; @@ -1565,18 +1578,20 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF bool hovered, held; bool pressed = ButtonBehavior(frame_bb, id, &hovered, &held); - bool popup_open = IsPopupOpen(id, ImGuiPopupFlags_None); + + const ImGuiID popup_id = ImHashStr("##ComboPopup", 0, id); + bool popup_open = IsPopupOpen(popup_id, ImGuiPopupFlags_None); const ImU32 frame_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); const float value_x2 = ImMax(frame_bb.Min.x, frame_bb.Max.x - arrow_size); RenderNavHighlight(frame_bb, id); if (!(flags & ImGuiComboFlags_NoPreview)) - window->DrawList->AddRectFilled(frame_bb.Min, ImVec2(value_x2, frame_bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Left); + window->DrawList->AddRectFilled(frame_bb.Min, ImVec2(value_x2, frame_bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersLeft); if (!(flags & ImGuiComboFlags_NoArrowButton)) { ImU32 bg_col = GetColorU32((popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button); ImU32 text_col = GetColorU32(ImGuiCol_Text); - window->DrawList->AddRectFilled(ImVec2(value_x2, frame_bb.Min.y), frame_bb.Max, bg_col, style.FrameRounding, (w <= arrow_size) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Right); + window->DrawList->AddRectFilled(ImVec2(value_x2, frame_bb.Min.y), frame_bb.Max, bg_col, style.FrameRounding, (w <= arrow_size) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersRight); if (value_x2 + arrow_size - style.FramePadding.x <= frame_bb.Max.x) RenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, frame_bb.Min.y + style.FramePadding.y), text_col, ImGuiDir_Down, 1.0f); } @@ -1595,7 +1610,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF { if (window->DC.NavLayerCurrent == 0) window->NavLastIds[0] = id; - OpenPopupEx(id, ImGuiPopupFlags_None); + OpenPopupEx(popup_id, ImGuiPopupFlags_None); popup_open = true; } @@ -1782,7 +1797,7 @@ static const ImGuiDataTypeInfo GDataTypeInfo[] = { sizeof(ImS64), "S64", "%lld", "%lld" }, // ImGuiDataType_S64 { sizeof(ImU64), "U64", "%llu", "%llu" }, #endif - { sizeof(float), "float", "%f", "%f" }, // ImGuiDataType_Float (float are promoted to double in va_arg) + { sizeof(float), "float", "%.3f","%f" }, // ImGuiDataType_Float (float are promoted to double in va_arg) { sizeof(double), "double","%f", "%lf" }, // ImGuiDataType_Double }; IM_STATIC_ASSERT(IM_ARRAYSIZE(GDataTypeInfo) == ImGuiDataType_COUNT); @@ -1969,13 +1984,15 @@ bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_b { // All other types assign constant // We don't bother handling support for legacy operators since they are a little too crappy. Instead we will later implement a proper expression evaluator in the future. - sscanf(buf, format, p_data); + if (sscanf(buf, format, p_data) < 1) + return false; } else { // Small types need a 32-bit buffer to receive the result from scanf() int v32; - sscanf(buf, format, &v32); + if (sscanf(buf, format, &v32) < 1) + return false; if (data_type == ImGuiDataType_S8) *(ImS8*)p_data = (ImS8)ImClamp(v32, (int)IM_S8_MIN, (int)IM_S8_MAX); else if (data_type == ImGuiDataType_U8) @@ -2069,12 +2086,36 @@ static const char* ImAtoi(const char* src, TYPE* output) return src; } +// Sanitize format +// - Zero terminate so extra characters after format (e.g. "%f123") don't confuse atof/atoi +// - stb_sprintf.h supports several new modifiers which format numbers in a way that also makes them incompatible atof/atoi. +static void SanitizeFormatString(const char* fmt, char* fmt_out, size_t fmt_out_size) +{ + IM_UNUSED(fmt_out_size); + const char* fmt_end = ImParseFormatFindEnd(fmt); + IM_ASSERT((size_t)(fmt_end - fmt + 1) < fmt_out_size); // Format is too long, let us know if this happens to you! + while (fmt < fmt_end) + { + char c = *(fmt++); + if (c != '\'' && c != '$' && c != '_') // Custom flags provided by stb_sprintf.h. POSIX 2008 also supports '. + *(fmt_out++) = c; + } + *fmt_out = 0; // Zero-terminate +} + template TYPE ImGui::RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, TYPE v) { const char* fmt_start = ImParseFormatFindStart(format); if (fmt_start[0] != '%' || fmt_start[1] == '%') // Don't apply if the value is not visible in the format string return v; + + // Sanitize format + char fmt_sanitized[32]; + SanitizeFormatString(fmt_start, fmt_sanitized, IM_ARRAYSIZE(fmt_sanitized)); + fmt_start = fmt_sanitized; + + // Format value with our rounding, and read back char v_str[64]; ImFormatString(v_str, IM_ARRAYSIZE(v_str), fmt_start, v); const char* p = v_str; @@ -2112,9 +2153,9 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const { ImGuiContext& g = *GImGui; const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; - const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); const bool is_clamped = (v_min < v_max); - const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) && is_decimal; + const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0; + const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); // Default tweak speed if (v_speed == 0.0f && is_clamped && (v_max - v_min < FLT_MAX)) @@ -2132,7 +2173,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const } else if (g.ActiveIdSource == ImGuiInputSource_Nav) { - int decimal_precision = is_decimal ? ImParseFormatPrecision(format, 3) : 0; + const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0; adjust_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 1.0f / 10.0f, 10.0f)[axis]; v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision)); } @@ -2172,7 +2213,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const if (is_logarithmic) { // When using logarithmic sliders, we need to clamp to avoid hitting zero, but our choice of clamp value greatly affects slider precision. We attempt to use the specified precision to estimate a good lower bound. - const int decimal_precision = is_decimal ? ImParseFormatPrecision(format, 3) : 1; + const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 1; logarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision); // Convert to parametric space, apply delta, convert back @@ -2210,9 +2251,9 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const // Clamp values (+ handle overflow/wrap-around for integer types) if (*v != v_cur && is_clamped) { - if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_decimal)) + if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_floating_point)) v_cur = v_min; - if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f && !is_decimal)) + if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f && !is_floating_point)) v_cur = v_max; } @@ -2238,7 +2279,7 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v } if (g.ActiveId != id) return false; - if ((g.CurrentWindow->DC.ItemFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) + if ((g.CurrentItemFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) return false; switch (data_type) @@ -2271,12 +2312,14 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); const float w = CalcItemWidth(); + const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0; ItemSize(total_bb, style.FramePadding.y); - if (!ItemAdd(total_bb, id, &frame_bb)) + if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemAddFlags_Focusable : 0)) return false; // Default format string when passing NULL @@ -2287,11 +2330,10 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, // Tabbing or CTRL-clicking on Drag turns it into an InputText const bool hovered = ItemHoverable(frame_bb, id); - const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0; bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); if (!temp_input_is_active) { - const bool focus_requested = temp_input_allowed && FocusableItemRegister(window, id); + const bool focus_requested = temp_input_allowed && (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Focused) != 0; const bool clicked = (hovered && g.IO.MouseClicked[0]); const bool double_clicked = (hovered && g.IO.MouseDoubleClicked[0]); if (focus_requested || clicked || double_clicked || g.NavActivateId == id || g.NavInputId == id) @@ -2301,10 +2343,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, FocusWindow(window); g.ActiveIdUsingNavDirMask = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); if (temp_input_allowed && (focus_requested || (clicked && g.IO.KeyCtrl) || double_clicked || g.NavInputId == id)) - { temp_input_is_active = true; - FocusableItemUnregister(window); - } } // Experimental: simple click (without moving) turns Drag into an InputText // FIXME: Currently polling ImGuiConfigFlags_IsTouchScreen, may either poll an hypothetical ImGuiBackendFlags_HasKeyboard and/or an explicit drag settings. @@ -2313,7 +2352,6 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, { g.NavInputId = id; temp_input_is_active = true; - FocusableItemUnregister(window); } } @@ -2344,7 +2382,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); return value_changed; } @@ -2603,7 +2641,7 @@ TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, T { if (v_min == v_max) return v_min; - const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); TYPE result; if (is_logarithmic) @@ -2651,7 +2689,7 @@ TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, T else { // Linear slider - if (is_decimal) + if (is_floating_point) { result = ImLerp(v_min, v_max, t); } @@ -2684,14 +2722,14 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ const ImGuiStyle& style = g.Style; const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; - const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); - const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) && is_decimal; + const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0; + const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); const float grab_padding = 2.0f; const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f; float grab_sz = style.GrabMinSize; SIGNEDTYPE v_range = (v_min < v_max ? v_max - v_min : v_min - v_max); - if (!is_decimal && v_range >= 0) // v_range < 0 may happen on integer overflows + if (!is_floating_point && v_range >= 0) // v_range < 0 may happen on integer overflows grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit grab_sz = ImMin(grab_sz, slider_sz); const float slider_usable_sz = slider_sz - grab_sz; @@ -2703,7 +2741,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ if (is_logarithmic) { // When using logarithmic sliders, we need to clamp to avoid hitting zero, but our choice of clamp value greatly affects slider precision. We attempt to use the specified precision to estimate a good lower bound. - const int decimal_precision = is_decimal ? ImParseFormatPrecision(format, 3) : 1; + const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 1; logarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision); zero_deadzone_halfsize = (style.LogSliderDeadzone * 0.5f) / ImMax(slider_usable_sz, 1.0f); } @@ -2741,7 +2779,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ float input_delta = (axis == ImGuiAxis_X) ? input_delta2.x : -input_delta2.y; if (input_delta != 0.0f) { - const int decimal_precision = is_decimal ? ImParseFormatPrecision(format, 3) : 0; + const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0; if (decimal_precision > 0) { input_delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds @@ -2844,7 +2882,7 @@ bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flag! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead."); ImGuiContext& g = *GImGui; - if ((g.CurrentWindow->DC.ItemFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) + if ((g.CurrentItemFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) return false; switch (data_type) @@ -2894,8 +2932,9 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0; ItemSize(total_bb, style.FramePadding.y); - if (!ItemAdd(total_bb, id, &frame_bb)) + if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemAddFlags_Focusable : 0)) return false; // Default format string when passing NULL @@ -2906,11 +2945,10 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat // Tabbing or CTRL-clicking on Slider turns it into an input box const bool hovered = ItemHoverable(frame_bb, id); - const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0; bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); if (!temp_input_is_active) { - const bool focus_requested = temp_input_allowed && FocusableItemRegister(window, id); + const bool focus_requested = temp_input_allowed && (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Focused) != 0; const bool clicked = (hovered && g.IO.MouseClicked[0]); if (focus_requested || clicked || g.NavActivateId == id || g.NavInputId == id) { @@ -2919,10 +2957,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat FocusWindow(window); g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); if (temp_input_allowed && (focus_requested || (clicked && g.IO.KeyCtrl) || g.NavInputId == id)) - { temp_input_is_active = true; - FocusableItemUnregister(window); - } } } @@ -2958,7 +2993,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); return value_changed; } @@ -3249,7 +3284,7 @@ bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* ClearActiveID(); g.CurrentWindow->DC.CursorPos = bb.Min; - bool value_changed = InputTextEx(label, NULL, buf, buf_size, bb.GetSize(), flags); + bool value_changed = InputTextEx(label, NULL, buf, buf_size, bb.GetSize(), flags | ImGuiInputTextFlags_MergedItem); if (init) { // First frame we started displaying the InputText widget, we expect it to take the active id. @@ -3286,7 +3321,7 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, p_data, NULL); if (p_clamp_min || p_clamp_max) { - if (DataTypeCompare(data_type, p_clamp_min, p_clamp_max) > 0) + if (p_clamp_min && p_clamp_max && DataTypeCompare(data_type, p_clamp_min, p_clamp_max) > 0) ImSwap(p_clamp_min, p_clamp_max); DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max); } @@ -3546,12 +3581,12 @@ static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* t 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_STRINGLEN(const ImGuiInputTextState* obj) { return obj->CurLenW; } +static ImWchar STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { return obj->TextW[idx]; } +static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* 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 >= 0x200000 ? 0 : key; } static ImWchar STB_TEXTEDIT_NEWLINE = '\n'; -static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* obj, int line_start_idx) +static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx) { const ImWchar* text = obj->TextW.Data; const ImWchar* text_remaining = NULL; @@ -3564,19 +3599,20 @@ static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* ob r->num_chars = (int)(text_remaining - (text + line_start_idx)); } +// When ImGuiInputTextFlags_Password is set, we don't want actions such as CTRL+Arrow to leak the fact that underlying data are blanks or separators. static bool is_separator(unsigned int c) { return ImCharIsBlankW(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; } -static int is_word_boundary_from_right(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (is_separator(obj->TextW[idx - 1]) && !is_separator(obj->TextW[idx]) ) : 1; } -static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } +static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) { if (obj->Flags & ImGuiInputTextFlags_Password) return 0; return idx > 0 ? (is_separator(obj->TextW[idx - 1]) && !is_separator(obj->TextW[idx]) ) : 1; } +static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } #ifdef __APPLE__ // FIXME: Move setting to IO structure -static int is_word_boundary_from_left(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (!is_separator(obj->TextW[idx - 1]) && is_separator(obj->TextW[idx]) ) : 1; } -static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } +static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) { if (obj->Flags & ImGuiInputTextFlags_Password) return 0; return idx > 0 ? (!is_separator(obj->TextW[idx - 1]) && is_separator(obj->TextW[idx]) ) : 1; } +static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } #else -static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } +static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } #endif #define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h #define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL -static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n) +static void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState* obj, int pos, int n) { ImWchar* dst = obj->TextW.Data + pos; @@ -3592,9 +3628,9 @@ static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n) *dst = '\0'; } -static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const ImWchar* new_text, int new_text_len) +static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const ImWchar* new_text, int new_text_len) { - const bool is_resizable = (obj->UserFlags & ImGuiInputTextFlags_CallbackResize) != 0; + const bool is_resizable = (obj->Flags & ImGuiInputTextFlags_CallbackResize) != 0; const int text_len = obj->CurLenW; IM_ASSERT(pos <= text_len); @@ -3648,7 +3684,7 @@ static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const Im // stb_textedit internally allows for a single undo record to do addition and deletion, but somehow, calling // the stb_textedit_paste() function creates two separate records, so we perform it manually. (FIXME: Report to nothings/stb?) -static void stb_textedit_replace(STB_TEXTEDIT_STRING* str, STB_TexteditState* state, const STB_TEXTEDIT_CHARTYPE* text, int text_len) +static void stb_textedit_replace(ImGuiInputTextState* str, STB_TexteditState* state, const STB_TEXTEDIT_CHARTYPE* text, int text_len) { stb_text_makeundo_replace(str, state, 0, str->CurLenW, text_len); ImStb::STB_TEXTEDIT_DELETECHARS(str, 0, str->CurLenW); @@ -3731,8 +3767,9 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons } // Return false to discard a character. -static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source) { + IM_ASSERT(input_source == ImGuiInputSource_Keyboard || input_source == ImGuiInputSource_Clipboard); unsigned int c = *p_char; // Filter non-printable (NB: isprint is unreliable! see #2467) @@ -3745,15 +3782,18 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f return false; } - // We ignore Ascii representation of delete (emitted from Backspace on OSX, see #2578, #2817) - if (c == 127) - return false; + if (input_source != ImGuiInputSource_Clipboard) + { + // We ignore Ascii representation of delete (emitted from Backspace on OSX, see #2578, #2817) + if (c == 127) + return false; - // Filter private Unicode range. GLFW on OSX seems to send private characters for special keys like arrow keys (FIXME) - if (c >= 0xE000 && c <= 0xF8FF) - return false; + // Filter private Unicode range. GLFW on OSX seems to send private characters for special keys like arrow keys (FIXME) + if (c >= 0xE000 && c <= 0xF8FF) + return false; + } - // Filter Unicode ranges we are not handling in this build. + // Filter Unicode ranges we are not handling in this build if (c > IM_UNICODE_CODEPOINT_MAX) return false; @@ -3857,7 +3897,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ ImVec2 inner_size = frame_size; if (is_multiline) { - if (!ItemAdd(total_bb, id, &frame_bb)) + if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemAddFlags_Focusable)) { ItemSize(total_bb, style.FramePadding.y); EndGroup(); @@ -3878,15 +3918,17 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ return false; } draw_window = g.CurrentWindow; // Child window - draw_window->DC.NavLayerActiveMaskNext |= (1 << draw_window->DC.NavLayerCurrent); // This is to ensure that EndChild() will display a navigation highlight so we can "enter" into it. + draw_window->DC.NavLayersActiveMaskNext |= (1 << draw_window->DC.NavLayerCurrent); // This is to ensure that EndChild() will display a navigation highlight so we can "enter" into it. draw_window->DC.CursorPos += style.FramePadding; inner_size.x -= draw_window->ScrollbarSizes.x; } else { + // Support for internal ImGuiInputTextFlags_MergedItem flag, which could be redesigned as an ItemFlags if needed (with test performed in ItemAdd) ItemSize(total_bb, style.FramePadding.y); - if (!ItemAdd(total_bb, id, &frame_bb)) - return false; + if (!(flags & ImGuiInputTextFlags_MergedItem)) + if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemAddFlags_Focusable)) + return false; } const bool hovered = ItemHoverable(frame_bb, id); if (hovered) @@ -3895,12 +3937,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // We are only allowed to access the state if we are already the active widget. ImGuiInputTextState* state = GetInputTextState(id); - const bool focus_requested = FocusableItemRegister(window, id); - const bool focus_requested_by_code = focus_requested && (g.FocusRequestCurrWindow == window && g.FocusRequestCurrCounterRegular == window->DC.FocusCounterRegular); - const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code; + const bool focus_requested_by_code = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_FocusedByCode) != 0; + const bool focus_requested_by_tabbing = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; 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_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_Keyboard)); 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); @@ -3910,7 +3951,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ float scroll_y = is_multiline ? draw_window->Scroll.y : FLT_MAX; const bool init_changed_specs = (state != NULL && state->Stb.single_line != !is_multiline); - const bool init_make_active = (focus_requested || user_clicked || user_scroll_finish || user_nav_input_start); + const bool init_make_active = (user_clicked || user_scroll_finish || user_nav_input_start || focus_requested_by_code || focus_requested_by_tabbing); const bool init_state = (init_make_active || user_scroll_active); if ((init_state && g.ActiveId != id) || init_changed_specs) { @@ -3949,9 +3990,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (!is_multiline && focus_requested_by_code) select_all = true; } - if (flags & ImGuiInputTextFlags_AlwaysInsertMode) - state->Stb.insert_mode = 1; - if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl))) + if (flags & ImGuiInputTextFlags_AlwaysOverwrite) + state->Stb.insert_mode = 1; // stb field name is indeed incorrect (see #2863) + if (!is_multiline && (focus_requested_by_tabbing || (user_clicked && io.KeyCtrl))) select_all = true; } @@ -4029,7 +4070,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ backup_current_text_length = state->CurLenA; state->Edited = false; state->BufCapacityA = buf_size; - state->UserFlags = flags; + state->Flags = flags; state->UserCallback = callback; state->UserCallbackData = callback_user_data; @@ -4078,7 +4119,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (!io.InputQueueCharacters.contains('\t')) { unsigned int c = '\t'; // Insert TAB - if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) state->OnKeyPressed((int)c); } @@ -4093,7 +4134,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ unsigned int c = (unsigned int)io.InputQueueCharacters[n]; if (c == '\t' && io.KeyShift) continue; - if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) state->OnKeyPressed((int)c); } @@ -4157,7 +4198,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ else if (!is_readonly) { unsigned int c = '\n'; // Insert new line - if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) state->OnKeyPressed((int)c); } } @@ -4210,7 +4251,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ s += ImTextCharFromUtf8(&c, s, NULL); if (c == 0) break; - if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Clipboard)) continue; clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c; } @@ -4382,7 +4423,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } // Clear temporary user storage - state->UserFlags = 0; + state->Flags = ImGuiInputTextFlags_None; state->UserCallback = NULL; state->UserCallbackData = NULL; } @@ -4566,7 +4607,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { state->CursorAnim += io.DeltaTime; bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f; - ImVec2 cursor_screen_pos = draw_pos + cursor_offset - draw_scroll; + ImVec2 cursor_screen_pos = ImFloor(draw_pos + cursor_offset - draw_scroll); ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f); if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text)); @@ -4616,7 +4657,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited)) MarkItemEdited(id); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0) return enter_pressed; else @@ -4772,11 +4813,14 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag char* p = buf; while (*p == '#' || ImCharIsBlankA(*p)) p++; - i[0] = i[1] = i[2] = i[3] = 0; + i[0] = i[1] = i[2] = 0; + i[3] = 0xFF; // alpha default to 255 is not parsed by scanf (e.g. inputting #FFFFFF omitting alpha) + int r; if (alpha) - sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); // Treat at unsigned (%X is unsigned) + r = sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); // Treat at unsigned (%X is unsigned) else - sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]); + r = sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]); + IM_UNUSED(r); // Fixes C6031: Return value ignored: 'sscanf'. } if (!(flags & ImGuiColorEditFlags_NoOptions)) OpenPopupOnItemClick("context"); @@ -5200,7 +5244,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl const float a1 = (n+1.0f)/6.0f * 2.0f * IM_PI + aeps; const int vert_start_idx = draw_list->VtxBuffer.Size; draw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer)*0.5f, a0, a1, segment_per_arc); - draw_list->PathStroke(col_white, false, wheel_thickness); + draw_list->PathStroke(col_white, 0, wheel_thickness); const int vert_end_idx = draw_list->VtxBuffer.Size; // Paint colors over existing vertices @@ -5326,8 +5370,8 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb.w < 1.0f) { float mid_x = IM_ROUND((bb_inner.Min.x + bb_inner.Max.x) * 0.5f); - RenderColorRectWithAlphaCheckerboard(window->DrawList, 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); + RenderColorRectWithAlphaCheckerboard(window->DrawList, 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, ImDrawFlags_RoundCornersRight); + window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawFlags_RoundCornersLeft); } else { @@ -5336,7 +5380,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl if (col_source.w < 1.0f) RenderColorRectWithAlphaCheckerboard(window->DrawList, bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding); else - window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding, ImDrawCornerFlags_All); + window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding); } RenderNavHighlight(bb, id); if ((flags & ImGuiColorEditFlags_NoBorder) == 0) @@ -5714,7 +5758,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l { if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) TreePushOverrideID(id); - IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.ItemFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.LastItemStatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); return is_open; } @@ -5840,7 +5884,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) TreePushOverrideID(id); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); return is_open; } @@ -5882,7 +5926,7 @@ void ImGui::TreePop() if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) if (g.NavIdIsAlive && (window->DC.TreeJumpToParentOnPopMask & tree_depth_mask)) { - SetNavID(window->IDStack.back(), g.NavLayer, 0); + SetNavID(window->IDStack.back(), g.NavLayer, 0, ImRect()); NavMoveRequestCancel(); } window->DC.TreeJumpToParentOnPopMask &= tree_depth_mask - 1; @@ -6023,10 +6067,10 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl bool item_add; if (flags & ImGuiSelectableFlags_Disabled) { - ImGuiItemFlags backup_item_flags = window->DC.ItemFlags; - window->DC.ItemFlags |= ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNavDefaultFocus; + ImGuiItemFlags backup_item_flags = g.CurrentItemFlags; + g.CurrentItemFlags |= ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNavDefaultFocus; item_add = ItemAdd(bb, id); - window->DC.ItemFlags = backup_item_flags; + g.CurrentItemFlags = backup_item_flags; } else { @@ -6070,8 +6114,8 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl { if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) { + SetNavID(id, window->DC.NavLayerCurrent, window->DC.NavFocusScopeIdCurrent, ImRect(bb.Min - window->Pos, bb.Max - window->Pos)); g.NavDisableHighlight = true; - SetNavID(id, window->DC.NavLayerCurrent, window->DC.NavFocusScopeIdCurrent); } } if (pressed) @@ -6104,10 +6148,10 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor(); // Automatically close popups - if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(window->DC.ItemFlags & ImGuiItemFlags_SelectableDontClosePopup)) + if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(g.CurrentItemFlags & ImGuiItemFlags_SelectableDontClosePopup)) CloseCurrentPopup(); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); return pressed; } @@ -6189,6 +6233,7 @@ void ImGui::EndListBox() ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; IM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) && "Mismatched BeginListBox/EndListBox calls. Did you test the return value of BeginListBox?"); + IM_UNUSED(window); EndChildFrame(); EndGroup(); // This is only required to be able to do IsItemXXX query on the whole ListBox including label @@ -6255,7 +6300,7 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v // Plot/Graph widgets are not very good. // Consider writing your own, or using a third-party one, see: // - ImPlot https://github.com/epezent/implot -// - others https://github.com/ocornut/imgui/wiki/Useful-Widgets +// - others https://github.com/ocornut/imgui/wiki/Useful-Extensions //------------------------------------------------------------------------- int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size) @@ -6547,21 +6592,22 @@ void ImGui::EndMenuBar() // To do so we claim focus back, restore NavId and then process the movement request for yet another frame. // This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth the hassle/cost) const ImGuiNavLayer layer = ImGuiNavLayer_Menu; - IM_ASSERT(window->DC.NavLayerActiveMaskNext & (1 << layer)); // Sanity check + IM_ASSERT(window->DC.NavLayersActiveMaskNext & (1 << layer)); // Sanity check FocusWindow(window); - SetNavIDWithRectRel(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); - g.NavLayer = layer; + SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection. + g.NavDisableMouseHover = g.NavMousePosDirty = true; g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; NavMoveRequestCancel(); } } + IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'" IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); IM_ASSERT(window->DC.MenuBarAppending); PopClipRect(); PopID(); - window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->MenuBarRect().Min.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos. + window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->Pos.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos. g.GroupStack.back().EmitItem = false; EndGroup(); // Restore position on layer 0 window->DC.LayoutType = ImGuiLayoutType_Vertical; @@ -6569,46 +6615,63 @@ void ImGui::EndMenuBar() window->DC.MenuBarAppending = false; } -bool ImGui::BeginMainMenuBar() +// Important: calling order matters! +// FIXME: Somehow overlapping with docking tech. +// FIXME: The "rect-cut" aspect of this could be formalized into a lower-level helper (rect-cut: https://halt.software/dead-simple-layouts) +bool ImGui::BeginViewportSideBar(const char* name, ImGuiViewport* viewport_p, ImGuiDir dir, float axis_size, ImGuiWindowFlags window_flags) { - ImGuiContext& g = *GImGui; - ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport(); - ImGuiWindow* menu_bar_window = FindWindowByName("##MainMenuBar"); + IM_ASSERT(dir != ImGuiDir_None); - // For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set. - g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f)); - - // Get our rectangle at the top of the work area - if (menu_bar_window == NULL || menu_bar_window->BeginCount == 0) + ImGuiWindow* bar_window = FindWindowByName(name); + if (bar_window == NULL || bar_window->BeginCount == 0) { - // Set window position - // We don't attempt to calculate our height ahead, as it depends on the per-viewport font size. - // However menu-bar will affect the minimum window size so we'll get the right height. - ImVec2 menu_bar_pos = viewport->Pos + viewport->CurrWorkOffsetMin; - ImVec2 menu_bar_size = ImVec2(viewport->Size.x - viewport->CurrWorkOffsetMin.x + viewport->CurrWorkOffsetMax.x, 1.0f); - SetNextWindowPos(menu_bar_pos); - SetNextWindowSize(menu_bar_size); + // Calculate and set window size/position + ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)(viewport_p ? viewport_p : GetMainViewport()); + ImRect avail_rect = viewport->GetBuildWorkRect(); + ImGuiAxis axis = (dir == ImGuiDir_Up || dir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X; + ImVec2 pos = avail_rect.Min; + if (dir == ImGuiDir_Right || dir == ImGuiDir_Down) + pos[axis] = avail_rect.Max[axis] - axis_size; + ImVec2 size = avail_rect.GetSize(); + size[axis] = axis_size; + SetNextWindowPos(pos); + SetNextWindowSize(size); + + // Report our size into work area (for next frame) using actual window size + if (dir == ImGuiDir_Up || dir == ImGuiDir_Left) + viewport->BuildWorkOffsetMin[axis] += axis_size; + else if (dir == ImGuiDir_Down || dir == ImGuiDir_Right) + viewport->BuildWorkOffsetMax[axis] -= axis_size; } - // Create window + window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); - PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); // Lift normal size constraint, however the presence of a menu-bar will give us the minimum height we want. - ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar; - bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar(); + PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); // Lift normal size constraint + bool is_open = Begin(name, NULL, window_flags); PopStyleVar(2); - // Report our size into work area (for next frame) using actual window size - menu_bar_window = GetCurrentWindow(); - if (menu_bar_window->BeginCount == 1) - viewport->CurrWorkOffsetMin.y += menu_bar_window->Size.y; + return is_open; +} + +bool ImGui::BeginMainMenuBar() +{ + ImGuiContext& g = *GImGui; + ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport(); + // For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set. + // FIXME: This could be generalized as an opt-in way to clamp window->DC.CursorStartPos to avoid SafeArea? + // FIXME: Consider removing support for safe area down the line... it's messy. Nowadays consoles have support for TV calibration in OS settings. + g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f)); + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar; + float height = GetFrameHeight(); + bool is_open = BeginViewportSideBar("##MainMenuBar", viewport, ImGuiDir_Up, height, window_flags); g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); - if (!is_open) - { + + if (is_open) + BeginMenuBar(); + else End(); - return false; - } - return true; //-V1020 + return is_open; } void ImGui::EndMainMenuBar() @@ -6762,7 +6825,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) if (want_close && IsPopupOpen(id, ImGuiPopupFlags_None)) ClosePopupToLevel(g.BeginPopupStack.Size, true); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0)); if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.BeginPopupStack.Size) { @@ -6822,11 +6885,11 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) { // Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful - // Note that in this situation we render neither the shortcut neither the selected tick mark + // Note that in this situation: we don't render the shortcut, we render a highlight instead of the selected tick mark. float w = label_size.x; window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); - pressed = Selectable(label, false, flags, ImVec2(w, 0.0f)); + pressed = Selectable(label, selected, flags, ImVec2(w, 0.0f)); PopStyleVar(); window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). } @@ -6849,7 +6912,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo RenderCheckMark(window->DrawList, pos + ImVec2(window->DC.MenuColumns.Pos[2] + extra_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled), g.FontSize * 0.866f); } - IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.LastItemStatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0)); return pressed; } @@ -6898,7 +6961,7 @@ namespace ImGui static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label); static float TabBarCalcMaxTabWidth(); static float TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling); - static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImGuiTabBarSection* sections); + static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGuiTabBarSection* sections); static ImGuiTabItem* TabBarScrollingButtons(ImGuiTabBar* tab_bar); static ImGuiTabItem* TabBarTabListPopupButton(ImGuiTabBar* tab_bar); } @@ -6910,12 +6973,17 @@ ImGuiTabBar::ImGuiTabBar() LastTabItemIdx = -1; } +static inline int TabItemGetSectionIdx(const ImGuiTabItem* tab) +{ + return (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1; +} + static int IMGUI_CDECL TabItemComparerBySection(const void* lhs, const void* rhs) { const ImGuiTabItem* a = (const ImGuiTabItem*)lhs; const ImGuiTabItem* b = (const ImGuiTabItem*)rhs; - const int a_section = (a->Flags & ImGuiTabItemFlags_Leading) ? 0 : (a->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1; - const int b_section = (b->Flags & ImGuiTabItemFlags_Leading) ? 0 : (b->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1; + const int a_section = TabItemGetSectionIdx(a); + const int b_section = TabItemGetSectionIdx(b); if (a_section != b_section) return a_section - b_section; return (int)(a->IndexDuringLayout - b->IndexDuringLayout); @@ -7084,11 +7152,11 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) tab->IndexDuringLayout = (ImS16)tab_dst_n; // We will need sorting if tabs have changed section (e.g. moved from one of Leading/Central/Trailing to another) - int curr_tab_section_n = (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1; + int curr_tab_section_n = TabItemGetSectionIdx(tab); if (tab_dst_n > 0) { ImGuiTabItem* prev_tab = &tab_bar->Tabs[tab_dst_n - 1]; - int prev_tab_section_n = (prev_tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (prev_tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1; + int prev_tab_section_n = TabItemGetSectionIdx(prev_tab); if (curr_tab_section_n == 0 && prev_tab_section_n != 0) need_sort_by_section = true; if (prev_tab_section_n == 2 && curr_tab_section_n != 2) @@ -7109,12 +7177,12 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) sections[1].Spacing = sections[1].TabCount > 0 && sections[2].TabCount > 0 ? g.Style.ItemInnerSpacing.x : 0.0f; // Setup next selected tab - ImGuiID scroll_track_selected_tab_id = 0; + ImGuiID scroll_to_tab_id = 0; if (tab_bar->NextSelectedTabId) { tab_bar->SelectedTabId = tab_bar->NextSelectedTabId; tab_bar->NextSelectedTabId = 0; - scroll_track_selected_tab_id = tab_bar->SelectedTabId; + scroll_to_tab_id = tab_bar->SelectedTabId; } // Process order change request (we could probably process it when requested but it's just saner to do it in a single spot). @@ -7122,7 +7190,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) { if (TabBarProcessReorder(tab_bar)) if (tab_bar->ReorderRequestTabId == tab_bar->SelectedTabId) - scroll_track_selected_tab_id = tab_bar->ReorderRequestTabId; + scroll_to_tab_id = tab_bar->ReorderRequestTabId; tab_bar->ReorderRequestTabId = 0; } @@ -7130,7 +7198,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) const bool tab_list_popup_button = (tab_bar->Flags & ImGuiTabBarFlags_TabListPopupButton) != 0; if (tab_list_popup_button) if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Min.x! - scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID; + scroll_to_tab_id = tab_bar->SelectedTabId = tab_to_select->ID; // Leading/Trailing tabs will be shrink only if central one aren't visible anymore, so layout the shrink data as: leading, trailing, central // (whereas our tabs are stored as: leading, central, trailing) @@ -7150,8 +7218,8 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) most_recently_selected_tab = tab; if (tab->ID == tab_bar->SelectedTabId) found_selected_tab_id = true; - if (scroll_track_selected_tab_id == 0 && g.NavJustMovedToId == tab->ID) - scroll_track_selected_tab_id = tab->ID; + if (scroll_to_tab_id == 0 && g.NavJustMovedToId == tab->ID) + scroll_to_tab_id = tab->ID; // Refresh tab width immediately, otherwise changes of style e.g. style.FramePadding.x would noticeably lag in the tab bar. // Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet, @@ -7160,12 +7228,13 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) const bool has_close_button = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) ? false : true; tab->ContentWidth = TabItemCalcSize(tab_name, has_close_button).x; - int section_n = (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1; + int section_n = TabItemGetSectionIdx(tab); ImGuiTabBarSection* section = §ions[section_n]; section->Width += tab->ContentWidth + (section_n == curr_section_n ? g.Style.ItemInnerSpacing.x : 0.0f); curr_section_n = section_n; // Store data so we can build an array sorted by width if we need to shrink tabs down + IM_MSVC_WARNING_SUPPRESS(6385); int shrink_buffer_index = shrink_buffer_indexes[section_n]++; g.ShrinkWidthBuffer[shrink_buffer_index].Index = tab_n; g.ShrinkWidthBuffer[shrink_buffer_index].Width = tab->ContentWidth; @@ -7182,11 +7251,11 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) // Horizontal scrolling buttons // (note that TabBarScrollButtons() will alter BarRect.Max.x) if ((tab_bar->WidthAllTabsIdeal > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll)) - if (ImGuiTabItem* scroll_track_selected_tab = TabBarScrollingButtons(tab_bar)) + if (ImGuiTabItem* scroll_and_select_tab = TabBarScrollingButtons(tab_bar)) { - scroll_track_selected_tab_id = scroll_track_selected_tab->ID; - if (!(scroll_track_selected_tab->Flags & ImGuiTabItemFlags_Button)) - tab_bar->SelectedTabId = scroll_track_selected_tab_id; + scroll_to_tab_id = scroll_and_select_tab->ID; + if ((scroll_and_select_tab->Flags & ImGuiTabItemFlags_Button) == 0) + tab_bar->SelectedTabId = scroll_to_tab_id; } // Shrink widths if full tabs don't fit in their allocated space @@ -7215,7 +7284,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) if (shrinked_width < 0.0f) continue; - int section_n = (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1; + int section_n = TabItemGetSectionIdx(tab); sections[section_n].Width -= (tab->Width - shrinked_width); tab->Width = shrinked_width; } @@ -7246,16 +7315,15 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) if (found_selected_tab_id == false) tab_bar->SelectedTabId = 0; if (tab_bar->SelectedTabId == 0 && tab_bar->NextSelectedTabId == 0 && most_recently_selected_tab != NULL) - scroll_track_selected_tab_id = tab_bar->SelectedTabId = most_recently_selected_tab->ID; + scroll_to_tab_id = tab_bar->SelectedTabId = most_recently_selected_tab->ID; // Lock in visible tab tab_bar->VisibleTabId = tab_bar->SelectedTabId; tab_bar->VisibleTabWasSubmitted = false; // Update scrolling - if (scroll_track_selected_tab_id) - if (ImGuiTabItem* scroll_track_selected_tab = TabBarFindTabByID(tab_bar, scroll_track_selected_tab_id)) - TabBarScrollToTab(tab_bar, scroll_track_selected_tab, sections); + if (scroll_to_tab_id != 0) + TabBarScrollToTab(tab_bar, scroll_to_tab_id, sections); tab_bar->ScrollingAnim = TabBarScrollClamp(tab_bar, tab_bar->ScrollingAnim); tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget); if (tab_bar->ScrollingAnim != tab_bar->ScrollingTarget) @@ -7355,9 +7423,13 @@ static float ImGui::TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling) return ImMax(scrolling, 0.0f); } -static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImGuiTabBarSection* sections) +// Note: we may scroll to tab that are not selected! e.g. using keyboard arrow keys +static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGuiTabBarSection* sections) { - if (tab->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) + ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id); + if (tab == NULL) + return; + if (tab->Flags & ImGuiTabItemFlags_SectionMask_) return; ImGuiContext& g = *GImGui; @@ -7386,12 +7458,48 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, Im } } -void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir) +void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int offset) { - IM_ASSERT(dir == -1 || dir == +1); + IM_ASSERT(offset != 0); IM_ASSERT(tab_bar->ReorderRequestTabId == 0); tab_bar->ReorderRequestTabId = tab->ID; - tab_bar->ReorderRequestDir = (ImS8)dir; + tab_bar->ReorderRequestOffset = (ImS16)offset; +} + +void ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, const ImGuiTabItem* src_tab, ImVec2 mouse_pos) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(tab_bar->ReorderRequestTabId == 0); + if ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) == 0) + return; + + const bool is_central_section = (src_tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0; + const float bar_offset = tab_bar->BarRect.Min.x - (is_central_section ? tab_bar->ScrollingTarget : 0); + + // Count number of contiguous tabs we are crossing over + const int dir = (bar_offset + src_tab->Offset) > mouse_pos.x ? -1 : +1; + const int src_idx = tab_bar->Tabs.index_from_ptr(src_tab); + int dst_idx = src_idx; + for (int i = src_idx; i >= 0 && i < tab_bar->Tabs.Size; i += dir) + { + // Reordered tabs must share the same section + const ImGuiTabItem* dst_tab = &tab_bar->Tabs[i]; + if (dst_tab->Flags & ImGuiTabItemFlags_NoReorder) + break; + if ((dst_tab->Flags & ImGuiTabItemFlags_SectionMask_) != (src_tab->Flags & ImGuiTabItemFlags_SectionMask_)) + break; + dst_idx = i; + + // Include spacing after tab, so when mouse cursor is between tabs we would not continue checking further tabs that are not hovered. + const float x1 = bar_offset + dst_tab->Offset - g.Style.ItemInnerSpacing.x; + const float x2 = bar_offset + dst_tab->Offset + dst_tab->Width + g.Style.ItemInnerSpacing.x; + //GetForegroundDrawList()->AddRect(ImVec2(x1, tab_bar->BarRect.Min.y), ImVec2(x2, tab_bar->BarRect.Max.y), IM_COL32(255, 0, 0, 255)); + if ((dir < 0 && mouse_pos.x > x1) || (dir > 0 && mouse_pos.x < x2)) + break; + } + + if (dst_idx != src_idx) + TabBarQueueReorder(tab_bar, src_tab, dst_idx - src_idx); } bool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar) @@ -7401,19 +7509,23 @@ bool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar) return false; //IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools - int tab2_order = tab_bar->GetTabOrder(tab1) + tab_bar->ReorderRequestDir; + int tab2_order = tab_bar->GetTabOrder(tab1) + tab_bar->ReorderRequestOffset; if (tab2_order < 0 || tab2_order >= tab_bar->Tabs.Size) return false; - // Reordered TabItem must share the same position flags than target + // Reordered tabs must share the same section + // (Note: TabBarQueueReorderFromMousePos() also has a similar test but since we allow direct calls to TabBarQueueReorder() we do it here too) ImGuiTabItem* tab2 = &tab_bar->Tabs[tab2_order]; if (tab2->Flags & ImGuiTabItemFlags_NoReorder) return false; - if ((tab1->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) != (tab2->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing))) + if ((tab1->Flags & ImGuiTabItemFlags_SectionMask_) != (tab2->Flags & ImGuiTabItemFlags_SectionMask_)) return false; ImGuiTabItem item_tmp = *tab1; - *tab1 = *tab2; + ImGuiTabItem* src_tab = (tab_bar->ReorderRequestOffset > 0) ? tab1 + 1 : tab2; + ImGuiTabItem* dst_tab = (tab_bar->ReorderRequestOffset > 0) ? tab1 : tab2 + 1; + const int move_count = (tab_bar->ReorderRequestOffset > 0) ? tab_bar->ReorderRequestOffset : -tab_bar->ReorderRequestOffset; + memmove(dst_tab, src_tab, move_count * sizeof(ImGuiTabItem)); *tab2 = item_tmp; if (tab_bar->Flags & ImGuiTabBarFlags_SaveSettings) @@ -7695,7 +7807,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, const ImVec2 backup_main_cursor_pos = window->DC.CursorPos; // Layout - const bool is_central_section = (tab->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) == 0; + const bool is_central_section = (tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0; size.x = tab->Width; if (is_central_section) window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(IM_FLOOR(tab->Offset - tab_bar->ScrollingAnim), 0.0f); @@ -7743,13 +7855,11 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // While moving a tab it will jump on the other side of the mouse, so we also test for MouseDelta.x if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < bb.Min.x) { - if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) - TabBarQueueReorder(tab_bar, tab, -1); + TabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos); } else if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > bb.Max.x) { - if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) - TabBarQueueReorder(tab_bar, tab, +1); + TabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos); } } } @@ -7856,7 +7966,7 @@ void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabI draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding + 0.5f, y1 + rounding + 0.5f), rounding, 6, 9); draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding - 0.5f, y1 + rounding + 0.5f), rounding, 9, 12); draw_list->PathLineTo(ImVec2(bb.Max.x - 0.5f, y2)); - draw_list->PathStroke(GetColorU32(ImGuiCol_Border), false, g.Style.TabBorderSize); + draw_list->PathStroke(GetColorU32(ImGuiCol_Border), 0, g.Style.TabBorderSize); } } diff --git a/libs/yocto_gui/yocto_imgui.cpp b/libs/yocto_gui/yocto_imgui.cpp index 1a1d3e7ce..4ef8618bc 100644 --- a/libs/yocto_gui/yocto_imgui.cpp +++ b/libs/yocto_gui/yocto_imgui.cpp @@ -996,7 +996,7 @@ struct ImGuiAppLog { ImGui::TextUnformatted(Buf.begin()); } - if (ScrollToBottom) ImGui::SetScrollHere(1.0f); + if (ScrollToBottom) ImGui::SetScrollHereY(1.0f); ScrollToBottom = false; ImGui::PopStyleVar(); ImGui::EndChild(); diff --git a/tests/arealights1/arealights1.json b/tests/arealights1/arealights1.json index 2d65b9a23..6afe68a5c 100644 --- a/tests/arealights1/arealights1.json +++ b/tests/arealights1/arealights1.json @@ -7,50 +7,50 @@ "cameras": { "default": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "aspect": 2.4000000953674316, "focus": 1.2168092727661133 }, "front": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 0.936329185962677, -0.3511234223842621 ], - [ 0.0, 0.3511234223842621, 0.936329185962677 ], - [ 0.0, 0.574999988079071, 1.399999976158142 ] + [1.0, 0.0, 0.0], + [0.0, 0.936329185962677, -0.3511234223842621], + [0.0, 0.3511234223842621, 0.936329185962677], + [0.0, 0.574999988079071, 1.399999976158142] ], "aspect": 3.0, "focus": 1.4952006340026855 }, "back": { "frame": [ - [ -1.0, 0.0, 0.0 ], - [ 0.0, 0.936329185962677, 0.3511234223842621 ], - [ 0.0, 0.3511234223842621, -0.936329185962677 ], - [ 0.0, 0.574999988079071, -1.399999976158142 ] + [-1.0, 0.0, 0.0], + [0.0, 0.936329185962677, 0.3511234223842621], + [0.0, 0.3511234223842621, -0.936329185962677], + [0.0, 0.574999988079071, -1.399999976158142] ], "aspect": 3.0, "focus": 1.4952006340026855 }, "perspective-sharp": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "aspect": 2.4000000953674316, "focus": 1.2168092727661133 }, "perspective-dof": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "aspect": 2.4000000953674316, "focus": 1.2168092727661133, @@ -58,10 +58,10 @@ }, "orthographic-sharp": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "orthographic": true, "aspect": 2.4000000953674316, @@ -69,10 +69,10 @@ }, "orthographic-dof": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "orthographic": true, "aspect": 2.4000000953674316, @@ -86,39 +86,39 @@ }, "materials": { "floor": { - "color": [ 0.699999988079071, 0.699999988079071, 0.699999988079071 ], + "color": [0.699999988079071, 0.699999988079071, 0.699999988079071], "color_tex": "floor" }, "arealight1": { - "emission": [ 20.0, 20.0, 20.0 ] + "emission": [20.0, 20.0, 20.0] }, "arealight2": { - "emission": [ 20.0, 20.0, 20.0 ] + "emission": [20.0, 20.0, 20.0] }, "bunny-uvgrid": { "type": "glossy", - "color": [ 1.0, 1.0, 1.0 ], + "color": [1.0, 1.0, 1.0], "roughness": 0.10000000149011612, "color_tex": "uvgrid" }, "sphere-plastic-sharp": { "type": "glossy", - "color": [ 0.5, 0.5, 0.699999988079071 ], + "color": [0.5, 0.5, 0.699999988079071], "roughness": 0.009999999776482582 }, "bunny-metal-rough": { - "type": "metallic", - "color": [ 0.6600000262260437, 0.44999998807907104, 0.3400000035762787 ], + "type": "reflective", + "color": [0.6600000262260437, 0.44999998807907104, 0.3400000035762787], "roughness": 0.20000000298023224 }, "sphere-plastic-rough": { "type": "glossy", - "color": [ 0.5, 0.699999988079071, 0.5 ], + "color": [0.5, 0.699999988079071, 0.5], "roughness": 0.20000000298023224 }, "bunny-metal-sharp": { - "type": "metallic", - "color": [ 0.699999988079071, 0.699999988079071, 0.699999988079071 ] + "type": "reflective", + "color": [0.699999988079071, 0.699999988079071, 0.699999988079071] } }, "shapes": { @@ -135,40 +135,40 @@ }, "arealight1": { "frame": [ - [ 0.8944271802902222, -0.0, 0.4472135901451111 ], - [ 0.27562475204467773, 0.7874992489814758, -0.5512495040893555 ], - [ -0.3521803617477417, 0.6163156628608704, 0.7043607234954834 ], - [ -0.4000000059604645, 0.800000011920929, 0.800000011920929 ] + [0.8944271802902222, -0.0, 0.4472135901451111], + [0.27562475204467773, 0.7874992489814758, -0.5512495040893555], + [-0.3521803617477417, 0.6163156628608704, 0.7043607234954834], + [-0.4000000059604645, 0.800000011920929, 0.800000011920929] ], "shape": "arealight1", "material": "arealight1" }, "arealight2": { "frame": [ - [ 0.8944271802902222, 0.0, -0.4472135901451111 ], - [ -0.27562475204467773, 0.7874992489814758, -0.5512495040893555 ], - [ 0.3521803617477417, 0.6163156628608704, 0.7043607234954834 ], - [ 0.4000000059604645, 0.800000011920929, 0.800000011920929 ] + [0.8944271802902222, 0.0, -0.4472135901451111], + [-0.27562475204467773, 0.7874992489814758, -0.5512495040893555], + [0.3521803617477417, 0.6163156628608704, 0.7043607234954834], + [0.4000000059604645, 0.800000011920929, 0.800000011920929] ], "shape": "arealight2", "material": "arealight2" }, "bunny-uvgrid": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ -0.4000000059604645, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [-0.4000000059604645, 0.0, 0.0] ], "shape": "bunny", "material": "bunny-uvgrid" }, "sphere-plastic-sharp": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ -0.20000000298023224, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [-0.20000000298023224, 0.0, 0.0] ], "shape": "sphere", "material": "sphere-plastic-sharp" @@ -179,23 +179,23 @@ }, "sphere-plastic-rough": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.20000000298023224, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.20000000298023224, 0.0, 0.0] ], "shape": "sphere", "material": "sphere-plastic-rough" }, "bunny-metal-sharp": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.4000000059604645, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.4000000059604645, 0.0, 0.0] ], "shape": "bunny", "material": "bunny-metal-sharp" } } -} \ No newline at end of file +} diff --git a/tests/environments1/environments1.json b/tests/environments1/environments1.json index 2370faba1..cfc000105 100644 --- a/tests/environments1/environments1.json +++ b/tests/environments1/environments1.json @@ -7,50 +7,50 @@ "cameras": { "default": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "aspect": 2.4000000953674316, "focus": 1.2168092727661133 }, "front": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 0.936329185962677, -0.3511234223842621 ], - [ 0.0, 0.3511234223842621, 0.936329185962677 ], - [ 0.0, 0.574999988079071, 1.399999976158142 ] + [1.0, 0.0, 0.0], + [0.0, 0.936329185962677, -0.3511234223842621], + [0.0, 0.3511234223842621, 0.936329185962677], + [0.0, 0.574999988079071, 1.399999976158142] ], "aspect": 3.0, "focus": 1.4952006340026855 }, "back": { "frame": [ - [ -1.0, 0.0, 0.0 ], - [ 0.0, 0.936329185962677, 0.3511234223842621 ], - [ 0.0, 0.3511234223842621, -0.936329185962677 ], - [ 0.0, 0.574999988079071, -1.399999976158142 ] + [-1.0, 0.0, 0.0], + [0.0, 0.936329185962677, 0.3511234223842621], + [0.0, 0.3511234223842621, -0.936329185962677], + [0.0, 0.574999988079071, -1.399999976158142] ], "aspect": 3.0, "focus": 1.4952006340026855 }, "perspective-sharp": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "aspect": 2.4000000953674316, "focus": 1.2168092727661133 }, "perspective-dof": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "aspect": 2.4000000953674316, "focus": 1.2168092727661133, @@ -58,10 +58,10 @@ }, "orthographic-sharp": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "orthographic": true, "aspect": 2.4000000953674316, @@ -69,10 +69,10 @@ }, "orthographic-dof": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "orthographic": true, "aspect": 2.4000000953674316, @@ -87,33 +87,33 @@ }, "materials": { "floor": { - "color": [ 0.699999988079071, 0.699999988079071, 0.699999988079071 ], + "color": [0.699999988079071, 0.699999988079071, 0.699999988079071], "color_tex": "floor" }, "bunny-uvgrid": { "type": "glossy", - "color": [ 1.0, 1.0, 1.0 ], + "color": [1.0, 1.0, 1.0], "roughness": 0.10000000149011612, "color_tex": "uvgrid" }, "sphere-plastic-sharp": { "type": "glossy", - "color": [ 0.5, 0.5, 0.699999988079071 ], + "color": [0.5, 0.5, 0.699999988079071], "roughness": 0.009999999776482582 }, "bunny-metal-rough": { - "type": "metallic", - "color": [ 0.6600000262260437, 0.44999998807907104, 0.3400000035762787 ], + "type": "reflective", + "color": [0.6600000262260437, 0.44999998807907104, 0.3400000035762787], "roughness": 0.20000000298023224 }, "sphere-plastic-rough": { "type": "glossy", - "color": [ 0.5, 0.699999988079071, 0.5 ], + "color": [0.5, 0.699999988079071, 0.5], "roughness": 0.20000000298023224 }, "bunny-metal-sharp": { - "type": "metallic", - "color": [ 0.699999988079071, 0.699999988079071, 0.699999988079071 ] + "type": "reflective", + "color": [0.699999988079071, 0.699999988079071, 0.699999988079071] } }, "shapes": { @@ -128,20 +128,20 @@ }, "bunny-uvgrid": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ -0.4000000059604645, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [-0.4000000059604645, 0.0, 0.0] ], "shape": "bunny", "material": "bunny-uvgrid" }, "sphere-plastic-sharp": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ -0.20000000298023224, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [-0.20000000298023224, 0.0, 0.0] ], "shape": "sphere", "material": "sphere-plastic-sharp" @@ -152,20 +152,20 @@ }, "sphere-plastic-rough": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.20000000298023224, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.20000000298023224, 0.0, 0.0] ], "shape": "sphere", "material": "sphere-plastic-rough" }, "bunny-metal-sharp": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.4000000059604645, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.4000000059604645, 0.0, 0.0] ], "shape": "bunny", "material": "bunny-metal-sharp" @@ -173,8 +173,8 @@ }, "environments": { "sunsky": { - "emission": [ 1.0, 1.0, 1.0 ], + "emission": [1.0, 1.0, 1.0], "emission_tex": "sunsky" } } -} \ No newline at end of file +} diff --git a/tests/environments2/environments2.json b/tests/environments2/environments2.json index 60759b0c3..ebb669b60 100644 --- a/tests/environments2/environments2.json +++ b/tests/environments2/environments2.json @@ -7,50 +7,50 @@ "cameras": { "default": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "aspect": 2.4000000953674316, "focus": 1.2168092727661133 }, "front": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 0.936329185962677, -0.3511234223842621 ], - [ 0.0, 0.3511234223842621, 0.936329185962677 ], - [ 0.0, 0.574999988079071, 1.399999976158142 ] + [1.0, 0.0, 0.0], + [0.0, 0.936329185962677, -0.3511234223842621], + [0.0, 0.3511234223842621, 0.936329185962677], + [0.0, 0.574999988079071, 1.399999976158142] ], "aspect": 3.0, "focus": 1.4952006340026855 }, "back": { "frame": [ - [ -1.0, 0.0, 0.0 ], - [ 0.0, 0.936329185962677, 0.3511234223842621 ], - [ 0.0, 0.3511234223842621, -0.936329185962677 ], - [ 0.0, 0.574999988079071, -1.399999976158142 ] + [-1.0, 0.0, 0.0], + [0.0, 0.936329185962677, 0.3511234223842621], + [0.0, 0.3511234223842621, -0.936329185962677], + [0.0, 0.574999988079071, -1.399999976158142] ], "aspect": 3.0, "focus": 1.4952006340026855 }, "perspective-sharp": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "aspect": 2.4000000953674316, "focus": 1.2168092727661133 }, "perspective-dof": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "aspect": 2.4000000953674316, "focus": 1.2168092727661133, @@ -58,10 +58,10 @@ }, "orthographic-sharp": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "orthographic": true, "aspect": 2.4000000953674316, @@ -69,10 +69,10 @@ }, "orthographic-dof": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "orthographic": true, "aspect": 2.4000000953674316, @@ -87,33 +87,33 @@ }, "materials": { "floor": { - "color": [ 0.699999988079071, 0.699999988079071, 0.699999988079071 ], + "color": [0.699999988079071, 0.699999988079071, 0.699999988079071], "color_tex": "floor" }, "bunny-uvgrid": { "type": "glossy", - "color": [ 1.0, 1.0, 1.0 ], + "color": [1.0, 1.0, 1.0], "roughness": 0.10000000149011612, "color_tex": "uvgrid" }, "sphere-plastic-sharp": { "type": "glossy", - "color": [ 0.5, 0.5, 0.699999988079071 ], + "color": [0.5, 0.5, 0.699999988079071], "roughness": 0.009999999776482582 }, "bunny-metal-rough": { - "type": "metallic", - "color": [ 0.6600000262260437, 0.44999998807907104, 0.3400000035762787 ], + "type": "reflective", + "color": [0.6600000262260437, 0.44999998807907104, 0.3400000035762787], "roughness": 0.20000000298023224 }, "sphere-plastic-rough": { "type": "glossy", - "color": [ 0.5, 0.699999988079071, 0.5 ], + "color": [0.5, 0.699999988079071, 0.5], "roughness": 0.20000000298023224 }, "bunny-metal-sharp": { - "type": "metallic", - "color": [ 0.699999988079071, 0.699999988079071, 0.699999988079071 ] + "type": "reflective", + "color": [0.699999988079071, 0.699999988079071, 0.699999988079071] } }, "shapes": { @@ -128,20 +128,20 @@ }, "bunny-uvgrid": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ -0.4000000059604645, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [-0.4000000059604645, 0.0, 0.0] ], "shape": "bunny", "material": "bunny-uvgrid" }, "sphere-plastic-sharp": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ -0.20000000298023224, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [-0.20000000298023224, 0.0, 0.0] ], "shape": "sphere", "material": "sphere-plastic-sharp" @@ -152,20 +152,20 @@ }, "sphere-plastic-rough": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.20000000298023224, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.20000000298023224, 0.0, 0.0] ], "shape": "sphere", "material": "sphere-plastic-rough" }, "bunny-metal-sharp": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.4000000059604645, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.4000000059604645, 0.0, 0.0] ], "shape": "bunny", "material": "bunny-metal-sharp" @@ -173,8 +173,8 @@ }, "environments": { "sky": { - "emission": [ 1.0, 1.0, 1.0 ], + "emission": [1.0, 1.0, 1.0], "emission_tex": "sky" } } -} \ No newline at end of file +} diff --git a/tests/features1/features1.json b/tests/features1/features1.json index 3ebb6dd0e..d995b01c3 100644 --- a/tests/features1/features1.json +++ b/tests/features1/features1.json @@ -7,50 +7,50 @@ "cameras": { "default": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "aspect": 2.4000000953674316, "focus": 1.2168092727661133 }, "front": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 0.936329185962677, -0.3511234223842621 ], - [ 0.0, 0.3511234223842621, 0.936329185962677 ], - [ 0.0, 0.574999988079071, 1.399999976158142 ] + [1.0, 0.0, 0.0], + [0.0, 0.936329185962677, -0.3511234223842621], + [0.0, 0.3511234223842621, 0.936329185962677], + [0.0, 0.574999988079071, 1.399999976158142] ], "aspect": 3.0, "focus": 1.4952006340026855 }, "back": { "frame": [ - [ -1.0, 0.0, 0.0 ], - [ 0.0, 0.936329185962677, 0.3511234223842621 ], - [ 0.0, 0.3511234223842621, -0.936329185962677 ], - [ 0.0, 0.574999988079071, -1.399999976158142 ] + [-1.0, 0.0, 0.0], + [0.0, 0.936329185962677, 0.3511234223842621], + [0.0, 0.3511234223842621, -0.936329185962677], + [0.0, 0.574999988079071, -1.399999976158142] ], "aspect": 3.0, "focus": 1.4952006340026855 }, "perspective-sharp": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "aspect": 2.4000000953674316, "focus": 1.2168092727661133 }, "perspective-dof": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "aspect": 2.4000000953674316, "focus": 1.2168092727661133, @@ -58,10 +58,10 @@ }, "orthographic-sharp": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "orthographic": true, "aspect": 2.4000000953674316, @@ -69,10 +69,10 @@ }, "orthographic-dof": { "frame": [ - [ 0.8151804208755493, -0.0, 0.579207181930542 ], - [ 0.16660168766975403, 0.9577393531799316, -0.23447643220424652 ], - [ -0.5547295212745667, 0.28763750195503235, 0.7807304263114929 ], - [ -0.75, 0.4000000059604645, 0.8999999761581421 ] + [0.8151804208755493, -0.0, 0.579207181930542], + [0.16660168766975403, 0.9577393531799316, -0.23447643220424652], + [-0.5547295212745667, 0.28763750195503235, 0.7807304263114929], + [-0.75, 0.4000000059604645, 0.8999999761581421] ], "orthographic": true, "aspect": 2.4000000953674316, @@ -88,40 +88,42 @@ }, "materials": { "floor": { - "color": [ 0.699999988079071, 0.699999988079071, 0.699999988079071 ], + "color": [0.699999988079071, 0.699999988079071, 0.699999988079071], "color_tex": "floor" }, "bunny-uvgrid-coated": { "type": "glossy", - "color": [ 1.0, 1.0, 1.0 ], + "color": [1.0, 1.0, 1.0], "roughness": 0.20000000298023224, "color_tex": "uvgrid" }, "bunny-volume-jade": { "type": "refractive", - "color": [ 0.5, 0.5, 0.5 ], - "scattering": [ 0.30000001192092896, 0.6000000238418579, 0.30000001192092896 ] + "color": [0.5, 0.5, 0.5], + "scattering": [ + 0.30000001192092896, 0.6000000238418579, 0.30000001192092896 + ] }, "bunny-metal-rough": { - "type": "metallic", - "color": [ 0.6600000262260437, 0.44999998807907104, 0.3400000035762787 ], + "type": "reflective", + "color": [0.6600000262260437, 0.44999998807907104, 0.3400000035762787], "roughness": 0.20000000298023224 }, "sphere-volume-glass": { "type": "refractive", - "color": [ 1.0, 0.5, 0.5 ] + "color": [1.0, 0.5, 0.5] }, "sphere-plastic-rough-bumped": { "type": "glossy", - "color": [ 0.5, 0.699999988079071, 0.5 ], + "color": [0.5, 0.699999988079071, 0.5], "roughness": 0.20000000298023224, "normal_tex": "bumps-normal" }, "arealight1": { - "emission": [ 20.0, 20.0, 20.0 ] + "emission": [20.0, 20.0, 20.0] }, "arealight2": { - "emission": [ 20.0, 20.0, 20.0 ] + "emission": [20.0, 20.0, 20.0] } }, "shapes": { @@ -138,10 +140,10 @@ }, "bunny-uvgrid-coated": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ -0.4000000059604645, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [-0.4000000059604645, 0.0, 0.0] ], "shape": "bunny", "material": "bunny-uvgrid-coated" @@ -152,50 +154,50 @@ }, "bunny-metal-rough": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.4000000059604645, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.4000000059604645, 0.0, 0.0] ], "shape": "bunny", "material": "bunny-metal-rough" }, "sphere-volume-glass": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ -0.20000000298023224, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [-0.20000000298023224, 0.0, 0.0] ], "shape": "sphere", "material": "sphere-volume-glass" }, "sphere-plastic-rough-bumped": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.20000000298023224, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.20000000298023224, 0.0, 0.0] ], "shape": "sphere", "material": "sphere-plastic-rough-bumped" }, "arealight1": { "frame": [ - [ 0.8944271802902222, -0.0, 0.4472135901451111 ], - [ 0.27562475204467773, 0.7874992489814758, -0.5512495040893555 ], - [ -0.3521803617477417, 0.6163156628608704, 0.7043607234954834 ], - [ -0.4000000059604645, 0.800000011920929, 0.800000011920929 ] + [0.8944271802902222, -0.0, 0.4472135901451111], + [0.27562475204467773, 0.7874992489814758, -0.5512495040893555], + [-0.3521803617477417, 0.6163156628608704, 0.7043607234954834], + [-0.4000000059604645, 0.800000011920929, 0.800000011920929] ], "shape": "arealight1", "material": "arealight1" }, "arealight2": { "frame": [ - [ 0.8944271802902222, 0.0, -0.4472135901451111 ], - [ -0.27562475204467773, 0.7874992489814758, -0.5512495040893555 ], - [ 0.3521803617477417, 0.6163156628608704, 0.7043607234954834 ], - [ 0.4000000059604645, 0.800000011920929, 0.800000011920929 ] + [0.8944271802902222, 0.0, -0.4472135901451111], + [-0.27562475204467773, 0.7874992489814758, -0.5512495040893555], + [0.3521803617477417, 0.6163156628608704, 0.7043607234954834], + [0.4000000059604645, 0.800000011920929, 0.800000011920929] ], "shape": "arealight2", "material": "arealight2" @@ -203,8 +205,8 @@ }, "environments": { "sky": { - "emission": [ 0.5, 0.5, 0.5 ], + "emission": [0.5, 0.5, 0.5], "emission_tex": "sky" } } -} \ No newline at end of file +} diff --git a/tests/furnace1/furnace1.json b/tests/furnace1/furnace1.json index 49629af4f..698403a12 100644 --- a/tests/furnace1/furnace1.json +++ b/tests/furnace1/furnace1.json @@ -7,10 +7,10 @@ "cameras": { "default": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.0, 0.0, 1.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.0, 0.0, 1.0] ], "aspect": 2.4000000953674316, "focus": 1.0 @@ -18,8 +18,8 @@ }, "materials": { "sphere": { - "type": "metallic", - "color": [ 1.0, 1.0, 1.0 ], + "type": "reflective", + "color": [1.0, 1.0, 1.0], "roughness": 0.5 } }, @@ -29,10 +29,10 @@ "instances": { "sphere": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.0, -0.07500000298023224, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.0, -0.07500000298023224, 0.0] ], "shape": "sphere", "material": "sphere" @@ -40,7 +40,7 @@ }, "environments": { "env": { - "emission": [ 0.5, 0.5, 0.5 ] + "emission": [0.5, 0.5, 0.5] } } -} \ No newline at end of file +} diff --git a/tests/furnace2/furnace2.json b/tests/furnace2/furnace2.json index 48f349f53..859a55022 100644 --- a/tests/furnace2/furnace2.json +++ b/tests/furnace2/furnace2.json @@ -144,27 +144,27 @@ }, "materials": { "metallic-0": { - "type": "metallic", + "type": "reflective", "color": [1, 1, 1], "roughness": 0 }, "metallic-0.25": { - "type": "metallic", + "type": "reflective", "color": [1, 1, 1], "roughness": 0.25 }, "metallic-0.5": { - "type": "metallic", + "type": "reflective", "color": [1, 1, 1], "roughness": 0.5 }, "metallic-0.75": { - "type": "metallic", + "type": "reflective", "color": [1, 1, 1], "roughness": 0.75 }, "metallic-1": { - "type": "metallic", + "type": "reflective", "color": [1, 1, 1], "roughness": 1 }, diff --git a/tests/materials1/materials1.json b/tests/materials1/materials1.json index 0fecba4ba..57ab4874c 100644 --- a/tests/materials1/materials1.json +++ b/tests/materials1/materials1.json @@ -7,10 +7,10 @@ "cameras": { "default": { "frame": [ - [ 0.9805806875228882, -0.0, 0.1961161345243454 ], - [ 0.08506310731172562, 0.9010388255119324, -0.4253155291080475 ], - [ -0.17670825123786926, 0.43373844027519226, 0.8835412859916687 ], - [ -0.6000000238418579, 1.5, 2.75 ] + [0.9805806875228882, -0.0, 0.1961161345243454], + [0.08506310731172562, 0.9010388255119324, -0.4253155291080475], + [-0.17670825123786926, 0.43373844027519226, 0.8835412859916687], + [-0.6000000238418579, 1.5, 2.75] ], "lens": 0.10000000149011612, "aspect": 2.4000000953674316, @@ -18,10 +18,10 @@ }, "front": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 0.8853979110717773, -0.46483391523361206 ], - [ 0.0, 0.46483391523361206, 0.8853979110717773 ], - [ 0.0, 1.75, 3.0 ] + [1.0, 0.0, 0.0], + [0.0, 0.8853979110717773, -0.46483391523361206], + [0.0, 0.46483391523361206, 0.8853979110717773], + [0.0, 1.75, 3.0] ], "lens": 0.10000000149011612, "aspect": 3.0, @@ -29,10 +29,10 @@ }, "back": { "frame": [ - [ -1.0, 0.0, 0.0 ], - [ 0.0, 0.9026037454605103, 0.4304725229740143 ], - [ 0.0, 0.4304724931716919, -0.9026036858558655 ], - [ 0.0, 1.5, -3.25 ] + [-1.0, 0.0, 0.0], + [0.0, 0.9026037454605103, 0.4304725229740143], + [0.0, 0.4304724931716919, -0.9026036858558655], + [0.0, 1.5, -3.25] ], "lens": 0.10000000149011612, "aspect": 3.0, @@ -40,10 +40,10 @@ }, "perspective-sharp": { "frame": [ - [ 0.9805806875228882, -0.0, 0.1961161345243454 ], - [ 0.08506310731172562, 0.9010388255119324, -0.4253155291080475 ], - [ -0.17670825123786926, 0.43373844027519226, 0.8835412859916687 ], - [ -0.6000000238418579, 1.5, 2.75 ] + [0.9805806875228882, -0.0, 0.1961161345243454], + [0.08506310731172562, 0.9010388255119324, -0.4253155291080475], + [-0.17670825123786926, 0.43373844027519226, 0.8835412859916687], + [-0.6000000238418579, 1.5, 2.75] ], "lens": 0.10000000149011612, "aspect": 2.4000000953674316, @@ -51,10 +51,10 @@ }, "perspective-dof": { "frame": [ - [ 0.9805806875228882, -0.0, 0.1961161345243454 ], - [ 0.08506310731172562, 0.9010388255119324, -0.4253155291080475 ], - [ -0.17670825123786926, 0.43373844027519226, 0.8835412859916687 ], - [ -0.6000000238418579, 1.5, 2.75 ] + [0.9805806875228882, -0.0, 0.1961161345243454], + [0.08506310731172562, 0.9010388255119324, -0.4253155291080475], + [-0.17670825123786926, 0.43373844027519226, 0.8835412859916687], + [-0.6000000238418579, 1.5, 2.75] ], "lens": 0.10000000149011612, "aspect": 2.4000000953674316, @@ -63,10 +63,10 @@ }, "orthographic-sharp": { "frame": [ - [ 0.9756097197532654, -0.0, 0.2195121943950653 ], - [ 0.08407647162675858, 0.9237421154975891, -0.3736732006072998 ], - [ -0.20277264714241028, 0.3830150067806244, 0.9012117385864258 ], - [ -0.5, 1.0, 2.0 ] + [0.9756097197532654, -0.0, 0.2195121943950653], + [0.08407647162675858, 0.9237421154975891, -0.3736732006072998], + [-0.20277264714241028, 0.3830150067806244, 0.9012117385864258], + [-0.5, 1.0, 2.0] ], "orthographic": true, "lens": 0.029999999329447746, @@ -75,10 +75,10 @@ }, "orthographic-dof": { "frame": [ - [ 0.9756097197532654, -0.0, 0.2195121943950653 ], - [ 0.08407647162675858, 0.9237421154975891, -0.3736732006072998 ], - [ -0.20277264714241028, 0.3830150067806244, 0.9012117385864258 ], - [ -0.5, 1.0, 2.0 ] + [0.9756097197532654, -0.0, 0.2195121943950653], + [0.08407647162675858, 0.9237421154975891, -0.3736732006072998], + [-0.20277264714241028, 0.3830150067806244, 0.9012117385864258], + [-0.5, 1.0, 2.0] ], "orthographic": true, "lens": 0.029999999329447746, @@ -93,59 +93,59 @@ }, "materials": { "floor": { - "color": [ 0.699999988079071, 0.699999988079071, 0.699999988079071 ], + "color": [0.699999988079071, 0.699999988079071, 0.699999988079071], "color_tex": "floor" }, "largearealight1": { - "emission": [ 10.0, 10.0, 10.0 ] + "emission": [10.0, 10.0, 10.0] }, "largearealight2": { - "emission": [ 10.0, 10.0, 10.0 ] + "emission": [10.0, 10.0, 10.0] }, "sphere-plastic-sharp": { "type": "glossy", - "color": [ 0.5, 0.5, 0.699999988079071 ], + "color": [0.5, 0.5, 0.699999988079071], "roughness": 0.009999999776482582 }, "sphere-plastic-rough": { "type": "glossy", - "color": [ 0.5, 0.699999988079071, 0.5 ], + "color": [0.5, 0.699999988079071, 0.5], "roughness": 0.20000000298023224 }, "sphere-matte": { - "color": [ 0.699999988079071, 0.699999988079071, 0.699999988079071 ], + "color": [0.699999988079071, 0.699999988079071, 0.699999988079071], "roughness": 1.0 }, "sphere-metal-sharp": { - "type": "metallic", - "color": [ 0.699999988079071, 0.699999988079071, 0.699999988079071 ] + "type": "reflective", + "color": [0.699999988079071, 0.699999988079071, 0.699999988079071] }, "sphere-metal-rough": { - "type": "metallic", - "color": [ 0.6600000262260437, 0.44999998807907104, 0.3400000035762787 ], + "type": "reflective", + "color": [0.6600000262260437, 0.44999998807907104, 0.3400000035762787], "roughness": 0.20000000298023224 }, "bunny-plastic-sharp": { "type": "glossy", - "color": [ 0.5, 0.5, 0.699999988079071 ], + "color": [0.5, 0.5, 0.699999988079071], "roughness": 0.009999999776482582 }, "bunny-plastic-rough": { "type": "glossy", - "color": [ 0.5, 0.699999988079071, 0.5 ], + "color": [0.5, 0.699999988079071, 0.5], "roughness": 0.20000000298023224 }, "bunny-matte": { - "color": [ 0.699999988079071, 0.699999988079071, 0.699999988079071 ], + "color": [0.699999988079071, 0.699999988079071, 0.699999988079071], "roughness": 1.0 }, "bunny-metal-sharp": { - "type": "metallic", - "color": [ 0.699999988079071, 0.699999988079071, 0.699999988079071 ] + "type": "reflective", + "color": [0.699999988079071, 0.699999988079071, 0.699999988079071] }, "bunny-metal-rough": { - "type": "metallic", - "color": [ 0.6600000262260437, 0.44999998807907104, 0.3400000035762787 ], + "type": "reflective", + "color": [0.6600000262260437, 0.44999998807907104, 0.3400000035762787], "roughness": 0.20000000298023224 } }, @@ -163,40 +163,40 @@ }, "largearealight1": { "frame": [ - [ 0.8944271802902222, -0.0, 0.4472135901451111 ], - [ 0.2873478829860687, 0.766261100769043, -0.5746957659721375 ], - [ -0.3426823318004608, 0.6425293684005737, 0.6853646636009216 ], - [ -0.800000011920929, 1.600000023841858, 1.600000023841858 ] + [0.8944271802902222, -0.0, 0.4472135901451111], + [0.2873478829860687, 0.766261100769043, -0.5746957659721375], + [-0.3426823318004608, 0.6425293684005737, 0.6853646636009216], + [-0.800000011920929, 1.600000023841858, 1.600000023841858] ], "shape": "largearealight1", "material": "largearealight1" }, "largearealight2": { "frame": [ - [ 0.8944271802902222, 0.0, -0.4472135901451111 ], - [ -0.2873478829860687, 0.766261100769043, -0.5746957659721375 ], - [ 0.3426823318004608, 0.6425293684005737, 0.6853646636009216 ], - [ 0.800000011920929, 1.600000023841858, 1.600000023841858 ] + [0.8944271802902222, 0.0, -0.4472135901451111], + [-0.2873478829860687, 0.766261100769043, -0.5746957659721375], + [0.3426823318004608, 0.6425293684005737, 0.6853646636009216], + [0.800000011920929, 1.600000023841858, 1.600000023841858] ], "shape": "largearealight2", "material": "largearealight2" }, "sphere-plastic-sharp": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ -0.4000000059604645, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [-0.4000000059604645, 0.0, 0.0] ], "shape": "sphere", "material": "sphere-plastic-sharp" }, "sphere-plastic-rough": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ -0.20000000298023224, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [-0.20000000298023224, 0.0, 0.0] ], "shape": "sphere", "material": "sphere-plastic-rough" @@ -207,70 +207,70 @@ }, "sphere-metal-sharp": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.20000000298023224, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.20000000298023224, 0.0, 0.0] ], "shape": "sphere", "material": "sphere-metal-sharp" }, "sphere-metal-rough": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.4000000059604645, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.4000000059604645, 0.0, 0.0] ], "shape": "sphere", "material": "sphere-metal-rough" }, "bunny-plastic-sharp": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ -0.4000000059604645, 0.0, -0.4000000059604645 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [-0.4000000059604645, 0.0, -0.4000000059604645] ], "shape": "bunny", "material": "bunny-plastic-sharp" }, "bunny-plastic-rough": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ -0.20000000298023224, 0.0, -0.4000000059604645 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [-0.20000000298023224, 0.0, -0.4000000059604645] ], "shape": "bunny", "material": "bunny-plastic-rough" }, "bunny-matte": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.0, 0.0, -0.4000000059604645 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.0, 0.0, -0.4000000059604645] ], "shape": "bunny", "material": "bunny-matte" }, "bunny-metal-sharp": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.20000000298023224, 0.0, -0.4000000059604645 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.20000000298023224, 0.0, -0.4000000059604645] ], "shape": "bunny", "material": "bunny-metal-sharp" }, "bunny-metal-rough": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.4000000059604645, 0.0, -0.4000000059604645 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.4000000059604645, 0.0, -0.4000000059604645] ], "shape": "bunny", "material": "bunny-metal-rough" @@ -278,8 +278,8 @@ }, "environments": { "sky": { - "emission": [ 0.5, 0.5, 0.5 ], + "emission": [0.5, 0.5, 0.5], "emission_tex": "sky" } } -} \ No newline at end of file +} diff --git a/tests/materials3/materials3.json b/tests/materials3/materials3.json index 39f30dad2..cd9516685 100644 --- a/tests/materials3/materials3.json +++ b/tests/materials3/materials3.json @@ -7,10 +7,10 @@ "cameras": { "default": { "frame": [ - [ 0.9805806875228882, -0.0, 0.1961161345243454 ], - [ 0.08506310731172562, 0.9010388255119324, -0.4253155291080475 ], - [ -0.17670825123786926, 0.43373844027519226, 0.8835412859916687 ], - [ -0.6000000238418579, 1.5, 2.75 ] + [0.9805806875228882, -0.0, 0.1961161345243454], + [0.08506310731172562, 0.9010388255119324, -0.4253155291080475], + [-0.17670825123786926, 0.43373844027519226, 0.8835412859916687], + [-0.6000000238418579, 1.5, 2.75] ], "lens": 0.10000000149011612, "aspect": 2.4000000953674316, @@ -18,10 +18,10 @@ }, "front": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 0.8853979110717773, -0.46483391523361206 ], - [ 0.0, 0.46483391523361206, 0.8853979110717773 ], - [ 0.0, 1.75, 3.0 ] + [1.0, 0.0, 0.0], + [0.0, 0.8853979110717773, -0.46483391523361206], + [0.0, 0.46483391523361206, 0.8853979110717773], + [0.0, 1.75, 3.0] ], "lens": 0.10000000149011612, "aspect": 3.0, @@ -29,10 +29,10 @@ }, "back": { "frame": [ - [ -1.0, 0.0, 0.0 ], - [ 0.0, 0.9026037454605103, 0.4304725229740143 ], - [ 0.0, 0.4304724931716919, -0.9026036858558655 ], - [ 0.0, 1.5, -3.25 ] + [-1.0, 0.0, 0.0], + [0.0, 0.9026037454605103, 0.4304725229740143], + [0.0, 0.4304724931716919, -0.9026036858558655], + [0.0, 1.5, -3.25] ], "lens": 0.10000000149011612, "aspect": 3.0, @@ -40,10 +40,10 @@ }, "perspective-sharp": { "frame": [ - [ 0.9805806875228882, -0.0, 0.1961161345243454 ], - [ 0.08506310731172562, 0.9010388255119324, -0.4253155291080475 ], - [ -0.17670825123786926, 0.43373844027519226, 0.8835412859916687 ], - [ -0.6000000238418579, 1.5, 2.75 ] + [0.9805806875228882, -0.0, 0.1961161345243454], + [0.08506310731172562, 0.9010388255119324, -0.4253155291080475], + [-0.17670825123786926, 0.43373844027519226, 0.8835412859916687], + [-0.6000000238418579, 1.5, 2.75] ], "lens": 0.10000000149011612, "aspect": 2.4000000953674316, @@ -51,10 +51,10 @@ }, "perspective-dof": { "frame": [ - [ 0.9805806875228882, -0.0, 0.1961161345243454 ], - [ 0.08506310731172562, 0.9010388255119324, -0.4253155291080475 ], - [ -0.17670825123786926, 0.43373844027519226, 0.8835412859916687 ], - [ -0.6000000238418579, 1.5, 2.75 ] + [0.9805806875228882, -0.0, 0.1961161345243454], + [0.08506310731172562, 0.9010388255119324, -0.4253155291080475], + [-0.17670825123786926, 0.43373844027519226, 0.8835412859916687], + [-0.6000000238418579, 1.5, 2.75] ], "lens": 0.10000000149011612, "aspect": 2.4000000953674316, @@ -63,10 +63,10 @@ }, "orthographic-sharp": { "frame": [ - [ 0.9756097197532654, -0.0, 0.2195121943950653 ], - [ 0.08407647162675858, 0.9237421154975891, -0.3736732006072998 ], - [ -0.20277264714241028, 0.3830150067806244, 0.9012117385864258 ], - [ -0.5, 1.0, 2.0 ] + [0.9756097197532654, -0.0, 0.2195121943950653], + [0.08407647162675858, 0.9237421154975891, -0.3736732006072998], + [-0.20277264714241028, 0.3830150067806244, 0.9012117385864258], + [-0.5, 1.0, 2.0] ], "orthographic": true, "lens": 0.029999999329447746, @@ -75,10 +75,10 @@ }, "orthographic-dof": { "frame": [ - [ 0.9756097197532654, -0.0, 0.2195121943950653 ], - [ 0.08407647162675858, 0.9237421154975891, -0.3736732006072998 ], - [ -0.20277264714241028, 0.3830150067806244, 0.9012117385864258 ], - [ -0.5, 1.0, 2.0 ] + [0.9756097197532654, -0.0, 0.2195121943950653], + [0.08407647162675858, 0.9237421154975891, -0.3736732006072998], + [-0.20277264714241028, 0.3830150067806244, 0.9012117385864258], + [-0.5, 1.0, 2.0] ], "orthographic": true, "lens": 0.029999999329447746, @@ -94,65 +94,65 @@ }, "materials": { "floor": { - "color": [ 0.699999988079071, 0.699999988079071, 0.699999988079071 ], + "color": [0.699999988079071, 0.699999988079071, 0.699999988079071], "color_tex": "floor" }, "largearealight1": { - "emission": [ 10.0, 10.0, 10.0 ] + "emission": [10.0, 10.0, 10.0] }, "largearealight2": { - "emission": [ 10.0, 10.0, 10.0 ] + "emission": [10.0, 10.0, 10.0] }, "sphere-plastic-sharp-bumped": { "type": "glossy", - "color": [ 0.5, 0.5, 0.699999988079071 ], + "color": [0.5, 0.5, 0.699999988079071], "roughness": 0.009999999776482582, "normal_tex": "bumps-normal" }, "sphere-plastic-rough-coated": { "type": "glossy", - "color": [ 0.5, 0.699999988079071, 0.5 ], + "color": [0.5, 0.699999988079071, 0.5], "roughness": 0.20000000298023224 }, "sphere-metal-sharp-bumped": { - "type": "metallic", - "color": [ 0.699999988079071, 0.699999988079071, 0.699999988079071 ], + "type": "reflective", + "color": [0.699999988079071, 0.699999988079071, 0.699999988079071], "normal_tex": "bumps-normal" }, "sphere-metal-rough-coated": { - "type": "metallic", - "color": [ 0.6600000262260437, 0.44999998807907104, 0.3400000035762787 ], + "type": "reflective", + "color": [0.6600000262260437, 0.44999998807907104, 0.3400000035762787], "roughness": 0.20000000298023224 }, "sphere-metal-rough": { - "type": "metallic", - "color": [ 0.6600000262260437, 0.44999998807907104, 0.3400000035762787 ], + "type": "reflective", + "color": [0.6600000262260437, 0.44999998807907104, 0.3400000035762787], "roughness": 0.20000000298023224 }, "bunny-plastic-sharp-bumped": { "type": "glossy", - "color": [ 0.5, 0.5, 0.699999988079071 ], + "color": [0.5, 0.5, 0.699999988079071], "roughness": 0.009999999776482582, "normal_tex": "bumps-normal" }, "bunny-plastic-rough-coated": { "type": "glossy", - "color": [ 0.5, 0.699999988079071, 0.5 ], + "color": [0.5, 0.699999988079071, 0.5], "roughness": 0.20000000298023224 }, "bunny-metal-sharp-bumped": { - "type": "metallic", - "color": [ 0.699999988079071, 0.699999988079071, 0.699999988079071 ], + "type": "reflective", + "color": [0.699999988079071, 0.699999988079071, 0.699999988079071], "normal_tex": "bumps-normal" }, "bunny-metal-rough-coated": { - "type": "metallic", - "color": [ 0.6600000262260437, 0.44999998807907104, 0.3400000035762787 ], + "type": "reflective", + "color": [0.6600000262260437, 0.44999998807907104, 0.3400000035762787], "roughness": 0.20000000298023224 }, "bunny-metal-rough": { - "type": "metallic", - "color": [ 0.6600000262260437, 0.44999998807907104, 0.3400000035762787 ], + "type": "reflective", + "color": [0.6600000262260437, 0.44999998807907104, 0.3400000035762787], "roughness": 0.20000000298023224 } }, @@ -170,40 +170,40 @@ }, "largearealight1": { "frame": [ - [ 0.8944271802902222, -0.0, 0.4472135901451111 ], - [ 0.2873478829860687, 0.766261100769043, -0.5746957659721375 ], - [ -0.3426823318004608, 0.6425293684005737, 0.6853646636009216 ], - [ -0.800000011920929, 1.600000023841858, 1.600000023841858 ] + [0.8944271802902222, -0.0, 0.4472135901451111], + [0.2873478829860687, 0.766261100769043, -0.5746957659721375], + [-0.3426823318004608, 0.6425293684005737, 0.6853646636009216], + [-0.800000011920929, 1.600000023841858, 1.600000023841858] ], "shape": "largearealight1", "material": "largearealight1" }, "largearealight2": { "frame": [ - [ 0.8944271802902222, 0.0, -0.4472135901451111 ], - [ -0.2873478829860687, 0.766261100769043, -0.5746957659721375 ], - [ 0.3426823318004608, 0.6425293684005737, 0.6853646636009216 ], - [ 0.800000011920929, 1.600000023841858, 1.600000023841858 ] + [0.8944271802902222, 0.0, -0.4472135901451111], + [-0.2873478829860687, 0.766261100769043, -0.5746957659721375], + [0.3426823318004608, 0.6425293684005737, 0.6853646636009216], + [0.800000011920929, 1.600000023841858, 1.600000023841858] ], "shape": "largearealight2", "material": "largearealight2" }, "sphere-plastic-sharp-bumped": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ -0.4000000059604645, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [-0.4000000059604645, 0.0, 0.0] ], "shape": "sphere", "material": "sphere-plastic-sharp-bumped" }, "sphere-plastic-rough-coated": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ -0.20000000298023224, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [-0.20000000298023224, 0.0, 0.0] ], "shape": "sphere", "material": "sphere-plastic-rough-coated" @@ -214,70 +214,70 @@ }, "sphere-metal-rough-coated": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.20000000298023224, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.20000000298023224, 0.0, 0.0] ], "shape": "sphere", "material": "sphere-metal-rough-coated" }, "sphere-metal-rough": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.4000000059604645, 0.0, 0.0 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.4000000059604645, 0.0, 0.0] ], "shape": "sphere", "material": "sphere-metal-rough" }, "bunny-plastic-sharp-bumped": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ -0.4000000059604645, 0.0, -0.4000000059604645 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [-0.4000000059604645, 0.0, -0.4000000059604645] ], "shape": "bunny", "material": "bunny-plastic-sharp-bumped" }, "bunny-plastic-rough-coated": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ -0.20000000298023224, 0.0, -0.4000000059604645 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [-0.20000000298023224, 0.0, -0.4000000059604645] ], "shape": "bunny", "material": "bunny-plastic-rough-coated" }, "bunny-metal-sharp-bumped": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.0, 0.0, -0.4000000059604645 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.0, 0.0, -0.4000000059604645] ], "shape": "bunny", "material": "bunny-metal-sharp-bumped" }, "bunny-metal-rough-coated": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.20000000298023224, 0.0, -0.4000000059604645 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.20000000298023224, 0.0, -0.4000000059604645] ], "shape": "bunny", "material": "bunny-metal-rough-coated" }, "bunny-metal-rough": { "frame": [ - [ 1.0, 0.0, 0.0 ], - [ 0.0, 1.0, 0.0 ], - [ 0.0, 0.0, 1.0 ], - [ 0.4000000059604645, 0.0, -0.4000000059604645 ] + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.4000000059604645, 0.0, -0.4000000059604645] ], "shape": "bunny", "material": "bunny-metal-rough" @@ -285,8 +285,8 @@ }, "environments": { "sky": { - "emission": [ 0.5, 0.5, 0.5 ], + "emission": [0.5, 0.5, 0.5], "emission_tex": "sky" } } -} \ No newline at end of file +}