From 08b0e0458440b4fa3e7fbfdbc5991b41e8b4a7da Mon Sep 17 00:00:00 2001 From: Peter Siegmund Date: Mon, 29 Sep 2025 23:15:06 +0200 Subject: [PATCH] implement new light mode (off/day/night/simulation) missing: - fully connect it to the ui - setup duration in light settings Signed-off-by: Peter Siegmund --- .../components/analytics/include/analytics.h | 13 +- .../include/wifi_manager.h | 13 +- .../connectivity-manager/src/wifi_manager.c | 20 +- firmware/components/imgui/imgui_demo.cpp | 5304 +++++++----- firmware/components/imgui/imgui_draw.cpp | 4010 +++++---- firmware/components/imgui/imgui_widgets.cpp | 5326 +++++++----- firmware/components/imgui/include/imgui.h | 7535 +++++++++++------ firmware/components/insa/CMakeLists.txt | 5 +- .../insa/include/common/ColorSettingsMenu.h | 29 - .../components/insa/include/common/Menu.h | 4 +- .../insa/include/common/ScrollBar.h | 44 +- .../components/insa/include/common/Widget.h | 6 +- .../insa/include/ui/ClockScreenSaver.h | 6 +- .../insa/include/ui/DayColorSettingsMenu.h | 14 - .../insa/include/ui/LightSettingsMenu.h | 35 - .../insa/include/ui/NightColorSettingsMenu.h | 15 - .../components/insa/include/ui/ScreenSaver.h | 6 +- .../components/insa/include/ui/SplashScreen.h | 62 +- .../insa/src/common/ColorSettingsMenu.cpp | 101 - firmware/components/insa/src/common/Menu.cpp | 8 +- .../components/insa/src/common/ScrollBar.cpp | 2 +- .../components/insa/src/common/Widget.cpp | 6 +- .../insa/src/ui/ClockScreenSaver.cpp | 27 +- .../insa/src/ui/DayColorSettingsMenu.cpp | 5 - firmware/components/insa/src/ui/LightMenu.cpp | 41 +- .../insa/src/ui/LightSettingsMenu.cpp | 102 - .../insa/src/ui/NightColorSettingsMenu.cpp | 5 - .../components/insa/src/ui/ScreenSaver.cpp | 6 +- .../components/insa/src/ui/SplashScreen.cpp | 4 +- .../components/led-manager/CMakeLists.txt | 3 +- firmware/components/led-manager/Kconfig | 6 + .../components/led-manager/include/color.h | 12 + .../led-manager/include/led_manager.h | 23 - .../led-manager/include/led_status.h | 52 +- .../led-manager/include/led_strip_ws2812.h | 18 + firmware/components/led-manager/src/color.c | 8 + .../led-manager/src/led_manager.cpp | 112 - .../components/led-manager/src/led_status.c | 10 +- .../led-manager/src/led_strip_ws2812.c | 111 + firmware/components/simulator/CMakeLists.txt | 4 +- .../components/simulator/include/simulator.h | 25 +- firmware/components/simulator/simulator.c | 120 - firmware/components/simulator/src/simulator.c | 245 + .../components/simulator/{ => src}/storage.c | 0 firmware/main/app_task.cpp | 24 +- firmware/main/button_handling.h | 15 +- firmware/main/hal/u8g2_esp32_hal.h | 31 +- firmware/main/i2c_checker.h | 11 +- firmware/main/main.cpp | 77 +- firmware/src/ui/Device.cpp | 6 +- 50 files changed, 14880 insertions(+), 8787 deletions(-) delete mode 100644 firmware/components/insa/include/common/ColorSettingsMenu.h delete mode 100644 firmware/components/insa/include/ui/DayColorSettingsMenu.h delete mode 100644 firmware/components/insa/include/ui/LightSettingsMenu.h delete mode 100644 firmware/components/insa/include/ui/NightColorSettingsMenu.h delete mode 100644 firmware/components/insa/src/common/ColorSettingsMenu.cpp delete mode 100644 firmware/components/insa/src/ui/DayColorSettingsMenu.cpp delete mode 100644 firmware/components/insa/src/ui/LightSettingsMenu.cpp delete mode 100644 firmware/components/insa/src/ui/NightColorSettingsMenu.cpp create mode 100644 firmware/components/led-manager/include/color.h delete mode 100644 firmware/components/led-manager/include/led_manager.h create mode 100644 firmware/components/led-manager/include/led_strip_ws2812.h create mode 100644 firmware/components/led-manager/src/color.c delete mode 100644 firmware/components/led-manager/src/led_manager.cpp create mode 100644 firmware/components/led-manager/src/led_strip_ws2812.c delete mode 100644 firmware/components/simulator/simulator.c create mode 100644 firmware/components/simulator/src/simulator.c rename firmware/components/simulator/{ => src}/storage.c (100%) diff --git a/firmware/components/analytics/include/analytics.h b/firmware/components/analytics/include/analytics.h index 4230b81..32cf960 100644 --- a/firmware/components/analytics/include/analytics.h +++ b/firmware/components/analytics/include/analytics.h @@ -1,10 +1,7 @@ #pragma once -#ifdef __cplusplus -extern "C" -{ -#endif - void analytics_init(void); -#ifdef __cplusplus -} -#endif +#include + +__BEGIN_DECLS +void analytics_init(void); +__END_DECLS diff --git a/firmware/components/connectivity-manager/include/wifi_manager.h b/firmware/components/connectivity-manager/include/wifi_manager.h index 2fe4061..359b434 100644 --- a/firmware/components/connectivity-manager/include/wifi_manager.h +++ b/firmware/components/connectivity-manager/include/wifi_manager.h @@ -1,10 +1,7 @@ #pragma once -#ifdef __cplusplus -extern "C" -{ -#endif - void wifi_manager_init(void); -#ifdef __cplusplus -} -#endif +#include + +__BEGIN_DECLS +void wifi_manager_init(void); +__END_DECLS diff --git a/firmware/components/connectivity-manager/src/wifi_manager.c b/firmware/components/connectivity-manager/src/wifi_manager.c index 7295df8..fb1ccd8 100644 --- a/firmware/components/connectivity-manager/src/wifi_manager.c +++ b/firmware/components/connectivity-manager/src/wifi_manager.c @@ -30,8 +30,10 @@ static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_ #if CONFIG_WIFI_ENABLED if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { - led_behavior_t led0_behavior = { - .mode = LED_MODE_BLINK, .color = {.r = 50, .g = 50, .b = 0}, .on_time_ms = 200, .off_time_ms = 200}; + led_behavior_t led0_behavior = {.mode = LED_MODE_BLINK, + .color = {.red = 50, .green = 50, .blue = 0}, + .on_time_ms = 200, + .off_time_ms = 200}; led_status_set_behavior(0, led0_behavior); esp_wifi_connect(); @@ -40,8 +42,10 @@ static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_ { if (s_retry_num < CONFIG_WIFI_CONNECT_RETRIES) { - led_behavior_t led0_behavior = { - .mode = LED_MODE_BLINK, .color = {.r = 50, .g = 50, .b = 0}, .on_time_ms = 200, .off_time_ms = 200}; + led_behavior_t led0_behavior = {.mode = LED_MODE_BLINK, + .color = {.red = 50, .green = 50, .blue = 0}, + .on_time_ms = 200, + .off_time_ms = 200}; led_status_set_behavior(0, led0_behavior); esp_wifi_connect(); @@ -49,8 +53,10 @@ static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_ ESP_DIAG_EVENT(TAG, "Retrying to connect to the AP"); return; } - led_behavior_t led0_behavior = { - .mode = LED_MODE_BLINK, .color = {.r = 50, .g = 0, .b = 0}, .on_time_ms = 1000, .off_time_ms = 500}; + led_behavior_t led0_behavior = {.mode = LED_MODE_BLINK, + .color = {.red = 50, .green = 0, .blue = 0}, + .on_time_ms = 1000, + .off_time_ms = 500}; led_status_set_behavior(0, led0_behavior); xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); @@ -59,7 +65,7 @@ static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_ { led_behavior_t led0_behavior = { .mode = LED_MODE_SOLID, - .color = {.r = 0, .g = 50, .b = 0}, + .color = {.red = 0, .green = 50, .blue = 0}, }; led_status_set_behavior(0, led0_behavior); diff --git a/firmware/components/imgui/imgui_demo.cpp b/firmware/components/imgui/imgui_demo.cpp index 8999320..885c753 100644 --- a/firmware/components/imgui/imgui_demo.cpp +++ b/firmware/components/imgui/imgui_demo.cpp @@ -11,8 +11,10 @@ // Get the latest version at https://github.com/ocornut/imgui // How to easily locate code? -// - Use Tools->Item Picker to debug break in code by clicking any widgets: https://github.com/ocornut/imgui/wiki/Debug-Tools -// - Browse an online version the demo with code linked to hovered widgets: https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html +// - Use Tools->Item Picker to debug break in code by clicking any widgets: +// https://github.com/ocornut/imgui/wiki/Debug-Tools +// - Browse an online version the demo with code linked to hovered widgets: +// https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html // - Find a visible string and search for it in the code! //--------------------------------------------------- @@ -35,9 +37,8 @@ // ABOUT THE MEANING OF THE 'static' KEYWORD: //-------------------------------------------- // In this demo code, we frequently use 'static' variables inside functions. -// A static variable persists across calls. It is essentially a global variable but declared inside the scope of the function. -// Think of "static int n = 0;" as "global int n = 0;" ! -// We do this IN THE DEMO because we want: +// A static variable persists across calls. It is essentially a global variable but declared inside the scope of the +// function. Think of "static int n = 0;" as "global int n = 0;" ! We do this IN THE DEMO because we want: // - to gather code and data in the same place. // - to make the demo source code faster to read, faster to change, smaller in size. // - it is also a convenient way of storing simple UI related information as long as your function @@ -59,8 +60,10 @@ // Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp. // Navigating this file: -// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. -// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments. +// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 +// ("Edit.GoToImplementation") cannot. +// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside +// comments. // - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments. // - You can search/grep for all sections listed in the index to find the section. @@ -131,71 +134,96 @@ Index of this file: #ifndef IMGUI_DISABLE // System includes -#include // toupper -#include // INT_MIN, INT_MAX -#include // sqrtf, powf, cosf, sinf, floorf, ceilf -#include // vsnprintf, sscanf, printf -#include // NULL, malloc, free, atoi -#include // intptr_t +#include // toupper +#include // INT_MIN, INT_MAX +#include // sqrtf, powf, cosf, sinf, floorf, ceilf +#include // intptr_t +#include // vsnprintf, sscanf, printf +#include // NULL, malloc, free, atoi #if !defined(_MSC_VER) || _MSC_VER >= 1800 -#include // PRId64/PRIu64, not avail in some MinGW headers. +#include // PRId64/PRIu64, not avail in some MinGW headers. #endif #ifdef __EMSCRIPTEN__ -#include // __EMSCRIPTEN_major__ etc. +#include // __EMSCRIPTEN_major__ etc. #endif // Visual Studio warnings #ifdef _MSC_VER -#pragma warning (disable: 4127) // condition expression is constant -#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 an 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#pragma warning(disable : 4127) // condition expression is constant +#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 an 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 #if defined(__clang__) #if __has_warning("-Wunknown-warning-option") -#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! +#pragma clang diagnostic ignored \ + "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known + // by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers + // new warnings on some configuration. Great! #endif -#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' -#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. -#pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning: 'xx' is deprecated: The POSIX name for this.. // for strdup used in demo code (so user can copy & paste the code) -#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type -#pragma clang diagnostic ignored "-Wformat" // warning: format specifies type 'int' but the argument has type 'unsigned int' -#pragma clang diagnostic ignored "-Wformat-security" // warning: format string is not a string literal -#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. -#pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used. -#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 -#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. -#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier -#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision -#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access -#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored \ + "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored \ + "-Wdeprecated-declarations" // warning: 'xx' is deprecated: The POSIX name for this.. // for strdup used in demo + // code (so user can copy & paste the code) +#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type +#pragma clang diagnostic ignored \ + "-Wformat" // warning: format specifies type 'int' but the argument has type 'unsigned int' +#pragma clang diagnostic ignored "-Wformat-security" // warning: format string is not a string literal +#pragma clang diagnostic ignored \ + "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order + // is undefined. if MemFree() leads to users code that has been disabled before exit it + // might cause problems. ImGui coding style welcomes static/globals. +#pragma clang diagnostic ignored \ + "-Wunused-macros" // warning: macro is not used // we define snprintf/vsnprintf on + // Windows so they are available, but not always used. +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some + // standard header variations use #define NULL 0 +#pragma clang diagnostic ignored \ + "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // + // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier +#pragma clang diagnostic ignored \ + "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access +#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label #elif defined(__GNUC__) -#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe -#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size -#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*' -#pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure) -#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function -#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value -#pragma GCC diagnostic ignored "-Wmisleading-indentation" // [__GNUC__ >= 6] warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub. -#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1 -#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size +#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X + // has type 'unsigned int'/'ImGuiWindow*' +#pragma GCC diagnostic ignored \ + "-Wformat-security" // warning: format string is not a string literal (potentially insecure) +#pragma GCC diagnostic ignored \ + "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wmisleading-indentation" // [__GNUC__ >= 6] warning: this 'if' clause does not guard + // this statement // GCC 6.0+ only. See #883 on GitHub. +#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying + // division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1 +#pragma GCC diagnostic ignored \ + "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers #endif // Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!) #ifdef _WIN32 -#define IM_NEWLINE "\r\n" +#define IM_NEWLINE "\r\n" #else -#define IM_NEWLINE "\n" +#define IM_NEWLINE "\n" #endif // Helpers #if defined(_MSC_VER) && !defined(snprintf) -#define snprintf _snprintf +#define snprintf _snprintf #endif #if defined(_MSC_VER) && !defined(vsnprintf) -#define vsnprintf _vsnprintf +#define vsnprintf _vsnprintf #endif // Format specifiers for 64-bit values (hasn't been decently standardized before VS2013) @@ -211,9 +239,9 @@ Index of this file: // 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... // In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo. -#define IM_MIN(A, B) (((A) < (B)) ? (A) : (B)) -#define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B)) -#define IM_CLAMP(V, MN, MX) ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V)) +#define IM_MIN(A, B) (((A) < (B)) ? (A) : (B)) +#define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B)) +#define IM_CLAMP(V, MN, MX) ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V)) // Enforce cdecl calling convention for functions called by the standard library, // in case compilation settings changed the default to e.g. __vectorcall @@ -234,25 +262,25 @@ Index of this file: // Forward Declarations struct ImGuiDemoWindowData; static void ShowExampleAppMainMenuBar(); -static void ShowExampleAppAssetsBrowser(bool* p_open); -static void ShowExampleAppConsole(bool* p_open); -static void ShowExampleAppCustomRendering(bool* p_open); -static void ShowExampleAppDocuments(bool* p_open); -static void ShowExampleAppLog(bool* p_open); -static void ShowExampleAppLayout(bool* p_open); -static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data); -static void ShowExampleAppSimpleOverlay(bool* p_open); -static void ShowExampleAppAutoResize(bool* p_open); -static void ShowExampleAppConstrainedResize(bool* p_open); -static void ShowExampleAppFullscreen(bool* p_open); -static void ShowExampleAppLongText(bool* p_open); -static void ShowExampleAppWindowTitles(bool* p_open); +static void ShowExampleAppAssetsBrowser(bool *p_open); +static void ShowExampleAppConsole(bool *p_open); +static void ShowExampleAppCustomRendering(bool *p_open); +static void ShowExampleAppDocuments(bool *p_open); +static void ShowExampleAppLog(bool *p_open); +static void ShowExampleAppLayout(bool *p_open); +static void ShowExampleAppPropertyEditor(bool *p_open, ImGuiDemoWindowData *demo_data); +static void ShowExampleAppSimpleOverlay(bool *p_open); +static void ShowExampleAppAutoResize(bool *p_open); +static void ShowExampleAppConstrainedResize(bool *p_open); +static void ShowExampleAppFullscreen(bool *p_open); +static void ShowExampleAppLongText(bool *p_open); +static void ShowExampleAppWindowTitles(bool *p_open); static void ShowExampleMenuFile(); // We split the contents of the big ShowDemoWindow() function into smaller functions // (because the link time of very large functions tends to grow non-linearly) -static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data); -static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data); +static void DemoWindowMenuBar(ImGuiDemoWindowData *demo_data); +static void DemoWindowWidgets(ImGuiDemoWindowData *demo_data); static void DemoWindowLayout(); static void DemoWindowPopups(); static void DemoWindowTables(); @@ -261,8 +289,8 @@ static void DemoWindowInputs(); // Helper tree functions used by Property Editor & Multi-Select demos struct ExampleTreeNode; -static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, ExampleTreeNode* parent); -static void ExampleTree_DestroyNode(ExampleTreeNode* node); +static ExampleTreeNode *ExampleTree_CreateNode(const char *name, int uid, ExampleTreeNode *parent); +static void ExampleTree_DestroyNode(ExampleTreeNode *node); //----------------------------------------------------------------------------- // [SECTION] Helpers @@ -270,7 +298,7 @@ static void ExampleTree_DestroyNode(ExampleTreeNode* node); // Helper to display a little (?) mark which shows a tooltip when hovered. // In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md) -static void HelpMarker(const char* desc) +static void HelpMarker(const char *desc) { ImGui::TextDisabled("(?)"); if (ImGui::BeginItemTooltip()) @@ -283,12 +311,17 @@ static void HelpMarker(const char* desc) } // Helper to wire demo markers located in code to an interactive browser -typedef void (*ImGuiDemoMarkerCallback)(const char* file, int line, const char* section, void* user_data); -extern ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback; -extern void* GImGuiDemoMarkerCallbackUserData; -ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback = NULL; -void* GImGuiDemoMarkerCallbackUserData = NULL; -#define IMGUI_DEMO_MARKER(section) do { if (GImGuiDemoMarkerCallback != NULL) GImGuiDemoMarkerCallback(__FILE__, __LINE__, section, GImGuiDemoMarkerCallbackUserData); } while (0) +typedef void (*ImGuiDemoMarkerCallback)(const char *file, int line, const char *section, void *user_data); +extern ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback; +extern void *GImGuiDemoMarkerCallbackUserData; +ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback = NULL; +void *GImGuiDemoMarkerCallbackUserData = NULL; +#define IMGUI_DEMO_MARKER(section) \ + do \ + { \ + if (GImGuiDemoMarkerCallback != NULL) \ + GImGuiDemoMarkerCallback(__FILE__, __LINE__, section, GImGuiDemoMarkerCallbackUserData); \ + } while (0) //----------------------------------------------------------------------------- // [SECTION] Demo Window / ShowDemoWindow() @@ -322,47 +355,106 @@ struct ImGuiDemoWindowData // Other data bool DisableSections = false; - ExampleTreeNode* DemoTree = NULL; + ExampleTreeNode *DemoTree = NULL; - ~ImGuiDemoWindowData() { if (DemoTree) ExampleTree_DestroyNode(DemoTree); } + ~ImGuiDemoWindowData() + { + if (DemoTree) + ExampleTree_DestroyNode(DemoTree); + } }; // Demonstrate most Dear ImGui features (this is big function!) // You may execute this function to experiment with the UI and understand what it does. // You may then search for keywords in the code when you are interested by a specific feature. -void ImGui::ShowDemoWindow(bool* p_open) +void ImGui::ShowDemoWindow(bool *p_open) { // Exceptionally add an extra assert here for people confused about initial Dear ImGui setup // Most functions would normally just assert/crash if the context is missing. IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing Dear ImGui context. Refer to examples app!"); - // Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues. + // Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build + // issues. IMGUI_CHECKVERSION(); // Stored data static ImGuiDemoWindowData demo_data; // Examples Apps (accessible from the "Examples" menu) - if (demo_data.ShowMainMenuBar) { ShowExampleAppMainMenuBar(); } - if (demo_data.ShowAppDocuments) { ShowExampleAppDocuments(&demo_data.ShowAppDocuments); } - if (demo_data.ShowAppAssetsBrowser) { ShowExampleAppAssetsBrowser(&demo_data.ShowAppAssetsBrowser); } - if (demo_data.ShowAppConsole) { ShowExampleAppConsole(&demo_data.ShowAppConsole); } - if (demo_data.ShowAppCustomRendering) { ShowExampleAppCustomRendering(&demo_data.ShowAppCustomRendering); } - if (demo_data.ShowAppLog) { ShowExampleAppLog(&demo_data.ShowAppLog); } - if (demo_data.ShowAppLayout) { ShowExampleAppLayout(&demo_data.ShowAppLayout); } - if (demo_data.ShowAppPropertyEditor) { ShowExampleAppPropertyEditor(&demo_data.ShowAppPropertyEditor, &demo_data); } - if (demo_data.ShowAppSimpleOverlay) { ShowExampleAppSimpleOverlay(&demo_data.ShowAppSimpleOverlay); } - if (demo_data.ShowAppAutoResize) { ShowExampleAppAutoResize(&demo_data.ShowAppAutoResize); } - if (demo_data.ShowAppConstrainedResize) { ShowExampleAppConstrainedResize(&demo_data.ShowAppConstrainedResize); } - if (demo_data.ShowAppFullscreen) { ShowExampleAppFullscreen(&demo_data.ShowAppFullscreen); } - if (demo_data.ShowAppLongText) { ShowExampleAppLongText(&demo_data.ShowAppLongText); } - if (demo_data.ShowAppWindowTitles) { ShowExampleAppWindowTitles(&demo_data.ShowAppWindowTitles); } + if (demo_data.ShowMainMenuBar) + { + ShowExampleAppMainMenuBar(); + } + if (demo_data.ShowAppDocuments) + { + ShowExampleAppDocuments(&demo_data.ShowAppDocuments); + } + if (demo_data.ShowAppAssetsBrowser) + { + ShowExampleAppAssetsBrowser(&demo_data.ShowAppAssetsBrowser); + } + if (demo_data.ShowAppConsole) + { + ShowExampleAppConsole(&demo_data.ShowAppConsole); + } + if (demo_data.ShowAppCustomRendering) + { + ShowExampleAppCustomRendering(&demo_data.ShowAppCustomRendering); + } + if (demo_data.ShowAppLog) + { + ShowExampleAppLog(&demo_data.ShowAppLog); + } + if (demo_data.ShowAppLayout) + { + ShowExampleAppLayout(&demo_data.ShowAppLayout); + } + if (demo_data.ShowAppPropertyEditor) + { + ShowExampleAppPropertyEditor(&demo_data.ShowAppPropertyEditor, &demo_data); + } + if (demo_data.ShowAppSimpleOverlay) + { + ShowExampleAppSimpleOverlay(&demo_data.ShowAppSimpleOverlay); + } + if (demo_data.ShowAppAutoResize) + { + ShowExampleAppAutoResize(&demo_data.ShowAppAutoResize); + } + if (demo_data.ShowAppConstrainedResize) + { + ShowExampleAppConstrainedResize(&demo_data.ShowAppConstrainedResize); + } + if (demo_data.ShowAppFullscreen) + { + ShowExampleAppFullscreen(&demo_data.ShowAppFullscreen); + } + if (demo_data.ShowAppLongText) + { + ShowExampleAppLongText(&demo_data.ShowAppLongText); + } + if (demo_data.ShowAppWindowTitles) + { + ShowExampleAppWindowTitles(&demo_data.ShowAppWindowTitles); + } // Dear ImGui Tools (accessible from the "Tools" menu) - if (demo_data.ShowMetrics) { ImGui::ShowMetricsWindow(&demo_data.ShowMetrics); } - if (demo_data.ShowDebugLog) { ImGui::ShowDebugLogWindow(&demo_data.ShowDebugLog); } - if (demo_data.ShowIDStackTool) { ImGui::ShowIDStackToolWindow(&demo_data.ShowIDStackTool); } - if (demo_data.ShowAbout) { ImGui::ShowAboutWindow(&demo_data.ShowAbout); } + if (demo_data.ShowMetrics) + { + ImGui::ShowMetricsWindow(&demo_data.ShowMetrics); + } + if (demo_data.ShowDebugLog) + { + ImGui::ShowDebugLogWindow(&demo_data.ShowDebugLog); + } + if (demo_data.ShowIDStackTool) + { + ImGui::ShowIDStackToolWindow(&demo_data.ShowIDStackTool); + } + if (demo_data.ShowAbout) + { + ImGui::ShowAboutWindow(&demo_data.ShowAbout); + } if (demo_data.ShowStyleEditor) { ImGui::Begin("Dear ImGui Style Editor", &demo_data.ShowStyleEditor); @@ -384,22 +476,34 @@ void ImGui::ShowDemoWindow(bool* p_open) static bool unsaved_document = false; ImGuiWindowFlags window_flags = 0; - if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar; - if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar; - if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar; - if (no_move) window_flags |= ImGuiWindowFlags_NoMove; - if (no_resize) window_flags |= ImGuiWindowFlags_NoResize; - if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse; - if (no_nav) window_flags |= ImGuiWindowFlags_NoNav; - if (no_background) window_flags |= ImGuiWindowFlags_NoBackground; - if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; - if (unsaved_document) window_flags |= ImGuiWindowFlags_UnsavedDocument; - if (no_close) p_open = NULL; // Don't pass our bool* to Begin + if (no_titlebar) + window_flags |= ImGuiWindowFlags_NoTitleBar; + if (no_scrollbar) + window_flags |= ImGuiWindowFlags_NoScrollbar; + if (!no_menu) + window_flags |= ImGuiWindowFlags_MenuBar; + if (no_move) + window_flags |= ImGuiWindowFlags_NoMove; + if (no_resize) + window_flags |= ImGuiWindowFlags_NoResize; + if (no_collapse) + window_flags |= ImGuiWindowFlags_NoCollapse; + if (no_nav) + window_flags |= ImGuiWindowFlags_NoNav; + if (no_background) + window_flags |= ImGuiWindowFlags_NoBackground; + if (no_bring_to_front) + window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; + if (unsaved_document) + window_flags |= ImGuiWindowFlags_UnsavedDocument; + if (no_close) + p_open = NULL; // Don't pass our bool* to Begin // We specify a default position/size in case there's no data in the .ini file. // We only do it to make the demo applications a little more welcoming, but typically this isn't required. - const ImGuiViewport* main_viewport = ImGui::GetMainViewport(); - ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkPos.x + 650, main_viewport->WorkPos.y + 20), ImGuiCond_FirstUseEver); + const ImGuiViewport *main_viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkPos.x + 650, main_viewport->WorkPos.y + 20), + ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver); // Main body of the Demo window starts here. @@ -416,13 +520,15 @@ void ImGui::ShowDemoWindow(bool* p_open) // - The default value is about GetWindowWidth() * 0.65f. // - See 'Demo->Layout->Widgets Width' for details. // Here we change the frame width based on how much width we want to give to the label. - const float label_width_base = ImGui::GetFontSize() * 12; // Some amount of width for label, based on font size. - const float label_width_max = ImGui::GetContentRegionAvail().x * 0.40f; // ...but always leave some room for framed widgets. + const float label_width_base = ImGui::GetFontSize() * 12; // Some amount of width for label, based on font size. + const float label_width_max = + ImGui::GetContentRegionAvail().x * 0.40f; // ...but always leave some room for framed widgets. const float label_width = IM_MIN(label_width_base, label_width_max); - ImGui::PushItemWidth(-label_width); // Right-align: framed items will leave 'label_width' available for the label. - //ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.40f); // e.g. Use 40% width for framed widgets, leaving 60% width for labels. - //ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.40f); // e.g. Use 40% width for labels, leaving 60% width for framed widgets. - //ImGui::PushItemWidth(ImGui::GetFontSize() * -12); // e.g. Use XXX width for labels, leaving the rest for framed widgets. + ImGui::PushItemWidth(-label_width); // Right-align: framed items will leave 'label_width' available for the label. + // ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.40f); // e.g. Use 40% width for framed widgets, + // leaving 60% width for labels. ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.40f); // e.g. Use + // 40% width for labels, leaving 60% width for framed widgets. ImGui::PushItemWidth(ImGui::GetFontSize() * -12); // + // e.g. Use XXX width for labels, leaving the rest for framed widgets. // Menu Bar DemoWindowMenuBar(&demo_data); @@ -456,17 +562,23 @@ void ImGui::ShowDemoWindow(bool* p_open) IMGUI_DEMO_MARKER("Configuration"); if (ImGui::CollapsingHeader("Configuration")) { - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO &io = ImGui::GetIO(); if (ImGui::TreeNode("Configuration##2")) { ImGui::SeparatorText("General"); - ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); - ImGui::SameLine(); HelpMarker("Enable keyboard controls."); - ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); - ImGui::SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details."); - ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse); - ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable mouse inputs and interactions."); + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, + ImGuiConfigFlags_NavEnableKeyboard); + ImGui::SameLine(); + HelpMarker("Enable keyboard controls."); + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, + ImGuiConfigFlags_NavEnableGamepad); + ImGui::SameLine(); + HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= " + "ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details."); + ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse); + ImGui::SameLine(); + HelpMarker("Instruct dear imgui to disable mouse inputs and interactions."); // The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it: if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) @@ -481,83 +593,128 @@ void ImGui::ShowDemoWindow(bool* p_open) io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse; } - ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); - ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility."); + ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, + ImGuiConfigFlags_NoMouseCursorChange); + ImGui::SameLine(); + HelpMarker("Instruct backend to not alter mouse cursor shape and visibility."); ImGui::CheckboxFlags("io.ConfigFlags: NoKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NoKeyboard); - ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable keyboard inputs and interactions."); + ImGui::SameLine(); + HelpMarker("Instruct dear imgui to disable keyboard inputs and interactions."); ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue); - ImGui::SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates."); + ImGui::SameLine(); + HelpMarker( + "Enable input queue trickling: some types of events submitted during the same frame (e.g. button down " + "+ up) will be spread over multiple frames, improving interactions with low framerates."); ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); - ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); + ImGui::SameLine(); + HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via " + "your application GPU rendering path will feel more laggy than hardware cursor, but will be " + "more in sync with your other visuals.\n\nSome desktop applications may use both kinds of " + "cursors (e.g. enable software cursor only when resizing/dragging something)."); ImGui::SeparatorText("Keyboard/Gamepad Navigation"); ImGui::Checkbox("io.ConfigNavSwapGamepadButtons", &io.ConfigNavSwapGamepadButtons); ImGui::Checkbox("io.ConfigNavMoveSetMousePos", &io.ConfigNavMoveSetMousePos); - ImGui::SameLine(); HelpMarker("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult"); + ImGui::SameLine(); + HelpMarker("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems " + "where moving a virtual mouse is difficult"); ImGui::Checkbox("io.ConfigNavCaptureKeyboard", &io.ConfigNavCaptureKeyboard); ImGui::Checkbox("io.ConfigNavEscapeClearFocusItem", &io.ConfigNavEscapeClearFocusItem); - ImGui::SameLine(); HelpMarker("Pressing Escape clears focused item."); + ImGui::SameLine(); + HelpMarker("Pressing Escape clears focused item."); ImGui::Checkbox("io.ConfigNavEscapeClearFocusWindow", &io.ConfigNavEscapeClearFocusWindow); - ImGui::SameLine(); HelpMarker("Pressing Escape clears focused window."); + ImGui::SameLine(); + HelpMarker("Pressing Escape clears focused window."); ImGui::Checkbox("io.ConfigNavCursorVisibleAuto", &io.ConfigNavCursorVisibleAuto); - ImGui::SameLine(); HelpMarker("Using directional navigation key makes the cursor visible. Mouse click hides the cursor."); + ImGui::SameLine(); + HelpMarker("Using directional navigation key makes the cursor visible. Mouse click hides the cursor."); ImGui::Checkbox("io.ConfigNavCursorVisibleAlways", &io.ConfigNavCursorVisibleAlways); - ImGui::SameLine(); HelpMarker("Navigation cursor is always visible."); + ImGui::SameLine(); + HelpMarker("Navigation cursor is always visible."); ImGui::SeparatorText("Windows"); ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); - ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback."); + ImGui::SameLine(); + HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires " + "ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback."); ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); - ImGui::Checkbox("io.ConfigWindowsCopyContentsWithCtrlC", &io.ConfigWindowsCopyContentsWithCtrlC); // [EXPERIMENTAL] - ImGui::SameLine(); HelpMarker("*EXPERIMENTAL* CTRL+C copy the contents of focused window into the clipboard.\n\nExperimental because:\n- (1) has known issues with nested Begin/End pairs.\n- (2) text output quality varies.\n- (3) text output is in submission order rather than spatial order."); + ImGui::Checkbox("io.ConfigWindowsCopyContentsWithCtrlC", + &io.ConfigWindowsCopyContentsWithCtrlC); // [EXPERIMENTAL] + ImGui::SameLine(); + HelpMarker("*EXPERIMENTAL* CTRL+C copy the contents of focused window into the clipboard.\n\nExperimental " + "because:\n- (1) has known issues with nested Begin/End pairs.\n- (2) text output quality " + "varies.\n- (3) text output is in submission order rather than spatial order."); ImGui::Checkbox("io.ConfigScrollbarScrollByPage", &io.ConfigScrollbarScrollByPage); - ImGui::SameLine(); HelpMarker("Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location."); + ImGui::SameLine(); + HelpMarker("Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always " + "scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location."); ImGui::SeparatorText("Widgets"); ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); - ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)."); + ImGui::SameLine(); + HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)."); ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive); - ImGui::SameLine(); HelpMarker("Pressing Enter will keep item active and select contents (single-line only)."); + ImGui::SameLine(); + HelpMarker("Pressing Enter will keep item active and select contents (single-line only)."); ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText); - ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving)."); + ImGui::SameLine(); + HelpMarker( + "Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving)."); ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors); - ImGui::SameLine(); HelpMarker("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors."); + ImGui::SameLine(); + HelpMarker("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors."); ImGui::Text("Also see Style->Rendering for rendering options."); // Also read: https://github.com/ocornut/imgui/wiki/Error-Handling ImGui::SeparatorText("Error Handling"); ImGui::Checkbox("io.ConfigErrorRecovery", &io.ConfigErrorRecovery); - ImGui::SameLine(); HelpMarker( - "Options to configure how we handle recoverable errors.\n" - "- Error recovery is not perfect nor guaranteed! It is a feature to ease development.\n" - "- You not are not supposed to rely on it in the course of a normal application run.\n" - "- Possible usage: facilitate recovery from errors triggered from a scripting language or after specific exceptions handlers.\n" - "- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when making direct imgui API call! " - "Otherwise it would severely hinder your ability to catch and correct mistakes!"); + ImGui::SameLine(); + HelpMarker("Options to configure how we handle recoverable errors.\n" + "- Error recovery is not perfect nor guaranteed! It is a feature to ease development.\n" + "- You not are not supposed to rely on it in the course of a normal application run.\n" + "- Possible usage: facilitate recovery from errors triggered from a scripting language or after " + "specific exceptions handlers.\n" + "- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when " + "making direct imgui API call! " + "Otherwise it would severely hinder your ability to catch and correct mistakes!"); ImGui::Checkbox("io.ConfigErrorRecoveryEnableAssert", &io.ConfigErrorRecoveryEnableAssert); ImGui::Checkbox("io.ConfigErrorRecoveryEnableDebugLog", &io.ConfigErrorRecoveryEnableDebugLog); ImGui::Checkbox("io.ConfigErrorRecoveryEnableTooltip", &io.ConfigErrorRecoveryEnableTooltip); - if (!io.ConfigErrorRecoveryEnableAssert && !io.ConfigErrorRecoveryEnableDebugLog && !io.ConfigErrorRecoveryEnableTooltip) - io.ConfigErrorRecoveryEnableAssert = io.ConfigErrorRecoveryEnableDebugLog = io.ConfigErrorRecoveryEnableTooltip = true; + if (!io.ConfigErrorRecoveryEnableAssert && !io.ConfigErrorRecoveryEnableDebugLog && + !io.ConfigErrorRecoveryEnableTooltip) + io.ConfigErrorRecoveryEnableAssert = io.ConfigErrorRecoveryEnableDebugLog = + io.ConfigErrorRecoveryEnableTooltip = true; // Also read: https://github.com/ocornut/imgui/wiki/Debug-Tools ImGui::SeparatorText("Debug"); ImGui::Checkbox("io.ConfigDebugIsDebuggerPresent", &io.ConfigDebugIsDebuggerPresent); - ImGui::SameLine(); HelpMarker("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application."); + ImGui::SameLine(); + HelpMarker("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, " + "otherwise IM_DEBUG_BREAK() options will appear to crash your application."); ImGui::Checkbox("io.ConfigDebugHighlightIdConflicts", &io.ConfigDebugHighlightIdConflicts); - ImGui::SameLine(); HelpMarker("Highlight and show an error message when multiple items have conflicting identifiers."); + ImGui::SameLine(); + HelpMarker("Highlight and show an error message when multiple items have conflicting identifiers."); ImGui::BeginDisabled(); ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce); ImGui::EndDisabled(); - ImGui::SameLine(); HelpMarker("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover."); + ImGui::SameLine(); + HelpMarker("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it " + "needs to be set at application boot-time to make sense. Showing the disabled option is a way " + "to make this feature easier to discover."); ImGui::Checkbox("io.ConfigDebugBeginReturnValueLoop", &io.ConfigDebugBeginReturnValueLoop); - ImGui::SameLine(); HelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running."); + ImGui::SameLine(); + HelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then " + "repeat. Windows should be flickering while running."); ImGui::Checkbox("io.ConfigDebugIgnoreFocusLoss", &io.ConfigDebugIgnoreFocusLoss); - ImGui::SameLine(); HelpMarker("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data."); + ImGui::SameLine(); + HelpMarker("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a " + "debugger when focus loss leads to clearing inputs data."); ImGui::Checkbox("io.ConfigDebugIniSettings", &io.ConfigDebugIniSettings); - ImGui::SameLine(); HelpMarker("Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower)."); + ImGui::SameLine(); + HelpMarker("Option to save .ini data with extra comments (particularly helpful for Docking, but makes " + "saving slower)."); ImGui::TreePop(); ImGui::Spacing(); @@ -566,17 +723,19 @@ void ImGui::ShowDemoWindow(bool* p_open) IMGUI_DEMO_MARKER("Configuration/Backend Flags"); if (ImGui::TreeNode("Backend Flags")) { - HelpMarker( - "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n" - "Here we expose them as read-only fields to avoid breaking interactions with your backend."); + HelpMarker("Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n" + "Here we expose them as read-only fields to avoid breaking interactions with your backend."); // FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright? ImGui::BeginDisabled(); - ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &io.BackendFlags, ImGuiBackendFlags_HasGamepad); - ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors); - ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &io.BackendFlags, ImGuiBackendFlags_HasSetMousePos); - ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset); - ImGui::CheckboxFlags("io.BackendFlags: RendererHasTextures", &io.BackendFlags, ImGuiBackendFlags_RendererHasTextures); + ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &io.BackendFlags, ImGuiBackendFlags_HasGamepad); + ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, + ImGuiBackendFlags_HasMouseCursors); + ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &io.BackendFlags, ImGuiBackendFlags_HasSetMousePos); + ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &io.BackendFlags, + ImGuiBackendFlags_RendererHasVtxOffset); + ImGui::CheckboxFlags("io.BackendFlags: RendererHasTextures", &io.BackendFlags, + ImGuiBackendFlags_RendererHasTextures); ImGui::EndDisabled(); ImGui::TreePop(); @@ -588,7 +747,8 @@ void ImGui::ShowDemoWindow(bool* p_open) { ImGui::Checkbox("Style Editor", &demo_data.ShowStyleEditor); ImGui::SameLine(); - HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function."); + HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() " + "function."); ImGui::TreePop(); ImGui::Spacing(); } @@ -618,17 +778,28 @@ void ImGui::ShowDemoWindow(bool* p_open) { if (ImGui::BeginTable("split", 3)) { - ImGui::TableNextColumn(); ImGui::Checkbox("No titlebar", &no_titlebar); - ImGui::TableNextColumn(); ImGui::Checkbox("No scrollbar", &no_scrollbar); - ImGui::TableNextColumn(); ImGui::Checkbox("No menu", &no_menu); - ImGui::TableNextColumn(); ImGui::Checkbox("No move", &no_move); - ImGui::TableNextColumn(); ImGui::Checkbox("No resize", &no_resize); - ImGui::TableNextColumn(); ImGui::Checkbox("No collapse", &no_collapse); - ImGui::TableNextColumn(); ImGui::Checkbox("No close", &no_close); - ImGui::TableNextColumn(); ImGui::Checkbox("No nav", &no_nav); - ImGui::TableNextColumn(); ImGui::Checkbox("No background", &no_background); - ImGui::TableNextColumn(); ImGui::Checkbox("No bring to front", &no_bring_to_front); - ImGui::TableNextColumn(); ImGui::Checkbox("Unsaved document", &unsaved_document); + ImGui::TableNextColumn(); + ImGui::Checkbox("No titlebar", &no_titlebar); + ImGui::TableNextColumn(); + ImGui::Checkbox("No scrollbar", &no_scrollbar); + ImGui::TableNextColumn(); + ImGui::Checkbox("No menu", &no_menu); + ImGui::TableNextColumn(); + ImGui::Checkbox("No move", &no_move); + ImGui::TableNextColumn(); + ImGui::Checkbox("No resize", &no_resize); + ImGui::TableNextColumn(); + ImGui::Checkbox("No collapse", &no_collapse); + ImGui::TableNextColumn(); + ImGui::Checkbox("No close", &no_close); + ImGui::TableNextColumn(); + ImGui::Checkbox("No nav", &no_nav); + ImGui::TableNextColumn(); + ImGui::Checkbox("No background", &no_background); + ImGui::TableNextColumn(); + ImGui::Checkbox("No bring to front", &no_bring_to_front); + ImGui::TableNextColumn(); + ImGui::Checkbox("Unsaved document", &unsaved_document); ImGui::EndTable(); } } @@ -649,7 +820,7 @@ void ImGui::ShowDemoWindow(bool* p_open) // [SECTION] DemoWindowMenuBar() //----------------------------------------------------------------------------- -static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data) +static void DemoWindowMenuBar(ImGuiDemoWindowData *demo_data) { IMGUI_DEMO_MARKER("Menu"); if (ImGui::BeginMenuBar()) @@ -684,11 +855,11 @@ static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data) ImGui::EndMenu(); } - //if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar! + // if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar! if (ImGui::BeginMenu("Tools")) { IMGUI_DEMO_MARKER("Menu/Tools"); - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO &io = ImGui::GetIO(); #ifndef IMGUI_DISABLE_DEBUG_TOOLS const bool has_debug_tools = true; #else @@ -707,10 +878,11 @@ static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data) ImGui::MenuItem("Debug Log", NULL, &demo_data->ShowDebugLog, has_debug_tools); ImGui::MenuItem("ID Stack Tool", NULL, &demo_data->ShowIDStackTool, has_debug_tools); bool is_debugger_present = io.ConfigDebugIsDebuggerPresent; - if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools))// && is_debugger_present)) + if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools)) // && is_debugger_present)) ImGui::DebugStartItemPicker(); if (!is_debugger_present) - ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable some extra features to avoid casual users crashing the application."); + ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise " + "disable some extra features to avoid casual users crashing the application."); ImGui::MenuItem("Style Editor", NULL, &demo_data->ShowStyleEditor); ImGui::MenuItem("About Dear ImGui", NULL, &demo_data->ShowAbout); @@ -729,41 +901,40 @@ static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data) struct ExampleTreeNode { // Tree structure - char Name[28] = ""; - int UID = 0; - ExampleTreeNode* Parent = NULL; - ImVector Childs; - unsigned short IndexInParent = 0; // Maintaining this allows us to implement linear traversal more easily + char Name[28] = ""; + int UID = 0; + ExampleTreeNode *Parent = NULL; + ImVector Childs; + unsigned short IndexInParent = 0; // Maintaining this allows us to implement linear traversal more easily // Leaf Data - bool HasData = false; // All leaves have data - bool DataMyBool = true; - int DataMyInt = 128; - ImVec2 DataMyVec2 = ImVec2(0.0f, 3.141592f); + bool HasData = false; // All leaves have data + bool DataMyBool = true; + int DataMyInt = 128; + ImVec2 DataMyVec2 = ImVec2(0.0f, 3.141592f); }; // Simple representation of struct metadata/serialization data. // (this is a minimal version of what a typical advanced application may provide) struct ExampleMemberInfo { - const char* Name; // Member name - ImGuiDataType DataType; // Member type - int DataCount; // Member count (1 when scalar) - int Offset; // Offset inside parent structure + const char *Name; // Member name + ImGuiDataType DataType; // Member type + int DataCount; // Member count (1 when scalar) + int Offset; // Offset inside parent structure }; // Metadata description of ExampleTreeNode struct. -static const ExampleMemberInfo ExampleTreeNodeMemberInfos[] -{ - { "MyName", ImGuiDataType_String, 1, offsetof(ExampleTreeNode, Name) }, - { "MyBool", ImGuiDataType_Bool, 1, offsetof(ExampleTreeNode, DataMyBool) }, - { "MyInt", ImGuiDataType_S32, 1, offsetof(ExampleTreeNode, DataMyInt) }, - { "MyVec2", ImGuiDataType_Float, 2, offsetof(ExampleTreeNode, DataMyVec2) }, +static const ExampleMemberInfo ExampleTreeNodeMemberInfos[]{ + {"MyName", ImGuiDataType_String, 1, offsetof(ExampleTreeNode, Name)}, + {"MyBool", ImGuiDataType_Bool, 1, offsetof(ExampleTreeNode, DataMyBool)}, + {"MyInt", ImGuiDataType_S32, 1, offsetof(ExampleTreeNode, DataMyInt)}, + {"MyVec2", ImGuiDataType_Float, 2, offsetof(ExampleTreeNode, DataMyVec2)}, }; -static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, ExampleTreeNode* parent) +static ExampleTreeNode *ExampleTree_CreateNode(const char *name, int uid, ExampleTreeNode *parent) { - ExampleTreeNode* node = IM_NEW(ExampleTreeNode); + ExampleTreeNode *node = IM_NEW(ExampleTreeNode); snprintf(node->Name, IM_ARRAYSIZE(node->Name), "%s", name); node->UID = uid; node->Parent = parent; @@ -773,37 +944,39 @@ static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, Exampl return node; } -static void ExampleTree_DestroyNode(ExampleTreeNode* node) +static void ExampleTree_DestroyNode(ExampleTreeNode *node) { - for (ExampleTreeNode* child_node : node->Childs) + for (ExampleTreeNode *child_node : node->Childs) ExampleTree_DestroyNode(child_node); IM_DELETE(node); } // Create example tree data // (this allocates _many_ more times than most other code in either Dear ImGui or others demo) -static ExampleTreeNode* ExampleTree_CreateDemoTree() +static ExampleTreeNode *ExampleTree_CreateDemoTree() { - static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" }; + static const char *root_names[] = {"Apple", "Banana", "Cherry", "Kiwi", "Mango", + "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon"}; const size_t NAME_MAX_LEN = sizeof(ExampleTreeNode::Name); char name_buf[NAME_MAX_LEN]; int uid = 0; - ExampleTreeNode* node_L0 = ExampleTree_CreateNode("", ++uid, NULL); + ExampleTreeNode *node_L0 = ExampleTree_CreateNode("", ++uid, NULL); const int root_items_multiplier = 2; for (int idx_L0 = 0; idx_L0 < IM_ARRAYSIZE(root_names) * root_items_multiplier; idx_L0++) { - snprintf(name_buf, IM_ARRAYSIZE(name_buf), "%s %d", root_names[idx_L0 / root_items_multiplier], idx_L0 % root_items_multiplier); - ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0); + snprintf(name_buf, IM_ARRAYSIZE(name_buf), "%s %d", root_names[idx_L0 / root_items_multiplier], + idx_L0 % root_items_multiplier); + ExampleTreeNode *node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0); const int number_of_childs = (int)strlen(node_L1->Name); for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++) { snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Child %d", idx_L1); - ExampleTreeNode* node_L2 = ExampleTree_CreateNode(name_buf, ++uid, node_L1); + ExampleTreeNode *node_L2 = ExampleTree_CreateNode(name_buf, ++uid, node_L1); node_L2->HasData = true; if (idx_L1 == 0) { snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Sub-child %d", 0); - ExampleTreeNode* node_L3 = ExampleTree_CreateNode(name_buf, ++uid, node_L2); + ExampleTreeNode *node_L3 = ExampleTree_CreateNode(name_buf, ++uid, node_L2); node_L3->HasData = true; } } @@ -838,8 +1011,10 @@ static void DemoWindowWidgetsBasic() IMGUI_DEMO_MARKER("Widgets/Basic/RadioButton"); static int e = 0; - ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); - ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); + ImGui::RadioButton("radio a", &e, 0); + ImGui::SameLine(); + ImGui::RadioButton("radio b", &e, 1); + ImGui::SameLine(); ImGui::RadioButton("radio c", &e, 2); // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. @@ -869,9 +1044,15 @@ static void DemoWindowWidgetsBasic() static int counter = 0; float spacing = ImGui::GetStyle().ItemInnerSpacing.x; ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); - if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; } + if (ImGui::ArrowButton("##left", ImGuiDir_Left)) + { + counter--; + } ImGui::SameLine(0.0f, spacing); - if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; } + if (ImGui::ArrowButton("##right", ImGuiDir_Right)) + { + counter++; + } ImGui::PopItemFlag(); ImGui::SameLine(); ImGui::Text("%d", counter); @@ -889,18 +1070,18 @@ static void DemoWindowWidgetsBasic() IMGUI_DEMO_MARKER("Widgets/Basic/InputText"); static char str0[128] = "Hello, world!"; ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0)); - ImGui::SameLine(); HelpMarker( - "USER:\n" - "Hold SHIFT or use mouse to select text.\n" - "CTRL+Left/Right to word jump.\n" - "CTRL+A or Double-Click to select all.\n" - "CTRL+X,CTRL+C,CTRL+V for clipboard.\n" - "CTRL+Z to undo, CTRL+Y/CTRL+SHIFT+Z to redo.\n" - "ESCAPE to revert.\n\n" - "PROGRAMMER:\n" - "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() " - "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated " - "in imgui_demo.cpp)."); + ImGui::SameLine(); + HelpMarker("USER:\n" + "Hold SHIFT or use mouse to select text.\n" + "CTRL+Left/Right to word jump.\n" + "CTRL+A or Double-Click to select all.\n" + "CTRL+X,CTRL+C,CTRL+V for clipboard.\n" + "CTRL+Z to undo, CTRL+Y/CTRL+SHIFT+Z to redo.\n" + "ESCAPE to revert.\n\n" + "PROGRAMMER:\n" + "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() " + "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated " + "in imgui_demo.cpp)."); static char str1[128] = ""; ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1)); @@ -917,11 +1098,11 @@ static void DemoWindowWidgetsBasic() static float f1 = 1.e10f; ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e"); - ImGui::SameLine(); HelpMarker( - "You can input value using the scientific notation,\n" - " e.g. \"1e+8\" becomes \"100000000\"."); + ImGui::SameLine(); + HelpMarker("You can input value using the scientific notation,\n" + " e.g. \"1e+8\" becomes \"100000000\"."); - static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; + static float vec4a[4] = {0.10f, 0.20f, 0.30f, 0.44f}; ImGui::InputFloat3("input float3", vec4a); } @@ -931,17 +1112,17 @@ static void DemoWindowWidgetsBasic() IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat"); static int i1 = 50, i2 = 42, i3 = 128; ImGui::DragInt("drag int", &i1, 1); - ImGui::SameLine(); HelpMarker( - "Click and drag to edit value.\n" - "Hold SHIFT/ALT for faster/slower edit.\n" - "Double-click or CTRL+click to input value."); + ImGui::SameLine(); + HelpMarker("Click and drag to edit value.\n" + "Hold SHIFT/ALT for faster/slower edit.\n" + "Double-click or CTRL+click to input value."); ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); ImGui::DragInt("drag int wrap 100..200", &i3, 1, 100, 200, "%d", ImGuiSliderFlags_WrapAround); static float f1 = 1.00f, f2 = 0.0067f; ImGui::DragFloat("drag float", &f1, 0.005f); ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); - //ImGui::DragFloat("drag wrap -1..1", &f3, 0.005f, -1.0f, 1.0f, NULL, ImGuiSliderFlags_WrapAround); + // ImGui::DragFloat("drag wrap -1..1", &f3, 0.005f, -1.0f, 1.0f, NULL, ImGuiSliderFlags_WrapAround); } ImGui::SeparatorText("Sliders"); @@ -950,7 +1131,8 @@ static void DemoWindowWidgetsBasic() IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat"); static int i1 = 0; ImGui::SliderInt("slider int", &i1, -1, 3); - ImGui::SameLine(); HelpMarker("CTRL+click to input value."); + ImGui::SameLine(); + HelpMarker("CTRL+click to input value."); static float f1 = 0.123f, f2 = 0.0f; ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f"); @@ -964,26 +1146,35 @@ static void DemoWindowWidgetsBasic() // Here we completely omit '%d' from the format string, so it'll only display a name. // This technique can also be used with DragInt(). IMGUI_DEMO_MARKER("Widgets/Basic/Slider (enum)"); - enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT }; + enum Element + { + Element_Fire, + Element_Earth, + Element_Air, + Element_Water, + Element_COUNT + }; static int elem = Element_Fire; - const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" }; - const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown"; - ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); // Use ImGuiSliderFlags_NoInput flag to disable CTRL+Click here. - ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer."); + const char *elems_names[Element_COUNT] = {"Fire", "Earth", "Air", "Water"}; + const char *elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown"; + ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, + elem_name); // Use ImGuiSliderFlags_NoInput flag to disable CTRL+Click here. + ImGui::SameLine(); + HelpMarker("Using the format string parameter to display a name instead of the underlying integer."); } ImGui::SeparatorText("Selectors/Pickers"); { IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4"); - static float col1[3] = { 1.0f, 0.0f, 0.2f }; - static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; + static float col1[3] = {1.0f, 0.0f, 0.2f}; + static float col2[4] = {0.4f, 0.7f, 0.0f, 0.5f}; ImGui::ColorEdit3("color 1", col1); - ImGui::SameLine(); HelpMarker( - "Click on the color square to open a color picker.\n" - "Click and hold to use drag and drop.\n" - "Right-click on the color square to show options.\n" - "CTRL+click on individual component to input value.\n"); + ImGui::SameLine(); + HelpMarker("Click on the color square to open a color picker.\n" + "Click and hold to use drag and drop.\n" + "Right-click on the color square to show options.\n" + "CTRL+click on individual component to input value.\n"); ImGui::ColorEdit4("color 2", col2); } @@ -992,29 +1183,33 @@ static void DemoWindowWidgetsBasic() // Using the _simplified_ one-liner Combo() api here // See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api. IMGUI_DEMO_MARKER("Widgets/Basic/Combo"); - const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" }; + const char *items[] = {"AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", + "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK"}; static int item_current = 0; ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); - ImGui::SameLine(); HelpMarker( - "Using the simplified one-liner Combo API here.\n" - "Refer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API."); + ImGui::SameLine(); + HelpMarker("Using the simplified one-liner Combo API here.\n" + "Refer to the \"Combo\" section below for an explanation of how to use the more flexible and " + "general BeginCombo/EndCombo API."); } { // Using the _simplified_ one-liner ListBox() api here // See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api. IMGUI_DEMO_MARKER("Widgets/Basic/ListBox"); - const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; + const char *items[] = {"Apple", "Banana", "Cherry", "Kiwi", "Mango", + "Orange", "Pineapple", "Strawberry", "Watermelon"}; static int item_current = 1; ImGui::ListBox("listbox", &item_current, items, IM_ARRAYSIZE(items), 4); - ImGui::SameLine(); HelpMarker( - "Using the simplified one-liner ListBox API here.\n" - "Refer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API."); + ImGui::SameLine(); + HelpMarker("Using the simplified one-liner ListBox API here.\n" + "Refer to the \"List boxes\" section below for an explanation of how to use the more flexible " + "and general BeginListBox/EndListBox API."); } // Testing ImGuiOnceUponAFrame helper. - //static ImGuiOnceUponAFrame once; - //for (int i = 0; i < 5; i++) + // static ImGuiOnceUponAFrame once; + // for (int i = 0; i < 5; i++) // if (once) // ImGui::Text("This will be displayed only once."); @@ -1038,8 +1233,10 @@ static void DemoWindowWidgetsBullets() ImGui::BulletText("Another bullet point"); ImGui::TreePop(); } - ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)"); - ImGui::Bullet(); ImGui::SmallButton("Button"); + ImGui::Bullet(); + ImGui::Text("Bullet point 3 (two calls)"); + ImGui::Bullet(); + ImGui::SmallButton("Button"); ImGui::TreePop(); } } @@ -1093,32 +1290,37 @@ static void DemoWindowWidgetsColorAndPickers() ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaNoBg", &base_flags, ImGuiColorEditFlags_AlphaNoBg); ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaPreviewHalf", &base_flags, ImGuiColorEditFlags_AlphaPreviewHalf); ImGui::CheckboxFlags("ImGuiColorEditFlags_NoDragDrop", &base_flags, ImGuiColorEditFlags_NoDragDrop); - ImGui::CheckboxFlags("ImGuiColorEditFlags_NoOptions", &base_flags, ImGuiColorEditFlags_NoOptions); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options."); - ImGui::CheckboxFlags("ImGuiColorEditFlags_HDR", &base_flags, ImGuiColorEditFlags_HDR); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); + ImGui::CheckboxFlags("ImGuiColorEditFlags_NoOptions", &base_flags, ImGuiColorEditFlags_NoOptions); + ImGui::SameLine(); + HelpMarker("Right-click on the individual color widget to show options."); + ImGui::CheckboxFlags("ImGuiColorEditFlags_HDR", &base_flags, ImGuiColorEditFlags_HDR); + ImGui::SameLine(); + HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit"); ImGui::SeparatorText("Inline color editor"); ImGui::Text("Color widget:"); - ImGui::SameLine(); HelpMarker( - "Click on the color square to open a color picker.\n" - "CTRL+click on individual component to input value.\n"); - ImGui::ColorEdit3("MyColor##1", (float*)&color, base_flags); + ImGui::SameLine(); + HelpMarker("Click on the color square to open a color picker.\n" + "CTRL+click on individual component to input value.\n"); + ImGui::ColorEdit3("MyColor##1", (float *)&color, base_flags); IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)"); ImGui::Text("Color widget HSV with Alpha:"); - ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | base_flags); + ImGui::ColorEdit4("MyColor##2", (float *)&color, ImGuiColorEditFlags_DisplayHSV | base_flags); IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)"); ImGui::Text("Color widget with Float Display:"); - ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | base_flags); + ImGui::ColorEdit4("MyColor##2f", (float *)&color, ImGuiColorEditFlags_Float | base_flags); IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)"); ImGui::Text("Color button with Picker:"); - ImGui::SameLine(); HelpMarker( - "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n" - "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only " - "be used for the tooltip and picker popup."); - ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | base_flags); + ImGui::SameLine(); + HelpMarker("With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n" + "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only " + "be used for the tooltip and picker popup."); + ImGui::ColorEdit4("MyColor##3", (float *)&color, + ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | base_flags); IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)"); ImGui::Text("Color button with Custom Picker Popup:"); @@ -1130,8 +1332,8 @@ static void DemoWindowWidgetsColorAndPickers() { for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) { - ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, - saved_palette[n].x, saved_palette[n].y, saved_palette[n].z); + ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, saved_palette[n].x, saved_palette[n].y, + saved_palette[n].z); saved_palette[n].w = 1.0f; // Alpha } saved_palette_init = false; @@ -1150,14 +1352,17 @@ static void DemoWindowWidgetsColorAndPickers() { ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!"); ImGui::Separator(); - ImGui::ColorPicker4("##picker", (float*)&color, base_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); + ImGui::ColorPicker4("##picker", (float *)&color, + base_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); ImGui::SameLine(); ImGui::BeginGroup(); // Lock X position ImGui::Text("Current"); - ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)); + ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, + ImVec2(60, 40)); ImGui::Text("Previous"); - if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40))) + if (ImGui::ColorButton("##previous", backup_color, + ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40))) color = backup_color; ImGui::Separator(); ImGui::Text("Palette"); @@ -1167,18 +1372,20 @@ static void DemoWindowWidgetsColorAndPickers() if ((n % 8) != 0) ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); - ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; + ImGuiColorEditFlags palette_button_flags = + ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20))) - color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! + color = + ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! // Allow user to drop colors into each palette entry. Note that ColorButton() is already a // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag. if (ImGui::BeginDragDropTarget()) { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) - memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3); - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) - memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4); + if (const ImGuiPayload *payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + memcpy((float *)&saved_palette[n], payload->Data, sizeof(float) * 3); + if (const ImGuiPayload *payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + memcpy((float *)&saved_palette[n], payload->Data, sizeof(float) * 4); ImGui::EndDragDropTarget(); } @@ -1192,7 +1399,8 @@ static void DemoWindowWidgetsColorAndPickers() ImGui::Text("Color button only:"); static bool no_border = false; ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border); - ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, base_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); + ImGui::ColorButton("MyColor##3c", *(ImVec4 *)&color, + base_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker"); ImGui::SeparatorText("Color picker"); @@ -1206,7 +1414,8 @@ static void DemoWindowWidgetsColorAndPickers() ImGui::PushID("Color picker"); ImGui::CheckboxFlags("ImGuiColorEditFlags_NoAlpha", &color_picker_flags, ImGuiColorEditFlags_NoAlpha); ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaBar", &color_picker_flags, ImGuiColorEditFlags_AlphaBar); - ImGui::CheckboxFlags("ImGuiColorEditFlags_NoSidePreview", &color_picker_flags, ImGuiColorEditFlags_NoSidePreview); + ImGui::CheckboxFlags("ImGuiColorEditFlags_NoSidePreview", &color_picker_flags, + ImGuiColorEditFlags_NoSidePreview); if (color_picker_flags & ImGuiColorEditFlags_NoSidePreview) { ImGui::SameLine(); @@ -1218,58 +1427,79 @@ static void DemoWindowWidgetsColorAndPickers() } } - ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0ImGuiColorEditFlags_PickerHueBar\0ImGuiColorEditFlags_PickerHueWheel\0"); - ImGui::SameLine(); HelpMarker("When not specified explicitly, user can right-click the picker to change mode."); + ImGui::Combo("Picker Mode", &picker_mode, + "Auto/Current\0ImGuiColorEditFlags_PickerHueBar\0ImGuiColorEditFlags_PickerHueWheel\0"); + ImGui::SameLine(); + HelpMarker("When not specified explicitly, user can right-click the picker to change mode."); - ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0ImGuiColorEditFlags_NoInputs\0ImGuiColorEditFlags_DisplayRGB\0ImGuiColorEditFlags_DisplayHSV\0ImGuiColorEditFlags_DisplayHex\0"); - ImGui::SameLine(); HelpMarker( - "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, " - "but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex " - "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions()."); + ImGui::Combo("Display Mode", &display_mode, + "Auto/" + "Current\0ImGuiColorEditFlags_NoInputs\0ImGuiColorEditFlags_DisplayRGB\0ImGuiColorEditFlags_" + "DisplayHSV\0ImGuiColorEditFlags_DisplayHex\0"); + ImGui::SameLine(); + HelpMarker("ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, " + "but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to " + "displaying RGB+HSV+Hex " + "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions()."); ImGuiColorEditFlags flags = base_flags | color_picker_flags; - if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar; - if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel; - if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays - if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode - if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV; - if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex; - ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL); + if (picker_mode == 1) + flags |= ImGuiColorEditFlags_PickerHueBar; + if (picker_mode == 2) + flags |= ImGuiColorEditFlags_PickerHueWheel; + if (display_mode == 1) + flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays + if (display_mode == 2) + flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode + if (display_mode == 3) + flags |= ImGuiColorEditFlags_DisplayHSV; + if (display_mode == 4) + flags |= ImGuiColorEditFlags_DisplayHex; + ImGui::ColorPicker4("MyColor##4", (float *)&color, flags, ref_color ? &ref_color_v.x : NULL); ImGui::Text("Set defaults in code:"); - ImGui::SameLine(); HelpMarker( - "SetColorEditOptions() is designed to allow you to set boot-time default.\n" - "We don't have Push/Pop functions because you can force options on a per-widget basis if needed, " - "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid " - "encouraging you to persistently save values that aren't forward-compatible."); + ImGui::SameLine(); + HelpMarker("SetColorEditOptions() is designed to allow you to set boot-time default.\n" + "We don't have Push/Pop functions because you can force options on a per-widget basis if needed, " + "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid " + "encouraging you to persistently save values that aren't forward-compatible."); if (ImGui::Button("Default: Uint8 + HSV + Hue Bar")) - ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar); + ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | + ImGuiColorEditFlags_PickerHueBar); if (ImGui::Button("Default: Float + HDR + Hue Wheel")) - ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel); + ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | + ImGuiColorEditFlags_PickerHueWheel); // Always display a small version of both types of pickers // (that's in order to make it more visible in the demo to people who are skimming quickly through it) ImGui::Text("Both types:"); float w = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.y) * 0.40f; ImGui::SetNextItemWidth(w); - ImGui::ColorPicker3("##MyColor##5", (float*)&color, ImGuiColorEditFlags_PickerHueBar | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha); + ImGui::ColorPicker3("##MyColor##5", (float *)&color, + ImGuiColorEditFlags_PickerHueBar | ImGuiColorEditFlags_NoSidePreview | + ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha); ImGui::SameLine(); ImGui::SetNextItemWidth(w); - ImGui::ColorPicker3("##MyColor##6", (float*)&color, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha); + ImGui::ColorPicker3("##MyColor##6", (float *)&color, + ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | + ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha); ImGui::PopID(); // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV! ImGui::Spacing(); ImGui::Text("HSV encoded colors"); - ImGui::SameLine(); HelpMarker( + ImGui::SameLine(); + HelpMarker( "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV " "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the " "added benefit that you can manipulate hue values with the picker even when saturation or value are zero."); ImGui::Text("Color widget with InputHSV:"); - ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); - ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); - ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f); + ImGui::ColorEdit4("HSV shown as RGB##1", (float *)&color_hsv, + ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); + ImGui::ColorEdit4("HSV shown as HSV##1", (float *)&color_hsv, + ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); + ImGui::DragFloat4("Raw HSV values", (float *)&color_hsv, 0.01f, 0.0f, 1.0f); ImGui::TreePop(); } @@ -1288,9 +1518,10 @@ static void DemoWindowWidgetsComboBoxes() // Expose flags as checkbox for the demo static ImGuiComboFlags flags = 0; ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", &flags, ImGuiComboFlags_PopupAlignLeft); - ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo"); + ImGui::SameLine(); + HelpMarker("Only makes a difference if the popup is larger than the combo"); if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", &flags, ImGuiComboFlags_NoArrowButton)) - flags &= ~ImGuiComboFlags_NoPreview; // Clear incompatible flags + flags &= ~ImGuiComboFlags_NoPreview; // Clear incompatible flags if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", &flags, ImGuiComboFlags_NoPreview)) flags &= ~(ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_WidthFitPreview); // Clear incompatible flags if (ImGui::CheckboxFlags("ImGuiComboFlags_WidthFitPreview", &flags, ImGuiComboFlags_WidthFitPreview)) @@ -1307,11 +1538,13 @@ static void DemoWindowWidgetsComboBoxes() // Using the generic BeginCombo() API, you have full control over how to display the combo contents. // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively // stored in the object itself, etc.) - const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; + const char *items[] = {"AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", + "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO"}; static int item_selected_idx = 0; // Here we store our selection data as an index. - // Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[]) - const char* combo_preview_value = items[item_selected_idx]; + // Pass in the preview value visible before opening the combo (it could technically be different contents or not + // pulled from items[]) + const char *combo_preview_value = items[item_selected_idx]; if (ImGui::BeginCombo("combo 1", combo_preview_value, flags)) { for (int n = 0; n < IM_ARRAYSIZE(items); n++) @@ -1352,7 +1585,8 @@ static void DemoWindowWidgetsComboBoxes() ImGui::Spacing(); ImGui::SeparatorText("One-liner variants"); - HelpMarker("The Combo() function is not greatly useful apart from cases were you want to embed all options in a single strings.\nFlags above don't apply to this section."); + HelpMarker("The Combo() function is not greatly useful apart from cases were you want to embed all options in " + "a single strings.\nFlags above don't apply to this section."); // Simplified one-liner Combo() API, using values packed in a single constant string // This is a convenience for when the selection set is small and known at compile-time. @@ -1366,7 +1600,9 @@ static void DemoWindowWidgetsComboBoxes() // Simplified one-liner Combo() using an accessor function static int item_current_4 = 0; - ImGui::Combo("combo 5 (function)", &item_current_4, [](void* data, int n) { return ((const char**)data)[n]; }, items, IM_ARRAYSIZE(items)); + ImGui::Combo( + "combo 5 (function)", &item_current_4, [](void *data, int n) { return ((const char **)data)[n]; }, items, + IM_ARRAYSIZE(items)); ImGui::TreePop(); } @@ -1381,49 +1617,53 @@ static void DemoWindowWidgetsDataTypes() IMGUI_DEMO_MARKER("Widgets/Data Types"); if (ImGui::TreeNode("Data Types")) { - // DragScalar/InputScalar/SliderScalar functions allow various data types - // - signed/unsigned - // - 8/16/32/64-bits - // - integer/float/double - // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum - // to pass the type, and passing all arguments by pointer. - // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each type. - // In practice, if you frequently use a given type that is not covered by the normal API entry points, - // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*, - // and then pass their address to the generic function. For example: - // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") - // { - // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); - // } +// DragScalar/InputScalar/SliderScalar functions allow various data types +// - signed/unsigned +// - 8/16/32/64-bits +// - integer/float/double +// To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum +// to pass the type, and passing all arguments by pointer. +// This is the reason the test code below creates local variables to hold "zero" "one" etc. for each type. +// In practice, if you frequently use a given type that is not covered by the normal API entry points, +// you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*, +// and then pass their address to the generic function. For example: +// bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") +// { +// return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); +// } - // Setup limits (as helper variables so we can take their address, as explained above) - // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2. - #ifndef LLONG_MIN +// Setup limits (as helper variables so we can take their address, as explained above) +// Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2. +#ifndef LLONG_MIN ImS64 LLONG_MIN = -9223372036854775807LL - 1; ImS64 LLONG_MAX = 9223372036854775807LL; ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1); - #endif - const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127; - const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255; - const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767; - const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535; - const ImS32 s32_zero = 0, s32_one = 1, s32_fifty = 50, s32_min = INT_MIN/2, s32_max = INT_MAX/2, s32_hi_a = INT_MAX/2 - 100, s32_hi_b = INT_MAX/2; - const ImU32 u32_zero = 0, u32_one = 1, u32_fifty = 50, u32_min = 0, u32_max = UINT_MAX/2, u32_hi_a = UINT_MAX/2 - 100, u32_hi_b = UINT_MAX/2; - const ImS64 s64_zero = 0, s64_one = 1, s64_fifty = 50, s64_min = LLONG_MIN/2, s64_max = LLONG_MAX/2, s64_hi_a = LLONG_MAX/2 - 100, s64_hi_b = LLONG_MAX/2; - const ImU64 u64_zero = 0, u64_one = 1, u64_fifty = 50, u64_min = 0, u64_max = ULLONG_MAX/2, u64_hi_a = ULLONG_MAX/2 - 100, u64_hi_b = ULLONG_MAX/2; - const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f; - const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0; +#endif + const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127; + const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255; + const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767; + const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535; + const ImS32 s32_zero = 0, s32_one = 1, s32_fifty = 50, s32_min = INT_MIN / 2, s32_max = INT_MAX / 2, + s32_hi_a = INT_MAX / 2 - 100, s32_hi_b = INT_MAX / 2; + const ImU32 u32_zero = 0, u32_one = 1, u32_fifty = 50, u32_min = 0, u32_max = UINT_MAX / 2, + u32_hi_a = UINT_MAX / 2 - 100, u32_hi_b = UINT_MAX / 2; + const ImS64 s64_zero = 0, s64_one = 1, s64_fifty = 50, s64_min = LLONG_MIN / 2, s64_max = LLONG_MAX / 2, + s64_hi_a = LLONG_MAX / 2 - 100, s64_hi_b = LLONG_MAX / 2; + const ImU64 u64_zero = 0, u64_one = 1, u64_fifty = 50, u64_min = 0, u64_max = ULLONG_MAX / 2, + u64_hi_a = ULLONG_MAX / 2 - 100, u64_hi_b = ULLONG_MAX / 2; + const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f; + const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0; // State - static char s8_v = 127; - static ImU8 u8_v = 255; - static short s16_v = 32767; - static ImU16 u16_v = 65535; - static ImS32 s32_v = -1; - static ImU32 u32_v = (ImU32)-1; - static ImS64 s64_v = -1; - static ImU64 u64_v = (ImU64)-1; - static float f32_v = 0.123f; + static char s8_v = 127; + static ImU8 u8_v = 255; + static short s16_v = 32767; + static ImU16 u16_v = 65535; + static ImS32 s32_v = -1; + static ImU32 u32_v = (ImU32)-1; + static ImS64 s64_v = -1; + static ImU64 u64_v = (ImU64)-1; + static float f32_v = 0.123f; static double f64_v = 90000.01234567890123456789; const float drag_speed = 0.2f; @@ -1431,56 +1671,69 @@ static void DemoWindowWidgetsDataTypes() IMGUI_DEMO_MARKER("Widgets/Data Types/Drags"); ImGui::SeparatorText("Drags"); ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); - ImGui::SameLine(); HelpMarker( - "As with every widget in dear imgui, we never modify values unless there is a user interaction.\n" - "You can override the clamping limits by using CTRL+Click to input a value."); - ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL); - ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms"); - ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL); - ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms"); - ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL); - ImGui::DragScalar("drag s32 hex", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL, "0x%08X"); - ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms"); - ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL); - ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL); - ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f"); - ImGui::DragScalar("drag float log", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic); - ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams"); - ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic); + ImGui::SameLine(); + HelpMarker("As with every widget in dear imgui, we never modify values unless there is a user interaction.\n" + "You can override the clamping limits by using CTRL+Click to input a value."); + ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, + drag_clamp ? &s8_fifty : NULL); + ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, + drag_clamp ? &u8_fifty : NULL, "%u ms"); + ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, + drag_clamp ? &s16_fifty : NULL); + ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, + drag_clamp ? &u16_fifty : NULL, "%u ms"); + ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, + drag_clamp ? &s32_fifty : NULL); + ImGui::DragScalar("drag s32 hex", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, + drag_clamp ? &s32_fifty : NULL, "0x%08X"); + ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, + drag_clamp ? &u32_fifty : NULL, "%u ms"); + ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, + drag_clamp ? &s64_fifty : NULL); + ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, + drag_clamp ? &u64_fifty : NULL); + ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f"); + ImGui::DragScalar("drag float log", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", + ImGuiSliderFlags_Logarithmic); + ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams"); + ImGui::DragScalar("drag double log", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, + "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic); IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders"); ImGui::SeparatorText("Sliders"); - ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d"); - ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u"); - ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d"); - ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u"); - ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d"); - ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d"); - ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d"); - ImGui::SliderScalar("slider s32 hex", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty, "0x%04X"); - 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,"%" PRId64); - ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" PRId64); - ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" PRId64); - ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" PRIu64 " ms"); - ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" PRIu64 " ms"); - ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" 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"); - ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams"); - ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic); - ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams"); + ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d"); + ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u"); + ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d"); + ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u"); + ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty, "%d"); + ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d"); + ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d"); + ImGui::SliderScalar("slider s32 hex", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty, "0x%04X"); + 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, "%" PRId64); + ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" PRId64); + ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" PRId64); + ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty, "%" PRIu64 " ms"); + ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" PRIu64 " ms"); + ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" 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"); + ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams"); + ImGui::SliderScalar("slider double low log", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", + ImGuiSliderFlags_Logarithmic); + ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams"); ImGui::SeparatorText("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 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, "%" PRId64); - ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" PRIu64 " ms"); + 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, "%" PRId64); + ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" PRIu64 " ms"); IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs"); static bool inputs_step = true; @@ -1490,18 +1743,22 @@ static void DemoWindowWidgetsDataTypes() ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly); ImGui::CheckboxFlags("ImGuiInputTextFlags_ParseEmptyRefVal", &flags, ImGuiInputTextFlags_ParseEmptyRefVal); ImGui::CheckboxFlags("ImGuiInputTextFlags_DisplayEmptyRefVal", &flags, ImGuiInputTextFlags_DisplayEmptyRefVal); - ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d", flags); - ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u", flags); - ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d", flags); - ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u", flags); - ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d", flags); - ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%04X", flags); - ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u", flags); - ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", flags); - ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL, NULL, NULL, flags); - ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL, NULL, NULL, flags); - ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL, NULL, NULL, flags); - ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL, NULL, NULL, flags); + ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d", flags); + ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u", flags); + ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d", flags); + ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u", flags); + ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d", flags); + ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%04X", + flags); + ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u", flags); + ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", + flags); + ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL, NULL, NULL, flags); + ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL, NULL, NULL, flags); + ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL, NULL, NULL, + flags); + ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL, NULL, NULL, + flags); ImGui::TreePop(); } @@ -1511,13 +1768,14 @@ static void DemoWindowWidgetsDataTypes() // [SECTION] DemoWindowWidgetsDisableBlocks() //----------------------------------------------------------------------------- -static void DemoWindowWidgetsDisableBlocks(ImGuiDemoWindowData* demo_data) +static void DemoWindowWidgetsDisableBlocks(ImGuiDemoWindowData *demo_data) { IMGUI_DEMO_MARKER("Widgets/Disable Blocks"); if (ImGui::TreeNode("Disable Blocks")) { ImGui::Checkbox("Disable entire section above", &demo_data->DisableSections); - ImGui::SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across other sections."); + ImGui::SameLine(); + HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across other sections."); ImGui::TreePop(); } } @@ -1539,8 +1797,8 @@ static void DemoWindowWidgetsDragAndDrop() // to allow your own widgets to use colors in their drag and drop interaction. // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo. HelpMarker("You can drag from the color squares."); - static float col1[3] = { 1.0f, 0.0f, 0.2f }; - static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; + static float col1[3] = {1.0f, 0.0f, 0.2f}; + static float col2[4] = {0.4f, 0.7f, 0.0f, 0.5f}; ImGui::ColorEdit3("color 1", col1); ImGui::ColorEdit4("color 2", col2); ImGui::TreePop(); @@ -1556,15 +1814,22 @@ static void DemoWindowWidgetsDragAndDrop() Mode_Swap }; static int mode = 0; - if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine(); - if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine(); - if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; } - static const char* names[9] = + if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { - "Bobby", "Beatrice", "Betty", - "Brianna", "Barry", "Bernard", - "Bibi", "Blaine", "Bryn" - }; + mode = Mode_Copy; + } + ImGui::SameLine(); + if (ImGui::RadioButton("Move", mode == Mode_Move)) + { + mode = Mode_Move; + } + ImGui::SameLine(); + if (ImGui::RadioButton("Swap", mode == Mode_Swap)) + { + mode = Mode_Swap; + } + static const char *names[9] = {"Bobby", "Beatrice", "Betty", "Brianna", "Barry", + "Bernard", "Bibi", "Blaine", "Bryn"}; for (int n = 0; n < IM_ARRAYSIZE(names); n++) { ImGui::PushID(n); @@ -1580,17 +1845,26 @@ static void DemoWindowWidgetsDragAndDrop() // Display preview (could be anything, e.g. when dragging an image we could decide to display // the filename and a small preview of the image, etc.) - if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); } - if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); } - if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); } + if (mode == Mode_Copy) + { + ImGui::Text("Copy %s", names[n]); + } + if (mode == Mode_Move) + { + ImGui::Text("Move %s", names[n]); + } + if (mode == Mode_Swap) + { + ImGui::Text("Swap %s", names[n]); + } ImGui::EndDragDropSource(); } if (ImGui::BeginDragDropTarget()) { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL")) + if (const ImGuiPayload *payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL")) { IM_ASSERT(payload->DataSize == sizeof(int)); - int payload_n = *(const int*)payload->Data; + int payload_n = *(const int *)payload->Data; if (mode == Mode_Copy) { names[n] = names[payload_n]; @@ -1602,7 +1876,7 @@ static void DemoWindowWidgetsDragAndDrop() } if (mode == Mode_Swap) { - const char* tmp = names[n]; + const char *tmp = names[n]; names[n] = names[payload_n]; names[payload_n] = tmp; } @@ -1617,19 +1891,18 @@ static void DemoWindowWidgetsDragAndDrop() IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)"); if (ImGui::TreeNode("Drag to reorder items (simple)")) { - // FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice. - // This code was always slightly faulty but in a way which was not easily noticeable. + // FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be + // submitting twice. This code was always slightly faulty but in a way which was not easily noticeable. // Until we fix this, enable ImGuiItemFlags_AllowDuplicateId to disable detecting the issue. ImGui::PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true); // Simple reordering - HelpMarker( - "We don't use the drag and drop api at all here! " - "Instead we query when the item is held but not hovered, and order items accordingly."); - static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" }; + HelpMarker("We don't use the drag and drop api at all here! " + "Instead we query when the item is held but not hovered, and order items accordingly."); + static const char *item_names[] = {"Item One", "Item Two", "Item Three", "Item Four", "Item Five"}; for (int n = 0; n < IM_ARRAYSIZE(item_names); n++) { - const char* item = item_names[n]; + const char *item = item_names[n]; ImGui::Selectable(item); if (ImGui::IsItemActive() && !ImGui::IsItemHovered()) @@ -1657,8 +1930,10 @@ static void DemoWindowWidgetsDragAndDrop() ImGui::Button(n ? "drop here##1" : "drop here##0"); if (ImGui::BeginDragDropTarget()) { - ImGuiDragDropFlags drop_target_flags = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoPreviewTooltip; - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, drop_target_flags)) + ImGuiDragDropFlags drop_target_flags = + ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoPreviewTooltip; + if (const ImGuiPayload *payload = + ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, drop_target_flags)) { IM_UNUSED(payload); ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed); @@ -1668,10 +1943,9 @@ static void DemoWindowWidgetsDragAndDrop() } // Drop source - static ImVec4 col4 = { 1.0f, 0.0f, 0.2f, 1.0f }; + static ImVec4 col4 = {1.0f, 0.0f, 0.2f, 1.0f}; if (n == 0) ImGui::ColorButton("drag me", col4); - } ImGui::TreePop(); } @@ -1693,19 +1967,30 @@ static void DemoWindowWidgetsDragsAndSliders() static ImGuiSliderFlags flags = ImGuiSliderFlags_None; ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp); ImGui::CheckboxFlags("ImGuiSliderFlags_ClampOnInput", &flags, ImGuiSliderFlags_ClampOnInput); - ImGui::SameLine(); HelpMarker("Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds."); + ImGui::SameLine(); + HelpMarker("Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows " + "going out of bounds."); ImGui::CheckboxFlags("ImGuiSliderFlags_ClampZeroRange", &flags, ImGuiSliderFlags_ClampZeroRange); - ImGui::SameLine(); HelpMarker("Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp."); + ImGui::SameLine(); + HelpMarker("Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp."); ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic); - ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values)."); + ImGui::SameLine(); + HelpMarker("Enable logarithmic editing (more precision for small values)."); ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat); - ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits)."); + ImGui::SameLine(); + HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are " + "rounded to those 3 digits)."); ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput); - ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget."); + ImGui::SameLine(); + HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget."); ImGui::CheckboxFlags("ImGuiSliderFlags_NoSpeedTweaks", &flags, ImGuiSliderFlags_NoSpeedTweaks); - ImGui::SameLine(); HelpMarker("Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic."); + ImGui::SameLine(); + HelpMarker("Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself " + "based on your own logic."); ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuiSliderFlags_WrapAround); - ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)"); + ImGui::SameLine(); + HelpMarker( + "Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)"); // Drags static float drag_f = 0.5f; @@ -1715,8 +2000,8 @@ static void DemoWindowWidgetsDragsAndSliders() ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags); ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags); ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags); - //ImGui::DragFloat("DragFloat (0 -> 0)", &drag_f, 0.005f, 0.0f, 0.0f, "%.3f", flags); // To test ClampZeroRange - //ImGui::DragFloat("DragFloat (100 -> 100)", &drag_f, 0.005f, 100.0f, 100.0f, "%.3f", flags); + // ImGui::DragFloat("DragFloat (0 -> 0)", &drag_f, 0.005f, 0.0f, 0.0f, "%.3f", flags); // To test + // ClampZeroRange ImGui::DragFloat("DragFloat (100 -> 100)", &drag_f, 0.005f, 100.0f, 100.0f, "%.3f", flags); ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags); // Sliders @@ -1736,14 +2021,17 @@ static void DemoWindowWidgetsDragsAndSliders() //----------------------------------------------------------------------------- // Forward declare ShowFontAtlas() which isn't worth putting in public API yet -namespace ImGui { IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); } +namespace ImGui +{ +IMGUI_API void ShowFontAtlas(ImFontAtlas *atlas); +} static void DemoWindowWidgetsFonts() { IMGUI_DEMO_MARKER("Widgets/Fonts"); if (ImGui::TreeNode("Fonts")) { - ImFontAtlas* atlas = ImGui::GetIO().Fonts; + ImFontAtlas *atlas = ImGui::GetIO().Fonts; ImGui::ShowFontAtlas(atlas); // FIXME-NEWATLAS: Provide a demo to add/create a procedural font? ImGui::TreePop(); @@ -1759,7 +2047,7 @@ static void DemoWindowWidgetsImages() IMGUI_DEMO_MARKER("Widgets/Images"); if (ImGui::TreeNode("Images")) { - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO &io = ImGui::GetIO(); ImGui::TextWrapped( "Below we are displaying the font texture (which is the only texture we have access to in this demo). " "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. " @@ -1771,7 +2059,8 @@ static void DemoWindowWidgetsImages() // of their respective source file to specify what they are using as texture identifier, for example: // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer. // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc. - // So with the DirectX11 backend, you call ImGui::Image() with a 'ID3D11ShaderResourceView*' cast to ImTextureID. + // So with the DirectX11 backend, you call ImGui::Image() with a 'ID3D11ShaderResourceView*' cast to + // ImTextureID. // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers // to ImGui::Image(), and gather width/height through your own functions, etc. // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer, @@ -1783,7 +2072,8 @@ static void DemoWindowWidgetsImages() // Grab the current texture identifier used by the font atlas. ImTextureRef my_tex_id = io.Fonts->TexRef; - // Regular user code should never have to care about TexData-> fields, but since we want to display the entire texture here, we pull Width/Height from it. + // Regular user code should never have to care about TexData-> fields, but since we want to display the entire + // texture here, we pull Width/Height from it. float my_tex_w = (float)io.Fonts->TexData->Width; float my_tex_h = (float)io.Fonts->TexData->Height; @@ -1800,15 +2090,28 @@ static void DemoWindowWidgetsImages() float region_x = io.MousePos.x - pos.x - region_sz * 0.5f; float region_y = io.MousePos.y - pos.y - region_sz * 0.5f; float zoom = 4.0f; - if (region_x < 0.0f) { region_x = 0.0f; } - else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; } - if (region_y < 0.0f) { region_y = 0.0f; } - else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; } + if (region_x < 0.0f) + { + region_x = 0.0f; + } + else if (region_x > my_tex_w - region_sz) + { + region_x = my_tex_w - region_sz; + } + if (region_y < 0.0f) + { + region_y = 0.0f; + } + else if (region_y > my_tex_h - region_sz) + { + region_y = my_tex_h - region_sz; + } ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y); ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz); ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h); ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h); - ImGui::ImageWithBg(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + ImGui::ImageWithBg(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, + ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); ImGui::EndTooltip(); } ImGui::PopStyleVar(); @@ -1821,15 +2124,16 @@ static void DemoWindowWidgetsImages() { // UV coordinates are often (0.0f, 0.0f) and (1.0f, 1.0f) to display an entire textures. // Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation. - // Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples + // Read about UV coordinates here: + // https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples ImGui::PushID(i); if (i > 0) ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(i - 1.0f, i - 1.0f)); - ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible - ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left - ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h); // UV coordinates for (32,32) in our texture - ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background - ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint + ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible + ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left + ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h); // UV coordinates for (32,32) in our texture + ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background + ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint if (ImGui::ImageButton("", my_tex_id, size, uv0, uv1, bg_col, tint_col)) pressed_count += 1; if (i > 0) @@ -1860,7 +2164,8 @@ static void DemoWindowWidgetsListBoxes() // Using the generic BeginListBox() API, you have full control over how to display the combo contents. // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively // stored in the object itself, etc.) - const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; + const char *items[] = {"AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", + "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO"}; static int item_selected_idx = 0; // Here we store our selected data as an index. static bool item_highlight = false; @@ -1884,7 +2189,8 @@ static void DemoWindowWidgetsListBoxes() } ImGui::EndListBox(); } - ImGui::SameLine(); HelpMarker("Here we are sharing selection state between both boxes."); + ImGui::SameLine(); + HelpMarker("Here we are sharing selection state between both boxes."); // Custom size: use all width, 5 items tall ImGui::Text("Full-width:"); @@ -1917,8 +2223,8 @@ static void DemoWindowWidgetsMultiComponents() IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets"); if (ImGui::TreeNode("Multi-component Widgets")) { - static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; - static int vec4i[4] = { 1, 5, 100, 255 }; + static float vec4f[4] = {0.10f, 0.20f, 0.30f, 0.44f}; + static int vec4i[4] = {1, 5, 100, 255}; ImGui::SeparatorText("2-wide"); ImGui::InputFloat2("input float2", vec4f); @@ -1947,7 +2253,8 @@ static void DemoWindowWidgetsMultiComponents() ImGui::SeparatorText("Ranges"); static float begin = 10, end = 90; static int begin_i = 100, end_i = 1000; - ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp); + ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", + ImGuiSliderFlags_AlwaysClamp); ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units"); ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units"); @@ -1962,8 +2269,8 @@ static void DemoWindowWidgetsMultiComponents() static void DemoWindowWidgetsPlotting() { // Plot/Graph widgets are not very good. -// Consider using a third-party library such as ImPlot: https://github.com/epezent/implot -// (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions) + // Consider using a third-party library such as ImPlot: https://github.com/epezent/implot + // (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions) IMGUI_DEMO_MARKER("Widgets/Plotting"); if (ImGui::TreeNode("Plotting")) { @@ -1975,10 +2282,10 @@ static void DemoWindowWidgetsPlotting() ImGui::Checkbox("Animate", &animate); // Plot as lines and plot as histogram - static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; + static float arr[] = {0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f}; ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f)); - //ImGui::SameLine(); HelpMarker("Consider using ImPlot instead!"); + // ImGui::SameLine(); HelpMarker("Consider using ImPlot instead!"); // Fill an array of contiguous float values to plot // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float @@ -2006,7 +2313,8 @@ static void DemoWindowWidgetsPlotting() average /= (float)IM_ARRAYSIZE(values); char overlay[32]; sprintf(overlay, "avg %f", average); - ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f)); + ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, + ImVec2(0, 80.0f)); } // Use functions to generate output @@ -2014,8 +2322,14 @@ static void DemoWindowWidgetsPlotting() // We probably want an API passing floats and user provide sample rate/count. struct Funcs { - static float Sin(void*, int i) { return sinf(i * 0.1f); } - static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; } + static float Sin(void *, int i) + { + return sinf(i * 0.1f); + } + static float Saw(void *, int i) + { + return (i & 1) ? 1.0f : -1.0f; + } }; static int func_type = 0, display_count = 70; ImGui::SeparatorText("Functions"); @@ -2023,7 +2337,7 @@ static void DemoWindowWidgetsPlotting() ImGui::Combo("func", &func_type, "Sin\0Saw\0"); ImGui::SameLine(); ImGui::SliderInt("Sample count", &display_count, 1, 400); - float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; + float (*func)(void *, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; ImGui::PlotLines("Lines##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); ImGui::PlotHistogram("Histogram##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); @@ -2043,8 +2357,16 @@ static void DemoWindowWidgetsProgressBars() // Animate a simple progress bar static float progress = 0.0f, progress_dir = 1.0f; progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime; - if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; } - if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; } + if (progress >= +1.1f) + { + progress = +1.1f; + progress_dir *= -1.0f; + } + if (progress <= -0.1f) + { + progress = -0.1f; + progress_dir *= -1.0f; + } // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width, // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth. @@ -2077,41 +2399,111 @@ static void DemoWindowWidgetsQueryingStatuses() if (ImGui::TreeNode("Querying Item Status (Edited/Active/Hovered etc.)")) { // Select an item type - const char* item_names[] = - { - "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat", - "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox" - }; + const char *item_names[] = {"Text", + "Button", + "Button (w/ repeat)", + "Checkbox", + "SliderFloat", + "InputText", + "InputTextMultiline", + "InputFloat", + "InputFloat3", + "ColorEdit4", + "Selectable", + "MenuItem", + "TreeNode", + "TreeNode (w/ double-click)", + "Combo", + "ListBox"}; static int item_type = 4; static bool item_disabled = false; ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names)); ImGui::SameLine(); - HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered()."); + HelpMarker( + "Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool " + "return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered()."); ImGui::Checkbox("Item Disabled", &item_disabled); // Submit selected items so we can query their status in the code following it. bool ret = false; static bool b = false; - static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f }; + static float col4f[4] = {1.0f, 0.5, 0.0f, 1.0f}; static char str[16] = {}; if (item_disabled) ImGui::BeginDisabled(true); - if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction - if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button - if (item_type == 2) { ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); ret = ImGui::Button("ITEM: Button"); ImGui::PopItemFlag(); } // Testing button (with repeater) - if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox - if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item - if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing) - if (item_type == 6) { ret = ImGui::InputTextMultiline("ITEM: InputTextMultiline", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which uses a child window) - if (item_type == 7) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input - if (item_type == 8) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) - if (item_type == 9) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) - if (item_type == 10) { ret = ImGui::Selectable("ITEM: Selectable"); } // Testing selectable item - if (item_type == 11) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) - if (item_type == 12) { ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node - if (item_type == 13) { ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. - if (item_type == 14) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", ¤t, items, IM_ARRAYSIZE(items)); } - if (item_type == 15) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } + if (item_type == 0) + { + ImGui::Text("ITEM: Text"); + } // Testing text items with no identifier/interaction + if (item_type == 1) + { + ret = ImGui::Button("ITEM: Button"); + } // Testing button + if (item_type == 2) + { + ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); + ret = ImGui::Button("ITEM: Button"); + ImGui::PopItemFlag(); + } // Testing button (with repeater) + if (item_type == 3) + { + ret = ImGui::Checkbox("ITEM: Checkbox", &b); + } // Testing checkbox + if (item_type == 4) + { + ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); + } // Testing basic item + if (item_type == 5) + { + ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); + } // Testing input text (which handles tabbing) + if (item_type == 6) + { + ret = ImGui::InputTextMultiline("ITEM: InputTextMultiline", &str[0], IM_ARRAYSIZE(str)); + } // Testing input text (which uses a child window) + if (item_type == 7) + { + ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); + } // Testing +/- buttons on scalar input + if (item_type == 8) + { + ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); + } // Testing multi-component items (IsItemXXX flags are reported merged) + if (item_type == 9) + { + ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); + } // Testing multi-component items (IsItemXXX flags are reported merged) + if (item_type == 10) + { + ret = ImGui::Selectable("ITEM: Selectable"); + } // Testing selectable item + if (item_type == 11) + { + ret = ImGui::MenuItem("ITEM: MenuItem"); + } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) + if (item_type == 12) + { + ret = ImGui::TreeNode("ITEM: TreeNode"); + if (ret) + ImGui::TreePop(); + } // Testing tree node + if (item_type == 13) + { + ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", + ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); + } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. + if (item_type == 14) + { + const char *items[] = {"Apple", "Banana", "Cherry", "Kiwi"}; + static int current = 1; + ret = ImGui::Combo("ITEM: Combo", ¤t, items, IM_ARRAYSIZE(items)); + } + if (item_type == 15) + { + const char *items[] = {"Apple", "Banana", "Cherry", "Kiwi"}; + static int current = 1; + ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); + } bool hovered_delay_none = ImGui::IsItemHovered(); bool hovered_delay_stationary = ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary); @@ -2144,35 +2536,24 @@ static void DemoWindowWidgetsQueryingStatuses() "GetItemRectMin() = (%.1f, %.1f)\n" "GetItemRectMax() = (%.1f, %.1f)\n" "GetItemRectSize() = (%.1f, %.1f)", - ret, - ImGui::IsItemFocused(), - ImGui::IsItemHovered(), + ret, ImGui::IsItemFocused(), ImGui::IsItemHovered(), ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByItem), ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByWindow), - ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled), - ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), - ImGui::IsItemActive(), - ImGui::IsItemEdited(), - ImGui::IsItemActivated(), - ImGui::IsItemDeactivated(), - ImGui::IsItemDeactivatedAfterEdit(), - ImGui::IsItemVisible(), - ImGui::IsItemClicked(), - ImGui::IsItemToggledOpen(), - ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y, - ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y, - ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y - ); - ImGui::BulletText( - "with Hovering Delay or Stationary test:\n" - "IsItemHovered() = = %d\n" - "IsItemHovered(_Stationary) = %d\n" - "IsItemHovered(_DelayShort) = %d\n" - "IsItemHovered(_DelayNormal) = %d\n" - "IsItemHovered(_Tooltip) = %d", - hovered_delay_none, hovered_delay_stationary, hovered_delay_short, hovered_delay_normal, hovered_delay_tooltip); + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled), ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), + ImGui::IsItemActive(), ImGui::IsItemEdited(), ImGui::IsItemActivated(), ImGui::IsItemDeactivated(), + ImGui::IsItemDeactivatedAfterEdit(), ImGui::IsItemVisible(), ImGui::IsItemClicked(), + ImGui::IsItemToggledOpen(), ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y, ImGui::GetItemRectMax().x, + ImGui::GetItemRectMax().y, ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y); + ImGui::BulletText("with Hovering Delay or Stationary test:\n" + "IsItemHovered() = = %d\n" + "IsItemHovered(_Stationary) = %d\n" + "IsItemHovered(_DelayShort) = %d\n" + "IsItemHovered(_DelayNormal) = %d\n" + "IsItemHovered(_Tooltip) = %d", + hovered_delay_none, hovered_delay_stationary, hovered_delay_short, hovered_delay_normal, + hovered_delay_tooltip); if (item_disabled) ImGui::EndDisabled(); @@ -2180,7 +2561,8 @@ static void DemoWindowWidgetsQueryingStatuses() char buf[1] = ""; ImGui::InputText("unused", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_ReadOnly); ImGui::SameLine(); - HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status."); + HelpMarker( + "This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status."); ImGui::TreePop(); } @@ -2189,28 +2571,28 @@ static void DemoWindowWidgetsQueryingStatuses() if (ImGui::TreeNode("Querying Window Status (Focused/Hovered etc.)")) { static bool embed_all_inside_a_child_window = false; - ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", &embed_all_inside_a_child_window); + ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", + &embed_all_inside_a_child_window); if (embed_all_inside_a_child_window) ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Borders); // Testing IsWindowFocused() function with its various flags. - ImGui::BulletText( - "IsWindowFocused() = %d\n" - "IsWindowFocused(_ChildWindows) = %d\n" - "IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n" - "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" - "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" - "IsWindowFocused(_RootWindow) = %d\n" - "IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n" - "IsWindowFocused(_AnyWindow) = %d\n", - ImGui::IsWindowFocused(), - ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), - ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy), - ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), - ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy), - ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), - ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy), - ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); + ImGui::BulletText("IsWindowFocused() = %d\n" + "IsWindowFocused(_ChildWindows) = %d\n" + "IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n" + "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" + "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" + "IsWindowFocused(_RootWindow) = %d\n" + "IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n" + "IsWindowFocused(_AnyWindow) = %d\n", + ImGui::IsWindowFocused(), ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | + ImGuiFocusedFlags_NoPopupHierarchy), + ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), + ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy), + ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); // Testing IsWindowHovered() function with its various flags. ImGui::BulletText( @@ -2226,18 +2608,17 @@ static void DemoWindowWidgetsQueryingStatuses() "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" "IsWindowHovered(_AnyWindow) = %d\n" "IsWindowHovered(_Stationary) = %d\n", - ImGui::IsWindowHovered(), - ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsWindowHovered(), ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy), ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), - ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | + ImGuiHoveredFlags_NoPopupHierarchy), ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy), ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup), - ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow), - ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary)); + ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow), ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary)); ImGui::BeginChild("child", ImVec2(0, 50), ImGuiChildFlags_Borders); ImGui::Text("This is another child window for testing the _ChildWindows flag."); @@ -2254,13 +2635,15 @@ static void DemoWindowWidgetsQueryingStatuses() ImGui::Begin("Title bar Hovered/Active tests", &test_window); if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered() { - if (ImGui::MenuItem("Close")) { test_window = false; } + if (ImGui::MenuItem("Close")) + { + test_window = false; + } ImGui::EndPopup(); } - ImGui::Text( - "IsItemHovered() after begin = %d (== is title bar hovered)\n" - "IsItemActive() after begin = %d (== is window being clicked/moved)\n", - ImGui::IsItemHovered(), ImGui::IsItemActive()); + ImGui::Text("IsItemHovered() after begin = %d (== is title bar hovered)\n" + "IsItemActive() after begin = %d (== is window being clicked/moved)\n", + ImGui::IsItemHovered(), ImGui::IsItemActive()); ImGui::End(); } @@ -2275,7 +2658,7 @@ static void DemoWindowWidgetsQueryingStatuses() static void DemoWindowWidgetsSelectables() { IMGUI_DEMO_MARKER("Widgets/Selectables"); - //ImGui::SetNextItemOpen(true, ImGuiCond_Once); + // ImGui::SetNextItemOpen(true, ImGuiCond_Once); if (ImGui::TreeNode("Selectables")) { // Selectable() has 2 overloads: @@ -2287,7 +2670,7 @@ static void DemoWindowWidgetsSelectables() IMGUI_DEMO_MARKER("Widgets/Selectables/Basic"); if (ImGui::TreeNode("Basic")) { - static bool selection[5] = { false, true, false, false }; + static bool selection[5] = {false, true, false, false}; ImGui::Selectable("1. I am selectable", &selection[0]); ImGui::Selectable("2. I am selectable", &selection[1]); ImGui::Selectable("3. I am selectable", &selection[2]); @@ -2301,11 +2684,21 @@ static void DemoWindowWidgetsSelectables() if (ImGui::TreeNode("Rendering more items on the same line")) { // (1) Using SetNextItemAllowOverlap() - // (2) Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically. - static bool selected[3] = { false, false, false }; - ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(); ImGui::SmallButton("Link 1"); - ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(); ImGui::SmallButton("Link 2"); - ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(); ImGui::SmallButton("Link 3"); + // (2) Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled + // automatically. + static bool selected[3] = {false, false, false}; + ImGui::SetNextItemAllowOverlap(); + ImGui::Selectable("main.c", &selected[0]); + ImGui::SameLine(); + ImGui::SmallButton("Link 1"); + ImGui::SetNextItemAllowOverlap(); + ImGui::Selectable("Hello.cpp", &selected[1]); + ImGui::SameLine(); + ImGui::SmallButton("Link 2"); + ImGui::SetNextItemAllowOverlap(); + ImGui::Selectable("Hello.h", &selected[2]); + ImGui::SameLine(); + ImGui::SmallButton("Link 3"); ImGui::TreePop(); } @@ -2314,7 +2707,8 @@ static void DemoWindowWidgetsSelectables() { static bool selected[10] = {}; - if (ImGui::BeginTable("split1", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders)) + if (ImGui::BeginTable( + "split1", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders)) { for (int i = 0; i < 10; i++) { @@ -2326,7 +2720,8 @@ static void DemoWindowWidgetsSelectables() ImGui::EndTable(); } ImGui::Spacing(); - if (ImGui::BeginTable("split2", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders)) + if (ImGui::BeginTable( + "split2", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders)) { for (int i = 0; i < 10; i++) { @@ -2348,13 +2743,14 @@ static void DemoWindowWidgetsSelectables() IMGUI_DEMO_MARKER("Widgets/Selectables/Grid"); if (ImGui::TreeNode("Grid")) { - static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }; + static char selected[4][4] = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}; // Add in a bit of silly fun... const float time = (float)ImGui::GetTime(); const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected... if (winning_state) - ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f))); + ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, + ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f))); for (int y = 0; y < 4; y++) for (int x = 0; x < 4; x++) @@ -2366,10 +2762,22 @@ static void DemoWindowWidgetsSelectables() { // Toggle clicked cell + toggle neighbors selected[y][x] ^= 1; - if (x > 0) { selected[y][x - 1] ^= 1; } - if (x < 3) { selected[y][x + 1] ^= 1; } - if (y > 0) { selected[y - 1][x] ^= 1; } - if (y < 3) { selected[y + 1][x] ^= 1; } + if (x > 0) + { + selected[y][x - 1] ^= 1; + } + if (x < 3) + { + selected[y][x + 1] ^= 1; + } + if (y > 0) + { + selected[y - 1][x] ^= 1; + } + if (y < 3) + { + selected[y + 1][x] ^= 1; + } } ImGui::PopID(); } @@ -2381,11 +2789,10 @@ static void DemoWindowWidgetsSelectables() IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment"); if (ImGui::TreeNode("Alignment")) { - HelpMarker( - "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item " - "basis using PushStyleVar(). You'll probably want to always keep your default situation to " - "left-align otherwise it becomes difficult to layout multiple items on a same line"); - static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true }; + HelpMarker("By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item " + "basis using PushStyleVar(). You'll probably want to always keep your default situation to " + "left-align otherwise it becomes difficult to layout multiple items on a same line"); + static bool selected[3 * 3] = {true, false, true, false, true, false, true, false, true}; for (int y = 0; y < 3; y++) { for (int x = 0; x < 3; x++) @@ -2393,7 +2800,8 @@ static void DemoWindowWidgetsSelectables() ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f); char name[32]; sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y); - if (x > 0) ImGui::SameLine(); + if (x > 0) + ImGui::SameLine(); ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment); ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80)); ImGui::PopStyleVar(); @@ -2412,34 +2820,40 @@ static void DemoWindowWidgetsSelectables() // Also read: https://github.com/ocornut/imgui/wiki/Multi-Select //----------------------------------------------------------------------------- -static const char* ExampleNames[] = -{ - "Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper", - "Bitter Gourd", "Bok Choy", "Broccoli", "Brussels Sprouts", "Burdock Root", "Cabbage", "Calabash", "Capers", "Carrot", "Cassava", - "Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", "Chinese Broccoli", "Corn", "Cucumber" -}; +static const char *ExampleNames[] = {"Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", + "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper", + "Bitter Gourd", "Bok Choy", "Broccoli", "Brussels Sprouts", "Burdock Root", + "Cabbage", "Calabash", "Capers", "Carrot", "Cassava", + "Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", + "Chinese Broccoli", "Corn", "Cucumber"}; // Extra functions to add deletion support to ImGuiSelectionBasicStorage struct ExampleSelectionWithDeletion : ImGuiSelectionBasicStorage { // Find which item should be Focused after deletion. - // Call _before_ item submission. Return an index in the before-deletion item list, your item loop should call SetKeyboardFocusHere() on it. - // The subsequent ApplyDeletionPostLoop() code will use it to apply Selection. + // Call _before_ item submission. Return an index in the before-deletion item list, your item loop should call + // SetKeyboardFocusHere() on it. The subsequent ApplyDeletionPostLoop() code will use it to apply Selection. // - We cannot provide this logic in core Dear ImGui because we don't have access to selection data. - // - We don't actually manipulate the ImVector<> here, only in ApplyDeletionPostLoop(), but using similar API for consistency and flexibility. - // - Important: Deletion only works if the underlying ImGuiID for your items are stable: aka not depend on their index, but on e.g. item id/ptr. - // FIXME-MULTISELECT: Doesn't take account of the possibility focus target will be moved during deletion. Need refocus or scroll offset. - int ApplyDeletionPreLoop(ImGuiMultiSelectIO* ms_io, int items_count) + // - We don't actually manipulate the ImVector<> here, only in ApplyDeletionPostLoop(), but using similar API for + // consistency and flexibility. + // - Important: Deletion only works if the underlying ImGuiID for your items are stable: aka not depend on their + // index, but on e.g. item id/ptr. + // FIXME-MULTISELECT: Doesn't take account of the possibility focus target will be moved during deletion. Need + // refocus or scroll offset. + int ApplyDeletionPreLoop(ImGuiMultiSelectIO *ms_io, int items_count) { if (Size == 0) return -1; // If focused item is not selected... - const int focused_idx = (int)ms_io->NavIdItem; // Index of currently focused item - if (ms_io->NavIdSelected == false) // This is merely a shortcut, == Contains(adapter->IndexToStorage(items, focused_idx)) + const int focused_idx = (int)ms_io->NavIdItem; // Index of currently focused item + if (ms_io->NavIdSelected == + false) // This is merely a shortcut, == Contains(adapter->IndexToStorage(items, focused_idx)) { - ms_io->RangeSrcReset = true; // Request to recover RangeSrc from NavId next frame. Would be ok to reset even when NavIdSelected==true, but it would take an extra frame to recover RangeSrc when deleting a selected item. - return focused_idx; // Request to focus same item after deletion. + ms_io->RangeSrcReset = true; // Request to recover RangeSrc from NavId next frame. Would be ok to reset even + // when NavIdSelected==true, but it would take an extra frame to recover + // RangeSrc when deleting a selected item. + return focused_idx; // Request to focus same item after deletion. } // If focused item is selected: land on first unselected item after focused item. @@ -2457,12 +2871,13 @@ struct ExampleSelectionWithDeletion : ImGuiSelectionBasicStorage // Rewrite item list (delete items) + update selection. // - Call after EndMultiSelect() - // - We cannot provide this logic in core Dear ImGui because we don't have access to your items, nor to selection data. - template - void ApplyDeletionPostLoop(ImGuiMultiSelectIO* ms_io, ImVector& items, int item_curr_idx_to_select) + // - We cannot provide this logic in core Dear ImGui because we don't have access to your items, nor to selection + // data. + template + void ApplyDeletionPostLoop(ImGuiMultiSelectIO *ms_io, ImVector &items, int item_curr_idx_to_select) { - // Rewrite item list (delete items) + convert old selection index (before deletion) to new selection index (after selection). - // If NavId was not part of selection, we will stay on same item. + // Rewrite item list (delete items) + convert old selection index (before deletion) to new selection index + // (after selection). If NavId was not part of selection, we will stay on same item. ImVector new_items; new_items.reserve(items.Size - Size); int item_next_idx_to_select = -1; @@ -2485,9 +2900,9 @@ struct ExampleSelectionWithDeletion : ImGuiSelectionBasicStorage // Example: Implement dual list box storage and interface struct ExampleDualListBox { - ImVector Items[2]; // ID is index into ExampleName[] - ImGuiSelectionBasicStorage Selections[2]; // Store ExampleItemId into selection - bool OptKeepSorted = true; + ImVector Items[2]; // ID is index into ExampleName[] + ImGuiSelectionBasicStorage Selections[2]; // Store ExampleItemId into selection + bool OptKeepSorted = true; void MoveAll(int src, int dst) { @@ -2506,7 +2921,8 @@ struct ExampleDualListBox ImGuiID item_id = Items[src][src_n]; if (!Selections[src].Contains(item_id)) continue; - Items[src].erase(&Items[src][src_n]); // FIXME-OPT: Could be implemented more optimally (rebuild src items and swap) + Items[src].erase( + &Items[src][src_n]); // FIXME-OPT: Could be implemented more optimally (rebuild src items and swap) Items[dst].push_back(item_id); src_n--; } @@ -2515,17 +2931,20 @@ struct ExampleDualListBox Selections[src].Swap(Selections[dst]); Selections[src].Clear(); } - void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, int side) + void ApplySelectionRequests(ImGuiMultiSelectIO *ms_io, int side) { // In this example we store item id in selection (instead of item index) Selections[side].UserData = Items[side].Data; - Selections[side].AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImGuiID* items = (ImGuiID*)self->UserData; return items[idx]; }; + Selections[side].AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage *self, int idx) { + ImGuiID *items = (ImGuiID *)self->UserData; + return items[idx]; + }; Selections[side].ApplyRequests(ms_io); } - static int IMGUI_CDECL CompareItemsByValue(const void* lhs, const void* rhs) + static int IMGUI_CDECL CompareItemsByValue(const void *lhs, const void *rhs) { - const int* a = (const int*)lhs; - const int* b = (const int*)rhs; + const int *a = (const int *)lhs; + const int *b = (const int *)rhs; return (*a - *b); } void SortItems(int n) @@ -2534,12 +2953,12 @@ struct ExampleDualListBox } void Show() { - //if (ImGui::Checkbox("Sorted", &OptKeepSorted) && OptKeepSorted) { SortItems(0); SortItems(1); } + // if (ImGui::Checkbox("Sorted", &OptKeepSorted) && OptKeepSorted) { SortItems(0); SortItems(1); } if (ImGui::BeginTable("split", 3, ImGuiTableFlags_None)) { - ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); // Left side - ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed); // Buttons - ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); // Right side + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); // Left side + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed); // Buttons + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); // Right side ImGui::TableNextRow(); int request_move_selected = -1; @@ -2549,8 +2968,8 @@ struct ExampleDualListBox { // FIXME-MULTISELECT: Dual List Box: Add context menus // FIXME-NAV: Using ImGuiWindowFlags_NavFlattened exhibit many issues. - ImVector& items = Items[side]; - ImGuiSelectionBasicStorage& selection = Selections[side]; + ImVector &items = Items[side]; + ImGuiSelectionBasicStorage &selection = Selections[side]; ImGui::TableSetColumnIndex((side == 0) ? 0 : 2); ImGui::Text("%s (%d)", (side == 0) ? "Available" : "Basket", items.Size); @@ -2563,19 +2982,22 @@ struct ExampleDualListBox if (side == 0) { // Left child is resizable - ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetFrameHeightWithSpacing() * 4), ImVec2(FLT_MAX, FLT_MAX)); - child_visible = ImGui::BeginChild("0", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY); + ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetFrameHeightWithSpacing() * 4), + ImVec2(FLT_MAX, FLT_MAX)); + child_visible = ImGui::BeginChild("0", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), + ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY); child_height_0 = ImGui::GetWindowSize().y; } else { // Right child use same height as left one - child_visible = ImGui::BeginChild("1", ImVec2(-FLT_MIN, child_height_0), ImGuiChildFlags_FrameStyle); + child_visible = + ImGui::BeginChild("1", ImVec2(-FLT_MIN, child_height_0), ImGuiChildFlags_FrameStyle); } if (child_visible) { ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_None; - ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size); + ImGuiMultiSelectIO *ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size); ApplySelectionRequests(ms_io, side); for (int item_n = 0; item_n < items.Size; item_n++) @@ -2583,7 +3005,8 @@ struct ExampleDualListBox ImGuiID item_id = items[item_n]; bool item_is_selected = selection.Contains(item_id); ImGui::SetNextItemSelectionUserData(item_n); - ImGui::Selectable(ExampleNames[item_id], item_is_selected, ImGuiSelectableFlags_AllowDoubleClick); + ImGui::Selectable(ExampleNames[item_id], item_is_selected, + ImGuiSelectableFlags_AllowDoubleClick); if (ImGui::IsItemFocused()) { // FIXME-MULTISELECT: Dual List Box: Transfer focus @@ -2603,8 +3026,9 @@ struct ExampleDualListBox // Buttons columns ImGui::TableSetColumnIndex(1); ImGui::NewLine(); - //ImVec2 button_sz = { ImGui::CalcTextSize(">>").x + ImGui::GetStyle().FramePadding.x * 2.0f, ImGui::GetFrameHeight() + padding.y * 2.0f }; - ImVec2 button_sz = { ImGui::GetFrameHeight(), ImGui::GetFrameHeight() }; + // ImVec2 button_sz = { ImGui::CalcTextSize(">>").x + ImGui::GetStyle().FramePadding.x * 2.0f, + // ImGui::GetFrameHeight() + padding.y * 2.0f }; + ImVec2 button_sz = {ImGui::GetFrameHeight(), ImGui::GetFrameHeight()}; // (Using BeginDisabled()/EndDisabled() works but feels distracting given how it is currently visualized) if (ImGui::Button(">>", button_sz)) @@ -2637,12 +3061,13 @@ struct ExampleDualListBox } }; -static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_data) +static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData *demo_data) { IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select"); if (ImGui::TreeNode("Selection State & Multi-Select")) { - HelpMarker("Selections can be built using Selectable(), TreeNode() or other widgets. Selection state is owned by application code/data."); + HelpMarker("Selections can be built using Selectable(), TreeNode() or other widgets. Selection state is owned " + "by application code/data."); // Without any fancy API: manage single-selection yourself. IMGUI_DEMO_MARKER("Widgets/Selection State/Single-Select"); @@ -2665,7 +3090,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d if (ImGui::TreeNode("Multi-Select (manual/simplified, without BeginMultiSelect)")) { HelpMarker("Hold CTRL and click to select multiple items."); - static bool selection[5] = { false, false, false, false, false }; + static bool selection[5] = {false, false, false, false, false}; for (int n = 0; n < 5; n++) { char buf[32]; @@ -2701,10 +3126,11 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT); // The BeginChild() has no purpose for selection logic, other that offering a scrolling region. - if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY)) + if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), + ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY)) { ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d; - ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT); + ImGuiMultiSelectIO *ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT); selection.ApplyRequests(ms_io); for (int n = 0; n < ITEMS_COUNT; n++) @@ -2735,10 +3161,11 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d const int ITEMS_COUNT = 10000; ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT); - if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY)) + if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), + ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY)) { ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d; - ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT); + ImGuiMultiSelectIO *ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT); selection.ApplyRequests(ms_io); ImGuiListClipper clipper; @@ -2766,8 +3193,10 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d // Demonstrate dynamic item list + deletion support using the BeginMultiSelect/EndMultiSelect API. // In order to support Deletion without any glitches you need to: - // - (1) If items are submitted in their own scrolling area, submit contents size SetNextWindowContentSize() ahead of time to prevent one-frame readjustment of scrolling. - // - (2) Items needs to have persistent ID Stack identifier = ID needs to not depends on their index. PushID(index) = KO. PushID(item_id) = OK. This is in order to focus items reliably after a selection. + // - (1) If items are submitted in their own scrolling area, submit contents size SetNextWindowContentSize() + // ahead of time to prevent one-frame readjustment of scrolling. + // - (2) Items needs to have persistent ID Stack identifier = ID needs to not depends on their index. + // PushID(index) = KO. PushID(item_id) = OK. This is in order to focus items reliably after a selection. // - (3) BeginXXXX process // - (4) Focus process // - (5) EndXXXX process @@ -2775,12 +3204,16 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d if (ImGui::TreeNode("Multi-Select (with deletion)")) { // Storing items data separately from selection data. - // (you may decide to store selection data inside your item (aka intrusive storage) if you don't need multiple views over same items) - // Use a custom selection.Adapter: store item identifier in Selection (instead of index) + // (you may decide to store selection data inside your item (aka intrusive storage) if you don't need + // multiple views over same items) Use a custom selection.Adapter: store item identifier in Selection + // (instead of index) static ImVector items; static ExampleSelectionWithDeletion selection; - selection.UserData = (void*)&items; - selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImVector* p_items = (ImVector*)self->UserData; return (*p_items)[idx]; }; // Index -> ID + selection.UserData = (void *)&items; + selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage *self, int idx) { + ImVector *p_items = (ImVector *)self->UserData; + return (*p_items)[idx]; + }; // Index -> ID ImGui::Text("Added features:"); ImGui::BulletText("Dynamic list with Delete key support."); @@ -2791,21 +3224,36 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d if (items_next_id == 0) for (ImGuiID n = 0; n < 50; n++) items.push_back(items_next_id++); - if (ImGui::SmallButton("Add 20 items")) { for (int n = 0; n < 20; n++) { items.push_back(items_next_id++); } } + if (ImGui::SmallButton("Add 20 items")) + { + for (int n = 0; n < 20; n++) + { + items.push_back(items_next_id++); + } + } ImGui::SameLine(); - if (ImGui::SmallButton("Remove 20 items")) { for (int n = IM_MIN(20, items.Size); n > 0; n--) { selection.SetItemSelected(items.back(), false); items.pop_back(); } } + if (ImGui::SmallButton("Remove 20 items")) + { + for (int n = IM_MIN(20, items.Size); n > 0; n--) + { + selection.SetItemSelected(items.back(), false); + items.pop_back(); + } + } // (1) Extra to support deletion: Submit scrolling range to avoid glitches on deletion const float items_height = ImGui::GetTextLineHeightWithSpacing(); ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height)); - if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY)) + if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), + ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY)) { ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d; - ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size); + ImGuiMultiSelectIO *ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size); selection.ApplyRequests(ms_io); - const bool want_delete = ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0); + const bool want_delete = + ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0); const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1; for (int n = 0; n < items.Size; n++) @@ -2855,7 +3303,8 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d const int ITEMS_COUNT = 10000; ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT); - if (ImGui::BeginTable("##Basket", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter)) + if (ImGui::BeginTable("##Basket", 2, + ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter)) { ImGui::TableSetupColumn("Object"); ImGui::TableSetupColumn("Action"); @@ -2863,7 +3312,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d ImGui::TableHeadersRow(); ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d; - ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT); + ImGuiMultiSelectIO *ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT); selection.ApplyRequests(ms_io); ImGuiListClipper clipper; @@ -2880,7 +3329,8 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]); bool item_is_selected = selection.Contains((ImGuiID)n); ImGui::SetNextItemSelectionUserData(n); - ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap); + ImGui::Selectable(label, item_is_selected, + ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap); ImGui::TableNextColumn(); ImGui::SmallButton("hello"); } @@ -2901,19 +3351,28 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d ImGui::BulletText("Shift+Click to check multiple boxes."); ImGui::BulletText("Shift+Keyboard to copy current value to other boxes."); - // If you have an array of checkboxes, you may want to use NoAutoSelect + NoAutoClear and the ImGuiSelectionExternalStorage helper. + // If you have an array of checkboxes, you may want to use NoAutoSelect + NoAutoClear and the + // ImGuiSelectionExternalStorage helper. static bool items[20] = {}; - static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_NoAutoSelect | ImGuiMultiSelectFlags_NoAutoClear | ImGuiMultiSelectFlags_ClearOnEscape; + static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_NoAutoSelect | + ImGuiMultiSelectFlags_NoAutoClear | + ImGuiMultiSelectFlags_ClearOnEscape; ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoSelect", &flags, ImGuiMultiSelectFlags_NoAutoSelect); ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear); - ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d); // Cannot use ImGuiMultiSelectFlags_BoxSelect1d as checkboxes are varying width. + ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, + ImGuiMultiSelectFlags_BoxSelect2d); // Cannot use ImGuiMultiSelectFlags_BoxSelect1d as + // checkboxes are varying width. - if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY)) + if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), + ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY)) { - ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, -1, IM_ARRAYSIZE(items)); + ImGuiMultiSelectIO *ms_io = ImGui::BeginMultiSelect(flags, -1, IM_ARRAYSIZE(items)); ImGuiSelectionExternalStorage storage_wrapper; - storage_wrapper.UserData = (void*)items; - storage_wrapper.AdapterSetItemSelected = [](ImGuiSelectionExternalStorage* self, int n, bool selected) { bool* array = (bool*)self->UserData; array[n] = selected; }; + storage_wrapper.UserData = (void *)items; + storage_wrapper.AdapterSetItemSelected = [](ImGuiSelectionExternalStorage *self, int n, bool selected) { + bool *array = (bool *)self->UserData; + array[n] = selected; + }; storage_wrapper.ApplyRequests(ms_io); for (int n = 0; n < 20; n++) { @@ -2940,19 +3399,24 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d static ImGuiSelectionBasicStorage selections_data[SCOPES_COUNT]; // Use ImGuiMultiSelectFlags_ScopeRect to not affect other selections in same window. - static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ScopeRect | ImGuiMultiSelectFlags_ClearOnEscape;// | ImGuiMultiSelectFlags_ClearOnClickVoid; - if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow)) + static ImGuiMultiSelectFlags flags = + ImGuiMultiSelectFlags_ScopeRect | + ImGuiMultiSelectFlags_ClearOnEscape; // | ImGuiMultiSelectFlags_ClearOnClickVoid; + if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && + (flags & ImGuiMultiSelectFlags_ScopeWindow)) flags &= ~ImGuiMultiSelectFlags_ScopeRect; - if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect)) + if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && + (flags & ImGuiMultiSelectFlags_ScopeRect)) flags &= ~ImGuiMultiSelectFlags_ScopeWindow; - ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid); + ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, + ImGuiMultiSelectFlags_ClearOnClickVoid); ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect1d", &flags, ImGuiMultiSelectFlags_BoxSelect1d); for (int selection_scope_n = 0; selection_scope_n < SCOPES_COUNT; selection_scope_n++) { ImGui::PushID(selection_scope_n); - ImGuiSelectionBasicStorage* selection = &selections_data[selection_scope_n]; - ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection->Size, ITEMS_COUNT); + ImGuiSelectionBasicStorage *selection = &selections_data[selection_scope_n]; + ImGuiMultiSelectIO *ms_io = ImGui::BeginMultiSelect(flags, selection->Size, ITEMS_COUNT); selection->ApplyRequests(ms_io); ImGui::SeparatorText("Selection scope"); @@ -2991,22 +3455,25 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d // This is implemented by our TreeGetNextNodeInVisibleOrder() user-space helper. // - Important: In a real codebase aiming to implement full-featured selectable tree with custom filtering, you // are more likely to build an array mapping sequential indices to visible tree nodes, since your - // filtering/search + clipping process will benefit from it. Having this will make this interpolation much easier. + // filtering/search + clipping process will benefit from it. Having this will make this interpolation much + // easier. // - Consider this a prototype: we are working toward simplifying some of it. IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (trees)"); if (ImGui::TreeNode("Multi-Select (trees)")) { - HelpMarker( - "This is rather advanced and experimental. If you are getting started with multi-select, " - "please don't start by looking at how to use it for a tree!\n\n" - "Future versions will try to simplify and formalize some of this."); + HelpMarker("This is rather advanced and experimental. If you are getting started with multi-select, " + "please don't start by looking at how to use it for a tree!\n\n" + "Future versions will try to simplify and formalize some of this."); struct ExampleTreeFuncs { - static void DrawNode(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection) + static void DrawNode(ExampleTreeNode *node, ImGuiSelectionBasicStorage *selection) { - ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; - tree_node_flags |= ImGuiTreeNodeFlags_NavLeftJumpsToParent; // Enable pressing left to jump to parent + ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | + ImGuiTreeNodeFlags_OpenOnArrow | + ImGuiTreeNodeFlags_OpenOnDoubleClick; + tree_node_flags |= + ImGuiTreeNodeFlags_NavLeftJumpsToParent; // Enable pressing left to jump to parent if (node->Childs.Size == 0) tree_node_flags |= ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_Leaf; if (selection->Contains((ImGuiID)node->UID)) @@ -3018,7 +3485,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d ImGui::SetNextItemStorageID((ImGuiID)node->UID); if (ImGui::TreeNodeEx(node->Name, tree_node_flags)) { - for (ExampleTreeNode* child : node->Childs) + for (ExampleTreeNode *child : node->Childs) DrawNode(child, selection); ImGui::TreePop(); } @@ -3028,26 +3495,28 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d } } - static bool TreeNodeGetOpen(ExampleTreeNode* node) + static bool TreeNodeGetOpen(ExampleTreeNode *node) { return ImGui::GetStateStorage()->GetBool((ImGuiID)node->UID); } - static void TreeNodeSetOpen(ExampleTreeNode* node, bool open) + static void TreeNodeSetOpen(ExampleTreeNode *node, bool open) { ImGui::GetStateStorage()->SetBool((ImGuiID)node->UID, open); } - // When closing a node: 1) close and unselect all child nodes, 2) select parent if any child was selected. + // When closing a node: 1) close and unselect all child nodes, 2) select parent if any child was + // selected. // FIXME: This is currently handled by user logic but I'm hoping to eventually provide tree node // features to do this automatically, e.g. a ImGuiTreeNodeFlags_AutoCloseChildNodes etc. - static int TreeCloseAndUnselectChildNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, int depth = 0) + static int TreeCloseAndUnselectChildNodes(ExampleTreeNode *node, ImGuiSelectionBasicStorage *selection, + int depth = 0) { // Recursive close (the test for depth == 0 is because we call this on a node that was just closed!) int unselected_count = selection->Contains((ImGuiID)node->UID) ? 1 : 0; if (depth == 0 || TreeNodeGetOpen(node)) { - for (ExampleTreeNode* child : node->Childs) + for (ExampleTreeNode *child : node->Childs) unselected_count += TreeCloseAndUnselectChildNodes(child, selection, depth + 1); TreeNodeSetOpen(node, false); } @@ -3058,9 +3527,10 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d } // Apply multi-selection requests - static void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, ExampleTreeNode* tree, ImGuiSelectionBasicStorage* selection) + static void ApplySelectionRequests(ImGuiMultiSelectIO *ms_io, ExampleTreeNode *tree, + ImGuiSelectionBasicStorage *selection) { - for (ImGuiSelectionRequest& req : ms_io->Requests) + for (ImGuiSelectionRequest &req : ms_io->Requests) { if (req.Type == ImGuiSelectionRequestType_SetAll) { @@ -3071,32 +3541,38 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d } else if (req.Type == ImGuiSelectionRequestType_SetRange) { - ExampleTreeNode* first_node = (ExampleTreeNode*)(intptr_t)req.RangeFirstItem; - ExampleTreeNode* last_node = (ExampleTreeNode*)(intptr_t)req.RangeLastItem; - for (ExampleTreeNode* node = first_node; node != NULL; node = TreeGetNextNodeInVisibleOrder(node, last_node)) + ExampleTreeNode *first_node = (ExampleTreeNode *)(intptr_t)req.RangeFirstItem; + ExampleTreeNode *last_node = (ExampleTreeNode *)(intptr_t)req.RangeLastItem; + for (ExampleTreeNode *node = first_node; node != NULL; + node = TreeGetNextNodeInVisibleOrder(node, last_node)) selection->SetItemSelected((ImGuiID)node->UID, req.Selected); } } } - static void TreeSetAllInOpenNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, bool selected) + static void TreeSetAllInOpenNodes(ExampleTreeNode *node, ImGuiSelectionBasicStorage *selection, + bool selected) { if (node->Parent != NULL) // Root node isn't visible nor selectable in our scheme selection->SetItemSelected((ImGuiID)node->UID, selected); if (node->Parent == NULL || TreeNodeGetOpen(node)) - for (ExampleTreeNode* child : node->Childs) + for (ExampleTreeNode *child : node->Childs) TreeSetAllInOpenNodes(child, selection, selected); } // Interpolate in *user-visible order* AND only *over opened nodes*. - // If you have a sequential mapping tables (e.g. generated after a filter/search pass) this would be simpler. - // Here the tricks are that: - // - we store/maintain ExampleTreeNode::IndexInParent which allows implementing a linear iterator easily, without searches, without recursion. - // this could be replaced by a search in parent, aka 'int index_in_parent = curr_node->Parent->Childs.find_index(curr_node)' - // which would only be called when crossing from child to a parent, aka not too much. - // - we call SetNextItemStorageID() before our TreeNode() calls with an ID which doesn't relate to UI stack, + // If you have a sequential mapping tables (e.g. generated after a filter/search pass) this would be + // simpler. Here the tricks are that: + // - we store/maintain ExampleTreeNode::IndexInParent which allows implementing a linear iterator + // easily, without searches, without recursion. + // this could be replaced by a search in parent, aka 'int index_in_parent = + // curr_node->Parent->Childs.find_index(curr_node)' which would only be called when crossing from + // child to a parent, aka not too much. + // - we call SetNextItemStorageID() before our TreeNode() calls with an ID which doesn't relate to UI + // stack, // making it easier to call TreeNodeGetOpen()/TreeNodeSetOpen() from any location. - static ExampleTreeNode* TreeGetNextNodeInVisibleOrder(ExampleTreeNode* curr_node, ExampleTreeNode* last_node) + static ExampleTreeNode *TreeGetNextNodeInVisibleOrder(ExampleTreeNode *curr_node, + ExampleTreeNode *last_node) { // Reached last node if (curr_node == last_node) @@ -3123,13 +3599,15 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d demo_data->DemoTree = ExampleTree_CreateDemoTree(); // Create tree once ImGui::Text("Selection size: %d", selection.Size); - if (ImGui::BeginChild("##Tree", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY)) + if (ImGui::BeginChild("##Tree", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), + ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY)) { - ExampleTreeNode* tree = demo_data->DemoTree; - ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect2d; - ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, selection.Size, -1); + ExampleTreeNode *tree = demo_data->DemoTree; + ImGuiMultiSelectFlags ms_flags = + ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect2d; + ImGuiMultiSelectIO *ms_io = ImGui::BeginMultiSelect(ms_flags, selection.Size, -1); ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection); - for (ExampleTreeNode* node : tree->Childs) + for (ExampleTreeNode *node : tree->Childs) ExampleTreeFuncs::DrawNode(node, &selection); ms_io = ImGui::EndMultiSelect(); ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection); @@ -3143,29 +3621,45 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d // - Showcase clipping. // - Showcase deletion. // - Showcase basic drag and drop. - // - Showcase TreeNode variant (note that tree node don't expand in the demo: supporting expanding tree nodes + clipping a separate thing). + // - Showcase TreeNode variant (note that tree node don't expand in the demo: supporting expanding tree nodes + + // clipping a separate thing). // - Showcase using inside a table. IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (advanced)"); - //ImGui::SetNextItemOpen(true, ImGuiCond_Once); + // ImGui::SetNextItemOpen(true, ImGuiCond_Once); if (ImGui::TreeNode("Multi-Select (advanced)")) { // Options - enum WidgetType { WidgetType_Selectable, WidgetType_TreeNode }; + enum WidgetType + { + WidgetType_Selectable, + WidgetType_TreeNode + }; static bool use_clipper = true; static bool use_deletion = true; static bool use_drag_drop = true; static bool show_in_table = false; static bool show_color_button = true; - static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d; + static ImGuiMultiSelectFlags flags = + ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d; static WidgetType widget_type = WidgetType_Selectable; if (ImGui::TreeNode("Options")) { - if (ImGui::RadioButton("Selectables", widget_type == WidgetType_Selectable)) { widget_type = WidgetType_Selectable; } + if (ImGui::RadioButton("Selectables", widget_type == WidgetType_Selectable)) + { + widget_type = WidgetType_Selectable; + } ImGui::SameLine(); - if (ImGui::RadioButton("Tree nodes", widget_type == WidgetType_TreeNode)) { widget_type = WidgetType_TreeNode; } + if (ImGui::RadioButton("Tree nodes", widget_type == WidgetType_TreeNode)) + { + widget_type = WidgetType_TreeNode; + } ImGui::SameLine(); - HelpMarker("TreeNode() is technically supported but... using this correctly is more complicated (you need some sort of linear/random access to your tree, which is suited to advanced trees setups already implementing filters and clipper. We will work toward simplifying and demoing this.\n\nFor now the tree demo is actually a little bit meaningless because it is an empty tree with only root nodes."); + HelpMarker("TreeNode() is technically supported but... using this correctly is more complicated (you " + "need some sort of linear/random access to your tree, which is suited to advanced trees " + "setups already implementing filters and clipper. We will work toward simplifying and " + "demoing this.\n\nFor now the tree demo is actually a little bit meaningless because it is " + "an empty tree with only root nodes."); ImGui::Checkbox("Enable clipper", &use_clipper); ImGui::Checkbox("Enable deletion", &use_deletion); ImGui::Checkbox("Enable drag & drop", &use_drag_drop); @@ -3173,24 +3667,37 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d ImGui::Checkbox("Show color button", &show_color_button); ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SingleSelect", &flags, ImGuiMultiSelectFlags_SingleSelect); ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoSelectAll", &flags, ImGuiMultiSelectFlags_NoSelectAll); - ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoRangeSelect", &flags, ImGuiMultiSelectFlags_NoRangeSelect); + ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoRangeSelect", &flags, + ImGuiMultiSelectFlags_NoRangeSelect); ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoSelect", &flags, ImGuiMultiSelectFlags_NoAutoSelect); ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear); - ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClearOnReselect", &flags, ImGuiMultiSelectFlags_NoAutoClearOnReselect); + ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClearOnReselect", &flags, + ImGuiMultiSelectFlags_NoAutoClearOnReselect); ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect1d", &flags, ImGuiMultiSelectFlags_BoxSelect1d); ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d); - ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelectNoScroll", &flags, ImGuiMultiSelectFlags_BoxSelectNoScroll); - ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnEscape", &flags, ImGuiMultiSelectFlags_ClearOnEscape); - ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid); - if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow)) + ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelectNoScroll", &flags, + ImGuiMultiSelectFlags_BoxSelectNoScroll); + ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnEscape", &flags, + ImGuiMultiSelectFlags_ClearOnEscape); + ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, + ImGuiMultiSelectFlags_ClearOnClickVoid); + if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, + ImGuiMultiSelectFlags_ScopeWindow) && + (flags & ImGuiMultiSelectFlags_ScopeWindow)) flags &= ~ImGuiMultiSelectFlags_ScopeRect; - if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect)) + if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && + (flags & ImGuiMultiSelectFlags_ScopeRect)) flags &= ~ImGuiMultiSelectFlags_ScopeWindow; - if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClick", &flags, ImGuiMultiSelectFlags_SelectOnClick) && (flags & ImGuiMultiSelectFlags_SelectOnClick)) + if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClick", &flags, + ImGuiMultiSelectFlags_SelectOnClick) && + (flags & ImGuiMultiSelectFlags_SelectOnClick)) flags &= ~ImGuiMultiSelectFlags_SelectOnClickRelease; - if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClickRelease", &flags, ImGuiMultiSelectFlags_SelectOnClickRelease) && (flags & ImGuiMultiSelectFlags_SelectOnClickRelease)) + if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClickRelease", &flags, + ImGuiMultiSelectFlags_SelectOnClickRelease) && + (flags & ImGuiMultiSelectFlags_SelectOnClickRelease)) flags &= ~ImGuiMultiSelectFlags_SelectOnClick; - ImGui::SameLine(); HelpMarker("Allow dragging an unselected item without altering selection."); + ImGui::SameLine(); + HelpMarker("Allow dragging an unselected item without altering selection."); ImGui::TreePop(); } @@ -3198,24 +3705,34 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection static ImVector items; static int items_next_id = 0; - if (items_next_id == 0) { for (int n = 0; n < 1000; n++) { items.push_back(items_next_id++); } } + if (items_next_id == 0) + { + for (int n = 0; n < 1000; n++) + { + items.push_back(items_next_id++); + } + } static ExampleSelectionWithDeletion selection; static bool request_deletion_from_menu = false; // Queue deletion triggered from context menu ImGui::Text("Selection size: %d/%d", selection.Size, items.Size); - const float items_height = (widget_type == WidgetType_TreeNode) ? ImGui::GetTextLineHeight() : ImGui::GetTextLineHeightWithSpacing(); + const float items_height = (widget_type == WidgetType_TreeNode) ? ImGui::GetTextLineHeight() + : ImGui::GetTextLineHeightWithSpacing(); ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height)); - if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY)) + if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), + ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY)) { ImVec2 color_button_sz(ImGui::GetFontSize(), ImGui::GetFontSize()); if (widget_type == WidgetType_TreeNode) ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, 0.0f); - ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size); + ImGuiMultiSelectIO *ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size); selection.ApplyRequests(ms_io); - const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0)) || request_deletion_from_menu; + const bool want_delete = + (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0)) || + request_deletion_from_menu; const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1; request_deletion_from_menu = false; @@ -3223,10 +3740,12 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d { if (widget_type == WidgetType_TreeNode) ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0.0f, 0.0f)); - ImGui::BeginTable("##Split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_NoPadOuterX); + ImGui::BeginTable("##Split", 2, + ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | + ImGuiTableFlags_NoPadOuterX); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.70f); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.30f); - //ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacingY, 0.0f); + // ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacingY, 0.0f); } ImGuiListClipper clipper; @@ -3249,7 +3768,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d ImGui::TableNextColumn(); const int item_id = items[n]; - const char* item_category = ExampleNames[item_id % IM_ARRAYSIZE(ExampleNames)]; + const char *item_category = ExampleNames[item_id % IM_ARRAYSIZE(ExampleNames)]; char label[64]; sprintf(label, "Object %05d: %s", item_id, item_category); @@ -3264,7 +3783,8 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d if (show_color_button) { ImU32 dummy_col = (ImU32)((unsigned int)n * 0xC250B74B) | IM_COL32_A_MASK; - ImGui::ColorButton("##", ImColor(dummy_col), ImGuiColorEditFlags_NoTooltip, color_button_sz); + ImGui::ColorButton("##", ImColor(dummy_col), ImGuiColorEditFlags_NoTooltip, + color_button_sz); ImGui::SameLine(); } @@ -3278,7 +3798,9 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d } else if (widget_type == WidgetType_TreeNode) { - ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; + ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | + ImGuiTreeNodeFlags_OpenOnArrow | + ImGuiTreeNodeFlags_OpenOnDoubleClick; if (item_is_selected) tree_node_flags |= ImGuiTreeNodeFlags_Selected; item_is_open = ImGui::TreeNodeEx(label, tree_node_flags); @@ -3296,22 +3818,24 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d if (ImGui::GetDragDropPayload() == NULL) { ImVector payload_items; - void* it = NULL; + void *it = NULL; ImGuiID id = 0; if (!item_is_selected) payload_items.push_back(item_id); else while (selection.GetNextSelectedItem(&it, &id)) payload_items.push_back((int)id); - ImGui::SetDragDropPayload("MULTISELECT_DEMO_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes()); + ImGui::SetDragDropPayload("MULTISELECT_DEMO_ITEMS", payload_items.Data, + (size_t)payload_items.size_in_bytes()); } // Display payload content in tooltip - const ImGuiPayload* payload = ImGui::GetDragDropPayload(); - const int* payload_items = (int*)payload->Data; + const ImGuiPayload *payload = ImGui::GetDragDropPayload(); + const int *payload_items = (int *)payload->Data; const int payload_count = (int)payload->DataSize / (int)sizeof(int); if (payload_count == 1) - ImGui::Text("Object %05d: %s", payload_items[0], ExampleNames[payload_items[0] % IM_ARRAYSIZE(ExampleNames)]); + ImGui::Text("Object %05d: %s", payload_items[0], + ExampleNames[payload_items[0] % IM_ARRAYSIZE(ExampleNames)]); else ImGui::Text("Dragging %d objects", payload_count); @@ -3339,7 +3863,8 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d ImGui::TableNextColumn(); ImGui::SetNextItemWidth(-FLT_MIN); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); - ImGui::InputText("###NoLabel", (char*)(void*)item_category, strlen(item_category), ImGuiInputTextFlags_ReadOnly); + ImGui::InputText("###NoLabel", (char *)(void *)item_category, strlen(item_category), + ImGuiInputTextFlags_ReadOnly); ImGui::PopStyleVar(); } @@ -3414,22 +3939,28 @@ static void DemoWindowWidgetsTabs() // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", &tab_bar_flags, ImGuiTabBarFlags_Reorderable); - ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); - ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); - ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); - ImGui::CheckboxFlags("ImGuiTabBarFlags_DrawSelectedOverline", &tab_bar_flags, ImGuiTabBarFlags_DrawSelectedOverline); + ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, + ImGuiTabBarFlags_AutoSelectNewTabs); + ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, + ImGuiTabBarFlags_TabListPopupButton); + ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, + ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); + ImGui::CheckboxFlags("ImGuiTabBarFlags_DrawSelectedOverline", &tab_bar_flags, + ImGuiTabBarFlags_DrawSelectedOverline); if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; - if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, + ImGuiTabBarFlags_FittingPolicyResizeDown)) tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); - if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, + ImGuiTabBarFlags_FittingPolicyScroll)) tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); // Tab Bar ImGui::AlignTextToFramePadding(); ImGui::Text("Opened:"); - const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" }; - static bool opened[4] = { true, true, true, true }; // Persistent user state + const char *names[4] = {"Artichoke", "Beetroot", "Celery", "Daikon"}; + static bool opened[4] = {true, true, true, true}; // Persistent user state for (int n = 0; n < IM_ARRAYSIZE(opened); n++) { ImGui::SameLine(); @@ -3464,19 +3995,23 @@ static void DemoWindowWidgetsTabs() active_tabs.push_back(next_tab_id++); // TabItemButton() and Leading/Trailing flags are distinct features which we will demo together. - // (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags... - // but they tend to make more sense together) + // (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without + // Leading/Trailing flags... but they tend to make more sense together) static bool show_leading_button = true; static bool show_trailing_button = true; ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button); ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button); // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs - static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown; - ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); - if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) + static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | + ImGuiTabBarFlags_FittingPolicyResizeDown; + ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, + ImGuiTabBarFlags_TabListPopupButton); + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, + ImGuiTabBarFlags_FittingPolicyResizeDown)) tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); - if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, + ImGuiTabBarFlags_FittingPolicyScroll)) tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) @@ -3493,13 +4028,14 @@ static void DemoWindowWidgetsTabs() // Demo Trailing Tabs: click the "+" button to add a new tab. // (In your app you may want to use a font icon instead of the "+") - // We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will always appear at the end. + // We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will + // always appear at the end. if (show_trailing_button) if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip)) active_tabs.push_back(next_tab_id++); // Add new tab // Submit our regular tabs - for (int n = 0; n < active_tabs.Size; ) + for (int n = 0; n < active_tabs.Size;) { bool open = true; char name[16]; @@ -3541,7 +4077,8 @@ static void DemoWindowWidgetsText() ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink"); ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow"); ImGui::TextDisabled("Disabled"); - ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle."); + ImGui::SameLine(); + HelpMarker("The TextDisabled color is stored in ImGuiStyle."); ImGui::TreePop(); } @@ -3557,7 +4094,7 @@ static void DemoWindowWidgetsText() static float wrap_width = 200.0f; ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f"); - ImDrawList* draw_list = ImGui::GetWindowDrawList(); + ImDrawList *draw_list = ImGui::GetWindowDrawList(); for (int n = 0; n < 2; n++) { ImGui::Text("Test paragraph %d:", n); @@ -3566,7 +4103,9 @@ static void DemoWindowWidgetsText() ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()); ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); if (n == 0) - ImGui::Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width); + ImGui::Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 " + "character word. The quick brown fox jumps over the lazy dog.", + wrap_width); else ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh"); @@ -3599,7 +4138,7 @@ static void DemoWindowWidgetsText() ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)"); static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; - //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis + // static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf)); ImGui::TreePop(); } @@ -3621,12 +4160,13 @@ static void DemoWindowWidgetsTextFilter() HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings."); static ImGuiTextFilter filter; ImGui::Text("Filter usage:\n" - " \"\" display all lines\n" - " \"xxx\" display lines containing \"xxx\"\n" - " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" - " \"-xxx\" hide lines containing \"xxx\""); + " \"\" display all lines\n" + " \"xxx\" display lines containing \"xxx\"\n" + " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" + " \"-xxx\" hide lines containing \"xxx\""); filter.Draw(); - const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; + const char *lines[] = {"aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", + "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world"}; for (int i = 0; i < IM_ARRAYSIZE(lines); i++) if (filter.PassFilter(lines[i])) ImGui::BulletText("%s", lines[i]); @@ -3650,25 +4190,31 @@ static void DemoWindowWidgetsTextInput() { // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings. - static char text[1024 * 16] = - "/*\n" - " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" - " the hexadecimal encoding of one offending instruction,\n" - " more formally, the invalid operand with locked CMPXCHG8B\n" - " instruction bug, is a design flaw in the majority of\n" - " Intel Pentium, Pentium MMX, and Pentium OverDrive\n" - " processors (all in the P5 microarchitecture).\n" - "*/\n\n" - "label:\n" - "\tlock cmpxchg8b eax\n"; + static char text[1024 * 16] = "/*\n" + " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" + " the hexadecimal encoding of one offending instruction,\n" + " more formally, the invalid operand with locked CMPXCHG8B\n" + " instruction bug, is a design flaw in the majority of\n" + " Intel Pentium, Pentium MMX, and Pentium OverDrive\n" + " processors (all in the P5 microarchitecture).\n" + "*/\n\n" + "label:\n" + "\tlock cmpxchg8b eax\n"; static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput; - HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in imgui_demo.cpp because we don't want to include in here)"); + HelpMarker( + "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() " + "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in " + "imgui_demo.cpp because we don't want to include in here)"); ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly); ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", &flags, ImGuiInputTextFlags_AllowTabInput); - ImGui::SameLine(); HelpMarker("When _AllowTabInput is set, passing through the widget with Tabbing doesn't automatically activate it, in order to also cycling through subsequent widgets."); - ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", &flags, ImGuiInputTextFlags_CtrlEnterForNewLine); - ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags); + ImGui::SameLine(); + HelpMarker("When _AllowTabInput is set, passing through the widget with Tabbing doesn't automatically " + "activate it, in order to also cycling through subsequent widgets."); + ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", &flags, + ImGuiInputTextFlags_CtrlEnterForNewLine); + ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), + ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags); ImGui::TreePop(); } @@ -3677,16 +4223,23 @@ static void DemoWindowWidgetsTextInput() { struct TextFilters { - // Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter callback) - static int FilterCasingSwap(ImGuiInputTextCallbackData* data) + // Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter + // callback) + static int FilterCasingSwap(ImGuiInputTextCallbackData *data) { - if (data->EventChar >= 'a' && data->EventChar <= 'z') { data->EventChar -= 'a' - 'A'; } // Lowercase becomes uppercase - else if (data->EventChar >= 'A' && data->EventChar <= 'Z') { data->EventChar += 'a' - 'A'; } // Uppercase becomes lowercase + if (data->EventChar >= 'a' && data->EventChar <= 'z') + { + data->EventChar -= 'a' - 'A'; + } // Lowercase becomes uppercase + else if (data->EventChar >= 'A' && data->EventChar <= 'Z') + { + data->EventChar += 'a' - 'A'; + } // Uppercase becomes lowercase return 0; } // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out) - static int FilterImGuiLetters(ImGuiInputTextCallbackData* data) + static int FilterImGuiLetters(ImGuiInputTextCallbackData *data) { if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) return 0; @@ -3694,13 +4247,23 @@ static void DemoWindowWidgetsTextInput() } }; - static char buf1[32] = ""; ImGui::InputText("default", buf1, IM_ARRAYSIZE(buf1)); - static char buf2[32] = ""; ImGui::InputText("decimal", buf2, IM_ARRAYSIZE(buf2), ImGuiInputTextFlags_CharsDecimal); - static char buf3[32] = ""; ImGui::InputText("hexadecimal", buf3, IM_ARRAYSIZE(buf3), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); - static char buf4[32] = ""; ImGui::InputText("uppercase", buf4, IM_ARRAYSIZE(buf4), ImGuiInputTextFlags_CharsUppercase); - static char buf5[32] = ""; ImGui::InputText("no blank", buf5, IM_ARRAYSIZE(buf5), ImGuiInputTextFlags_CharsNoBlank); - static char buf6[32] = ""; ImGui::InputText("casing swap", buf6, IM_ARRAYSIZE(buf6), ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterCasingSwap); // Use CharFilter callback to replace characters. - static char buf7[32] = ""; ImGui::InputText("\"imgui\"", buf7, IM_ARRAYSIZE(buf7), ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); // Use CharFilter callback to disable some characters. + static char buf1[32] = ""; + ImGui::InputText("default", buf1, IM_ARRAYSIZE(buf1)); + static char buf2[32] = ""; + ImGui::InputText("decimal", buf2, IM_ARRAYSIZE(buf2), ImGuiInputTextFlags_CharsDecimal); + static char buf3[32] = ""; + ImGui::InputText("hexadecimal", buf3, IM_ARRAYSIZE(buf3), + ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); + static char buf4[32] = ""; + ImGui::InputText("uppercase", buf4, IM_ARRAYSIZE(buf4), ImGuiInputTextFlags_CharsUppercase); + static char buf5[32] = ""; + ImGui::InputText("no blank", buf5, IM_ARRAYSIZE(buf5), ImGuiInputTextFlags_CharsNoBlank); + static char buf6[32] = ""; + ImGui::InputText("casing swap", buf6, IM_ARRAYSIZE(buf6), ImGuiInputTextFlags_CallbackCharFilter, + TextFilters::FilterCasingSwap); // Use CharFilter callback to replace characters. + static char buf7[32] = ""; + ImGui::InputText("\"imgui\"", buf7, IM_ARRAYSIZE(buf7), ImGuiInputTextFlags_CallbackCharFilter, + TextFilters::FilterImGuiLetters); // Use CharFilter callback to disable some characters. ImGui::TreePop(); } @@ -3709,8 +4272,10 @@ static void DemoWindowWidgetsTextInput() { static char password[64] = "password123"; ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); - ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); - ImGui::InputTextWithHint("password (w/ hint)", "", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); + ImGui::SameLine(); + HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); + ImGui::InputTextWithHint("password (w/ hint)", "", password, IM_ARRAYSIZE(password), + ImGuiInputTextFlags_Password); ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password)); ImGui::TreePop(); } @@ -3720,7 +4285,7 @@ static void DemoWindowWidgetsTextInput() { struct Funcs { - static int MyCallback(ImGuiInputTextCallbackData* data) + static int MyCallback(ImGuiInputTextCallbackData *data) { if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion) { @@ -3745,34 +4310,39 @@ static void DemoWindowWidgetsTextInput() { // Toggle casing of first character char c = data->Buf[0]; - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32; + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) + data->Buf[0] ^= 32; data->BufDirty = true; // Increment a counter - int* p_int = (int*)data->UserData; + int *p_int = (int *)data->UserData; *p_int = *p_int + 1; } return 0; } }; static char buf1[64]; - ImGui::InputText("Completion", buf1, IM_ARRAYSIZE(buf1), ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback); - ImGui::SameLine(); HelpMarker( - "Here we append \"..\" each time Tab is pressed. " - "See 'Examples>Console' for a more meaningful demonstration of using this callback."); + ImGui::InputText("Completion", buf1, IM_ARRAYSIZE(buf1), ImGuiInputTextFlags_CallbackCompletion, + Funcs::MyCallback); + ImGui::SameLine(); + HelpMarker("Here we append \"..\" each time Tab is pressed. " + "See 'Examples>Console' for a more meaningful demonstration of using this callback."); static char buf2[64]; - ImGui::InputText("History", buf2, IM_ARRAYSIZE(buf2), ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback); - ImGui::SameLine(); HelpMarker( - "Here we replace and select text each time Up/Down are pressed. " - "See 'Examples>Console' for a more meaningful demonstration of using this callback."); + ImGui::InputText("History", buf2, IM_ARRAYSIZE(buf2), ImGuiInputTextFlags_CallbackHistory, + Funcs::MyCallback); + ImGui::SameLine(); + HelpMarker("Here we replace and select text each time Up/Down are pressed. " + "See 'Examples>Console' for a more meaningful demonstration of using this callback."); static char buf3[64]; static int edit_count = 0; - ImGui::InputText("Edit", buf3, IM_ARRAYSIZE(buf3), ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count); - ImGui::SameLine(); HelpMarker( - "Here we toggle the casing of the first character on every edit + count edits."); - ImGui::SameLine(); ImGui::Text("(%d)", edit_count); + ImGui::InputText("Edit", buf3, IM_ARRAYSIZE(buf3), ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, + (void *)&edit_count); + ImGui::SameLine(); + HelpMarker("Here we toggle the casing of the first character on every edit + count edits."); + ImGui::SameLine(); + ImGui::Text("(%d)", edit_count); ImGui::TreePop(); } @@ -3783,18 +4353,18 @@ static void DemoWindowWidgetsTextInput() // To wire InputText() with std::string or any other custom string type, // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string. - HelpMarker( - "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n" - "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string."); + HelpMarker("Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n" + "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string."); struct Funcs { - static int MyResizeCallback(ImGuiInputTextCallbackData* data) + static int MyResizeCallback(ImGuiInputTextCallbackData *data) { if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) { - ImVector* my_str = (ImVector*)data->UserData; + ImVector *my_str = (ImVector *)data->UserData; IM_ASSERT(my_str->begin() == data->Buf); - my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1 + my_str->resize( + data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1 data->Buf = my_str->begin(); } return 0; @@ -3802,10 +4372,13 @@ static void DemoWindowWidgetsTextInput() // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace. // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)' - static bool MyInputTextMultiline(const char* label, ImVector* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0) + static bool MyInputTextMultiline(const char *label, ImVector *my_str, + const ImVec2 &size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0) { IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); - return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str); + return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, + flags | ImGuiInputTextFlags_CallbackResize, + Funcs::MyResizeCallback, (void *)my_str); } }; @@ -3816,7 +4389,7 @@ static void DemoWindowWidgetsTextInput() if (my_str.empty()) my_str.push_back(0); Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16)); - ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity()); + ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void *)my_str.begin(), my_str.size(), my_str.capacity()); ImGui::TreePop(); } @@ -3844,7 +4417,6 @@ static void DemoWindowWidgetsTextInput() ImGui::TreePop(); } - } //----------------------------------------------------------------------------- @@ -3866,9 +4438,8 @@ static void DemoWindowWidgetsTooltips() // - Full-form (text only): if (IsItemHovered(...)) { SetTooltip("Hello"); } // - Full-form (any contents): if (IsItemHovered(...) && BeginTooltip()) { Text("Hello"); EndTooltip(); } - HelpMarker( - "Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\n" - "We provide a helper SetItemTooltip() function to perform the two with standards flags."); + HelpMarker("Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\n" + "We provide a helper SetItemTooltip() function to perform the two with standards flags."); ImVec2 sz = ImVec2(-FLT_MIN, 0.0f); @@ -3879,7 +4450,7 @@ static void DemoWindowWidgetsTooltips() if (ImGui::BeginItemTooltip()) { ImGui::Text("I am a fancy tooltip"); - static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; + static float arr[] = {0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f}; ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr)); ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime())); ImGui::EndTooltip(); @@ -3905,15 +4476,15 @@ static void DemoWindowWidgetsTooltips() ImGui::SeparatorText("Custom"); - HelpMarker( - "Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize " - "tooltip activation details across your application. You may however decide to use custom " - "flags for a specific tooltip instance."); + HelpMarker("Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize " + "tooltip activation details across your application. You may however decide to use custom " + "flags for a specific tooltip instance."); // The following examples are passed for documentation purpose but may not be useful to most users. // Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from - // 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used. - // With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary. + // 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or + // keyboard/gamepad is being used. With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to + // ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary. ImGui::Button("Manual", sz); if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip)) ImGui::SetTooltip("I am a manually emitted tooltip."); @@ -3934,8 +4505,8 @@ static void DemoWindowWidgetsTooltips() if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) ImGui::SetTooltip("I am a tooltip requiring mouse to be stationary before activating."); - // Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav', - // which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag. + // Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or + // 'style.HoverFlagsForTooltipNav', which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag. ImGui::BeginDisabled(); ImGui::Button("Disabled item", sz); if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip)) @@ -3955,7 +4526,8 @@ static void DemoWindowWidgetsTreeNodes() IMGUI_DEMO_MARKER("Widgets/Tree Nodes"); if (ImGui::TreeNode("Tree Nodes")) { - // See see "Examples -> Property Editor" (ShowExampleAppPropertyEditor() function) for a fancier, data-driven tree. + // See see "Examples -> Property Editor" (ShowExampleAppPropertyEditor() function) for a fancier, data-driven + // tree. IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic trees"); if (ImGui::TreeNode("Basic trees")) { @@ -3966,15 +4538,18 @@ static void DemoWindowWidgetsTreeNodes() if (i == 0) ImGui::SetNextItemOpen(true, ImGuiCond_Once); - // Here we use PushID() to generate a unique base ID, and then the "" used as TreeNode id won't conflict. - // An alternative to using 'PushID() + TreeNode("", ...)' to generate a unique ID is to use 'TreeNode((void*)(intptr_t)i, ...)', - // aka generate a dummy pointer-sized value to be hashed. The demo below uses that technique. Both are fine. + // Here we use PushID() to generate a unique base ID, and then the "" used as TreeNode id won't + // conflict. An alternative to using 'PushID() + TreeNode("", ...)' to generate a unique ID is to use + // 'TreeNode((void*)(intptr_t)i, ...)', aka generate a dummy pointer-sized value to be hashed. The demo + // below uses that technique. Both are fine. ImGui::PushID(i); if (ImGui::TreeNode("", "Child %d", i)) { ImGui::Text("blah blah"); ImGui::SameLine(); - if (ImGui::SmallButton("button")) {} + if (ImGui::SmallButton("button")) + { + } ImGui::TreePop(); } ImGui::PopID(); @@ -3989,7 +4564,8 @@ static void DemoWindowWidgetsTreeNodes() HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags"); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", &base_flags, ImGuiTreeNodeFlags_DrawLinesNone); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", &base_flags, ImGuiTreeNodeFlags_DrawLinesFull); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", &base_flags, ImGuiTreeNodeFlags_DrawLinesToNodes); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", &base_flags, + ImGuiTreeNodeFlags_DrawLinesToNodes); if (ImGui::TreeNodeEx("Parent", base_flags)) { @@ -4014,26 +4590,39 @@ static void DemoWindowWidgetsTreeNodes() IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced, with Selectable nodes"); if (ImGui::TreeNode("Advanced, with Selectable nodes")) { - HelpMarker( - "This is a more typical looking tree with selectable nodes.\n" - "Click to select, CTRL+Click to toggle, click on arrows or double-click to open."); - static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; + HelpMarker("This is a more typical looking tree with selectable nodes.\n" + "Click to select, CTRL+Click to toggle, click on arrows or double-click to open."); + static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | + ImGuiTreeNodeFlags_OpenOnDoubleClick | + ImGuiTreeNodeFlags_SpanAvailWidth; static bool align_label_with_current_x_position = false; static bool test_drag_and_drop = false; ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", &base_flags, ImGuiTreeNodeFlags_OpenOnArrow); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node."); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, + ImGuiTreeNodeFlags_OpenOnDoubleClick); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); + ImGui::SameLine(); + HelpMarker( + "Extend hit area to all available width instead of allowing more items to be laid out after the node."); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", &base_flags, ImGuiTreeNodeFlags_SpanLabelWidth); ImGui::SameLine(); HelpMarker("Reduce hit area to the text label and a bit of margin."); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only."); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", &base_flags, ImGuiTreeNodeFlags_SpanLabelWidth); + ImGui::SameLine(); + HelpMarker("Reduce hit area to the text label and a bit of margin."); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); + ImGui::SameLine(); + HelpMarker("For use in Tables only."); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)"); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsToParent", &base_flags, ImGuiTreeNodeFlags_NavLeftJumpsToParent); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); + ImGui::SameLine(); + HelpMarker("Draw frame with background (e.g. for CollapsingHeader)"); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsToParent", &base_flags, + ImGuiTreeNodeFlags_NavLeftJumpsToParent); HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags"); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", &base_flags, ImGuiTreeNodeFlags_DrawLinesNone); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", &base_flags, ImGuiTreeNodeFlags_DrawLinesFull); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", &base_flags, ImGuiTreeNodeFlags_DrawLinesToNodes); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", &base_flags, + ImGuiTreeNodeFlags_DrawLinesToNodes); ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position); ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop); @@ -4050,7 +4639,8 @@ static void DemoWindowWidgetsTreeNodes() for (int i = 0; i < 6; i++) { // Disable the default "open on single-click behavior" + set Selected flag according to our selection. - // To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't alter selection. + // To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't + // alter selection. ImGuiTreeNodeFlags node_flags = base_flags; const bool is_selected = (selection_mask & (1 << i)) != 0; if (is_selected) @@ -4058,7 +4648,7 @@ static void DemoWindowWidgetsTreeNodes() if (i < 3) { // Items 0..2 are Tree Node - bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i); + bool node_open = ImGui::TreeNodeEx((void *)(intptr_t)i, node_flags, "Selectable Node %d", i); if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) node_clicked = i; if (test_drag_and_drop && ImGui::BeginDragDropSource()) @@ -4071,7 +4661,9 @@ static void DemoWindowWidgetsTreeNodes() { // Item 2 has an additional inline button to help demonstrate SpanLabelWidth. ImGui::SameLine(); - if (ImGui::SmallButton("button")) {} + if (ImGui::SmallButton("button")) + { + } } if (node_open) { @@ -4086,8 +4678,9 @@ static void DemoWindowWidgetsTreeNodes() // Items 3..5 are Tree Leaves // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). - node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet - ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i); + node_flags |= + ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet + ImGui::TreeNodeEx((void *)(intptr_t)i, node_flags, "Selectable Leaf %d", i); if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) node_clicked = i; if (test_drag_and_drop && ImGui::BeginDragDropSource()) @@ -4103,9 +4696,10 @@ static void DemoWindowWidgetsTreeNodes() // Update selection state // (process outside of tree loop to avoid visual inconsistencies during the clicking frame) if (ImGui::GetIO().KeyCtrl) - selection_mask ^= (1 << node_clicked); // CTRL+click to toggle - else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection - selection_mask = (1 << node_clicked); // Click to single-select + selection_mask ^= (1 << node_clicked); // CTRL+click to toggle + else // if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may + // want to preserve selection when clicking on item that is part of the selection + selection_mask = (1 << node_clicked); // Click to single-select } if (align_label_with_current_x_position) ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing()); @@ -4131,11 +4725,12 @@ static void DemoWindowWidgetsVerticalSliders() ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5); ImGui::SameLine(); - static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f }; + static float values[7] = {0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f}; ImGui::PushID("set1"); for (int i = 0; i < 7; i++) { - if (i > 0) ImGui::SameLine(); + if (i > 0) + ImGui::SameLine(); ImGui::PushID(i); ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i / 7.0f, 0.5f, 0.5f)); ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.5f)); @@ -4151,12 +4746,13 @@ static void DemoWindowWidgetsVerticalSliders() ImGui::SameLine(); ImGui::PushID("set2"); - static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f }; + static float values2[4] = {0.20f, 0.80f, 0.40f, 0.25f}; const int rows = 3; const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows)); for (int nx = 0; nx < 4; nx++) { - if (nx > 0) ImGui::SameLine(); + if (nx > 0) + ImGui::SameLine(); ImGui::BeginGroup(); for (int ny = 0; ny < rows; ny++) { @@ -4174,7 +4770,8 @@ static void DemoWindowWidgetsVerticalSliders() ImGui::PushID("set3"); for (int i = 0; i < 4; i++) { - if (i > 0) ImGui::SameLine(); + if (i > 0) + ImGui::SameLine(); ImGui::PushID(i); ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40); ImGui::VSliderFloat("##v", ImVec2(40, 160), &values[i], 0.0f, 1.0f, "%.2f\nsec"); @@ -4191,14 +4788,15 @@ static void DemoWindowWidgetsVerticalSliders() // [SECTION] DemoWindowWidgets() //----------------------------------------------------------------------------- -static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) +static void DemoWindowWidgets(ImGuiDemoWindowData *demo_data) { IMGUI_DEMO_MARKER("Widgets"); - //ImGui::SetNextItemOpen(true, ImGuiCond_Once); + // ImGui::SetNextItemOpen(true, ImGuiCond_Once); if (!ImGui::CollapsingHeader("Widgets")) return; - const bool disable_all = demo_data->DisableSections; // The Checkbox for that is inside the "Disabled" section at the bottom + const bool disable_all = + demo_data->DisableSections; // The Checkbox for that is inside the "Disabled" section at the bottom if (disable_all) ImGui::BeginDisabled(); @@ -4253,7 +4851,8 @@ static void DemoWindowLayout() { ImGui::SeparatorText("Child windows"); - HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window."); + HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a " + "host window."); static bool disable_mouse_wheel = false; static bool disable_menu = false; ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel); @@ -4264,7 +4863,8 @@ static void DemoWindowLayout() ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar; if (disable_mouse_wheel) window_flags |= ImGuiWindowFlags_NoScrollWithMouse; - ImGui::BeginChild("ChildL", ImVec2(ImGui::GetContentRegionAvail().x * 0.5f, 260), ImGuiChildFlags_None, window_flags); + ImGui::BeginChild("ChildL", ImVec2(ImGui::GetContentRegionAvail().x * 0.5f, 260), ImGuiChildFlags_None, + window_flags); for (int i = 0; i < 100; i++) ImGui::Text("%04d: scrollable region", i); ImGui::EndChild(); @@ -4309,11 +4909,12 @@ static void DemoWindowLayout() ImGui::SeparatorText("Manual-resize"); { HelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents."); - //if (ImGui::Button("Set Height to 200")) - // ImGui::SetNextWindowSize(ImVec2(-FLT_MIN, 200.0f)); + // if (ImGui::Button("Set Height to 200")) + // ImGui::SetNextWindowSize(ImVec2(-FLT_MIN, 200.0f)); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg)); - if (ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY)) + if (ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), + ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY)) for (int n = 0; n < 10; n++) ImGui::Text("Line %04d", n); ImGui::PopStyleColor(); @@ -4330,8 +4931,11 @@ static void DemoWindowLayout() ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); ImGui::DragInt("Max Height (in Lines)", &max_height_in_lines, 0.2f); - ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 1), ImVec2(FLT_MAX, ImGui::GetTextLineHeightWithSpacing() * max_height_in_lines)); - if (ImGui::BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0f), ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY)) + ImGui::SetNextWindowSizeConstraints( + ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 1), + ImVec2(FLT_MAX, ImGui::GetTextLineHeightWithSpacing() * max_height_in_lines)); + if (ImGui::BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0f), + ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY)) for (int n = 0; n < draw_lines; n++) ImGui::Text("Line %04d", n); ImGui::EndChild(); @@ -4349,16 +4953,20 @@ static void DemoWindowLayout() { static int offset_x = 0; static bool override_bg_color = true; - static ImGuiChildFlags child_flags = ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY; + static ImGuiChildFlags child_flags = + ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY; ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000); ImGui::Checkbox("Override ChildBg color", &override_bg_color); ImGui::CheckboxFlags("ImGuiChildFlags_Borders", &child_flags, ImGuiChildFlags_Borders); - ImGui::CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", &child_flags, ImGuiChildFlags_AlwaysUseWindowPadding); + ImGui::CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", &child_flags, + ImGuiChildFlags_AlwaysUseWindowPadding); ImGui::CheckboxFlags("ImGuiChildFlags_ResizeX", &child_flags, ImGuiChildFlags_ResizeX); ImGui::CheckboxFlags("ImGuiChildFlags_ResizeY", &child_flags, ImGuiChildFlags_ResizeY); ImGui::CheckboxFlags("ImGuiChildFlags_FrameStyle", &child_flags, ImGuiChildFlags_FrameStyle); - ImGui::SameLine(); HelpMarker("Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding."); + ImGui::SameLine(); + HelpMarker("Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, " + "FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding."); if (child_flags & ImGuiChildFlags_FrameStyle) override_bg_color = false; @@ -4376,7 +4984,8 @@ static void DemoWindowLayout() ImVec2 child_rect_min = ImGui::GetItemRectMin(); ImVec2 child_rect_max = ImGui::GetItemRectMax(); ImGui::Text("Hovered: %d", child_is_hovered); - ImGui::Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y); + ImGui::Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, + child_rect_max.x, child_rect_max.y); } ImGui::TreePop(); @@ -4395,7 +5004,8 @@ static void DemoWindowLayout() // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc. ImGui::Text("SetNextItemWidth/PushItemWidth(100)"); - ImGui::SameLine(); HelpMarker("Fixed width."); + ImGui::SameLine(); + HelpMarker("Fixed width."); ImGui::PushItemWidth(100); ImGui::DragFloat("float##1b", &f); if (show_indented_items) @@ -4407,7 +5017,8 @@ static void DemoWindowLayout() ImGui::PopItemWidth(); ImGui::Text("SetNextItemWidth/PushItemWidth(-100)"); - ImGui::SameLine(); HelpMarker("Align to right edge minus 100"); + ImGui::SameLine(); + HelpMarker("Align to right edge minus 100"); ImGui::PushItemWidth(-100); ImGui::DragFloat("float##2a", &f); if (show_indented_items) @@ -4419,7 +5030,8 @@ static void DemoWindowLayout() ImGui::PopItemWidth(); ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)"); - ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)"); + ImGui::SameLine(); + HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)"); ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.5f); ImGui::DragFloat("float##3a", &f); if (show_indented_items) @@ -4431,7 +5043,8 @@ static void DemoWindowLayout() ImGui::PopItemWidth(); ImGui::Text("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)"); - ImGui::SameLine(); HelpMarker("Align to right edge minus half"); + ImGui::SameLine(); + HelpMarker("Align to right edge minus half"); ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f); ImGui::DragFloat("float##4a", &f); if (show_indented_items) @@ -4456,7 +5069,8 @@ static void DemoWindowLayout() // Demonstrate using PushItemWidth to surround three items. // Calling SetNextItemWidth() before each of them would have the same effect. ImGui::Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)"); - ImGui::SameLine(); HelpMarker("Align to right edge"); + ImGui::SameLine(); + HelpMarker("Align to right edge"); ImGui::PushItemWidth(-FLT_MIN); ImGui::DragFloat("##float5a", &f); if (show_indented_items) @@ -4477,78 +5091,98 @@ static void DemoWindowLayout() // Text IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine"); - ImGui::Text("Two items: Hello"); ImGui::SameLine(); + ImGui::Text("Two items: Hello"); + ImGui::SameLine(); ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor"); // Adjust spacing - ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20); + ImGui::Text("More spacing: Hello"); + ImGui::SameLine(0, 20); ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor"); // Button ImGui::AlignTextToFramePadding(); - ImGui::Text("Normal buttons"); ImGui::SameLine(); - ImGui::Button("Banana"); ImGui::SameLine(); - ImGui::Button("Apple"); ImGui::SameLine(); + ImGui::Text("Normal buttons"); + ImGui::SameLine(); + ImGui::Button("Banana"); + ImGui::SameLine(); + ImGui::Button("Apple"); + ImGui::SameLine(); ImGui::Button("Corniflower"); // Button - ImGui::Text("Small buttons"); ImGui::SameLine(); - ImGui::SmallButton("Like this one"); ImGui::SameLine(); + ImGui::Text("Small buttons"); + ImGui::SameLine(); + ImGui::SmallButton("Like this one"); + ImGui::SameLine(); ImGui::Text("can fit within a text block."); // Aligned to arbitrary position. Easy/cheap column. IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)"); ImGui::Text("Aligned"); - ImGui::SameLine(150); ImGui::Text("x=150"); - ImGui::SameLine(300); ImGui::Text("x=300"); + ImGui::SameLine(150); + ImGui::Text("x=150"); + ImGui::SameLine(300); + ImGui::Text("x=300"); ImGui::Text("Aligned"); - ImGui::SameLine(150); ImGui::SmallButton("x=150"); - ImGui::SameLine(300); ImGui::SmallButton("x=300"); + ImGui::SameLine(150); + ImGui::SmallButton("x=150"); + ImGui::SameLine(300); + ImGui::SmallButton("x=300"); // Checkbox IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)"); static bool c1 = false, c2 = false, c3 = false, c4 = false; - ImGui::Checkbox("My", &c1); ImGui::SameLine(); - ImGui::Checkbox("Tailor", &c2); ImGui::SameLine(); - ImGui::Checkbox("Is", &c3); ImGui::SameLine(); + ImGui::Checkbox("My", &c1); + ImGui::SameLine(); + ImGui::Checkbox("Tailor", &c2); + ImGui::SameLine(); + ImGui::Checkbox("Is", &c3); + ImGui::SameLine(); ImGui::Checkbox("Rich", &c4); // Various static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f; ImGui::PushItemWidth(80); - const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" }; + const char *items[] = {"AAAA", "BBBB", "CCCC", "DDDD"}; static int item = -1; - ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine(); - ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine(); - ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine(); + ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); + ImGui::SameLine(); + ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); + ImGui::SameLine(); + ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); + ImGui::SameLine(); ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f); ImGui::PopItemWidth(); ImGui::PushItemWidth(80); ImGui::Text("Lists:"); - static int selection[4] = { 0, 1, 2, 3 }; + static int selection[4] = {0, 1, 2, 3}; for (int i = 0; i < 4; i++) { - if (i > 0) ImGui::SameLine(); + if (i > 0) + ImGui::SameLine(); ImGui::PushID(i); ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items)); ImGui::PopID(); - //ImGui::SetItemTooltip("ListBox %d hovered", i); + // ImGui::SetItemTooltip("ListBox %d hovered", i); } ImGui::PopItemWidth(); // Dummy IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Dummy"); ImVec2 button_sz(40, 40); - ImGui::Button("A", button_sz); ImGui::SameLine(); - ImGui::Dummy(button_sz); ImGui::SameLine(); + ImGui::Button("A", button_sz); + ImGui::SameLine(); + ImGui::Dummy(button_sz); + ImGui::SameLine(); ImGui::Button("B", button_sz); // Manually wrapping // (we should eventually provide this as an automatic layout feature, but for now you can do it manually) IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping"); ImGui::Text("Manual wrapping:"); - ImGuiStyle& style = ImGui::GetStyle(); + ImGuiStyle &style = ImGui::GetStyle(); int buttons_count = 20; float window_visible_x2 = ImGui::GetCursorScreenPos().x + ImGui::GetContentRegionAvail().x; for (int n = 0; n < buttons_count; n++) @@ -4556,7 +5190,8 @@ static void DemoWindowLayout() ImGui::PushID(n); ImGui::Button("Box", button_sz); float last_button_x2 = ImGui::GetItemRectMax().x; - float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line + float next_button_x2 = + last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line if (n + 1 < buttons_count && next_button_x2 < window_visible_x2) ImGui::SameLine(); ImGui::PopID(); @@ -4568,10 +5203,9 @@ static void DemoWindowLayout() IMGUI_DEMO_MARKER("Layout/Groups"); if (ImGui::TreeNode("Groups")) { - HelpMarker( - "BeginGroup() basically locks the horizontal position for new line. " - "EndGroup() bundles the whole group so that you can use \"item\" functions such as " - "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group."); + HelpMarker("BeginGroup() basically locks the horizontal position for new line. " + "EndGroup() bundles the whole group so that you can use \"item\" functions such as " + "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group."); ImGui::BeginGroup(); { ImGui::BeginGroup(); @@ -4590,7 +5224,7 @@ static void DemoWindowLayout() } // Capture the group size and create widgets using the same size ImVec2 size = ImGui::GetItemRectSize(); - const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f }; + const float values[5] = {0.5f, 0.20f, 0.80f, 0.60f, 0.25f}; ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size); ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y)); @@ -4617,34 +5251,46 @@ static void DemoWindowLayout() { { ImGui::BulletText("Text baseline:"); - ImGui::SameLine(); HelpMarker( + ImGui::SameLine(); + HelpMarker( "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. " - "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets."); + "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed " + "widgets."); ImGui::Indent(); - ImGui::Text("KO Blahblah"); ImGui::SameLine(); - ImGui::Button("Some framed item"); ImGui::SameLine(); + ImGui::Text("KO Blahblah"); + ImGui::SameLine(); + ImGui::Button("Some framed item"); + ImGui::SameLine(); HelpMarker("Baseline of button will look misaligned with text.."); // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. // (because we don't know what's coming after the Text() statement, we need to move the text baseline // down by FramePadding.y ahead of time) ImGui::AlignTextToFramePadding(); - ImGui::Text("OK Blahblah"); ImGui::SameLine(); - ImGui::Button("Some framed item##2"); ImGui::SameLine(); + ImGui::Text("OK Blahblah"); + ImGui::SameLine(); + ImGui::Button("Some framed item##2"); + ImGui::SameLine(); HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y"); // SmallButton() uses the same vertical padding as Text - ImGui::Button("TEST##1"); ImGui::SameLine(); - ImGui::Text("TEST"); ImGui::SameLine(); + ImGui::Button("TEST##1"); + ImGui::SameLine(); + ImGui::Text("TEST"); + ImGui::SameLine(); ImGui::SmallButton("TEST##2"); // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. ImGui::AlignTextToFramePadding(); - ImGui::Text("Text aligned to framed item"); ImGui::SameLine(); - ImGui::Button("Item##1"); ImGui::SameLine(); - ImGui::Text("Item"); ImGui::SameLine(); - ImGui::SmallButton("Item##2"); ImGui::SameLine(); + ImGui::Text("Text aligned to framed item"); + ImGui::SameLine(); + ImGui::Button("Item##1"); + ImGui::SameLine(); + ImGui::Text("Item"); + ImGui::SameLine(); + ImGui::SmallButton("Item##2"); + ImGui::SameLine(); ImGui::Button("Item##3"); ImGui::Unindent(); @@ -4655,21 +5301,30 @@ static void DemoWindowLayout() { ImGui::BulletText("Multi-line text:"); ImGui::Indent(); - ImGui::Text("One\nTwo\nThree"); ImGui::SameLine(); - ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("One\nTwo\nThree"); + ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); + ImGui::SameLine(); ImGui::Text("Banana"); - ImGui::Text("Banana"); ImGui::SameLine(); - ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("Banana"); + ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); + ImGui::SameLine(); ImGui::Text("One\nTwo\nThree"); - ImGui::Button("HOP##1"); ImGui::SameLine(); - ImGui::Text("Banana"); ImGui::SameLine(); - ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Button("HOP##1"); + ImGui::SameLine(); + ImGui::Text("Banana"); + ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); + ImGui::SameLine(); ImGui::Text("Banana"); - ImGui::Button("HOP##2"); ImGui::SameLine(); - ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Button("HOP##2"); + ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); + ImGui::SameLine(); ImGui::Text("Banana"); ImGui::Unindent(); } @@ -4690,7 +5345,8 @@ static void DemoWindowLayout() ImGui::SmallButton("SmallButton()"); // Tree - // (here the node appears after a button and has odd intent, so we use ImGuiTreeNodeFlags_DrawLinesNone to disable hierarchy outline) + // (here the node appears after a button and has odd intent, so we use ImGuiTreeNodeFlags_DrawLinesNone to + // disable hierarchy outline) const float spacing = ImGui::GetStyle().ItemInnerSpacing.x; ImGui::Button("Button##1"); ImGui::SameLine(0.0f, spacing); @@ -4709,7 +5365,8 @@ static void DemoWindowLayout() // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add // other contents below the node. bool node_open = ImGui::TreeNode("Node##2"); - ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2"); + ImGui::SameLine(0.0f, spacing); + ImGui::Button("Button##2"); if (node_open) { // Placeholder tree data @@ -4725,7 +5382,8 @@ static void DemoWindowLayout() ImGui::AlignTextToFramePadding(); ImGui::BulletText("Node"); - ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4"); + ImGui::SameLine(0.0f, spacing); + ImGui::Button("Button##4"); ImGui::Unindent(); } @@ -4749,33 +5407,38 @@ static void DemoWindowLayout() ImGui::Checkbox("Track", &enable_track); ImGui::PushItemWidth(100); - ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d"); + ImGui::SameLine(140); + enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d"); bool scroll_to_off = ImGui::Button("Scroll Offset"); - ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px"); + ImGui::SameLine(140); + scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px"); bool scroll_to_pos = ImGui::Button("Scroll To Pos"); - ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px"); + ImGui::SameLine(140); + scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px"); ImGui::PopItemWidth(); if (scroll_to_off || scroll_to_pos) enable_track = false; - ImGuiStyle& style = ImGui::GetStyle(); + ImGuiStyle &style = ImGui::GetStyle(); float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5; if (child_w < 1.0f) child_w = 1.0f; ImGui::PushID("##VerticalScrolling"); for (int i = 0; i < 5; i++) { - if (i > 0) ImGui::SameLine(); + if (i > 0) + ImGui::SameLine(); ImGui::BeginGroup(); - const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" }; + const char *names[] = {"Top", "25%", "Center", "75%", "Bottom"}; ImGui::TextUnformatted(names[i]); const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0; - const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); - const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), ImGuiChildFlags_Borders, child_flags); + const ImGuiID child_id = ImGui::GetID((void *)(intptr_t)i); + const bool child_is_visible = + ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), ImGuiChildFlags_Borders, child_flags); if (ImGui::BeginMenuBar()) { ImGui::TextUnformatted("abc"); @@ -4811,18 +5474,19 @@ static void DemoWindowLayout() // Horizontal scroll functions IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal"); ImGui::Spacing(); - HelpMarker( - "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n" - "Because the clipping rectangle of most window hides half worth of WindowPadding on the " - "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the " - "equivalent SetScrollFromPosY(+1) wouldn't."); + HelpMarker("Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n" + "Because the clipping rectangle of most window hides half worth of WindowPadding on the " + "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the " + "equivalent SetScrollFromPosY(+1) wouldn't."); ImGui::PushID("##HorizontalScrolling"); for (int i = 0; i < 5; i++) { float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f; - ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0); - ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); - bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags_Borders, child_flags); + ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | + (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0); + ImGuiID child_id = ImGui::GetID((void *)(intptr_t)i); + bool child_is_visible = + ImGui::BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags_Borders, child_flags); if (scroll_to_off) ImGui::SetScrollX(scroll_to_off_px); if (scroll_to_pos) @@ -4848,7 +5512,7 @@ static void DemoWindowLayout() float scroll_max_x = ImGui::GetScrollMaxX(); ImGui::EndChild(); ImGui::SameLine(); - const char* names[] = { "Left", "25%", "Center", "75%", "Right" }; + const char *names[] = {"Left", "25%", "Center", "75%", "Right"}; ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x); ImGui::Spacing(); } @@ -4856,15 +5520,16 @@ static void DemoWindowLayout() // Miscellaneous Horizontal Scrolling Demo IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal (more)"); - HelpMarker( - "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n" - "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin()."); + HelpMarker("Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n" + "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before " + "Begin()."); static int lines = 7; ImGui::SliderInt("Lines", &lines, 1, 15); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f)); ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30); - ImGui::BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags_Borders, ImGuiWindowFlags_HorizontalScrollbar); + ImGui::BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags_Borders, + ImGuiWindowFlags_HorizontalScrollbar); for (int line = 0; line < lines; line++) { // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() @@ -4874,11 +5539,12 @@ static void DemoWindowLayout() int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3); for (int n = 0; n < num_buttons; n++) { - if (n > 0) ImGui::SameLine(); + if (n > 0) + ImGui::SameLine(); ImGui::PushID(n + line * 1000); char num_buf[16]; sprintf(num_buf, "%d", n); - const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf; + const char *label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf; float hue = n * 0.05f; ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f)); @@ -4897,7 +5563,8 @@ static void DemoWindowLayout() if (ImGui::IsItemActive()) scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; ImGui::SameLine(); - ImGui::Text("Scroll from code"); ImGui::SameLine(); + ImGui::Text("Scroll from code"); + ImGui::SameLine(); ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; @@ -4929,22 +5596,25 @@ static void DemoWindowLayout() static float contents_size_x = 300.0f; if (explicit_content_size) ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f)); - ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0); + ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, + show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0); IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window"); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0)); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0)); - HelpMarker( - "Test how different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\n" - "Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles."); + HelpMarker("Test how different widgets react and impact the work rectangle growing when horizontal " + "scrolling is enabled.\n\n" + "Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles."); ImGui::Checkbox("H-scrollbar", &show_h_scrollbar); - ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten) - ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width - ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size - ImGui::Checkbox("Columns", &show_columns); // Will use contents size - ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size - ImGui::Checkbox("Child", &show_child); // Will grow and use contents size + ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten) + ImGui::Checkbox("Tree nodes", + &show_tree_nodes); // Will grow contents size and display highlight over full width + ImGui::Checkbox("Text wrapped", &show_text_wrapped); // Will grow and use contents size + ImGui::Checkbox("Columns", &show_columns); // Will use contents size + ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size + ImGui::Checkbox("Child", &show_child); // Will grow and use contents size ImGui::Checkbox("Explicit content size", &explicit_content_size); - ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY()); + ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), + ImGui::GetScrollMaxY()); if (explicit_content_size) { ImGui::SameLine(); @@ -4952,7 +5622,8 @@ static void DemoWindowLayout() ImGui::DragFloat("##csx", &contents_size_x); ImVec2 p = ImGui::GetCursorScreenPos(); ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE); - ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE); + ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), + ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE); ImGui::Dummy(ImVec2(0, 10)); } ImGui::PopStyleVar(2); @@ -5002,10 +5673,22 @@ static void DemoWindowLayout() } if (show_tab_bar && ImGui::BeginTabBar("Hello")) { - if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); } + if (ImGui::BeginTabItem("OneOneOne")) + { + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("TwoTwoTwo")) + { + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("ThreeThreeThree")) + { + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("FourFourFour")) + { + ImGui::EndTabItem(); + } ImGui::EndTabBar(); } if (show_child) @@ -5024,19 +5707,18 @@ static void DemoWindowLayout() { static ImVec2 size(100.0f, 100.0f); static ImVec2 offset(30.0f, 30.0f); - ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f"); + ImGui::DragFloat2("size", (float *)&size, 0.5f, 1.0f, 200.0f, "%.0f"); ImGui::TextWrapped("(Click and drag to scroll)"); - HelpMarker( - "(Left) Using ImGui::PushClipRect():\n" - "Will alter ImGui hit-testing logic + ImDrawList rendering.\n" - "(use this if you want your clipping rectangle to affect interactions)\n\n" - "(Center) Using ImDrawList::PushClipRect():\n" - "Will alter ImDrawList rendering only.\n" - "(use this as a shortcut if you are only using ImDrawList calls)\n\n" - "(Right) Using ImDrawList::AddText() with a fine ClipRect:\n" - "Will alter only this specific ImDrawList::AddText() rendering.\n" - "This is often used internally to avoid altering the clipping rectangle and minimize draw calls."); + HelpMarker("(Left) Using ImGui::PushClipRect():\n" + "Will alter ImGui hit-testing logic + ImDrawList rendering.\n" + "(use this if you want your clipping rectangle to affect interactions)\n\n" + "(Center) Using ImDrawList::PushClipRect():\n" + "Will alter ImDrawList rendering only.\n" + "(use this as a shortcut if you are only using ImDrawList calls)\n\n" + "(Right) Using ImDrawList::AddText() with a fine ClipRect:\n" + "Will alter only this specific ImDrawList::AddText() rendering.\n" + "This is often used internally to avoid altering the clipping rectangle and minimize draw calls."); for (int n = 0; n < 3; n++) { @@ -5056,9 +5738,9 @@ static void DemoWindowLayout() const ImVec2 p0 = ImGui::GetItemRectMin(); const ImVec2 p1 = ImGui::GetItemRectMax(); - const char* text_str = "Line 1 hello\nLine 2 clip me!"; + const char *text_str = "Line 1 hello\nLine 2 clip me!"; const ImVec2 text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y); - ImDrawList* draw_list = ImGui::GetWindowDrawList(); + ImDrawList *draw_list = ImGui::GetWindowDrawList(); switch (n) { case 0: @@ -5076,7 +5758,8 @@ static void DemoWindowLayout() case 2: ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert. draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)); - draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, NULL, 0.0f, &clip_rect); + draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, NULL, + 0.0f, &clip_rect); break; } } @@ -5089,10 +5772,11 @@ static void DemoWindowLayout() { static bool enable_allow_overlap = true; - HelpMarker( - "Hit-testing is by default performed in item submission order, which generally is perceived as 'back-to-front'.\n\n" - "By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. " - "Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to accept hovered state."); + HelpMarker("Hit-testing is by default performed in item submission order, which generally is perceived as " + "'back-to-front'.\n\n" + "By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. " + "Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to " + "accept hovered state."); ImGui::Checkbox("Enable AllowOverlap", &enable_allow_overlap); ImVec2 button1_pos = ImGui::GetCursorScreenPos(); @@ -5137,7 +5821,8 @@ static void DemoWindowPopups() // popups at any time. // Typical use for regular windows: - // bool my_tool_is_active = false; if (ImGui::Button("Open")) my_tool_is_active = true; [...] if (my_tool_is_active) Begin("My Tool", &my_tool_is_active) { [...] } End(); + // bool my_tool_is_active = false; if (ImGui::Button("Open")) my_tool_is_active = true; [...] if + // (my_tool_is_active) Begin("My Tool", &my_tool_is_active) { [...] } End(); // Typical use for popups: // if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); } @@ -5147,13 +5832,12 @@ static void DemoWindowPopups() IMGUI_DEMO_MARKER("Popups/Popups"); if (ImGui::TreeNode("Popups")) { - ImGui::TextWrapped( - "When a popup is active, it inhibits interacting with windows that are behind the popup. " - "Clicking outside the popup closes it."); + ImGui::TextWrapped("When a popup is active, it inhibits interacting with windows that are behind the popup. " + "Clicking outside the popup closes it."); static int selected_fish = -1; - const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" }; - static bool toggles[] = { true, false, false, false, false }; + const char *names[] = {"Bream", "Haddock", "Mackerel", "Pollock", "Tilefish"}; + static bool toggles[] = {true, false, false, false, false}; // Simple selection popup (if you want to show the current selection inside the Button itself, // you may want to build a string using the "###" operator to preserve a constant ID with a variable label) @@ -5240,7 +5924,8 @@ static void DemoWindowPopups() IMGUI_DEMO_MARKER("Popups/Context menus"); if (ImGui::TreeNode("Context menus")) { - HelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier."); + 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 (id == 0) @@ -5255,7 +5940,7 @@ static void DemoWindowPopups() // 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" }; + const char *names[5] = {"Label1", "Label2", "Label3", "Label4", "Label5"}; static int selected = -1; for (int n = 0; n < 5; n++) { @@ -5274,16 +5959,19 @@ static void DemoWindowPopups() } // 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. + // 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. { 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 text", value); if (ImGui::BeginPopupContextItem("my popup")) { - if (ImGui::Selectable("Set to zero")) value = 0.0f; - if (ImGui::Selectable("Set to PI")) value = 3.1415f; + 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(); @@ -5303,9 +5991,11 @@ static void DemoWindowPopups() // 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). + // 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."); + 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 @@ -5318,7 +6008,8 @@ static void DemoWindowPopups() ImGui::CloseCurrentPopup(); ImGui::EndPopup(); } - ImGui::SameLine(); ImGui::Text("(<-- right-click here)"); + ImGui::SameLine(); + ImGui::Text("(<-- right-click here)"); } ImGui::TreePop(); @@ -5341,18 +6032,24 @@ static void DemoWindowPopups() ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!"); ImGui::Separator(); - //static int unused_i = 0; - //ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0"); + // static int unused_i = 0; + // ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0"); static bool dont_ask_me_next_time = false; ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time); ImGui::PopStyleVar(); - if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } + if (ImGui::Button("OK", ImVec2(120, 0))) + { + ImGui::CloseCurrentPopup(); + } ImGui::SetItemDefaultFocus(); ImGui::SameLine(); - if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } + if (ImGui::Button("Cancel", ImVec2(120, 0))) + { + ImGui::CloseCurrentPopup(); + } ImGui::EndPopup(); } @@ -5364,7 +6061,9 @@ static void DemoWindowPopups() { if (ImGui::BeginMenu("File")) { - if (ImGui::MenuItem("Some menu item")) {} + if (ImGui::MenuItem("Some menu item")) + { + } ImGui::EndMenu(); } ImGui::EndMenuBar(); @@ -5373,7 +6072,7 @@ static void DemoWindowPopups() // Testing behavior of widgets stacking their own regular popups over the modal. static int item = 1; - static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; + static float color[4] = {0.4f, 0.7f, 0.0f, 0.5f}; ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); ImGui::ColorEdit4("Color", color); @@ -5404,7 +6103,8 @@ static void DemoWindowPopups() IMGUI_DEMO_MARKER("Popups/Menus inside a regular window"); if (ImGui::TreeNode("Menus inside a regular window")) { - ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!"); + ImGui::TextWrapped( + "Below we are testing adding menu items to a regular window. It's rather unusual but should work!"); ImGui::Separator(); ImGui::MenuItem("Menu item", "CTRL+M"); @@ -5419,13 +6119,14 @@ static void DemoWindowPopups() } // Dummy data structure that we use for the Table demo. -// (pre-C++11 doesn't allow us to instantiate ImVector template if this structure is defined inside the demo function) +// (pre-C++11 doesn't allow us to instantiate ImVector template if this structure is defined inside the demo +// function) namespace { // We are passing our own identifier to TableSetupColumn() to facilitate identifying columns in the sorting code. // This identifier will be passed down into ImGuiTableSortSpec::ColumnUserID. -// But it is possible to omit the user id parameter of TableSetupColumn() and just use the column index instead! (ImGuiTableSortSpec::ColumnIndex) -// If you don't use sorting, you will generally never care about giving column an ID! +// But it is possible to omit the user id parameter of TableSetupColumn() and just use the column index instead! +// (ImGuiTableSortSpec::ColumnIndex) If you don't use sorting, you will generally never care about giving column an ID! enum MyItemColumnID { MyItemColumnID_ID, @@ -5437,20 +6138,20 @@ enum MyItemColumnID struct MyItem { - int ID; - const char* Name; - int Quantity; + int ID; + const char *Name; + int Quantity; // We have a problem which is affecting _only this demo_ and should not affect your code: - // As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(), - // however qsort doesn't allow passing user data to comparing function. - // As a workaround, we are storing the sort specs in a static/global for the comparing function to access. - // In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global. - // We could technically call ImGui::TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called - // very often by the sorting algorithm it would be a little wasteful. - static const ImGuiTableSortSpecs* s_current_sort_specs; + // As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to + // qsort(), however qsort doesn't allow passing user data to comparing function. As a workaround, we are storing the + // sort specs in a static/global for the comparing function to access. In your own use case you would probably pass + // the sort specs to your sorting/comparing functions directly and not use a global. We could technically call + // ImGui::TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called very often by + // the sorting algorithm it would be a little wasteful. + static const ImGuiTableSortSpecs *s_current_sort_specs; - static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, MyItem* items, int items_count) + static void SortWithSortSpecs(ImGuiTableSortSpecs *sort_specs, MyItem *items, int items_count) { s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function. if (items_count > 1) @@ -5459,23 +6160,33 @@ struct MyItem } // Compare function to be used by qsort() - static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs) + static int IMGUI_CDECL CompareWithSortSpecs(const void *lhs, const void *rhs) { - const MyItem* a = (const MyItem*)lhs; - const MyItem* b = (const MyItem*)rhs; + const MyItem *a = (const MyItem *)lhs; + const MyItem *b = (const MyItem *)rhs; for (int n = 0; n < s_current_sort_specs->SpecsCount; n++) { // Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn() // We could also choose to identify columns based on their index (sort_spec->ColumnIndex), which is simpler! - const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n]; + const ImGuiTableColumnSortSpecs *sort_spec = &s_current_sort_specs->Specs[n]; int delta = 0; switch (sort_spec->ColumnUserID) { - case MyItemColumnID_ID: delta = (a->ID - b->ID); break; - case MyItemColumnID_Name: delta = (strcmp(a->Name, b->Name)); break; - case MyItemColumnID_Quantity: delta = (a->Quantity - b->Quantity); break; - case MyItemColumnID_Description: delta = (strcmp(a->Name, b->Name)); break; - default: IM_ASSERT(0); break; + case MyItemColumnID_ID: + delta = (a->ID - b->ID); + break; + case MyItemColumnID_Name: + delta = (strcmp(a->Name, b->Name)); + break; + case MyItemColumnID_Quantity: + delta = (a->Quantity - b->Quantity); + break; + case MyItemColumnID_Description: + delta = (strcmp(a->Name, b->Name)); + break; + default: + IM_ASSERT(0); + break; } if (delta > 0) return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1; @@ -5489,13 +6200,13 @@ struct MyItem return (a->ID - b->ID); } }; -const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL; -} +const ImGuiTableSortSpecs *MyItem::s_current_sort_specs = NULL; +} // namespace // Make the UI compact because there are so many fields static void PushStyleCompact() { - ImGuiStyle& style = ImGui::GetStyle(); + ImGuiStyle &style = ImGui::GetStyle(); ImGui::PushStyleVarY(ImGuiStyleVar_FramePadding, (float)(int)(style.FramePadding.y * 0.60f)); ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, (float)(int)(style.ItemSpacing.y * 0.60f)); } @@ -5506,22 +6217,33 @@ static void PopStyleCompact() } // Show a combo box with a choice of sizing policies -static void EditTableSizingFlags(ImGuiTableFlags* p_flags) +static void EditTableSizingFlags(ImGuiTableFlags *p_flags) { - struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; }; - static const EnumDesc policies[] = + struct EnumDesc { - { ImGuiTableFlags_None, "Default", "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise." }, - { ImGuiTableFlags_SizingFixedFit, "ImGuiTableFlags_SizingFixedFit", "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." }, - { ImGuiTableFlags_SizingFixedSame, "ImGuiTableFlags_SizingFixedSame", "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." }, - { ImGuiTableFlags_SizingStretchProp, "ImGuiTableFlags_SizingStretchProp", "Columns default to _WidthStretch with weights proportional to their widths." }, - { ImGuiTableFlags_SizingStretchSame, "ImGuiTableFlags_SizingStretchSame", "Columns default to _WidthStretch with same weights." } + ImGuiTableFlags Value; + const char *Name; + const char *Tooltip; }; + static const EnumDesc policies[] = { + {ImGuiTableFlags_None, "Default", + "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has " + "ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise."}, + {ImGuiTableFlags_SizingFixedFit, "ImGuiTableFlags_SizingFixedFit", + "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width."}, + {ImGuiTableFlags_SizingFixedSame, "ImGuiTableFlags_SizingFixedSame", + "Columns are all the same width, matching the maximum contents width.\nImplicitly disable " + "ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible."}, + {ImGuiTableFlags_SizingStretchProp, "ImGuiTableFlags_SizingStretchProp", + "Columns default to _WidthStretch with weights proportional to their widths."}, + {ImGuiTableFlags_SizingStretchSame, "ImGuiTableFlags_SizingStretchSame", + "Columns default to _WidthStretch with same weights."}}; int idx; for (idx = 0; idx < IM_ARRAYSIZE(policies); idx++) if (policies[idx].Value == (*p_flags & ImGuiTableFlags_SizingMask_)) break; - const char* preview_text = (idx < IM_ARRAYSIZE(policies)) ? policies[idx].Name + (idx > 0 ? strlen("ImGuiTableFlags") : 0) : ""; + const char *preview_text = + (idx < IM_ARRAYSIZE(policies)) ? policies[idx].Name + (idx > 0 ? strlen("ImGuiTableFlags") : 0) : ""; if (ImGui::BeginCombo("Sizing Policy", preview_text)) { for (int n = 0; n < IM_ARRAYSIZE(policies); n++) @@ -5547,9 +6269,11 @@ static void EditTableSizingFlags(ImGuiTableFlags* p_flags) } } -static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags) +static void EditTableColumnsFlags(ImGuiTableColumnFlags *p_flags) { - ImGui::CheckboxFlags("_Disabled", p_flags, ImGuiTableColumnFlags_Disabled); ImGui::SameLine(); HelpMarker("Master disable flag (also hide from context menu)"); + ImGui::CheckboxFlags("_Disabled", p_flags, ImGuiTableColumnFlags_Disabled); + ImGui::SameLine(); + HelpMarker("Master disable flag (also hide from context menu)"); ImGui::CheckboxFlags("_DefaultHide", p_flags, ImGuiTableColumnFlags_DefaultHide); ImGui::CheckboxFlags("_DefaultSort", p_flags, ImGuiTableColumnFlags_DefaultSort); if (ImGui::CheckboxFlags("_WidthStretch", p_flags, ImGuiTableColumnFlags_WidthStretch)) @@ -5567,8 +6291,12 @@ static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags) ImGui::CheckboxFlags("_NoHeaderWidth", p_flags, ImGuiTableColumnFlags_NoHeaderWidth); ImGui::CheckboxFlags("_PreferSortAscending", p_flags, ImGuiTableColumnFlags_PreferSortAscending); ImGui::CheckboxFlags("_PreferSortDescending", p_flags, ImGuiTableColumnFlags_PreferSortDescending); - ImGui::CheckboxFlags("_IndentEnable", p_flags, ImGuiTableColumnFlags_IndentEnable); ImGui::SameLine(); HelpMarker("Default for column 0"); - ImGui::CheckboxFlags("_IndentDisable", p_flags, ImGuiTableColumnFlags_IndentDisable); ImGui::SameLine(); HelpMarker("Default for column >0"); + ImGui::CheckboxFlags("_IndentEnable", p_flags, ImGuiTableColumnFlags_IndentEnable); + ImGui::SameLine(); + HelpMarker("Default for column 0"); + ImGui::CheckboxFlags("_IndentDisable", p_flags, ImGuiTableColumnFlags_IndentDisable); + ImGui::SameLine(); + HelpMarker("Default for column >0"); ImGui::CheckboxFlags("_AngledHeader", p_flags, ImGuiTableColumnFlags_AngledHeader); } @@ -5586,7 +6314,7 @@ static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags) static void DemoWindowTables() { - //ImGui::SetNextItemOpen(true, ImGuiCond_Once); + // ImGui::SetNextItemOpen(true, ImGuiCond_Once); IMGUI_DEMO_MARKER("Tables"); if (!ImGui::CollapsingHeader("Tables & Columns")) return; @@ -5615,14 +6343,15 @@ static void DemoWindowTables() ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f); // About Styling of tables - // Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs. - // There are however a few settings that a shared and part of the ImGuiStyle structure: + // Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns + // APIs. There are however a few settings that a shared and part of the ImGuiStyle structure: // style.CellPadding // Padding within each cell // style.Colors[ImGuiCol_TableHeaderBg] // Table header background // style.Colors[ImGuiCol_TableBorderStrong] // Table outer and header borders // style.Colors[ImGuiCol_TableBorderLight] // Table inner borders - // style.Colors[ImGuiCol_TableRowBg] // Table row background when ImGuiTableFlags_RowBg is enabled (even rows) - // style.Colors[ImGuiCol_TableRowBgAlt] // Table row background when ImGuiTableFlags_RowBg is enabled (odds rows) + // style.Colors[ImGuiCol_TableRowBg] // Table row background when ImGuiTableFlags_RowBg is enabled (even + // rows) style.Colors[ImGuiCol_TableRowBgAlt] // Table row background when ImGuiTableFlags_RowBg is enabled + // (odds rows) // Demos if (open_action != -1) @@ -5650,8 +6379,9 @@ static void DemoWindowTables() ImGui::EndTable(); } - // [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex(). - // This is generally more convenient when you have code manually submitting the contents of each column. + // [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + + // TableSetColumnIndex(). This is generally more convenient when you have code manually submitting the contents + // of each column. HelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually."); if (ImGui::BeginTable("table2", 3)) { @@ -5671,10 +6401,9 @@ static void DemoWindowTables() // [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(), // as TableNextColumn() will automatically wrap around and create new rows as needed. // This is generally more convenient when your cells all contains the same type of data. - HelpMarker( - "Only using TableNextColumn(), which tends to be convenient for tables where every cell contains " - "the same type of contents.\n This is also more similar to the old NextColumn() function of the " - "Columns API, and provided to facilitate the Columns->Tables API transition."); + HelpMarker("Only using TableNextColumn(), which tends to be convenient for tables where every cell contains " + "the same type of contents.\n This is also more similar to the old NextColumn() function of the " + "Columns API, and provided to facilitate the Columns->Tables API transition."); if (ImGui::BeginTable("table3", 3)) { for (int item = 0; item < 14; item++) @@ -5694,7 +6423,11 @@ static void DemoWindowTables() if (ImGui::TreeNode("Borders, background")) { // Expose a few Borders related flags interactively - enum ContentsType { CT_Text, CT_FillButton }; + enum ContentsType + { + CT_Text, + CT_FillButton + }; static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg; static bool display_headers = false; static int contents_type = CT_Text; @@ -5702,7 +6435,9 @@ static void DemoWindowTables() PushStyleCompact(); ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg); ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders); - ImGui::SameLine(); HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerH\n | ImGuiTableFlags_BordersOuterH"); + ImGui::SameLine(); + HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | " + "ImGuiTableFlags_BordersInnerH\n | ImGuiTableFlags_BordersOuterH"); ImGui::Indent(); ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH); @@ -5721,17 +6456,23 @@ static void DemoWindowTables() ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags, ImGuiTableFlags_BordersInner); ImGui::Unindent(); - ImGui::AlignTextToFramePadding(); ImGui::Text("Cell contents:"); - ImGui::SameLine(); ImGui::RadioButton("Text", &contents_type, CT_Text); - ImGui::SameLine(); ImGui::RadioButton("FillButton", &contents_type, CT_FillButton); + ImGui::AlignTextToFramePadding(); + ImGui::Text("Cell contents:"); + ImGui::SameLine(); + ImGui::RadioButton("Text", &contents_type, CT_Text); + ImGui::SameLine(); + ImGui::RadioButton("FillButton", &contents_type, CT_FillButton); ImGui::Checkbox("Display headers", &display_headers); - ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers"); + ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); + ImGui::SameLine(); + HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers"); PopStyleCompact(); if (ImGui::BeginTable("table1", 3, flags)) { // Display headers so we can inspect their interaction with borders - // (Headers are not the main purpose of this section of the demo, so we are not elaborating on them now. See other sections for details) + // (Headers are not the main purpose of this section of the demo, so we are not elaborating on them now. See + // other sections for details) if (display_headers) { ImGui::TableSetupColumn("One"); @@ -5766,13 +6507,15 @@ static void DemoWindowTables() { // By default, if we don't enable ScrollX the sizing policy for each column is "Stretch" // All columns maintain a sizing weight, and they will occupy all available width. - static ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody; + static ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | + ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | + ImGuiTableFlags_ContextMenuInBody; PushStyleCompact(); ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV); - ImGui::SameLine(); HelpMarker( - "Using the _Resizable flag automatically enables the _BordersInnerV flag as well, " - "this is why the resize borders are still showing when unchecking this."); + ImGui::SameLine(); + HelpMarker("Using the _Resizable flag automatically enables the _BordersInnerV flag as well, " + "this is why the resize borders are still showing when unchecking this."); PopStyleCompact(); if (ImGui::BeginTable("table1", 3, flags)) @@ -5797,15 +6540,18 @@ static void DemoWindowTables() if (ImGui::TreeNode("Resizable, fixed")) { // Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set) - // So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small) - // If there is not enough available width to fit all columns, they will however be resized down. - // FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings - HelpMarker( - "Using _Resizable + _SizingFixedFit flags.\n" - "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n" - "Double-click a column border to auto-fit the column to its contents."); + // So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available + // width (unless table is small) If there is not enough available width to fit all columns, they will however be + // resized down. + // FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved + // settings + HelpMarker("Using _Resizable + _SizingFixedFit flags.\n" + "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n" + "Double-click a column border to auto-fit the column to its contents."); PushStyleCompact(); - static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody; + static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | + ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | + ImGuiTableFlags_ContextMenuInBody; ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX); PopStyleCompact(); @@ -5830,10 +6576,12 @@ static void DemoWindowTables() IMGUI_DEMO_MARKER("Tables/Resizable, mixed"); if (ImGui::TreeNode("Resizable, mixed")) { - HelpMarker( - "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n" - "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch."); - static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; + HelpMarker("Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n" + "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns " + "to use _WidthStretch."); + static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | + ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | + ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; if (ImGui::BeginTable("table1", 3, flags)) { @@ -5880,23 +6628,29 @@ static void DemoWindowTables() IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers"); if (ImGui::TreeNode("Reorderable, hideable, with headers")) { - HelpMarker( - "Click and drag column headers to reorder columns.\n\n" - "Right-click on a header to open a context menu."); - static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV; + HelpMarker("Click and drag column headers to reorder columns.\n\n" + "Right-click on a header to open a context menu."); + static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | + ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | + ImGuiTableFlags_BordersV; PushStyleCompact(); ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable); ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable); ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); - ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)"); + ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, + ImGuiTableFlags_NoBordersInBodyUntilResize); + ImGui::SameLine(); + HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in " + "Headers)"); ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn); PopStyleCompact(); if (ImGui::BeginTable("table1", 3, flags)) { - // Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column. - // (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.) + // Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in + // each column. (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight + // etc.) ImGui::TableSetupColumn("One"); ImGui::TableSetupColumn("Two"); ImGui::TableSetupColumn("Three"); @@ -5950,16 +6704,21 @@ static void DemoWindowTables() "Because of this, activating BorderOuterV sets the default to PadOuterX. " "Using PadOuterX or NoPadOuterX you can override the default.\n\n" "Actual padding values are using style.CellPadding.\n\n" - "In this demo we don't show horizontal borders to emphasize how they don't affect default horizontal padding."); + "In this demo we don't show horizontal borders to emphasize how they don't affect default horizontal " + "padding."); static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV; PushStyleCompact(); ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags1, ImGuiTableFlags_PadOuterX); - ImGui::SameLine(); HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)"); + ImGui::SameLine(); + HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)"); ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags1, ImGuiTableFlags_NoPadOuterX); - ImGui::SameLine(); HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)"); + ImGui::SameLine(); + HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)"); ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags1, ImGuiTableFlags_NoPadInnerX); - ImGui::SameLine(); HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)"); + ImGui::SameLine(); + HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner " + "padding if BordersOuterV is off)"); ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags1, ImGuiTableFlags_BordersOuterV); ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags1, ImGuiTableFlags_BordersInnerV); static bool show_headers = false; @@ -5992,8 +6751,8 @@ static void DemoWindowTables() sprintf(buf, "Hello %d,%d", column, row); ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); } - //if (ImGui::TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) - // ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, IM_COL32(0, 100, 0, 255)); + // if (ImGui::TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) + // ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, IM_COL32(0, 100, 0, 255)); } } ImGui::EndTable(); @@ -6050,13 +6809,16 @@ static void DemoWindowTables() IMGUI_DEMO_MARKER("Tables/Explicit widths"); if (ImGui::TreeNode("Sizing policies")) { - static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody; + static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | + ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody; PushStyleCompact(); ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable); ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags1, ImGuiTableFlags_NoHostExtendX); PopStyleCompact(); - static ImGuiTableFlags sizing_policy_flags[4] = { ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingFixedSame, ImGuiTableFlags_SizingStretchProp, ImGuiTableFlags_SizingStretchSame }; + static ImGuiTableFlags sizing_policy_flags[4] = { + ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingFixedSame, ImGuiTableFlags_SizingStretchProp, + ImGuiTableFlags_SizingStretchSame}; for (int table_n = 0; table_n < 4; table_n++) { ImGui::PushID(table_n); @@ -6071,9 +6833,12 @@ static void DemoWindowTables() for (int row = 0; row < 3; row++) { ImGui::TableNextRow(); - ImGui::TableNextColumn(); ImGui::Text("Oh dear"); - ImGui::TableNextColumn(); ImGui::Text("Oh dear"); - ImGui::TableNextColumn(); ImGui::Text("Oh dear"); + ImGui::TableNextColumn(); + ImGui::Text("Oh dear"); + ImGui::TableNextColumn(); + ImGui::Text("Oh dear"); + ImGui::TableNextColumn(); + ImGui::Text("Oh dear"); } ImGui::EndTable(); } @@ -6082,9 +6847,12 @@ static void DemoWindowTables() for (int row = 0; row < 3; row++) { ImGui::TableNextRow(); - ImGui::TableNextColumn(); ImGui::Text("AAAA"); - ImGui::TableNextColumn(); ImGui::Text("BBBBBBBB"); - ImGui::TableNextColumn(); ImGui::Text("CCCCCCCCCCCC"); + ImGui::TableNextColumn(); + ImGui::Text("AAAA"); + ImGui::TableNextColumn(); + ImGui::Text("BBBBBBBB"); + ImGui::TableNextColumn(); + ImGui::Text("CCCCCCCCCCCC"); } ImGui::EndTable(); } @@ -6094,12 +6862,20 @@ static void DemoWindowTables() ImGui::Spacing(); ImGui::TextUnformatted("Advanced"); ImGui::SameLine(); - HelpMarker( - "This section allows you to interact and see the effect of various sizing policies " - "depending on whether Scroll is enabled and the contents of your columns."); + HelpMarker("This section allows you to interact and see the effect of various sizing policies " + "depending on whether Scroll is enabled and the contents of your columns."); - enum ContentsType { CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText }; - static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable; + enum ContentsType + { + CT_ShowWidth, + CT_ShortText, + CT_LongText, + CT_Button, + CT_FillButton, + CT_InputText + }; + static ImGuiTableFlags flags = + ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable; static int contents_type = CT_ShowWidth; static int column_count = 3; @@ -6111,14 +6887,16 @@ static void DemoWindowTables() if (contents_type == CT_FillButton) { ImGui::SameLine(); - HelpMarker( - "Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop " - "where contents width can feed into auto-column width can feed into contents width."); + HelpMarker("Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop " + "where contents width can feed into auto-column width can feed into contents width."); } ImGui::DragInt("Columns", &column_count, 0.1f, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp); ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths); - ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth."); + ImGui::SameLine(); + HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table " + "with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of " + "columns, resizing will appear to be less smooth."); ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX); ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY); ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip); @@ -6140,12 +6918,25 @@ static void DemoWindowTables() sprintf(label, "Hello %d,%d", column, row); switch (contents_type) { - case CT_ShortText: ImGui::TextUnformatted(label); break; - case CT_LongText: ImGui::Text("Some %s text %d,%d\nOver two lines..", column == 0 ? "long" : "longeeer", column, row); break; - case CT_ShowWidth: ImGui::Text("W: %.1f", ImGui::GetContentRegionAvail().x); break; - case CT_Button: ImGui::Button(label); break; - case CT_FillButton: ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); break; - case CT_InputText: ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText("##", text_buf, IM_ARRAYSIZE(text_buf)); break; + case CT_ShortText: + ImGui::TextUnformatted(label); + break; + case CT_LongText: + ImGui::Text("Some %s text %d,%d\nOver two lines..", column == 0 ? "long" : "longeeer", column, row); + break; + case CT_ShowWidth: + ImGui::Text("W: %.1f", ImGui::GetContentRegionAvail().x); + break; + case CT_Button: + ImGui::Button(label); + break; + case CT_FillButton: + ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); + break; + case CT_InputText: + ImGui::SetNextItemWidth(-FLT_MIN); + ImGui::InputText("##", text_buf, IM_ARRAYSIZE(text_buf)); + break; } ImGui::PopID(); } @@ -6159,10 +6950,12 @@ static void DemoWindowTables() IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping"); if (ImGui::TreeNode("Vertical scrolling, with clipping")) { - HelpMarker( - "Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\n" - "We also demonstrate using ImGuiListClipper to virtualize the submission of many items."); - static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; + HelpMarker("Here we activate ScrollY, which will create a child window container to allow hosting scrollable " + "contents.\n\n" + "We also demonstrate using ImGuiListClipper to virtualize the submission of many items."); + static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | + ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | + ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; PushStyleCompact(); ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY); @@ -6204,13 +6997,16 @@ static void DemoWindowTables() IMGUI_DEMO_MARKER("Tables/Horizontal scrolling"); if (ImGui::TreeNode("Horizontal scrolling")) { - HelpMarker( - "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, " - "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n" - "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX, " - "because the container window won't automatically extend vertically to fix contents " - "(this may be improved in future versions)."); - static ImGuiTableFlags flags = ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; + HelpMarker("When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, " + "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n" + "Also note that as of the current version, you will almost always want to enable ScrollY along with " + "ScrollX, " + "because the container window won't automatically extend vertically to fix contents " + "(this may be improved in future versions)."); + static ImGuiTableFlags flags = ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | + ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | + ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | + ImGuiTableFlags_Hideable; static int freeze_cols = 1; static int freeze_rows = 1; @@ -6230,7 +7026,9 @@ static void DemoWindowTables() if (ImGui::BeginTable("table_scrollx", 7, flags, outer_size)) { ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows); - ImGui::TableSetupColumn("Line #", ImGuiTableColumnFlags_NoHide); // Make the first column not hideable to match our use of TableSetupScrollFreeze() + ImGui::TableSetupColumn("Line #", + ImGuiTableColumnFlags_NoHide); // Make the first column not hideable to match our + // use of TableSetupScrollFreeze() ImGui::TableSetupColumn("One"); ImGui::TableSetupColumn("Two"); ImGui::TableSetupColumn("Three"); @@ -6243,12 +7041,13 @@ static void DemoWindowTables() ImGui::TableNextRow(); for (int column = 0; column < 7; column++) { - // Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement. - // Because here we know that: + // Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or + // performing width measurement. Because here we know that: // - A) all our columns are contributing the same to row height // - B) column 0 is always visible, // We only always submit this one column and can skip others. - // More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags(). + // More advanced per-column clipping behaviors may benefit from polling the status flags via + // TableGetColumnFlags(). if (!ImGui::TableSetColumnIndex(column) && column > 0) continue; if (column == 0) @@ -6263,12 +7062,13 @@ static void DemoWindowTables() ImGui::Spacing(); ImGui::TextUnformatted("Stretch + ScrollX"); ImGui::SameLine(); - HelpMarker( - "Showcase using Stretch columns + ScrollX together: " - "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n" - "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns " - "along with ScrollX doesn't make sense."); - static ImGuiTableFlags flags2 = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody; + HelpMarker("Showcase using Stretch columns + ScrollX together: " + "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n" + "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns " + "along with ScrollX doesn't make sense."); + static ImGuiTableFlags flags2 = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_ScrollX | + ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | + ImGuiTableFlags_ContextMenuInBody; static float inner_width = 1000.0f; PushStyleCompact(); ImGui::PushID("flags3"); @@ -6297,9 +7097,10 @@ static void DemoWindowTables() { // Create a first table just to show all the options/flags we want to make visible in our example! const int column_count = 3; - const char* column_names[column_count] = { "One", "Two", "Three" }; - static ImGuiTableColumnFlags column_flags[column_count] = { ImGuiTableColumnFlags_DefaultSort, ImGuiTableColumnFlags_None, ImGuiTableColumnFlags_DefaultHide }; - static ImGuiTableColumnFlags column_flags_out[column_count] = { 0, 0, 0 }; // Output from TableGetColumnFlags() + const char *column_names[column_count] = {"One", "Two", "Three"}; + static ImGuiTableColumnFlags column_flags[column_count] = { + ImGuiTableColumnFlags_DefaultSort, ImGuiTableColumnFlags_None, ImGuiTableColumnFlags_DefaultHide}; + static ImGuiTableColumnFlags column_flags_out[column_count] = {0, 0, 0}; // Output from TableGetColumnFlags() if (ImGui::BeginTable("table_columns_flags_checkboxes", column_count, ImGuiTableFlags_None)) { @@ -6308,7 +7109,8 @@ static void DemoWindowTables() { ImGui::TableNextColumn(); ImGui::PushID(column); - ImGui::AlignTextToFramePadding(); // FIXME-TABLE: Workaround for wrong text baseline propagation across columns + ImGui::AlignTextToFramePadding(); // FIXME-TABLE: Workaround for wrong text baseline propagation across + // columns ImGui::Text("'%s'", column_names[column]); ImGui::Spacing(); ImGui::Text("Input flags:"); @@ -6325,13 +7127,14 @@ static void DemoWindowTables() } // Create the real table we care about for the example! - // We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above, - // otherwise in a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible + // We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags + // above, otherwise in a non-scrolling table columns are always visible (unless using + // ImGuiTableFlags_NoKeepColumnsVisible // + resizing the parent window down). - const ImGuiTableFlags flags - = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY - | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV - | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable; + const ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | + ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | + ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | + ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable; ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 9); if (ImGui::BeginTable("table_columns_flags", column_count, flags, outer_size)) { @@ -6375,11 +7178,13 @@ static void DemoWindowTables() static ImGuiTableFlags flags1 = ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBodyUntilResize; PushStyleCompact(); ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable); - ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags1, ImGuiTableFlags_NoBordersInBodyUntilResize); + ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags1, + ImGuiTableFlags_NoBordersInBodyUntilResize); PopStyleCompact(); if (ImGui::BeginTable("table1", 3, flags1)) { - // We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed. + // We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to + // ImGuiTableColumnFlags_WidthFixed. ImGui::TableSetupColumn("one", ImGuiTableColumnFlags_WidthFixed, 100.0f); // Default to 100.0f ImGui::TableSetupColumn("two", ImGuiTableColumnFlags_WidthFixed, 200.0f); // Default to 200.0f ImGui::TableSetupColumn("three", ImGuiTableColumnFlags_WidthFixed); // Default to auto @@ -6399,9 +7204,8 @@ static void DemoWindowTables() ImGui::EndTable(); } - HelpMarker( - "Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, " - "fixed columns with set width may still be shrunk down if there's not enough space in the host."); + HelpMarker("Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, " + "fixed columns with set width may still be shrunk down if there's not enough space in the host."); static ImGuiTableFlags flags2 = ImGuiTableFlags_None; PushStyleCompact(); @@ -6441,7 +7245,9 @@ static void DemoWindowTables() { HelpMarker("This demonstrates embedding a table into another table cell."); - if (ImGui::BeginTable("table_nested1", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) + if (ImGui::BeginTable("table_nested1", 2, + ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | + ImGuiTableFlags_Hideable)) { ImGui::TableSetupColumn("A0"); ImGui::TableSetupColumn("A1"); @@ -6451,7 +7257,9 @@ static void DemoWindowTables() ImGui::Text("A0 Row 0"); { float rows_height = TEXT_BASE_HEIGHT * 2; - if (ImGui::BeginTable("table_nested2", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) + if (ImGui::BeginTable("table_nested2", 2, + ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | + ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) { ImGui::TableSetupColumn("B0"); ImGui::TableSetupColumn("B1"); @@ -6471,9 +7279,12 @@ static void DemoWindowTables() ImGui::EndTable(); } } - ImGui::TableNextColumn(); ImGui::Text("A1 Row 0"); - ImGui::TableNextColumn(); ImGui::Text("A0 Row 1"); - ImGui::TableNextColumn(); ImGui::Text("A1 Row 1"); + ImGui::TableNextColumn(); + ImGui::Text("A1 Row 0"); + ImGui::TableNextColumn(); + ImGui::Text("A0 Row 1"); + ImGui::TableNextColumn(); + ImGui::Text("A1 Row 1"); ImGui::EndTable(); } ImGui::TreePop(); @@ -6484,10 +7295,10 @@ static void DemoWindowTables() IMGUI_DEMO_MARKER("Tables/Row height"); if (ImGui::TreeNode("Row height")) { - HelpMarker( - "You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, " - "so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\n" - "We cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row."); + HelpMarker("You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' " + "on top and bottom, " + "so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\n" + "We cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row."); if (ImGui::BeginTable("table_row_height", 1, ImGuiTableFlags_Borders)) { for (int row = 0; row < 8; row++) @@ -6500,10 +7311,9 @@ static void DemoWindowTables() ImGui::EndTable(); } - HelpMarker( - "Showcase using SameLine(0,0) to share Current Line Height between cells.\n\n" - "Please note that Tables Row Height is not the same thing as Current Line Height, " - "as a table cell may contains multiple lines."); + HelpMarker("Showcase using SameLine(0,0) to share Current Line Height between cells.\n\n" + "Please note that Tables Row Height is not the same thing as Current Line Height, " + "as a table cell may contains multiple lines."); if (ImGui::BeginTable("table_share_lineheight", 2, ImGuiTableFlags_Borders)) { ImGui::TableNextRow(); @@ -6524,10 +7334,11 @@ static void DemoWindowTables() ImGui::EndTable(); } - HelpMarker("Showcase altering CellPadding.y between rows. Note that CellPadding.x is locked for the entire table."); + HelpMarker( + "Showcase altering CellPadding.y between rows. Note that CellPadding.x is locked for the entire table."); if (ImGui::BeginTable("table_changing_cellpadding_y", 1, ImGuiTableFlags_Borders)) { - ImGuiStyle& style = ImGui::GetStyle(); + ImGuiStyle &style = ImGui::GetStyle(); for (int row = 0; row < 8; row++) { if ((row % 3) == 2) @@ -6553,11 +7364,18 @@ static void DemoWindowTables() // Important to that note how the two flags have slightly different behaviors! ImGui::Text("Using NoHostExtendX and NoHostExtendY:"); PushStyleCompact(); - static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_ContextMenuInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX; + static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | + ImGuiTableFlags_ContextMenuInBody | ImGuiTableFlags_RowBg | + ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX; ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX); - ImGui::SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used."); + ImGui::SameLine(); + HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when " + "ScrollX/ScrollY are disabled and Stretch columns are not used."); ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY); - ImGui::SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible."); + ImGui::SameLine(); + HelpMarker( + "Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly " + "available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible."); PopStyleCompact(); ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 5.5f); @@ -6580,7 +7398,8 @@ static void DemoWindowTables() ImGui::Spacing(); ImGui::Text("Using explicit size:"); - if (ImGui::BeginTable("table2", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f))) + if (ImGui::BeginTable("table2", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, + ImVec2(TEXT_BASE_WIDTH * 30, 0.0f))) { for (int row = 0; row < 5; row++) { @@ -6594,7 +7413,8 @@ static void DemoWindowTables() ImGui::EndTable(); } ImGui::SameLine(); - if (ImGui::BeginTable("table3", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f))) + if (ImGui::BeginTable("table3", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, + ImVec2(TEXT_BASE_WIDTH * 30, 0.0f))) { for (int row = 0; row < 3; row++) { @@ -6624,10 +7444,15 @@ static void DemoWindowTables() PushStyleCompact(); ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders); ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg); - ImGui::SameLine(); HelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style."); - ImGui::Combo("row bg type", (int*)&row_bg_type, "None\0Red\0Gradient\0"); - ImGui::Combo("row bg target", (int*)&row_bg_target, "RowBg0\0RowBg1\0"); ImGui::SameLine(); HelpMarker("Target RowBg0 to override the alternating odd/even colors,\nTarget RowBg1 to blend with them."); - ImGui::Combo("cell bg type", (int*)&cell_bg_type, "None\0Blue\0"); ImGui::SameLine(); HelpMarker("We are colorizing cells to B1->C2 here."); + ImGui::SameLine(); + HelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style."); + ImGui::Combo("row bg type", (int *)&row_bg_type, "None\0Red\0Gradient\0"); + ImGui::Combo("row bg target", (int *)&row_bg_target, "RowBg0\0RowBg1\0"); + ImGui::SameLine(); + HelpMarker("Target RowBg0 to override the alternating odd/even colors,\nTarget RowBg1 to blend with them."); + ImGui::Combo("cell bg type", (int *)&cell_bg_type, "None\0Blue\0"); + ImGui::SameLine(); + HelpMarker("We are colorizing cells to B1->C2 here."); IM_ASSERT(row_bg_type >= 0 && row_bg_type <= 2); IM_ASSERT(row_bg_target >= 0 && row_bg_target <= 1); IM_ASSERT(cell_bg_type >= 0 && cell_bg_type <= 1); @@ -6639,11 +7464,14 @@ static void DemoWindowTables() { ImGui::TableNextRow(); - // Demonstrate setting a row background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBgX, ...)' - // We use a transparent color so we can see the one behind in case our target is RowBg1 and RowBg0 was already targeted by the ImGuiTableFlags_RowBg flag. + // Demonstrate setting a row background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBgX, + // ...)' We use a transparent color so we can see the one behind in case our target is RowBg1 and RowBg0 + // was already targeted by the ImGuiTableFlags_RowBg flag. if (row_bg_type != 0) { - ImU32 row_bg_color = ImGui::GetColorU32(row_bg_type == 1 ? ImVec4(0.7f, 0.3f, 0.3f, 0.65f) : ImVec4(0.2f + row * 0.1f, 0.2f, 0.2f, 0.65f)); // Flat or Gradient? + ImU32 row_bg_color = ImGui::GetColorU32( + row_bg_type == 1 ? ImVec4(0.7f, 0.3f, 0.3f, 0.65f) + : ImVec4(0.2f + row * 0.1f, 0.2f, 0.2f, 0.65f)); // Flat or Gradient? ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0 + row_bg_target, row_bg_color); } @@ -6654,9 +7482,10 @@ static void DemoWindowTables() ImGui::Text("%c%c", 'A' + row, '0' + column); // Change background of Cells B1->C2 - // Demonstrate setting a cell background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ...)' - // (the CellBg color will be blended over the RowBg and ColumnBg colors) - // We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop. + // Demonstrate setting a cell background color with + // 'ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ...)' (the CellBg color will be blended over + // the RowBg and ColumnBg colors) We can also pass a column number as a third parameter to + // TableSetBgColor() and do this outside the column loop. if (row >= 1 && row <= 2 && column >= 1 && column <= 2 && cell_bg_type == 1) { ImU32 cell_bg_color = ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.7f, 0.65f)); @@ -6674,19 +7503,28 @@ static void DemoWindowTables() IMGUI_DEMO_MARKER("Tables/Tree view"); if (ImGui::TreeNode("Tree view")) { - static ImGuiTableFlags table_flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody; + static ImGuiTableFlags table_flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | + ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | + ImGuiTableFlags_NoBordersInBody; - static ImGuiTreeNodeFlags tree_node_flags_base = ImGuiTreeNodeFlags_SpanAllColumns | ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_DrawLinesFull; - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanFullWidth); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanLabelWidth); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanAllColumns); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_LabelSpanAllColumns", &tree_node_flags_base, ImGuiTreeNodeFlags_LabelSpanAllColumns); - ImGui::SameLine(); HelpMarker("Useful if you know that you aren't displaying contents in other columns"); + static ImGuiTreeNodeFlags tree_node_flags_base = + ImGuiTreeNodeFlags_SpanAllColumns | ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_DrawLinesFull; + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags_base, + ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", &tree_node_flags_base, + ImGuiTreeNodeFlags_SpanLabelWidth); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags_base, + ImGuiTreeNodeFlags_SpanAllColumns); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_LabelSpanAllColumns", &tree_node_flags_base, + ImGuiTreeNodeFlags_LabelSpanAllColumns); + ImGui::SameLine(); + HelpMarker("Useful if you know that you aren't displaying contents in other columns"); HelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns."); if (ImGui::BeginTable("3ways", 3, table_flags)) { - // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On + // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is + // On ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide); ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f); ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f); @@ -6695,12 +7533,12 @@ static void DemoWindowTables() // Simple storage to output a dummy file-system. struct MyTreeNode { - const char* Name; - const char* Type; - int Size; - int ChildIdx; - int ChildCount; - static void DisplayNode(const MyTreeNode* node, const MyTreeNode* all_nodes) + const char *Name; + const char *Type; + int Size; + int ChildIdx; + int ChildCount; + static void DisplayNode(const MyTreeNode *node, const MyTreeNode *all_nodes) { ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -6708,7 +7546,8 @@ static void DemoWindowTables() ImGuiTreeNodeFlags node_flags = tree_node_flags_base; if (node != &all_nodes[0]) - node_flags &= ~ImGuiTreeNodeFlags_LabelSpanAllColumns; // Only demonstrate this on the root node. + node_flags &= + ~ImGuiTreeNodeFlags_LabelSpanAllColumns; // Only demonstrate this on the root node. if (is_folder) { @@ -6729,7 +7568,8 @@ static void DemoWindowTables() } else { - ImGui::TreeNodeEx(node->Name, node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen); + ImGui::TreeNodeEx(node->Name, node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | + ImGuiTreeNodeFlags_NoTreePushOnOpen); ImGui::TableNextColumn(); ImGui::Text("%d", node->Size); ImGui::TableNextColumn(); @@ -6737,17 +7577,16 @@ static void DemoWindowTables() } } }; - static const MyTreeNode nodes[] = - { - { "Root with Long Name", "Folder", -1, 1, 3 }, // 0 - { "Music", "Folder", -1, 4, 2 }, // 1 - { "Textures", "Folder", -1, 6, 3 }, // 2 - { "desktop.ini", "System file", 1024, -1,-1 }, // 3 - { "File1_a.wav", "Audio file", 123000, -1,-1 }, // 4 - { "File1_b.wav", "Audio file", 456000, -1,-1 }, // 5 - { "Image001.png", "Image file", 203128, -1,-1 }, // 6 - { "Copy of Image001.png", "Image file", 203256, -1,-1 }, // 7 - { "Copy of Image001 (Final2).png","Image file", 203512, -1,-1 }, // 8 + static const MyTreeNode nodes[] = { + {"Root with Long Name", "Folder", -1, 1, 3}, // 0 + {"Music", "Folder", -1, 4, 2}, // 1 + {"Textures", "Folder", -1, 6, 3}, // 2 + {"desktop.ini", "System file", 1024, -1, -1}, // 3 + {"File1_a.wav", "Audio file", 123000, -1, -1}, // 4 + {"File1_b.wav", "Audio file", 456000, -1, -1}, // 5 + {"Image001.png", "Image file", 203128, -1, -1}, // 6 + {"Copy of Image001.png", "Image file", 203256, -1, -1}, // 7 + {"Copy of Image001 (Final2).png", "Image file", 203512, -1, -1}, // 8 }; MyTreeNode::DisplayNode(&nodes[0], nodes); @@ -6762,10 +7601,9 @@ static void DemoWindowTables() IMGUI_DEMO_MARKER("Tables/Item width"); if (ImGui::TreeNode("Item width")) { - HelpMarker( - "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n" - "Note that on auto-resizing non-resizable fixed columns, querying the content width for " - "e.g. right-alignment doesn't make sense."); + HelpMarker("Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n" + "Note that on auto-resizing non-resizable fixed columns, querying the content width for " + "e.g. right-alignment doesn't make sense."); if (ImGui::BeginTable("table_item_width", 3, ImGuiTableFlags_Borders)) { ImGui::TableSetupColumn("small"); @@ -6778,7 +7616,8 @@ static void DemoWindowTables() ImGui::TableNextRow(); if (row == 0) { - // Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient) + // Setup ItemWidth once (instead of setting up every time, which is also possible but less + // efficient) ImGui::TableSetColumnIndex(0); ImGui::PushItemWidth(TEXT_BASE_WIDTH * 3.0f); // Small ImGui::TableSetColumnIndex(1); @@ -6810,7 +7649,8 @@ static void DemoWindowTables() if (ImGui::TreeNode("Custom headers")) { const int COLUMNS_COUNT = 3; - if (ImGui::BeginTable("table_custom_headers", COLUMNS_COUNT, ImGuiTableFlags_Borders | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) + if (ImGui::BeginTable("table_custom_headers", COLUMNS_COUNT, + ImGuiTableFlags_Borders | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) { ImGui::TableSetupColumn("Apricot"); ImGui::TableSetupColumn("Banana"); @@ -6824,12 +7664,14 @@ static void DemoWindowTables() // (A different approach is also possible: // - Specify ImGuiTableColumnFlags_NoHeaderLabel in some TableSetupColumn() call. // - Call TableHeadersRow() normally. This will submit TableHeader() with no name. - // - Then call TableSetColumnIndex() to position yourself in the column and submit your stuff e.g. Checkbox().) + // - Then call TableSetColumnIndex() to position yourself in the column and submit your stuff e.g. + // Checkbox().) ImGui::TableNextRow(ImGuiTableRowFlags_Headers); for (int column = 0; column < COLUMNS_COUNT; column++) { ImGui::TableSetColumnIndex(column); - const char* column_name = ImGui::TableGetColumnName(column); // Retrieve name passed to TableSetupColumn() + const char *column_name = + ImGui::TableGetColumnName(column); // Retrieve name passed to TableSetupColumn() ImGui::PushID(column); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); ImGui::Checkbox("##checkall", &column_selected[column]); @@ -6862,12 +7704,17 @@ static void DemoWindowTables() IMGUI_DEMO_MARKER("Tables/Angled headers"); if (ImGui::TreeNode("Angled headers")) { - const char* column_names[] = { "Track", "cabasa", "ride", "smash", "tom-hi", "tom-mid", "tom-low", "hihat-o", "hihat-c", "snare-s", "snare-c", "clap", "rim", "kick" }; + const char *column_names[] = {"Track", "cabasa", "ride", "smash", "tom-hi", "tom-mid", "tom-low", + "hihat-o", "hihat-c", "snare-s", "snare-c", "clap", "rim", "kick"}; const int columns_count = IM_ARRAYSIZE(column_names); const int rows_count = 12; - static ImGuiTableFlags table_flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_Hideable | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_HighlightHoveredColumn; - static ImGuiTableColumnFlags column_flags = ImGuiTableColumnFlags_AngledHeader | ImGuiTableColumnFlags_WidthFixed; + static ImGuiTableFlags table_flags = + ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | + ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_Hideable | + ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_HighlightHoveredColumn; + static ImGuiTableColumnFlags column_flags = + ImGuiTableColumnFlags_AngledHeader | ImGuiTableColumnFlags_WidthFixed; static bool bools[columns_count * rows_count] = {}; // Dummy storage selection storage static int frozen_cols = 1; static int frozen_rows = 2; @@ -6881,16 +7728,19 @@ static void DemoWindowTables() ImGui::SliderInt("Frozen columns", &frozen_cols, 0, 2); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); ImGui::SliderInt("Frozen rows", &frozen_rows, 0, 2); - ImGui::CheckboxFlags("Disable header contributing to column width", &column_flags, ImGuiTableColumnFlags_NoHeaderWidth); + ImGui::CheckboxFlags("Disable header contributing to column width", &column_flags, + ImGuiTableColumnFlags_NoHeaderWidth); if (ImGui::TreeNode("Style settings")) { ImGui::SameLine(); HelpMarker("Giving access to some ImGuiStyle value in this demo for convenience."); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); - ImGui::SliderAngle("style.TableAngledHeadersAngle", &ImGui::GetStyle().TableAngledHeadersAngle, -50.0f, +50.0f); + ImGui::SliderAngle("style.TableAngledHeadersAngle", &ImGui::GetStyle().TableAngledHeadersAngle, -50.0f, + +50.0f); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); - ImGui::SliderFloat2("style.TableAngledHeadersTextAlign", (float*)&ImGui::GetStyle().TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f"); + ImGui::SliderFloat2("style.TableAngledHeadersTextAlign", + (float *)&ImGui::GetStyle().TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::TreePop(); } @@ -6901,8 +7751,9 @@ static void DemoWindowTables() ImGui::TableSetupColumn(column_names[n], column_flags); ImGui::TableSetupScrollFreeze(frozen_cols, frozen_rows); - ImGui::TableAngledHeadersRow(); // Draw angled headers for all columns with the ImGuiTableColumnFlags_AngledHeader flag. - ImGui::TableHeadersRow(); // Draw remaining headers and allow access to context-menu and other functions. + ImGui::TableAngledHeadersRow(); // Draw angled headers for all columns with the + // ImGuiTableColumnFlags_AngledHeader flag. + ImGui::TableHeadersRow(); // Draw remaining headers and allow access to context-menu and other functions. for (int row = 0; row < rows_count; row++) { ImGui::PushID(row); @@ -6931,10 +7782,12 @@ static void DemoWindowTables() IMGUI_DEMO_MARKER("Tables/Context menus"); if (ImGui::TreeNode("Context menus")) { - HelpMarker( - "By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\n" - "Using ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body."); - static ImGuiTableFlags flags1 = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_ContextMenuInBody; + HelpMarker("By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default " + "context-menu.\n" + "Using ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body."); + static ImGuiTableFlags flags1 = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | + ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | + ImGuiTableFlags_ContextMenuInBody; PushStyleCompact(); ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags1, ImGuiTableFlags_ContextMenuInBody); @@ -6942,7 +7795,8 @@ static void DemoWindowTables() // Context Menus: first example // [1.1] Right-click on the TableHeadersRow() line to open the default table context menu. - // [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set) + // [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody + // is set) const int COLUMNS_COUNT = 3; if (ImGui::BeginTable("table_context_menu", COLUMNS_COUNT, flags1)) { @@ -6970,10 +7824,10 @@ static void DemoWindowTables() // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. // [2.2] Right-click on the ".." to open a custom popup // [2.3] Right-click in columns to open another custom popup - HelpMarker( - "Demonstrate mixing table context menu (over header), item context button (over button) " - "and custom per-colunm context menu (over column body)."); - ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders; + HelpMarker("Demonstrate mixing table context menu (over header), item context button (over button) " + "and custom per-colunm context menu (over column body)."); + ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | + ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders; if (ImGui::BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2)) { ImGui::TableSetupColumn("One"); @@ -7007,8 +7861,9 @@ static void DemoWindowTables() } // [2.3] Right-click anywhere in columns to open another custom popup - // (instead of testing for !IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup - // to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping) + // (instead of testing for !IsAnyItemHovered() we could also call OpenPopup() with + // ImGuiPopupFlags_NoOpenOverExistingPopup to manage popup priority as the popups triggers, here "are we + // hovering a column" are overlapping) int hovered_column = -1; for (int column = 0; column < COLUMNS_COUNT + 1; column++) { @@ -7044,7 +7899,9 @@ static void DemoWindowTables() { HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc."); - static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings; + static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | + ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | + ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings; ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY); ImGui::CheckboxFlags("ImGuiTableFlags_SizingFixedFit", &flags, ImGuiTableFlags_SizingFixedFit); @@ -7060,7 +7917,8 @@ static void DemoWindowTables() ImGui::TableSetupColumn("Two"); ImGui::TableSetupColumn("Three"); ImGui::TableHeadersRow(); - const int cell_count = (n == 1) ? 27 : 9; // Make second table have a scrollbar to verify that additional decoration is not affecting column positions. + const int cell_count = (n == 1) ? 27 : 9; // Make second table have a scrollbar to verify that + // additional decoration is not affecting column positions. for (int cell = 0; cell < cell_count; cell++) { ImGui::TableNextColumn(); @@ -7073,13 +7931,12 @@ static void DemoWindowTables() } // Demonstrate using Sorting facilities - // This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting. - // Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified) - static const char* template_items_names[] = - { - "Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango", - "Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot" - }; + // This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle + // sorting. Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have + // been modified) + static const char *template_items_names[] = {"Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", + "Strawberry", "Mango", "Kiwi", "Orange", "Pineapple", + "Blueberry", "Plum", "Coconut", "Pear", "Apricot"}; if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); IMGUI_DEMO_MARKER("Tables/Sorting"); @@ -7093,7 +7950,7 @@ static void DemoWindowTables() for (int n = 0; n < items.Size; n++) { const int template_n = n % IM_ARRAYSIZE(template_items_names); - MyItem& item = items[n]; + MyItem &item = items[n]; item.ID = n; item.Name = template_items_names[template_n]; item.Quantity = (n * n - n) % 20; // Assign default quantities @@ -7101,35 +7958,45 @@ static void DemoWindowTables() } // Options - static ImGuiTableFlags flags = - ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti - | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody - | ImGuiTableFlags_ScrollY; + static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | + ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti | + ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | + ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_ScrollY; PushStyleCompact(); ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti); - ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1)."); + ImGui::SameLine(); + HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. " + "TableGetSortSpecs() may return specs where (SpecsCount > 1)."); ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate); - ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0)."); + ImGui::SameLine(); + HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return " + "specs where (SpecsCount == 0)."); PopStyleCompact(); if (ImGui::BeginTable("table_sorting", 4, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 15), 0.0f)) { // Declare columns - // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. - // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! - // Demonstrate using a mixture of flags among available sort-related flags: + // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort + // specifications. This is so our sort function can identify a column given our own identifier. We could + // also identify them based on their index! Demonstrate using a mixture of flags among available + // sort-related flags: // - ImGuiTableColumnFlags_DefaultSort - // - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending + // - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / + // ImGuiTableColumnFlags_NoSortDescending // - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending - ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_ID); - ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name); - ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action); - ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Quantity); + ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, + MyItemColumnID_ID); + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name); + ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, + MyItemColumnID_Action); + ImGui::TableSetupColumn("Quantity", + ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, + 0.0f, MyItemColumnID_Quantity); ImGui::TableSetupScrollFreeze(0, 1); // Make row always visible ImGui::TableHeadersRow(); // Sort our data if sort specs have been changed! - if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs()) + if (ImGuiTableSortSpecs *sort_specs = ImGui::TableGetSortSpecs()) if (sort_specs->SpecsDirty) { MyItem::SortWithSortSpecs(sort_specs, items.Data, items.Size); @@ -7143,7 +8010,7 @@ static void DemoWindowTables() for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++) { // Display a data item - MyItem* item = &items[row_n]; + MyItem *item = &items[row_n]; ImGui::PushID(item->ID); ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -7164,34 +8031,43 @@ static void DemoWindowTables() // 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] + // ImGui::SetNextItemOpen(true, ImGuiCond_Once); // [DEBUG] if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); IMGUI_DEMO_MARKER("Tables/Advanced"); if (ImGui::TreeNode("Advanced")) { - static ImGuiTableFlags flags = - ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable - | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti - | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody - | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY - | ImGuiTableFlags_SizingFixedFit; + static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | + ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti | + ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | + ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_ScrollX | + ImGuiTableFlags_ScrollY | ImGuiTableFlags_SizingFixedFit; static ImGuiTableColumnFlags columns_base_flags = ImGuiTableColumnFlags_None; - enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow }; + enum ContentsType + { + CT_Text, + CT_Button, + CT_SmallButton, + CT_FillButton, + CT_Selectable, + CT_SelectableSpanRow + }; static int contents_type = CT_SelectableSpanRow; - const char* contents_type_names[] = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" }; + const char *contents_type_names[] = {"Text", "Button", "SmallButton", + "FillButton", "Selectable", "Selectable (span row)"}; static int freeze_cols = 1; static int freeze_rows = 1; static int items_count = IM_ARRAYSIZE(template_items_names) * 2; static ImVec2 outer_size_value = ImVec2(0.0f, TEXT_BASE_HEIGHT * 12); - static float row_min_height = 0.0f; // Auto + static float row_min_height = 0.0f; // Auto static float inner_width_with_scroll = 0.0f; // Auto-extend static bool outer_size_enabled = true; static bool show_headers = true; static bool show_wrapped_text = false; - //static ImGuiTextFilter filter; - //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affect column sizing + // static ImGuiTextFilter filter; + // ImGui::SetNextItemOpen(true, ImGuiCond_Once); // FIXME-TABLE: Enabling this results in initial clipped first + // pass on table which tend to affect column sizing if (ImGui::TreeNode("Options")) { // Make the UI compact because there are so many fields @@ -7218,25 +8094,46 @@ static void DemoWindowTables() ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH); ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH); ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH); - ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers"); - ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)"); + ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); + ImGui::SameLine(); + HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers"); + ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, + ImGuiTableFlags_NoBordersInBodyUntilResize); + ImGui::SameLine(); + HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always " + "appear in Headers)"); ImGui::TreePop(); } if (ImGui::TreeNodeEx("Sizing:", ImGuiTreeNodeFlags_DefaultOpen)) { EditTableSizingFlags(&flags); - ImGui::SameLine(); HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical."); + ImGui::SameLine(); + HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings " + "have less effect that typical."); ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX); - ImGui::SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used."); + ImGui::SameLine(); + HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available " + "when ScrollX/ScrollY are disabled and Stretch columns are not used."); ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY); - ImGui::SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible."); - ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible); - ImGui::SameLine(); HelpMarker("Only available if ScrollX is disabled."); + ImGui::SameLine(); + HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the " + "limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be " + "clipped and not visible."); + ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, + ImGuiTableFlags_NoKeepColumnsVisible); + ImGui::SameLine(); + HelpMarker("Only available if ScrollX is disabled."); ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths); - ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth."); + ImGui::SameLine(); + HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide " + "table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger " + "number of columns, resizing will appear to be less smooth."); ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip); - ImGui::SameLine(); HelpMarker("Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with ScrollFreeze options."); + ImGui::SameLine(); + HelpMarker( + "Disable clipping rectangle for every individual columns (reduce draw command count, items will be " + "able to overflow into other columns). Generally incompatible with ScrollFreeze options."); ImGui::TreePop(); } @@ -7264,18 +8161,26 @@ static void DemoWindowTables() if (ImGui::TreeNodeEx("Sorting:", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti); - ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1)."); + ImGui::SameLine(); + HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. " + "TableGetSortSpecs() may return specs where (SpecsCount > 1)."); ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate); - ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0)."); + ImGui::SameLine(); + HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() " + "may return specs where (SpecsCount == 0)."); ImGui::TreePop(); } if (ImGui::TreeNodeEx("Headers:", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::Checkbox("show_headers", &show_headers); - ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn); - ImGui::CheckboxFlags("ImGuiTableColumnFlags_AngledHeader", &columns_base_flags, ImGuiTableColumnFlags_AngledHeader); - ImGui::SameLine(); HelpMarker("Enable AngledHeader on all columns. Best enabled on selected narrow columns (see \"Angled headers\" section of the demo)."); + ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, + ImGuiTableFlags_HighlightHoveredColumn); + ImGui::CheckboxFlags("ImGuiTableColumnFlags_AngledHeader", &columns_base_flags, + ImGuiTableColumnFlags_AngledHeader); + ImGui::SameLine(); + HelpMarker("Enable AngledHeader on all columns. Best enabled on selected narrow columns (see \"Angled " + "headers\" section of the demo)."); ImGui::TreePop(); } @@ -7288,21 +8193,25 @@ static void DemoWindowTables() ImGui::Checkbox("outer_size", &outer_size_enabled); ImGui::SameLine(); HelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n" - "- The table is output directly in the parent window.\n" - "- OuterSize.x < 0.0f will right-align the table.\n" - "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch columns.\n" - "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set)."); + "- The table is output directly in the parent window.\n" + "- OuterSize.x < 0.0f will right-align the table.\n" + "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch columns.\n" + "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if " + "there are more rows (unless NoHostExtendY is set)."); - // From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling. - // To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled. + // From a user point of view we will tend to use 'inner_width' differently depending on whether our + // table is embedding scrolling. To facilitate toying with this demo we will actually pass 0.0f to the + // BeginTable() when ScrollX is disabled. ImGui::DragFloat("inner_width (when ScrollX active)", &inner_width_with_scroll, 1.0f, 0.0f, FLT_MAX); ImGui::DragFloat("row_min_height", &row_min_height, 1.0f, 0.0f, FLT_MAX); - ImGui::SameLine(); HelpMarker("Specify height of the Selectable item."); + ImGui::SameLine(); + HelpMarker("Specify height of the Selectable item."); ImGui::DragInt("items_count", &items_count, 0.1f, 0, 9999); - ImGui::Combo("items_type (first column)", &contents_type, contents_type_names, IM_ARRAYSIZE(contents_type_names)); - //filter.Draw("filter"); + ImGui::Combo("items_type (first column)", &contents_type, contents_type_names, + IM_ARRAYSIZE(contents_type_names)); + // filter.Draw("filter"); ImGui::TreePop(); } @@ -7322,35 +8231,48 @@ static void DemoWindowTables() for (int n = 0; n < items_count; n++) { const int template_n = n % IM_ARRAYSIZE(template_items_names); - MyItem& item = items[n]; + MyItem &item = items[n]; item.ID = n; item.Name = template_items_names[template_n]; item.Quantity = (template_n == 3) ? 10 : (template_n == 4) ? 20 : 0; // Assign default quantities } } - const ImDrawList* parent_draw_list = ImGui::GetWindowDrawList(); + const ImDrawList *parent_draw_list = ImGui::GetWindowDrawList(); const int parent_draw_list_draw_cmd_count = parent_draw_list->CmdBuffer.Size; ImVec2 table_scroll_cur, table_scroll_max; // For debug display - const ImDrawList* table_draw_list = NULL; // " + 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)) + if (ImGui::BeginTable("table_advanced", 6, flags, outer_size_enabled ? outer_size_value : ImVec2(0, 0), + inner_width_to_use)) { // Declare columns - // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. - // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! - ImGui::TableSetupColumn("ID", columns_base_flags | ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, 0.0f, MyItemColumnID_ID); - ImGui::TableSetupColumn("Name", columns_base_flags | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name); - ImGui::TableSetupColumn("Action", columns_base_flags | ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action); - ImGui::TableSetupColumn("Quantity", columns_base_flags | ImGuiTableColumnFlags_PreferSortDescending, 0.0f, MyItemColumnID_Quantity); - ImGui::TableSetupColumn("Description", columns_base_flags | ((flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch), 0.0f, MyItemColumnID_Description); - ImGui::TableSetupColumn("Hidden", columns_base_flags | ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort); + // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort + // specifications. This is so our sort function can identify a column given our own identifier. We could + // also identify them based on their index! + ImGui::TableSetupColumn("ID", + columns_base_flags | ImGuiTableColumnFlags_DefaultSort | + ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, + 0.0f, MyItemColumnID_ID); + ImGui::TableSetupColumn("Name", columns_base_flags | ImGuiTableColumnFlags_WidthFixed, 0.0f, + MyItemColumnID_Name); + ImGui::TableSetupColumn( + "Action", columns_base_flags | ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, + MyItemColumnID_Action); + ImGui::TableSetupColumn("Quantity", columns_base_flags | ImGuiTableColumnFlags_PreferSortDescending, 0.0f, + MyItemColumnID_Quantity); + ImGui::TableSetupColumn( + "Description", + columns_base_flags | ((flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch), + 0.0f, MyItemColumnID_Description); + ImGui::TableSetupColumn("Hidden", columns_base_flags | ImGuiTableColumnFlags_DefaultHide | + ImGuiTableColumnFlags_NoSort); ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows); // Sort our data if sort specs have been changed! - ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs(); + ImGuiTableSortSpecs *sort_specs = ImGui::TableGetSortSpecs(); if (sort_specs && sort_specs->SpecsDirty) items_need_sort = true; if (sort_specs && items_need_sort && items.Size > 1) @@ -7362,7 +8284,8 @@ static void DemoWindowTables() // Take note of whether we are currently sorting based on the Quantity field, // we will use this to trigger sorting when we know the data of this column has been modified. - const bool sorts_specs_using_quantity = (ImGui::TableGetColumnFlags(3) & ImGuiTableColumnFlags_IsSorted) != 0; + const bool sorts_specs_using_quantity = + (ImGui::TableGetColumnFlags(3) & ImGuiTableColumnFlags_IsSorted) != 0; // Show headers if (show_headers && (columns_base_flags & ImGuiTableColumnFlags_AngledHeader) != 0) @@ -7385,9 +8308,9 @@ static void DemoWindowTables() for (int row_n = 0; row_n < items.Size; row_n++) #endif { - MyItem* item = &items[row_n]; - //if (!filter.PassFilter(item->Name)) - // continue; + MyItem *item = &items[row_n]; + // if (!filter.PassFilter(item->Name)) + // continue; const bool item_is_selected = selection.contains(item->ID); ImGui::PushID(item->ID); @@ -7407,7 +8330,10 @@ static void DemoWindowTables() ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); else if (contents_type == CT_Selectable || contents_type == CT_SelectableSpanRow) { - ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap : ImGuiSelectableFlags_None; + ImGuiSelectableFlags selectable_flags = + (contents_type == CT_SelectableSpanRow) + ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap + : ImGuiSelectableFlags_None; if (ImGui::Selectable(label, item_is_selected, selectable_flags, ImVec2(0, row_min_height))) { if (ImGui::GetIO().KeyCtrl) @@ -7430,15 +8356,28 @@ static void DemoWindowTables() // 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 some extra logic if you want to automatically sort when a specific entry changes. + // To avoid triggering a sort while holding the button, we only trigger it when the button has been + // released. You will probably need some extra logic if you want to automatically sort when a + // specific entry changes. if (ImGui::TableSetColumnIndex(2)) { - if (ImGui::SmallButton("Chop")) { item->Quantity += 1; } - if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; } + if (ImGui::SmallButton("Chop")) + { + item->Quantity += 1; + } + if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) + { + items_need_sort = true; + } ImGui::SameLine(); - if (ImGui::SmallButton("Eat")) { item->Quantity -= 1; } - if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; } + if (ImGui::SmallButton("Eat")) + { + item->Quantity -= 1; + } + if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) + { + items_need_sort = true; + } } if (ImGui::TableSetColumnIndex(3)) @@ -7471,10 +8410,11 @@ static void DemoWindowTables() const int table_draw_list_draw_cmd_count = table_draw_list->CmdBuffer.Size; if (table_draw_list == parent_draw_list) ImGui::Text(": DrawCmd: +%d (in same window)", - table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count); + table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count); else ImGui::Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)", - table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y); + table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, + table_scroll_cur.y, table_scroll_max.y); } ImGui::TreePop(); } @@ -7503,14 +8443,16 @@ static void DemoWindowColumns() if (ImGui::TreeNode("Basic")) { ImGui::Text("Without border:"); - ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border + ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border ImGui::Separator(); for (int n = 0; n < 14; n++) { char label[32]; sprintf(label, "Item %d", n); - if (ImGui::Selectable(label)) {} - //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {} + if (ImGui::Selectable(label)) + { + } + // if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {} ImGui::NextColumn(); } ImGui::Columns(1); @@ -7519,13 +8461,17 @@ static void DemoWindowColumns() ImGui::Text("With border:"); ImGui::Columns(4, "mycolumns"); // 4-ways, with border ImGui::Separator(); - ImGui::Text("ID"); ImGui::NextColumn(); - ImGui::Text("Name"); ImGui::NextColumn(); - ImGui::Text("Path"); ImGui::NextColumn(); - ImGui::Text("Hovered"); ImGui::NextColumn(); + ImGui::Text("ID"); + ImGui::NextColumn(); + ImGui::Text("Name"); + ImGui::NextColumn(); + ImGui::Text("Path"); + ImGui::NextColumn(); + ImGui::Text("Hovered"); + ImGui::NextColumn(); ImGui::Separator(); - const char* names[3] = { "One", "Two", "Three" }; - const char* paths[3] = { "/path/one", "/path/two", "/path/three" }; + const char *names[3] = {"One", "Two", "Three"}; + const char *paths[3] = {"/path/one", "/path/two", "/path/three"}; static int selected = -1; for (int i = 0; i < 3; i++) { @@ -7535,9 +8481,12 @@ static void DemoWindowColumns() selected = i; bool hovered = ImGui::IsItemHovered(); ImGui::NextColumn(); - ImGui::Text(names[i]); ImGui::NextColumn(); - ImGui::Text(paths[i]); ImGui::NextColumn(); - ImGui::Text("%d", hovered); ImGui::NextColumn(); + ImGui::Text(names[i]); + ImGui::NextColumn(); + ImGui::Text(paths[i]); + ImGui::NextColumn(); + ImGui::Text("%d", hovered); + ImGui::NextColumn(); } ImGui::Columns(1); ImGui::Separator(); @@ -7605,9 +8554,21 @@ static void DemoWindowColumns() ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f"); ImGui::NextColumn(); - if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); - if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); - if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); + if (ImGui::CollapsingHeader("Category A")) + { + ImGui::Text("Blah blah blah"); + } + ImGui::NextColumn(); + if (ImGui::CollapsingHeader("Category B")) + { + ImGui::Text("Blah blah blah"); + } + ImGui::NextColumn(); + if (ImGui::CollapsingHeader("Category C")) + { + ImGui::Text("Blah blah blah"); + } + ImGui::NextColumn(); ImGui::Columns(1); ImGui::Separator(); ImGui::TreePop(); @@ -7661,7 +8622,7 @@ static void DemoWindowColumns() ImGui::Columns(2, "tree", true); for (int x = 0; x < 3; x++) { - bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x); + bool open1 = ImGui::TreeNode((void *)(intptr_t)x, "Node%d", x); ImGui::NextColumn(); ImGui::Text("Node contents"); ImGui::NextColumn(); @@ -7669,7 +8630,7 @@ static void DemoWindowColumns() { for (int y = 0; y < 3; y++) { - bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y); + bool open2 = ImGui::TreeNode((void *)(intptr_t)y, "Node%d.%d", x, y); ImGui::NextColumn(); ImGui::Text("Node contents"); if (open2) @@ -7704,17 +8665,16 @@ static void DemoWindowInputs() IMGUI_DEMO_MARKER("Inputs & Focus"); if (ImGui::CollapsingHeader("Inputs & Focus")) { - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO &io = ImGui::GetIO(); // Display inputs submitted to ImGuiIO IMGUI_DEMO_MARKER("Inputs & Focus/Inputs"); ImGui::SetNextItemOpen(true, ImGuiCond_Once); bool inputs_opened = ImGui::TreeNode("Inputs"); ImGui::SameLine(); - HelpMarker( - "This is a simplified view. See more detailed input state:\n" - "- in 'Tools->Metrics/Debugger->Inputs'.\n" - "- in 'Tools->Debug Log->IO'."); + HelpMarker("This is a simplified view. See more detailed input state:\n" + "- in 'Tools->Metrics/Debugger->Inputs'.\n" + "- in 'Tools->Debug Log->IO'."); if (inputs_opened) { if (ImGui::IsMousePosValid()) @@ -7723,20 +8683,49 @@ static void DemoWindowInputs() 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 (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } + 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 wheel: %.1f", io.MouseWheel); ImGui::Text("Mouse clicked count:"); - for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseClickedCount[i] > 0) { ImGui::SameLine(); ImGui::Text("b%d: %d", i, io.MouseClickedCount[i]); } + for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) + if (io.MouseClickedCount[i] > 0) + { + ImGui::SameLine(); + ImGui::Text("b%d: %d", i, io.MouseClickedCount[i]); + } - // We iterate both legacy native range and named ImGuiKey ranges. This is a little unusual/odd but this allows - // displaying the data for old/new backends. - // User code should never have to go through such hoops! + // We iterate both legacy native range and named ImGuiKey ranges. This is a little unusual/odd but this + // allows displaying the data for old/new backends. User code should never have to go through such hoops! // You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END. - struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } }; + struct funcs + { + static bool IsLegacyNativeDupe(ImGuiKey) + { + return false; + } + }; ImGuiKey start_key = ImGuiKey_NamedKey_BEGIN; - ImGui::Text("Keys down:"); for (ImGuiKey key = start_key; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !ImGui::IsKeyDown(key)) continue; ImGui::SameLine(); ImGui::Text((key < ImGuiKey_NamedKey_BEGIN) ? "\"%s\"" : "\"%s\" %d", ImGui::GetKeyName(key), key); } - 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("Keys down:"); + for (ImGuiKey key = start_key; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) + { + if (funcs::IsLegacyNativeDupe(key) || !ImGui::IsKeyDown(key)) + continue; + ImGui::SameLine(); + ImGui::Text((key < ImGuiKey_NamedKey_BEGIN) ? "\"%s\"" : "\"%s\" %d", ImGui::GetKeyName(key), key); + } + 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::TreePop(); } @@ -7765,19 +8754,23 @@ static void DemoWindowInputs() IMGUI_DEMO_MARKER("Inputs & Focus/Outputs/WantCapture override"); if (ImGui::TreeNode("WantCapture override")) { - HelpMarker( - "Hovering the colored canvas will override io.WantCaptureXXX fields.\n" - "Notice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering " - "and true when clicking."); + HelpMarker("Hovering the colored canvas will override io.WantCaptureXXX fields.\n" + "Notice how normally (when set to none), the value of io.WantCaptureKeyboard would be false " + "when hovering " + "and true when clicking."); static int capture_override_mouse = -1; static int capture_override_keyboard = -1; - const char* capture_override_desc[] = { "None", "Set to false", "Set to true" }; + const char *capture_override_desc[] = {"None", "Set to false", "Set to true"}; ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15); - ImGui::SliderInt("SetNextFrameWantCaptureMouse() on hover", &capture_override_mouse, -1, +1, capture_override_desc[capture_override_mouse + 1], ImGuiSliderFlags_AlwaysClamp); + ImGui::SliderInt("SetNextFrameWantCaptureMouse() on hover", &capture_override_mouse, -1, +1, + capture_override_desc[capture_override_mouse + 1], ImGuiSliderFlags_AlwaysClamp); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15); - ImGui::SliderInt("SetNextFrameWantCaptureKeyboard() on hover", &capture_override_keyboard, -1, +1, capture_override_desc[capture_override_keyboard + 1], ImGuiSliderFlags_AlwaysClamp); + ImGui::SliderInt("SetNextFrameWantCaptureKeyboard() on hover", &capture_override_keyboard, -1, +1, + capture_override_desc[capture_override_keyboard + 1], ImGuiSliderFlags_AlwaysClamp); - ImGui::ColorButton("##panel", ImVec4(0.7f, 0.1f, 0.7f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, ImVec2(128.0f, 96.0f)); // Dummy item + ImGui::ColorButton("##panel", ImVec4(0.7f, 0.1f, 0.7f, 1.0f), + ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, + ImVec2(128.0f, 96.0f)); // Dummy item if (ImGui::IsItemHovered() && capture_override_mouse != -1) ImGui::SetNextFrameWantCaptureMouse(capture_override_mouse == 1); if (ImGui::IsItemHovered() && capture_override_keyboard != -1) @@ -7794,7 +8787,8 @@ static void DemoWindowInputs() // - Multiple locations may be interested in same chord! Routing helps find a winner. // - Every frame, we resolve all claims and assign one owner if the modifiers are matching. // - The lower-level function is 'bool SetShortcutRouting()', returns true when caller got the route. - // - Most of the times, SetShortcutRouting() is not called directly. User mostly calls Shortcut() with routing flags. + // - Most of the times, SetShortcutRouting() is not called directly. User mostly calls Shortcut() with routing + // flags. // - If you call Shortcut() WITHOUT any routing option, it uses ImGuiInputFlags_RouteFocused. // TL;DR: Most uses will simply be: // - Shortcut(ImGuiMod_Ctrl | ImGuiKey_A); // Use ImGuiInputFlags_RouteFocused policy. @@ -7811,13 +8805,15 @@ static void DemoWindowInputs() ImGui::BeginDisabled(route_type != ImGuiInputFlags_RouteGlobal); ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverFocused", &route_options, ImGuiInputFlags_RouteOverFocused); ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverActive", &route_options, ImGuiInputFlags_RouteOverActive); - ImGui::CheckboxFlags("ImGuiInputFlags_RouteUnlessBgFocused", &route_options, ImGuiInputFlags_RouteUnlessBgFocused); + ImGui::CheckboxFlags("ImGuiInputFlags_RouteUnlessBgFocused", &route_options, + ImGuiInputFlags_RouteUnlessBgFocused); ImGui::EndDisabled(); ImGui::Unindent(); ImGui::RadioButton("ImGuiInputFlags_RouteAlways", &route_type, ImGuiInputFlags_RouteAlways); ImGuiInputFlags flags = route_type | route_options; // Merged flags if (route_type != ImGuiInputFlags_RouteGlobal) - flags &= ~(ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive | ImGuiInputFlags_RouteUnlessBgFocused); + flags &= ~(ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive | + ImGuiInputFlags_RouteUnlessBgFocused); ImGui::SeparatorText("Using SetNextItemShortcut()"); ImGui::Text("Ctrl+S"); @@ -7833,7 +8829,8 @@ static void DemoWindowInputs() const ImGuiKeyChord key_chord = ImGuiMod_Ctrl | ImGuiKey_A; ImGui::Text("Ctrl+A"); - ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "..."); + ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), + ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "..."); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 0.0f, 1.0f, 0.1f)); @@ -7843,16 +8840,18 @@ static void DemoWindowInputs() // 1: Window polling for CTRL+A ImGui::Text("(in WindowA)"); - ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "..."); + ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), + ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "..."); // 2: InputText also polling for CTRL+A: it always uses _RouteFocused internally (gets priority when active) // (Commented because the owner-aware version of Shortcut() is still in imgui_internal.h) - //char str[16] = "Press CTRL+A"; - //ImGui::Spacing(); - //ImGui::InputText("InputTextB", str, IM_ARRAYSIZE(str), ImGuiInputTextFlags_ReadOnly); - //ImGuiID item_id = ImGui::GetItemID(); - //ImGui::SameLine(); HelpMarker("Internal widgets always use _RouteFocused"); - //ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags, item_id) ? "PRESSED" : "..."); + // char str[16] = "Press CTRL+A"; + // ImGui::Spacing(); + // ImGui::InputText("InputTextB", str, IM_ARRAYSIZE(str), ImGuiInputTextFlags_ReadOnly); + // ImGuiID item_id = ImGui::GetItemID(); + // ImGui::SameLine(); HelpMarker("Internal widgets always use _RouteFocused"); + // ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, + // flags, item_id) ? "PRESSED" : "..."); // 3: Dummy child is not claiming the route: focusing them shouldn't steal route away from WindowA ImGui::BeginChild("ChildD", ImVec2(-FLT_MIN, line_height * 4), true); @@ -7863,7 +8862,8 @@ static void DemoWindowInputs() // 4: Child window polling for CTRL+A. It is deeper than WindowA and gets priority when focused. ImGui::BeginChild("ChildE", ImVec2(-FLT_MIN, line_height * 4), true); ImGui::Text("(in ChildE: using same Shortcut)"); - ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "..."); + ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), + ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "..."); ImGui::EndChild(); // 5: In a popup @@ -7872,10 +8872,12 @@ static void DemoWindowInputs() if (ImGui::BeginPopup("PopupF")) { ImGui::Text("(in PopupF)"); - ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "..."); + ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), + ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "..."); // (Commented because the owner-aware version of Shortcut() is still in imgui_internal.h) - //ImGui::InputText("InputTextG", str, IM_ARRAYSIZE(str), ImGuiInputTextFlags_ReadOnly); - //ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags, ImGui::GetItemID()) ? "PRESSED" : "..."); + // ImGui::InputText("InputTextG", str, IM_ARRAYSIZE(str), ImGuiInputTextFlags_ReadOnly); + // ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, + // flags, ImGui::GetItemID()) ? "PRESSED" : "..."); ImGui::EndPopup(); } ImGui::EndChild(); @@ -7888,18 +8890,24 @@ static void DemoWindowInputs() IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors"); if (ImGui::TreeNode("Mouse Cursors")) { - const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "Wait", "Progress", "NotAllowed" }; + const char *mouse_cursors_names[] = {"Arrow", "TextInput", "ResizeAll", "ResizeNS", + "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", + "Wait", "Progress", "NotAllowed"}; IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); ImGuiMouseCursor current = ImGui::GetMouseCursor(); - const char* cursor_name = (current >= ImGuiMouseCursor_Arrow) && (current < ImGuiMouseCursor_COUNT) ? mouse_cursors_names[current] : "N/A"; + const char *cursor_name = (current >= ImGuiMouseCursor_Arrow) && (current < ImGuiMouseCursor_COUNT) + ? mouse_cursors_names[current] + : "N/A"; ImGui::Text("Current mouse cursor = %d: %s", current, cursor_name); ImGui::BeginDisabled(true); - ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors); + ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, + ImGuiBackendFlags_HasMouseCursors); ImGui::EndDisabled(); ImGui::Text("Hover to see mouse cursors:"); - ImGui::SameLine(); HelpMarker( + ImGui::SameLine(); + HelpMarker( "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. " "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, " "otherwise your backend needs to handle it."); @@ -7907,7 +8915,8 @@ static void DemoWindowInputs() { char label[32]; sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]); - ImGui::Bullet(); ImGui::Selectable(label, false); + ImGui::Bullet(); + ImGui::Selectable(label, false); if (ImGui::IsItemHovered()) ImGui::SetMouseCursor(i); } @@ -7924,7 +8933,8 @@ static void DemoWindowInputs() ImGui::InputText("3", buf, IM_ARRAYSIZE(buf)); ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop, true); ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf)); - ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab."); + ImGui::SameLine(); + HelpMarker("Item won't be cycled through when using TAB or Shift+Tab."); ImGui::PopItemFlag(); ImGui::InputText("5", buf, IM_ARRAYSIZE(buf)); ImGui::TreePop(); @@ -7933,25 +8943,34 @@ static void DemoWindowInputs() IMGUI_DEMO_MARKER("Inputs & Focus/Focus from code"); if (ImGui::TreeNode("Focus from code")) { - bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine(); - bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine(); + bool focus_1 = ImGui::Button("Focus on 1"); + ImGui::SameLine(); + bool focus_2 = ImGui::Button("Focus on 2"); + ImGui::SameLine(); bool focus_3 = ImGui::Button("Focus on 3"); int has_focus = 0; static char buf[128] = "click on a button to set focus"; - if (focus_1) ImGui::SetKeyboardFocusHere(); + if (focus_1) + ImGui::SetKeyboardFocusHere(); ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); - if (ImGui::IsItemActive()) has_focus = 1; + if (ImGui::IsItemActive()) + has_focus = 1; - if (focus_2) ImGui::SetKeyboardFocusHere(); + if (focus_2) + ImGui::SetKeyboardFocusHere(); ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); - if (ImGui::IsItemActive()) has_focus = 2; + if (ImGui::IsItemActive()) + has_focus = 2; ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop, true); - if (focus_3) ImGui::SetKeyboardFocusHere(); + 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."); + if (ImGui::IsItemActive()) + has_focus = 3; + ImGui::SameLine(); + HelpMarker("Item won't be cycled through when using TAB or Shift+Tab."); ImGui::PopItemFlag(); if (has_focus) @@ -7960,12 +8979,24 @@ static void DemoWindowInputs() ImGui::Text("Item with focus: "); // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item - static float f3[3] = { 0.0f, 0.0f, 0.0f }; + static float f3[3] = {0.0f, 0.0f, 0.0f}; int focus_ahead = -1; - if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine(); - if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine(); - if (ImGui::Button("Focus on Z")) { focus_ahead = 2; } - if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead); + if (ImGui::Button("Focus on X")) + { + focus_ahead = 0; + } + ImGui::SameLine(); + if (ImGui::Button("Focus on Y")) + { + focus_ahead = 1; + } + ImGui::SameLine(); + if (ImGui::Button("Focus on Z")) + { + focus_ahead = 2; + } + if (focus_ahead != -1) + ImGui::SetKeyboardFocusHere(focus_ahead); ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f); ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code."); @@ -7975,7 +9006,8 @@ static void DemoWindowInputs() IMGUI_DEMO_MARKER("Inputs & Focus/Dragging"); if (ImGui::TreeNode("Dragging")) { - ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); + ImGui::TextWrapped( + "You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); for (int button = 0; button < 3; button++) { ImGui::Text("IsMouseDragging(%d):", button); @@ -7986,7 +9018,9 @@ static void DemoWindowInputs() ImGui::Button("Drag Me"); if (ImGui::IsItemActive()) - ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor + ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, + ImGui::GetColorU32(ImGuiCol_Button), + 4.0f); // Draw a line between the button and the mouse cursor // Drag operations gets "unlocked" when the mouse has moved past a certain threshold // (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher @@ -7995,7 +9029,8 @@ static void DemoWindowInputs() ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0); ImVec2 mouse_delta = io.MouseDelta; ImGui::Text("GetMouseDragDelta(0):"); - ImGui::Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y); + ImGui::Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, + value_with_lock_threshold.y); ImGui::Text(" w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y); ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y); ImGui::TreePop(); @@ -8008,7 +9043,7 @@ static void DemoWindowInputs() // Access from Dear ImGui Demo -> Tools -> About //----------------------------------------------------------------------------- -void ImGui::ShowAboutWindow(bool* p_open) +void ImGui::ShowAboutWindow(bool *p_open) { if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize)) { @@ -8038,8 +9073,8 @@ void ImGui::ShowAboutWindow(bool* p_open) ImGui::Checkbox("Config/Build Information", &show_config_info); if (show_config_info) { - ImGuiIO& io = ImGui::GetIO(); - ImGuiStyle& style = ImGui::GetStyle(); + ImGuiIO &io = ImGui::GetIO(); + ImGuiStyle &style = ImGui::GetStyle(); bool copy_to_clipboard = ImGui::Button("Copy to clipboard"); ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18); @@ -8052,7 +9087,8 @@ void ImGui::ShowAboutWindow(bool* p_open) ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); ImGui::Separator(); - ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert)); + ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), + (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert)); ImGui::Text("define: __cplusplus=%d", (int)__cplusplus); #ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS"); @@ -8125,30 +9161,50 @@ void ImGui::ShowAboutWindow(bool* p_open) ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL"); ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL"); ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags); - if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard"); - if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad"); - if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse"); - if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange"); - if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard) ImGui::Text(" NoKeyboard"); - if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor"); - if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors"); - if (io.ConfigNavMoveSetMousePos) ImGui::Text("io.ConfigNavMoveSetMousePos"); - if (io.ConfigNavCaptureKeyboard) ImGui::Text("io.ConfigNavCaptureKeyboard"); - if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink"); - if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges"); - if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly"); - if (io.ConfigMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer); + if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) + ImGui::Text(" NavEnableKeyboard"); + if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) + ImGui::Text(" NavEnableGamepad"); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) + ImGui::Text(" NoMouse"); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) + ImGui::Text(" NoMouseCursorChange"); + if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard) + ImGui::Text(" NoKeyboard"); + if (io.MouseDrawCursor) + ImGui::Text("io.MouseDrawCursor"); + if (io.ConfigMacOSXBehaviors) + ImGui::Text("io.ConfigMacOSXBehaviors"); + if (io.ConfigNavMoveSetMousePos) + ImGui::Text("io.ConfigNavMoveSetMousePos"); + if (io.ConfigNavCaptureKeyboard) + ImGui::Text("io.ConfigNavCaptureKeyboard"); + if (io.ConfigInputTextCursorBlink) + ImGui::Text("io.ConfigInputTextCursorBlink"); + if (io.ConfigWindowsResizeFromEdges) + ImGui::Text("io.ConfigWindowsResizeFromEdges"); + if (io.ConfigWindowsMoveFromTitleBarOnly) + ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly"); + if (io.ConfigMemoryCompactTimer >= 0.0f) + ImGui::Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer); ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags); - if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad"); - if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors"); - if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos"); - if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(" RendererHasVtxOffset"); - if (io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) ImGui::Text(" RendererHasTextures"); + if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) + ImGui::Text(" HasGamepad"); + if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) + ImGui::Text(" HasMouseCursors"); + if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) + ImGui::Text(" HasSetMousePos"); + if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) + ImGui::Text(" RendererHasVtxOffset"); + if (io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) + ImGui::Text(" RendererHasTextures"); ImGui::Separator(); - ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexData->Width, io.Fonts->TexData->Height); + ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, + io.Fonts->TexData->Width, io.Fonts->TexData->Height); ImGui::Text("io.Fonts->FontLoaderName: \"%s\"", io.Fonts->FontLoaderName ? io.Fonts->FontLoaderName : "NULL"); ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y); - ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); + ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, + io.DisplayFramebufferScale.y); ImGui::Separator(); ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y); ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize); @@ -8178,37 +9234,46 @@ void ImGui::ShowAboutWindow(bool* p_open) // 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) +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; + case 0: + ImGui::StyleColorsDark(); + break; + case 1: + ImGui::StyleColorsLight(); + break; + case 2: + ImGui::StyleColorsClassic(); + break; } return true; } return false; } -static const char* GetTreeLinesFlagsName(ImGuiTreeNodeFlags flags) +static const char *GetTreeLinesFlagsName(ImGuiTreeNodeFlags flags) { - if (flags == ImGuiTreeNodeFlags_DrawLinesNone) return "DrawLinesNone"; - if (flags == ImGuiTreeNodeFlags_DrawLinesFull) return "DrawLinesFull"; - if (flags == ImGuiTreeNodeFlags_DrawLinesToNodes) return "DrawLinesToNodes"; + if (flags == ImGuiTreeNodeFlags_DrawLinesNone) + return "DrawLinesNone"; + if (flags == ImGuiTreeNodeFlags_DrawLinesFull) + return "DrawLinesFull"; + if (flags == ImGuiTreeNodeFlags_DrawLinesToNodes) + return "DrawLinesToNodes"; return ""; } // We omit the ImGui:: prefix in this function, as we don't expect user to be copy and pasting this code. -void ImGui::ShowStyleEditor(ImGuiStyle* ref) +void ImGui::ShowStyleEditor(ImGuiStyle *ref) { IMGUI_DEMO_MARKER("Tools/Style Editor"); // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to // (without a reference style pointer, we will use one compared locally as a reference) - ImGuiStyle& style = GetStyle(); + ImGuiStyle &style = GetStyle(); static ImGuiStyle ref_saved_style; // Default to using internal storage as reference @@ -8225,28 +9290,48 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) // General SeparatorText("General"); if ((GetIO().BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) - BulletText("Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!"); + BulletText( + "Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!"); if (ShowStyleSelector("Colors##Selector")) ref_saved_style = style; ShowFontSelector("Fonts##Selector"); if (DragFloat("FontSizeBase", &style.FontSizeBase, 0.20f, 5.0f, 100.0f, "%.0f")) style._NextFrameFontSizeBase = style.FontSizeBase; // FIXME: Temporary hack until we finish remaining work. - SameLine(0.0f, 0.0f); Text(" (out %.2f)", GetFontSize()); + SameLine(0.0f, 0.0f); + Text(" (out %.2f)", GetFontSize()); DragFloat("FontScaleMain", &style.FontScaleMain, 0.02f, 0.5f, 4.0f); - //BeginDisabled(GetIO().ConfigDpiScaleFonts); + // BeginDisabled(GetIO().ConfigDpiScaleFonts); DragFloat("FontScaleDpi", &style.FontScaleDpi, 0.02f, 0.5f, 5.0f); - //SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten."); - //EndDisabled(); + // SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten."); + // EndDisabled(); // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) if (SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding - { bool border = (style.WindowBorderSize > 0.0f); if (Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } } + { + bool border = (style.WindowBorderSize > 0.0f); + if (Checkbox("WindowBorder", &border)) + { + style.WindowBorderSize = border ? 1.0f : 0.0f; + } + } SameLine(); - { bool border = (style.FrameBorderSize > 0.0f); if (Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } } + { + bool border = (style.FrameBorderSize > 0.0f); + if (Checkbox("FrameBorder", &border)) + { + style.FrameBorderSize = border ? 1.0f : 0.0f; + } + } SameLine(); - { bool border = (style.PopupBorderSize > 0.0f); if (Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } } + { + bool border = (style.PopupBorderSize > 0.0f); + if (Checkbox("PopupBorder", &border)) + { + style.PopupBorderSize = border ? 1.0f : 0.0f; + } + } } // Save/Revert button @@ -8256,9 +9341,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) if (Button("Revert Ref")) style = *ref; SameLine(); - HelpMarker( - "Save/Revert in local non-persistent storage. Default Colors definition are not affected. " - "Use \"Export\" below to save them somewhere."); + HelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. " + "Use \"Export\" below to save them somewhere."); SeparatorText("Details"); if (BeginTabBar("##tabs", ImGuiTabBarFlags_None)) @@ -8266,11 +9350,11 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) if (BeginTabItem("Sizes")) { SeparatorText("Main"); - SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); - SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); - SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); - SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); - SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); + SliderFloat2("WindowPadding", (float *)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); + SliderFloat2("FramePadding", (float *)&style.FramePadding, 0.0f, 20.0f, "%.0f"); + SliderFloat2("ItemSpacing", (float *)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); + SliderFloat2("ItemInnerSpacing", (float *)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); + SliderFloat2("TouchExtraPadding", (float *)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); @@ -8293,23 +9377,32 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f"); SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 3.0f, "%.0f"); - SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set."); - DragFloat("TabCloseButtonMinWidthSelected", &style.TabCloseButtonMinWidthSelected, 0.1f, -1.0f, 100.0f, (style.TabCloseButtonMinWidthSelected < 0.0f) ? "%.0f (Always)" : "%.0f"); - DragFloat("TabCloseButtonMinWidthUnselected", &style.TabCloseButtonMinWidthUnselected, 0.1f, -1.0f, 100.0f, (style.TabCloseButtonMinWidthUnselected < 0.0f) ? "%.0f (Always)" : "%.0f"); + SameLine(); + HelpMarker( + "Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set."); + DragFloat("TabCloseButtonMinWidthSelected", &style.TabCloseButtonMinWidthSelected, 0.1f, -1.0f, 100.0f, + (style.TabCloseButtonMinWidthSelected < 0.0f) ? "%.0f (Always)" : "%.0f"); + DragFloat("TabCloseButtonMinWidthUnselected", &style.TabCloseButtonMinWidthUnselected, 0.1f, -1.0f, 100.0f, + (style.TabCloseButtonMinWidthUnselected < 0.0f) ? "%.0f (Always)" : "%.0f"); SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); SeparatorText("Tables"); - SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f"); + SliderFloat2("CellPadding", (float *)&style.CellPadding, 0.0f, 20.0f, "%.0f"); SliderAngle("TableAngledHeadersAngle", &style.TableAngledHeadersAngle, -50.0f, +50.0f); - SliderFloat2("TableAngledHeadersTextAlign", (float*)&style.TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f"); + SliderFloat2("TableAngledHeadersTextAlign", (float *)&style.TableAngledHeadersTextAlign, 0.0f, 1.0f, + "%.2f"); SeparatorText("Trees"); bool combo_open = BeginCombo("TreeLinesFlags", GetTreeLinesFlagsName(style.TreeLinesFlags)); SameLine(); - HelpMarker("[Experimental] Tree lines may not work in all situations (e.g. using a clipper) and may incurs slight traversal overhead.\n\nImGuiTreeNodeFlags_DrawLinesFull is faster than ImGuiTreeNodeFlags_DrawLinesToNode."); + HelpMarker("[Experimental] Tree lines may not work in all situations (e.g. using a clipper) and may incurs " + "slight traversal overhead.\n\nImGuiTreeNodeFlags_DrawLinesFull is faster than " + "ImGuiTreeNodeFlags_DrawLinesToNode."); if (combo_open) { - const ImGuiTreeNodeFlags options[] = { ImGuiTreeNodeFlags_DrawLinesNone, ImGuiTreeNodeFlags_DrawLinesFull, ImGuiTreeNodeFlags_DrawLinesToNodes }; + const ImGuiTreeNodeFlags options[] = {ImGuiTreeNodeFlags_DrawLinesNone, + ImGuiTreeNodeFlags_DrawLinesFull, + ImGuiTreeNodeFlags_DrawLinesToNodes}; for (ImGuiTreeNodeFlags option : options) if (Selectable(GetTreeLinesFlagsName(option), style.TreeLinesFlags == option)) style.TreeLinesFlags = option; @@ -8319,21 +9412,23 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) SliderFloat("TreeLinesRounding", &style.TreeLinesRounding, 0.0f, 12.0f, "%.0f"); SeparatorText("Windows"); - SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); + SliderFloat2("WindowTitleAlign", (float *)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); SliderFloat("WindowBorderHoverPadding", &style.WindowBorderHoverPadding, 1.0f, 20.0f, "%.0f"); int window_menu_button_position = style.WindowMenuButtonPosition + 1; - if (Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) + if (Combo("WindowMenuButtonPosition", (int *)&window_menu_button_position, "None\0Left\0Right\0")) style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1); SeparatorText("Widgets"); - Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0"); - SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); - SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); - SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); - SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); + Combo("ColorButtonPosition", (int *)&style.ColorButtonPosition, "Left\0Right\0"); + SliderFloat2("ButtonTextAlign", (float *)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); + SameLine(); + HelpMarker("Alignment applies when a button is larger than its text content."); + SliderFloat2("SelectableTextAlign", (float *)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); + SameLine(); + HelpMarker("Alignment applies when a selectable is larger than its text content."); SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f"); - SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f"); - SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f"); + SliderFloat2("SeparatorTextAlign", (float *)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f"); + SliderFloat2("SeparatorTextPadding", (float *)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f"); SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f"); SliderFloat("ImageBorderSize", &style.ImageBorderSize, 0.0f, 1.0f, "%.0f"); @@ -8341,7 +9436,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) for (int n = 0; n < 2; n++) if (TreeNodeEx(n == 0 ? "HoverFlagsForTooltipMouse" : "HoverFlagsForTooltipNav")) { - ImGuiHoveredFlags* p = (n == 0) ? &style.HoverFlagsForTooltipMouse : &style.HoverFlagsForTooltipNav; + ImGuiHoveredFlags *p = (n == 0) ? &style.HoverFlagsForTooltipMouse : &style.HoverFlagsForTooltipNav; CheckboxFlags("ImGuiHoveredFlags_DelayNone", p, ImGuiHoveredFlags_DelayNone); CheckboxFlags("ImGuiHoveredFlags_DelayShort", p, ImGuiHoveredFlags_DelayShort); CheckboxFlags("ImGuiHoveredFlags_DelayNormal", p, ImGuiHoveredFlags_DelayNormal); @@ -8351,8 +9446,15 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) } SeparatorText("Misc"); - SliderFloat2("DisplayWindowPadding", (float*)&style.DisplayWindowPadding, 0.0f, 30.0f, "%.0f"); SameLine(); HelpMarker("Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen."); - SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); SameLine(); HelpMarker("Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); + SliderFloat2("DisplayWindowPadding", (float *)&style.DisplayWindowPadding, 0.0f, 30.0f, "%.0f"); + SameLine(); + HelpMarker("Apply to regular windows: amount which we enforce to keep visible when moving near edges of " + "your screen."); + SliderFloat2("DisplaySafeAreaPadding", (float *)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); + SameLine(); + HelpMarker( + "Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if " + "you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); EndTabItem(); } @@ -8370,35 +9472,50 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) LogText("ImVec4* colors = GetStyle().Colors;" IM_NEWLINE); for (int i = 0; i < ImGuiCol_COUNT; i++) { - const ImVec4& col = style.Colors[i]; - const char* name = GetStyleColorName(i); + const ImVec4 &col = style.Colors[i]; + const char *name = GetStyleColorName(i); if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) - LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, - name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w); + LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, name, + 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w); } LogFinish(); } - SameLine(); SetNextItemWidth(120); Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); - SameLine(); Checkbox("Only Modified Colors", &output_only_modified); + SameLine(); + SetNextItemWidth(120); + Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); + SameLine(); + Checkbox("Only Modified Colors", &output_only_modified); static ImGuiTextFilter filter; filter.Draw("Filter colors", GetFontSize() * 16); static ImGuiColorEditFlags alpha_flags = 0; - if (RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_AlphaOpaque)) { alpha_flags = ImGuiColorEditFlags_AlphaOpaque; } SameLine(); - if (RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } SameLine(); - if (RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } SameLine(); - HelpMarker( - "In the color list:\n" - "Left-click on color square to open color picker,\n" - "Right-click to open edit options menu."); + if (RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_AlphaOpaque)) + { + alpha_flags = ImGuiColorEditFlags_AlphaOpaque; + } + SameLine(); + if (RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_None)) + { + alpha_flags = ImGuiColorEditFlags_None; + } + SameLine(); + if (RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) + { + alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; + } + SameLine(); + HelpMarker("In the color list:\n" + "Left-click on color square to open color picker,\n" + "Right-click to open edit options menu."); SetNextWindowSizeConstraints(ImVec2(0.0f, GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX)); - BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); + BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened, + ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); PushItemWidth(GetFontSize() * -12); for (int i = 0; i < ImGuiCol_COUNT; i++) { - const char* name = GetStyleColorName(i); + const char *name = GetStyleColorName(i); if (!filter.PassFilter(name)) continue; PushID(i); @@ -8408,14 +9525,22 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) SetItemTooltip("Flash given color to identify places where it is used."); SameLine(); #endif - ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); + ColorEdit4("##color", (float *)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) { // Tips: in a real user application, you may want to merge and use an icon font into the main font, // so instead of "Save"/"Revert" you'd use icons! // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient! - SameLine(0.0f, style.ItemInnerSpacing.x); if (Button("Save")) { ref->Colors[i] = style.Colors[i]; } - SameLine(0.0f, style.ItemInnerSpacing.x); if (Button("Revert")) { style.Colors[i] = ref->Colors[i]; } + SameLine(0.0f, style.ItemInnerSpacing.x); + if (Button("Save")) + { + ref->Colors[i] = style.Colors[i]; + } + SameLine(0.0f, style.ItemInnerSpacing.x); + if (Button("Revert")) + { + style.Colors[i] = ref->Colors[i]; + } } SameLine(0.0f, style.ItemInnerSpacing.x); TextUnformatted(name); @@ -8429,12 +9554,13 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) if (BeginTabItem("Fonts")) { - ImGuiIO& io = GetIO(); - ImFontAtlas* atlas = io.Fonts; + ImGuiIO &io = GetIO(); + ImFontAtlas *atlas = io.Fonts; 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). + // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out + // of bounds). /* SeparatorText("Legacy Scaling"); const float MIN_SCALE = 0.3f; @@ -8445,9 +9571,11 @@ 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."); PushItemWidth(GetFontSize() * 8); - DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything + DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", + ImGuiSliderFlags_AlwaysClamp); // Scale everything //static float window_scale = 1.0f; - //if (DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window + //if (DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", + ImGuiSliderFlags_AlwaysClamp)) // Scale only this window // SetWindowFontScale(window_scale); PopItemWidth(); */ @@ -8459,19 +9587,24 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) { Checkbox("Anti-aliased lines", &style.AntiAliasedLines); SameLine(); - HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); + HelpMarker( + "When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex); SameLine(); - HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering)."); + HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not " + "point/nearest filtering)."); Checkbox("Anti-aliased fill", &style.AntiAliasedFill); PushItemWidth(GetFontSize() * 8); DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f"); - if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f; + 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. - DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp); + // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated + // circles. + DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError, 0.005f, 0.10f, 5.0f, "%.2f", + ImGuiSliderFlags_AlwaysClamp); const bool show_samples = IsItemActive(); if (show_samples) SetNextWindowPos(GetCursorScreenPos()); @@ -8479,7 +9612,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) { TextUnformatted("(R = radius, N = approx number of segments)"); Spacing(); - ImDrawList* draw_list = GetWindowDrawList(); + ImDrawList *draw_list = GetWindowDrawList(); const float min_widget_width = CalcTextSize("R: MMM\nN: MMM").x; for (int n = 0; n < 8; n++) { @@ -8493,8 +9626,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) 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 float offset_x = floorf(canvas_width * 0.5f); + const float offset_y = floorf(RAD_MAX); const ImVec2 p1 = GetCursorScreenPos(); draw_list->AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, GetColorU32(ImGuiCol_Text)); @@ -8502,8 +9635,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) /* const ImVec2 p2 = GetCursorScreenPos(); - draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, GetColorU32(ImGuiCol_Text)); - Dummy(ImVec2(canvas_width, RAD_MAX * 2)); + draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, + GetColorU32(ImGuiCol_Text)); Dummy(ImVec2(canvas_width, RAD_MAX * 2)); */ EndGroup(); @@ -8512,10 +9645,15 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) EndTooltip(); } SameLine(); - HelpMarker("When drawing circle primitives with \"num_segments == 0\" tessellation will be calculated automatically."); + HelpMarker("When drawing circle primitives with \"num_segments == 0\" tessellation will be calculated " + "automatically."); - DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. - DragFloat("Disabled Alpha", &style.DisabledAlpha, 0.005f, 0.0f, 1.0f, "%.2f"); SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha)."); + DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, + "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). + // But application code could have a toggle to switch between zero and non-zero. + DragFloat("Disabled Alpha", &style.DisabledAlpha, 0.005f, 0.0f, 1.0f, "%.2f"); + SameLine(); + HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha)."); PopItemWidth(); EndTabItem(); @@ -8533,11 +9671,10 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) // We omit the ImGui:: prefix in this function, as we don't expect user to be copy and pasting this code. void ImGui::ShowUserGuide() { - ImGuiIO& io = GetIO(); + ImGuiIO &io = GetIO(); BulletText("Double-click on title bar to collapse window."); - BulletText( - "Click and drag on lower corner to resize window\n" - "(double-click to auto fit window to its contents)."); + BulletText("Click and drag on lower corner to resize window\n" + "(double-click to auto fit window to its contents)."); BulletText("CTRL+Click on a slider or drag box to input value as text."); BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); BulletText("CTRL+Tab to select a window."); @@ -8571,7 +9708,8 @@ void ImGui::ShowUserGuide() // Demonstrate creating a "main" fullscreen menu bar and populating it. // Note the difference between BeginMainMenuBar() and BeginMenuBar(): // - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!) -// - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it. +// - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() +// into it. static void ShowExampleAppMainMenuBar() { if (ImGui::BeginMainMenuBar()) @@ -8583,12 +9721,22 @@ static void ShowExampleAppMainMenuBar() } if (ImGui::BeginMenu("Edit")) { - if (ImGui::MenuItem("Undo", "CTRL+Z")) {} - if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item + if (ImGui::MenuItem("Undo", "CTRL+Z")) + { + } + if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) + { + } // Disabled item ImGui::Separator(); - if (ImGui::MenuItem("Cut", "CTRL+X")) {} - if (ImGui::MenuItem("Copy", "CTRL+C")) {} - if (ImGui::MenuItem("Paste", "CTRL+V")) {} + if (ImGui::MenuItem("Cut", "CTRL+X")) + { + } + if (ImGui::MenuItem("Copy", "CTRL+C")) + { + } + if (ImGui::MenuItem("Paste", "CTRL+V")) + { + } ImGui::EndMenu(); } ImGui::EndMainMenuBar(); @@ -8601,8 +9749,12 @@ static void ShowExampleMenuFile() { IMGUI_DEMO_MARKER("Examples/Menu"); ImGui::MenuItem("(demo menu)", NULL, false, false); - if (ImGui::MenuItem("New")) {} - if (ImGui::MenuItem("Open", "Ctrl+O")) {} + if (ImGui::MenuItem("New")) + { + } + if (ImGui::MenuItem("Open", "Ctrl+O")) + { + } if (ImGui::BeginMenu("Open Recent")) { ImGui::MenuItem("fish_hat.c"); @@ -8621,8 +9773,12 @@ static void ShowExampleMenuFile() } ImGui::EndMenu(); } - if (ImGui::MenuItem("Save", "Ctrl+S")) {} - if (ImGui::MenuItem("Save As..")) {} + if (ImGui::MenuItem("Save", "Ctrl+S")) + { + } + if (ImGui::MenuItem("Save As..")) + { + } ImGui::Separator(); IMGUI_DEMO_MARKER("Examples/Menu/Options"); @@ -8648,7 +9804,7 @@ static void ShowExampleMenuFile() float sz = ImGui::GetTextLineHeight(); for (int i = 0; i < ImGuiCol_COUNT; i++) { - const char* name = ImGui::GetStyleColorName((ImGuiCol)i); + const char *name = ImGui::GetStyleColorName((ImGuiCol)i); ImVec2 p = ImGui::GetCursorScreenPos(); ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i)); ImGui::Dummy(ImVec2(sz, sz)); @@ -8673,9 +9829,13 @@ static void ShowExampleMenuFile() { IM_ASSERT(0); } - if (ImGui::MenuItem("Checked", NULL, true)) {} + if (ImGui::MenuItem("Checked", NULL, true)) + { + } ImGui::Separator(); - if (ImGui::MenuItem("Quit", "Alt+F4")) {} + if (ImGui::MenuItem("Quit", "Alt+F4")) + { + } } //----------------------------------------------------------------------------- @@ -8686,14 +9846,14 @@ static void ShowExampleMenuFile() // For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions. struct ExampleAppConsole { - char InputBuf[256]; - ImVector Items; - ImVector Commands; - ImVector History; - int HistoryPos; // -1: new line, 0..History.Size-1 browsing history. - ImGuiTextFilter Filter; - bool AutoScroll; - bool ScrollToBottom; + char InputBuf[256]; + ImVector Items; + ImVector Commands; + ImVector History; + int HistoryPos; // -1: new line, 0..History.Size-1 browsing history. + ImGuiTextFilter Filter; + bool AutoScroll; + bool ScrollToBottom; ExampleAppConsole() { @@ -8719,31 +9879,63 @@ struct ExampleAppConsole } // Portable helpers - static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; } - static int Strnicmp(const char* s1, const char* s2, int n) { int d = 0; while (n > 0 && (d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; n--; } return d; } - static char* Strdup(const char* s) { IM_ASSERT(s); size_t len = strlen(s) + 1; void* buf = ImGui::MemAlloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)s, len); } - static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; } + static int Stricmp(const char *s1, const char *s2) + { + int d; + while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) + { + s1++; + s2++; + } + return d; + } + static int Strnicmp(const char *s1, const char *s2, int n) + { + int d = 0; + while (n > 0 && (d = toupper(*s2) - toupper(*s1)) == 0 && *s1) + { + s1++; + s2++; + n--; + } + return d; + } + static char *Strdup(const char *s) + { + IM_ASSERT(s); + size_t len = strlen(s) + 1; + void *buf = ImGui::MemAlloc(len); + IM_ASSERT(buf); + return (char *)memcpy(buf, (const void *)s, len); + } + static void Strtrim(char *s) + { + char *str_end = s + strlen(s); + while (str_end > s && str_end[-1] == ' ') + str_end--; + *str_end = 0; + } - void ClearLog() + void ClearLog() { for (int i = 0; i < Items.Size; i++) ImGui::MemFree(Items[i]); Items.clear(); } - void AddLog(const char* fmt, ...) IM_FMTARGS(2) + void AddLog(const char *fmt, ...) IM_FMTARGS(2) { // FIXME-OPT char buf[1024]; va_list args; va_start(args, fmt); vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); - buf[IM_ARRAYSIZE(buf)-1] = 0; + buf[IM_ARRAYSIZE(buf) - 1] = 0; va_end(args); Items.push_back(Strdup(buf)); } - void Draw(const char* title, bool* p_open) + void Draw(const char *title, bool *p_open) { ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); if (!ImGui::Begin(title, p_open)) @@ -8763,20 +9955,32 @@ struct ExampleAppConsole } ImGui::TextWrapped( - "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate " + "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A " + "more elaborate " "implementation may want to store entries along with extra data such as timestamp, emitter, etc."); ImGui::TextWrapped("Enter 'HELP' for help."); // TODO: display items starting from the bottom - if (ImGui::SmallButton("Add Debug Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } + if (ImGui::SmallButton("Add Debug Text")) + { + AddLog("%d some text", Items.Size); + AddLog("some more text"); + AddLog("display very important message here!"); + } ImGui::SameLine(); - if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); } + if (ImGui::SmallButton("Add Debug Error")) + { + AddLog("[error] something went wrong"); + } ImGui::SameLine(); - if (ImGui::SmallButton("Clear")) { ClearLog(); } + if (ImGui::SmallButton("Clear")) + { + ClearLog(); + } ImGui::SameLine(); bool copy_to_clipboard = ImGui::SmallButton("Copy"); - //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); } + // static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); } ImGui::Separator(); @@ -8797,20 +10001,22 @@ struct ExampleAppConsole // Reserve enough left-over height for 1 separator + 1 input text const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); - if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_HorizontalScrollbar)) + if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_NavFlattened, + ImGuiWindowFlags_HorizontalScrollbar)) { if (ImGui::BeginPopupContextWindow()) { - if (ImGui::Selectable("Clear")) ClearLog(); + if (ImGui::Selectable("Clear")) + ClearLog(); ImGui::EndPopup(); } // Display every line as a separate entry so we can change their color or add custom widgets. // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); - // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping - // to only process visible items. The clipper will automatically measure the height of your first item and then - // "seek" to display only items in the visible area. - // To use the clipper we can replace your standard loop: + // NB- if you have thousands of entries this approach may be too inefficient and may require user-side + // clipping to only process visible items. The clipper will automatically measure the height of your first + // item and then "seek" to display only items in the visible area. To use the clipper we can replace your + // standard loop: // for (int i = 0; i < Items.Size; i++) // With: // ImGuiListClipper clipper; @@ -8832,7 +10038,7 @@ struct ExampleAppConsole ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing if (copy_to_clipboard) ImGui::LogToClipboard(); - for (const char* item : Items) + for (const char *item : Items) { if (!Filter.PassFilter(item)) continue; @@ -8841,8 +10047,16 @@ struct ExampleAppConsole // (e.g. make Items[] an array of structure, store color/type etc.) ImVec4 color; bool has_color = false; - if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; } - else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; } + if (strstr(item, "[error]")) + { + color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); + has_color = true; + } + else if (strncmp(item, "# ", 2) == 0) + { + color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); + has_color = true; + } if (has_color) ImGui::PushStyleColor(ImGuiCol_Text, color); ImGui::TextUnformatted(item); @@ -8852,8 +10066,8 @@ struct ExampleAppConsole if (copy_to_clipboard) ImGui::LogFinish(); - // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. - // Using a scrollbar or mouse-wheel will take away from the bottom edge. + // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the + // frame. Using a scrollbar or mouse-wheel will take away from the bottom edge. if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) ImGui::SetScrollHereY(1.0f); ScrollToBottom = false; @@ -8865,10 +10079,13 @@ struct ExampleAppConsole // Command-line bool reclaim_focus = false; - ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_EscapeClearsAll | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; - if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this)) + ImGuiInputTextFlags input_text_flags = + ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_EscapeClearsAll | + ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; + if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, + (void *)this)) { - char* s = InputBuf; + char *s = InputBuf; Strtrim(s); if (s[0]) ExecCommand(s); @@ -8884,7 +10101,7 @@ struct ExampleAppConsole ImGui::End(); } - void ExecCommand(const char* command_line) + void ExecCommand(const char *command_line) { AddLog("# %s\n", command_line); @@ -8927,115 +10144,113 @@ struct ExampleAppConsole } // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks - static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) + static int TextEditCallbackStub(ImGuiInputTextCallbackData *data) { - ExampleAppConsole* console = (ExampleAppConsole*)data->UserData; + ExampleAppConsole *console = (ExampleAppConsole *)data->UserData; return console->TextEditCallback(data); } - int TextEditCallback(ImGuiInputTextCallbackData* data) + int TextEditCallback(ImGuiInputTextCallbackData *data) { - //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd); + // AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd); switch (data->EventFlag) { - case ImGuiInputTextFlags_CallbackCompletion: - { - // Example of TEXT COMPLETION + case ImGuiInputTextFlags_CallbackCompletion: { + // Example of TEXT COMPLETION - // Locate beginning of current word - const char* word_end = data->Buf + data->CursorPos; - const char* word_start = word_end; - while (word_start > data->Buf) + // Locate beginning of current word + const char *word_end = data->Buf + data->CursorPos; + const char *word_start = word_end; + while (word_start > data->Buf) + { + const char c = word_start[-1]; + if (c == ' ' || c == '\t' || c == ',' || c == ';') + break; + word_start--; + } + + // Build a list of candidates + ImVector candidates; + for (int i = 0; i < Commands.Size; i++) + if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0) + candidates.push_back(Commands[i]); + + if (candidates.Size == 0) + { + // No match + AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start); + } + else if (candidates.Size == 1) + { + // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing. + data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); + data->InsertChars(data->CursorPos, candidates[0]); + data->InsertChars(data->CursorPos, " "); + } + else + { + // Multiple matches. Complete as much as we can.. + // So inputting "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. + int match_len = (int)(word_end - word_start); + for (;;) { - const char c = word_start[-1]; - if (c == ' ' || c == '\t' || c == ',' || c == ';') + int c = 0; + bool all_candidates_matches = true; + for (int i = 0; i < candidates.Size && all_candidates_matches; i++) + if (i == 0) + c = toupper(candidates[i][match_len]); + else if (c == 0 || c != toupper(candidates[i][match_len])) + all_candidates_matches = false; + if (!all_candidates_matches) break; - word_start--; + match_len++; } - // Build a list of candidates - ImVector candidates; - for (int i = 0; i < Commands.Size; i++) - if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0) - candidates.push_back(Commands[i]); - - if (candidates.Size == 0) + if (match_len > 0) { - // No match - AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start); - } - else if (candidates.Size == 1) - { - // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing. data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); - data->InsertChars(data->CursorPos, candidates[0]); - data->InsertChars(data->CursorPos, " "); - } - else - { - // Multiple matches. Complete as much as we can.. - // So inputting "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. - int match_len = (int)(word_end - word_start); - for (;;) - { - int c = 0; - bool all_candidates_matches = true; - for (int i = 0; i < candidates.Size && all_candidates_matches; i++) - if (i == 0) - c = toupper(candidates[i][match_len]); - else if (c == 0 || c != toupper(candidates[i][match_len])) - all_candidates_matches = false; - if (!all_candidates_matches) - break; - match_len++; - } - - if (match_len > 0) - { - data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); - data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len); - } - - // List matches - AddLog("Possible matches:\n"); - for (int i = 0; i < candidates.Size; i++) - AddLog("- %s\n", candidates[i]); + data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len); } - break; + // List matches + AddLog("Possible matches:\n"); + for (int i = 0; i < candidates.Size; i++) + AddLog("- %s\n", candidates[i]); } - case ImGuiInputTextFlags_CallbackHistory: + + break; + } + case ImGuiInputTextFlags_CallbackHistory: { + // Example of HISTORY + const int prev_history_pos = HistoryPos; + if (data->EventKey == ImGuiKey_UpArrow) { - // Example of HISTORY - const int prev_history_pos = HistoryPos; - if (data->EventKey == ImGuiKey_UpArrow) - { - if (HistoryPos == -1) - HistoryPos = History.Size - 1; - else if (HistoryPos > 0) - HistoryPos--; - } - else if (data->EventKey == ImGuiKey_DownArrow) - { - if (HistoryPos != -1) - if (++HistoryPos >= History.Size) - HistoryPos = -1; - } - - // A better implementation would preserve the data on the current input line along with cursor position. - if (prev_history_pos != HistoryPos) - { - const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : ""; - data->DeleteChars(0, data->BufTextLen); - data->InsertChars(0, history_str); - } + if (HistoryPos == -1) + HistoryPos = History.Size - 1; + else if (HistoryPos > 0) + HistoryPos--; } + else if (data->EventKey == ImGuiKey_DownArrow) + { + if (HistoryPos != -1) + if (++HistoryPos >= History.Size) + HistoryPos = -1; + } + + // A better implementation would preserve the data on the current input line along with cursor position. + if (prev_history_pos != HistoryPos) + { + const char *history_str = (HistoryPos >= 0) ? History[HistoryPos] : ""; + data->DeleteChars(0, data->BufTextLen); + data->InsertChars(0, history_str); + } + } } return 0; } }; -static void ShowExampleAppConsole(bool* p_open) +static void ShowExampleAppConsole(bool *p_open) { static ExampleAppConsole console; console.Draw("Example: Console", p_open); @@ -9051,10 +10266,10 @@ static void ShowExampleAppConsole(bool* p_open) // my_log.Draw("title"); struct ExampleAppLog { - ImGuiTextBuffer Buf; - ImGuiTextFilter Filter; - ImVector LineOffsets; // Index to lines offset. We maintain this with AddLog() calls. - bool AutoScroll; // Keep scrolling if already at the bottom. + ImGuiTextBuffer Buf; + ImGuiTextFilter Filter; + ImVector LineOffsets; // Index to lines offset. We maintain this with AddLog() calls. + bool AutoScroll; // Keep scrolling if already at the bottom. ExampleAppLog() { @@ -9062,14 +10277,14 @@ struct ExampleAppLog Clear(); } - void Clear() + void Clear() { Buf.clear(); LineOffsets.clear(); LineOffsets.push_back(0); } - void AddLog(const char* fmt, ...) IM_FMTARGS(2) + void AddLog(const char *fmt, ...) IM_FMTARGS(2) { int old_size = Buf.size(); va_list args; @@ -9081,7 +10296,7 @@ struct ExampleAppLog LineOffsets.push_back(old_size + 1); } - void Draw(const char* title, bool* p_open = NULL) + void Draw(const char *title, bool *p_open = NULL) { if (!ImGui::Begin(title, p_open)) { @@ -9116,8 +10331,8 @@ struct ExampleAppLog ImGui::LogToClipboard(); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); - const char* buf = Buf.begin(); - const char* buf_end = Buf.end(); + const char *buf = Buf.begin(); + const char *buf_end = Buf.end(); if (Filter.IsActive()) { // In this example we don't use the clipper when Filter is enabled. @@ -9126,8 +10341,9 @@ struct ExampleAppLog // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp). for (int line_no = 0; line_no < LineOffsets.Size; line_no++) { - const char* line_start = buf + LineOffsets[line_no]; - const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; + const char *line_start = buf + LineOffsets[line_no]; + const char *line_end = + (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; if (Filter.PassFilter(line_start, line_end)) ImGui::TextUnformatted(line_start, line_end); } @@ -9136,25 +10352,27 @@ struct ExampleAppLog { // The simplest and easy way to display the entire buffer: // ImGui::TextUnformatted(buf_begin, buf_end); - // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward - // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are - // within the visible area. - // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them - // on your side is recommended. Using ImGuiListClipper requires + // And it'll just work. TextUnformatted() has specialization for large blob of text and will + // fast-forward to skip non-visible lines. Here we instead demonstrate using the clipper to only process + // lines that are within the visible area. If you have tens of thousands of items and their processing + // cost is non-negligible, coarse clipping them on your side is recommended. Using ImGuiListClipper + // requires // - A) random access into your data // - B) items all being the same height, // both of which we can handle since we have an array pointing to the beginning of each line of text. - // When using the filter (in the block of code above) we don't have random access into the data to display - // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make - // it possible (and would be recommended if you want to search through tens of thousands of entries). + // When using the filter (in the block of code above) we don't have random access into the data to + // display anymore, which is why we don't use the clipper. Storing or skimming through the search result + // would make it possible (and would be recommended if you want to search through tens of thousands of + // entries). ImGuiListClipper clipper; clipper.Begin(LineOffsets.Size); while (clipper.Step()) { for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) { - const char* line_start = buf + LineOffsets[line_no]; - const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; + const char *line_start = buf + LineOffsets[line_no]; + const char *line_end = + (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; ImGui::TextUnformatted(line_start, line_end); } } @@ -9162,8 +10380,8 @@ struct ExampleAppLog } ImGui::PopStyleVar(); - // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. - // Using a scrollbar or mouse-wheel will take away from the bottom edge. + // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the + // frame. Using a scrollbar or mouse-wheel will take away from the bottom edge. if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) ImGui::SetScrollHereY(1.0f); } @@ -9173,7 +10391,7 @@ struct ExampleAppLog }; // Demonstrate creating a simple log window with basic filtering. -static void ShowExampleAppLog(bool* p_open) +static void ShowExampleAppLog(bool *p_open) { static ExampleAppLog log; @@ -9186,14 +10404,15 @@ static void ShowExampleAppLog(bool* p_open) if (ImGui::SmallButton("[Debug] Add 5 entries")) { static int counter = 0; - const char* categories[3] = { "info", "warn", "error" }; - const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" }; + const char *categories[3] = {"info", "warn", "error"}; + const char *words[] = {"Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", + "Absquatulate", "Nincompoop", "Pauciloquent"}; for (int n = 0; n < 5; n++) { - const char* category = categories[counter % IM_ARRAYSIZE(categories)]; - const char* word = words[counter % IM_ARRAYSIZE(words)]; - log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", - ImGui::GetFrameCount(), category, ImGui::GetTime(), word); + const char *category = categories[counter % IM_ARRAYSIZE(categories)]; + const char *word = words[counter % IM_ARRAYSIZE(words)]; + log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", ImGui::GetFrameCount(), + category, ImGui::GetTime(), word); counter++; } } @@ -9208,7 +10427,7 @@ static void ShowExampleAppLog(bool* p_open) //----------------------------------------------------------------------------- // Demonstrate create a window with multiple child windows. -static void ShowExampleAppLayout(bool* p_open) +static void ShowExampleAppLayout(bool *p_open) { ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver); if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar)) @@ -9218,7 +10437,10 @@ static void ShowExampleAppLayout(bool* p_open) { if (ImGui::BeginMenu("File")) { - if (ImGui::MenuItem("Close", "Ctrl+W")) { *p_open = false; } + if (ImGui::MenuItem("Close", "Ctrl+W")) + { + *p_open = false; + } ImGui::EndMenu(); } ImGui::EndMenuBar(); @@ -9243,14 +10465,16 @@ static void ShowExampleAppLayout(bool* p_open) // Right { ImGui::BeginGroup(); - ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us + ImGui::BeginChild("item view", + ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us ImGui::Text("MyObject: %d", selected); ImGui::Separator(); if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None)) { if (ImGui::BeginTabItem("Description")) { - ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "); + ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor " + "incididunt ut labore et dolore magna aliqua. "); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Details")) @@ -9261,9 +10485,13 @@ static void ShowExampleAppLayout(bool* p_open) ImGui::EndTabBar(); } ImGui::EndChild(); - if (ImGui::Button("Revert")) {} + if (ImGui::Button("Revert")) + { + } ImGui::SameLine(); - if (ImGui::Button("Save")) {} + if (ImGui::Button("Save")) + { + } ImGui::EndGroup(); } } @@ -9276,30 +10504,33 @@ static void ShowExampleAppLayout(bool* p_open) // Some of the interactions are a bit lack-luster: // - We would want pressing validating or leaving the filter to somehow restore focus. // - We may want more advanced filtering (child nodes) and clipper support: both will need extra work. -// - We would want to customize some keyboard interactions to easily keyboard navigate between the tree and the properties. +// - We would want to customize some keyboard interactions to easily keyboard navigate between the tree and the +// properties. //----------------------------------------------------------------------------- struct ExampleAppPropertyEditor { - ImGuiTextFilter Filter; - ExampleTreeNode* VisibleNode = NULL; + ImGuiTextFilter Filter; + ExampleTreeNode *VisibleNode = NULL; - void Draw(ExampleTreeNode* root_node) + void Draw(ExampleTreeNode *root_node) { // Left side: draw tree // - Currently using a table to benefit from RowBg feature - if (ImGui::BeginChild("##tree", ImVec2(300, 0), ImGuiChildFlags_ResizeX | ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened)) + if (ImGui::BeginChild("##tree", ImVec2(300, 0), + ImGuiChildFlags_ResizeX | ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened)) { ImGui::SetNextItemWidth(-FLT_MIN); ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip); ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true); - if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_ARRAYSIZE(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll)) + if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_ARRAYSIZE(Filter.InputBuf), + ImGuiInputTextFlags_EscapeClearsAll)) Filter.Build(); ImGui::PopItemFlag(); if (ImGui::BeginTable("##bg", 1, ImGuiTableFlags_RowBg)) { - for (ExampleTreeNode* node : root_node->Childs) + for (ExampleTreeNode *node : root_node->Childs) if (Filter.PassFilter(node->Name)) // Filter root node DrawTreeNode(node); ImGui::EndTable(); @@ -9311,7 +10542,7 @@ struct ExampleAppPropertyEditor ImGui::SameLine(); ImGui::BeginGroup(); // Lock X position - if (ExampleTreeNode* node = VisibleNode) + if (ExampleTreeNode *node = VisibleNode) { ImGui::Text("%s", node->Name); ImGui::TextDisabled("UID: 0x%08X", node->UID); @@ -9325,9 +10556,10 @@ struct ExampleAppPropertyEditor if (node->HasData) { // In a typical application, the structure description would be derived from a data-driven system. - // - We try to mimic this with our ExampleMemberInfo structure and the ExampleTreeNodeMemberInfos[] array. + // - We try to mimic this with our ExampleMemberInfo structure and the ExampleTreeNodeMemberInfos[] + // array. // - Limits and some details are hard-coded to simplify the demo. - for (const ExampleMemberInfo& field_desc : ExampleTreeNodeMemberInfos) + for (const ExampleMemberInfo &field_desc : ExampleTreeNodeMemberInfos) { ImGui::TableNextRow(); ImGui::PushID(field_desc.Name); @@ -9335,32 +10567,30 @@ struct ExampleAppPropertyEditor ImGui::AlignTextToFramePadding(); ImGui::TextUnformatted(field_desc.Name); ImGui::TableNextColumn(); - void* field_ptr = (void*)(((unsigned char*)node) + field_desc.Offset); + void *field_ptr = (void *)(((unsigned char *)node) + field_desc.Offset); switch (field_desc.DataType) { - case ImGuiDataType_Bool: - { + case ImGuiDataType_Bool: { IM_ASSERT(field_desc.DataCount == 1); - ImGui::Checkbox("##Editor", (bool*)field_ptr); + ImGui::Checkbox("##Editor", (bool *)field_ptr); break; } - case ImGuiDataType_S32: - { + case ImGuiDataType_S32: { int v_min = INT_MIN, v_max = INT_MAX; ImGui::SetNextItemWidth(-FLT_MIN); - ImGui::DragScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, 1.0f, &v_min, &v_max); + ImGui::DragScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, 1.0f, + &v_min, &v_max); break; } - case ImGuiDataType_Float: - { + case ImGuiDataType_Float: { float v_min = 0.0f, v_max = 1.0f; ImGui::SetNextItemWidth(-FLT_MIN); - ImGui::SliderScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, &v_min, &v_max); + ImGui::SliderScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, + &v_min, &v_max); break; } - case ImGuiDataType_String: - { - ImGui::InputText("##Editor", reinterpret_cast(field_ptr), 28); + case ImGuiDataType_String: { + ImGui::InputText("##Editor", reinterpret_cast(field_ptr), 28); break; } } @@ -9374,16 +10604,18 @@ struct ExampleAppPropertyEditor ImGui::EndGroup(); } - void DrawTreeNode(ExampleTreeNode* node) + void DrawTreeNode(ExampleTreeNode *node) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::PushID(node->UID); ImGuiTreeNodeFlags tree_flags = ImGuiTreeNodeFlags_None; - tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;// Standard opening mode as we are likely to want to add selection afterwards - tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsToParent; // Left arrow support - tree_flags |= ImGuiTreeNodeFlags_SpanFullWidth; // Span full width for easier mouse reach - tree_flags |= ImGuiTreeNodeFlags_DrawLinesToNodes; // Always draw hierarchy outlines + tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | + ImGuiTreeNodeFlags_OpenOnDoubleClick; // Standard opening mode as we are likely to want to add + // selection afterwards + tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsToParent; // Left arrow support + tree_flags |= ImGuiTreeNodeFlags_SpanFullWidth; // Span full width for easier mouse reach + tree_flags |= ImGuiTreeNodeFlags_DrawLinesToNodes; // Always draw hierarchy outlines if (node == VisibleNode) tree_flags |= ImGuiTreeNodeFlags_Selected; if (node->Childs.Size == 0) @@ -9397,7 +10629,7 @@ struct ExampleAppPropertyEditor VisibleNode = node; if (node_open) { - for (ExampleTreeNode* child : node->Childs) + for (ExampleTreeNode *child : node->Childs) DrawTreeNode(child); ImGui::TreePop(); } @@ -9406,7 +10638,7 @@ struct ExampleAppPropertyEditor }; // Demonstrate creating a simple property editor. -static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data) +static void ShowExampleAppPropertyEditor(bool *p_open, ImGuiDemoWindowData *demo_data) { ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); if (!ImGui::Begin("Example: Property editor", p_open)) @@ -9429,7 +10661,7 @@ static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo //----------------------------------------------------------------------------- // Demonstrate/test rendering huge amount of text, and the incidence of clipping. -static void ShowExampleAppLongText(bool* p_open) +static void ShowExampleAppLongText(bool *p_open) { ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); if (!ImGui::Begin("Example: Long text display", p_open)) @@ -9444,11 +10676,15 @@ static void ShowExampleAppLongText(bool* p_open) static int lines = 0; ImGui::Text("Printing unusually long amount of text."); ImGui::Combo("Test type", &test_type, - "Single call to TextUnformatted()\0" - "Multiple calls to Text(), clipped\0" - "Multiple calls to Text(), not clipped (slow)\0"); + "Single call to TextUnformatted()\0" + "Multiple calls to Text(), clipped\0" + "Multiple calls to Text(), not clipped (slow)\0"); ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size()); - if (ImGui::Button("Clear")) { log.clear(); lines = 0; } + if (ImGui::Button("Clear")) + { + log.clear(); + lines = 0; + } ImGui::SameLine(); if (ImGui::Button("Add 1000 lines")) { @@ -9463,18 +10699,17 @@ static void ShowExampleAppLongText(bool* p_open) // Single call to TextUnformatted() with a big buffer ImGui::TextUnformatted(log.begin(), log.end()); break; - case 1: - { - // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); - ImGuiListClipper clipper; - clipper.Begin(lines); - while (clipper.Step()) - for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) - ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); - ImGui::PopStyleVar(); - break; - } + case 1: { + // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + ImGuiListClipper clipper; + clipper.Begin(lines); + while (clipper.Step()) + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); + ImGui::PopStyleVar(); + break; + } case 2: // Multiple calls to Text(), not clipped (slow) ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); @@ -9492,7 +10727,7 @@ static void ShowExampleAppLongText(bool* p_open) //----------------------------------------------------------------------------- // Demonstrate creating a window which gets auto-resized according to its content. -static void ShowExampleAppAutoResize(bool* p_open) +static void ShowExampleAppAutoResize(bool *p_open) { if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize)) { @@ -9502,10 +10737,9 @@ static void ShowExampleAppAutoResize(bool* p_open) IMGUI_DEMO_MARKER("Examples/Auto-resizing window"); static int lines = 10; - ImGui::TextUnformatted( - "Window will resize every-frame to the size of its content.\n" - "Note that you probably don't want to query the window size to\n" - "output your content because that would create a feedback loop."); + ImGui::TextUnformatted("Window will resize every-frame to the size of its content.\n" + "Note that you probably don't want to query the window size to\n" + "output your content because that would create a feedback loop."); ImGui::SliderInt("Number of lines", &lines, 1, 20); for (int i = 0; i < lines; i++) ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally @@ -9518,31 +10752,31 @@ static void ShowExampleAppAutoResize(bool* p_open) // Demonstrate creating a window with custom resize constraints. // Note that size constraints currently don't work on a docked window (when in 'docking' branch) -static void ShowExampleAppConstrainedResize(bool* p_open) +static void ShowExampleAppConstrainedResize(bool *p_open) { struct CustomConstraints { // Helper functions to demonstrate programmatic constraints // FIXME: This doesn't take account of decoration size (e.g. title bar), library should make this easier. // FIXME: None of the three demos works consistently when resizing from borders. - static void AspectRatio(ImGuiSizeCallbackData* data) + static void AspectRatio(ImGuiSizeCallbackData *data) { - float aspect_ratio = *(float*)data->UserData; + float aspect_ratio = *(float *)data->UserData; data->DesiredSize.y = (float)(int)(data->DesiredSize.x / aspect_ratio); } - static void Square(ImGuiSizeCallbackData* data) + static void Square(ImGuiSizeCallbackData *data) { data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y); } - static void Step(ImGuiSizeCallbackData* data) + static void Step(ImGuiSizeCallbackData *data) { - float step = *(float*)data->UserData; - data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step); + float step = *(float *)data->UserData; + data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, + (int)(data->DesiredSize.y / step + 0.5f) * step); } }; - const char* test_desc[] = - { + const char *test_desc[] = { "Between 100x100 and 500x500", "At least 100x100", "Resize vertical + lock current width", @@ -9563,15 +10797,28 @@ static void ShowExampleAppConstrainedResize(bool* p_open) // Submit constraint float aspect_ratio = 16.0f / 9.0f; float fixed_step = 100.0f; - if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500)); // Between 100x100 and 500x500 - if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 - if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Resize vertical + lock current width - if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Resize horizontal + lock current height - if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width Between and 400 and 500 - if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, FLT_MAX)); // Height at least 400 - if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::AspectRatio, (void*)&aspect_ratio); // Aspect ratio - if (type == 7) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square - if (type == 8) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)&fixed_step); // Fixed Step + if (type == 0) + ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500)); // Between 100x100 and 500x500 + if (type == 1) + ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 + if (type == 2) + ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Resize vertical + lock current width + if (type == 3) + ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), + ImVec2(FLT_MAX, -1)); // Resize horizontal + lock current height + if (type == 4) + ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width Between and 400 and 500 + if (type == 5) + ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, FLT_MAX)); // Height at least 400 + if (type == 6) + ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::AspectRatio, + (void *)&aspect_ratio); // Aspect ratio + if (type == 7) + ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), + CustomConstraints::Square); // Always Square + if (type == 8) + ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, + (void *)&fixed_step); // Fixed Step // Submit window if (!window_padding) @@ -9588,16 +10835,28 @@ static void ShowExampleAppConstrainedResize(bool* p_open) // Display a dummy viewport (in your real app you would likely use ImageButton() to display a texture. ImVec2 avail_size = ImGui::GetContentRegionAvail(); ImVec2 pos = ImGui::GetCursorScreenPos(); - ImGui::ColorButton("viewport", ImVec4(0.5f, 0.2f, 0.5f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, avail_size); + ImGui::ColorButton("viewport", ImVec4(0.5f, 0.2f, 0.5f, 1.0f), + ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, avail_size); ImGui::SetCursorScreenPos(ImVec2(pos.x + 10, pos.y + 10)); ImGui::Text("%.2f x %.2f", avail_size.x, avail_size.y); } else { ImGui::Text("(Hold SHIFT to display a dummy viewport)"); - if (ImGui::Button("Set 200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine(); - if (ImGui::Button("Set 500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine(); - if (ImGui::Button("Set 800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); } + if (ImGui::Button("Set 200x200")) + { + ImGui::SetWindowSize(ImVec2(200, 200)); + } + ImGui::SameLine(); + if (ImGui::Button("Set 500x500")) + { + ImGui::SetWindowSize(ImVec2(500, 500)); + } + ImGui::SameLine(); + if (ImGui::Button("Set 800x200")) + { + ImGui::SetWindowSize(ImVec2(800, 200)); + } ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20); ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc)); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20); @@ -9617,15 +10876,17 @@ static void ShowExampleAppConstrainedResize(bool* p_open) // Demonstrate creating a simple static window with no decoration // + a context-menu to choose which corner of the screen to use. -static void ShowExampleAppSimpleOverlay(bool* p_open) +static void ShowExampleAppSimpleOverlay(bool *p_open) { static int location = 0; - ImGuiIO& io = ImGui::GetIO(); - ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav; + ImGuiIO &io = ImGui::GetIO(); + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | + ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | + ImGuiWindowFlags_NoNav; if (location >= 0) { const float PAD = 10.0f; - const ImGuiViewport* viewport = ImGui::GetMainViewport(); + const ImGuiViewport *viewport = ImGui::GetMainViewport(); ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any! ImVec2 work_size = viewport->WorkSize; ImVec2 window_pos, window_pos_pivot; @@ -9646,7 +10907,8 @@ static void ShowExampleAppSimpleOverlay(bool* p_open) if (ImGui::Begin("Example: Simple overlay", p_open, window_flags)) { IMGUI_DEMO_MARKER("Examples/Simple Overlay"); - ImGui::Text("Simple overlay\n" "(right-click to change position)"); + ImGui::Text("Simple overlay\n" + "(right-click to change position)"); ImGui::Separator(); if (ImGui::IsMousePosValid()) ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y); @@ -9654,13 +10916,20 @@ static void ShowExampleAppSimpleOverlay(bool* p_open) ImGui::Text("Mouse Position: "); if (ImGui::BeginPopupContextWindow()) { - if (ImGui::MenuItem("Custom", NULL, location == -1)) location = -1; - if (ImGui::MenuItem("Center", NULL, location == -2)) location = -2; - if (ImGui::MenuItem("Top-left", NULL, location == 0)) location = 0; - if (ImGui::MenuItem("Top-right", NULL, location == 1)) location = 1; - if (ImGui::MenuItem("Bottom-left", NULL, location == 2)) location = 2; - if (ImGui::MenuItem("Bottom-right", NULL, location == 3)) location = 3; - if (p_open && ImGui::MenuItem("Close")) *p_open = false; + if (ImGui::MenuItem("Custom", NULL, location == -1)) + location = -1; + if (ImGui::MenuItem("Center", NULL, location == -2)) + location = -2; + if (ImGui::MenuItem("Top-left", NULL, location == 0)) + location = 0; + if (ImGui::MenuItem("Top-right", NULL, location == 1)) + location = 1; + if (ImGui::MenuItem("Bottom-left", NULL, location == 2)) + location = 2; + if (ImGui::MenuItem("Bottom-right", NULL, location == 3)) + location = 3; + if (p_open && ImGui::MenuItem("Close")) + *p_open = false; ImGui::EndPopup(); } } @@ -9672,14 +10941,15 @@ static void ShowExampleAppSimpleOverlay(bool* p_open) //----------------------------------------------------------------------------- // Demonstrate creating a window covering the entire screen/viewport -static void ShowExampleAppFullscreen(bool* p_open) +static void ShowExampleAppFullscreen(bool *p_open) { static bool use_work_area = true; - static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings; + static ImGuiWindowFlags flags = + ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings; // We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.) // Based on your use case you may want one or the other. - const ImGuiViewport* viewport = ImGui::GetMainViewport(); + const ImGuiViewport *viewport = ImGui::GetMainViewport(); ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos); ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize : viewport->Size); @@ -9687,7 +10957,8 @@ static void ShowExampleAppFullscreen(bool* p_open) { ImGui::Checkbox("Use work area instead of main area", &use_work_area); ImGui::SameLine(); - HelpMarker("Main Area = entire viewport,\nWork Area = entire viewport minus sections used by the main menu bars, task bars etc.\n\nEnable the main-menu bar in Examples menu to see the difference."); + HelpMarker("Main Area = entire viewport,\nWork Area = entire viewport minus sections used by the main menu " + "bars, task bars etc.\n\nEnable the main-menu bar in Examples menu to see the difference."); ImGui::CheckboxFlags("ImGuiWindowFlags_NoBackground", &flags, ImGuiWindowFlags_NoBackground); ImGui::CheckboxFlags("ImGuiWindowFlags_NoDecoration", &flags, ImGuiWindowFlags_NoDecoration); @@ -9710,9 +10981,9 @@ static void ShowExampleAppFullscreen(bool* p_open) // Demonstrate the use of "##" and "###" in identifiers to manipulate ID generation. // This applies to all regular items as well. // Read FAQ section "How can I have multiple widgets with the same label?" for details. -static void ShowExampleAppWindowTitles(bool*) +static void ShowExampleAppWindowTitles(bool *) { - const ImGuiViewport* viewport = ImGui::GetMainViewport(); + const ImGuiViewport *viewport = ImGui::GetMainViewport(); const ImVec2 base_pos = viewport->Pos; // By default, Windows are uniquely identified by their title. @@ -9732,7 +11003,8 @@ static void ShowExampleAppWindowTitles(bool*) // Using "###" to display a changing title but keep a static identifier "AnimatedTitle" char buf[128]; - sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount()); + sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], + ImGui::GetFrameCount()); ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), ImGuiCond_FirstUseEver); ImGui::Begin(buf); ImGui::Text("This window has a changing title."); @@ -9744,15 +11016,16 @@ static void ShowExampleAppWindowTitles(bool*) //----------------------------------------------------------------------------- // Add a |_| looking shape -static void PathConcaveShape(ImDrawList* draw_list, float x, float y, float sz) +static void PathConcaveShape(ImDrawList *draw_list, float x, float y, float sz) { - const ImVec2 pos_norms[] = { { 0.0f, 0.0f }, { 0.3f, 0.0f }, { 0.3f, 0.7f }, { 0.7f, 0.7f }, { 0.7f, 0.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }, { 0.0f, 1.0f } }; - for (const ImVec2& p : pos_norms) + const ImVec2 pos_norms[] = {{0.0f, 0.0f}, {0.3f, 0.0f}, {0.3f, 0.7f}, {0.7f, 0.7f}, + {0.7f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}}; + for (const ImVec2 &p : pos_norms) draw_list->PathLineTo(ImVec2(x + 0.5f + (int)(sz * p.x), y + 0.5f + (int)(sz * p.y))); } // Demonstrate using the low-level ImDrawList to draw custom shapes. -static void ShowExampleAppCustomRendering(bool* p_open) +static void ShowExampleAppCustomRendering(bool *p_open) { if (!ImGui::Begin("Example: Custom rendering", p_open)) { @@ -9771,11 +11044,12 @@ static void ShowExampleAppCustomRendering(bool* p_open) if (ImGui::BeginTabItem("Primitives")) { ImGui::PushItemWidth(-ImGui::GetFontSize() * 15); - ImDrawList* draw_list = ImGui::GetWindowDrawList(); + ImDrawList *draw_list = ImGui::GetWindowDrawList(); // Draw gradients // (note that those are currently exacerbating our sRGB/Linear issues) - // Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well.. + // Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the + // IM_COL32() directly as well.. ImGui::Text("Gradients"); ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight()); { @@ -9810,7 +11084,8 @@ static void ShowExampleAppCustomRendering(bool* p_open) ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12); ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - circle_segments_override |= ImGui::SliderInt("Circle segments override", &circle_segments_override_v, 3, 40); + circle_segments_override |= + ImGui::SliderInt("Circle segments override", &circle_segments_override_v, 3, 40); ImGui::Checkbox("##curvessegmentoverride", &curve_segments_override); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); curve_segments_override |= ImGui::SliderInt("Curves segments override", &curve_segments_override_v, 3, 40); @@ -9823,8 +11098,10 @@ static void ShowExampleAppCustomRendering(bool* p_open) 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; - const ImVec2 cp3[3] = { ImVec2(0.0f, sz * 0.6f), ImVec2(sz * 0.5f, -sz * 0.4f), ImVec2(sz, sz) }; // Control points for curves - const ImVec2 cp4[4] = { ImVec2(0.0f, 0.0f), ImVec2(sz * 1.3f, sz * 0.3f), ImVec2(sz - sz * 1.3f, sz - sz * 0.3f), ImVec2(sz, sz) }; + const ImVec2 cp3[3] = {ImVec2(0.0f, sz * 0.6f), ImVec2(sz * 0.5f, -sz * 0.4f), + ImVec2(sz, sz)}; // Control points for curves + const ImVec2 cp4[4] = {ImVec2(0.0f, 0.0f), ImVec2(sz * 1.3f, sz * 0.3f), + ImVec2(sz - sz * 1.3f, sz - sz * 0.3f), ImVec2(sz, sz)}; float x = p.x + 4.0f; float y = p.y + 4.0f; @@ -9832,49 +11109,82 @@ static void ShowExampleAppCustomRendering(bool* p_open) { // First line uses a thickness of 1.0f, second line uses the configurable thickness 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->AddEllipse(ImVec2(x + sz*0.5f, y + sz*0.5f), ImVec2(sz*0.5f, sz*0.3f), col, -0.3f, circle_segments, th); x += sz + spacing; // Ellipse - 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 - PathConcaveShape(draw_list, x, y, sz); draw_list->PathStroke(col, ImDrawFlags_Closed, th); x += sz + spacing; // Concave Shape - //draw_list->AddPolyline(concave_shape, IM_ARRAYSIZE(concave_shape), col, ImDrawFlags_Closed, th); - draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!) - draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!) - draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line + 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->AddEllipse(ImVec2(x + sz * 0.5f, y + sz * 0.5f), ImVec2(sz * 0.5f, sz * 0.3f), col, -0.3f, + circle_segments, th); + x += sz + spacing; // Ellipse + 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 + PathConcaveShape(draw_list, x, y, sz); + draw_list->PathStroke(col, ImDrawFlags_Closed, th); + x += sz + spacing; // Concave Shape + // draw_list->AddPolyline(concave_shape, IM_ARRAYSIZE(concave_shape), col, ImDrawFlags_Closed, th); + draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th); + x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!) + draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); + x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!) + draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); + x += sz + spacing; // Diagonal line // Path - draw_list->PathArcTo(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, 3.141592f, 3.141592f * -0.5f); + draw_list->PathArcTo(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, 3.141592f, 3.141592f * -0.5f); draw_list->PathStroke(col, ImDrawFlags_None, th); x += sz + spacing; // Quadratic Bezier Curve (3 control points) - draw_list->AddBezierQuadratic(ImVec2(x + cp3[0].x, y + cp3[0].y), ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), col, th, curve_segments); + draw_list->AddBezierQuadratic(ImVec2(x + cp3[0].x, y + cp3[0].y), ImVec2(x + cp3[1].x, y + cp3[1].y), + ImVec2(x + cp3[2].x, y + cp3[2].y), col, th, curve_segments); x += sz + spacing; // Cubic Bezier Curve (4 control points) - draw_list->AddBezierCubic(ImVec2(x + cp4[0].x, y + cp4[0].y), ImVec2(x + cp4[1].x, y + cp4[1].y), ImVec2(x + cp4[2].x, y + cp4[2].y), ImVec2(x + cp4[3].x, y + cp4[3].y), col, th, curve_segments); + draw_list->AddBezierCubic(ImVec2(x + cp4[0].x, y + cp4[0].y), ImVec2(x + cp4[1].x, y + cp4[1].y), + ImVec2(x + cp4[2].x, y + cp4[2].y), ImVec2(x + cp4[3].x, y + cp4[3].y), col, + th, curve_segments); x = p.x + 4; y += sz + spacing; } // Filled shapes - draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, ngon_sides); x += sz + spacing; // N-gon - draw_list->AddCircleFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, circle_segments); x += sz + spacing; // Circle - draw_list->AddEllipseFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), ImVec2(sz * 0.5f, sz * 0.3f), col, -0.3f, circle_segments); x += sz + spacing;// Ellipse - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); x += sz + spacing; // Square with all rounded corners - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br); x += sz + spacing; // Square with two rounded corners - draw_list->AddTriangleFilled(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col); x += sz + spacing; // Triangle - //draw_list->AddTriangleFilled(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col); x += sz*0.4f + spacing; // Thin triangle - PathConcaveShape(draw_list, x, y, sz); draw_list->PathFillConcave(col); x += sz + spacing; // Concave shape - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x += sz + spacing; // Horizontal line (faster than AddLine, but only handle integer thickness) - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x += spacing * 2.0f;// Vertical line (faster than AddLine, but only handle integer thickness) - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine) + draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, ngon_sides); + x += sz + spacing; // N-gon + draw_list->AddCircleFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, circle_segments); + x += sz + spacing; // Circle + draw_list->AddEllipseFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), ImVec2(sz * 0.5f, sz * 0.3f), col, -0.3f, + circle_segments); + x += sz + spacing; // Ellipse + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); + x += sz + spacing; // Square + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); + x += sz + spacing; // Square with all rounded corners + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br); + x += sz + spacing; // Square with two rounded corners + draw_list->AddTriangleFilled(ImVec2(x + sz * 0.5f, y), ImVec2(x + sz, y + sz - 0.5f), + ImVec2(x, y + sz - 0.5f), col); + x += sz + spacing; // Triangle + // draw_list->AddTriangleFilled(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), + // col); x += sz*0.4f + spacing; // Thin triangle + PathConcaveShape(draw_list, x, y, sz); + draw_list->PathFillConcave(col); + x += sz + spacing; // Concave shape + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); + x += sz + spacing; // Horizontal line (faster than AddLine, but only handle integer thickness) + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); + x += spacing * 2.0f; // Vertical line (faster than AddLine, but only handle integer thickness) + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); + x += sz; // Pixel (faster than AddLine) // Path draw_list->PathArcTo(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, 3.141592f * -0.5f, 3.141592f); @@ -9883,11 +11193,14 @@ static void ShowExampleAppCustomRendering(bool* p_open) // Quadratic Bezier Curve (3 control points) draw_list->PathLineTo(ImVec2(x + cp3[0].x, y + cp3[0].y)); - draw_list->PathBezierQuadraticCurveTo(ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), curve_segments); + draw_list->PathBezierQuadraticCurveTo(ImVec2(x + cp3[1].x, y + cp3[1].y), + ImVec2(x + cp3[2].x, y + cp3[2].y), curve_segments); draw_list->PathFillConvex(col); x += sz + spacing; - draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255)); + draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), + IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), + IM_COL32(0, 255, 0, 255)); x += sz + spacing; ImGui::Dummy(ImVec2((sz + spacing) * 13.2f, (sz + spacing) * 3.0f)); @@ -9908,8 +11221,8 @@ static void ShowExampleAppCustomRendering(bool* p_open) ImGui::Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu."); // Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling. - // Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls. - // To use a child window instead we could use, e.g: + // Here we demonstrate that this can be replaced by simple offsetting + custom drawing + + // PushClipRect/PopClipRect() calls. To use a child window instead we could use, e.g: // ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Disable padding // ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove); @@ -9918,23 +11231,27 @@ static void ShowExampleAppCustomRendering(bool* p_open) // [...] // ImGui::EndChild(); - // Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive() - ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates! - ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available - if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f; - if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f; + // Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use + // IsItemHovered()/IsItemActive() + ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates! + ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available + if (canvas_sz.x < 50.0f) + canvas_sz.x = 50.0f; + if (canvas_sz.y < 50.0f) + canvas_sz.y = 50.0f; ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y); // Draw border and background color - ImGuiIO& io = ImGui::GetIO(); - ImDrawList* draw_list = ImGui::GetWindowDrawList(); + ImGuiIO &io = ImGui::GetIO(); + ImDrawList *draw_list = ImGui::GetWindowDrawList(); draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255)); draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255)); // This will catch our interactions - ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight); - const bool is_hovered = ImGui::IsItemHovered(); // Hovered - const bool is_active = ImGui::IsItemActive(); // Held + ImGui::InvisibleButton("canvas", canvas_sz, + ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight); + const bool is_hovered = ImGui::IsItemHovered(); // Hovered + const bool is_active = ImGui::IsItemActive(); // Held const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y); @@ -9970,8 +11287,14 @@ static void ShowExampleAppCustomRendering(bool* p_open) if (adding_line) points.resize(points.size() - 2); adding_line = false; - if (ImGui::MenuItem("Remove one", NULL, false, points.Size > 0)) { points.resize(points.size() - 2); } - if (ImGui::MenuItem("Remove all", NULL, false, points.Size > 0)) { points.clear(); } + if (ImGui::MenuItem("Remove one", NULL, false, points.Size > 0)) + { + points.resize(points.size() - 2); + } + if (ImGui::MenuItem("Remove all", NULL, false, points.Size > 0)) + { + points.clear(); + } ImGui::EndPopup(); } @@ -9981,12 +11304,16 @@ static void ShowExampleAppCustomRendering(bool* p_open) { const float GRID_STEP = 64.0f; for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP) - draw_list->AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), ImVec2(canvas_p0.x + x, canvas_p1.y), IM_COL32(200, 200, 200, 40)); + draw_list->AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), ImVec2(canvas_p0.x + x, canvas_p1.y), + IM_COL32(200, 200, 200, 40)); for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP) - draw_list->AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), ImVec2(canvas_p1.x, canvas_p0.y + y), IM_COL32(200, 200, 200, 40)); + draw_list->AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), ImVec2(canvas_p1.x, canvas_p0.y + y), + IM_COL32(200, 200, 200, 40)); } for (int n = 0; n < points.Size; n += 2) - draw_list->AddLine(ImVec2(origin.x + points[n].x, origin.y + points[n].y), ImVec2(origin.x + points[n + 1].x, origin.y + points[n + 1].y), IM_COL32(255, 255, 0, 255), 2.0f); + draw_list->AddLine(ImVec2(origin.x + points[n].x, origin.y + points[n].y), + ImVec2(origin.x + points[n + 1].x, origin.y + points[n + 1].y), + IM_COL32(255, 255, 0, 255), 2.0f); draw_list->PopClipRect(); ImGui::EndTabItem(); @@ -9997,16 +11324,20 @@ static void ShowExampleAppCustomRendering(bool* p_open) static bool draw_bg = true; static bool draw_fg = true; ImGui::Checkbox("Draw in Background draw list", &draw_bg); - ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows."); + ImGui::SameLine(); + HelpMarker("The Background draw list will be rendered below every Dear ImGui windows."); ImGui::Checkbox("Draw in Foreground draw list", &draw_fg); - ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows."); + ImGui::SameLine(); + HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows."); ImVec2 window_pos = ImGui::GetWindowPos(); ImVec2 window_size = ImGui::GetWindowSize(); ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f); if (draw_bg) - ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10 + 4); + ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), + 0, 10 + 4); if (draw_fg) - ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10); + ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), + 0, 10); ImGui::EndTabItem(); } @@ -10015,13 +11346,15 @@ static void ShowExampleAppCustomRendering(bool* p_open) // but you can also instantiate your own ImDrawListSplitter if you need to nest them. if (ImGui::BeginTabItem("Draw Channels")) { - ImDrawList* draw_list = ImGui::GetWindowDrawList(); + ImDrawList *draw_list = ImGui::GetWindowDrawList(); { ImGui::Text("Blue shape is drawn first: appears in back"); ImGui::Text("Red shape is drawn after: appears in front"); ImVec2 p0 = ImGui::GetCursorScreenPos(); - draw_list->AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)); // Blue - draw_list->AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)); // Red + draw_list->AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), + IM_COL32(0, 0, 255, 255)); // Blue + draw_list->AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), + IM_COL32(255, 0, 0, 255)); // Red ImGui::Dummy(ImVec2(75, 75)); } ImGui::Separator(); @@ -10031,12 +11364,15 @@ static void ShowExampleAppCustomRendering(bool* p_open) ImVec2 p1 = ImGui::GetCursorScreenPos(); // Create 2 channels and draw a Blue shape THEN a Red shape. - // You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls. + // You can create any number of channels. Tables API use 1 channel per column in order to better batch + // draw calls. draw_list->ChannelsSplit(2); draw_list->ChannelsSetCurrent(1); - draw_list->AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)); // Blue + draw_list->AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), + IM_COL32(0, 0, 255, 255)); // Blue draw_list->ChannelsSetCurrent(0); - draw_list->AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)); // Red + draw_list->AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), + IM_COL32(255, 0, 0, 255)); // Red // Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1. // This works by copying draw indices only (vertices are not copied). @@ -10060,14 +11396,14 @@ static void ShowExampleAppCustomRendering(bool* p_open) // Simplified structure to mimic a Document model struct MyDocument { - char Name[32]; // Document title - int UID; // Unique ID (necessary as we can change title) - bool Open; // Set when open (we keep an array of all available documents to simplify demo code!) - bool OpenPrev; // Copy of Open from last update. - bool Dirty; // Set when the document has been modified - ImVec4 Color; // An arbitrary variable associated to the document + char Name[32]; // Document title + int UID; // Unique ID (necessary as we can change title) + bool Open; // Set when open (we keep an array of all available documents to simplify demo code!) + bool OpenPrev; // Copy of Open from last update. + bool Dirty; // Set when the document has been modified + ImVec4 Color; // An arbitrary variable associated to the document - MyDocument(int uid, const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f)) + MyDocument(int uid, const char *name, bool open = true, const ImVec4 &color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f)) { UID = uid; snprintf(Name, sizeof(Name), "%s", name); @@ -10075,41 +11411,52 @@ struct MyDocument Dirty = false; Color = color; } - void DoOpen() { Open = true; } - void DoForceClose() { Open = false; Dirty = false; } - void DoSave() { Dirty = false; } + void DoOpen() + { + Open = true; + } + void DoForceClose() + { + Open = false; + Dirty = false; + } + void DoSave() + { + Dirty = false; + } }; struct ExampleAppDocuments { - ImVector Documents; - ImVector CloseQueue; - MyDocument* RenamingDoc = NULL; - bool RenamingStarted = false; + ImVector Documents; + ImVector CloseQueue; + MyDocument *RenamingDoc = NULL; + bool RenamingStarted = false; ExampleAppDocuments() { - Documents.push_back(MyDocument(0, "Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f))); - Documents.push_back(MyDocument(1, "Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f))); - Documents.push_back(MyDocument(2, "Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f))); - Documents.push_back(MyDocument(3, "Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f))); + Documents.push_back(MyDocument(0, "Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f))); + Documents.push_back(MyDocument(1, "Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f))); + Documents.push_back(MyDocument(2, "Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f))); + Documents.push_back(MyDocument(3, "Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f))); Documents.push_back(MyDocument(4, "A Rather Long Title", false, ImVec4(0.4f, 0.8f, 0.8f, 1.0f))); - Documents.push_back(MyDocument(5, "Some Document", false, ImVec4(0.8f, 0.8f, 1.0f, 1.0f))); + Documents.push_back(MyDocument(5, "Some Document", false, ImVec4(0.8f, 0.8f, 1.0f, 1.0f))); } // As we allow to change document name, we append a never-changing document ID so tabs are stable - void GetTabName(MyDocument* doc, char* out_buf, size_t out_buf_size) + void GetTabName(MyDocument *doc, char *out_buf, size_t out_buf_size) { snprintf(out_buf, out_buf_size, "%s###doc%d", doc->Name, doc->UID); } // Display placeholder contents for the Document - void DisplayDocContents(MyDocument* doc) + void DisplayDocContents(MyDocument *doc) { ImGui::PushID(doc); ImGui::Text("Document \"%s\"", doc->Name); ImGui::PushStyleColor(ImGuiCol_Text, doc->Color); - ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."); + ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt " + "ut labore et dolore magna aliqua."); ImGui::PopStyleColor(); ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_R, ImGuiInputFlags_Tooltip); @@ -10133,12 +11480,13 @@ struct ExampleAppDocuments ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_W, ImGuiInputFlags_Tooltip); if (ImGui::Button("Close")) CloseQueue.push_back(doc); - ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior. + ImGui::ColorEdit3("color", + &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior. ImGui::PopID(); } // Display context menu for the Document - void DisplayDocContextMenu(MyDocument* doc) + void DisplayDocContextMenu(MyDocument *doc) { if (!ImGui::BeginPopupContextItem()) return; @@ -10164,7 +11512,7 @@ struct ExampleAppDocuments // Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag. void NotifyOfDocumentsClosedElsewhere() { - for (MyDocument& doc : Documents) + for (MyDocument &doc : Documents) { if (!doc.Open && doc.OpenPrev) ImGui::SetTabItemClosed(doc.Name); @@ -10173,7 +11521,7 @@ struct ExampleAppDocuments } }; -void ShowExampleAppDocuments(bool* p_open) +void ShowExampleAppDocuments(bool *p_open) { static ExampleAppDocuments app; @@ -10194,18 +11542,18 @@ void ShowExampleAppDocuments(bool* p_open) if (ImGui::BeginMenu("File")) { int open_count = 0; - for (MyDocument& doc : app.Documents) + for (MyDocument &doc : app.Documents) open_count += doc.Open ? 1 : 0; if (ImGui::BeginMenu("Open", open_count < app.Documents.Size)) { - for (MyDocument& doc : app.Documents) + for (MyDocument &doc : app.Documents) if (!doc.Open && ImGui::MenuItem(doc.Name)) doc.DoOpen(); ImGui::EndMenu(); } if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0)) - for (MyDocument& doc : app.Documents) + for (MyDocument &doc : app.Documents) app.CloseQueue.push_back(&doc); if (ImGui::MenuItem("Exit") && p_open) *p_open = false; @@ -10217,7 +11565,7 @@ void ShowExampleAppDocuments(bool* p_open) // [Debug] List documents with one checkbox for each for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) { - MyDocument& doc = app.Documents[doc_n]; + MyDocument &doc = app.Documents[doc_n]; if (doc_n > 0) ImGui::SameLine(); ImGui::PushID(&doc); @@ -10234,10 +11582,10 @@ void ShowExampleAppDocuments(bool* p_open) // - Display a dot next to the title. // - Tab is selected when clicking the X close button. // - Closure is not assumed (will wait for user to stop submitting the tab). - // Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. - // We need to assume closure by default otherwise waiting for "lack of submission" on the next frame would leave an empty - // hole for one-frame, both in the tab-bar and in tab-contents when closing a tab/window. - // The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole. + // Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab + // bar. We need to assume closure by default otherwise waiting for "lack of submission" on the next frame would + // leave an empty hole for one-frame, both in the tab-bar and in tab-contents when closing a tab/window. The + // rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole. // Submit Tab Bar and Tabs { @@ -10249,11 +11597,13 @@ void ShowExampleAppDocuments(bool* p_open) app.NotifyOfDocumentsClosedElsewhere(); // [DEBUG] Stress tests - //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on. - //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway.. + // if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide + // a tab. Test various interactions e.g. dragging with this on. if (ImGui::GetIO().KeyCtrl) + // ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful + // as-is anyway.. // Submit Tabs - for (MyDocument& doc : app.Documents) + for (MyDocument &doc : app.Documents) { if (!doc.Open) continue; @@ -10291,7 +11641,8 @@ void ShowExampleAppDocuments(bool* p_open) if (ImGui::BeginPopup("Rename")) { ImGui::SetNextItemWidth(ImGui::GetFontSize() * 30); - if (ImGui::InputText("###Name", app.RenamingDoc->Name, IM_ARRAYSIZE(app.RenamingDoc->Name), ImGuiInputTextFlags_EnterReturnsTrue)) + if (ImGui::InputText("###Name", app.RenamingDoc->Name, IM_ARRAYSIZE(app.RenamingDoc->Name), + ImGuiInputTextFlags_EnterReturnsTrue)) { ImGui::CloseCurrentPopup(); app.RenamingDoc = NULL; @@ -10330,8 +11681,9 @@ void ShowExampleAppDocuments(bool* p_open) { ImGui::Text("Save change to the following items?"); float item_height = ImGui::GetTextLineHeightWithSpacing(); - if (ImGui::BeginChild(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height), ImGuiChildFlags_FrameStyle)) - for (MyDocument* doc : app.CloseQueue) + if (ImGui::BeginChild(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height), + ImGuiChildFlags_FrameStyle)) + for (MyDocument *doc : app.CloseQueue) if (doc->Dirty) ImGui::Text("%s", doc->Name); ImGui::EndChild(); @@ -10339,7 +11691,7 @@ void ShowExampleAppDocuments(bool* p_open) ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f); if (ImGui::Button("Yes", button_size)) { - for (MyDocument* doc : app.CloseQueue) + for (MyDocument *doc : app.CloseQueue) { if (doc->Dirty) doc->DoSave(); @@ -10351,7 +11703,7 @@ void ShowExampleAppDocuments(bool* p_open) ImGui::SameLine(); if (ImGui::Button("No", button_size)) { - for (MyDocument* doc : app.CloseQueue) + for (MyDocument *doc : app.CloseQueue) doc->DoForceClose(); app.CloseQueue.clear(); ImGui::CloseCurrentPopup(); @@ -10374,18 +11726,22 @@ void ShowExampleAppDocuments(bool* p_open) // [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser() //----------------------------------------------------------------------------- -//#include "imgui_internal.h" // NavMoveRequestTryWrapping() +// #include "imgui_internal.h" // NavMoveRequestTryWrapping() struct ExampleAsset { ImGuiID ID; - int Type; + int Type; - ExampleAsset(ImGuiID id, int type) { ID = id; Type = type; } + ExampleAsset(ImGuiID id, int type) + { + ID = id; + Type = type; + } - static const ImGuiTableSortSpecs* s_current_sort_specs; + static const ImGuiTableSortSpecs *s_current_sort_specs; - static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, ExampleAsset* items, int items_count) + static void SortWithSortSpecs(ImGuiTableSortSpecs *sort_specs, ExampleAsset *items, int items_count) { s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function. if (items_count > 1) @@ -10394,13 +11750,13 @@ struct ExampleAsset } // Compare function to be used by qsort() - static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs) + static int IMGUI_CDECL CompareWithSortSpecs(const void *lhs, const void *rhs) { - const ExampleAsset* a = (const ExampleAsset*)lhs; - const ExampleAsset* b = (const ExampleAsset*)rhs; + const ExampleAsset *a = (const ExampleAsset *)lhs; + const ExampleAsset *b = (const ExampleAsset *)rhs; for (int n = 0; n < s_current_sort_specs->SpecsCount; n++) { - const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n]; + const ImGuiTableColumnSortSpecs *sort_spec = &s_current_sort_specs->Specs[n]; int delta = 0; if (sort_spec->ColumnIndex == 0) delta = ((int)a->ID - (int)b->ID); @@ -10414,36 +11770,39 @@ struct ExampleAsset return ((int)a->ID - (int)b->ID); } }; -const ImGuiTableSortSpecs* ExampleAsset::s_current_sort_specs = NULL; +const ImGuiTableSortSpecs *ExampleAsset::s_current_sort_specs = NULL; struct ExampleAssetsBrowser { // Options - bool ShowTypeOverlay = true; - bool AllowSorting = true; - bool AllowDragUnselected = false; - bool AllowBoxSelect = true; - float IconSize = 32.0f; - int IconSpacing = 10; - int IconHitSpacing = 4; // Increase hit-spacing if you want to make it possible to clear or box-select from gaps. Some spacing is required to able to amend with Shift+box-select. Value is small in Explorer. - bool StretchSpacing = true; + bool ShowTypeOverlay = true; + bool AllowSorting = true; + bool AllowDragUnselected = false; + bool AllowBoxSelect = true; + float IconSize = 32.0f; + int IconSpacing = 10; + int IconHitSpacing = + 4; // Increase hit-spacing if you want to make it possible to clear or box-select from gaps. Some spacing is + // required to able to amend with Shift+box-select. Value is small in Explorer. + bool StretchSpacing = true; // State - ImVector Items; // Our items - ExampleSelectionWithDeletion Selection; // Our selection (ImGuiSelectionBasicStorage + helper funcs to handle deletion) - ImGuiID NextItemId = 0; // Unique identifier when creating new items - bool RequestDelete = false; // Deferred deletion request - bool RequestSort = false; // Deferred sort request - float ZoomWheelAccum = 0.0f; // Mouse wheel accumulator to handle smooth wheels better + ImVector Items; // Our items + ExampleSelectionWithDeletion + Selection; // Our selection (ImGuiSelectionBasicStorage + helper funcs to handle deletion) + ImGuiID NextItemId = 0; // Unique identifier when creating new items + bool RequestDelete = false; // Deferred deletion request + bool RequestSort = false; // Deferred sort request + float ZoomWheelAccum = 0.0f; // Mouse wheel accumulator to handle smooth wheels better // Calculated sizes for layout, output of UpdateLayoutSizes(). Could be locals but our code is simpler this way. - ImVec2 LayoutItemSize; - ImVec2 LayoutItemStep; // == LayoutItemSize + LayoutItemSpacing - float LayoutItemSpacing = 0.0f; - float LayoutSelectableSpacing = 0.0f; - float LayoutOuterPadding = 0.0f; - int LayoutColumnCount = 0; - int LayoutLineCount = 0; + ImVec2 LayoutItemSize; + ImVec2 LayoutItemStep; // == LayoutItemSize + LayoutItemSpacing + float LayoutItemSpacing = 0.0f; + float LayoutSelectableSpacing = 0.0f; + float LayoutOuterPadding = 0.0f; + int LayoutColumnCount = 0; + int LayoutLineCount = 0; // Functions ExampleAssetsBrowser() @@ -10479,7 +11838,8 @@ struct ExampleAssetsBrowser LayoutColumnCount = IM_MAX((int)(avail_width / (LayoutItemSize.x + LayoutItemSpacing)), 1); LayoutLineCount = (Items.Size + LayoutColumnCount - 1) / LayoutColumnCount; - // Layout: when stretching: allocate remaining space to more spacing. Round before division, so item_spacing may be non-integer. + // Layout: when stretching: allocate remaining space to more spacing. Round before division, so item_spacing may + // be non-integer. if (StretchSpacing && LayoutColumnCount > 1) LayoutItemSpacing = floorf(avail_width - LayoutItemSize.x * LayoutColumnCount) / LayoutColumnCount; @@ -10488,7 +11848,7 @@ struct ExampleAssetsBrowser LayoutOuterPadding = floorf(LayoutItemSpacing * 0.5f); } - void Draw(const char* title, bool* p_open) + void Draw(const char *title, bool *p_open) { ImGui::SetNextWindowSize(ImVec2(IconSize * 25, IconSize * 15), ImGuiCond_FirstUseEver); if (!ImGui::Begin(title, p_open, ImGuiWindowFlags_MenuBar)) @@ -10531,7 +11891,8 @@ struct ExampleAssetsBrowser ImGui::SeparatorText("Layout"); ImGui::SliderFloat("Icon Size", &IconSize, 16.0f, 128.0f, "%.0f"); - ImGui::SameLine(); HelpMarker("Use CTRL+Wheel to zoom"); + ImGui::SameLine(); + HelpMarker("Use CTRL+Wheel to zoom"); ImGui::SliderInt("Icon Spacing", &IconSpacing, 0, 32); ImGui::SliderInt("Icon Hit Spacing", &IconHitSpacing, 0, 32); ImGui::Checkbox("Stretch Spacing", &StretchSpacing); @@ -10545,13 +11906,15 @@ struct ExampleAssetsBrowser if (AllowSorting) { ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); - ImGuiTableFlags table_flags_for_sort_specs = ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Borders; - if (ImGui::BeginTable("for_sort_specs_only", 2, table_flags_for_sort_specs, ImVec2(0.0f, ImGui::GetFrameHeight()))) + ImGuiTableFlags table_flags_for_sort_specs = ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti | + ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Borders; + if (ImGui::BeginTable("for_sort_specs_only", 2, table_flags_for_sort_specs, + ImVec2(0.0f, ImGui::GetFrameHeight()))) { ImGui::TableSetupColumn("Index"); ImGui::TableSetupColumn("Type"); ImGui::TableHeadersRow(); - if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs()) + if (ImGuiTableSortSpecs *sort_specs = ImGui::TableGetSortSpecs()) if (sort_specs->SpecsDirty || RequestSort) { ExampleAsset::SortWithSortSpecs(sort_specs, Items.Data, Items.Size); @@ -10562,11 +11925,13 @@ struct ExampleAssetsBrowser ImGui::PopStyleVar(); } - ImGuiIO& io = ImGui::GetIO(); - ImGui::SetNextWindowContentSize(ImVec2(0.0f, LayoutOuterPadding + LayoutLineCount * (LayoutItemSize.y + LayoutItemSpacing))); - if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove)) + ImGuiIO &io = ImGui::GetIO(); + ImGui::SetNextWindowContentSize( + ImVec2(0.0f, LayoutOuterPadding + LayoutLineCount * (LayoutItemSize.y + LayoutItemSpacing))); + if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, + ImGuiWindowFlags_NoMove)) { - ImDrawList* draw_list = ImGui::GetWindowDrawList(); + ImDrawList *draw_list = ImGui::GetWindowDrawList(); const float avail_width = ImGui::GetContentRegionAvail().x; UpdateLayoutSizes(avail_width); @@ -10577,9 +11942,11 @@ struct ExampleAssetsBrowser ImGui::SetCursorScreenPos(start_pos); // Multi-select - ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_ClearOnClickVoid; + ImGuiMultiSelectFlags ms_flags = + ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_ClearOnClickVoid; - // - Enable box-select (in 2D mode, so that changing box-select rectangle X1/X2 boundaries will affect clipped items) + // - Enable box-select (in 2D mode, so that changing box-select rectangle X1/X2 boundaries will affect + // clipped items) if (AllowBoxSelect) ms_flags |= ImGuiMultiSelectFlags_BoxSelect2d; @@ -10588,31 +11955,38 @@ struct ExampleAssetsBrowser ms_flags |= ImGuiMultiSelectFlags_SelectOnClickRelease; // - Enable keyboard wrapping on X axis - // (FIXME-MULTISELECT: We haven't designed/exposed a general nav wrapping api yet, so this flag is provided as a courtesy to avoid doing: + // (FIXME-MULTISELECT: We haven't designed/exposed a general nav wrapping api yet, so this flag is provided + // as a courtesy to avoid doing: // ImGui::NavMoveRequestTryWrapping(ImGui::GetCurrentWindow(), ImGuiNavMoveFlags_WrapX); - // When we finish implementing a more general API for this, we will obsolete this flag in favor of the new system) + // When we finish implementing a more general API for this, we will obsolete this flag in favor of the new + // system) ms_flags |= ImGuiMultiSelectFlags_NavWrapX; - ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, Selection.Size, Items.Size); + ImGuiMultiSelectIO *ms_io = ImGui::BeginMultiSelect(ms_flags, Selection.Size, Items.Size); // Use custom selection adapter: store ID in selection (recommended) Selection.UserData = this; - Selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self_, int idx) { ExampleAssetsBrowser* self = (ExampleAssetsBrowser*)self_->UserData; return self->Items[idx].ID; }; + Selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage *self_, int idx) { + ExampleAssetsBrowser *self = (ExampleAssetsBrowser *)self_->UserData; + return self->Items[idx].ID; + }; Selection.ApplyRequests(ms_io); - const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (Selection.Size > 0)) || RequestDelete; + const bool want_delete = + (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (Selection.Size > 0)) || RequestDelete; const int item_curr_idx_to_focus = want_delete ? Selection.ApplyDeletionPreLoop(ms_io, Items.Size) : -1; RequestDelete = false; - // Push LayoutSelectableSpacing (which is LayoutItemSpacing minus hit-spacing, if we decide to have hit gaps between items) - // Altering style ItemSpacing may seem unnecessary as we position every items using SetCursorScreenPos()... - // But it is necessary for two reasons: + // Push LayoutSelectableSpacing (which is LayoutItemSpacing minus hit-spacing, if we decide to have hit gaps + // between items) Altering style ItemSpacing may seem unnecessary as we position every items using + // SetCursorScreenPos()... But it is necessary for two reasons: // - Selectables uses it by default to visually fill the space between two items. - // - The vertical spacing would be measured by Clipper to calculate line height if we didn't provide it explicitly (here we do). + // - The vertical spacing would be measured by Clipper to calculate line height if we didn't provide it + // explicitly (here we do). ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(LayoutSelectableSpacing, LayoutSelectableSpacing)); // Rendering parameters - const ImU32 icon_type_overlay_colors[3] = { 0, IM_COL32(200, 70, 70, 255), IM_COL32(70, 170, 70, 255) }; + const ImU32 icon_type_overlay_colors[3] = {0, IM_COL32(200, 70, 70, 255), IM_COL32(70, 170, 70, 255)}; const ImU32 icon_bg_color = ImGui::GetColorU32(IM_COL32(35, 35, 35, 220)); const ImVec2 icon_type_overlay_size = ImVec2(4.0f, 4.0f); const bool display_label = (LayoutItemSize.x >= ImGui::CalcTextSize("999").x); @@ -10621,22 +11995,26 @@ struct ExampleAssetsBrowser ImGuiListClipper clipper; clipper.Begin(LayoutLineCount, LayoutItemStep.y); if (item_curr_idx_to_focus != -1) - clipper.IncludeItemByIndex(item_curr_idx_to_focus / column_count); // Ensure focused item line is not clipped. + clipper.IncludeItemByIndex(item_curr_idx_to_focus / + column_count); // Ensure focused item line is not clipped. if (ms_io->RangeSrcItem != -1) - clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem / column_count); // Ensure RangeSrc item line is not clipped. + clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem / + column_count); // Ensure RangeSrc item line is not clipped. while (clipper.Step()) { for (int line_idx = clipper.DisplayStart; line_idx < clipper.DisplayEnd; line_idx++) { const int item_min_idx_for_current_line = line_idx * column_count; const int item_max_idx_for_current_line = IM_MIN((line_idx + 1) * column_count, Items.Size); - for (int item_idx = item_min_idx_for_current_line; item_idx < item_max_idx_for_current_line; ++item_idx) + for (int item_idx = item_min_idx_for_current_line; item_idx < item_max_idx_for_current_line; + ++item_idx) { - ExampleAsset* item_data = &Items[item_idx]; + ExampleAsset *item_data = &Items[item_idx]; ImGui::PushID((int)item_data->ID); // Position item - ImVec2 pos = ImVec2(start_pos.x + (item_idx % column_count) * LayoutItemStep.x, start_pos.y + line_idx * LayoutItemStep.y); + ImVec2 pos = ImVec2(start_pos.x + (item_idx % column_count) * LayoutItemStep.x, + start_pos.y + line_idx * LayoutItemStep.y); ImGui::SetCursorScreenPos(pos); ImGui::SetNextItemSelectionUserData(item_idx); @@ -10661,19 +12039,20 @@ struct ExampleAssetsBrowser if (ImGui::GetDragDropPayload() == NULL) { ImVector payload_items; - void* it = NULL; + void *it = NULL; ImGuiID id = 0; if (!item_is_selected) payload_items.push_back(item_data->ID); else while (Selection.GetNextSelectedItem(&it, &id)) payload_items.push_back(id); - ImGui::SetDragDropPayload("ASSETS_BROWSER_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes()); + ImGui::SetDragDropPayload("ASSETS_BROWSER_ITEMS", payload_items.Data, + (size_t)payload_items.size_in_bytes()); } // Display payload content in tooltip, by extracting it from the payload data // (we could read from selection, but it is more correct and reusable to read from payload) - const ImGuiPayload* payload = ImGui::GetDragDropPayload(); + const ImGuiPayload *payload = ImGui::GetDragDropPayload(); const int payload_count = (int)payload->DataSize / (int)sizeof(ImGuiID); ImGui::Text("%d assets", payload_count); @@ -10681,23 +12060,30 @@ struct ExampleAssetsBrowser } // Render icon (a real app would likely display an image/thumbnail here) - // Because we use ImGuiMultiSelectFlags_BoxSelect2d, clipping vertical may occasionally be larger, so we coarse-clip our rendering as well. + // Because we use ImGuiMultiSelectFlags_BoxSelect2d, clipping vertical may occasionally be + // larger, so we coarse-clip our rendering as well. if (item_is_visible) { ImVec2 box_min(pos.x - 1, pos.y - 1); - ImVec2 box_max(box_min.x + LayoutItemSize.x + 2, box_min.y + LayoutItemSize.y + 2); // Dubious + ImVec2 box_max(box_min.x + LayoutItemSize.x + 2, + box_min.y + LayoutItemSize.y + 2); // Dubious draw_list->AddRectFilled(box_min, box_max, icon_bg_color); // Background color if (ShowTypeOverlay && item_data->Type != 0) { - ImU32 type_col = icon_type_overlay_colors[item_data->Type % IM_ARRAYSIZE(icon_type_overlay_colors)]; - draw_list->AddRectFilled(ImVec2(box_max.x - 2 - icon_type_overlay_size.x, box_min.y + 2), ImVec2(box_max.x - 2, box_min.y + 2 + icon_type_overlay_size.y), type_col); + ImU32 type_col = + icon_type_overlay_colors[item_data->Type % IM_ARRAYSIZE(icon_type_overlay_colors)]; + draw_list->AddRectFilled( + ImVec2(box_max.x - 2 - icon_type_overlay_size.x, box_min.y + 2), + ImVec2(box_max.x - 2, box_min.y + 2 + icon_type_overlay_size.y), type_col); } if (display_label) { - ImU32 label_col = ImGui::GetColorU32(item_is_selected ? ImGuiCol_Text : ImGuiCol_TextDisabled); + ImU32 label_col = + ImGui::GetColorU32(item_is_selected ? ImGuiCol_Text : ImGuiCol_TextDisabled); char label[32]; sprintf(label, "%d", item_data->ID); - draw_list->AddText(ImVec2(box_min.x, box_max.y - ImGui::GetFontSize()), label_col, label); + draw_list->AddText(ImVec2(box_min.x, box_max.y - ImGui::GetFontSize()), label_col, + label); } } @@ -10726,17 +12112,22 @@ struct ExampleAssetsBrowser // Zooming with CTRL+Wheel if (ImGui::IsWindowAppearing()) ZoomWheelAccum = 0.0f; - if (ImGui::IsWindowHovered() && io.MouseWheel != 0.0f && ImGui::IsKeyDown(ImGuiMod_Ctrl) && ImGui::IsAnyItemActive() == false) + if (ImGui::IsWindowHovered() && io.MouseWheel != 0.0f && ImGui::IsKeyDown(ImGuiMod_Ctrl) && + ImGui::IsAnyItemActive() == false) { ZoomWheelAccum += io.MouseWheel; if (fabsf(ZoomWheelAccum) >= 1.0f) { // Calculate hovered item index from mouse location - // FIXME: Locking aiming on 'hovered_item_idx' (with a cool-down timer) would ensure zoom keeps on it. - const float hovered_item_nx = (io.MousePos.x - start_pos.x + LayoutItemSpacing * 0.5f) / LayoutItemStep.x; - const float hovered_item_ny = (io.MousePos.y - start_pos.y + LayoutItemSpacing * 0.5f) / LayoutItemStep.y; + // FIXME: Locking aiming on 'hovered_item_idx' (with a cool-down timer) would ensure zoom keeps on + // it. + const float hovered_item_nx = + (io.MousePos.x - start_pos.x + LayoutItemSpacing * 0.5f) / LayoutItemStep.x; + const float hovered_item_ny = + (io.MousePos.y - start_pos.y + LayoutItemSpacing * 0.5f) / LayoutItemStep.y; const int hovered_item_idx = ((int)hovered_item_ny * LayoutColumnCount) + (int)hovered_item_nx; - //ImGui::SetTooltip("%f,%f -> item %d", hovered_item_nx, hovered_item_ny, hovered_item_idx); // Move those 4 lines in block above for easy debugging + // ImGui::SetTooltip("%f,%f -> item %d", hovered_item_nx, hovered_item_ny, hovered_item_idx); // + // Move those 4 lines in block above for easy debugging // Zoom IconSize *= powf(1.1f, (float)(int)ZoomWheelAccum); @@ -10747,7 +12138,9 @@ struct ExampleAssetsBrowser // Manipulate scroll to that we will land at the same Y location of currently hovered item. // - Calculate next frame position of item under mouse // - Set new scroll position to be used in next ImGui::BeginChild() call. - float hovered_item_rel_pos_y = ((float)(hovered_item_idx / LayoutColumnCount) + fmodf(hovered_item_ny, 1.0f)) * LayoutItemStep.y; + float hovered_item_rel_pos_y = + ((float)(hovered_item_idx / LayoutColumnCount) + fmodf(hovered_item_ny, 1.0f)) * + LayoutItemStep.y; hovered_item_rel_pos_y += ImGui::GetStyle().WindowPadding.y; float mouse_local_y = io.MousePos.y - ImGui::GetWindowPos().y; ImGui::SetScrollY(hovered_item_rel_pos_y - mouse_local_y); @@ -10761,7 +12154,7 @@ struct ExampleAssetsBrowser } }; -void ShowExampleAppAssetsBrowser(bool* p_open) +void ShowExampleAppAssetsBrowser(bool *p_open) { IMGUI_DEMO_MARKER("Examples/Assets Browser"); static ExampleAssetsBrowser assets_browser; @@ -10771,11 +12164,22 @@ void ShowExampleAppAssetsBrowser(bool* p_open) // End of Demo code #else -void ImGui::ShowAboutWindow(bool*) {} -void ImGui::ShowDemoWindow(bool*) {} -void ImGui::ShowUserGuide() {} -void ImGui::ShowStyleEditor(ImGuiStyle*) {} -bool ImGui::ShowStyleSelector(const char*) { return false; } +void ImGui::ShowAboutWindow(bool *) +{ +} +void ImGui::ShowDemoWindow(bool *) +{ +} +void ImGui::ShowUserGuide() +{ +} +void ImGui::ShowStyleEditor(ImGuiStyle *) +{ +} +bool ImGui::ShowStyleSelector(const char *) +{ + return false; +} #endif // #ifndef IMGUI_DISABLE_DEMO_WINDOWS diff --git a/firmware/components/imgui/imgui_draw.cpp b/firmware/components/imgui/imgui_draw.cpp index cd3d22e..924e46b 100644 --- a/firmware/components/imgui/imgui_draw.cpp +++ b/firmware/components/imgui/imgui_draw.cpp @@ -39,48 +39,70 @@ Index of this file: #include "misc/freetype/imgui_freetype.h" #endif -#include // vsnprintf, sscanf, printf -#include // intptr_t +#include // intptr_t +#include // vsnprintf, sscanf, printf // 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: 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) +#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 : 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 #if defined(__clang__) #if __has_warning("-Wunknown-warning-option") -#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! +#pragma clang diagnostic ignored \ + "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are + // known by all Clang versions and they tend to be rename-happy.. so ignoring warnings + // triggers new warnings on some configuration. Great! #endif -#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' -#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. -#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok. -#pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is. -#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness -#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 -#pragma clang diagnostic ignored "-Wcomma" // warning: possible misuse of comma operator here -#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier -#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. -#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision -#pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter -#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access -#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type -#pragma clang diagnostic ignored "-Wcast-qual" // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier -#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored \ + "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing + // and comparing against same constants ok. +#pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // + // similar to above, not sure what the exact difference is. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some + // standard header variations use #define NULL 0 +#pragma clang diagnostic ignored "-Wcomma" // warning: possible misuse of comma operator here +#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier +#pragma clang diagnostic ignored \ + "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // + // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#pragma clang diagnostic ignored \ + "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision +#pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts + // with '_' followed by a capital letter +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access +#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to + // non-trivially copyable type +#pragma clang diagnostic ignored "-Wcast-qual" // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier +#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label #elif defined(__GNUC__) -#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used -#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe -#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function -#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value -#pragma GCC diagnostic ignored "-Wstack-protector" // warning: stack protector not protecting local variables: variable length buffer -#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1 -#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead -#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used +#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe +#pragma GCC diagnostic ignored \ + "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored \ + "-Wstack-protector" // warning: stack protector not protecting local variables: variable length buffer +#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying + // division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1 +#pragma GCC diagnostic ignored \ + "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no + // trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored \ + "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers #endif //------------------------------------------------------------------------- @@ -88,11 +110,11 @@ Index of this file: //------------------------------------------------------------------------- // Compile time options: -//#define IMGUI_STB_NAMESPACE ImStb -//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" -//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" -//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION -//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION +// #define IMGUI_STB_NAMESPACE ImStb +// #define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" +// #define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" +// #define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION +// #define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION #ifdef IMGUI_STB_NAMESPACE namespace IMGUI_STB_NAMESPACE @@ -100,31 +122,41 @@ namespace IMGUI_STB_NAMESPACE #endif #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. +#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__) #pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used +#pragma clang diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used #pragma clang diagnostic ignored "-Wmissing-prototypes" #pragma clang diagnostic ignored "-Wimplicit-fallthrough" #endif #if defined(__GNUC__) #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wtype-limits" // warning: comparison is always true due to limited range of data type [-Wtype-limits] -#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" // warning: this statement may fall through +#pragma GCC diagnostic ignored \ + "-Wtype-limits" // warning: comparison is always true due to limited range of data type [-Wtype-limits] +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" // warning: this statement may fall through #endif -#ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) -#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in another compilation unit +#ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit + // (e.g. unity builds) +#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in another + // compilation unit #define STBRP_STATIC -#define STBRP_ASSERT(x) do { IM_ASSERT(x); } while (0) -#define STBRP_SORT ImQsort +#define STBRP_ASSERT(x) \ + do \ + { \ + IM_ASSERT(x); \ + } while (0) +#define STBRP_SORT ImQsort #define STB_RECT_PACK_IMPLEMENTATION #endif #ifdef IMGUI_STB_RECT_PACK_FILENAME @@ -134,19 +166,25 @@ namespace IMGUI_STB_NAMESPACE #endif #endif -#ifdef IMGUI_ENABLE_STB_TRUETYPE -#ifndef STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) -#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in another compilation unit -#define STBTT_malloc(x,u) ((void)(u), IM_ALLOC(x)) -#define STBTT_free(x,u) ((void)(u), IM_FREE(x)) -#define STBTT_assert(x) do { IM_ASSERT(x); } while(0) -#define STBTT_fmod(x,y) ImFmod(x,y) -#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)ImFloor(x)) -#define STBTT_iceil(x) ((int)ImCeil(x)) -#define STBTT_strlen(x) ImStrlen(x) +#ifdef IMGUI_ENABLE_STB_TRUETYPE +#ifndef STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit + // (e.g. unity builds) +#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in another + // compilation unit +#define STBTT_malloc(x, u) ((void)(u), IM_ALLOC(x)) +#define STBTT_free(x, u) ((void)(u), IM_FREE(x)) +#define STBTT_assert(x) \ + do \ + { \ + IM_ASSERT(x); \ + } while (0) +#define STBTT_fmod(x, y) ImFmod(x, y) +#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)ImFloor(x)) +#define STBTT_iceil(x) ((int)ImCeil(x)) +#define STBTT_strlen(x) ImStrlen(x) #define STBTT_STATIC #define STB_TRUETYPE_IMPLEMENTATION #else @@ -169,7 +207,7 @@ namespace IMGUI_STB_NAMESPACE #endif #if defined(_MSC_VER) -#pragma warning (pop) +#pragma warning(pop) #endif #ifdef IMGUI_STB_NAMESPACE @@ -181,200 +219,200 @@ using namespace IMGUI_STB_NAMESPACE; // [SECTION] Style functions //----------------------------------------------------------------------------- -void ImGui::StyleColorsDark(ImGuiStyle* dst) +void ImGui::StyleColorsDark(ImGuiStyle *dst) { - ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); - ImVec4* colors = style->Colors; + ImGuiStyle *style = dst ? dst : &ImGui::GetStyle(); + ImVec4 *colors = style->Colors; - colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); - colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); - colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f); - colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); - colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f); - colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - colors[ImGuiCol_FrameBg] = ImVec4(0.16f, 0.29f, 0.48f, 0.54f); - colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); - colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); - colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f); - colors[ImGuiCol_TitleBgActive] = ImVec4(0.16f, 0.29f, 0.48f, 1.00f); - colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f); - colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f); - colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f); - colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f); - colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); - colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f); - colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); - colors[ImGuiCol_SliderGrab] = ImVec4(0.24f, 0.52f, 0.88f, 1.00f); - colors[ImGuiCol_SliderGrabActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); - colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); - colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); - colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); - colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); - colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); - colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); - colors[ImGuiCol_Separator] = colors[ImGuiCol_Border]; - colors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f); - colors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f); - colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.20f); - colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); - colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); - colors[ImGuiCol_InputTextCursor] = colors[ImGuiCol_Text]; - colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; - colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); - colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); - colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive]; - colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); - colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f); + colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); + colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(0.16f, 0.29f, 0.48f, 0.54f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.16f, 0.29f, 0.48f, 1.00f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f); + colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_SliderGrab] = ImVec4(0.24f, 0.52f, 0.88f, 1.00f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_Separator] = colors[ImGuiCol_Border]; + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.20f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_InputTextCursor] = colors[ImGuiCol_Text]; + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); + colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive]; + colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f); colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.50f, 0.50f, 0.50f, 0.00f); - colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); - colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); - colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); - colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); - colors[ImGuiCol_TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f); - colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f); // Prefer using Alpha=1.0 here - colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f); // Prefer using Alpha=1.0 here - colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f); - colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive]; - colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); - colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border]; - colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); - colors[ImGuiCol_NavCursor] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); - colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); - colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); - colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); + colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); + colors[ImGuiCol_TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f); + colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f); + colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive]; + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); + colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border]; + colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); + colors[ImGuiCol_NavCursor] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); } -void ImGui::StyleColorsClassic(ImGuiStyle* dst) +void ImGui::StyleColorsClassic(ImGuiStyle *dst) { - ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); - ImVec4* colors = style->Colors; + ImGuiStyle *style = dst ? dst : &ImGui::GetStyle(); + ImVec4 *colors = style->Colors; - colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); - colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); - colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.85f); - colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - colors[ImGuiCol_PopupBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f); - colors[ImGuiCol_Border] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f); - colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - colors[ImGuiCol_FrameBg] = ImVec4(0.43f, 0.43f, 0.43f, 0.39f); - colors[ImGuiCol_FrameBgHovered] = ImVec4(0.47f, 0.47f, 0.69f, 0.40f); - colors[ImGuiCol_FrameBgActive] = ImVec4(0.42f, 0.41f, 0.64f, 0.69f); - colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.27f, 0.54f, 0.83f); - colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.32f, 0.63f, 0.87f); - colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f); - colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f); - colors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.25f, 0.30f, 0.60f); - colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f); - colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f); - colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f); - colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f); - colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); - colors[ImGuiCol_SliderGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f); - colors[ImGuiCol_Button] = ImVec4(0.35f, 0.40f, 0.61f, 0.62f); - colors[ImGuiCol_ButtonHovered] = ImVec4(0.40f, 0.48f, 0.71f, 0.79f); - colors[ImGuiCol_ButtonActive] = ImVec4(0.46f, 0.54f, 0.80f, 1.00f); - colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f); - colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f); - colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f); - colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 0.60f); - colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f); - colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f); - colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.10f); - colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f); - colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f); - colors[ImGuiCol_InputTextCursor] = colors[ImGuiCol_Text]; - colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; - colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); - colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); - colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive]; - colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); - colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f); + colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.85f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_PopupBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f); + colors[ImGuiCol_Border] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(0.43f, 0.43f, 0.43f, 0.39f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.47f, 0.47f, 0.69f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.42f, 0.41f, 0.64f, 0.69f); + colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.27f, 0.54f, 0.83f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.32f, 0.63f, 0.87f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.25f, 0.30f, 0.60f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f); + colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f); + colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f); + colors[ImGuiCol_Button] = ImVec4(0.35f, 0.40f, 0.61f, 0.62f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.40f, 0.48f, 0.71f, 0.79f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.46f, 0.54f, 0.80f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f); + colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 0.60f); + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.10f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f); + colors[ImGuiCol_InputTextCursor] = colors[ImGuiCol_Text]; + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); + colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive]; + colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f); colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.53f, 0.53f, 0.87f, 0.00f); - colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); - colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); - colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); - colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); - colors[ImGuiCol_TableHeaderBg] = ImVec4(0.27f, 0.27f, 0.38f, 1.00f); - colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.45f, 1.00f); // Prefer using Alpha=1.0 here - colors[ImGuiCol_TableBorderLight] = ImVec4(0.26f, 0.26f, 0.28f, 1.00f); // Prefer using Alpha=1.0 here - colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.07f); - colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive]; - colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); - colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border]; - colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); - colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered]; - colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); - colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); - colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); + colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); + colors[ImGuiCol_TableHeaderBg] = ImVec4(0.27f, 0.27f, 0.38f, 1.00f); + colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.45f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableBorderLight] = ImVec4(0.26f, 0.26f, 0.28f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.07f); + colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive]; + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); + colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border]; + colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); + colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); } // Those light colors are better suited with a thicker font than the default one + FrameBorder -void ImGui::StyleColorsLight(ImGuiStyle* dst) +void ImGui::StyleColorsLight(ImGuiStyle *dst) { - ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); - ImVec4* colors = style->Colors; + ImGuiStyle *style = dst ? dst : &ImGui::GetStyle(); + ImVec4 *colors = style->Colors; - colors[ImGuiCol_Text] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); - colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); - colors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 1.00f); - colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - colors[ImGuiCol_PopupBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.98f); - colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.30f); - colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - colors[ImGuiCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); - colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); - colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); - colors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f); - colors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f); - colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f); - colors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f); - colors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f); - colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 0.80f); - colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.49f, 0.49f, 0.49f, 0.80f); - colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.49f, 0.49f, 0.49f, 1.00f); - colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); - colors[ImGuiCol_SliderGrab] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f); - colors[ImGuiCol_SliderGrabActive] = ImVec4(0.46f, 0.54f, 0.80f, 0.60f); - colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); - colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); - colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); - colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); - colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); - colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); - colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 0.62f); - colors[ImGuiCol_SeparatorHovered] = ImVec4(0.14f, 0.44f, 0.80f, 0.78f); - colors[ImGuiCol_SeparatorActive] = ImVec4(0.14f, 0.44f, 0.80f, 1.00f); - colors[ImGuiCol_ResizeGrip] = ImVec4(0.35f, 0.35f, 0.35f, 0.17f); - colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); - colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); - colors[ImGuiCol_InputTextCursor] = colors[ImGuiCol_Text]; - colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; - colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f); - colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); - colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive]; - colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); - colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f); + colors[ImGuiCol_Text] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 1.00f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_PopupBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.98f); + colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.30f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 0.80f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.49f, 0.49f, 0.49f, 0.80f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.49f, 0.49f, 0.49f, 1.00f); + colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_SliderGrab] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.46f, 0.54f, 0.80f, 0.60f); + colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 0.62f); + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.14f, 0.44f, 0.80f, 0.78f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.14f, 0.44f, 0.80f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(0.35f, 0.35f, 0.35f, 0.17f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_InputTextCursor] = colors[ImGuiCol_Text]; + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f); + colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive]; + colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f); colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.26f, 0.59f, 1.00f, 0.00f); - colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); - colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); - colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); - colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.45f, 0.00f, 1.00f); - colors[ImGuiCol_TableHeaderBg] = ImVec4(0.78f, 0.87f, 0.98f, 1.00f); - colors[ImGuiCol_TableBorderStrong] = ImVec4(0.57f, 0.57f, 0.64f, 1.00f); // Prefer using Alpha=1.0 here - colors[ImGuiCol_TableBorderLight] = ImVec4(0.68f, 0.68f, 0.74f, 1.00f); // Prefer using Alpha=1.0 here - colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - colors[ImGuiCol_TableRowBgAlt] = ImVec4(0.30f, 0.30f, 0.30f, 0.09f); - colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive]; - colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); - colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border]; - colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); - colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered]; - colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f); - colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.20f); - colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); + colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.45f, 0.00f, 1.00f); + colors[ImGuiCol_TableHeaderBg] = ImVec4(0.78f, 0.87f, 0.98f, 1.00f); + colors[ImGuiCol_TableBorderStrong] = ImVec4(0.57f, 0.57f, 0.64f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableBorderLight] = ImVec4(0.68f, 0.68f, 0.74f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_TableRowBgAlt] = ImVec4(0.30f, 0.30f, 0.30f, 0.09f); + colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive]; + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); + colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border]; + colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); } //----------------------------------------------------------------------------- @@ -408,12 +446,13 @@ void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error) for (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++) { const float radius = (float)i; - CircleSegmentCounts[i] = (ImU8)((i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError) : IM_DRAWLIST_ARCFAST_SAMPLE_MAX); + CircleSegmentCounts[i] = (ImU8)((i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError) + : IM_DRAWLIST_ARCFAST_SAMPLE_MAX); } ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError); } -ImDrawList::ImDrawList(ImDrawListSharedData* shared_data) +ImDrawList::ImDrawList(ImDrawListSharedData *shared_data) { memset(this, 0, sizeof(*this)); _SetDrawListSharedData(shared_data); @@ -425,7 +464,7 @@ ImDrawList::~ImDrawList() _SetDrawListSharedData(NULL); } -void ImDrawList::_SetDrawListSharedData(ImDrawListSharedData* data) +void ImDrawList::_SetDrawListSharedData(ImDrawListSharedData *data) { if (_Data != NULL) _Data->DrawLists.find_erase_unsorted(this); @@ -478,9 +517,9 @@ void ImDrawList::_ClearFreeMemory() _Splitter.ClearFreeMemory(); } -ImDrawList* ImDrawList::CloneOutput() const +ImDrawList *ImDrawList::CloneOutput() const { - ImDrawList* dst = IM_NEW(ImDrawList(_Data)); + ImDrawList *dst = IM_NEW(ImDrawList(_Data)); dst->CmdBuffer = CmdBuffer; dst->IdxBuffer = IdxBuffer; dst->VtxBuffer = VtxBuffer; @@ -491,7 +530,7 @@ ImDrawList* ImDrawList::CloneOutput() const void ImDrawList::AddDrawCmd() { ImDrawCmd draw_cmd; - draw_cmd.ClipRect = _CmdHeader.ClipRect; // Same as calling ImDrawCmd_HeaderCopy() + draw_cmd.ClipRect = _CmdHeader.ClipRect; // Same as calling ImDrawCmd_HeaderCopy() draw_cmd.TexRef = _CmdHeader.TexRef; draw_cmd.VtxOffset = _CmdHeader.VtxOffset; draw_cmd.IdxOffset = IdxBuffer.Size; @@ -501,22 +540,23 @@ void ImDrawList::AddDrawCmd() } // Pop trailing draw command (used before merging or presenting to user) -// Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > 0 && CmdBuffer.back().UserCallback == NULL +// Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > +// 0 && CmdBuffer.back().UserCallback == NULL void ImDrawList::_PopUnusedDrawCmd() { while (CmdBuffer.Size > 0) { - ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + ImDrawCmd *curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; if (curr_cmd->ElemCount != 0 || curr_cmd->UserCallback != NULL) - return;// break; + return; // break; CmdBuffer.pop_back(); } } -void ImDrawList::AddCallback(ImDrawCallback callback, void* userdata, size_t userdata_size) +void ImDrawList::AddCallback(ImDrawCallback callback, void *userdata, size_t userdata_size) { IM_ASSERT_PARANOID(CmdBuffer.Size > 0); - ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + ImDrawCmd *curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; IM_ASSERT(curr_cmd->UserCallback == NULL); if (curr_cmd->ElemCount != 0) { @@ -548,31 +588,35 @@ void ImDrawList::AddCallback(ImDrawCallback callback, void* userdata, size_t use } // Compare ClipRect, TexRef and VtxOffset with a single memcmp() -#define ImDrawCmd_HeaderSize (offsetof(ImDrawCmd, VtxOffset) + sizeof(unsigned int)) -#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TexRef, VtxOffset -#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TexRef, VtxOffset -#define ImDrawCmd_AreSequentialIdxOffset(CMD_0, CMD_1) (CMD_0->IdxOffset + CMD_0->ElemCount == CMD_1->IdxOffset) +#define ImDrawCmd_HeaderSize (offsetof(ImDrawCmd, VtxOffset) + sizeof(unsigned int)) +#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) \ + (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TexRef, VtxOffset +#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) \ + (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TexRef, VtxOffset +#define ImDrawCmd_AreSequentialIdxOffset(CMD_0, CMD_1) (CMD_0->IdxOffset + CMD_0->ElemCount == CMD_1->IdxOffset) // Try to merge two last draw commands void ImDrawList::_TryMergeDrawCmds() { IM_ASSERT_PARANOID(CmdBuffer.Size > 0); - ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; - ImDrawCmd* prev_cmd = curr_cmd - 1; - if (ImDrawCmd_HeaderCompare(curr_cmd, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && curr_cmd->UserCallback == NULL && prev_cmd->UserCallback == NULL) + ImDrawCmd *curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + ImDrawCmd *prev_cmd = curr_cmd - 1; + if (ImDrawCmd_HeaderCompare(curr_cmd, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && + curr_cmd->UserCallback == NULL && prev_cmd->UserCallback == NULL) { prev_cmd->ElemCount += curr_cmd->ElemCount; CmdBuffer.pop_back(); } } -// Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack. -// The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only. +// Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to +// perform any check so we always have a command ready in the stack. The cost of figuring out if a new command has to be +// added or if we can merge is paid in those Update** functions only. void ImDrawList::_OnChangedClipRect() { // If current command is used with different settings we need to add a new command IM_ASSERT_PARANOID(CmdBuffer.Size > 0); - ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + ImDrawCmd *curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; if (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0) { AddDrawCmd(); @@ -581,8 +625,9 @@ void ImDrawList::_OnChangedClipRect() IM_ASSERT(curr_cmd->UserCallback == NULL); // Try to merge with previous command if it matches, else use current command - ImDrawCmd* prev_cmd = curr_cmd - 1; - if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL) + ImDrawCmd *prev_cmd = curr_cmd - 1; + if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && + ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL) { CmdBuffer.pop_back(); return; @@ -594,20 +639,22 @@ void ImDrawList::_OnChangedTexture() { // If current command is used with different settings we need to add a new command IM_ASSERT_PARANOID(CmdBuffer.Size > 0); - ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + ImDrawCmd *curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; if (curr_cmd->ElemCount != 0 && curr_cmd->TexRef != _CmdHeader.TexRef) { AddDrawCmd(); return; } - // Unlike other _OnChangedXXX functions this may be called by ImFontAtlasUpdateDrawListsTextures() in more locations so we need to handle this case. + // Unlike other _OnChangedXXX functions this may be called by ImFontAtlasUpdateDrawListsTextures() in more locations + // so we need to handle this case. if (curr_cmd->UserCallback != NULL) return; // Try to merge with previous command if it matches, else use current command - ImDrawCmd* prev_cmd = curr_cmd - 1; - if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL) + ImDrawCmd *prev_cmd = curr_cmd - 1; + if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && + ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL) { CmdBuffer.pop_back(); return; @@ -617,11 +664,12 @@ void ImDrawList::_OnChangedTexture() void ImDrawList::_OnChangedVtxOffset() { - // We don't need to compare curr_cmd->VtxOffset != _CmdHeader.VtxOffset because we know it'll be different at the time we call this. + // We don't need to compare curr_cmd->VtxOffset != _CmdHeader.VtxOffset because we know it'll be different at the + // time we call this. _VtxCurrentIdx = 0; IM_ASSERT_PARANOID(CmdBuffer.Size > 0); - ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; - //IM_ASSERT(curr_cmd->VtxOffset != _CmdHeader.VtxOffset); // See #3349 + ImDrawCmd *curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + // IM_ASSERT(curr_cmd->VtxOffset != _CmdHeader.VtxOffset); // See #3349 if (curr_cmd->ElemCount != 0) { AddDrawCmd(); @@ -641,17 +689,22 @@ int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const 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(const ImVec2& cr_min, const ImVec2& cr_max, bool intersect_with_current_clip_rect) +// 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(const ImVec2 &cr_min, const ImVec2 &cr_max, bool intersect_with_current_clip_rect) { ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y); if (intersect_with_current_clip_rect) { ImVec4 current = _CmdHeader.ClipRect; - if (cr.x < current.x) cr.x = current.x; - if (cr.y < current.y) cr.y = current.y; - if (cr.z > current.z) cr.z = current.z; - if (cr.w > current.w) cr.w = current.w; + if (cr.x < current.x) + cr.x = current.x; + if (cr.y < current.y) + cr.y = current.y; + if (cr.z > current.z) + cr.z = current.z; + if (cr.w > current.w) + cr.w = current.w; } cr.z = ImMax(cr.x, cr.z); cr.w = ImMax(cr.y, cr.w); @@ -663,13 +716,15 @@ void ImDrawList::PushClipRect(const ImVec2& cr_min, const ImVec2& cr_max, bool i void ImDrawList::PushClipRectFullScreen() { - PushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w)); + PushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), + ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w)); } void ImDrawList::PopClipRect() { _ClipRectStack.pop_back(); - _CmdHeader.ClipRect = (_ClipRectStack.Size == 0) ? _Data->ClipRectFullscreen : _ClipRectStack.Data[_ClipRectStack.Size - 1]; + _CmdHeader.ClipRect = + (_ClipRectStack.Size == 0) ? _Data->ClipRectFullscreen : _ClipRectStack.Data[_ClipRectStack.Size - 1]; _OnChangedClipRect(); } @@ -689,7 +744,8 @@ void ImDrawList::PopTexture() _OnChangedTexture(); } -// This is used by ImGui::PushFont()/PopFont(). It works because we never use _TextureIdStack[] elsewhere than in PushTexture()/PopTexture(). +// This is used by ImGui::PushFont()/PopFont(). It works because we never use _TextureIdStack[] elsewhere than in +// PushTexture()/PopTexture(). void ImDrawList::_SetTexture(ImTextureRef tex_ref) { if (_CmdHeader.TexRef == tex_ref) @@ -708,13 +764,14 @@ void ImDrawList::PrimReserve(int idx_count, int vtx_count) if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset)) { // FIXME: In theory we should be testing that vtx_count <64k here. - // In practice, RenderText() relies on reserving ahead for a worst case scenario so it is currently useful for us - // to not make that check until we rework the text functions to handle clipping and large horizontal lines better. + // In practice, RenderText() relies on reserving ahead for a worst case scenario so it is currently useful for + // us to not make that check until we rework the text functions to handle clipping and large horizontal lines + // better. _CmdHeader.VtxOffset = VtxBuffer.Size; _OnChangedVtxOffset(); } - ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + ImDrawCmd *draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; draw_cmd->ElemCount += idx_count; int vtx_buffer_old_size = VtxBuffer.Size; @@ -731,67 +788,129 @@ void ImDrawList::PrimUnreserve(int idx_count, int vtx_count) { IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0); - ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + ImDrawCmd *draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; draw_cmd->ElemCount -= idx_count; VtxBuffer.shrink(VtxBuffer.Size - vtx_count); IdxBuffer.shrink(IdxBuffer.Size - idx_count); } // Fully unrolled with inline call to keep our debug builds decently fast. -void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col) +void ImDrawList::PrimRect(const ImVec2 &a, const ImVec2 &c, ImU32 col) { ImVec2 b(c.x, a.y), d(a.x, c.y), uv(_Data->TexUvWhitePixel); ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; - _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); - _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); - _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; - _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col; - _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col; - _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col; + _IdxWritePtr[0] = idx; + _IdxWritePtr[1] = (ImDrawIdx)(idx + 1); + _IdxWritePtr[2] = (ImDrawIdx)(idx + 2); + _IdxWritePtr[3] = idx; + _IdxWritePtr[4] = (ImDrawIdx)(idx + 2); + _IdxWritePtr[5] = (ImDrawIdx)(idx + 3); + _VtxWritePtr[0].pos = a; + _VtxWritePtr[0].uv = uv; + _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = b; + _VtxWritePtr[1].uv = uv; + _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = c; + _VtxWritePtr[2].uv = uv; + _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = d; + _VtxWritePtr[3].uv = uv; + _VtxWritePtr[3].col = col; _VtxWritePtr += 4; _VtxCurrentIdx += 4; _IdxWritePtr += 6; } -void ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a, const ImVec2& uv_c, ImU32 col) +void ImDrawList::PrimRectUV(const ImVec2 &a, const ImVec2 &c, const ImVec2 &uv_a, const ImVec2 &uv_c, ImU32 col) { ImVec2 b(c.x, a.y), d(a.x, c.y), uv_b(uv_c.x, uv_a.y), uv_d(uv_a.x, uv_c.y); ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; - _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); - _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); - _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col; - _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col; - _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col; - _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col; + _IdxWritePtr[0] = idx; + _IdxWritePtr[1] = (ImDrawIdx)(idx + 1); + _IdxWritePtr[2] = (ImDrawIdx)(idx + 2); + _IdxWritePtr[3] = idx; + _IdxWritePtr[4] = (ImDrawIdx)(idx + 2); + _IdxWritePtr[5] = (ImDrawIdx)(idx + 3); + _VtxWritePtr[0].pos = a; + _VtxWritePtr[0].uv = uv_a; + _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = b; + _VtxWritePtr[1].uv = uv_b; + _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = c; + _VtxWritePtr[2].uv = uv_c; + _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = d; + _VtxWritePtr[3].uv = uv_d; + _VtxWritePtr[3].col = col; _VtxWritePtr += 4; _VtxCurrentIdx += 4; _IdxWritePtr += 6; } -void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col) +void ImDrawList::PrimQuadUV(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &d, const ImVec2 &uv_a, + const ImVec2 &uv_b, const ImVec2 &uv_c, const ImVec2 &uv_d, ImU32 col) { ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; - _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); - _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); - _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col; - _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col; - _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col; - _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col; + _IdxWritePtr[0] = idx; + _IdxWritePtr[1] = (ImDrawIdx)(idx + 1); + _IdxWritePtr[2] = (ImDrawIdx)(idx + 2); + _IdxWritePtr[3] = idx; + _IdxWritePtr[4] = (ImDrawIdx)(idx + 2); + _IdxWritePtr[5] = (ImDrawIdx)(idx + 3); + _VtxWritePtr[0].pos = a; + _VtxWritePtr[0].uv = uv_a; + _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = b; + _VtxWritePtr[1].uv = uv_b; + _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = c; + _VtxWritePtr[2].uv = uv_c; + _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = d; + _VtxWritePtr[3].uv = uv_d; + _VtxWritePtr[3].col = col; _VtxWritePtr += 4; _VtxCurrentIdx += 4; _IdxWritePtr += 6; } -// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to optimize debug/non-inlined builds. +// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to +// optimize debug/non-inlined builds. // - Those macros expects l-values and need to be used as their own statement. -// - Those macros are intentionally not surrounded by the 'do {} while (0)' idiom because even that translates to runtime with debug compilers. -#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = ImRsqrt(d2); VX *= inv_len; VY *= inv_len; } } (void)0 -#define IM_FIXNORMAL2F_MAX_INVLEN2 100.0f // 500.0f (see #4053, #3366) -#define IM_FIXNORMAL2F(VX,VY) { 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; } } (void)0 +// - Those macros are intentionally not surrounded by the 'do {} while (0)' idiom because even that translates to +// runtime with debug compilers. +#define IM_NORMALIZE2F_OVER_ZERO(VX, VY) \ + { \ + float d2 = VX * VX + VY * VY; \ + if (d2 > 0.0f) \ + { \ + float inv_len = ImRsqrt(d2); \ + VX *= inv_len; \ + VY *= inv_len; \ + } \ + } \ + (void)0 +#define IM_FIXNORMAL2F_MAX_INVLEN2 100.0f // 500.0f (see #4053, #3366) +#define IM_FIXNORMAL2F(VX, VY) \ + { \ + 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; \ + } \ + } \ + (void)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, ImDrawFlags flags, float thickness) +void ImDrawList::AddPolyline(const ImVec2 *points, const int points_count, ImU32 col, ImDrawFlags flags, + float thickness) { if (points_count < 2 || (col & IM_COL32_A_MASK) == 0) return; @@ -813,11 +932,15 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 const float fractional_thickness = thickness - integer_thickness; // Do we want to draw this line using a texture? - // - For now, only draw integer-width lines using textures to avoid issues with the way scaling occurs, could be improved. + // - For now, only draw integer-width lines using textures to avoid issues with the way scaling occurs, could be + // improved. // - If AA_SIZE is not 1.0f we cannot use the texture path. - const bool use_texture = (Flags & ImDrawListFlags_AntiAliasedLinesUseTex) && (integer_thickness < IM_DRAWLIST_TEX_LINES_WIDTH_MAX) && (fractional_thickness <= 0.00001f) && (AA_SIZE == 1.0f); + const bool use_texture = (Flags & ImDrawListFlags_AntiAliasedLinesUseTex) && + (integer_thickness < IM_DRAWLIST_TEX_LINES_WIDTH_MAX) && + (fractional_thickness <= 0.00001f) && (AA_SIZE == 1.0f); - // We should never hit this, because NewFrame() doesn't set ImDrawListFlags_AntiAliasedLinesUseTex unless ImFontAtlasFlags_NoBakedLines is off + // We should never hit this, because NewFrame() doesn't set ImDrawListFlags_AntiAliasedLinesUseTex unless + // ImFontAtlasFlags_NoBakedLines is off IM_ASSERT_PARANOID(!use_texture || !(_Data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines)); const int idx_count = use_texture ? (count * 6) : (thick_line ? count * 18 : count * 12); @@ -825,10 +948,11 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 PrimReserve(idx_count, vtx_count); // Temporary buffer - // The first items are normals at each line point, then after that there are either 2 or 4 temp points for each line point + // The first items are normals at each line point, then after that there are either 2 or 4 temp + // points for each line point _Data->TempBuffer.reserve_discard(points_count * ((use_texture || !thick_line) ? 3 : 5)); - ImVec2* temp_normals = _Data->TempBuffer.Data; - ImVec2* temp_points = temp_normals + points_count; + ImVec2 *temp_normals = _Data->TempBuffer.Data; + ImVec2 *temp_points = temp_normals + points_count; // Calculate normals (tangents) for each line segment for (int i1 = 0; i1 < count; i1++) @@ -843,36 +967,46 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 if (!closed) temp_normals[points_count - 1] = temp_normals[points_count - 2]; - // If we are drawing a one-pixel-wide line without a texture, or a textured line of any width, we only need 2 or 3 vertices per point + // If we are drawing a one-pixel-wide line without a texture, or a textured line of any width, we only need 2 or + // 3 vertices per point if (use_texture || !thick_line) { // [PATH 1] Texture-based lines (thick or non-thick) // [PATH 2] Non texture-based lines (non-thick) - // The width of the geometry we need to draw - this is essentially pixels for the line itself, plus "one pixel" for AA. + // The width of the geometry we need to draw - this is essentially pixels for the line itself, + // plus "one pixel" for AA. // - In the texture-based path, we don't use AA_SIZE here because the +1 is tied to the generated texture - // (see ImFontAtlasBuildRenderLinesTexData() function), and so alternate values won't work without changes to that code. - // - In the non texture-based paths, we would allow AA_SIZE to potentially be != 1.0f with a patch (e.g. fringe_scale patch to + // (see ImFontAtlasBuildRenderLinesTexData() function), and so alternate values won't work without changes + // to that code. + // - In the non texture-based paths, we would allow AA_SIZE to potentially be != 1.0f with a patch (e.g. + // fringe_scale patch to // allow scaling geometry while preserving one-screen-pixel AA fringe). const float half_draw_size = use_texture ? ((thickness * 0.5f) + 1) : AA_SIZE; - // If line is not closed, the first and last points need to be generated differently as there are no normals to blend + // If line is not closed, the first and last points need to be generated differently as there are no normals + // to blend if (!closed) { temp_points[0] = points[0] + temp_normals[0] * half_draw_size; temp_points[1] = points[0] - temp_normals[0] * half_draw_size; - temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * half_draw_size; - temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * half_draw_size; + temp_points[(points_count - 1) * 2 + 0] = + points[points_count - 1] + temp_normals[points_count - 1] * half_draw_size; + temp_points[(points_count - 1) * 2 + 1] = + points[points_count - 1] - temp_normals[points_count - 1] * half_draw_size; } - // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges - // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps) + // Generate the indices to form a number of triangles for each line segment, and the vertices for the line + // edges This takes points n and n+1 and writes into n+1, with the first point in a closed line being + // generated from the final one (as n+1 wraps) // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment - for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment + for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment { const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; // i2 is the second point of the line segment - const unsigned int idx2 = ((i1 + 1) == points_count) ? _VtxCurrentIdx : (idx1 + (use_texture ? 2 : 3)); // Vertex index for end of segment + const unsigned int idx2 = ((i1 + 1) == points_count) + ? _VtxCurrentIdx + : (idx1 + (use_texture ? 2 : 3)); // Vertex index for end of segment // Average normals float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; @@ -882,7 +1016,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 dm_y *= half_draw_size; // Add temporary vertices for the outer edges - ImVec2* out_vtx = &temp_points[i2 * 2]; + ImVec2 *out_vtx = &temp_points[i2 * 2]; out_vtx[0].x = points[i2].x + dm_x; out_vtx[0].y = points[i2].y + dm_y; out_vtx[1].x = points[i2].x - dm_x; @@ -891,17 +1025,29 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 if (use_texture) { // Add indices for two triangles - _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 1); // Right tri - _IdxWritePtr[3] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[4] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Left tri + _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); + _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); + _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 1); // Right tri + _IdxWritePtr[3] = (ImDrawIdx)(idx2 + 1); + _IdxWritePtr[4] = (ImDrawIdx)(idx1 + 1); + _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Left tri _IdxWritePtr += 6; } else { // Add indexes for four triangles - _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); // Right tri 1 - _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Right tri 2 - _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); // Left tri 1 - _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); // Left tri 2 + _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); + _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); + _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); // Right tri 1 + _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); + _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); + _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Right tri 2 + _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); + _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); + _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); // Left tri 1 + _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); + _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); + _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); // Left tri 2 _IdxWritePtr += 12; } @@ -925,8 +1071,12 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 ImVec2 tex_uv1(tex_uvs.z, tex_uvs.w); for (int i = 0; i < points_count; i++) { - _VtxWritePtr[0].pos = temp_points[i * 2 + 0]; _VtxWritePtr[0].uv = tex_uv0; _VtxWritePtr[0].col = col; // Left-side outer edge - _VtxWritePtr[1].pos = temp_points[i * 2 + 1]; _VtxWritePtr[1].uv = tex_uv1; _VtxWritePtr[1].col = col; // Right-side outer edge + _VtxWritePtr[0].pos = temp_points[i * 2 + 0]; + _VtxWritePtr[0].uv = tex_uv0; + _VtxWritePtr[0].col = col; // Left-side outer edge + _VtxWritePtr[1].pos = temp_points[i * 2 + 1]; + _VtxWritePtr[1].uv = tex_uv1; + _VtxWritePtr[1].col = col; // Right-side outer edge _VtxWritePtr += 2; } } @@ -935,19 +1085,27 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 // If we're not using a texture, we need the center vertex as well for (int i = 0; i < points_count; i++) { - _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col; // Center of line - _VtxWritePtr[1].pos = temp_points[i * 2 + 0]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col_trans; // Left-side outer edge - _VtxWritePtr[2].pos = temp_points[i * 2 + 1]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col_trans; // Right-side outer edge + _VtxWritePtr[0].pos = points[i]; + _VtxWritePtr[0].uv = opaque_uv; + _VtxWritePtr[0].col = col; // Center of line + _VtxWritePtr[1].pos = temp_points[i * 2 + 0]; + _VtxWritePtr[1].uv = opaque_uv; + _VtxWritePtr[1].col = col_trans; // Left-side outer edge + _VtxWritePtr[2].pos = temp_points[i * 2 + 1]; + _VtxWritePtr[2].uv = opaque_uv; + _VtxWritePtr[2].col = col_trans; // Right-side outer edge _VtxWritePtr += 3; } } } else { - // [PATH 2] Non texture-based lines (thick): we need to draw the solid line core and thus require four vertices per point + // [PATH 2] Non texture-based lines (thick): we need to draw the solid line core and thus require four + // vertices per point const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f; - // If line is not closed, the first and last points need to be generated differently as there are no normals to blend + // If line is not closed, the first and last points need to be generated differently as there are no normals + // to blend if (!closed) { const int points_last = points_count - 1; @@ -955,20 +1113,26 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness); temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness); temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE); - temp_points[points_last * 4 + 0] = points[points_last] + temp_normals[points_last] * (half_inner_thickness + AA_SIZE); - temp_points[points_last * 4 + 1] = points[points_last] + temp_normals[points_last] * (half_inner_thickness); - temp_points[points_last * 4 + 2] = points[points_last] - temp_normals[points_last] * (half_inner_thickness); - temp_points[points_last * 4 + 3] = points[points_last] - temp_normals[points_last] * (half_inner_thickness + AA_SIZE); + temp_points[points_last * 4 + 0] = + points[points_last] + temp_normals[points_last] * (half_inner_thickness + AA_SIZE); + temp_points[points_last * 4 + 1] = + points[points_last] + temp_normals[points_last] * (half_inner_thickness); + temp_points[points_last * 4 + 2] = + points[points_last] - temp_normals[points_last] * (half_inner_thickness); + temp_points[points_last * 4 + 3] = + points[points_last] - temp_normals[points_last] * (half_inner_thickness + AA_SIZE); } - // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges - // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps) + // Generate the indices to form a number of triangles for each line segment, and the vertices for the line + // edges This takes points n and n+1 and writes into n+1, with the first point in a closed line being + // generated from the final one (as n+1 wraps) // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment - for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment + for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment { const int i2 = (i1 + 1) == points_count ? 0 : (i1 + 1); // i2 is the second point of the line segment - const unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : (idx1 + 4); // Vertex index for end of segment + const unsigned int idx2 = + (i1 + 1) == points_count ? _VtxCurrentIdx : (idx1 + 4); // Vertex index for end of segment // Average normals float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; @@ -980,7 +1144,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 float dm_in_y = dm_y * half_inner_thickness; // Add temporary vertices - ImVec2* out_vtx = &temp_points[i2 * 4]; + ImVec2 *out_vtx = &temp_points[i2 * 4]; out_vtx[0].x = points[i2].x + dm_out_x; out_vtx[0].y = points[i2].y + dm_out_y; out_vtx[1].x = points[i2].x + dm_in_x; @@ -991,12 +1155,24 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 out_vtx[3].y = points[i2].y - dm_out_y; // Add indexes - _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); - _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 1); - _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); - _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); - _IdxWritePtr[12] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[13] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[14] = (ImDrawIdx)(idx1 + 3); - _IdxWritePtr[15] = (ImDrawIdx)(idx1 + 3); _IdxWritePtr[16] = (ImDrawIdx)(idx2 + 3); _IdxWritePtr[17] = (ImDrawIdx)(idx2 + 2); + _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 1); + _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 1); + _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); + _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); + _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); + _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 1); + _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); + _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); + _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); + _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); + _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); + _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); + _IdxWritePtr[12] = (ImDrawIdx)(idx2 + 2); + _IdxWritePtr[13] = (ImDrawIdx)(idx1 + 2); + _IdxWritePtr[14] = (ImDrawIdx)(idx1 + 3); + _IdxWritePtr[15] = (ImDrawIdx)(idx1 + 3); + _IdxWritePtr[16] = (ImDrawIdx)(idx2 + 3); + _IdxWritePtr[17] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr += 18; idx1 = idx2; @@ -1005,10 +1181,18 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 // Add vertices for (int i = 0; i < points_count; i++) { - _VtxWritePtr[0].pos = temp_points[i * 4 + 0]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col_trans; - _VtxWritePtr[1].pos = temp_points[i * 4 + 1]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col; - _VtxWritePtr[2].pos = temp_points[i * 4 + 2]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col; - _VtxWritePtr[3].pos = temp_points[i * 4 + 3]; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col_trans; + _VtxWritePtr[0].pos = temp_points[i * 4 + 0]; + _VtxWritePtr[0].uv = opaque_uv; + _VtxWritePtr[0].col = col_trans; + _VtxWritePtr[1].pos = temp_points[i * 4 + 1]; + _VtxWritePtr[1].uv = opaque_uv; + _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = temp_points[i * 4 + 2]; + _VtxWritePtr[2].uv = opaque_uv; + _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = temp_points[i * 4 + 3]; + _VtxWritePtr[3].uv = opaque_uv; + _VtxWritePtr[3].col = col_trans; _VtxWritePtr += 4; } } @@ -1018,14 +1202,14 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 { // [PATH 4] Non texture-based, Non anti-aliased lines const int idx_count = count * 6; - const int vtx_count = count * 4; // FIXME-OPT: Not sharing edges + const int vtx_count = count * 4; // FIXME-OPT: Not sharing edges PrimReserve(idx_count, vtx_count); for (int i1 = 0; i1 < count; i1++) { const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; - const ImVec2& p1 = points[i1]; - const ImVec2& p2 = points[i2]; + const ImVec2 &p1 = points[i1]; + const ImVec2 &p2 = points[i2]; float dx = p2.x - p1.x; float dy = p2.y - p1.y; @@ -1033,23 +1217,41 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 dx *= (thickness * 0.5f); dy *= (thickness * 0.5f); - _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col; - _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col; - _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col; - _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col; + _VtxWritePtr[0].pos.x = p1.x + dy; + _VtxWritePtr[0].pos.y = p1.y - dx; + _VtxWritePtr[0].uv = opaque_uv; + _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos.x = p2.x + dy; + _VtxWritePtr[1].pos.y = p2.y - dx; + _VtxWritePtr[1].uv = opaque_uv; + _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos.x = p2.x - dy; + _VtxWritePtr[2].pos.y = p2.y + dx; + _VtxWritePtr[2].uv = opaque_uv; + _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos.x = p1.x - dy; + _VtxWritePtr[3].pos.y = p1.y + dx; + _VtxWritePtr[3].uv = opaque_uv; + _VtxWritePtr[3].col = col; _VtxWritePtr += 4; - _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + 2); - _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx + 2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx + 3); + _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); + _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + 1); + _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + 2); + _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); + _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx + 2); + _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx + 3); _IdxWritePtr += 6; _VtxCurrentIdx += 4; } } } -// - We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds. -// - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing. -void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col) +// - We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined +// builds. +// - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise +// shapes will have "inward" anti-aliasing. +void ImDrawList::AddConvexPolyFilled(const ImVec2 *points, const int points_count, ImU32 col) { if (points_count < 3 || (col & IM_COL32_A_MASK) == 0) return; @@ -1061,7 +1263,7 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun // Anti-aliased Fill const float AA_SIZE = _FringeScale; const ImU32 col_trans = col & ~IM_COL32_A_MASK; - const int idx_count = (points_count - 2)*3 + points_count * 6; + const int idx_count = (points_count - 2) * 3 + points_count * 6; const int vtx_count = (points_count * 2); PrimReserve(idx_count, vtx_count); @@ -1070,17 +1272,19 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun unsigned int vtx_outer_idx = _VtxCurrentIdx + 1; for (int i = 2; i < points_count; i++) { - _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + ((i - 1) << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (i << 1)); + _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); + _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + ((i - 1) << 1)); + _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (i << 1)); _IdxWritePtr += 3; } // Compute normals _Data->TempBuffer.reserve_discard(points_count); - ImVec2* temp_normals = _Data->TempBuffer.Data; + ImVec2 *temp_normals = _Data->TempBuffer.Data; for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) { - const ImVec2& p0 = points[i0]; - const ImVec2& p1 = points[i1]; + const ImVec2 &p0 = points[i0]; + const ImVec2 &p1 = points[i1]; float dx = p1.x - p0.x; float dy = p1.y - p0.y; IM_NORMALIZE2F_OVER_ZERO(dx, dy); @@ -1091,8 +1295,8 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) { // Average normals - const ImVec2& n0 = temp_normals[i0]; - const ImVec2& n1 = temp_normals[i1]; + const ImVec2 &n0 = temp_normals[i0]; + const ImVec2 &n1 = temp_normals[i1]; float dm_x = (n0.x + n1.x) * 0.5f; float dm_y = (n0.y + n1.y) * 0.5f; IM_FIXNORMAL2F(dm_x, dm_y); @@ -1100,13 +1304,23 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun dm_y *= AA_SIZE * 0.5f; // Add vertices - _VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner - _VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer + _VtxWritePtr[0].pos.x = (points[i1].x - dm_x); + _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); + _VtxWritePtr[0].uv = uv; + _VtxWritePtr[0].col = col; // Inner + _VtxWritePtr[1].pos.x = (points[i1].x + dm_x); + _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); + _VtxWritePtr[1].uv = uv; + _VtxWritePtr[1].col = col_trans; // Outer _VtxWritePtr += 2; // Add indexes for fringes - _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); - _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); + _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); + _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); + _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); + _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); + _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); + _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr += 6; } _VtxCurrentIdx += (ImDrawIdx)vtx_count; @@ -1114,24 +1328,28 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun else { // Non Anti-aliased Fill - const int idx_count = (points_count - 2)*3; + const int idx_count = (points_count - 2) * 3; const int vtx_count = points_count; PrimReserve(idx_count, vtx_count); for (int i = 0; i < vtx_count; i++) { - _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; + _VtxWritePtr[0].pos = points[i]; + _VtxWritePtr[0].uv = uv; + _VtxWritePtr[0].col = col; _VtxWritePtr++; } for (int i = 2; i < points_count; i++) { - _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + i - 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + i); + _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); + _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + i - 1); + _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + i); _IdxWritePtr += 3; } _VtxCurrentIdx += (ImDrawIdx)vtx_count; } } -void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step) +void ImDrawList::_PathArcToFastEx(const ImVec2 ¢er, float radius, int a_min_sample, int a_max_sample, int a_step) { if (radius < 0.5f) { @@ -1153,7 +1371,7 @@ void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_ bool extra_max_sample = false; if (a_step > 1) { - samples = sample_range / a_step + 1; + samples = sample_range / a_step + 1; const int overstep = sample_range % a_step; if (overstep > 0) @@ -1169,7 +1387,7 @@ void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_ } _Path.resize(_Path.Size + samples); - ImVec2* out_ptr = _Path.Data + (_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) @@ -1183,7 +1401,8 @@ void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_ { 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 + // 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; @@ -1197,7 +1416,8 @@ void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_ { 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 + // 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; @@ -1223,7 +1443,7 @@ void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_ IM_ASSERT_PARANOID(_Path.Data + _Path.Size == out_ptr); } -void ImDrawList::_PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments) +void ImDrawList::_PathArcToN(const ImVec2 ¢er, float radius, float a_min, float a_max, int num_segments) { if (radius < 0.5f) { @@ -1242,17 +1462,18 @@ void ImDrawList::_PathArcToN(const ImVec2& center, float radius, float a_min, fl } // 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) +void ImDrawList::PathArcToFast(const ImVec2 ¢er, float radius, int a_min_of_12, int a_max_of_12) { if (radius < 0.5f) { _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); + _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) +void ImDrawList::PathArcTo(const ImVec2 ¢er, float radius, float a_min, float a_max, int num_segments) { if (radius < 0.5f) { @@ -1278,7 +1499,8 @@ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, floa const int a_min_sample = a_is_reverse ? (int)ImFloor(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)ImFloor(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 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; @@ -1297,15 +1519,18 @@ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, floa { 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)); + 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); } } -void ImDrawList::PathEllipticalArcTo(const ImVec2& center, const ImVec2& radius, float rot, float a_min, float a_max, int num_segments) +void ImDrawList::PathEllipticalArcTo(const ImVec2 ¢er, const ImVec2 &radius, float rot, float a_min, float a_max, + int num_segments) { if (num_segments <= 0) - num_segments = _CalcCircleAutoSegmentCount(ImMax(radius.x, radius.y)); // A bit pessimistic, maybe there's a better computation to do here. + num_segments = _CalcCircleAutoSegmentCount( + ImMax(radius.x, radius.y)); // A bit pessimistic, maybe there's a better computation to do here. _Path.reserve(_Path.Size + (num_segments + 1)); @@ -1322,7 +1547,7 @@ void ImDrawList::PathEllipticalArcTo(const ImVec2& center, const ImVec2& radius, } } -ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t) +ImVec2 ImBezierCubicCalc(const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, const ImVec2 &p4, float t) { float u = 1.0f - t; float w1 = u * u * u; @@ -1332,7 +1557,7 @@ ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, c return ImVec2(w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x, w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y); } -ImVec2 ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float t) +ImVec2 ImBezierQuadraticCalc(const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, float t) { float u = 1.0f - t; float w1 = u * u; @@ -1342,7 +1567,8 @@ ImVec2 ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p } // Closely mimics ImBezierCubicClosestPointCasteljau() in imgui.cpp -static void PathBezierCubicCurveToCasteljau(ImVector* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level) +static void PathBezierCubicCurveToCasteljau(ImVector *path, float x1, float y1, float x2, float y2, float x3, + float y3, float x4, float y4, float tess_tol, int level) { float dx = x4 - x1; float dy = y4 - y1; @@ -1367,7 +1593,8 @@ static void PathBezierCubicCurveToCasteljau(ImVector* path, float x1, fl } } -static void PathBezierQuadraticCurveToCasteljau(ImVector* path, float x1, float y1, float x2, float y2, float x3, float y3, float tess_tol, int level) +static void PathBezierQuadraticCurveToCasteljau(ImVector *path, float x1, float y1, float x2, float y2, + float x3, float y3, float tess_tol, int level) { float dx = x3 - x1, dy = y3 - y1; float det = (x2 - x3) * dy - (y2 - y3) * dx; @@ -1385,13 +1612,14 @@ static void PathBezierQuadraticCurveToCasteljau(ImVector* path, float x1 } } -void ImDrawList::PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments) +void ImDrawList::PathBezierCubicCurveTo(const ImVec2 &p2, const ImVec2 &p3, const ImVec2 &p4, int num_segments) { ImVec2 p1 = _Path.back(); if (num_segments == 0) { IM_ASSERT(_Data->CurveTessellationTol > 0.0f); - PathBezierCubicCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); // Auto-tessellated + PathBezierCubicCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, + _Data->CurveTessellationTol, 0); // Auto-tessellated } else { @@ -1401,13 +1629,14 @@ void ImDrawList::PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, cons } } -void ImDrawList::PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments) +void ImDrawList::PathBezierQuadraticCurveTo(const ImVec2 &p2, const ImVec2 &p3, int num_segments) { ImVec2 p1 = _Path.back(); if (num_segments == 0) { IM_ASSERT(_Data->CurveTessellationTol > 0.0f); - PathBezierQuadraticCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, _Data->CurveTessellationTol, 0);// Auto-tessellated + PathBezierQuadraticCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, _Data->CurveTessellationTol, + 0); // Auto-tessellated } else { @@ -1422,17 +1651,19 @@ static inline ImDrawFlags FixRectCornerFlags(ImDrawFlags flags) /* IM_STATIC_ASSERT(ImDrawFlags_RoundCornersTopLeft == (1 << 4)); #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - // Obsoleted in 1.82 (from February 2021). This code was stripped/simplified and mostly commented in 1.90 (from September 2023) + // Obsoleted in 1.82 (from February 2021). This code was stripped/simplified and mostly commented in 1.90 (from +September 2023) // - Legacy Support for hard coded ~0 (used to be a suggested equivalent to ImDrawCornerFlags_All) if (flags == ~0) { return ImDrawFlags_RoundCornersAll; } - // - Legacy Support for hard coded 0x01 to 0x0F (matching 15 out of 16 old flags combinations). Read details in older version of this code. - 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 + // - Legacy Support for hard coded 0x01 to 0x0F (matching 15 out of 16 old flags combinations). Read details in +older version of this code. 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 assert 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. anyway. - // See details in 1.82 Changelog as well as 2021/03/12 and 2023/09/08 entries in "API BREAKING CHANGES" section. + // If this assert 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. + // anyway. See details in 1.82 Changelog as well as 2021/03/12 and 2023/09/08 entries in "API BREAKING CHANGES" + // section. IM_ASSERT((flags & 0x0F) == 0 && "Misuse of legacy hardcoded ImDrawCornerFlags values!"); if ((flags & ImDrawFlags_RoundCornersMask_) == 0) @@ -1441,13 +1672,25 @@ static inline ImDrawFlags FixRectCornerFlags(ImDrawFlags flags) return flags; } -void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawFlags flags) +void ImDrawList::PathRect(const ImVec2 &a, const ImVec2 &b, float rounding, ImDrawFlags flags) { if (rounding >= 0.5f) { 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); + 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.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) { @@ -1458,10 +1701,10 @@ void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDr } else { - const float rounding_tl = (flags & ImDrawFlags_RoundCornersTopLeft) ? rounding : 0.0f; - const float rounding_tr = (flags & ImDrawFlags_RoundCornersTopRight) ? 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; + 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); @@ -1469,7 +1712,7 @@ void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDr } } -void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness) +void ImDrawList::AddLine(const ImVec2 &p1, const ImVec2 &p2, ImU32 col, float thickness) { if ((col & IM_COL32_A_MASK) == 0) return; @@ -1480,18 +1723,20 @@ void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float th // 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, ImDrawFlags flags, 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, flags); else - 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. + 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, ImDrawFlags flags) +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; @@ -1508,22 +1753,28 @@ void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 c } // p_min = upper-left, p_max = lower-right -void ImDrawList::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) +void ImDrawList::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) { if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0) return; const ImVec2 uv = _Data->TexUvWhitePixel; PrimReserve(6, 4); - PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); - PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 3)); + PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); + PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 1)); + PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); + PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); + PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); + PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 3)); PrimWriteVtx(p_min, uv, col_upr_left); PrimWriteVtx(ImVec2(p_max.x, p_min.y), uv, col_upr_right); PrimWriteVtx(p_max, uv, col_bot_right); PrimWriteVtx(ImVec2(p_min.x, p_max.y), uv, col_bot_left); } -void ImDrawList::AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness) +void ImDrawList::AddQuad(const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, const ImVec2 &p4, ImU32 col, + float thickness) { if ((col & IM_COL32_A_MASK) == 0) return; @@ -1535,7 +1786,7 @@ void ImDrawList::AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, c PathStroke(col, ImDrawFlags_Closed, thickness); } -void ImDrawList::AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col) +void ImDrawList::AddQuadFilled(const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, const ImVec2 &p4, ImU32 col) { if ((col & IM_COL32_A_MASK) == 0) return; @@ -1547,7 +1798,7 @@ void ImDrawList::AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& PathFillConvex(col); } -void ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness) +void ImDrawList::AddTriangle(const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, ImU32 col, float thickness) { if ((col & IM_COL32_A_MASK) == 0) return; @@ -1558,7 +1809,7 @@ void ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p PathStroke(col, ImDrawFlags_Closed, thickness); } -void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col) +void ImDrawList::AddTriangleFilled(const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, ImU32 col) { if ((col & IM_COL32_A_MASK) == 0) return; @@ -1569,7 +1820,7 @@ void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImV PathFillConvex(col); } -void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness) +void ImDrawList::AddCircle(const ImVec2 ¢er, float radius, ImU32 col, int num_segments, float thickness) { if ((col & IM_COL32_A_MASK) == 0 || radius < 0.5f) return; @@ -1593,7 +1844,7 @@ void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int nu PathStroke(col, ImDrawFlags_Closed, thickness); } -void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) +void ImDrawList::AddCircleFilled(const ImVec2 ¢er, float radius, ImU32 col, int num_segments) { if ((col & IM_COL32_A_MASK) == 0 || radius < 0.5f) return; @@ -1618,7 +1869,7 @@ void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, } // Guaranteed to honor 'num_segments' -void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness) +void ImDrawList::AddNgon(const ImVec2 ¢er, float radius, ImU32 col, int num_segments, float thickness) { if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) return; @@ -1630,7 +1881,7 @@ void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_ } // Guaranteed to honor 'num_segments' -void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) +void ImDrawList::AddNgonFilled(const ImVec2 ¢er, float radius, ImU32 col, int num_segments) { if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) return; @@ -1642,13 +1893,15 @@ void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, in } // Ellipse -void ImDrawList::AddEllipse(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot, int num_segments, float thickness) +void ImDrawList::AddEllipse(const ImVec2 ¢er, const ImVec2 &radius, ImU32 col, float rot, int num_segments, + float thickness) { if ((col & IM_COL32_A_MASK) == 0) return; if (num_segments <= 0) - num_segments = _CalcCircleAutoSegmentCount(ImMax(radius.x, radius.y)); // A bit pessimistic, maybe there's a better computation to do here. + num_segments = _CalcCircleAutoSegmentCount( + ImMax(radius.x, radius.y)); // A bit pessimistic, maybe there's a better computation to do here. // 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; @@ -1656,13 +1909,14 @@ void ImDrawList::AddEllipse(const ImVec2& center, const ImVec2& radius, ImU32 co PathStroke(col, true, thickness); } -void ImDrawList::AddEllipseFilled(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot, int num_segments) +void ImDrawList::AddEllipseFilled(const ImVec2 ¢er, const ImVec2 &radius, ImU32 col, float rot, int num_segments) { if ((col & IM_COL32_A_MASK) == 0) return; if (num_segments <= 0) - num_segments = _CalcCircleAutoSegmentCount(ImMax(radius.x, radius.y)); // A bit pessimistic, maybe there's a better computation to do here. + num_segments = _CalcCircleAutoSegmentCount( + ImMax(radius.x, radius.y)); // A bit pessimistic, maybe there's a better computation to do here. // 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; @@ -1671,7 +1925,8 @@ void ImDrawList::AddEllipseFilled(const ImVec2& center, const ImVec2& radius, Im } // Cubic Bezier takes 4 controls points -void ImDrawList::AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments) +void ImDrawList::AddBezierCubic(const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, const ImVec2 &p4, ImU32 col, + float thickness, int num_segments) { if ((col & IM_COL32_A_MASK) == 0) return; @@ -1682,7 +1937,8 @@ void ImDrawList::AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2 } // Quadratic Bezier takes 3 controls points -void ImDrawList::AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments) +void ImDrawList::AddBezierQuadratic(const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, ImU32 col, float thickness, + int num_segments) { if ((col & IM_COL32_A_MASK) == 0) return; @@ -1692,7 +1948,8 @@ void ImDrawList::AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const Im PathStroke(col, 0, thickness); } -void ImDrawList::AddText(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) +void ImDrawList::AddText(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) { if ((col & IM_COL32_A_MASK) == 0) return; @@ -1716,15 +1973,17 @@ void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z); clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w); } - font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL); + font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, + cpu_fine_clip_rect != NULL); } -void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end) +void ImDrawList::AddText(const ImVec2 &pos, ImU32 col, const char *text_begin, const char *text_end) { AddText(_Data->Font, _Data->FontSize, pos, col, text_begin, text_end); } -void ImDrawList::AddImage(ImTextureRef tex_ref, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col) +void ImDrawList::AddImage(ImTextureRef tex_ref, const ImVec2 &p_min, const ImVec2 &p_max, const ImVec2 &uv_min, + const ImVec2 &uv_max, ImU32 col) { if ((col & IM_COL32_A_MASK) == 0) return; @@ -1740,7 +1999,9 @@ void ImDrawList::AddImage(ImTextureRef tex_ref, const ImVec2& p_min, const ImVec PopTexture(); } -void ImDrawList::AddImageQuad(ImTextureRef tex_ref, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1, const ImVec2& uv2, const ImVec2& uv3, const ImVec2& uv4, ImU32 col) +void ImDrawList::AddImageQuad(ImTextureRef tex_ref, const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, + const ImVec2 &p4, const ImVec2 &uv1, const ImVec2 &uv2, const ImVec2 &uv3, + const ImVec2 &uv4, ImU32 col) { if ((col & IM_COL32_A_MASK) == 0) return; @@ -1756,7 +2017,8 @@ void ImDrawList::AddImageQuad(ImTextureRef tex_ref, const ImVec2& p1, const ImVe PopTexture(); } -void ImDrawList::AddImageRounded(ImTextureRef tex_ref, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags) +void ImDrawList::AddImageRounded(ImTextureRef tex_ref, 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; @@ -1802,63 +2064,85 @@ enum ImTriangulatorNodeType struct ImTriangulatorNode { - ImTriangulatorNodeType Type; - int Index; - ImVec2 Pos; - ImTriangulatorNode* Next; - ImTriangulatorNode* Prev; + ImTriangulatorNodeType Type; + int Index; + ImVec2 Pos; + ImTriangulatorNode *Next; + ImTriangulatorNode *Prev; - void Unlink() { Next->Prev = Prev; Prev->Next = Next; } + void Unlink() + { + Next->Prev = Prev; + Prev->Next = Next; + } }; struct ImTriangulatorNodeSpan { - ImTriangulatorNode** Data = NULL; - int Size = 0; + ImTriangulatorNode **Data = NULL; + int Size = 0; - void push_back(ImTriangulatorNode* node) { Data[Size++] = node; } - void find_erase_unsorted(int idx) { for (int i = Size - 1; i >= 0; i--) if (Data[i]->Index == idx) { Data[i] = Data[Size - 1]; Size--; return; } } + void push_back(ImTriangulatorNode *node) + { + Data[Size++] = node; + } + void find_erase_unsorted(int idx) + { + for (int i = Size - 1; i >= 0; i--) + if (Data[i]->Index == idx) + { + Data[i] = Data[Size - 1]; + Size--; + return; + } + } }; struct ImTriangulator { - static int EstimateTriangleCount(int points_count) { return (points_count < 3) ? 0 : points_count - 2; } - static int EstimateScratchBufferSize(int points_count) { return sizeof(ImTriangulatorNode) * points_count + sizeof(ImTriangulatorNode*) * points_count * 2; } + static int EstimateTriangleCount(int points_count) + { + return (points_count < 3) ? 0 : points_count - 2; + } + static int EstimateScratchBufferSize(int points_count) + { + return sizeof(ImTriangulatorNode) * points_count + sizeof(ImTriangulatorNode *) * points_count * 2; + } - void Init(const ImVec2* points, int points_count, void* scratch_buffer); - void GetNextTriangle(unsigned int out_triangle[3]); // Return relative indexes for next triangle + void Init(const ImVec2 *points, int points_count, void *scratch_buffer); + void GetNextTriangle(unsigned int out_triangle[3]); // Return relative indexes for next triangle // Internal functions - void BuildNodes(const ImVec2* points, int points_count); - void BuildReflexes(); - void BuildEars(); - void FlipNodeList(); - bool IsEar(int i0, int i1, int i2, const ImVec2& v0, const ImVec2& v1, const ImVec2& v2) const; - void ReclassifyNode(ImTriangulatorNode* node); + void BuildNodes(const ImVec2 *points, int points_count); + void BuildReflexes(); + void BuildEars(); + void FlipNodeList(); + bool IsEar(int i0, int i1, int i2, const ImVec2 &v0, const ImVec2 &v1, const ImVec2 &v2) const; + void ReclassifyNode(ImTriangulatorNode *node); // Internal members - int _TrianglesLeft = 0; - ImTriangulatorNode* _Nodes = NULL; - ImTriangulatorNodeSpan _Ears; - ImTriangulatorNodeSpan _Reflexes; + int _TrianglesLeft = 0; + ImTriangulatorNode *_Nodes = NULL; + ImTriangulatorNodeSpan _Ears; + ImTriangulatorNodeSpan _Reflexes; }; // Distribute storage for nodes, ears and reflexes. // FIXME-OPT: if everything is convex, we could report it to caller and let it switch to an convex renderer // (this would require first building reflexes to bail to convex if empty, without even building nodes) -void ImTriangulator::Init(const ImVec2* points, int points_count, void* scratch_buffer) +void ImTriangulator::Init(const ImVec2 *points, int points_count, void *scratch_buffer) { IM_ASSERT(scratch_buffer != NULL && points_count >= 3); _TrianglesLeft = EstimateTriangleCount(points_count); - _Nodes = (ImTriangulatorNode*)scratch_buffer; // points_count x Node - _Ears.Data = (ImTriangulatorNode**)(_Nodes + points_count); // points_count x Node* - _Reflexes.Data = (ImTriangulatorNode**)(_Nodes + points_count) + points_count; // points_count x Node* + _Nodes = (ImTriangulatorNode *)scratch_buffer; // points_count x Node + _Ears.Data = (ImTriangulatorNode **)(_Nodes + points_count); // points_count x Node* + _Reflexes.Data = (ImTriangulatorNode **)(_Nodes + points_count) + points_count; // points_count x Node* BuildNodes(points, points_count); BuildReflexes(); BuildEars(); } -void ImTriangulator::BuildNodes(const ImVec2* points, int points_count) +void ImTriangulator::BuildNodes(const ImVec2 *points, int points_count) { for (int i = 0; i < points_count; i++) { @@ -1874,7 +2158,7 @@ void ImTriangulator::BuildNodes(const ImVec2* points, int points_count) void ImTriangulator::BuildReflexes() { - ImTriangulatorNode* n1 = _Nodes; + ImTriangulatorNode *n1 = _Nodes; for (int i = _TrianglesLeft; i >= 0; i--, n1 = n1->Next) { if (ImTriangleIsClockwise(n1->Prev->Pos, n1->Pos, n1->Next->Pos)) @@ -1886,7 +2170,7 @@ void ImTriangulator::BuildReflexes() void ImTriangulator::BuildEars() { - ImTriangulatorNode* n1 = _Nodes; + ImTriangulatorNode *n1 = _Nodes; for (int i = _TrianglesLeft; i >= 0; i--, n1 = n1->Next) { if (n1->Type != ImTriangulatorNodeType_Convex) @@ -1904,7 +2188,7 @@ void ImTriangulator::GetNextTriangle(unsigned int out_triangle[3]) { FlipNodeList(); - ImTriangulatorNode* node = _Nodes; + ImTriangulatorNode *node = _Nodes; for (int i = _TrianglesLeft; i >= 0; i--, node = node->Next) node->Type = ImTriangulatorNodeType_Convex; _Reflexes.Size = 0; @@ -1917,11 +2201,11 @@ void ImTriangulator::GetNextTriangle(unsigned int out_triangle[3]) // Return first triangle available, mimicking the behavior of convex fill. IM_ASSERT(_TrianglesLeft > 0); // Geometry is degenerated _Ears.Data[0] = _Nodes; - _Ears.Size = 1; + _Ears.Size = 1; } } - ImTriangulatorNode* ear = _Ears.Data[--_Ears.Size]; + ImTriangulatorNode *ear = _Ears.Data[--_Ears.Size]; out_triangle[0] = ear->Prev->Index; out_triangle[1] = ear->Index; out_triangle[2] = ear->Next->Index; @@ -1937,9 +2221,9 @@ void ImTriangulator::GetNextTriangle(unsigned int out_triangle[3]) void ImTriangulator::FlipNodeList() { - ImTriangulatorNode* prev = _Nodes; - ImTriangulatorNode* temp = _Nodes; - ImTriangulatorNode* current = _Nodes->Next; + ImTriangulatorNode *prev = _Nodes; + ImTriangulatorNode *temp = _Nodes; + ImTriangulatorNode *current = _Nodes->Next; prev->Next = prev; prev->Prev = prev; while (current != _Nodes) @@ -1958,12 +2242,12 @@ void ImTriangulator::FlipNodeList() } // A triangle is an ear is no other vertex is inside it. We can test reflexes vertices only (see reference algorithm) -bool ImTriangulator::IsEar(int i0, int i1, int i2, const ImVec2& v0, const ImVec2& v1, const ImVec2& v2) const +bool ImTriangulator::IsEar(int i0, int i1, int i2, const ImVec2 &v0, const ImVec2 &v1, const ImVec2 &v2) const { - ImTriangulatorNode** p_end = _Reflexes.Data + _Reflexes.Size; - for (ImTriangulatorNode** p = _Reflexes.Data; p < p_end; p++) + ImTriangulatorNode **p_end = _Reflexes.Data + _Reflexes.Size; + for (ImTriangulatorNode **p = _Reflexes.Data; p < p_end; p++) { - ImTriangulatorNode* reflex = *p; + ImTriangulatorNode *reflex = *p; if (reflex->Index != i0 && reflex->Index != i1 && reflex->Index != i2) if (ImTriangleContainsPoint(v0, v1, v2, reflex->Pos)) return false; @@ -1971,12 +2255,12 @@ bool ImTriangulator::IsEar(int i0, int i1, int i2, const ImVec2& v0, const ImVec return true; } -void ImTriangulator::ReclassifyNode(ImTriangulatorNode* n1) +void ImTriangulator::ReclassifyNode(ImTriangulatorNode *n1) { // Classify node ImTriangulatorNodeType type; - const ImTriangulatorNode* n0 = n1->Prev; - const ImTriangulatorNode* n2 = n1->Next; + const ImTriangulatorNode *n0 = n1->Prev; + const ImTriangulatorNode *n2 = n1->Next; if (!ImTriangleIsClockwise(n0->Pos, n1->Pos, n2->Pos)) type = ImTriangulatorNodeType_Reflex; else if (IsEar(n0->Index, n1->Index, n2->Index, n0->Pos, n1->Pos, n2->Pos)) @@ -2003,7 +2287,7 @@ void ImTriangulator::ReclassifyNode(ImTriangulatorNode* n1) // It is up to caller to ensure not making costly calls that will be outside of visible area. // As concave fill is noticeably more expensive than other primitives, be mindful of this... // Caller can build AABB of points, and avoid filling if 'draw_list->_CmdHeader.ClipRect.Overlays(points_bb) == false') -void ImDrawList::AddConcavePolyFilled(const ImVec2* points, const int points_count, ImU32 col) +void ImDrawList::AddConcavePolyFilled(const ImVec2 *points, const int points_count, ImU32 col) { if (points_count < 3 || (col & IM_COL32_A_MASK) == 0) return; @@ -2024,22 +2308,25 @@ void ImDrawList::AddConcavePolyFilled(const ImVec2* points, const int points_cou unsigned int vtx_inner_idx = _VtxCurrentIdx; unsigned int vtx_outer_idx = _VtxCurrentIdx + 1; - _Data->TempBuffer.reserve_discard((ImTriangulator::EstimateScratchBufferSize(points_count) + sizeof(ImVec2)) / sizeof(ImVec2)); + _Data->TempBuffer.reserve_discard((ImTriangulator::EstimateScratchBufferSize(points_count) + sizeof(ImVec2)) / + sizeof(ImVec2)); triangulator.Init(points, points_count, _Data->TempBuffer.Data); while (triangulator._TrianglesLeft > 0) { triangulator.GetNextTriangle(triangle); - _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (triangle[0] << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (triangle[1] << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (triangle[2] << 1)); + _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (triangle[0] << 1)); + _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (triangle[1] << 1)); + _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (triangle[2] << 1)); _IdxWritePtr += 3; } // Compute normals _Data->TempBuffer.reserve_discard(points_count); - ImVec2* temp_normals = _Data->TempBuffer.Data; + ImVec2 *temp_normals = _Data->TempBuffer.Data; for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) { - const ImVec2& p0 = points[i0]; - const ImVec2& p1 = points[i1]; + const ImVec2 &p0 = points[i0]; + const ImVec2 &p1 = points[i1]; float dx = p1.x - p0.x; float dy = p1.y - p0.y; IM_NORMALIZE2F_OVER_ZERO(dx, dy); @@ -2050,8 +2337,8 @@ void ImDrawList::AddConcavePolyFilled(const ImVec2* points, const int points_cou for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) { // Average normals - const ImVec2& n0 = temp_normals[i0]; - const ImVec2& n1 = temp_normals[i1]; + const ImVec2 &n0 = temp_normals[i0]; + const ImVec2 &n1 = temp_normals[i1]; float dm_x = (n0.x + n1.x) * 0.5f; float dm_y = (n0.y + n1.y) * 0.5f; IM_FIXNORMAL2F(dm_x, dm_y); @@ -2059,13 +2346,23 @@ void ImDrawList::AddConcavePolyFilled(const ImVec2* points, const int points_cou dm_y *= AA_SIZE * 0.5f; // Add vertices - _VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner - _VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer + _VtxWritePtr[0].pos.x = (points[i1].x - dm_x); + _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); + _VtxWritePtr[0].uv = uv; + _VtxWritePtr[0].col = col; // Inner + _VtxWritePtr[1].pos.x = (points[i1].x + dm_x); + _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); + _VtxWritePtr[1].uv = uv; + _VtxWritePtr[1].col = col_trans; // Outer _VtxWritePtr += 2; // Add indexes for fringes - _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); - _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); + _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); + _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); + _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); + _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); + _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); + _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr += 6; } _VtxCurrentIdx += (ImDrawIdx)vtx_count; @@ -2078,15 +2375,20 @@ void ImDrawList::AddConcavePolyFilled(const ImVec2* points, const int points_cou PrimReserve(idx_count, vtx_count); for (int i = 0; i < vtx_count; i++) { - _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; + _VtxWritePtr[0].pos = points[i]; + _VtxWritePtr[0].uv = uv; + _VtxWritePtr[0].col = col; _VtxWritePtr++; } - _Data->TempBuffer.reserve_discard((ImTriangulator::EstimateScratchBufferSize(points_count) + sizeof(ImVec2)) / sizeof(ImVec2)); + _Data->TempBuffer.reserve_discard((ImTriangulator::EstimateScratchBufferSize(points_count) + sizeof(ImVec2)) / + sizeof(ImVec2)); triangulator.Init(points, points_count, _Data->TempBuffer.Data); while (triangulator._TrianglesLeft > 0) { triangulator.GetNextTriangle(triangle); - _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx + triangle[0]); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + triangle[1]); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + triangle[2]); + _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx + triangle[0]); + _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + triangle[1]); + _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + triangle[2]); _IdxWritePtr += 3; } _VtxCurrentIdx += (ImDrawIdx)vtx_count; @@ -2096,7 +2398,8 @@ void ImDrawList::AddConcavePolyFilled(const ImVec2* points, const int points_cou //----------------------------------------------------------------------------- // [SECTION] ImDrawListSplitter //----------------------------------------------------------------------------- -// FIXME: This may be a little confusing, trying to be a little too low-level/optimal instead of just doing vector swap.. +// FIXME: This may be a little confusing, trying to be a little too low-level/optimal instead of just doing vector +// swap.. //----------------------------------------------------------------------------- void ImDrawListSplitter::ClearFreeMemory() @@ -2104,7 +2407,8 @@ void ImDrawListSplitter::ClearFreeMemory() for (int i = 0; i < _Channels.Size; i++) { if (i == _Current) - memset(&_Channels[i], 0, sizeof(_Channels[i])); // Current channel is a copy of CmdBuffer/IdxBuffer, don't destruct again + memset(&_Channels[i], 0, + sizeof(_Channels[i])); // Current channel is a copy of CmdBuffer/IdxBuffer, don't destruct again _Channels[i]._CmdBuffer.clear(); _Channels[i]._IdxBuffer.clear(); } @@ -2113,10 +2417,11 @@ void ImDrawListSplitter::ClearFreeMemory() _Channels.clear(); } -void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count) +void ImDrawListSplitter::Split(ImDrawList *draw_list, int channels_count) { IM_UNUSED(draw_list); - IM_ASSERT(_Current == 0 && _Count <= 1 && "Nested channel splitting is not supported. Please use separate instances of ImDrawListSplitter."); + IM_ASSERT(_Current == 0 && _Count <= 1 && + "Nested channel splitting is not supported. Please use separate instances of ImDrawListSplitter."); int old_channels_count = _Channels.Size; if (old_channels_count < channels_count) { @@ -2126,8 +2431,9 @@ void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count) _Count = channels_count; // Channels[] (24/32 bytes each) hold storage that we'll swap with draw_list->_CmdBuffer/_IdxBuffer - // The content of Channels[0] at this point doesn't matter. We clear it to make state tidy in a debugger but we don't strictly need to. - // When we switch to the next channel, we'll copy draw_list->_CmdBuffer/_IdxBuffer into Channels[0] and then Channels[1] into draw_list->CmdBuffer/_IdxBuffer + // The content of Channels[0] at this point doesn't matter. We clear it to make state tidy in a debugger but we + // don't strictly need to. When we switch to the next channel, we'll copy draw_list->_CmdBuffer/_IdxBuffer into + // Channels[0] and then Channels[1] into draw_list->CmdBuffer/_IdxBuffer memset(&_Channels[0], 0, sizeof(ImDrawChannel)); for (int i = 1; i < channels_count; i++) { @@ -2143,9 +2449,10 @@ void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count) } } -void ImDrawListSplitter::Merge(ImDrawList* draw_list) +void ImDrawListSplitter::Merge(ImDrawList *draw_list) { - // Note that we never use or rely on _Channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use. + // Note that we never use or rely on _Channels.Size because it is merely a buffer that we never shrink back to 0 to + // keep all sub-buffers ready for use. if (_Count <= 1) return; @@ -2155,20 +2462,23 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command. int new_cmd_buffer_count = 0; int new_idx_buffer_count = 0; - ImDrawCmd* last_cmd = (_Count > 0 && draw_list->CmdBuffer.Size > 0) ? &draw_list->CmdBuffer.back() : NULL; + ImDrawCmd *last_cmd = (_Count > 0 && draw_list->CmdBuffer.Size > 0) ? &draw_list->CmdBuffer.back() : NULL; int idx_offset = last_cmd ? last_cmd->IdxOffset + last_cmd->ElemCount : 0; for (int i = 1; i < _Count; i++) { - ImDrawChannel& ch = _Channels[i]; - if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0 && ch._CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd() + ImDrawChannel &ch = _Channels[i]; + if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0 && + ch._CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd() ch._CmdBuffer.pop_back(); if (ch._CmdBuffer.Size > 0 && last_cmd != NULL) { - // Do not include ImDrawCmd_AreSequentialIdxOffset() in the compare as we rebuild IdxOffset values ourselves. - // Manipulating IdxOffset (e.g. by reordering draw commands like done by RenderDimmedBackgroundBehindWindow()) is not supported within a splitter. - ImDrawCmd* next_cmd = &ch._CmdBuffer[0]; - if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL) + // Do not include ImDrawCmd_AreSequentialIdxOffset() in the compare as we rebuild IdxOffset values + // ourselves. Manipulating IdxOffset (e.g. by reordering draw commands like done by + // RenderDimmedBackgroundBehindWindow()) is not supported within a splitter. + ImDrawCmd *next_cmd = &ch._CmdBuffer[0]; + if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && + next_cmd->UserCallback == NULL) { // Merge previous channel last draw command with current channel first draw command if matching. last_cmd->ElemCount += next_cmd->ElemCount; @@ -2190,13 +2500,21 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) draw_list->IdxBuffer.resize(draw_list->IdxBuffer.Size + new_idx_buffer_count); // Write commands and indices in order (they are fairly small structures, we don't copy vertices only indices) - ImDrawCmd* cmd_write = draw_list->CmdBuffer.Data + draw_list->CmdBuffer.Size - new_cmd_buffer_count; - ImDrawIdx* idx_write = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size - new_idx_buffer_count; + ImDrawCmd *cmd_write = draw_list->CmdBuffer.Data + draw_list->CmdBuffer.Size - new_cmd_buffer_count; + ImDrawIdx *idx_write = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size - new_idx_buffer_count; for (int i = 1; i < _Count; i++) { - ImDrawChannel& ch = _Channels[i]; - if (int sz = ch._CmdBuffer.Size) { memcpy(cmd_write, ch._CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; } - if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; } + ImDrawChannel &ch = _Channels[i]; + if (int sz = ch._CmdBuffer.Size) + { + memcpy(cmd_write, ch._CmdBuffer.Data, sz * sizeof(ImDrawCmd)); + cmd_write += sz; + } + if (int sz = ch._IdxBuffer.Size) + { + memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); + idx_write += sz; + } } draw_list->_IdxWritePtr = idx_write; @@ -2205,7 +2523,7 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) draw_list->AddDrawCmd(); // If current command is used with different settings we need to add a new command - ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; + ImDrawCmd *curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; if (curr_cmd->ElemCount == 0) ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TexRef, VtxOffset else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0) @@ -2214,7 +2532,7 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) _Count = 1; } -void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx) +void ImDrawListSplitter::SetCurrentChannel(ImDrawList *draw_list, int idx) { IM_ASSERT(idx >= 0 && idx < _Count); if (_Current == idx) @@ -2229,7 +2547,8 @@ void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx) draw_list->_IdxWritePtr = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size; // If current command is used with different settings we need to add a new command - ImDrawCmd* curr_cmd = (draw_list->CmdBuffer.Size == 0) ? NULL : &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; + ImDrawCmd *curr_cmd = + (draw_list->CmdBuffer.Size == 0) ? NULL : &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; if (curr_cmd == NULL) draw_list->AddDrawCmd(); else if (curr_cmd->ElemCount == 0) @@ -2254,41 +2573,52 @@ void ImDrawData::Clear() // Important: 'out_list' is generally going to be draw_data->CmdLists, but may be another temporary list // as long at it is expected that the result will be later merged into draw_data->CmdLists[]. -void ImGui::AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector* out_list, ImDrawList* draw_list) +void ImGui::AddDrawListToDrawDataEx(ImDrawData *draw_data, ImVector *out_list, ImDrawList *draw_list) { if (draw_list->CmdBuffer.Size == 0) return; - if (draw_list->CmdBuffer.Size == 1 && draw_list->CmdBuffer[0].ElemCount == 0 && draw_list->CmdBuffer[0].UserCallback == NULL) + if (draw_list->CmdBuffer.Size == 1 && draw_list->CmdBuffer[0].ElemCount == 0 && + draw_list->CmdBuffer[0].UserCallback == NULL) return; - // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. - // May trigger for you if you are using PrimXXX functions incorrectly. - IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size); - IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size); + // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr + // etc. May trigger for you if you are using PrimXXX functions incorrectly. + IM_ASSERT(draw_list->VtxBuffer.Size == 0 || + draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size); + IM_ASSERT(draw_list->IdxBuffer.Size == 0 || + draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size); if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset)) IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); - // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window) - // If this assert triggers because you are drawing lots of stuff manually: + // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K + // vertices per ImDrawList = per window) If this assert triggers because you are drawing lots of stuff manually: // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds. - // Be mindful that the lower-level ImDrawList API doesn't filter vertices. Use the Metrics/Debugger window to inspect draw list contents. + // Be mindful that the lower-level ImDrawList API doesn't filter vertices. Use the Metrics/Debugger window to + // inspect draw list contents. // - If you want large meshes with more than 64K vertices, you can either: - // (A) Handle the ImDrawCmd::VtxOffset value in your renderer backend, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'. + // (A) Handle the ImDrawCmd::VtxOffset value in your renderer backend, and set 'io.BackendFlags |= + // ImGuiBackendFlags_RendererHasVtxOffset'. // Most example backends already support this from 1.71. Pre-1.71 backends won't. - // Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them. - // (B) Or handle 32-bit indices in your renderer backend, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h. - // Most example backends already support this. For example, the OpenGL example code detect index size at compile-time: - // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); + // Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported + // for them. + // (B) Or handle 32-bit indices in your renderer backend, and uncomment '#define ImDrawIdx unsigned int' line in + // imconfig.h. + // Most example backends already support this. For example, the OpenGL example code detect index size at + // compile-time: + // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : + // GL_UNSIGNED_INT, idx_buffer_offset); // Your own engine or render API may use different parameters or function calls to specify index sizes. // 2 and 4 bytes indices are generally supported by most graphics API. - // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching + // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() + // before reaching // the 64K limit to split your draw commands in multiple draw lists. if (sizeof(ImDrawIdx) == 2) - IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above"); + IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && + "Too many vertices in ImDrawList using 16-bit indices. Read comment above"); // Resolve callback data pointers if (draw_list->_CallbacksDataBuf.Size > 0) - for (ImDrawCmd& cmd : draw_list->CmdBuffer) + for (ImDrawCmd &cmd : draw_list->CmdBuffer) if (cmd.UserCallback != NULL && cmd.UserCallbackDataOffset != -1 && cmd.UserCallbackDataSize > 0) cmd.UserCallbackData = draw_list->_CallbacksDataBuf.Data + cmd.UserCallbackDataOffset; @@ -2299,21 +2629,22 @@ void ImGui::AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector draw_data->TotalIdxCount += draw_list->IdxBuffer.Size; } -void ImDrawData::AddDrawList(ImDrawList* draw_list) +void ImDrawData::AddDrawList(ImDrawList *draw_list) { IM_ASSERT(CmdLists.Size == CmdListsCount); draw_list->_PopUnusedDrawCmd(); ImGui::AddDrawListToDrawDataEx(this, &CmdLists, draw_list); } -// For backward compatibility: convert all buffers from indexed to de-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! +// For backward compatibility: convert all buffers from indexed to de-indexed, in case you cannot render indexed. Note: +// this is slow and most likely a waste of resources. Always prefer indexed rendering! void ImDrawData::DeIndexAllBuffers() { ImVector new_vtx_buffer; TotalVtxCount = TotalIdxCount = 0; for (int i = 0; i < CmdListsCount; i++) { - ImDrawList* cmd_list = CmdLists[i]; + ImDrawList *cmd_list = CmdLists[i]; if (cmd_list->IdxBuffer.empty()) continue; new_vtx_buffer.resize(cmd_list->IdxBuffer.Size); @@ -2328,11 +2659,12 @@ void ImDrawData::DeIndexAllBuffers() // Helper to scale the ClipRect field of each ImDrawCmd. // Use if your final output buffer is at a different scale than draw_data->DisplaySize, // or if there is a difference between your window resolution and framebuffer resolution. -void ImDrawData::ScaleClipRects(const ImVec2& fb_scale) +void ImDrawData::ScaleClipRects(const ImVec2 &fb_scale) { - for (ImDrawList* draw_list : CmdLists) - for (ImDrawCmd& cmd : draw_list->CmdBuffer) - cmd.ClipRect = ImVec4(cmd.ClipRect.x * fb_scale.x, cmd.ClipRect.y * fb_scale.y, cmd.ClipRect.z * fb_scale.x, cmd.ClipRect.w * fb_scale.y); + for (ImDrawList *draw_list : CmdLists) + for (ImDrawCmd &cmd : draw_list->CmdBuffer) + cmd.ClipRect = ImVec4(cmd.ClipRect.x * fb_scale.x, cmd.ClipRect.y * fb_scale.y, cmd.ClipRect.z * fb_scale.x, + cmd.ClipRect.w * fb_scale.y); } //----------------------------------------------------------------------------- @@ -2340,60 +2672,63 @@ void ImDrawData::ScaleClipRects(const ImVec2& fb_scale) //----------------------------------------------------------------------------- // Generic linear color gradient, write to RGB fields, leave A untouched. -void ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1) +void ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawList *draw_list, int vert_start_idx, int vert_end_idx, + ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1) { ImVec2 gradient_extent = gradient_p1 - gradient_p0; float gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent); - ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx; - ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx; + ImDrawVert *vert_start = draw_list->VtxBuffer.Data + vert_start_idx; + ImDrawVert *vert_end = draw_list->VtxBuffer.Data + vert_end_idx; const int col0_r = (int)(col0 >> IM_COL32_R_SHIFT) & 0xFF; const int col0_g = (int)(col0 >> IM_COL32_G_SHIFT) & 0xFF; const int col0_b = (int)(col0 >> IM_COL32_B_SHIFT) & 0xFF; const int col_delta_r = ((int)(col1 >> IM_COL32_R_SHIFT) & 0xFF) - col0_r; const int col_delta_g = ((int)(col1 >> IM_COL32_G_SHIFT) & 0xFF) - col0_g; const int col_delta_b = ((int)(col1 >> IM_COL32_B_SHIFT) & 0xFF) - col0_b; - for (ImDrawVert* vert = vert_start; vert < vert_end; vert++) + for (ImDrawVert *vert = vert_start; vert < vert_end; vert++) { float d = ImDot(vert->pos - gradient_p0, gradient_extent); float t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f); int r = (int)(col0_r + col_delta_r * t); int g = (int)(col0_g + col_delta_g * t); int b = (int)(col0_b + col_delta_b * t); - vert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK); + vert->col = + (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK); } } // Distribute UV over (a, b) rectangle -void ImGui::ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp) +void ImGui::ShadeVertsLinearUV(ImDrawList *draw_list, int vert_start_idx, int vert_end_idx, const ImVec2 &a, + const ImVec2 &b, const ImVec2 &uv_a, const ImVec2 &uv_b, bool clamp) { const ImVec2 size = b - a; const ImVec2 uv_size = uv_b - uv_a; - const ImVec2 scale = ImVec2( - size.x != 0.0f ? (uv_size.x / size.x) : 0.0f, - size.y != 0.0f ? (uv_size.y / size.y) : 0.0f); + const ImVec2 scale = + ImVec2(size.x != 0.0f ? (uv_size.x / size.x) : 0.0f, size.y != 0.0f ? (uv_size.y / size.y) : 0.0f); - ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx; - ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx; + ImDrawVert *vert_start = draw_list->VtxBuffer.Data + vert_start_idx; + ImDrawVert *vert_end = draw_list->VtxBuffer.Data + vert_end_idx; if (clamp) { const ImVec2 min = ImMin(uv_a, uv_b); const ImVec2 max = ImMax(uv_a, uv_b); - for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex) + for (ImDrawVert *vertex = vert_start; vertex < vert_end; ++vertex) vertex->uv = ImClamp(uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale), min, max); } else { - for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex) + for (ImDrawVert *vertex = vert_start; vertex < vert_end; ++vertex) vertex->uv = uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale); } } -void ImGui::ShadeVertsTransformPos(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& pivot_in, float cos_a, float sin_a, const ImVec2& pivot_out) +void ImGui::ShadeVertsTransformPos(ImDrawList *draw_list, int vert_start_idx, int vert_end_idx, const ImVec2 &pivot_in, + float cos_a, float sin_a, const ImVec2 &pivot_out) { - ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx; - ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx; - for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex) - vertex->pos = ImRotate(vertex->pos- pivot_in, cos_a, sin_a) + pivot_out; + ImDrawVert *vert_start = draw_list->VtxBuffer.Data + vert_start_idx; + ImDrawVert *vert_end = draw_list->VtxBuffer.Data + vert_end_idx; + for (ImDrawVert *vertex = vert_start; vertex < vert_end; ++vertex) + vertex->pos = ImRotate(vertex->pos - pivot_in, cos_a, sin_a) + pivot_out; } //----------------------------------------------------------------------------- @@ -2424,32 +2759,41 @@ int ImTextureDataGetFormatBytesPerPixel(ImTextureFormat format) { switch (format) { - case ImTextureFormat_Alpha8: return 1; - case ImTextureFormat_RGBA32: return 4; + case ImTextureFormat_Alpha8: + return 1; + case ImTextureFormat_RGBA32: + return 4; } IM_ASSERT(0); return 0; } -const char* ImTextureDataGetStatusName(ImTextureStatus status) +const char *ImTextureDataGetStatusName(ImTextureStatus status) { switch (status) { - case ImTextureStatus_OK: return "OK"; - case ImTextureStatus_Destroyed: return "Destroyed"; - case ImTextureStatus_WantCreate: return "WantCreate"; - case ImTextureStatus_WantUpdates: return "WantUpdates"; - case ImTextureStatus_WantDestroy: return "WantDestroy"; + case ImTextureStatus_OK: + return "OK"; + case ImTextureStatus_Destroyed: + return "Destroyed"; + case ImTextureStatus_WantCreate: + return "WantCreate"; + case ImTextureStatus_WantUpdates: + return "WantUpdates"; + case ImTextureStatus_WantDestroy: + return "WantDestroy"; } return "N/A"; } -const char* ImTextureDataGetFormatName(ImTextureFormat format) +const char *ImTextureDataGetFormatName(ImTextureFormat format) { switch (format) { - case ImTextureFormat_Alpha8: return "Alpha8"; - case ImTextureFormat_RGBA32: return "RGBA32"; + case ImTextureFormat_Alpha8: + return "Alpha8"; + case ImTextureFormat_RGBA32: + return "RGBA32"; } return "N/A"; } @@ -2462,7 +2806,7 @@ void ImTextureData::Create(ImTextureFormat format, int w, int h) Height = h; BytesPerPixel = ImTextureDataGetFormatBytesPerPixel(format); UseColors = false; - Pixels = (unsigned char*)IM_ALLOC(Width * Height * BytesPerPixel); + Pixels = (unsigned char *)IM_ALLOC(Width * Height * BytesPerPixel); IM_ASSERT(Pixels != NULL); memset(Pixels, 0, Width * Height * BytesPerPixel); UsedRect.x = UsedRect.y = UsedRect.w = UsedRect.h = 0; @@ -2569,55 +2913,82 @@ void ImTextureData::DestroyPixels() // (This is used when io.MouseDrawCursor = true) const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 122; // Actual texture will be 2 times that + 1 spacing. const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27; -static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] = -{ - "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX - XX XX " - "..- -X.....X- X.X - X.X -X.....X - X.....X- X..X -X..X X..X" - "--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X -X...X X...X" - "X - X.X - X.....X - X.....X -X...X - X...X- X..X - X...X X...X " - "XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X - X...X...X " - "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX - X.....X " - "X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX - X...X " - "X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX - X.X " - "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X - X...X " - "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X- X.....X " - "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X- X...X...X " - "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X- X...X X...X " - "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X-X...X X...X" - "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X-X..X X..X" - "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X- XX XX " - "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X--------------" - "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X - " - "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X - " - "X.X X..X - -X.......X- X.......X - XX XX - - X..........X - " - "XX X..X - - X.....X - X.....X - X.X X.X - - X........X - " - " X..X - - X...X - X...X - X..X X..X - - X........X - " - " XX - - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX - " - "------------- - X - X -X.....................X- ------------------- " - " ----------------------------------- X...XXXXXXXXXXXXX...X - " - " - X..X X..X - " - " - X.X X.X - " - " - XX XX - " -}; +static const char + FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] = { + "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX - " + "XX XX " + "..- -X.....X- X.X - X.X -X.....X - X.....X- X..X " + "-X..X X..X" + "--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X " + "-X...X X...X" + "X - X.X - X.....X - X.....X -X...X - X...X- X..X - " + "X...X X...X " + "XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X - " + " X...X...X " + "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX - " + " X.....X " + "X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX - " + " X...X " + "X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX - " + " X.X " + "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X - " + " X...X " + "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X- " + " X.....X " + "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X- " + " X...X...X " + "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X- " + "X...X X...X " + "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - " + "X..............X-X...X X...X" + "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - " + "X.............X-X..X X..X" + "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X- " + "XX XX " + "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - " + "X............X--------------" + "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X - " + " " + "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X - " + " " + "X.X X..X - -X.......X- X.......X - XX XX - - X..........X - " + " " + "XX X..X - - X.....X - X.....X - X.X X.X - - X........X - " + " " + " X..X - - X...X - X...X - X..X X..X - - X........X - " + " " + " XX - - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX - " + " " + "------------- - X - X -X.....................X- ------------------- " + " " + " ----------------------------------- X...XXXXXXXXXXXXX...X - " + " " + " - X..X X..X - " + " " + " - X.X X.X - " + " " + " - XX XX - " + " "}; -static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3] = -{ +static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3] = { // Pos ........ Size ......... Offset ...... - { ImVec2( 0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow - { ImVec2(13,0), ImVec2( 7,16), ImVec2( 1, 8) }, // ImGuiMouseCursor_TextInput - { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_ResizeAll - { ImVec2(21,0), ImVec2( 9,23), ImVec2( 4,11) }, // ImGuiMouseCursor_ResizeNS - { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 4) }, // ImGuiMouseCursor_ResizeEW - { ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW - { ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE - { ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand - { ImVec2(0,3), ImVec2(12,19), ImVec2(0, 0) }, // ImGuiMouseCursor_Wait // Arrow + custom code in ImGui::RenderMouseCursor() - { ImVec2(0,3), ImVec2(12,19), ImVec2(0, 0) }, // ImGuiMouseCursor_Progress // Arrow + custom code in ImGui::RenderMouseCursor() - { ImVec2(109,0),ImVec2(13,15), ImVec2( 6, 7) }, // ImGuiMouseCursor_NotAllowed + {ImVec2(0, 3), ImVec2(12, 19), ImVec2(0, 0)}, // ImGuiMouseCursor_Arrow + {ImVec2(13, 0), ImVec2(7, 16), ImVec2(1, 8)}, // ImGuiMouseCursor_TextInput + {ImVec2(31, 0), ImVec2(23, 23), ImVec2(11, 11)}, // ImGuiMouseCursor_ResizeAll + {ImVec2(21, 0), ImVec2(9, 23), ImVec2(4, 11)}, // ImGuiMouseCursor_ResizeNS + {ImVec2(55, 18), ImVec2(23, 9), ImVec2(11, 4)}, // ImGuiMouseCursor_ResizeEW + {ImVec2(73, 0), ImVec2(17, 17), ImVec2(8, 8)}, // ImGuiMouseCursor_ResizeNESW + {ImVec2(55, 0), ImVec2(17, 17), ImVec2(8, 8)}, // ImGuiMouseCursor_ResizeNWSE + {ImVec2(91, 0), ImVec2(17, 22), ImVec2(5, 0)}, // ImGuiMouseCursor_Hand + {ImVec2(0, 3), ImVec2(12, 19), + ImVec2(0, 0)}, // ImGuiMouseCursor_Wait // Arrow + custom code in ImGui::RenderMouseCursor() + {ImVec2(0, 3), ImVec2(12, 19), + ImVec2(0, 0)}, // ImGuiMouseCursor_Progress // Arrow + custom code in ImGui::RenderMouseCursor() + {ImVec2(109, 0), ImVec2(13, 15), ImVec2(6, 7)}, // ImGuiMouseCursor_NotAllowed }; -#define IM_FONTGLYPH_INDEX_UNUSED ((ImU16)-1) // 0xFFFF -#define IM_FONTGLYPH_INDEX_NOT_FOUND ((ImU16)-2) // 0xFFFE +#define IM_FONTGLYPH_INDEX_UNUSED ((ImU16) - 1) // 0xFFFF +#define IM_FONTGLYPH_INDEX_NOT_FOUND ((ImU16) - 2) // 0xFFFE ImFontAtlas::ImFontAtlas() { @@ -2628,7 +2999,8 @@ ImFontAtlas::ImFontAtlas() TexMinHeight = 128; TexMaxWidth = 8192; TexMaxHeight = 8192; - RendererHasTextures = false; // Assumed false by default, as apps can call e.g Atlas::Build() after backend init and before ImGui can update. + RendererHasTextures = false; // Assumed false by default, as apps can call e.g Atlas::Build() after backend init and + // before ImGui can update. TexNextUniqueID = 1; FontNextUniqueID = 1; Builder = NULL; @@ -2662,11 +3034,11 @@ void ImFontAtlas::ClearInputData() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); - for (ImFont* font : Fonts) + for (ImFont *font : Fonts) ImFontAtlasFontDestroyOutput(this, font); - for (ImFontConfig& font_cfg : Sources) + for (ImFontConfig &font_cfg : Sources) ImFontAtlasFontDestroySourceData(this, &font_cfg); - for (ImFont* font : Fonts) + for (ImFont *font : Fonts) { // When clearing this we lose access to the font name and other information used to build the font. font->Sources.clear(); @@ -2680,9 +3052,9 @@ void ImFontAtlas::ClearTexData() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); IM_ASSERT(RendererHasTextures == false && "Not supported for dynamic atlases, but you may call Clear()."); - for (ImTextureData* tex : TexList) + for (ImTextureData *tex : TexList) tex->DestroyPixels(); - //Locked = true; // Hoped to be able to lock this down but some reload patterns may not be happy with it. + // Locked = true; // Hoped to be able to lock this down but some reload patterns may not be happy with it. } void ImFontAtlas::ClearFonts() @@ -2693,22 +3065,22 @@ void ImFontAtlas::ClearFonts() ClearInputData(); Fonts.clear_delete(); TexIsBuilt = false; - for (ImDrawListSharedData* shared_data : DrawListSharedDatas) + for (ImDrawListSharedData *shared_data : DrawListSharedDatas) { shared_data->Font = NULL; shared_data->FontScale = shared_data->FontSize = 0.0f; } } -static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* atlas) +static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas *atlas) { // [LEGACY] Copy back the ImGuiBackendFlags_RendererHasTextures flag from ImGui context. // - This is the 1% exceptional case where that dependency if useful, to bypass an issue where otherwise at the // time of an early call to Build(), it would be impossible for us to tell if the backend supports texture update. // - Without this hack, we would have quite a pitfall as many legacy codebases have an early call to Build(). // Whereas conversely, the portion of people using ImDrawList without ImGui is expected to be pathologically rare. - for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas) - if (ImGuiContext* imgui_ctx = shared_data->Context) + for (ImDrawListSharedData *shared_data : atlas->DrawListSharedDatas) + if (ImGuiContext *imgui_ctx = shared_data->Context) { atlas->RendererHasTextures = (imgui_ctx->IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0; break; @@ -2718,10 +3090,12 @@ static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* at // Called by NewFrame() for atlases owned by a context. // If you manually manage font atlases, you'll need to call this yourself. // - 'frame_count' needs to be provided because we can gc/prioritize baked fonts based on their age. -// - 'frame_count' may not match those of all imgui contexts using this atlas, as contexts may be updated as different frequencies. But generally you can use ImGui::GetFrameCount() on one of your context. -void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count, bool renderer_has_textures) +// - 'frame_count' may not match those of all imgui contexts using this atlas, as contexts may be updated as different +// frequencies. But generally you can use ImGui::GetFrameCount() on one of your context. +void ImFontAtlasUpdateNewFrame(ImFontAtlas *atlas, int frame_count, bool renderer_has_textures) { - IM_ASSERT(atlas->Builder == NULL || atlas->Builder->FrameCount < frame_count); // Protection against being called twice. + IM_ASSERT(atlas->Builder == NULL || + atlas->Builder->FrameCount < frame_count); // Protection against being called twice. atlas->RendererHasTextures = renderer_has_textures; // Check that font atlas was built or backend support texture reload in which case we can build now @@ -2733,16 +3107,22 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count, bool rendere } else // Legacy backend { - IM_ASSERT_USER_ERROR(atlas->TexIsBuilt, "Backend does not support ImGuiBackendFlags_RendererHasTextures, and font atlas is not built! Update backend OR make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()."); + IM_ASSERT_USER_ERROR( + atlas->TexIsBuilt, + "Backend does not support ImGuiBackendFlags_RendererHasTextures, and font atlas is not built! Update " + "backend OR make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should " + "call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()."); } if (atlas->TexIsBuilt && atlas->Builder->PreloadedAllGlyphsRanges) - IM_ASSERT_USER_ERROR(atlas->RendererHasTextures == false, "Called ImFontAtlas::Build() before ImGuiBackendFlags_RendererHasTextures got set! With new backends: you don't need to call Build()."); + IM_ASSERT_USER_ERROR(atlas->RendererHasTextures == false, + "Called ImFontAtlas::Build() before ImGuiBackendFlags_RendererHasTextures got set! With " + "new backends: you don't need to call Build()."); // Clear BakedCurrent cache, this is important because it ensure the uncached path gets taken once. // We also rely on ImFontBaked* pointers never crossing frames. - ImFontAtlasBuilder* builder = atlas->Builder; + ImFontAtlasBuilder *builder = atlas->Builder; builder->FrameCount = frame_count; - for (ImFont* font : atlas->Fonts) + for (ImFont *font : atlas->Fonts) font->LastBaked = NULL; // Garbage collect BakedPool @@ -2751,10 +3131,10 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count, bool rendere int dst_n = 0, src_n = 0; for (; src_n < builder->BakedPool.Size; src_n++) { - ImFontBaked* p_src = &builder->BakedPool[src_n]; + ImFontBaked *p_src = &builder->BakedPool[src_n]; if (p_src->WantDestroy) continue; - ImFontBaked* p_dst = &builder->BakedPool[dst_n++]; + ImFontBaked *p_dst = &builder->BakedPool[dst_n++]; if (p_dst == p_src) continue; memcpy(p_dst, p_src, sizeof(ImFontBaked)); @@ -2768,7 +3148,7 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count, bool rendere // Update texture status for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++) { - ImTextureData* tex = atlas->TexList[tex_n]; + ImTextureData *tex = atlas->TexList[tex_n]; bool remove_from_list = false; if (tex->Status == ImTextureStatus_OK) { @@ -2777,11 +3157,13 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count, bool rendere tex->UpdateRect.w = tex->UpdateRect.h = 0; } if (tex->Status == ImTextureStatus_WantCreate && atlas->RendererHasTextures) - IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture's TexID/BackendUserData but did not update Status to OK."); + IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && + "Backend set texture's TexID/BackendUserData but did not update Status to OK."); if (tex->Status == ImTextureStatus_Destroyed) { - IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture Status to Destroyed but did not clear TexID/BackendUserData!"); + IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && + "Backend set texture Status to Destroyed but did not clear TexID/BackendUserData!"); if (tex->WantDestroyNextFrame) remove_from_list = true; // Destroy was scheduled by us else @@ -2791,17 +3173,20 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count, bool rendere { // Request destroy. Keep bool as it allows us to keep track of things. // We don't destroy pixels right away, as backend may have an in-flight copy from RAM. - IM_ASSERT(tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates); + IM_ASSERT(tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantCreate || + tex->Status == ImTextureStatus_WantUpdates); tex->Status = ImTextureStatus_WantDestroy; } - // The backend may need defer destroying by a few frames, to handle texture used by previous in-flight rendering. - // We allow the texture staying in _WantDestroy state and increment a counter which the backend can use to take its decision. + // The backend may need defer destroying by a few frames, to handle texture used by previous in-flight + // rendering. We allow the texture staying in _WantDestroy state and increment a counter which the backend can + // use to take its decision. if (tex->Status == ImTextureStatus_WantDestroy) tex->UnusedFrames++; // If a texture has never reached the backend, they don't need to know about it. - if (tex->Status == ImTextureStatus_WantDestroy && tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL) + if (tex->Status == ImTextureStatus_WantDestroy && tex->TexID == ImTextureID_Invalid && + tex->BackendUserData == NULL) remove_from_list = true; // Destroy and remove @@ -2815,7 +3200,8 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count, bool rendere } } -void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst_pixels, ImTextureFormat dst_fmt, int dst_pitch, int w, int h) +void ImFontAtlasTextureBlockConvert(const unsigned char *src_pixels, ImTextureFormat src_fmt, int src_pitch, + unsigned char *dst_pixels, ImTextureFormat dst_fmt, int dst_pitch, int w, int h) { IM_ASSERT(src_pixels != NULL && dst_pixels != NULL); if (src_fmt == dst_fmt) @@ -2828,8 +3214,8 @@ void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFo { for (int ny = h; ny > 0; ny--, src_pixels += src_pitch, dst_pixels += dst_pitch) { - const ImU8* src_p = (const ImU8*)src_pixels; - ImU32* dst_p = (ImU32*)(void*)dst_pixels; + const ImU8 *src_p = (const ImU8 *)src_pixels; + ImU32 *dst_p = (ImU32 *)(void *)dst_pixels; for (int nx = w; nx > 0; nx--) *dst_p++ = IM_COL32(255, 255, 255, (unsigned int)(*src_p++)); } @@ -2838,8 +3224,8 @@ void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFo { for (int ny = h; ny > 0; ny--, src_pixels += src_pitch, dst_pixels += dst_pitch) { - const ImU32* src_p = (const ImU32*)(void*)src_pixels; - ImU8* dst_p = (ImU8*)dst_pixels; + const ImU32 *src_p = (const ImU32 *)(void *)src_pixels; + ImU8 *dst_p = (ImU8 *)dst_pixels; for (int nx = w; nx > 0; nx--) *dst_p++ = ((*src_p++) >> IM_COL32_A_SHIFT) & 0xFF; } @@ -2852,22 +3238,22 @@ void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFo // Source buffer may be written to (used for in-place mods). // Post-process hooks may eventually be added here. -void ImFontAtlasTextureBlockPostProcess(ImFontAtlasPostProcessData* data) +void ImFontAtlasTextureBlockPostProcess(ImFontAtlasPostProcessData *data) { // Multiply operator (legacy) if (data->FontSrc->RasterizerMultiply != 1.0f) ImFontAtlasTextureBlockPostProcessMultiply(data, data->FontSrc->RasterizerMultiply); } -void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlasPostProcessData* data, float multiply_factor) +void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlasPostProcessData *data, float multiply_factor) { - unsigned char* pixels = data->Pixels; + unsigned char *pixels = data->Pixels; int pitch = data->Pitch; if (data->Format == ImTextureFormat_Alpha8) { for (int ny = data->Height; ny > 0; ny--, pixels += pitch) { - ImU8* p = (ImU8*)pixels; + ImU8 *p = (ImU8 *)pixels; for (int nx = data->Width; nx > 0; nx--, p++) { unsigned int v = ImMin((unsigned int)(*p * multiply_factor), (unsigned int)255); @@ -2879,11 +3265,13 @@ void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlasPostProcessData* data { for (int ny = data->Height; ny > 0; ny--, pixels += pitch) { - ImU32* p = (ImU32*)(void*)pixels; + ImU32 *p = (ImU32 *)(void *)pixels; for (int nx = data->Width; nx > 0; nx--, p++) { - unsigned int a = ImMin((unsigned int)(((*p >> IM_COL32_A_SHIFT) & 0xFF) * multiply_factor), (unsigned int)255); - *p = IM_COL32((*p >> IM_COL32_R_SHIFT) & 0xFF, (*p >> IM_COL32_G_SHIFT) & 0xFF, (*p >> IM_COL32_B_SHIFT) & 0xFF, a); + unsigned int a = + ImMin((unsigned int)(((*p >> IM_COL32_A_SHIFT) & 0xFF) * multiply_factor), (unsigned int)255); + *p = IM_COL32((*p >> IM_COL32_R_SHIFT) & 0xFF, (*p >> IM_COL32_G_SHIFT) & 0xFF, + (*p >> IM_COL32_B_SHIFT) & 0xFF, a); } } } @@ -2894,19 +3282,19 @@ void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlasPostProcessData* data } // Fill with single color. We don't use this directly but it is convenient for anyone working on uploading custom rects. -void ImFontAtlasTextureBlockFill(ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h, ImU32 col) +void ImFontAtlasTextureBlockFill(ImTextureData *dst_tex, int dst_x, int dst_y, int w, int h, ImU32 col) { if (dst_tex->Format == ImTextureFormat_Alpha8) { ImU8 col_a = (col >> IM_COL32_A_SHIFT) & 0xFF; for (int y = 0; y < h; y++) - memset((ImU8*)dst_tex->GetPixelsAt(dst_x, dst_y + y), col_a, w); + memset((ImU8 *)dst_tex->GetPixelsAt(dst_x, dst_y + y), col_a, w); } else { for (int y = 0; y < h; y++) { - ImU32* p = (ImU32*)(void*)dst_tex->GetPixelsAt(dst_x, dst_y + y); + ImU32 *p = (ImU32 *)(void *)dst_tex->GetPixelsAt(dst_x, dst_y + y); for (int x = w; x > 0; x--, p++) *p = col; } @@ -2914,7 +3302,8 @@ void ImFontAtlasTextureBlockFill(ImTextureData* dst_tex, int dst_x, int dst_y, i } // Copy block from one texture to another -void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h) +void ImFontAtlasTextureBlockCopy(ImTextureData *src_tex, int src_x, int src_y, ImTextureData *dst_tex, int dst_x, + int dst_y, int w, int h) { IM_ASSERT(src_tex->Pixels != NULL && dst_tex->Pixels != NULL); IM_ASSERT(src_tex->Format == dst_tex->Format); @@ -2923,17 +3312,19 @@ void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, I IM_ASSERT(dst_x >= 0 && dst_x + w <= dst_tex->Width); IM_ASSERT(dst_y >= 0 && dst_y + h <= dst_tex->Height); for (int y = 0; y < h; y++) - memcpy(dst_tex->GetPixelsAt(dst_x, dst_y + y), src_tex->GetPixelsAt(src_x, src_y + y), w * dst_tex->BytesPerPixel); + memcpy(dst_tex->GetPixelsAt(dst_x, dst_y + y), src_tex->GetPixelsAt(src_x, src_y + y), + w * dst_tex->BytesPerPixel); } // Queue texture block update for renderer backend -void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, int x, int y, int w, int h) +void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas *atlas, ImTextureData *tex, int x, int y, int w, int h) { IM_ASSERT(tex->Status != ImTextureStatus_WantDestroy && tex->Status != ImTextureStatus_Destroyed); - IM_ASSERT(x >= 0 && x <= 0xFFFF && y >= 0 && y <= 0xFFFF && w >= 0 && x + w <= 0x10000 && h >= 0 && y + h <= 0x10000); + IM_ASSERT(x >= 0 && x <= 0xFFFF && y >= 0 && y <= 0xFFFF && w >= 0 && x + w <= 0x10000 && h >= 0 && + y + h <= 0x10000); IM_UNUSED(atlas); - ImTextureRect req = { (unsigned short)x, (unsigned short)y, (unsigned short)w, (unsigned short)h }; + ImTextureRect req = {(unsigned short)x, (unsigned short)y, (unsigned short)w, (unsigned short)h}; int new_x1 = ImMax(tex->UpdateRect.w == 0 ? 0 : tex->UpdateRect.x + tex->UpdateRect.w, req.x + req.w); int new_y1 = ImMax(tex->UpdateRect.h == 0 ? 0 : tex->UpdateRect.y + tex->UpdateRect.h, req.y + req.h); tex->UpdateRect.x = ImMin(tex->UpdateRect.x, req.x); @@ -2955,27 +3346,42 @@ void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, } #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -static void GetTexDataAsFormat(ImFontAtlas* atlas, ImTextureFormat format, unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) +static void GetTexDataAsFormat(ImFontAtlas *atlas, ImTextureFormat format, unsigned char **out_pixels, int *out_width, + int *out_height, int *out_bytes_per_pixel) { - ImTextureData* tex = atlas->TexData; + ImTextureData *tex = atlas->TexData; if (!atlas->TexIsBuilt || tex == NULL || tex->Pixels == NULL || atlas->TexDesiredFormat != format) { atlas->TexDesiredFormat = format; atlas->Build(); tex = atlas->TexData; } - if (out_pixels) { *out_pixels = (unsigned char*)tex->Pixels; }; - if (out_width) { *out_width = tex->Width; }; - if (out_height) { *out_height = tex->Height; }; - if (out_bytes_per_pixel) { *out_bytes_per_pixel = tex->BytesPerPixel; } + if (out_pixels) + { + *out_pixels = (unsigned char *)tex->Pixels; + }; + if (out_width) + { + *out_width = tex->Width; + }; + if (out_height) + { + *out_height = tex->Height; + }; + if (out_bytes_per_pixel) + { + *out_bytes_per_pixel = tex->BytesPerPixel; + } } -void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) +void ImFontAtlas::GetTexDataAsAlpha8(unsigned char **out_pixels, int *out_width, int *out_height, + int *out_bytes_per_pixel) { GetTexDataAsFormat(this, ImTextureFormat_Alpha8, out_pixels, out_width, out_height, out_bytes_per_pixel); } -void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) +void ImFontAtlas::GetTexDataAsRGBA32(unsigned char **out_pixels, int *out_width, int *out_height, + int *out_bytes_per_pixel) { GetTexDataAsFormat(this, ImTextureFormat_RGBA32, out_pixels, out_width, out_height, out_bytes_per_pixel); } @@ -2987,22 +3393,24 @@ bool ImFontAtlas::Build() } #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) +ImFont *ImFontAtlas::AddFont(const ImFontConfig *font_cfg_in) { // Sanity Checks IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); IM_ASSERT((font_cfg_in->FontData != NULL && font_cfg_in->FontDataSize > 0) || (font_cfg_in->FontLoader != NULL)); - //IM_ASSERT(font_cfg_in->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?"); + // IM_ASSERT(font_cfg_in->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?"); IM_ASSERT(font_cfg_in->RasterizerDensity > 0.0f && "Is ImFontConfig struct correctly initialized?"); - if (font_cfg_in->GlyphOffset.x != 0.0f || font_cfg_in->GlyphOffset.y != 0.0f || font_cfg_in->GlyphMinAdvanceX != 0.0f || font_cfg_in->GlyphMaxAdvanceX != FLT_MAX) - IM_ASSERT(font_cfg_in->SizePixels != 0.0f && "Specifying glyph offset/advances requires a reference size to base it on."); + if (font_cfg_in->GlyphOffset.x != 0.0f || font_cfg_in->GlyphOffset.y != 0.0f || + font_cfg_in->GlyphMinAdvanceX != 0.0f || font_cfg_in->GlyphMaxAdvanceX != FLT_MAX) + IM_ASSERT(font_cfg_in->SizePixels != 0.0f && + "Specifying glyph offset/advances requires a reference size to base it on."); // Lazily create builder on the first call to AddFont if (Builder == NULL) ImFontAtlasBuildInit(this); // Create new font - ImFont* font; + ImFont *font; if (!font_cfg_in->MergeMode) { font = IM_NEW(ImFont)(); @@ -3014,17 +3422,22 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) } else { - IM_ASSERT(Fonts.Size > 0 && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font. + IM_ASSERT(Fonts.Size > 0 && + "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already + // been added before. You can use + // ImGui::GetIO().Fonts->AddFontDefault() to add the + // default imgui font. font = Fonts.back(); } // Add to list Sources.push_back(*font_cfg_in); - ImFontConfig* font_cfg = &Sources.back(); + ImFontConfig *font_cfg = &Sources.back(); if (font_cfg->DstFont == NULL) font_cfg->DstFont = font; font->Sources.push_back(font_cfg); - ImFontAtlasBuildUpdatePointers(this); // Pointers to Sources are otherwise dangling after we called Sources.push_back(). + ImFontAtlasBuildUpdatePointers( + this); // Pointers to Sources are otherwise dangling after we called Sources.push_back(). if (font_cfg->FontDataOwnedByAtlas == false) { @@ -3037,21 +3450,26 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) if (font_cfg->GlyphExcludeRanges != NULL) { int size = 0; - for (const ImWchar* p = font_cfg->GlyphExcludeRanges; p[0] != 0; p++, size++) {} + for (const ImWchar *p = font_cfg->GlyphExcludeRanges; p[0] != 0; p++, size++) + { + } IM_ASSERT((size & 1) == 0 && "GlyphExcludeRanges[] size must be multiple of two!"); IM_ASSERT((size <= 64) && "GlyphExcludeRanges[] size must be small!"); - font_cfg->GlyphExcludeRanges = (ImWchar*)ImMemdup(font_cfg->GlyphExcludeRanges, sizeof(font_cfg->GlyphExcludeRanges[0]) * (size + 1)); + font_cfg->GlyphExcludeRanges = + (ImWchar *)ImMemdup(font_cfg->GlyphExcludeRanges, sizeof(font_cfg->GlyphExcludeRanges[0]) * (size + 1)); } if (font_cfg->FontLoader != NULL) { IM_ASSERT(font_cfg->FontLoader->FontBakedLoadGlyph != NULL); - IM_ASSERT(font_cfg->FontLoader->LoaderInit == NULL && font_cfg->FontLoader->LoaderShutdown == NULL); // FIXME-NEWATLAS: Unsupported yet. + IM_ASSERT(font_cfg->FontLoader->LoaderInit == NULL && + font_cfg->FontLoader->LoaderShutdown == NULL); // FIXME-NEWATLAS: Unsupported yet. } IM_ASSERT(font_cfg->FontLoaderData == NULL); if (!ImFontAtlasFontSourceInit(this, font_cfg)) { - // Rollback (this is a fragile/rarely exercised code-path. TestSuite's "misc_atlas_add_invalid_font" aim to test this) + // Rollback (this is a fragile/rarely exercised code-path. TestSuite's "misc_atlas_add_invalid_font" aim to test + // this) ImFontAtlasFontDestroySourceData(this, font_cfg); Sources.pop_back(); font->Sources.pop_back(); @@ -3067,26 +3485,35 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) return font; } -// Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder) -static unsigned int stb_decompress_length(const unsigned char* input); -static unsigned int stb_decompress(unsigned char* output, const unsigned char* input, unsigned int length); -static unsigned int Decode85Byte(char c) { return c >= '\\' ? c-36 : c-35; } -static void Decode85(const unsigned char* src, unsigned char* dst) +// Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for +// encoder) +static unsigned int stb_decompress_length(const unsigned char *input); +static unsigned int stb_decompress(unsigned char *output, const unsigned char *input, unsigned int length); +static unsigned int Decode85Byte(char c) +{ + return c >= '\\' ? c - 36 : c - 35; +} +static void Decode85(const unsigned char *src, unsigned char *dst) { while (*src) { - unsigned int tmp = Decode85Byte(src[0]) + 85 * (Decode85Byte(src[1]) + 85 * (Decode85Byte(src[2]) + 85 * (Decode85Byte(src[3]) + 85 * Decode85Byte(src[4])))); - dst[0] = ((tmp >> 0) & 0xFF); dst[1] = ((tmp >> 8) & 0xFF); dst[2] = ((tmp >> 16) & 0xFF); dst[3] = ((tmp >> 24) & 0xFF); // We can't assume little-endianness. + unsigned int tmp = Decode85Byte(src[0]) + + 85 * (Decode85Byte(src[1]) + + 85 * (Decode85Byte(src[2]) + 85 * (Decode85Byte(src[3]) + 85 * Decode85Byte(src[4])))); + dst[0] = ((tmp >> 0) & 0xFF); + dst[1] = ((tmp >> 8) & 0xFF); + dst[2] = ((tmp >> 16) & 0xFF); + dst[3] = ((tmp >> 24) & 0xFF); // We can't assume little-endianness. src += 5; dst += 4; } } #ifndef IMGUI_DISABLE_DEFAULT_FONT -static const char* GetDefaultCompressedFontDataTTF(int* out_size); +static const char *GetDefaultCompressedFontDataTTF(int *out_size); #endif // Load embedded ProggyClean.ttf at size 13, disable oversampling -ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) +ImFont *ImFontAtlas::AddFontDefault(const ImFontConfig *font_cfg_template) { #ifndef IMGUI_DISABLE_DEFAULT_FONT ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); @@ -3100,12 +3527,13 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) if (font_cfg.Name[0] == '\0') ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf"); font_cfg.EllipsisChar = (ImWchar)0x0085; - font_cfg.GlyphOffset.y = 1.0f * IM_TRUNC(font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units + font_cfg.GlyphOffset.y = 1.0f * IM_TRUNC(font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units int ttf_compressed_size = 0; - const char* ttf_compressed = GetDefaultCompressedFontDataTTF(&ttf_compressed_size); - const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault(); - ImFont* font = AddFontFromMemoryCompressedTTF(ttf_compressed, ttf_compressed_size, font_cfg.SizePixels, &font_cfg, glyph_ranges); + const char *ttf_compressed = GetDefaultCompressedFontDataTTF(&ttf_compressed_size); + const ImWchar *glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault(); + ImFont *font = AddFontFromMemoryCompressedTTF(ttf_compressed, ttf_compressed_size, font_cfg.SizePixels, &font_cfg, + glyph_ranges); return font; #else IM_ASSERT(0 && "AddFontDefault() disabled in this build."); @@ -3114,11 +3542,12 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) #endif // #ifndef IMGUI_DISABLE_DEFAULT_FONT } -ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) +ImFont *ImFontAtlas::AddFontFromFileTTF(const char *filename, float size_pixels, const ImFontConfig *font_cfg_template, + const ImWchar *glyph_ranges) { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); size_t data_size = 0; - void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0); + void *data = ImFileLoadToMemory(filename, "rb", &data_size, 0); if (!data) { if (font_cfg_template == NULL || (font_cfg_template->Flags & ImFontFlags_NoLoadError) == 0) @@ -3132,20 +3561,26 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, if (font_cfg.Name[0] == '\0') { // Store a short copy of filename into into the font name for convenience - const char* p; - for (p = filename + ImStrlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {} + const char *p; + for (p = filename + ImStrlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) + { + } ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s", p); } return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges); } -// NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build(). -ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* font_data, int font_data_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) +// NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned +// TTF buffer will be deleted after Build(). +ImFont *ImFontAtlas::AddFontFromMemoryTTF(void *font_data, int font_data_size, float size_pixels, + const ImFontConfig *font_cfg_template, const ImWchar *glyph_ranges) { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); IM_ASSERT(font_cfg.FontData == NULL); - IM_ASSERT(font_data_size > 100 && "Incorrect value for font_data_size!"); // Heuristic to prevent accidentally passing a wrong value to font_data_size. + IM_ASSERT(font_data_size > 100 && + "Incorrect value for font_data_size!"); // Heuristic to prevent accidentally passing a wrong value to + // font_data_size. font_cfg.FontData = font_data; font_cfg.FontDataSize = font_data_size; font_cfg.SizePixels = size_pixels > 0.0f ? size_pixels : font_cfg.SizePixels; @@ -3154,43 +3589,49 @@ ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* font_data, int font_data_size, f return AddFont(&font_cfg); } -ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) +ImFont *ImFontAtlas::AddFontFromMemoryCompressedTTF(const void *compressed_ttf_data, int compressed_ttf_size, + float size_pixels, const ImFontConfig *font_cfg_template, + const ImWchar *glyph_ranges) { - const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data); - unsigned char* buf_decompressed_data = (unsigned char*)IM_ALLOC(buf_decompressed_size); - stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size); + const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char *)compressed_ttf_data); + unsigned char *buf_decompressed_data = (unsigned char *)IM_ALLOC(buf_decompressed_size); + stb_decompress(buf_decompressed_data, (const unsigned char *)compressed_ttf_data, + (unsigned int)compressed_ttf_size); ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); IM_ASSERT(font_cfg.FontData == NULL); font_cfg.FontDataOwnedByAtlas = true; - return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges); + return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, + glyph_ranges); } -ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges) +ImFont *ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char *compressed_ttf_data_base85, float size_pixels, + const ImFontConfig *font_cfg, const ImWchar *glyph_ranges) { int compressed_ttf_size = (((int)ImStrlen(compressed_ttf_data_base85) + 4) / 5) * 4; - void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size); - Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf); - ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges); + void *compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size); + Decode85((const unsigned char *)compressed_ttf_data_base85, (unsigned char *)compressed_ttf); + ImFont *font = + AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges); IM_FREE(compressed_ttf); return font; } // On font removal we need to remove references (otherwise we could queue removal?) // We allow old_font == new_font which forces updating all values (e.g. sizes) -static void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font, ImFont* new_font) +static void ImFontAtlasBuildNotifySetFont(ImFontAtlas *atlas, ImFont *old_font, ImFont *new_font) { - for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas) + for (ImDrawListSharedData *shared_data : atlas->DrawListSharedDatas) { if (shared_data->Font == old_font) shared_data->Font = new_font; - if (ImGuiContext* ctx = shared_data->Context) + if (ImGuiContext *ctx = shared_data->Context) { if (ctx->IO.FontDefault == old_font) ctx->IO.FontDefault = new_font; if (ctx->Font == old_font) { - ImGuiContext* curr_ctx = ImGui::GetCurrentContext(); + ImGuiContext *curr_ctx = ImGui::GetCurrentContext(); bool need_bind_ctx = ctx != curr_ctx; if (need_bind_ctx) ImGui::SetCurrentContext(ctx); @@ -3198,20 +3639,20 @@ static void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font, if (need_bind_ctx) ImGui::SetCurrentContext(curr_ctx); } - for (ImFontStackData& font_stack_data : ctx->FontStack) + for (ImFontStackData &font_stack_data : ctx->FontStack) if (font_stack_data.Font == old_font) font_stack_data.Font = new_font; } } } -void ImFontAtlas::RemoveFont(ImFont* font) +void ImFontAtlas::RemoveFont(ImFont *font) { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); font->ClearOutputData(); ImFontAtlasFontDestroyOutput(this, font); - for (ImFontConfig* src : font->Sources) + for (ImFontConfig *src : font->Sources) ImFontAtlasFontDestroySourceData(this, src); for (int src_n = 0; src_n < Sources.Size; src_n++) if (Sources[src_n].DstFont == font) @@ -3227,12 +3668,13 @@ void ImFontAtlas::RemoveFont(ImFont* font) IM_DELETE(font); // Notify external systems - ImFont* new_current_font = Fonts.empty() ? NULL : Fonts[0]; + ImFont *new_current_font = Fonts.empty() ? NULL : Fonts[0]; ImFontAtlasBuildNotifySetFont(this, font, new_current_font); } -// At it is common to do an AddCustomRect() followed by a GetCustomRect(), we provide an optional 'ImFontAtlasRect* out_r = NULL' argument to retrieve the info straight away. -ImFontAtlasRectId ImFontAtlas::AddCustomRect(int width, int height, ImFontAtlasRect* out_r) +// At it is common to do an AddCustomRect() followed by a GetCustomRect(), we provide an optional 'ImFontAtlasRect* +// out_r = NULL' argument to retrieve the info straight away. +ImFontAtlasRectId ImFontAtlas::AddCustomRect(int width, int height, ImFontAtlasRect *out_r) { IM_ASSERT(width > 0 && width <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF); @@ -3248,7 +3690,7 @@ ImFontAtlasRectId ImFontAtlas::AddCustomRect(int width, int height, ImFontAtlasR if (RendererHasTextures) { - ImTextureRect* r = ImFontAtlasPackGetRect(this, r_id); + ImTextureRect *r = ImFontAtlasPackGetRect(this, r_id); ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h); } return r_id; @@ -3268,14 +3710,17 @@ void ImFontAtlas::RemoveCustomRect(ImFontAtlasRectId id) // ImFont* myfont = io.Fonts->AddFontFromFileTTF(....); // myfont->GetFontBaked(16.0f); // myfont->Flags |= ImFontFlags_LockBakedSizes; -ImFontAtlasRectId ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset) +ImFontAtlasRectId ImFontAtlas::AddCustomRectFontGlyph(ImFont *font, ImWchar codepoint, int width, int height, + float advance_x, const ImVec2 &offset) { float font_size = font->LegacySize; return AddCustomRectFontGlyphForSize(font, font_size, codepoint, width, height, advance_x, offset); } // FIXME: we automatically set glyph.Colored=true by default. // If you need to alter this, you can write 'font->Glyphs.back()->Colored' after calling AddCustomRectFontGlyph(). -ImFontAtlasRectId ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset) +ImFontAtlasRectId ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont *font, float font_size, ImWchar codepoint, + int width, int height, float advance_x, + const ImVec2 &offset) { #ifdef IMGUI_USE_WCHAR32 IM_ASSERT(codepoint <= IM_UNICODE_CODEPOINT_MAX); @@ -3284,12 +3729,12 @@ ImFontAtlasRectId ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float IM_ASSERT(width > 0 && width <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF); - ImFontBaked* baked = font->GetFontBaked(font_size); + ImFontBaked *baked = font->GetFontBaked(font_size); ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height); if (r_id == ImFontAtlasRectId_Invalid) return ImFontAtlasRectId_Invalid; - ImTextureRect* r = ImFontAtlasPackGetRect(this, r_id); + ImTextureRect *r = ImFontAtlasPackGetRect(this, r_id); if (RendererHasTextures) ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h); @@ -3311,12 +3756,13 @@ ImFontAtlasRectId ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float } #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -bool ImFontAtlas::GetCustomRect(ImFontAtlasRectId id, ImFontAtlasRect* out_r) const +bool ImFontAtlas::GetCustomRect(ImFontAtlasRectId id, ImFontAtlasRect *out_r) const { - ImTextureRect* r = ImFontAtlasPackGetRectSafe((ImFontAtlas*)this, id); + ImTextureRect *r = ImFontAtlasPackGetRectSafe((ImFontAtlas *)this, id); if (r == NULL) return false; - IM_ASSERT(TexData->Width > 0 && TexData->Height > 0); // Font atlas needs to be built before we can calculate UV coordinates + IM_ASSERT(TexData->Width > 0 && + TexData->Height > 0); // Font atlas needs to be built before we can calculate UV coordinates if (out_r == NULL) return true; out_r->x = r->x; @@ -3328,28 +3774,29 @@ bool ImFontAtlas::GetCustomRect(ImFontAtlasRectId id, ImFontAtlasRect* out_r) co return true; } -bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]) +bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas *atlas, ImGuiMouseCursor cursor_type, ImVec2 *out_offset, + ImVec2 *out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]) { if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_COUNT) return false; if (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) return false; - ImTextureRect* r = ImFontAtlasPackGetRect(atlas, atlas->Builder->PackIdMouseCursors); + ImTextureRect *r = ImFontAtlasPackGetRect(atlas, atlas->Builder->PackIdMouseCursors); ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r->x, (float)r->y); ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1]; *out_size = size; *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2]; - out_uv_border[0] = (pos) * atlas->TexUvScale; + out_uv_border[0] = (pos)*atlas->TexUvScale; out_uv_border[1] = (pos + size) * atlas->TexUvScale; pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; - out_uv_fill[0] = (pos) * atlas->TexUvScale; + out_uv_fill[0] = (pos)*atlas->TexUvScale; out_uv_fill[1] = (pos + size) * atlas->TexUvScale; return true; } // When atlas->RendererHasTextures = true, this is only called if no font were loaded. -void ImFontAtlasBuildMain(ImFontAtlas* atlas) +void ImFontAtlasBuildMain(ImFontAtlas *atlas) { IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!"); if (atlas->TexData && atlas->TexData->Format != atlas->TexDesiredFormat) @@ -3373,7 +3820,8 @@ void ImFontAtlasBuildMain(ImFontAtlas* atlas) atlas->TexIsBuilt = true; } -void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, ImFontBaked* baked, int* out_oversample_h, int* out_oversample_v) +void ImFontAtlasBuildGetOversampleFactors(ImFontConfig *src, ImFontBaked *baked, int *out_oversample_h, + int *out_oversample_v) { // Automatically disable horizontal oversampling over size 36 const float raster_size = baked->Size * baked->RasterizerDensity * src->RasterizerDensity; @@ -3383,13 +3831,13 @@ void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, ImFontBaked* baked, // Setup main font loader for the atlas // Every font source (ImFontConfig) will use this unless ImFontConfig::FontLoader specify a custom loader. -void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* font_loader) +void ImFontAtlasBuildSetupFontLoader(ImFontAtlas *atlas, const ImFontLoader *font_loader) { if (atlas->FontLoader == font_loader) return; IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!"); - for (ImFont* font : atlas->Fonts) + for (ImFont *font : atlas->Fonts) ImFontAtlasFontDestroyOutput(atlas, font); if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderShutdown) atlas->FontLoader->LoaderShutdown(atlas); @@ -3400,25 +3848,25 @@ void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* fon if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderInit) atlas->FontLoader->LoaderInit(atlas); - for (ImFont* font : atlas->Fonts) + for (ImFont *font : atlas->Fonts) ImFontAtlasFontInitOutput(atlas, font); } // Preload all glyph ranges for legacy backends. // This may lead to multiple texture creation which might be a little slower than before. -void ImFontAtlasBuildLegacyPreloadAllGlyphRanges(ImFontAtlas* atlas) +void ImFontAtlasBuildLegacyPreloadAllGlyphRanges(ImFontAtlas *atlas) { atlas->Builder->PreloadedAllGlyphsRanges = true; - for (ImFont* font : atlas->Fonts) + for (ImFont *font : atlas->Fonts) { - ImFontBaked* baked = font->GetFontBaked(font->LegacySize); + ImFontBaked *baked = font->GetFontBaked(font->LegacySize); if (font->FallbackChar != 0) baked->FindGlyph(font->FallbackChar); if (font->EllipsisChar != 0) baked->FindGlyph(font->EllipsisChar); - for (ImFontConfig* src : font->Sources) + for (ImFontConfig *src : font->Sources) { - const ImWchar* ranges = src->GlyphRanges ? src->GlyphRanges : atlas->GetGlyphRangesDefault(); + const ImWchar *ranges = src->GlyphRanges ? src->GlyphRanges : atlas->GetGlyphRangesDefault(); for (; ranges[0]; ranges += 2) for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560 baked->FindGlyph((ImWchar)c); @@ -3427,34 +3875,33 @@ void ImFontAtlasBuildLegacyPreloadAllGlyphRanges(ImFontAtlas* atlas) } // FIXME: May make ImFont::Sources a ImSpan<> and move ownership to ImFontAtlas -void ImFontAtlasBuildUpdatePointers(ImFontAtlas* atlas) +void ImFontAtlasBuildUpdatePointers(ImFontAtlas *atlas) { - for (ImFont* font : atlas->Fonts) + for (ImFont *font : atlas->Fonts) font->Sources.resize(0); - for (ImFontConfig& src : atlas->Sources) + for (ImFontConfig &src : atlas->Sources) src.DstFont->Sources.push_back(&src); } // Render a white-colored bitmap encoded in a string -void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char) +void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas *atlas, int x, int y, int w, int h, const char *in_str, + char in_marker_char) { - ImTextureData* tex = atlas->TexData; + ImTextureData *tex = atlas->TexData; IM_ASSERT(x >= 0 && x + w <= tex->Width); IM_ASSERT(y >= 0 && y + h <= tex->Height); switch (tex->Format) { - case ImTextureFormat_Alpha8: - { - ImU8* out_p = tex->GetPixelsAt(x, y); + case ImTextureFormat_Alpha8: { + ImU8 *out_p = tex->GetPixelsAt(x, y); for (int off_y = 0; off_y < h; off_y++, out_p += tex->Width, in_str += w) for (int off_x = 0; off_x < w; off_x++) out_p[off_x] = (in_str[off_x] == in_marker_char) ? 0xFF : 0x00; break; } - case ImTextureFormat_RGBA32: - { - ImU32* out_p = (ImU32*)(void*)tex->GetPixelsAt(x, y); + case ImTextureFormat_RGBA32: { + ImU32 *out_p = (ImU32 *)(void *)tex->GetPixelsAt(x, y); for (int off_y = 0; off_y < h; off_y++, out_p += tex->Width, in_str += w) for (int off_x = 0; off_x < w; off_x++) out_p[off_x] = (in_str[off_x] == in_marker_char) ? IM_COL32_WHITE : IM_COL32_BLACK_TRANS; @@ -3463,12 +3910,14 @@ void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas* atlas, int x, int y, in } } -static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas) +static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas *atlas) { // Pack and store identifier so we can refresh UV coordinates on texture resize. // FIXME-NEWATLAS: User/custom rects where user code wants to store UV coordinates will need to do the same thing. - ImFontAtlasBuilder* builder = atlas->Builder; - ImVec2i pack_size = (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) ? ImVec2i(2, 2) : ImVec2i(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H); + ImFontAtlasBuilder *builder = atlas->Builder; + ImVec2i pack_size = (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) + ? ImVec2i(2, 2) + : ImVec2i(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H); ImFontAtlasRect r; bool add_and_draw = (atlas->GetCustomRect(builder->PackIdMouseCursors, &r) == false); @@ -3481,15 +3930,22 @@ static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas) if (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) { // 2x2 white pixels - ImFontAtlasBuildRenderBitmapFromString(atlas, r.x, r.y, 2, 2, "XX" "XX", 'X'); + ImFontAtlasBuildRenderBitmapFromString(atlas, r.x, r.y, 2, 2, + "XX" + "XX", + 'X'); } else { // 2x2 white pixels + mouse cursors const int x_for_white = r.x; const int x_for_black = r.x + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; - ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_white, r.y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.'); - ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_black, r.y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X'); + ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_white, r.y, FONT_ATLAS_DEFAULT_TEX_DATA_W, + FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, + '.'); + ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_black, r.y, FONT_ATLAS_DEFAULT_TEX_DATA_W, + FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, + 'X'); } } @@ -3497,14 +3953,14 @@ static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas) atlas->TexUvWhitePixel = ImVec2((r.x + 0.5f) * atlas->TexUvScale.x, (r.y + 0.5f) * atlas->TexUvScale.y); } -static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas) +static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas *atlas) { if (atlas->Flags & ImFontAtlasFlags_NoBakedLines) return; // Pack and store identifier so we can refresh UV coordinates on texture resize. - ImTextureData* tex = atlas->TexData; - ImFontAtlasBuilder* builder = atlas->Builder; + ImTextureData *tex = atlas->TexData; + ImFontAtlasBuilder *builder = atlas->Builder; ImFontAtlasRect r; bool add_and_draw = atlas->GetCustomRect(builder->PackIdLinesTexData, &r) == false; @@ -3516,8 +3972,9 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas) } // Register texture region for thick lines - // The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width row - // This generates a triangular shape in the texture, with the various line widths stacked on top of each other to allow interpolation between them + // The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width + // row This generates a triangular shape in the texture, with the various line widths stacked on top of each other + // to allow interpolation between them for (int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row { // Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle @@ -3525,12 +3982,13 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas) const int line_width = n; const int pad_left = (r.w - line_width) / 2; const int pad_right = r.w - (pad_left + line_width); - IM_ASSERT(pad_left + line_width + pad_right == r.w && y < r.h); // Make sure we're inside the texture bounds before we start writing pixels + IM_ASSERT(pad_left + line_width + pad_right == r.w && + y < r.h); // Make sure we're inside the texture bounds before we start writing pixels // Write each slice if (add_and_draw && tex->Format == ImTextureFormat_Alpha8) { - ImU8* write_ptr = (ImU8*)tex->GetPixelsAt(r.x, r.y + y); + ImU8 *write_ptr = (ImU8 *)tex->GetPixelsAt(r.x, r.y + y); for (int i = 0; i < pad_left; i++) *(write_ptr + i) = 0x00; @@ -3542,7 +4000,7 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas) } else if (add_and_draw && tex->Format == ImTextureFormat_RGBA32) { - ImU32* write_ptr = (ImU32*)(void*)tex->GetPixelsAt(r.x, r.y + y); + ImU32 *write_ptr = (ImU32 *)(void *)tex->GetPixelsAt(r.x, r.y + y); for (int i = 0; i < pad_left; i++) *(write_ptr + i) = IM_COL32(255, 255, 255, 0); @@ -3556,34 +4014,37 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas) // Refresh UV coordinates ImVec2 uv0 = ImVec2((float)(r.x + pad_left - 1), (float)(r.y + y)) * atlas->TexUvScale; ImVec2 uv1 = ImVec2((float)(r.x + pad_left + line_width + 1), (float)(r.y + y + 1)) * atlas->TexUvScale; - float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts + float half_v = + (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts atlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v); } } //----------------------------------------------------------------------------------------------------------------------------- -// Was tempted to lazily init FontSrc but wouldn't save much + makes it more complicated to detect invalid data at AddFont() -bool ImFontAtlasFontInitOutput(ImFontAtlas* atlas, ImFont* font) +// Was tempted to lazily init FontSrc but wouldn't save much + makes it more complicated to detect invalid data at +// AddFont() +bool ImFontAtlasFontInitOutput(ImFontAtlas *atlas, ImFont *font) { bool ret = true; - for (ImFontConfig* src : font->Sources) + for (ImFontConfig *src : font->Sources) { - const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + const ImFontLoader *loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (loader && loader->FontSrcInit != NULL && !loader->FontSrcInit(atlas, src)) ret = false; } - IM_ASSERT(ret); // Unclear how to react to this meaningfully. Assume that result will be same as initial AddFont() call. + IM_ASSERT( + ret); // Unclear how to react to this meaningfully. Assume that result will be same as initial AddFont() call. return ret; } // Keep source/input FontData -void ImFontAtlasFontDestroyOutput(ImFontAtlas* atlas, ImFont* font) +void ImFontAtlasFontDestroyOutput(ImFontAtlas *atlas, ImFont *font) { font->ClearOutputData(); - for (ImFontConfig* src : font->Sources) + for (ImFontConfig *src : font->Sources) { - const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + const ImFontLoader *loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (loader && loader->FontSrcDestroy != NULL) loader->FontSrcDestroy(atlas, src); } @@ -3591,20 +4052,20 @@ void ImFontAtlasFontDestroyOutput(ImFontAtlas* atlas, ImFont* font) //----------------------------------------------------------------------------------------------------------------------------- -bool ImFontAtlasFontSourceInit(ImFontAtlas* atlas, ImFontConfig* src) +bool ImFontAtlasFontSourceInit(ImFontAtlas *atlas, ImFontConfig *src) { - const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + const ImFontLoader *loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (loader->FontSrcInit != NULL && !loader->FontSrcInit(atlas, src)) return false; return true; } -void ImFontAtlasFontSourceAddToFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src) +void ImFontAtlasFontSourceAddToFont(ImFontAtlas *atlas, ImFont *font, ImFontConfig *src) { if (src->MergeMode == false) { font->ClearOutputData(); - //font->FontSize = src->SizePixels; + // font->FontSize = src->SizePixels; font->ContainerAtlas = atlas; IM_ASSERT(font->Sources[0] == src); } @@ -3612,42 +4073,46 @@ void ImFontAtlasFontSourceAddToFont(ImFontAtlas* atlas, ImFont* font, ImFontConf ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, font, src); } -void ImFontAtlasFontDestroySourceData(ImFontAtlas* atlas, ImFontConfig* src) +void ImFontAtlasFontDestroySourceData(ImFontAtlas *atlas, ImFontConfig *src) { IM_UNUSED(atlas); if (src->FontDataOwnedByAtlas) IM_FREE(src->FontData); src->FontData = NULL; if (src->GlyphExcludeRanges) - IM_FREE((void*)src->GlyphExcludeRanges); + IM_FREE((void *)src->GlyphExcludeRanges); src->GlyphExcludeRanges = NULL; } // Create a compact, baked "..." if it doesn't exist, by using the ".". -// This may seem overly complicated right now but the point is to exercise and improve a technique which should be increasingly used. -// FIXME-NEWATLAS: This borrows too much from FontLoader's FontLoadGlyph() handlers and suggest that we should add further helpers. -static ImFontGlyph* ImFontAtlasBuildSetupFontBakedEllipsis(ImFontAtlas* atlas, ImFontBaked* baked) +// This may seem overly complicated right now but the point is to exercise and improve a technique which should be +// increasingly used. +// FIXME-NEWATLAS: This borrows too much from FontLoader's FontLoadGlyph() handlers and suggest that we should add +// further helpers. +static ImFontGlyph *ImFontAtlasBuildSetupFontBakedEllipsis(ImFontAtlas *atlas, ImFontBaked *baked) { - ImFont* font = baked->ContainerFont; + ImFont *font = baked->ContainerFont; IM_ASSERT(font->EllipsisChar != 0); - const ImFontGlyph* dot_glyph = baked->FindGlyphNoFallback((ImWchar)'.'); + const ImFontGlyph *dot_glyph = baked->FindGlyphNoFallback((ImWchar)'.'); if (dot_glyph == NULL) dot_glyph = baked->FindGlyphNoFallback((ImWchar)0xFF0E); if (dot_glyph == NULL) return NULL; ImFontAtlasRectId dot_r_id = dot_glyph->PackId; // Deep copy to avoid invalidation of glyphs and rect pointers - ImTextureRect* dot_r = ImFontAtlasPackGetRect(atlas, dot_r_id); + ImTextureRect *dot_r = ImFontAtlasPackGetRect(atlas, dot_r_id); const int dot_spacing = 1; const float dot_step = (dot_glyph->X1 - dot_glyph->X0) + dot_spacing; ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, (dot_r->w * 3 + dot_spacing * 2), dot_r->h); - ImTextureRect* r = ImFontAtlasPackGetRect(atlas, pack_id); + ImTextureRect *r = ImFontAtlasPackGetRect(atlas, pack_id); ImFontGlyph glyph_in = {}; - ImFontGlyph* glyph = &glyph_in; + ImFontGlyph *glyph = &glyph_in; glyph->Codepoint = font->EllipsisChar; - glyph->AdvanceX = ImMax(dot_glyph->AdvanceX, dot_glyph->X0 + dot_step * 3.0f - dot_spacing); // FIXME: Slightly odd for normally mono-space fonts but since this is used for trailing contents. + glyph->AdvanceX = ImMax(dot_glyph->AdvanceX, dot_glyph->X0 + dot_step * 3.0f - + dot_spacing); // FIXME: Slightly odd for normally mono-space fonts + // but since this is used for trailing contents. glyph->X0 = dot_glyph->X0; glyph->Y0 = dot_glyph->Y0; glyph->X1 = dot_glyph->X0 + dot_step * 3 - dot_spacing; @@ -3660,9 +4125,10 @@ static ImFontGlyph* ImFontAtlasBuildSetupFontBakedEllipsis(ImFontAtlas* atlas, I // Copy to texture, post-process and queue update for backend // FIXME-NEWATLAS-V2: Dot glyph is already post-processed as this point, so this would damage it. dot_r = ImFontAtlasPackGetRect(atlas, dot_r_id); - ImTextureData* tex = atlas->TexData; + ImTextureData *tex = atlas->TexData; for (int n = 0; n < 3; n++) - ImFontAtlasTextureBlockCopy(tex, dot_r->x, dot_r->y, tex, r->x + (dot_r->w + dot_spacing) * n, r->y, dot_r->w, dot_r->h); + ImFontAtlasTextureBlockCopy(tex, dot_r->x, dot_r->y, tex, r->x + (dot_r->w + dot_spacing) * n, r->y, dot_r->w, + dot_r->h); ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); return glyph; @@ -3670,35 +4136,38 @@ static ImFontGlyph* ImFontAtlasBuildSetupFontBakedEllipsis(ImFontAtlas* atlas, I // Load fallback in order to obtain its index // (this is called from in hot-path so we avoid extraneous parameters to minimize impact on code size) -static void ImFontAtlasBuildSetupFontBakedFallback(ImFontBaked* baked) +static void ImFontAtlasBuildSetupFontBakedFallback(ImFontBaked *baked) { IM_ASSERT(baked->FallbackGlyphIndex == -1); IM_ASSERT(baked->FallbackAdvanceX == 0.0f); - ImFont* font = baked->ContainerFont; - ImFontGlyph* fallback_glyph = NULL; + ImFont *font = baked->ContainerFont; + ImFontGlyph *fallback_glyph = NULL; if (font->FallbackChar != 0) fallback_glyph = baked->FindGlyphNoFallback(font->FallbackChar); if (fallback_glyph == NULL) { - ImFontGlyph* space_glyph = baked->FindGlyphNoFallback((ImWchar)' '); + ImFontGlyph *space_glyph = baked->FindGlyphNoFallback((ImWchar)' '); ImFontGlyph glyph; glyph.Codepoint = 0; glyph.AdvanceX = space_glyph ? space_glyph->AdvanceX : IM_ROUND(baked->Size * 0.40f); fallback_glyph = ImFontAtlasBakedAddFontGlyph(font->ContainerAtlas, baked, NULL, &glyph); } - baked->FallbackGlyphIndex = baked->Glyphs.index_from_ptr(fallback_glyph); // Storing index avoid need to update pointer on growth and simplify inner loop code + baked->FallbackGlyphIndex = baked->Glyphs.index_from_ptr( + fallback_glyph); // Storing index avoid need to update pointer on growth and simplify inner loop code baked->FallbackAdvanceX = fallback_glyph->AdvanceX; } -static void ImFontAtlasBuildSetupFontBakedBlanks(ImFontAtlas* atlas, ImFontBaked* baked) +static void ImFontAtlasBuildSetupFontBakedBlanks(ImFontAtlas *atlas, ImFontBaked *baked) { - // Mark space as always hidden (not strictly correct/necessary. but some e.g. icons fonts don't have a space. it tends to look neater in previews) - ImFontGlyph* space_glyph = baked->FindGlyphNoFallback((ImWchar)' '); + // Mark space as always hidden (not strictly correct/necessary. but some e.g. icons fonts don't have a space. it + // tends to look neater in previews) + ImFontGlyph *space_glyph = baked->FindGlyphNoFallback((ImWchar)' '); if (space_glyph != NULL) space_glyph->Visible = false; // Setup Tab character. - // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?) + // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string + // starts at "column 0" ?) if (baked->FindGlyphNoFallback('\t') == NULL && space_glyph != NULL) { ImFontGlyph tab_glyph; @@ -3710,13 +4179,14 @@ static void ImFontAtlasBuildSetupFontBakedBlanks(ImFontAtlas* atlas, ImFontBaked // Load/identify special glyphs // (note that this is called again for fonts with MergeMode) -void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src) +void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas *atlas, ImFont *font, ImFontConfig *src) { IM_UNUSED(atlas); IM_ASSERT(font->Sources.contains(src)); // Find Fallback character. Actual glyph loaded in GetFontBaked(). - const ImWchar fallback_chars[] = { font->FallbackChar, (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' }; + const ImWchar fallback_chars[] = {font->FallbackChar, (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', + (ImWchar)' '}; if (font->FallbackChar == 0) for (ImWchar candidate_char : fallback_chars) if (candidate_char != 0 && font->IsGlyphInFont(candidate_char)) @@ -3727,8 +4197,9 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, Im // Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis). // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character. - // FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots. - const ImWchar ellipsis_chars[] = { src->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085 }; + // FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three + // individual dots. + const ImWchar ellipsis_chars[] = {src->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085}; if (font->EllipsisChar == 0) for (ImWchar candidate_char : ellipsis_chars) if (candidate_char != 0 && font->IsGlyphInFont(candidate_char)) @@ -3743,7 +4214,7 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, Im } } -void ImFontAtlasBakedDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph) +void ImFontAtlasBakedDiscardFontGlyph(ImFontAtlas *atlas, ImFont *font, ImFontBaked *baked, ImFontGlyph *glyph) { if (glyph->PackId != ImFontAtlasRectId_Invalid) { @@ -3758,10 +4229,11 @@ void ImFontAtlasBakedDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBa baked->IndexAdvanceX[c] = baked->FallbackAdvanceX; } -ImFontBaked* ImFontAtlasBakedAdd(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density, ImGuiID baked_id) +ImFontBaked *ImFontAtlasBakedAdd(ImFontAtlas *atlas, ImFont *font, float font_size, float font_rasterizer_density, + ImGuiID baked_id) { IMGUI_DEBUG_LOG_FONT("[font] Created baked %.2fpx\n", font_size); - ImFontBaked* baked = atlas->Builder->BakedPool.push_back(ImFontBaked()); + ImFontBaked *baked = atlas->Builder->BakedPool.push_back(ImFontBaked()); baked->Size = font_size; baked->RasterizerDensity = font_rasterizer_density; baked->BakedId = baked_id; @@ -3770,16 +4242,16 @@ ImFontBaked* ImFontAtlasBakedAdd(ImFontAtlas* atlas, ImFont* font, float font_si // Initialize backend data size_t loader_data_size = 0; - for (ImFontConfig* src : font->Sources) // Cannot easily be cached as we allow changing backend + for (ImFontConfig *src : font->Sources) // Cannot easily be cached as we allow changing backend { - const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + const ImFontLoader *loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; loader_data_size += loader->FontBakedSrcLoaderDataSize; } baked->FontLoaderDatas = (loader_data_size > 0) ? IM_ALLOC(loader_data_size) : NULL; - char* loader_data_p = (char*)baked->FontLoaderDatas; - for (ImFontConfig* src : font->Sources) + char *loader_data_p = (char *)baked->FontLoaderDatas; + for (ImFontConfig *src : font->Sources) { - const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + const ImFontLoader *loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (loader->FontBakedInit) loader->FontBakedInit(atlas, src, baked, loader_data_p); loader_data_p += loader->FontBakedSrcLoaderDataSize; @@ -3789,17 +4261,19 @@ ImFontBaked* ImFontAtlasBakedAdd(ImFontAtlas* atlas, ImFont* font, float font_si return baked; } -// FIXME-OPT: This is not a fast query. Adding a BakedCount field in Font might allow to take a shortcut for the most common case. -ImFontBaked* ImFontAtlasBakedGetClosestMatch(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density) +// FIXME-OPT: This is not a fast query. Adding a BakedCount field in Font might allow to take a shortcut for the most +// common case. +ImFontBaked *ImFontAtlasBakedGetClosestMatch(ImFontAtlas *atlas, ImFont *font, float font_size, + float font_rasterizer_density) { - ImFontAtlasBuilder* builder = atlas->Builder; + ImFontAtlasBuilder *builder = atlas->Builder; for (int step_n = 0; step_n < 2; step_n++) { - ImFontBaked* closest_larger_match = NULL; - ImFontBaked* closest_smaller_match = NULL; + ImFontBaked *closest_larger_match = NULL; + ImFontBaked *closest_smaller_match = NULL; for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) { - ImFontBaked* baked = &builder->BakedPool[baked_n]; + ImFontBaked *baked = &builder->BakedPool[baked_n]; if (baked->ContainerFont != font || baked->WantDestroy) continue; if (step_n == 0 && baked->RasterizerDensity != font_rasterizer_density) // First try with same density @@ -3810,7 +4284,8 @@ ImFontBaked* ImFontAtlasBakedGetClosestMatch(ImFontAtlas* atlas, ImFont* font, f closest_smaller_match = baked; } if (closest_larger_match) - if (closest_smaller_match == NULL || (closest_larger_match->Size >= font_size * 2.0f && closest_smaller_match->Size > font_size * 0.5f)) + if (closest_smaller_match == NULL || + (closest_larger_match->Size >= font_size * 2.0f && closest_smaller_match->Size > font_size * 0.5f)) return closest_larger_match; if (closest_smaller_match) return closest_smaller_match; @@ -3818,19 +4293,19 @@ ImFontBaked* ImFontAtlasBakedGetClosestMatch(ImFontAtlas* atlas, ImFont* font, f return NULL; } -void ImFontAtlasBakedDiscard(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked) +void ImFontAtlasBakedDiscard(ImFontAtlas *atlas, ImFont *font, ImFontBaked *baked) { - ImFontAtlasBuilder* builder = atlas->Builder; + ImFontAtlasBuilder *builder = atlas->Builder; IMGUI_DEBUG_LOG_FONT("[font] Discard baked %.2f for \"%s\"\n", baked->Size, font->GetDebugName()); - for (ImFontGlyph& glyph : baked->Glyphs) + for (ImFontGlyph &glyph : baked->Glyphs) if (glyph.PackId != ImFontAtlasRectId_Invalid) ImFontAtlasPackDiscardRect(atlas, glyph.PackId); - char* loader_data_p = (char*)baked->FontLoaderDatas; - for (ImFontConfig* src : font->Sources) + char *loader_data_p = (char *)baked->FontLoaderDatas; + for (ImFontConfig *src : font->Sources) { - const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + const ImFontLoader *loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (loader->FontBakedDestroy) loader->FontBakedDestroy(atlas, src, baked, loader_data_p); loader_data_p += loader->FontBakedSrcLoaderDataSize; @@ -3848,12 +4323,12 @@ void ImFontAtlasBakedDiscard(ImFontAtlas* atlas, ImFont* font, ImFontBaked* bake } // use unused_frames==0 to discard everything. -void ImFontAtlasFontDiscardBakes(ImFontAtlas* atlas, ImFont* font, int unused_frames) +void ImFontAtlasFontDiscardBakes(ImFontAtlas *atlas, ImFont *font, int unused_frames) { - if (ImFontAtlasBuilder* builder = atlas->Builder) // This can be called from font destructor + if (ImFontAtlasBuilder *builder = atlas->Builder) // This can be called from font destructor for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) { - ImFontBaked* baked = &builder->BakedPool[baked_n]; + ImFontBaked *baked = &builder->BakedPool[baked_n]; if (baked->LastUsedFrame + unused_frames > atlas->Builder->FrameCount) continue; if (baked->ContainerFont != font || baked->WantDestroy) @@ -3863,12 +4338,12 @@ void ImFontAtlasFontDiscardBakes(ImFontAtlas* atlas, ImFont* font, int unused_fr } // use unused_frames==0 to discard everything. -void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames) +void ImFontAtlasBuildDiscardBakes(ImFontAtlas *atlas, int unused_frames) { - ImFontAtlasBuilder* builder = atlas->Builder; + ImFontAtlasBuilder *builder = atlas->Builder; for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) { - ImFontBaked* baked = &builder->BakedPool[baked_n]; + ImFontBaked *baked = &builder->BakedPool[baked_n]; if (baked->LastUsedFrame + unused_frames > atlas->Builder->FrameCount) continue; if (baked->WantDestroy || (baked->ContainerFont->Flags & ImFontFlags_LockBakedSizes)) @@ -3877,24 +4352,25 @@ void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames) } } -// Those functions are designed to facilitate changing the underlying structures for ImFontAtlas to store an array of ImDrawListSharedData* -void ImFontAtlasAddDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data) +// Those functions are designed to facilitate changing the underlying structures for ImFontAtlas to store an array of +// ImDrawListSharedData* +void ImFontAtlasAddDrawListSharedData(ImFontAtlas *atlas, ImDrawListSharedData *data) { IM_ASSERT(!atlas->DrawListSharedDatas.contains(data)); atlas->DrawListSharedDatas.push_back(data); } -void ImFontAtlasRemoveDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data) +void ImFontAtlasRemoveDrawListSharedData(ImFontAtlas *atlas, ImDrawListSharedData *data) { IM_ASSERT(atlas->DrawListSharedDatas.contains(data)); atlas->DrawListSharedDatas.find_erase(data); } // Update texture identifier in all active draw lists -void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex, ImTextureRef new_tex) +void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas *atlas, ImTextureRef old_tex, ImTextureRef new_tex) { - for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas) - for (ImDrawList* draw_list : shared_data->DrawLists) + for (ImDrawListSharedData *shared_data : atlas->DrawListSharedDatas) + for (ImDrawList *draw_list : shared_data->DrawLists) { // Replace in command-buffer // (there is not need to replace in ImDrawListSplitter: current channel is in ImDrawList's CmdBuffer[], @@ -3903,7 +4379,7 @@ void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex draw_list->_SetTexture(new_tex); // Replace in stack - for (ImTextureRef& stacked_tex : draw_list->_TextureStack) + for (ImTextureRef &stacked_tex : draw_list->_TextureStack) if (stacked_tex == old_tex) stacked_tex = new_tex; } @@ -3911,9 +4387,9 @@ void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex // Update texture coordinates in all draw list shared context // FIXME-NEWATLAS FIXME-OPT: Doesn't seem necessary to update for all, only one bound to current context? -void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas* atlas) +void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas *atlas) { - for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas) + for (ImDrawListSharedData *shared_data : atlas->DrawListSharedDatas) { shared_data->TexUvWhitePixel = atlas->TexUvWhitePixel; shared_data->TexUvLines = atlas->TexUvLines; @@ -3921,21 +4397,22 @@ void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas* atlas) } // Set current texture. This is mostly called from AddTexture() + to handle a failed resize. -static void ImFontAtlasBuildSetTexture(ImFontAtlas* atlas, ImTextureData* tex) +static void ImFontAtlasBuildSetTexture(ImFontAtlas *atlas, ImTextureData *tex) { ImTextureRef old_tex_ref = atlas->TexRef; atlas->TexData = tex; atlas->TexUvScale = ImVec2(1.0f / tex->Width, 1.0f / tex->Height); atlas->TexRef._TexData = tex; - //atlas->TexRef._TexID = tex->TexID; // <-- We intentionally don't do that. It would be misleading and betray promise that both fields aren't set. + // atlas->TexRef._TexID = tex->TexID; // <-- We intentionally don't do that. It would be misleading and betray + // promise that both fields aren't set. ImFontAtlasUpdateDrawListsTextures(atlas, old_tex_ref, atlas->TexRef); } // Create a new texture, discard previous one -ImTextureData* ImFontAtlasTextureAdd(ImFontAtlas* atlas, int w, int h) +ImTextureData *ImFontAtlasTextureAdd(ImFontAtlas *atlas, int w, int h) { - ImTextureData* old_tex = atlas->TexData; - ImTextureData* new_tex; + ImTextureData *old_tex = atlas->TexData; + ImTextureData *new_tex; // FIXME: Cannot reuse texture because old UV may have been used already (unless we remap UV). /*if (old_tex != NULL && old_tex->Status == ImTextureStatus_WantCreate) @@ -3958,7 +4435,8 @@ ImTextureData* ImFontAtlasTextureAdd(ImFontAtlas* atlas, int w, int h) { // Queue old as to destroy next frame old_tex->WantDestroyNextFrame = true; - IM_ASSERT(old_tex->Status == ImTextureStatus_OK || old_tex->Status == ImTextureStatus_WantCreate || old_tex->Status == ImTextureStatus_WantUpdates); + IM_ASSERT(old_tex->Status == ImTextureStatus_OK || old_tex->Status == ImTextureStatus_WantCreate || + old_tex->Status == ImTextureStatus_WantUpdates); } new_tex->Create(atlas->TexDesiredFormat, w, h); @@ -3982,19 +4460,22 @@ static void ImFontAtlasDebugWriteTexToDisk(ImTextureData* tex, const char* descr } #endif -void ImFontAtlasTextureRepack(ImFontAtlas* atlas, int w, int h) +void ImFontAtlasTextureRepack(ImFontAtlas *atlas, int w, int h) { - ImFontAtlasBuilder* builder = atlas->Builder; + ImFontAtlasBuilder *builder = atlas->Builder; builder->LockDisableResize = true; - ImTextureData* old_tex = atlas->TexData; - ImTextureData* new_tex = ImFontAtlasTextureAdd(atlas, w, h); + ImTextureData *old_tex = atlas->TexData; + ImTextureData *new_tex = ImFontAtlasTextureAdd(atlas, w, h); new_tex->UseColors = old_tex->UseColors; - IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: resize+repack %dx%d => Texture #%03d: %dx%d\n", old_tex->UniqueID, old_tex->Width, old_tex->Height, new_tex->UniqueID, new_tex->Width, new_tex->Height); - //for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) - // IMGUI_DEBUG_LOG_FONT("[font] - Baked %.2fpx, %d glyphs, want_destroy=%d\n", builder->BakedPool[baked_n].FontSize, builder->BakedPool[baked_n].Glyphs.Size, builder->BakedPool[baked_n].WantDestroy); - //IMGUI_DEBUG_LOG_FONT("[font] - Old packed rects: %d, area %d px\n", builder->RectsPackedCount, builder->RectsPackedSurface); - //ImFontAtlasDebugWriteTexToDisk(old_tex, "Before Pack"); + IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: resize+repack %dx%d => Texture #%03d: %dx%d\n", old_tex->UniqueID, + old_tex->Width, old_tex->Height, new_tex->UniqueID, new_tex->Width, new_tex->Height); + // for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) + // IMGUI_DEBUG_LOG_FONT("[font] - Baked %.2fpx, %d glyphs, want_destroy=%d\n", + // builder->BakedPool[baked_n].FontSize, builder->BakedPool[baked_n].Glyphs.Size, + // builder->BakedPool[baked_n].WantDestroy); + // IMGUI_DEBUG_LOG_FONT("[font] - Old packed rects: %d, area %d px\n", builder->RectsPackedCount, + // builder->RectsPackedSurface); ImFontAtlasDebugWriteTexToDisk(old_tex, "Before Pack"); // Repack, lose discarded rectangle, copy pixels // FIXME-NEWATLAS: This is unstable because packing order is based on RectsIndex @@ -4005,11 +4486,11 @@ void ImFontAtlasTextureRepack(ImFontAtlas* atlas, int w, int h) ImVector old_index = builder->RectsIndex; old_rects.swap(builder->Rects); - for (ImFontAtlasRectEntry& index_entry : builder->RectsIndex) + for (ImFontAtlasRectEntry &index_entry : builder->RectsIndex) { if (index_entry.IsUsed == false) continue; - ImTextureRect& old_r = old_rects[index_entry.TargetIndex]; + ImTextureRect &old_r = old_rects[index_entry.TargetIndex]; if (old_r.w == 0 && old_r.h == 0) continue; ImFontAtlasRectId new_r_id = ImFontAtlasPackAddRect(atlas, old_r.w, old_r.h, &index_entry); @@ -4026,7 +4507,7 @@ void ImFontAtlasTextureRepack(ImFontAtlas* atlas, int w, int h) return; } IM_ASSERT(ImFontAtlasRectId_GetIndex(new_r_id) == builder->RectsIndex.index_from_ptr(&index_entry)); - ImTextureRect* new_r = ImFontAtlasPackGetRect(atlas, new_r_id); + ImTextureRect *new_r = ImFontAtlasPackGetRect(atlas, new_r_id); ImFontAtlasTextureBlockCopy(old_tex, old_r.x, old_r.y, new_tex, new_r->x, new_r->y, new_r->w, new_r->h); } IM_ASSERT(old_rects.Size == builder->Rects.Size + builder->RectsDiscardedCount); @@ -4035,10 +4516,10 @@ void ImFontAtlasTextureRepack(ImFontAtlas* atlas, int w, int h) // Patch glyphs UV for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) - for (ImFontGlyph& glyph : builder->BakedPool[baked_n].Glyphs) + for (ImFontGlyph &glyph : builder->BakedPool[baked_n].Glyphs) if (glyph.PackId != ImFontAtlasRectId_Invalid) { - ImTextureRect* r = ImFontAtlasPackGetRect(atlas, glyph.PackId); + ImTextureRect *r = ImFontAtlasPackGetRect(atlas, glyph.PackId); glyph.U0 = (r->x) * atlas->TexUvScale.x; glyph.V0 = (r->y) * atlas->TexUvScale.y; glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x; @@ -4051,22 +4532,24 @@ void ImFontAtlasTextureRepack(ImFontAtlas* atlas, int w, int h) builder->LockDisableResize = false; ImFontAtlasUpdateDrawListsSharedData(atlas); - //ImFontAtlasDebugWriteTexToDisk(new_tex, "After Pack"); + // ImFontAtlasDebugWriteTexToDisk(new_tex, "After Pack"); } -void ImFontAtlasTextureGrow(ImFontAtlas* atlas, int old_tex_w, int old_tex_h) +void ImFontAtlasTextureGrow(ImFontAtlas *atlas, int old_tex_w, int old_tex_h) { - //ImFontAtlasDebugWriteTexToDisk(atlas->TexData, "Before Grow"); - ImFontAtlasBuilder* builder = atlas->Builder; + // ImFontAtlasDebugWriteTexToDisk(atlas->TexData, "Before Grow"); + ImFontAtlasBuilder *builder = atlas->Builder; if (old_tex_w == -1) old_tex_w = atlas->TexData->Width; if (old_tex_h == -1) old_tex_h = atlas->TexData->Height; // FIXME-NEWATLAS-V2: What to do when reaching limits exposed by backend? - // FIXME-NEWATLAS-V2: Does ImFontAtlasFlags_NoPowerOfTwoHeight makes sense now? Allow 'lock' and 'compact' operations? + // FIXME-NEWATLAS-V2: Does ImFontAtlasFlags_NoPowerOfTwoHeight makes sense now? Allow 'lock' and 'compact' + // operations? IM_ASSERT(ImIsPowerOfTwo(old_tex_w) && ImIsPowerOfTwo(old_tex_h)); - IM_ASSERT(ImIsPowerOfTwo(atlas->TexMinWidth) && ImIsPowerOfTwo(atlas->TexMaxWidth) && ImIsPowerOfTwo(atlas->TexMinHeight) && ImIsPowerOfTwo(atlas->TexMaxHeight)); + IM_ASSERT(ImIsPowerOfTwo(atlas->TexMinWidth) && ImIsPowerOfTwo(atlas->TexMaxWidth) && + ImIsPowerOfTwo(atlas->TexMinHeight) && ImIsPowerOfTwo(atlas->TexMaxHeight)); // Grow texture so it follows roughly a square. // - Grow height before width, as width imply more packing nodes. @@ -4086,11 +4569,11 @@ void ImFontAtlasTextureGrow(ImFontAtlas* atlas, int old_tex_w, int old_tex_h) ImFontAtlasTextureRepack(atlas, new_tex_w, new_tex_h); } -void ImFontAtlasTextureMakeSpace(ImFontAtlas* atlas) +void ImFontAtlasTextureMakeSpace(ImFontAtlas *atlas) { // Can some baked contents be ditched? - //IMGUI_DEBUG_LOG_FONT("[font] ImFontAtlasBuildMakeSpace()\n"); - ImFontAtlasBuilder* builder = atlas->Builder; + // IMGUI_DEBUG_LOG_FONT("[font] ImFontAtlasBuildMakeSpace()\n"); + ImFontAtlasBuilder *builder = atlas->Builder; ImFontAtlasBuildDiscardBakes(atlas, 2); // Currently using a heuristic for repack without growing. @@ -4100,17 +4583,18 @@ void ImFontAtlasTextureMakeSpace(ImFontAtlas* atlas) ImFontAtlasTextureRepack(atlas, atlas->TexData->Width, atlas->TexData->Height); } -ImVec2i ImFontAtlasTextureGetSizeEstimate(ImFontAtlas* atlas) +ImVec2i ImFontAtlasTextureGetSizeEstimate(ImFontAtlas *atlas) { int min_w = ImUpperPowerOfTwo(atlas->TexMinWidth); int min_h = ImUpperPowerOfTwo(atlas->TexMinHeight); if (atlas->Builder == NULL || atlas->TexData == NULL || atlas->TexData->Status == ImTextureStatus_WantDestroy) return ImVec2i(min_w, min_h); - ImFontAtlasBuilder* builder = atlas->Builder; + ImFontAtlasBuilder *builder = atlas->Builder; min_w = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.x), min_w); min_h = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.y), min_h); - const int surface_approx = builder->RectsPackedSurface - builder->RectsDiscardedSurface; // Expected surface after repack + const int surface_approx = + builder->RectsPackedSurface - builder->RectsDiscardedSurface; // Expected surface after repack const int surface_sqrt = (int)sqrtf((float)surface_approx); int new_tex_w; @@ -4135,27 +4619,27 @@ ImVec2i ImFontAtlasTextureGetSizeEstimate(ImFontAtlas* atlas) } // Clear all output. Invalidates all AddCustomRect() return values! -void ImFontAtlasBuildClear(ImFontAtlas* atlas) +void ImFontAtlasBuildClear(ImFontAtlas *atlas) { ImVec2i new_tex_size = ImFontAtlasTextureGetSizeEstimate(atlas); ImFontAtlasBuildDestroy(atlas); ImFontAtlasTextureAdd(atlas, new_tex_size.x, new_tex_size.y); ImFontAtlasBuildInit(atlas); - for (ImFontConfig& src : atlas->Sources) + for (ImFontConfig &src : atlas->Sources) ImFontAtlasFontSourceInit(atlas, &src); - for (ImFont* font : atlas->Fonts) - for (ImFontConfig* src : font->Sources) + for (ImFont *font : atlas->Fonts) + for (ImFontConfig *src : font->Sources) ImFontAtlasFontSourceAddToFont(atlas, font, src); } // You should not need to call this manually! // If you think you do, let us know and we can advise about policies auto-compact. -void ImFontAtlasTextureCompact(ImFontAtlas* atlas) +void ImFontAtlasTextureCompact(ImFontAtlas *atlas) { - ImFontAtlasBuilder* builder = atlas->Builder; + ImFontAtlasBuilder *builder = atlas->Builder; ImFontAtlasBuildDiscardBakes(atlas, 1); - ImTextureData* old_tex = atlas->TexData; + ImTextureData *old_tex = atlas->TexData; ImVec2i old_tex_size = ImVec2i(old_tex->Width, old_tex->Height); ImVec2i new_tex_size = ImFontAtlasTextureGetSizeEstimate(atlas); if (builder->RectsDiscardedCount == 0 && new_tex_size.x == old_tex_size.x && new_tex_size.y == old_tex_size.y) @@ -4165,7 +4649,7 @@ void ImFontAtlasTextureCompact(ImFontAtlas* atlas) } // Start packing over current empty texture -void ImFontAtlasBuildInit(ImFontAtlas* atlas) +void ImFontAtlasBuildInit(ImFontAtlas *atlas) { // Select Backend // - Note that we do not reassign to atlas->FontLoader, since it is likely to point to static data which @@ -4205,13 +4689,13 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) // Update UV coordinates etc. stored in bound ImDrawListSharedData instance ImFontAtlasUpdateDrawListsSharedData(atlas); - //atlas->TexIsBuilt = true; + // atlas->TexIsBuilt = true; } // Destroy builder and all cached glyphs. Do not destroy actual fonts. -void ImFontAtlasBuildDestroy(ImFontAtlas* atlas) +void ImFontAtlasBuildDestroy(ImFontAtlas *atlas) { - for (ImFont* font : atlas->Fonts) + for (ImFont *font : atlas->Fonts) ImFontAtlasFontDestroyOutput(atlas, font); if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderShutdown) { @@ -4222,27 +4706,29 @@ void ImFontAtlasBuildDestroy(ImFontAtlas* atlas) atlas->Builder = NULL; } -void ImFontAtlasPackInit(ImFontAtlas * atlas) +void ImFontAtlasPackInit(ImFontAtlas *atlas) { - ImTextureData* tex = atlas->TexData; - ImFontAtlasBuilder* builder = atlas->Builder; + ImTextureData *tex = atlas->TexData; + ImFontAtlasBuilder *builder = atlas->Builder; - // In theory we could decide to reduce the number of nodes, e.g. halve them, and waste a little texture space, but it doesn't seem worth it. + // In theory we could decide to reduce the number of nodes, e.g. halve them, and waste a little texture space, but + // it doesn't seem worth it. const int pack_node_count = tex->Width / 2; builder->PackNodes.resize(pack_node_count); IM_STATIC_ASSERT(sizeof(stbrp_context) <= sizeof(stbrp_context_opaque)); - stbrp_init_target((stbrp_context*)(void*)&builder->PackContext, tex->Width, tex->Height, builder->PackNodes.Data, builder->PackNodes.Size); + stbrp_init_target((stbrp_context *)(void *)&builder->PackContext, tex->Width, tex->Height, builder->PackNodes.Data, + builder->PackNodes.Size); builder->RectsPackedSurface = builder->RectsPackedCount = 0; builder->MaxRectSize = ImVec2i(0, 0); builder->MaxRectBounds = ImVec2i(0, 0); } // This is essentially a free-list pattern, it may be nice to wrap it into a dedicated type. -static ImFontAtlasRectId ImFontAtlasPackAllocRectEntry(ImFontAtlas* atlas, int rect_idx) +static ImFontAtlasRectId ImFontAtlasPackAllocRectEntry(ImFontAtlas *atlas, int rect_idx) { - ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; + ImFontAtlasBuilder *builder = (ImFontAtlasBuilder *)atlas->Builder; int index_idx; - ImFontAtlasRectEntry* index_entry; + ImFontAtlasRectEntry *index_entry; if (builder->RectsIndexFreeListStart < 0) { builder->RectsIndex.resize(builder->RectsIndex.Size + 1); @@ -4254,7 +4740,8 @@ static ImFontAtlasRectId ImFontAtlasPackAllocRectEntry(ImFontAtlas* atlas, int r { index_idx = builder->RectsIndexFreeListStart; index_entry = &builder->RectsIndex[index_idx]; - IM_ASSERT(index_entry->IsUsed == false && index_entry->Generation > 0); // Generation is incremented during DiscardRect + IM_ASSERT(index_entry->IsUsed == false && + index_entry->Generation > 0); // Generation is incremented during DiscardRect builder->RectsIndexFreeListStart = index_entry->TargetIndex; } index_entry->TargetIndex = rect_idx; @@ -4263,7 +4750,7 @@ static ImFontAtlasRectId ImFontAtlasPackAllocRectEntry(ImFontAtlas* atlas, int r } // Overwrite existing entry -static ImFontAtlasRectId ImFontAtlasPackReuseRectEntry(ImFontAtlas* atlas, ImFontAtlasRectEntry* index_entry) +static ImFontAtlasRectId ImFontAtlasPackReuseRectEntry(ImFontAtlas *atlas, ImFontAtlasRectEntry *index_entry) { IM_ASSERT(index_entry->IsUsed); index_entry->TargetIndex = atlas->Builder->Rects.Size - 1; @@ -4272,17 +4759,17 @@ static ImFontAtlasRectId ImFontAtlasPackReuseRectEntry(ImFontAtlas* atlas, ImFon } // This is expected to be called in batches and followed by a repack -void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id) +void ImFontAtlasPackDiscardRect(ImFontAtlas *atlas, ImFontAtlasRectId id) { IM_ASSERT(id != ImFontAtlasRectId_Invalid); - ImTextureRect* rect = ImFontAtlasPackGetRect(atlas, id); + ImTextureRect *rect = ImFontAtlasPackGetRect(atlas, id); if (rect == NULL) return; - ImFontAtlasBuilder* builder = atlas->Builder; + ImFontAtlasBuilder *builder = atlas->Builder; int index_idx = ImFontAtlasRectId_GetIndex(id); - ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx]; + ImFontAtlasRectEntry *index_entry = &builder->RectsIndex[index_idx]; IM_ASSERT(index_entry->IsUsed && index_entry->TargetIndex >= 0); index_entry->IsUsed = false; index_entry->TargetIndex = builder->RectsIndexFreeListStart; @@ -4297,25 +4784,25 @@ void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id) // Important: Calling this may recreate a new texture and therefore change atlas->TexData // FIXME-NEWFONTS: Expose other glyph padding settings for custom alteration (e.g. drop shadows). See #7962 -ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFontAtlasRectEntry* overwrite_entry) +ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas *atlas, int w, int h, ImFontAtlasRectEntry *overwrite_entry) { IM_ASSERT(w > 0 && w <= 0xFFFF); IM_ASSERT(h > 0 && h <= 0xFFFF); - ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; + ImFontAtlasBuilder *builder = (ImFontAtlasBuilder *)atlas->Builder; const int pack_padding = atlas->TexGlyphPadding; builder->MaxRectSize.x = ImMax(builder->MaxRectSize.x, w); builder->MaxRectSize.y = ImMax(builder->MaxRectSize.y, h); // Pack - ImTextureRect r = { 0, 0, (unsigned short)w, (unsigned short)h }; + ImTextureRect r = {0, 0, (unsigned short)w, (unsigned short)h}; for (int attempts_remaining = 3; attempts_remaining >= 0; attempts_remaining--) { // Try packing stbrp_rect pack_r = {}; pack_r.w = w + pack_padding; pack_r.h = h + pack_padding; - stbrp_pack_rects((stbrp_context*)(void*)&builder->PackContext, &pack_r, 1); + stbrp_pack_rects((stbrp_context *)(void *)&builder->PackContext, &pack_r, 1); r.x = (unsigned short)pack_r.x; r.y = (unsigned short)pack_r.y; if (pack_r.was_packed) @@ -4339,53 +4826,56 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon builder->Rects.push_back(r); if (overwrite_entry != NULL) - return ImFontAtlasPackReuseRectEntry(atlas, overwrite_entry); // Write into an existing entry instead of adding one (used during repack) + return ImFontAtlasPackReuseRectEntry( + atlas, overwrite_entry); // Write into an existing entry instead of adding one (used during repack) else return ImFontAtlasPackAllocRectEntry(atlas, builder->Rects.Size - 1); } // Generally for non-user facing functions: assert on invalid ID. -ImTextureRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id) +ImTextureRect *ImFontAtlasPackGetRect(ImFontAtlas *atlas, ImFontAtlasRectId id) { IM_ASSERT(id != ImFontAtlasRectId_Invalid); int index_idx = ImFontAtlasRectId_GetIndex(id); - ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; - ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx]; + ImFontAtlasBuilder *builder = (ImFontAtlasBuilder *)atlas->Builder; + ImFontAtlasRectEntry *index_entry = &builder->RectsIndex[index_idx]; IM_ASSERT(index_entry->Generation == ImFontAtlasRectId_GetGeneration(id)); IM_ASSERT(index_entry->IsUsed); return &builder->Rects[index_entry->TargetIndex]; } // For user-facing functions: return NULL on invalid ID. -// Important: return pointer is valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially invalidate previous pointers. -ImTextureRect* ImFontAtlasPackGetRectSafe(ImFontAtlas* atlas, ImFontAtlasRectId id) +// Important: return pointer is valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially +// invalidate previous pointers. +ImTextureRect *ImFontAtlasPackGetRectSafe(ImFontAtlas *atlas, ImFontAtlasRectId id) { if (id == ImFontAtlasRectId_Invalid) return NULL; int index_idx = ImFontAtlasRectId_GetIndex(id); if (atlas->Builder == NULL) ImFontAtlasBuildInit(atlas); - ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; + ImFontAtlasBuilder *builder = (ImFontAtlasBuilder *)atlas->Builder; if (index_idx >= builder->RectsIndex.Size) return NULL; - ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx]; + ImFontAtlasRectEntry *index_entry = &builder->RectsIndex[index_idx]; if (index_entry->Generation != ImFontAtlasRectId_GetGeneration(id) || !index_entry->IsUsed) return NULL; return &builder->Rects[index_entry->TargetIndex]; } // Important! This assume by ImFontConfig::GlyphExcludeRanges[] is a SMALL ARRAY (e.g. <10 entries) -// Use "Input Glyphs Overlap Detection Tool" to display a list of glyphs provided by multiple sources in order to set this array up. -static bool ImFontAtlasBuildAcceptCodepointForSource(ImFontConfig* src, ImWchar codepoint) +// Use "Input Glyphs Overlap Detection Tool" to display a list of glyphs provided by multiple sources in order to set +// this array up. +static bool ImFontAtlasBuildAcceptCodepointForSource(ImFontConfig *src, ImWchar codepoint) { - if (const ImWchar* exclude_list = src->GlyphExcludeRanges) + if (const ImWchar *exclude_list = src->GlyphExcludeRanges) for (; exclude_list[0] != 0; exclude_list += 2) if (codepoint >= exclude_list[0] && codepoint <= exclude_list[1]) return false; return true; } -static void ImFontBaked_BuildGrowIndex(ImFontBaked* baked, int new_size) +static void ImFontBaked_BuildGrowIndex(ImFontBaked *baked, int new_size) { IM_ASSERT(baked->IndexAdvanceX.Size == baked->IndexLookup.Size); if (new_size <= baked->IndexLookup.Size) @@ -4394,17 +4884,17 @@ static void ImFontBaked_BuildGrowIndex(ImFontBaked* baked, int new_size) baked->IndexLookup.resize(new_size, IM_FONTGLYPH_INDEX_UNUSED); } -static void ImFontAtlas_FontHookRemapCodepoint(ImFontAtlas* atlas, ImFont* font, ImWchar* c) +static void ImFontAtlas_FontHookRemapCodepoint(ImFontAtlas *atlas, ImFont *font, ImWchar *c) { IM_UNUSED(atlas); if (font->RemapPairs.Data.Size != 0) *c = (ImWchar)font->RemapPairs.GetInt((ImGuiID)*c, (int)*c); } -static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codepoint) +static ImFontGlyph *ImFontBaked_BuildLoadGlyph(ImFontBaked *baked, ImWchar codepoint) { - ImFont* font = baked->ContainerFont; - ImFontAtlas* atlas = font->ContainerAtlas; + ImFont *font = baked->ContainerFont; + ImFontAtlas *atlas = font->ContainerAtlas; if (atlas->Locked || (font->Flags & ImFontFlags_NoLoadGlyphs)) { // Lazily load fallback glyph @@ -4417,21 +4907,22 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep ImWchar src_codepoint = codepoint; ImFontAtlas_FontHookRemapCodepoint(atlas, font, &codepoint); - //char utf8_buf[5]; - //IMGUI_DEBUG_LOG("[font] BuildLoadGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint)); + // char utf8_buf[5]; + // IMGUI_DEBUG_LOG("[font] BuildLoadGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, + // (unsigned int)codepoint)); // Special hook // FIXME-NEWATLAS: it would be nicer if this used a more standardized way of hooking if (codepoint == font->EllipsisChar && font->EllipsisAutoBake) - if (ImFontGlyph* glyph = ImFontAtlasBuildSetupFontBakedEllipsis(atlas, baked)) + if (ImFontGlyph *glyph = ImFontAtlasBuildSetupFontBakedEllipsis(atlas, baked)) return glyph; // Call backend - char* loader_user_data_p = (char*)baked->FontLoaderDatas; + char *loader_user_data_p = (char *)baked->FontLoaderDatas; int src_n = 0; - for (ImFontConfig* src : font->Sources) + for (ImFontConfig *src : font->Sources) { - const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + const ImFontLoader *loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (!src->GlyphExcludeRanges || ImFontAtlasBuildAcceptCodepointForSource(src, codepoint)) { ImFontGlyph glyph_buf; @@ -4462,36 +4953,43 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep // The point of this indirection is to not be inlined in debug mode in order to not bloat inner loop.b IM_MSVC_RUNTIME_CHECKS_OFF -static float BuildLoadGlyphGetAdvanceOrFallback(ImFontBaked* baked, unsigned int codepoint) +static float BuildLoadGlyphGetAdvanceOrFallback(ImFontBaked *baked, unsigned int codepoint) { - ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(baked, (ImWchar)codepoint); + ImFontGlyph *glyph = ImFontBaked_BuildLoadGlyph(baked, (ImWchar)codepoint); return glyph ? glyph->AdvanceX : baked->FallbackAdvanceX; } IM_MSVC_RUNTIME_CHECKS_RESTORE #ifndef IMGUI_DISABLE_DEBUG_TOOLS -void ImFontAtlasDebugLogTextureRequests(ImFontAtlas* atlas) +void ImFontAtlasDebugLogTextureRequests(ImFontAtlas *atlas) { // [DEBUG] Log texture update requests - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; IM_UNUSED(g); - for (ImTextureData* tex : atlas->TexList) + for (ImTextureData *tex : atlas->TexList) { if ((g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) IM_ASSERT(tex->Updates.Size == 0); if (tex->Status == ImTextureStatus_WantCreate) IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: create %dx%d\n", tex->UniqueID, tex->Width, tex->Height); else if (tex->Status == ImTextureStatus_WantDestroy) - IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: destroy %dx%d, texid=0x%" IM_PRIX64 ", backend_data=%p\n", tex->UniqueID, tex->Width, tex->Height, tex->TexID, tex->BackendUserData); + IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: destroy %dx%d, texid=0x%" IM_PRIX64 ", backend_data=%p\n", + tex->UniqueID, tex->Width, tex->Height, tex->TexID, tex->BackendUserData); else if (tex->Status == ImTextureStatus_WantUpdates) { - IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: update %d regions, texid=0x%" IM_PRIX64 ", backend_data=0x%" IM_PRIX64 "\n", tex->UniqueID, tex->Updates.Size, tex->TexID, (ImU64)(intptr_t)tex->BackendUserData); - for (const ImTextureRect& r : tex->Updates) + IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: update %d regions, texid=0x%" IM_PRIX64 + ", backend_data=0x%" IM_PRIX64 "\n", + tex->UniqueID, tex->Updates.Size, tex->TexID, (ImU64)(intptr_t)tex->BackendUserData); + for (const ImTextureRect &r : tex->Updates) { IM_UNUSED(r); IM_ASSERT(r.x >= 0 && r.y >= 0); - IM_ASSERT(r.x + r.w <= tex->Width && r.y + r.h <= tex->Height); // In theory should subtract PackPadding but it's currently part of atlas and mid-frame change would wreck assert. - //IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: update (% 4d..%-4d)->(% 4d..%-4d), texid=0x%" IM_PRIX64 ", backend_data=0x%" IM_PRIX64 "\n", tex->UniqueID, r.x, r.y, r.x + r.w, r.y + r.h, tex->TexID, (ImU64)(intptr_t)tex->BackendUserData); + IM_ASSERT(r.x + r.w <= tex->Width && + r.y + r.h <= tex->Height); // In theory should subtract PackPadding but it's currently part of + // atlas and mid-frame change would wreck assert. + // IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: update (% 4d..%-4d)->(% 4d..%-4d), texid=0x%" IM_PRIX64 + // ", backend_data=0x%" IM_PRIX64 "\n", tex->UniqueID, r.x, r.y, r.x + r.w, r.y + r.h, tex->TexID, + // (ImU64)(intptr_t)tex->BackendUserData); } } } @@ -4509,29 +5007,30 @@ void ImFontAtlasDebugLogTextureRequests(ImFontAtlas* atlas) // One for each ConfigData struct ImGui_ImplStbTrueType_FontSrcData { - stbtt_fontinfo FontInfo; - float ScaleFactor; + stbtt_fontinfo FontInfo; + float ScaleFactor; }; -static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src) +static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas *atlas, ImFontConfig *src) { IM_UNUSED(atlas); - ImGui_ImplStbTrueType_FontSrcData* bd_font_data = IM_NEW(ImGui_ImplStbTrueType_FontSrcData); + ImGui_ImplStbTrueType_FontSrcData *bd_font_data = IM_NEW(ImGui_ImplStbTrueType_FontSrcData); IM_ASSERT(src->FontLoaderData == NULL); // Initialize helper structure for font loading and verify that the TTF/OTF data is correct - const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)src->FontData, src->FontNo); + const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char *)src->FontData, src->FontNo); if (font_offset < 0) { IM_DELETE(bd_font_data); IM_ASSERT_USER_ERROR(0, "stbtt_GetFontOffsetForIndex(): FontData is incorrect, or FontNo cannot be found."); return false; } - if (!stbtt_InitFont(&bd_font_data->FontInfo, (unsigned char*)src->FontData, font_offset)) + if (!stbtt_InitFont(&bd_font_data->FontInfo, (unsigned char *)src->FontData, font_offset)) { IM_DELETE(bd_font_data); - IM_ASSERT_USER_ERROR(0, "stbtt_InitFont(): failed to parse FontData. It is correct and complete? Check FontDataSize."); + IM_ASSERT_USER_ERROR( + 0, "stbtt_InitFont(): failed to parse FontData. It is correct and complete? Check FontDataSize."); return false; } src->FontLoaderData = bd_font_data; @@ -4544,35 +5043,36 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* else bd_font_data->ScaleFactor = stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, 1.0f); if (src->MergeMode && src->SizePixels != 0.0f) - bd_font_data->ScaleFactor *= src->SizePixels / src->DstFont->Sources[0]->SizePixels; // FIXME-NEWATLAS: Should tidy up that a bit + bd_font_data->ScaleFactor *= + src->SizePixels / src->DstFont->Sources[0]->SizePixels; // FIXME-NEWATLAS: Should tidy up that a bit return true; } -static void ImGui_ImplStbTrueType_FontSrcDestroy(ImFontAtlas* atlas, ImFontConfig* src) +static void ImGui_ImplStbTrueType_FontSrcDestroy(ImFontAtlas *atlas, ImFontConfig *src) { IM_UNUSED(atlas); - ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; + ImGui_ImplStbTrueType_FontSrcData *bd_font_data = (ImGui_ImplStbTrueType_FontSrcData *)src->FontLoaderData; IM_DELETE(bd_font_data); src->FontLoaderData = NULL; } -static bool ImGui_ImplStbTrueType_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint) +static bool ImGui_ImplStbTrueType_FontSrcContainsGlyph(ImFontAtlas *atlas, ImFontConfig *src, ImWchar codepoint) { IM_UNUSED(atlas); - ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; + ImGui_ImplStbTrueType_FontSrcData *bd_font_data = (ImGui_ImplStbTrueType_FontSrcData *)src->FontLoaderData; IM_ASSERT(bd_font_data != NULL); int glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint); return glyph_index != 0; } -static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*) +static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas *atlas, ImFontConfig *src, ImFontBaked *baked, void *) { IM_UNUSED(atlas); - ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; + ImGui_ImplStbTrueType_FontSrcData *bd_font_data = (ImGui_ImplStbTrueType_FontSrcData *)src->FontLoaderData; if (src->MergeMode == false) { // FIXME-NEWFONTS: reevaluate how to use sizing metrics @@ -4586,10 +5086,11 @@ static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig return true; } -static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*, ImWchar codepoint, ImFontGlyph* out_glyph) +static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas *atlas, ImFontConfig *src, ImFontBaked *baked, void *, + ImWchar codepoint, ImFontGlyph *out_glyph) { // Search for first font which has the glyph - ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; + ImGui_ImplStbTrueType_FontSrcData *bd_font_data = (ImGui_ImplStbTrueType_FontSrcData *)src->FontLoaderData; IM_ASSERT(bd_font_data); int glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint); if (glyph_index == 0) @@ -4606,7 +5107,8 @@ static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontC // Obtain size and advance int x0, y0, x1, y1; int advance, lsb; - stbtt_GetGlyphBitmapBoxSubpixel(&bd_font_data->FontInfo, glyph_index, scale_for_raster_x, scale_for_raster_y, 0, 0, &x0, &y0, &x1, &y1); + stbtt_GetGlyphBitmapBoxSubpixel(&bd_font_data->FontInfo, glyph_index, scale_for_raster_x, scale_for_raster_y, 0, 0, + &x0, &y0, &x1, &y1); stbtt_GetGlyphHMetrics(&bd_font_data->FontInfo, glyph_index, &advance, &lsb); const bool is_visible = (x0 != x1 && y0 != y1); @@ -4627,16 +5129,18 @@ static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontC IM_ASSERT(pack_id != ImFontAtlasRectId_Invalid && "Out of texture memory."); return false; } - ImTextureRect* r = ImFontAtlasPackGetRect(atlas, pack_id); + ImTextureRect *r = ImFontAtlasPackGetRect(atlas, pack_id); // Render - stbtt_GetGlyphBitmapBox(&bd_font_data->FontInfo, glyph_index, scale_for_raster_x, scale_for_raster_y, &x0, &y0, &x1, &y1); - ImFontAtlasBuilder* builder = atlas->Builder; + stbtt_GetGlyphBitmapBox(&bd_font_data->FontInfo, glyph_index, scale_for_raster_x, scale_for_raster_y, &x0, &y0, + &x1, &y1); + ImFontAtlasBuilder *builder = atlas->Builder; builder->TempBuffer.resize(w * h * 1); - unsigned char* bitmap_pixels = builder->TempBuffer.Data; + unsigned char *bitmap_pixels = builder->TempBuffer.Data; memset(bitmap_pixels, 0, w * h * 1); - stbtt_MakeGlyphBitmapSubpixel(&bd_font_data->FontInfo, bitmap_pixels, r->w - oversample_h + 1, r->h - oversample_v + 1, w, - scale_for_raster_x, scale_for_raster_y, 0, 0, glyph_index); + stbtt_MakeGlyphBitmapSubpixel(&bd_font_data->FontInfo, bitmap_pixels, r->w - oversample_h + 1, + r->h - oversample_v + 1, w, scale_for_raster_x, scale_for_raster_y, 0, 0, + glyph_index); // Oversampling // (those functions conveniently assert if pixels are not cleared, which is another safety layer) @@ -4649,7 +5153,8 @@ static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontC const float offsets_scale = (ref_size != 0.0f) ? (baked->Size / ref_size) : 1.0f; float font_off_x = (src->GlyphOffset.x * offsets_scale); float font_off_y = (src->GlyphOffset.y * offsets_scale); - if (src->PixelSnapH) // Snap scaled offset. This is to mitigate backward compatibility issues for GlyphOffset, but a better design would be welcome. + if (src->PixelSnapH) // Snap scaled offset. This is to mitigate backward compatibility issues for GlyphOffset, + // but a better design would be welcome. font_off_x = IM_ROUND(font_off_x); if (src->PixelSnapV) font_off_y = IM_ROUND(font_off_y); @@ -4673,7 +5178,7 @@ static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontC return true; } -const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype() +const ImFontLoader *ImFontAtlasGetFontLoaderForStbTruetype() { static ImFontLoader loader; loader.Name = "stb_truetype"; @@ -4704,21 +5209,20 @@ const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype() //----------------------------------------------------------------------------- // Retrieve list of range (2 int per range, values are inclusive) -const ImWchar* ImFontAtlas::GetGlyphRangesDefault() +const ImWchar *ImFontAtlas::GetGlyphRangesDefault() { - static const ImWchar ranges[] = - { - 0x0020, 0x00FF, // Basic Latin + Latin Supplement + static const ImWchar ranges[] = { + 0x0020, + 0x00FF, // Basic Latin + Latin Supplement 0, }; return &ranges[0]; } #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -const ImWchar* ImFontAtlas::GetGlyphRangesGreek() +const ImWchar *ImFontAtlas::GetGlyphRangesGreek() { - static const ImWchar ranges[] = - { + static const ImWchar ranges[] = { 0x0020, 0x00FF, // Basic Latin + Latin Supplement 0x0370, 0x03FF, // Greek and Coptic 0, @@ -4726,10 +5230,9 @@ const ImWchar* ImFontAtlas::GetGlyphRangesGreek() return &ranges[0]; } -const ImWchar* ImFontAtlas::GetGlyphRangesKorean() +const ImWchar *ImFontAtlas::GetGlyphRangesKorean() { - static const ImWchar ranges[] = - { + static const ImWchar ranges[] = { 0x0020, 0x00FF, // Basic Latin + Latin Supplement 0x3131, 0x3163, // Korean alphabets 0xAC00, 0xD7A3, // Korean characters @@ -4739,10 +5242,9 @@ const ImWchar* ImFontAtlas::GetGlyphRangesKorean() return &ranges[0]; } -const ImWchar* ImFontAtlas::GetGlyphRangesChineseFull() +const ImWchar *ImFontAtlas::GetGlyphRangesChineseFull() { - static const ImWchar ranges[] = - { + static const ImWchar ranges[] = { 0x0020, 0x00FF, // Basic Latin + Latin Supplement 0x2000, 0x206F, // General Punctuation 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana @@ -4755,7 +5257,8 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseFull() return &ranges[0]; } -static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short* accumulative_offsets, int accumulative_offsets_count, ImWchar* out_ranges) +static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short *accumulative_offsets, + int accumulative_offsets_count, ImWchar *out_ranges) { for (int n = 0; n < accumulative_offsets_count; n++, out_ranges += 2) { @@ -4765,75 +5268,143 @@ static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short* out_ranges[0] = 0; } -const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() +const ImWchar *ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() { // Store 2500 regularly used characters for Simplified Chinese. - // Sourced from https://zh.wiktionary.org/wiki/%E9%99%84%E5%BD%95:%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E5%AD%97%E8%A1%A8 + // Sourced from + // https://zh.wiktionary.org/wiki/%E9%99%84%E5%BD%95:%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E5%AD%97%E8%A1%A8 // This table covers 97.97% of all characters used during the month in July, 1987. - // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. - // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.) - static const short accumulative_offsets_from_0x4E00[] = - { - 0,1,2,4,1,1,1,1,2,1,3,2,1,2,2,1,1,1,1,1,5,2,1,2,3,3,3,2,2,4,1,1,1,2,1,5,2,3,1,2,1,2,1,1,2,1,1,2,2,1,4,1,1,1,1,5,10,1,2,19,2,1,2,1,2,1,2,1,2, - 1,5,1,6,3,2,1,2,2,1,1,1,4,8,5,1,1,4,1,1,3,1,2,1,5,1,2,1,1,1,10,1,1,5,2,4,6,1,4,2,2,2,12,2,1,1,6,1,1,1,4,1,1,4,6,5,1,4,2,2,4,10,7,1,1,4,2,4, - 2,1,4,3,6,10,12,5,7,2,14,2,9,1,1,6,7,10,4,7,13,1,5,4,8,4,1,1,2,28,5,6,1,1,5,2,5,20,2,2,9,8,11,2,9,17,1,8,6,8,27,4,6,9,20,11,27,6,68,2,2,1,1, - 1,2,1,2,2,7,6,11,3,3,1,1,3,1,2,1,1,1,1,1,3,1,1,8,3,4,1,5,7,2,1,4,4,8,4,2,1,2,1,1,4,5,6,3,6,2,12,3,1,3,9,2,4,3,4,1,5,3,3,1,3,7,1,5,1,1,1,1,2, - 3,4,5,2,3,2,6,1,1,2,1,7,1,7,3,4,5,15,2,2,1,5,3,22,19,2,1,1,1,1,2,5,1,1,1,6,1,1,12,8,2,9,18,22,4,1,1,5,1,16,1,2,7,10,15,1,1,6,2,4,1,2,4,1,6, - 1,1,3,2,4,1,6,4,5,1,2,1,1,2,1,10,3,1,3,2,1,9,3,2,5,7,2,19,4,3,6,1,1,1,1,1,4,3,2,1,1,1,2,5,3,1,1,1,2,2,1,1,2,1,1,2,1,3,1,1,1,3,7,1,4,1,1,2,1, - 1,2,1,2,4,4,3,8,1,1,1,2,1,3,5,1,3,1,3,4,6,2,2,14,4,6,6,11,9,1,15,3,1,28,5,2,5,5,3,1,3,4,5,4,6,14,3,2,3,5,21,2,7,20,10,1,2,19,2,4,28,28,2,3, - 2,1,14,4,1,26,28,42,12,40,3,52,79,5,14,17,3,2,2,11,3,4,6,3,1,8,2,23,4,5,8,10,4,2,7,3,5,1,1,6,3,1,2,2,2,5,28,1,1,7,7,20,5,3,29,3,17,26,1,8,4, - 27,3,6,11,23,5,3,4,6,13,24,16,6,5,10,25,35,7,3,2,3,3,14,3,6,2,6,1,4,2,3,8,2,1,1,3,3,3,4,1,1,13,2,2,4,5,2,1,14,14,1,2,2,1,4,5,2,3,1,14,3,12, - 3,17,2,16,5,1,2,1,8,9,3,19,4,2,2,4,17,25,21,20,28,75,1,10,29,103,4,1,2,1,1,4,2,4,1,2,3,24,2,2,2,1,1,2,1,3,8,1,1,1,2,1,1,3,1,1,1,6,1,5,3,1,1, - 1,3,4,1,1,5,2,1,5,6,13,9,16,1,1,1,1,3,2,3,2,4,5,2,5,2,2,3,7,13,7,2,2,1,1,1,1,2,3,3,2,1,6,4,9,2,1,14,2,14,2,1,18,3,4,14,4,11,41,15,23,15,23, - 176,1,3,4,1,1,1,1,5,3,1,2,3,7,3,1,1,2,1,2,4,4,6,2,4,1,9,7,1,10,5,8,16,29,1,1,2,2,3,1,3,5,2,4,5,4,1,1,2,2,3,3,7,1,6,10,1,17,1,44,4,6,2,1,1,6, - 5,4,2,10,1,6,9,2,8,1,24,1,2,13,7,8,8,2,1,4,1,3,1,3,3,5,2,5,10,9,4,9,12,2,1,6,1,10,1,1,7,7,4,10,8,3,1,13,4,3,1,6,1,3,5,2,1,2,17,16,5,2,16,6, - 1,4,2,1,3,3,6,8,5,11,11,1,3,3,2,4,6,10,9,5,7,4,7,4,7,1,1,4,2,1,3,6,8,7,1,6,11,5,5,3,24,9,4,2,7,13,5,1,8,82,16,61,1,1,1,4,2,2,16,10,3,8,1,1, - 6,4,2,1,3,1,1,1,4,3,8,4,2,2,1,1,1,1,1,6,3,5,1,1,4,6,9,2,1,1,1,2,1,7,2,1,6,1,5,4,4,3,1,8,1,3,3,1,3,2,2,2,2,3,1,6,1,2,1,2,1,3,7,1,8,2,1,2,1,5, - 2,5,3,5,10,1,2,1,1,3,2,5,11,3,9,3,5,1,1,5,9,1,2,1,5,7,9,9,8,1,3,3,3,6,8,2,3,2,1,1,32,6,1,2,15,9,3,7,13,1,3,10,13,2,14,1,13,10,2,1,3,10,4,15, - 2,15,15,10,1,3,9,6,9,32,25,26,47,7,3,2,3,1,6,3,4,3,2,8,5,4,1,9,4,2,2,19,10,6,2,3,8,1,2,2,4,2,1,9,4,4,4,6,4,8,9,2,3,1,1,1,1,3,5,5,1,3,8,4,6, - 2,1,4,12,1,5,3,7,13,2,5,8,1,6,1,2,5,14,6,1,5,2,4,8,15,5,1,23,6,62,2,10,1,1,8,1,2,2,10,4,2,2,9,2,1,1,3,2,3,1,5,3,3,2,1,3,8,1,1,1,11,3,1,1,4, - 3,7,1,14,1,2,3,12,5,2,5,1,6,7,5,7,14,11,1,3,1,8,9,12,2,1,11,8,4,4,2,6,10,9,13,1,1,3,1,5,1,3,2,4,4,1,18,2,3,14,11,4,29,4,2,7,1,3,13,9,2,2,5, - 3,5,20,7,16,8,5,72,34,6,4,22,12,12,28,45,36,9,7,39,9,191,1,1,1,4,11,8,4,9,2,3,22,1,1,1,1,4,17,1,7,7,1,11,31,10,2,4,8,2,3,2,1,4,2,16,4,32,2, - 3,19,13,4,9,1,5,2,14,8,1,1,3,6,19,6,5,1,16,6,2,10,8,5,1,2,3,1,5,5,1,11,6,6,1,3,3,2,6,3,8,1,1,4,10,7,5,7,7,5,8,9,2,1,3,4,1,1,3,1,3,3,2,6,16, - 1,4,6,3,1,10,6,1,3,15,2,9,2,10,25,13,9,16,6,2,2,10,11,4,3,9,1,2,6,6,5,4,30,40,1,10,7,12,14,33,6,3,6,7,3,1,3,1,11,14,4,9,5,12,11,49,18,51,31, - 140,31,2,2,1,5,1,8,1,10,1,4,4,3,24,1,10,1,3,6,6,16,3,4,5,2,1,4,2,57,10,6,22,2,22,3,7,22,6,10,11,36,18,16,33,36,2,5,5,1,1,1,4,10,1,4,13,2,7, - 5,2,9,3,4,1,7,43,3,7,3,9,14,7,9,1,11,1,1,3,7,4,18,13,1,14,1,3,6,10,73,2,2,30,6,1,11,18,19,13,22,3,46,42,37,89,7,3,16,34,2,2,3,9,1,7,1,1,1,2, - 2,4,10,7,3,10,3,9,5,28,9,2,6,13,7,3,1,3,10,2,7,2,11,3,6,21,54,85,2,1,4,2,2,1,39,3,21,2,2,5,1,1,1,4,1,1,3,4,15,1,3,2,4,4,2,3,8,2,20,1,8,7,13, - 4,1,26,6,2,9,34,4,21,52,10,4,4,1,5,12,2,11,1,7,2,30,12,44,2,30,1,1,3,6,16,9,17,39,82,2,2,24,7,1,7,3,16,9,14,44,2,1,2,1,2,3,5,2,4,1,6,7,5,3, - 2,6,1,11,5,11,2,1,18,19,8,1,3,24,29,2,1,3,5,2,2,1,13,6,5,1,46,11,3,5,1,1,5,8,2,10,6,12,6,3,7,11,2,4,16,13,2,5,1,1,2,2,5,2,28,5,2,23,10,8,4, - 4,22,39,95,38,8,14,9,5,1,13,5,4,3,13,12,11,1,9,1,27,37,2,5,4,4,63,211,95,2,2,2,1,3,5,2,1,1,2,2,1,1,1,3,2,4,1,2,1,1,5,2,2,1,1,2,3,1,3,1,1,1, - 3,1,4,2,1,3,6,1,1,3,7,15,5,3,2,5,3,9,11,4,2,22,1,6,3,8,7,1,4,28,4,16,3,3,25,4,4,27,27,1,4,1,2,2,7,1,3,5,2,28,8,2,14,1,8,6,16,25,3,3,3,14,3, - 3,1,1,2,1,4,6,3,8,4,1,1,1,2,3,6,10,6,2,3,18,3,2,5,5,4,3,1,5,2,5,4,23,7,6,12,6,4,17,11,9,5,1,1,10,5,12,1,1,11,26,33,7,3,6,1,17,7,1,5,12,1,11, - 2,4,1,8,14,17,23,1,2,1,7,8,16,11,9,6,5,2,6,4,16,2,8,14,1,11,8,9,1,1,1,9,25,4,11,19,7,2,15,2,12,8,52,7,5,19,2,16,4,36,8,1,16,8,24,26,4,6,2,9, - 5,4,36,3,28,12,25,15,37,27,17,12,59,38,5,32,127,1,2,9,17,14,4,1,2,1,1,8,11,50,4,14,2,19,16,4,17,5,4,5,26,12,45,2,23,45,104,30,12,8,3,10,2,2, - 3,3,1,4,20,7,2,9,6,15,2,20,1,3,16,4,11,15,6,134,2,5,59,1,2,2,2,1,9,17,3,26,137,10,211,59,1,2,4,1,4,1,1,1,2,6,2,3,1,1,2,3,2,3,1,3,4,4,2,3,3, - 1,4,3,1,7,2,2,3,1,2,1,3,3,3,2,2,3,2,1,3,14,6,1,3,2,9,6,15,27,9,34,145,1,1,2,1,1,1,1,2,1,1,1,1,2,2,2,3,1,2,1,1,1,2,3,5,8,3,5,2,4,1,3,2,2,2,12, - 4,1,1,1,10,4,5,1,20,4,16,1,15,9,5,12,2,9,2,5,4,2,26,19,7,1,26,4,30,12,15,42,1,6,8,172,1,1,4,2,1,1,11,2,2,4,2,1,2,1,10,8,1,2,1,4,5,1,2,5,1,8, - 4,1,3,4,2,1,6,2,1,3,4,1,2,1,1,1,1,12,5,7,2,4,3,1,1,1,3,3,6,1,2,2,3,3,3,2,1,2,12,14,11,6,6,4,12,2,8,1,7,10,1,35,7,4,13,15,4,3,23,21,28,52,5, - 26,5,6,1,7,10,2,7,53,3,2,1,1,1,2,163,532,1,10,11,1,3,3,4,8,2,8,6,2,2,23,22,4,2,2,4,2,1,3,1,3,3,5,9,8,2,1,2,8,1,10,2,12,21,20,15,105,2,3,1,1, - 3,2,3,1,1,2,5,1,4,15,11,19,1,1,1,1,5,4,5,1,1,2,5,3,5,12,1,2,5,1,11,1,1,15,9,1,4,5,3,26,8,2,1,3,1,1,15,19,2,12,1,2,5,2,7,2,19,2,20,6,26,7,5, - 2,2,7,34,21,13,70,2,128,1,1,2,1,1,2,1,1,3,2,2,2,15,1,4,1,3,4,42,10,6,1,49,85,8,1,2,1,1,4,4,2,3,6,1,5,7,4,3,211,4,1,2,1,2,5,1,2,4,2,2,6,5,6, - 10,3,4,48,100,6,2,16,296,5,27,387,2,2,3,7,16,8,5,38,15,39,21,9,10,3,7,59,13,27,21,47,5,21,6 - }; + // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or + // adding new characters. (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding + // is designed to helps us compact the source code size.) + static const short accumulative_offsets_from_0x4E00[] = { + 0, 1, 2, 4, 1, 1, 1, 1, 2, 1, 3, 2, 1, 2, 2, 1, 1, 1, 1, 1, 5, 2, 1, 2, + 3, 3, 3, 2, 2, 4, 1, 1, 1, 2, 1, 5, 2, 3, 1, 2, 1, 2, 1, 1, 2, 1, 1, 2, + 2, 1, 4, 1, 1, 1, 1, 5, 10, 1, 2, 19, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 5, 1, + 6, 3, 2, 1, 2, 2, 1, 1, 1, 4, 8, 5, 1, 1, 4, 1, 1, 3, 1, 2, 1, 5, 1, 2, + 1, 1, 1, 10, 1, 1, 5, 2, 4, 6, 1, 4, 2, 2, 2, 12, 2, 1, 1, 6, 1, 1, 1, 4, + 1, 1, 4, 6, 5, 1, 4, 2, 2, 4, 10, 7, 1, 1, 4, 2, 4, 2, 1, 4, 3, 6, 10, 12, + 5, 7, 2, 14, 2, 9, 1, 1, 6, 7, 10, 4, 7, 13, 1, 5, 4, 8, 4, 1, 1, 2, 28, 5, + 6, 1, 1, 5, 2, 5, 20, 2, 2, 9, 8, 11, 2, 9, 17, 1, 8, 6, 8, 27, 4, 6, 9, 20, + 11, 27, 6, 68, 2, 2, 1, 1, 1, 2, 1, 2, 2, 7, 6, 11, 3, 3, 1, 1, 3, 1, 2, 1, + 1, 1, 1, 1, 3, 1, 1, 8, 3, 4, 1, 5, 7, 2, 1, 4, 4, 8, 4, 2, 1, 2, 1, 1, + 4, 5, 6, 3, 6, 2, 12, 3, 1, 3, 9, 2, 4, 3, 4, 1, 5, 3, 3, 1, 3, 7, 1, 5, + 1, 1, 1, 1, 2, 3, 4, 5, 2, 3, 2, 6, 1, 1, 2, 1, 7, 1, 7, 3, 4, 5, 15, 2, + 2, 1, 5, 3, 22, 19, 2, 1, 1, 1, 1, 2, 5, 1, 1, 1, 6, 1, 1, 12, 8, 2, 9, 18, + 22, 4, 1, 1, 5, 1, 16, 1, 2, 7, 10, 15, 1, 1, 6, 2, 4, 1, 2, 4, 1, 6, 1, 1, + 3, 2, 4, 1, 6, 4, 5, 1, 2, 1, 1, 2, 1, 10, 3, 1, 3, 2, 1, 9, 3, 2, 5, 7, + 2, 19, 4, 3, 6, 1, 1, 1, 1, 1, 4, 3, 2, 1, 1, 1, 2, 5, 3, 1, 1, 1, 2, 2, + 1, 1, 2, 1, 1, 2, 1, 3, 1, 1, 1, 3, 7, 1, 4, 1, 1, 2, 1, 1, 2, 1, 2, 4, + 4, 3, 8, 1, 1, 1, 2, 1, 3, 5, 1, 3, 1, 3, 4, 6, 2, 2, 14, 4, 6, 6, 11, 9, + 1, 15, 3, 1, 28, 5, 2, 5, 5, 3, 1, 3, 4, 5, 4, 6, 14, 3, 2, 3, 5, 21, 2, 7, + 20, 10, 1, 2, 19, 2, 4, 28, 28, 2, 3, 2, 1, 14, 4, 1, 26, 28, 42, 12, 40, 3, 52, 79, + 5, 14, 17, 3, 2, 2, 11, 3, 4, 6, 3, 1, 8, 2, 23, 4, 5, 8, 10, 4, 2, 7, 3, 5, + 1, 1, 6, 3, 1, 2, 2, 2, 5, 28, 1, 1, 7, 7, 20, 5, 3, 29, 3, 17, 26, 1, 8, 4, + 27, 3, 6, 11, 23, 5, 3, 4, 6, 13, 24, 16, 6, 5, 10, 25, 35, 7, 3, 2, 3, 3, 14, 3, + 6, 2, 6, 1, 4, 2, 3, 8, 2, 1, 1, 3, 3, 3, 4, 1, 1, 13, 2, 2, 4, 5, 2, 1, + 14, 14, 1, 2, 2, 1, 4, 5, 2, 3, 1, 14, 3, 12, 3, 17, 2, 16, 5, 1, 2, 1, 8, 9, + 3, 19, 4, 2, 2, 4, 17, 25, 21, 20, 28, 75, 1, 10, 29, 103, 4, 1, 2, 1, 1, 4, 2, 4, + 1, 2, 3, 24, 2, 2, 2, 1, 1, 2, 1, 3, 8, 1, 1, 1, 2, 1, 1, 3, 1, 1, 1, 6, + 1, 5, 3, 1, 1, 1, 3, 4, 1, 1, 5, 2, 1, 5, 6, 13, 9, 16, 1, 1, 1, 1, 3, 2, + 3, 2, 4, 5, 2, 5, 2, 2, 3, 7, 13, 7, 2, 2, 1, 1, 1, 1, 2, 3, 3, 2, 1, 6, + 4, 9, 2, 1, 14, 2, 14, 2, 1, 18, 3, 4, 14, 4, 11, 41, 15, 23, 15, 23, 176, 1, 3, 4, + 1, 1, 1, 1, 5, 3, 1, 2, 3, 7, 3, 1, 1, 2, 1, 2, 4, 4, 6, 2, 4, 1, 9, 7, + 1, 10, 5, 8, 16, 29, 1, 1, 2, 2, 3, 1, 3, 5, 2, 4, 5, 4, 1, 1, 2, 2, 3, 3, + 7, 1, 6, 10, 1, 17, 1, 44, 4, 6, 2, 1, 1, 6, 5, 4, 2, 10, 1, 6, 9, 2, 8, 1, + 24, 1, 2, 13, 7, 8, 8, 2, 1, 4, 1, 3, 1, 3, 3, 5, 2, 5, 10, 9, 4, 9, 12, 2, + 1, 6, 1, 10, 1, 1, 7, 7, 4, 10, 8, 3, 1, 13, 4, 3, 1, 6, 1, 3, 5, 2, 1, 2, + 17, 16, 5, 2, 16, 6, 1, 4, 2, 1, 3, 3, 6, 8, 5, 11, 11, 1, 3, 3, 2, 4, 6, 10, + 9, 5, 7, 4, 7, 4, 7, 1, 1, 4, 2, 1, 3, 6, 8, 7, 1, 6, 11, 5, 5, 3, 24, 9, + 4, 2, 7, 13, 5, 1, 8, 82, 16, 61, 1, 1, 1, 4, 2, 2, 16, 10, 3, 8, 1, 1, 6, 4, + 2, 1, 3, 1, 1, 1, 4, 3, 8, 4, 2, 2, 1, 1, 1, 1, 1, 6, 3, 5, 1, 1, 4, 6, + 9, 2, 1, 1, 1, 2, 1, 7, 2, 1, 6, 1, 5, 4, 4, 3, 1, 8, 1, 3, 3, 1, 3, 2, + 2, 2, 2, 3, 1, 6, 1, 2, 1, 2, 1, 3, 7, 1, 8, 2, 1, 2, 1, 5, 2, 5, 3, 5, + 10, 1, 2, 1, 1, 3, 2, 5, 11, 3, 9, 3, 5, 1, 1, 5, 9, 1, 2, 1, 5, 7, 9, 9, + 8, 1, 3, 3, 3, 6, 8, 2, 3, 2, 1, 1, 32, 6, 1, 2, 15, 9, 3, 7, 13, 1, 3, 10, + 13, 2, 14, 1, 13, 10, 2, 1, 3, 10, 4, 15, 2, 15, 15, 10, 1, 3, 9, 6, 9, 32, 25, 26, + 47, 7, 3, 2, 3, 1, 6, 3, 4, 3, 2, 8, 5, 4, 1, 9, 4, 2, 2, 19, 10, 6, 2, 3, + 8, 1, 2, 2, 4, 2, 1, 9, 4, 4, 4, 6, 4, 8, 9, 2, 3, 1, 1, 1, 1, 3, 5, 5, + 1, 3, 8, 4, 6, 2, 1, 4, 12, 1, 5, 3, 7, 13, 2, 5, 8, 1, 6, 1, 2, 5, 14, 6, + 1, 5, 2, 4, 8, 15, 5, 1, 23, 6, 62, 2, 10, 1, 1, 8, 1, 2, 2, 10, 4, 2, 2, 9, + 2, 1, 1, 3, 2, 3, 1, 5, 3, 3, 2, 1, 3, 8, 1, 1, 1, 11, 3, 1, 1, 4, 3, 7, + 1, 14, 1, 2, 3, 12, 5, 2, 5, 1, 6, 7, 5, 7, 14, 11, 1, 3, 1, 8, 9, 12, 2, 1, + 11, 8, 4, 4, 2, 6, 10, 9, 13, 1, 1, 3, 1, 5, 1, 3, 2, 4, 4, 1, 18, 2, 3, 14, + 11, 4, 29, 4, 2, 7, 1, 3, 13, 9, 2, 2, 5, 3, 5, 20, 7, 16, 8, 5, 72, 34, 6, 4, + 22, 12, 12, 28, 45, 36, 9, 7, 39, 9, 191, 1, 1, 1, 4, 11, 8, 4, 9, 2, 3, 22, 1, 1, + 1, 1, 4, 17, 1, 7, 7, 1, 11, 31, 10, 2, 4, 8, 2, 3, 2, 1, 4, 2, 16, 4, 32, 2, + 3, 19, 13, 4, 9, 1, 5, 2, 14, 8, 1, 1, 3, 6, 19, 6, 5, 1, 16, 6, 2, 10, 8, 5, + 1, 2, 3, 1, 5, 5, 1, 11, 6, 6, 1, 3, 3, 2, 6, 3, 8, 1, 1, 4, 10, 7, 5, 7, + 7, 5, 8, 9, 2, 1, 3, 4, 1, 1, 3, 1, 3, 3, 2, 6, 16, 1, 4, 6, 3, 1, 10, 6, + 1, 3, 15, 2, 9, 2, 10, 25, 13, 9, 16, 6, 2, 2, 10, 11, 4, 3, 9, 1, 2, 6, 6, 5, + 4, 30, 40, 1, 10, 7, 12, 14, 33, 6, 3, 6, 7, 3, 1, 3, 1, 11, 14, 4, 9, 5, 12, 11, + 49, 18, 51, 31, 140, 31, 2, 2, 1, 5, 1, 8, 1, 10, 1, 4, 4, 3, 24, 1, 10, 1, 3, 6, + 6, 16, 3, 4, 5, 2, 1, 4, 2, 57, 10, 6, 22, 2, 22, 3, 7, 22, 6, 10, 11, 36, 18, 16, + 33, 36, 2, 5, 5, 1, 1, 1, 4, 10, 1, 4, 13, 2, 7, 5, 2, 9, 3, 4, 1, 7, 43, 3, + 7, 3, 9, 14, 7, 9, 1, 11, 1, 1, 3, 7, 4, 18, 13, 1, 14, 1, 3, 6, 10, 73, 2, 2, + 30, 6, 1, 11, 18, 19, 13, 22, 3, 46, 42, 37, 89, 7, 3, 16, 34, 2, 2, 3, 9, 1, 7, 1, + 1, 1, 2, 2, 4, 10, 7, 3, 10, 3, 9, 5, 28, 9, 2, 6, 13, 7, 3, 1, 3, 10, 2, 7, + 2, 11, 3, 6, 21, 54, 85, 2, 1, 4, 2, 2, 1, 39, 3, 21, 2, 2, 5, 1, 1, 1, 4, 1, + 1, 3, 4, 15, 1, 3, 2, 4, 4, 2, 3, 8, 2, 20, 1, 8, 7, 13, 4, 1, 26, 6, 2, 9, + 34, 4, 21, 52, 10, 4, 4, 1, 5, 12, 2, 11, 1, 7, 2, 30, 12, 44, 2, 30, 1, 1, 3, 6, + 16, 9, 17, 39, 82, 2, 2, 24, 7, 1, 7, 3, 16, 9, 14, 44, 2, 1, 2, 1, 2, 3, 5, 2, + 4, 1, 6, 7, 5, 3, 2, 6, 1, 11, 5, 11, 2, 1, 18, 19, 8, 1, 3, 24, 29, 2, 1, 3, + 5, 2, 2, 1, 13, 6, 5, 1, 46, 11, 3, 5, 1, 1, 5, 8, 2, 10, 6, 12, 6, 3, 7, 11, + 2, 4, 16, 13, 2, 5, 1, 1, 2, 2, 5, 2, 28, 5, 2, 23, 10, 8, 4, 4, 22, 39, 95, 38, + 8, 14, 9, 5, 1, 13, 5, 4, 3, 13, 12, 11, 1, 9, 1, 27, 37, 2, 5, 4, 4, 63, 211, 95, + 2, 2, 2, 1, 3, 5, 2, 1, 1, 2, 2, 1, 1, 1, 3, 2, 4, 1, 2, 1, 1, 5, 2, 2, + 1, 1, 2, 3, 1, 3, 1, 1, 1, 3, 1, 4, 2, 1, 3, 6, 1, 1, 3, 7, 15, 5, 3, 2, + 5, 3, 9, 11, 4, 2, 22, 1, 6, 3, 8, 7, 1, 4, 28, 4, 16, 3, 3, 25, 4, 4, 27, 27, + 1, 4, 1, 2, 2, 7, 1, 3, 5, 2, 28, 8, 2, 14, 1, 8, 6, 16, 25, 3, 3, 3, 14, 3, + 3, 1, 1, 2, 1, 4, 6, 3, 8, 4, 1, 1, 1, 2, 3, 6, 10, 6, 2, 3, 18, 3, 2, 5, + 5, 4, 3, 1, 5, 2, 5, 4, 23, 7, 6, 12, 6, 4, 17, 11, 9, 5, 1, 1, 10, 5, 12, 1, + 1, 11, 26, 33, 7, 3, 6, 1, 17, 7, 1, 5, 12, 1, 11, 2, 4, 1, 8, 14, 17, 23, 1, 2, + 1, 7, 8, 16, 11, 9, 6, 5, 2, 6, 4, 16, 2, 8, 14, 1, 11, 8, 9, 1, 1, 1, 9, 25, + 4, 11, 19, 7, 2, 15, 2, 12, 8, 52, 7, 5, 19, 2, 16, 4, 36, 8, 1, 16, 8, 24, 26, 4, + 6, 2, 9, 5, 4, 36, 3, 28, 12, 25, 15, 37, 27, 17, 12, 59, 38, 5, 32, 127, 1, 2, 9, 17, + 14, 4, 1, 2, 1, 1, 8, 11, 50, 4, 14, 2, 19, 16, 4, 17, 5, 4, 5, 26, 12, 45, 2, 23, + 45, 104, 30, 12, 8, 3, 10, 2, 2, 3, 3, 1, 4, 20, 7, 2, 9, 6, 15, 2, 20, 1, 3, 16, + 4, 11, 15, 6, 134, 2, 5, 59, 1, 2, 2, 2, 1, 9, 17, 3, 26, 137, 10, 211, 59, 1, 2, 4, + 1, 4, 1, 1, 1, 2, 6, 2, 3, 1, 1, 2, 3, 2, 3, 1, 3, 4, 4, 2, 3, 3, 1, 4, + 3, 1, 7, 2, 2, 3, 1, 2, 1, 3, 3, 3, 2, 2, 3, 2, 1, 3, 14, 6, 1, 3, 2, 9, + 6, 15, 27, 9, 34, 145, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 3, 1, 2, + 1, 1, 1, 2, 3, 5, 8, 3, 5, 2, 4, 1, 3, 2, 2, 2, 12, 4, 1, 1, 1, 10, 4, 5, + 1, 20, 4, 16, 1, 15, 9, 5, 12, 2, 9, 2, 5, 4, 2, 26, 19, 7, 1, 26, 4, 30, 12, 15, + 42, 1, 6, 8, 172, 1, 1, 4, 2, 1, 1, 11, 2, 2, 4, 2, 1, 2, 1, 10, 8, 1, 2, 1, + 4, 5, 1, 2, 5, 1, 8, 4, 1, 3, 4, 2, 1, 6, 2, 1, 3, 4, 1, 2, 1, 1, 1, 1, + 12, 5, 7, 2, 4, 3, 1, 1, 1, 3, 3, 6, 1, 2, 2, 3, 3, 3, 2, 1, 2, 12, 14, 11, + 6, 6, 4, 12, 2, 8, 1, 7, 10, 1, 35, 7, 4, 13, 15, 4, 3, 23, 21, 28, 52, 5, 26, 5, + 6, 1, 7, 10, 2, 7, 53, 3, 2, 1, 1, 1, 2, 163, 532, 1, 10, 11, 1, 3, 3, 4, 8, 2, + 8, 6, 2, 2, 23, 22, 4, 2, 2, 4, 2, 1, 3, 1, 3, 3, 5, 9, 8, 2, 1, 2, 8, 1, + 10, 2, 12, 21, 20, 15, 105, 2, 3, 1, 1, 3, 2, 3, 1, 1, 2, 5, 1, 4, 15, 11, 19, 1, + 1, 1, 1, 5, 4, 5, 1, 1, 2, 5, 3, 5, 12, 1, 2, 5, 1, 11, 1, 1, 15, 9, 1, 4, + 5, 3, 26, 8, 2, 1, 3, 1, 1, 15, 19, 2, 12, 1, 2, 5, 2, 7, 2, 19, 2, 20, 6, 26, + 7, 5, 2, 2, 7, 34, 21, 13, 70, 2, 128, 1, 1, 2, 1, 1, 2, 1, 1, 3, 2, 2, 2, 15, + 1, 4, 1, 3, 4, 42, 10, 6, 1, 49, 85, 8, 1, 2, 1, 1, 4, 4, 2, 3, 6, 1, 5, 7, + 4, 3, 211, 4, 1, 2, 1, 2, 5, 1, 2, 4, 2, 2, 6, 5, 6, 10, 3, 4, 48, 100, 6, 2, + 16, 296, 5, 27, 387, 2, 2, 3, 7, 16, 8, 5, 38, 15, 39, 21, 9, 10, 3, 7, 59, 13, 27, 21, + 47, 5, 21, 6}; static ImWchar base_ranges[] = // not zero-terminated - { - 0x0020, 0x00FF, // Basic Latin + Latin Supplement - 0x2000, 0x206F, // General Punctuation - 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana - 0x31F0, 0x31FF, // Katakana Phonetic Extensions - 0xFF00, 0xFFEF, // Half-width characters - 0xFFFD, 0xFFFD // Invalid - }; - static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 }; + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x2000, 0x206F, // General Punctuation + 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana + 0x31F0, 0x31FF, // Katakana Phonetic Extensions + 0xFF00, 0xFFEF, // Half-width characters + 0xFFFD, 0xFFFD // Invalid + }; + static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { + 0}; if (!full_ranges[0]) { memcpy(full_ranges, base_ranges, sizeof(base_ranges)); - UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges)); + UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), + full_ranges + IM_ARRAYSIZE(base_ranges)); } return &full_ranges[0]; } -const ImWchar* ImFontAtlas::GetGlyphRangesJapanese() +const ImWchar *ImFontAtlas::GetGlyphRangesJapanese() { // 2999 ideograms code points for Japanese // - 2136 Joyo (meaning "for regular use" or "for common use") Kanji code points @@ -4852,81 +5423,151 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese() // - (Wikipedia) https://en.wikipedia.org/wiki/List_of_j%C5%8Dy%C5%8D_kanji // - List of Jinmeiyo Kanji // - (Wikipedia) https://en.wikipedia.org/wiki/Jinmeiy%C5%8D_kanji - // - Missing 1 Joyo Kanji: U+20B9F (Kun'yomi: Shikaru, On'yomi: Shitsu,shichi), see https://github.com/ocornut/imgui/pull/3627 for details. - // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. - // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.) - static const short accumulative_offsets_from_0x4E00[] = - { - 0,1,2,4,1,1,1,1,2,1,3,3,2,2,1,5,3,5,7,5,6,1,2,1,7,2,6,3,1,8,1,1,4,1,1,18,2,11,2,6,2,1,2,1,5,1,2,1,3,1,2,1,2,3,3,1,1,2,3,1,1,1,12,7,9,1,4,5,1, - 1,2,1,10,1,1,9,2,2,4,5,6,9,3,1,1,1,1,9,3,18,5,2,2,2,2,1,6,3,7,1,1,1,1,2,2,4,2,1,23,2,10,4,3,5,2,4,10,2,4,13,1,6,1,9,3,1,1,6,6,7,6,3,1,2,11,3, - 2,2,3,2,15,2,2,5,4,3,6,4,1,2,5,2,12,16,6,13,9,13,2,1,1,7,16,4,7,1,19,1,5,1,2,2,7,7,8,2,6,5,4,9,18,7,4,5,9,13,11,8,15,2,1,1,1,2,1,2,2,1,2,2,8, - 2,9,3,3,1,1,4,4,1,1,1,4,9,1,4,3,5,5,2,7,5,3,4,8,2,1,13,2,3,3,1,14,1,1,4,5,1,3,6,1,5,2,1,1,3,3,3,3,1,1,2,7,6,6,7,1,4,7,6,1,1,1,1,1,12,3,3,9,5, - 2,6,1,5,6,1,2,3,18,2,4,14,4,1,3,6,1,1,6,3,5,5,3,2,2,2,2,12,3,1,4,2,3,2,3,11,1,7,4,1,2,1,3,17,1,9,1,24,1,1,4,2,2,4,1,2,7,1,1,1,3,1,2,2,4,15,1, - 1,2,1,1,2,1,5,2,5,20,2,5,9,1,10,8,7,6,1,1,1,1,1,1,6,2,1,2,8,1,1,1,1,5,1,1,3,1,1,1,1,3,1,1,12,4,1,3,1,1,1,1,1,10,3,1,7,5,13,1,2,3,4,6,1,1,30, - 2,9,9,1,15,38,11,3,1,8,24,7,1,9,8,10,2,1,9,31,2,13,6,2,9,4,49,5,2,15,2,1,10,2,1,1,1,2,2,6,15,30,35,3,14,18,8,1,16,10,28,12,19,45,38,1,3,2,3, - 13,2,1,7,3,6,5,3,4,3,1,5,7,8,1,5,3,18,5,3,6,1,21,4,24,9,24,40,3,14,3,21,3,2,1,2,4,2,3,1,15,15,6,5,1,1,3,1,5,6,1,9,7,3,3,2,1,4,3,8,21,5,16,4, - 5,2,10,11,11,3,6,3,2,9,3,6,13,1,2,1,1,1,1,11,12,6,6,1,4,2,6,5,2,1,1,3,3,6,13,3,1,1,5,1,2,3,3,14,2,1,2,2,2,5,1,9,5,1,1,6,12,3,12,3,4,13,2,14, - 2,8,1,17,5,1,16,4,2,2,21,8,9,6,23,20,12,25,19,9,38,8,3,21,40,25,33,13,4,3,1,4,1,2,4,1,2,5,26,2,1,1,2,1,3,6,2,1,1,1,1,1,1,2,3,1,1,1,9,2,3,1,1, - 1,3,6,3,2,1,1,6,6,1,8,2,2,2,1,4,1,2,3,2,7,3,2,4,1,2,1,2,2,1,1,1,1,1,3,1,2,5,4,10,9,4,9,1,1,1,1,1,1,5,3,2,1,6,4,9,6,1,10,2,31,17,8,3,7,5,40,1, - 7,7,1,6,5,2,10,7,8,4,15,39,25,6,28,47,18,10,7,1,3,1,1,2,1,1,1,3,3,3,1,1,1,3,4,2,1,4,1,3,6,10,7,8,6,2,2,1,3,3,2,5,8,7,9,12,2,15,1,1,4,1,2,1,1, - 1,3,2,1,3,3,5,6,2,3,2,10,1,4,2,8,1,1,1,11,6,1,21,4,16,3,1,3,1,4,2,3,6,5,1,3,1,1,3,3,4,6,1,1,10,4,2,7,10,4,7,4,2,9,4,3,1,1,1,4,1,8,3,4,1,3,1, - 6,1,4,2,1,4,7,2,1,8,1,4,5,1,1,2,2,4,6,2,7,1,10,1,1,3,4,11,10,8,21,4,6,1,3,5,2,1,2,28,5,5,2,3,13,1,2,3,1,4,2,1,5,20,3,8,11,1,3,3,3,1,8,10,9,2, - 10,9,2,3,1,1,2,4,1,8,3,6,1,7,8,6,11,1,4,29,8,4,3,1,2,7,13,1,4,1,6,2,6,12,12,2,20,3,2,3,6,4,8,9,2,7,34,5,1,18,6,1,1,4,4,5,7,9,1,2,2,4,3,4,1,7, - 2,2,2,6,2,3,25,5,3,6,1,4,6,7,4,2,1,4,2,13,6,4,4,3,1,5,3,4,4,3,2,1,1,4,1,2,1,1,3,1,11,1,6,3,1,7,3,6,2,8,8,6,9,3,4,11,3,2,10,12,2,5,11,1,6,4,5, - 3,1,8,5,4,6,6,3,5,1,1,3,2,1,2,2,6,17,12,1,10,1,6,12,1,6,6,19,9,6,16,1,13,4,4,15,7,17,6,11,9,15,12,6,7,2,1,2,2,15,9,3,21,4,6,49,18,7,3,2,3,1, - 6,8,2,2,6,2,9,1,3,6,4,4,1,2,16,2,5,2,1,6,2,3,5,3,1,2,5,1,2,1,9,3,1,8,6,4,8,11,3,1,1,1,1,3,1,13,8,4,1,3,2,2,1,4,1,11,1,5,2,1,5,2,5,8,6,1,1,7, - 4,3,8,3,2,7,2,1,5,1,5,2,4,7,6,2,8,5,1,11,4,5,3,6,18,1,2,13,3,3,1,21,1,1,4,1,4,1,1,1,8,1,2,2,7,1,2,4,2,2,9,2,1,1,1,4,3,6,3,12,5,1,1,1,5,6,3,2, - 4,8,2,2,4,2,7,1,8,9,5,2,3,2,1,3,2,13,7,14,6,5,1,1,2,1,4,2,23,2,1,1,6,3,1,4,1,15,3,1,7,3,9,14,1,3,1,4,1,1,5,8,1,3,8,3,8,15,11,4,14,4,4,2,5,5, - 1,7,1,6,14,7,7,8,5,15,4,8,6,5,6,2,1,13,1,20,15,11,9,2,5,6,2,11,2,6,2,5,1,5,8,4,13,19,25,4,1,1,11,1,34,2,5,9,14,6,2,2,6,1,1,14,1,3,14,13,1,6, - 12,21,14,14,6,32,17,8,32,9,28,1,2,4,11,8,3,1,14,2,5,15,1,1,1,1,3,6,4,1,3,4,11,3,1,1,11,30,1,5,1,4,1,5,8,1,1,3,2,4,3,17,35,2,6,12,17,3,1,6,2, - 1,1,12,2,7,3,3,2,1,16,2,8,3,6,5,4,7,3,3,8,1,9,8,5,1,2,1,3,2,8,1,2,9,12,1,1,2,3,8,3,24,12,4,3,7,5,8,3,3,3,3,3,3,1,23,10,3,1,2,2,6,3,1,16,1,16, - 22,3,10,4,11,6,9,7,7,3,6,2,2,2,4,10,2,1,1,2,8,7,1,6,4,1,3,3,3,5,10,12,12,2,3,12,8,15,1,1,16,6,6,1,5,9,11,4,11,4,2,6,12,1,17,5,13,1,4,9,5,1,11, - 2,1,8,1,5,7,28,8,3,5,10,2,17,3,38,22,1,2,18,12,10,4,38,18,1,4,44,19,4,1,8,4,1,12,1,4,31,12,1,14,7,75,7,5,10,6,6,13,3,2,11,11,3,2,5,28,15,6,18, - 18,5,6,4,3,16,1,7,18,7,36,3,5,3,1,7,1,9,1,10,7,2,4,2,6,2,9,7,4,3,32,12,3,7,10,2,23,16,3,1,12,3,31,4,11,1,3,8,9,5,1,30,15,6,12,3,2,2,11,19,9, - 14,2,6,2,3,19,13,17,5,3,3,25,3,14,1,1,1,36,1,3,2,19,3,13,36,9,13,31,6,4,16,34,2,5,4,2,3,3,5,1,1,1,4,3,1,17,3,2,3,5,3,1,3,2,3,5,6,3,12,11,1,3, - 1,2,26,7,12,7,2,14,3,3,7,7,11,25,25,28,16,4,36,1,2,1,6,2,1,9,3,27,17,4,3,4,13,4,1,3,2,2,1,10,4,2,4,6,3,8,2,1,18,1,1,24,2,2,4,33,2,3,63,7,1,6, - 40,7,3,4,4,2,4,15,18,1,16,1,1,11,2,41,14,1,3,18,13,3,2,4,16,2,17,7,15,24,7,18,13,44,2,2,3,6,1,1,7,5,1,7,1,4,3,3,5,10,8,2,3,1,8,1,1,27,4,2,1, - 12,1,2,1,10,6,1,6,7,5,2,3,7,11,5,11,3,6,6,2,3,15,4,9,1,1,2,1,2,11,2,8,12,8,5,4,2,3,1,5,2,2,1,14,1,12,11,4,1,11,17,17,4,3,2,5,5,7,3,1,5,9,9,8, - 2,5,6,6,13,13,2,1,2,6,1,2,2,49,4,9,1,2,10,16,7,8,4,3,2,23,4,58,3,29,1,14,19,19,11,11,2,7,5,1,3,4,6,2,18,5,12,12,17,17,3,3,2,4,1,6,2,3,4,3,1, - 1,1,1,5,1,1,9,1,3,1,3,6,1,8,1,1,2,6,4,14,3,1,4,11,4,1,3,32,1,2,4,13,4,1,2,4,2,1,3,1,11,1,4,2,1,4,4,6,3,5,1,6,5,7,6,3,23,3,5,3,5,3,3,13,3,9,10, - 1,12,10,2,3,18,13,7,160,52,4,2,2,3,2,14,5,4,12,4,6,4,1,20,4,11,6,2,12,27,1,4,1,2,2,7,4,5,2,28,3,7,25,8,3,19,3,6,10,2,2,1,10,2,5,4,1,3,4,1,5, - 3,2,6,9,3,6,2,16,3,3,16,4,5,5,3,2,1,2,16,15,8,2,6,21,2,4,1,22,5,8,1,1,21,11,2,1,11,11,19,13,12,4,2,3,2,3,6,1,8,11,1,4,2,9,5,2,1,11,2,9,1,1,2, - 14,31,9,3,4,21,14,4,8,1,7,2,2,2,5,1,4,20,3,3,4,10,1,11,9,8,2,1,4,5,14,12,14,2,17,9,6,31,4,14,1,20,13,26,5,2,7,3,6,13,2,4,2,19,6,2,2,18,9,3,5, - 12,12,14,4,6,2,3,6,9,5,22,4,5,25,6,4,8,5,2,6,27,2,35,2,16,3,7,8,8,6,6,5,9,17,2,20,6,19,2,13,3,1,1,1,4,17,12,2,14,7,1,4,18,12,38,33,2,10,1,1, - 2,13,14,17,11,50,6,33,20,26,74,16,23,45,50,13,38,33,6,6,7,4,4,2,1,3,2,5,8,7,8,9,3,11,21,9,13,1,3,10,6,7,1,2,2,18,5,5,1,9,9,2,68,9,19,13,2,5, - 1,4,4,7,4,13,3,9,10,21,17,3,26,2,1,5,2,4,5,4,1,7,4,7,3,4,2,1,6,1,1,20,4,1,9,2,2,1,3,3,2,3,2,1,1,1,20,2,3,1,6,2,3,6,2,4,8,1,3,2,10,3,5,3,4,4, - 3,4,16,1,6,1,10,2,4,2,1,1,2,10,11,2,2,3,1,24,31,4,10,10,2,5,12,16,164,15,4,16,7,9,15,19,17,1,2,1,1,5,1,1,1,1,1,3,1,4,3,1,3,1,3,1,2,1,1,3,3,7, - 2,8,1,2,2,2,1,3,4,3,7,8,12,92,2,10,3,1,3,14,5,25,16,42,4,7,7,4,2,21,5,27,26,27,21,25,30,31,2,1,5,13,3,22,5,6,6,11,9,12,1,5,9,7,5,5,22,60,3,5, - 13,1,1,8,1,1,3,3,2,1,9,3,3,18,4,1,2,3,7,6,3,1,2,3,9,1,3,1,3,2,1,3,1,1,1,2,1,11,3,1,6,9,1,3,2,3,1,2,1,5,1,1,4,3,4,1,2,2,4,4,1,7,2,1,2,2,3,5,13, - 18,3,4,14,9,9,4,16,3,7,5,8,2,6,48,28,3,1,1,4,2,14,8,2,9,2,1,15,2,4,3,2,10,16,12,8,7,1,1,3,1,1,1,2,7,4,1,6,4,38,39,16,23,7,15,15,3,2,12,7,21, - 37,27,6,5,4,8,2,10,8,8,6,5,1,2,1,3,24,1,16,17,9,23,10,17,6,1,51,55,44,13,294,9,3,6,2,4,2,2,15,1,1,1,13,21,17,68,14,8,9,4,1,4,9,3,11,7,1,1,1, - 5,6,3,2,1,1,1,2,3,8,1,2,2,4,1,5,5,2,1,4,3,7,13,4,1,4,1,3,1,1,1,5,5,10,1,6,1,5,2,1,5,2,4,1,4,5,7,3,18,2,9,11,32,4,3,3,2,4,7,11,16,9,11,8,13,38, - 32,8,4,2,1,1,2,1,2,4,4,1,1,1,4,1,21,3,11,1,16,1,1,6,1,3,2,4,9,8,57,7,44,1,3,3,13,3,10,1,1,7,5,2,7,21,47,63,3,15,4,7,1,16,1,1,2,8,2,3,42,15,4, - 1,29,7,22,10,3,78,16,12,20,18,4,67,11,5,1,3,15,6,21,31,32,27,18,13,71,35,5,142,4,10,1,2,50,19,33,16,35,37,16,19,27,7,1,133,19,1,4,8,7,20,1,4, - 4,1,10,3,1,6,1,2,51,5,40,15,24,43,22928,11,1,13,154,70,3,1,1,7,4,10,1,2,1,1,2,1,2,1,2,2,1,1,2,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1, - 3,2,1,1,1,1,2,1,1, + // - Missing 1 Joyo Kanji: U+20B9F (Kun'yomi: Shikaru, On'yomi: Shitsu,shichi), see + // https://github.com/ocornut/imgui/pull/3627 for details. You can use ImFontGlyphRangesBuilder to create your own + // ranges derived from this, by merging existing ranges or adding new characters. (Stored as accumulative offsets + // from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.) + static const short accumulative_offsets_from_0x4E00[] = { + 0, 1, 2, 4, 1, 1, 1, 1, 2, 1, 3, 3, 2, 2, 1, 5, 3, 5, 7, 5, 6, 1, 2, 1, 7, 2, + 6, 3, 1, 8, 1, 1, 4, 1, 1, 18, 2, 11, 2, 6, 2, 1, 2, 1, 5, 1, 2, 1, 3, 1, 2, 1, + 2, 3, 3, 1, 1, 2, 3, 1, 1, 1, 12, 7, 9, 1, 4, 5, 1, 1, 2, 1, 10, 1, 1, 9, 2, 2, + 4, 5, 6, 9, 3, 1, 1, 1, 1, 9, 3, 18, 5, 2, 2, 2, 2, 1, 6, 3, 7, 1, 1, 1, 1, 2, + 2, 4, 2, 1, 23, 2, 10, 4, 3, 5, 2, 4, 10, 2, 4, 13, 1, 6, 1, 9, 3, 1, 1, 6, 6, 7, + 6, 3, 1, 2, 11, 3, 2, 2, 3, 2, 15, 2, 2, 5, 4, 3, 6, 4, 1, 2, 5, 2, 12, 16, 6, 13, + 9, 13, 2, 1, 1, 7, 16, 4, 7, 1, 19, 1, 5, 1, 2, 2, 7, 7, 8, 2, 6, 5, 4, 9, 18, 7, + 4, 5, 9, 13, 11, 8, 15, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 8, 2, 9, 3, 3, 1, 1, 4, + 4, 1, 1, 1, 4, 9, 1, 4, 3, 5, 5, 2, 7, 5, 3, 4, 8, 2, 1, 13, 2, 3, 3, 1, 14, 1, + 1, 4, 5, 1, 3, 6, 1, 5, 2, 1, 1, 3, 3, 3, 3, 1, 1, 2, 7, 6, 6, 7, 1, 4, 7, 6, + 1, 1, 1, 1, 1, 12, 3, 3, 9, 5, 2, 6, 1, 5, 6, 1, 2, 3, 18, 2, 4, 14, 4, 1, 3, 6, + 1, 1, 6, 3, 5, 5, 3, 2, 2, 2, 2, 12, 3, 1, 4, 2, 3, 2, 3, 11, 1, 7, 4, 1, 2, 1, + 3, 17, 1, 9, 1, 24, 1, 1, 4, 2, 2, 4, 1, 2, 7, 1, 1, 1, 3, 1, 2, 2, 4, 15, 1, 1, + 2, 1, 1, 2, 1, 5, 2, 5, 20, 2, 5, 9, 1, 10, 8, 7, 6, 1, 1, 1, 1, 1, 1, 6, 2, 1, + 2, 8, 1, 1, 1, 1, 5, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 12, 4, 1, 3, 1, 1, 1, 1, 1, + 10, 3, 1, 7, 5, 13, 1, 2, 3, 4, 6, 1, 1, 30, 2, 9, 9, 1, 15, 38, 11, 3, 1, 8, 24, 7, + 1, 9, 8, 10, 2, 1, 9, 31, 2, 13, 6, 2, 9, 4, 49, 5, 2, 15, 2, 1, 10, 2, 1, 1, 1, 2, + 2, 6, 15, 30, 35, 3, 14, 18, 8, 1, 16, 10, 28, 12, 19, 45, 38, 1, 3, 2, 3, 13, 2, 1, 7, 3, + 6, 5, 3, 4, 3, 1, 5, 7, 8, 1, 5, 3, 18, 5, 3, 6, 1, 21, 4, 24, 9, 24, 40, 3, 14, 3, + 21, 3, 2, 1, 2, 4, 2, 3, 1, 15, 15, 6, 5, 1, 1, 3, 1, 5, 6, 1, 9, 7, 3, 3, 2, 1, + 4, 3, 8, 21, 5, 16, 4, 5, 2, 10, 11, 11, 3, 6, 3, 2, 9, 3, 6, 13, 1, 2, 1, 1, 1, 1, + 11, 12, 6, 6, 1, 4, 2, 6, 5, 2, 1, 1, 3, 3, 6, 13, 3, 1, 1, 5, 1, 2, 3, 3, 14, 2, + 1, 2, 2, 2, 5, 1, 9, 5, 1, 1, 6, 12, 3, 12, 3, 4, 13, 2, 14, 2, 8, 1, 17, 5, 1, 16, + 4, 2, 2, 21, 8, 9, 6, 23, 20, 12, 25, 19, 9, 38, 8, 3, 21, 40, 25, 33, 13, 4, 3, 1, 4, 1, + 2, 4, 1, 2, 5, 26, 2, 1, 1, 2, 1, 3, 6, 2, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 9, + 2, 3, 1, 1, 1, 3, 6, 3, 2, 1, 1, 6, 6, 1, 8, 2, 2, 2, 1, 4, 1, 2, 3, 2, 7, 3, + 2, 4, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 3, 1, 2, 5, 4, 10, 9, 4, 9, 1, 1, 1, 1, 1, + 1, 5, 3, 2, 1, 6, 4, 9, 6, 1, 10, 2, 31, 17, 8, 3, 7, 5, 40, 1, 7, 7, 1, 6, 5, 2, + 10, 7, 8, 4, 15, 39, 25, 6, 28, 47, 18, 10, 7, 1, 3, 1, 1, 2, 1, 1, 1, 3, 3, 3, 1, 1, + 1, 3, 4, 2, 1, 4, 1, 3, 6, 10, 7, 8, 6, 2, 2, 1, 3, 3, 2, 5, 8, 7, 9, 12, 2, 15, + 1, 1, 4, 1, 2, 1, 1, 1, 3, 2, 1, 3, 3, 5, 6, 2, 3, 2, 10, 1, 4, 2, 8, 1, 1, 1, + 11, 6, 1, 21, 4, 16, 3, 1, 3, 1, 4, 2, 3, 6, 5, 1, 3, 1, 1, 3, 3, 4, 6, 1, 1, 10, + 4, 2, 7, 10, 4, 7, 4, 2, 9, 4, 3, 1, 1, 1, 4, 1, 8, 3, 4, 1, 3, 1, 6, 1, 4, 2, + 1, 4, 7, 2, 1, 8, 1, 4, 5, 1, 1, 2, 2, 4, 6, 2, 7, 1, 10, 1, 1, 3, 4, 11, 10, 8, + 21, 4, 6, 1, 3, 5, 2, 1, 2, 28, 5, 5, 2, 3, 13, 1, 2, 3, 1, 4, 2, 1, 5, 20, 3, 8, + 11, 1, 3, 3, 3, 1, 8, 10, 9, 2, 10, 9, 2, 3, 1, 1, 2, 4, 1, 8, 3, 6, 1, 7, 8, 6, + 11, 1, 4, 29, 8, 4, 3, 1, 2, 7, 13, 1, 4, 1, 6, 2, 6, 12, 12, 2, 20, 3, 2, 3, 6, 4, + 8, 9, 2, 7, 34, 5, 1, 18, 6, 1, 1, 4, 4, 5, 7, 9, 1, 2, 2, 4, 3, 4, 1, 7, 2, 2, + 2, 6, 2, 3, 25, 5, 3, 6, 1, 4, 6, 7, 4, 2, 1, 4, 2, 13, 6, 4, 4, 3, 1, 5, 3, 4, + 4, 3, 2, 1, 1, 4, 1, 2, 1, 1, 3, 1, 11, 1, 6, 3, 1, 7, 3, 6, 2, 8, 8, 6, 9, 3, + 4, 11, 3, 2, 10, 12, 2, 5, 11, 1, 6, 4, 5, 3, 1, 8, 5, 4, 6, 6, 3, 5, 1, 1, 3, 2, + 1, 2, 2, 6, 17, 12, 1, 10, 1, 6, 12, 1, 6, 6, 19, 9, 6, 16, 1, 13, 4, 4, 15, 7, 17, 6, + 11, 9, 15, 12, 6, 7, 2, 1, 2, 2, 15, 9, 3, 21, 4, 6, 49, 18, 7, 3, 2, 3, 1, 6, 8, 2, + 2, 6, 2, 9, 1, 3, 6, 4, 4, 1, 2, 16, 2, 5, 2, 1, 6, 2, 3, 5, 3, 1, 2, 5, 1, 2, + 1, 9, 3, 1, 8, 6, 4, 8, 11, 3, 1, 1, 1, 1, 3, 1, 13, 8, 4, 1, 3, 2, 2, 1, 4, 1, + 11, 1, 5, 2, 1, 5, 2, 5, 8, 6, 1, 1, 7, 4, 3, 8, 3, 2, 7, 2, 1, 5, 1, 5, 2, 4, + 7, 6, 2, 8, 5, 1, 11, 4, 5, 3, 6, 18, 1, 2, 13, 3, 3, 1, 21, 1, 1, 4, 1, 4, 1, 1, + 1, 8, 1, 2, 2, 7, 1, 2, 4, 2, 2, 9, 2, 1, 1, 1, 4, 3, 6, 3, 12, 5, 1, 1, 1, 5, + 6, 3, 2, 4, 8, 2, 2, 4, 2, 7, 1, 8, 9, 5, 2, 3, 2, 1, 3, 2, 13, 7, 14, 6, 5, 1, + 1, 2, 1, 4, 2, 23, 2, 1, 1, 6, 3, 1, 4, 1, 15, 3, 1, 7, 3, 9, 14, 1, 3, 1, 4, 1, + 1, 5, 8, 1, 3, 8, 3, 8, 15, 11, 4, 14, 4, 4, 2, 5, 5, 1, 7, 1, 6, 14, 7, 7, 8, 5, + 15, 4, 8, 6, 5, 6, 2, 1, 13, 1, 20, 15, 11, 9, 2, 5, 6, 2, 11, 2, 6, 2, 5, 1, 5, 8, + 4, 13, 19, 25, 4, 1, 1, 11, 1, 34, 2, 5, 9, 14, 6, 2, 2, 6, 1, 1, 14, 1, 3, 14, 13, 1, + 6, 12, 21, 14, 14, 6, 32, 17, 8, 32, 9, 28, 1, 2, 4, 11, 8, 3, 1, 14, 2, 5, 15, 1, 1, 1, + 1, 3, 6, 4, 1, 3, 4, 11, 3, 1, 1, 11, 30, 1, 5, 1, 4, 1, 5, 8, 1, 1, 3, 2, 4, 3, + 17, 35, 2, 6, 12, 17, 3, 1, 6, 2, 1, 1, 12, 2, 7, 3, 3, 2, 1, 16, 2, 8, 3, 6, 5, 4, + 7, 3, 3, 8, 1, 9, 8, 5, 1, 2, 1, 3, 2, 8, 1, 2, 9, 12, 1, 1, 2, 3, 8, 3, 24, 12, + 4, 3, 7, 5, 8, 3, 3, 3, 3, 3, 3, 1, 23, 10, 3, 1, 2, 2, 6, 3, 1, 16, 1, 16, 22, 3, + 10, 4, 11, 6, 9, 7, 7, 3, 6, 2, 2, 2, 4, 10, 2, 1, 1, 2, 8, 7, 1, 6, 4, 1, 3, 3, + 3, 5, 10, 12, 12, 2, 3, 12, 8, 15, 1, 1, 16, 6, 6, 1, 5, 9, 11, 4, 11, 4, 2, 6, 12, 1, + 17, 5, 13, 1, 4, 9, 5, 1, 11, 2, 1, 8, 1, 5, 7, 28, 8, 3, 5, 10, 2, 17, 3, 38, 22, 1, + 2, 18, 12, 10, 4, 38, 18, 1, 4, 44, 19, 4, 1, 8, 4, 1, 12, 1, 4, 31, 12, 1, 14, 7, 75, 7, + 5, 10, 6, 6, 13, 3, 2, 11, 11, 3, 2, 5, 28, 15, 6, 18, 18, 5, 6, 4, 3, 16, 1, 7, 18, 7, + 36, 3, 5, 3, 1, 7, 1, 9, 1, 10, 7, 2, 4, 2, 6, 2, 9, 7, 4, 3, 32, 12, 3, 7, 10, 2, + 23, 16, 3, 1, 12, 3, 31, 4, 11, 1, 3, 8, 9, 5, 1, 30, 15, 6, 12, 3, 2, 2, 11, 19, 9, 14, + 2, 6, 2, 3, 19, 13, 17, 5, 3, 3, 25, 3, 14, 1, 1, 1, 36, 1, 3, 2, 19, 3, 13, 36, 9, 13, + 31, 6, 4, 16, 34, 2, 5, 4, 2, 3, 3, 5, 1, 1, 1, 4, 3, 1, 17, 3, 2, 3, 5, 3, 1, 3, + 2, 3, 5, 6, 3, 12, 11, 1, 3, 1, 2, 26, 7, 12, 7, 2, 14, 3, 3, 7, 7, 11, 25, 25, 28, 16, + 4, 36, 1, 2, 1, 6, 2, 1, 9, 3, 27, 17, 4, 3, 4, 13, 4, 1, 3, 2, 2, 1, 10, 4, 2, 4, + 6, 3, 8, 2, 1, 18, 1, 1, 24, 2, 2, 4, 33, 2, 3, 63, 7, 1, 6, 40, 7, 3, 4, 4, 2, 4, + 15, 18, 1, 16, 1, 1, 11, 2, 41, 14, 1, 3, 18, 13, 3, 2, 4, 16, 2, 17, 7, 15, 24, 7, 18, 13, + 44, 2, 2, 3, 6, 1, 1, 7, 5, 1, 7, 1, 4, 3, 3, 5, 10, 8, 2, 3, 1, 8, 1, 1, 27, 4, + 2, 1, 12, 1, 2, 1, 10, 6, 1, 6, 7, 5, 2, 3, 7, 11, 5, 11, 3, 6, 6, 2, 3, 15, 4, 9, + 1, 1, 2, 1, 2, 11, 2, 8, 12, 8, 5, 4, 2, 3, 1, 5, 2, 2, 1, 14, 1, 12, 11, 4, 1, 11, + 17, 17, 4, 3, 2, 5, 5, 7, 3, 1, 5, 9, 9, 8, 2, 5, 6, 6, 13, 13, 2, 1, 2, 6, 1, 2, + 2, 49, 4, 9, 1, 2, 10, 16, 7, 8, 4, 3, 2, 23, 4, 58, 3, 29, 1, 14, 19, 19, 11, 11, 2, 7, + 5, 1, 3, 4, 6, 2, 18, 5, 12, 12, 17, 17, 3, 3, 2, 4, 1, 6, 2, 3, 4, 3, 1, 1, 1, 1, + 5, 1, 1, 9, 1, 3, 1, 3, 6, 1, 8, 1, 1, 2, 6, 4, 14, 3, 1, 4, 11, 4, 1, 3, 32, 1, + 2, 4, 13, 4, 1, 2, 4, 2, 1, 3, 1, 11, 1, 4, 2, 1, 4, 4, 6, 3, 5, 1, 6, 5, 7, 6, + 3, 23, 3, 5, 3, 5, 3, 3, 13, 3, 9, 10, 1, 12, 10, 2, 3, 18, 13, 7, 160, 52, 4, 2, 2, 3, + 2, 14, 5, 4, 12, 4, 6, 4, 1, 20, 4, 11, 6, 2, 12, 27, 1, 4, 1, 2, 2, 7, 4, 5, 2, 28, + 3, 7, 25, 8, 3, 19, 3, 6, 10, 2, 2, 1, 10, 2, 5, 4, 1, 3, 4, 1, 5, 3, 2, 6, 9, 3, + 6, 2, 16, 3, 3, 16, 4, 5, 5, 3, 2, 1, 2, 16, 15, 8, 2, 6, 21, 2, 4, 1, 22, 5, 8, 1, + 1, 21, 11, 2, 1, 11, 11, 19, 13, 12, 4, 2, 3, 2, 3, 6, 1, 8, 11, 1, 4, 2, 9, 5, 2, 1, + 11, 2, 9, 1, 1, 2, 14, 31, 9, 3, 4, 21, 14, 4, 8, 1, 7, 2, 2, 2, 5, 1, 4, 20, 3, 3, + 4, 10, 1, 11, 9, 8, 2, 1, 4, 5, 14, 12, 14, 2, 17, 9, 6, 31, 4, 14, 1, 20, 13, 26, 5, 2, + 7, 3, 6, 13, 2, 4, 2, 19, 6, 2, 2, 18, 9, 3, 5, 12, 12, 14, 4, 6, 2, 3, 6, 9, 5, 22, + 4, 5, 25, 6, 4, 8, 5, 2, 6, 27, 2, 35, 2, 16, 3, 7, 8, 8, 6, 6, 5, 9, 17, 2, 20, 6, + 19, 2, 13, 3, 1, 1, 1, 4, 17, 12, 2, 14, 7, 1, 4, 18, 12, 38, 33, 2, 10, 1, 1, 2, 13, 14, + 17, 11, 50, 6, 33, 20, 26, 74, 16, 23, 45, 50, 13, 38, 33, 6, 6, 7, 4, 4, 2, 1, 3, 2, 5, 8, + 7, 8, 9, 3, 11, 21, 9, 13, 1, 3, 10, 6, 7, 1, 2, 2, 18, 5, 5, 1, 9, 9, 2, 68, 9, 19, + 13, 2, 5, 1, 4, 4, 7, 4, 13, 3, 9, 10, 21, 17, 3, 26, 2, 1, 5, 2, 4, 5, 4, 1, 7, 4, + 7, 3, 4, 2, 1, 6, 1, 1, 20, 4, 1, 9, 2, 2, 1, 3, 3, 2, 3, 2, 1, 1, 1, 20, 2, 3, + 1, 6, 2, 3, 6, 2, 4, 8, 1, 3, 2, 10, 3, 5, 3, 4, 4, 3, 4, 16, 1, 6, 1, 10, 2, 4, + 2, 1, 1, 2, 10, 11, 2, 2, 3, 1, 24, 31, 4, 10, 10, 2, 5, 12, 16, 164, 15, 4, 16, 7, 9, 15, + 19, 17, 1, 2, 1, 1, 5, 1, 1, 1, 1, 1, 3, 1, 4, 3, 1, 3, 1, 3, 1, 2, 1, 1, 3, 3, + 7, 2, 8, 1, 2, 2, 2, 1, 3, 4, 3, 7, 8, 12, 92, 2, 10, 3, 1, 3, 14, 5, 25, 16, 42, 4, + 7, 7, 4, 2, 21, 5, 27, 26, 27, 21, 25, 30, 31, 2, 1, 5, 13, 3, 22, 5, 6, 6, 11, 9, 12, 1, + 5, 9, 7, 5, 5, 22, 60, 3, 5, 13, 1, 1, 8, 1, 1, 3, 3, 2, 1, 9, 3, 3, 18, 4, 1, 2, + 3, 7, 6, 3, 1, 2, 3, 9, 1, 3, 1, 3, 2, 1, 3, 1, 1, 1, 2, 1, 11, 3, 1, 6, 9, 1, + 3, 2, 3, 1, 2, 1, 5, 1, 1, 4, 3, 4, 1, 2, 2, 4, 4, 1, 7, 2, 1, 2, 2, 3, 5, 13, + 18, 3, 4, 14, 9, 9, 4, 16, 3, 7, 5, 8, 2, 6, 48, 28, 3, 1, 1, 4, 2, 14, 8, 2, 9, 2, + 1, 15, 2, 4, 3, 2, 10, 16, 12, 8, 7, 1, 1, 3, 1, 1, 1, 2, 7, 4, 1, 6, 4, 38, 39, 16, + 23, 7, 15, 15, 3, 2, 12, 7, 21, 37, 27, 6, 5, 4, 8, 2, 10, 8, 8, 6, 5, 1, 2, 1, 3, 24, + 1, 16, 17, 9, 23, 10, 17, 6, 1, 51, 55, 44, 13, 294, 9, 3, 6, 2, 4, 2, 2, 15, 1, 1, 1, 13, + 21, 17, 68, 14, 8, 9, 4, 1, 4, 9, 3, 11, 7, 1, 1, 1, 5, 6, 3, 2, 1, 1, 1, 2, 3, 8, + 1, 2, 2, 4, 1, 5, 5, 2, 1, 4, 3, 7, 13, 4, 1, 4, 1, 3, 1, 1, 1, 5, 5, 10, 1, 6, + 1, 5, 2, 1, 5, 2, 4, 1, 4, 5, 7, 3, 18, 2, 9, 11, 32, 4, 3, 3, 2, 4, 7, 11, 16, 9, + 11, 8, 13, 38, 32, 8, 4, 2, 1, 1, 2, 1, 2, 4, 4, 1, 1, 1, 4, 1, 21, 3, 11, 1, 16, 1, + 1, 6, 1, 3, 2, 4, 9, 8, 57, 7, 44, 1, 3, 3, 13, 3, 10, 1, 1, 7, 5, 2, 7, 21, 47, 63, + 3, 15, 4, 7, 1, 16, 1, 1, 2, 8, 2, 3, 42, 15, 4, 1, 29, 7, 22, 10, 3, 78, 16, 12, 20, 18, + 4, 67, 11, 5, 1, 3, 15, 6, 21, 31, 32, 27, 18, 13, 71, 35, 5, 142, 4, 10, 1, 2, 50, 19, 33, 16, + 35, 37, 16, 19, 27, 7, 1, 133, 19, 1, 4, 8, 7, 20, 1, 4, 4, 1, 10, 3, 1, 6, 1, 2, 51, 5, + 40, 15, 24, 43, 22928, 11, 1, 13, 154, 70, 3, 1, 1, 7, 4, 10, 1, 2, 1, 1, 2, 1, 2, 1, 2, 2, + 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, + 3, 2, 1, 1, 1, 1, 2, 1, 1, }; static ImWchar base_ranges[] = // not zero-terminated - { - 0x0020, 0x00FF, // Basic Latin + Latin Supplement - 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana - 0x31F0, 0x31FF, // Katakana Phonetic Extensions - 0xFF00, 0xFFEF, // Half-width characters - 0xFFFD, 0xFFFD // Invalid - }; - static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 }; + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana + 0x31F0, 0x31FF, // Katakana Phonetic Extensions + 0xFF00, 0xFFEF, // Half-width characters + 0xFFFD, 0xFFFD // Invalid + }; + static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { + 0}; if (!full_ranges[0]) { memcpy(full_ranges, base_ranges, sizeof(base_ranges)); - UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges)); + UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), + full_ranges + IM_ARRAYSIZE(base_ranges)); } return &full_ranges[0]; } -const ImWchar* ImFontAtlas::GetGlyphRangesCyrillic() +const ImWchar *ImFontAtlas::GetGlyphRangesCyrillic() { - static const ImWchar ranges[] = - { + static const ImWchar ranges[] = { 0x0020, 0x00FF, // Basic Latin + Latin Supplement 0x0400, 0x052F, // Cyrillic + Cyrillic Supplement 0x2DE0, 0x2DFF, // Cyrillic Extended-A @@ -4936,10 +5577,9 @@ const ImWchar* ImFontAtlas::GetGlyphRangesCyrillic() return &ranges[0]; } -const ImWchar* ImFontAtlas::GetGlyphRangesThai() +const ImWchar *ImFontAtlas::GetGlyphRangesThai() { - static const ImWchar ranges[] = - { + static const ImWchar ranges[] = { 0x0020, 0x00FF, // Basic Latin 0x2010, 0x205E, // Punctuations 0x0E00, 0x0E7F, // Thai @@ -4948,19 +5588,12 @@ const ImWchar* ImFontAtlas::GetGlyphRangesThai() return &ranges[0]; } -const ImWchar* ImFontAtlas::GetGlyphRangesVietnamese() +const ImWchar *ImFontAtlas::GetGlyphRangesVietnamese() { - static const ImWchar ranges[] = - { + static const ImWchar ranges[] = { 0x0020, 0x00FF, // Basic Latin - 0x0102, 0x0103, - 0x0110, 0x0111, - 0x0128, 0x0129, - 0x0168, 0x0169, - 0x01A0, 0x01A1, - 0x01AF, 0x01B0, - 0x1EA0, 0x1EF9, - 0, + 0x0102, 0x0103, 0x0110, 0x0111, 0x0128, 0x0129, 0x0168, 0x0169, + 0x01A0, 0x01A1, 0x01AF, 0x01B0, 0x1EA0, 0x1EF9, 0, }; return &ranges[0]; } @@ -4970,7 +5603,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesVietnamese() // [SECTION] ImFontGlyphRangesBuilder //----------------------------------------------------------------------------- -void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end) +void ImFontGlyphRangesBuilder::AddText(const char *text, const char *text_end) { while (text_end ? (text < text_end) : *text) { @@ -4983,14 +5616,14 @@ void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end) } } -void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges) +void ImFontGlyphRangesBuilder::AddRanges(const ImWchar *ranges) { for (; ranges[0]; ranges += 2) for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560 AddChar((ImWchar)c); } -void ImFontGlyphRangesBuilder::BuildRanges(ImVector* out_ranges) +void ImFontGlyphRangesBuilder::BuildRanges(ImVector *out_ranges) { const int max_codepoint = IM_UNICODE_CODEPOINT_MAX; for (int n = 0; n <= max_codepoint; n++) @@ -5040,7 +5673,7 @@ ImFont::~ImFont() void ImFont::ClearOutputData() { - if (ImFontAtlas* atlas = ContainerAtlas) + if (ImFontAtlas *atlas = ContainerAtlas) ImFontAtlasFontDiscardBakes(atlas, this, 0); FallbackChar = EllipsisChar = 0; memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap)); @@ -5060,20 +5693,23 @@ bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last) return true; } -// x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero. -// Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis). -// - 'src' is not necessarily == 'this->Sources' because multiple source fonts+configs can be used to build one target font. -ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, const ImFontGlyph* in_glyph) +// x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly +// close to zero. Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format +// (0.0..1.0 on each texture axis). +// - 'src' is not necessarily == 'this->Sources' because multiple source fonts+configs can be used to build one target +// font. +ImFontGlyph *ImFontAtlasBakedAddFontGlyph(ImFontAtlas *atlas, ImFontBaked *baked, ImFontConfig *src, + const ImFontGlyph *in_glyph) { int glyph_idx = baked->Glyphs.Size; baked->Glyphs.push_back(*in_glyph); - ImFontGlyph* glyph = &baked->Glyphs[glyph_idx]; + ImFontGlyph *glyph = &baked->Glyphs[glyph_idx]; IM_ASSERT(baked->Glyphs.Size < 0xFFFE); // IndexLookup[] hold 16-bit values and -1/-2 are reserved. // Set UV from packed rectangle if (glyph->PackId != ImFontAtlasRectId_Invalid) { - ImTextureRect* r = ImFontAtlasPackGetRect(atlas, glyph->PackId); + ImTextureRect *r = ImFontAtlasPackGetRect(atlas, glyph->PackId); IM_ASSERT(glyph->U0 == 0.0f && glyph->V0 == 0.0f && glyph->U1 == 0.0f && glyph->V1 == 0.0f); glyph->U0 = (r->x) * atlas->TexUvScale.x; glyph->V0 = (r->y) * atlas->TexUvScale.y; @@ -5087,10 +5723,12 @@ ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked // Clamp & recenter if needed const float ref_size = baked->ContainerFont->Sources[0]->SizePixels; const float offsets_scale = (ref_size != 0.0f) ? (baked->Size / ref_size) : 1.0f; - float advance_x = ImClamp(glyph->AdvanceX, src->GlyphMinAdvanceX * offsets_scale, src->GlyphMaxAdvanceX * offsets_scale); + float advance_x = + ImClamp(glyph->AdvanceX, src->GlyphMinAdvanceX * offsets_scale, src->GlyphMaxAdvanceX * offsets_scale); if (advance_x != glyph->AdvanceX) { - float char_off_x = src->PixelSnapH ? ImTrunc((advance_x - glyph->AdvanceX) * 0.5f) : (advance_x - glyph->AdvanceX) * 0.5f; + float char_off_x = + src->PixelSnapH ? ImTrunc((advance_x - glyph->AdvanceX) * 0.5f) : (advance_x - glyph->AdvanceX) * 0.5f; glyph->X0 += char_off_x; glyph->X1 += char_off_x; } @@ -5117,12 +5755,17 @@ ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked } // Copy to texture, post-process and queue update for backend -void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImFontGlyph* glyph, ImTextureRect* r, const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch) +void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas *atlas, ImFontBaked *baked, ImFontConfig *src, ImFontGlyph *glyph, + ImTextureRect *r, const unsigned char *src_pixels, ImTextureFormat src_fmt, + int src_pitch) { - ImTextureData* tex = atlas->TexData; + ImTextureData *tex = atlas->TexData; IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height); - ImFontAtlasTextureBlockConvert(src_pixels, src_fmt, src_pitch, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), r->w, r->h); - ImFontAtlasPostProcessData pp_data = { atlas, baked->ContainerFont, src, baked, glyph, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), r->w, r->h }; + ImFontAtlasTextureBlockConvert(src_pixels, src_fmt, src_pitch, tex->GetPixelsAt(r->x, r->y), tex->Format, + tex->GetPitch(), r->w, r->h); + ImFontAtlasPostProcessData pp_data = { + atlas, baked->ContainerFont, src, baked, glyph, tex->GetPixelsAt(r->x, r->y), + tex->Format, tex->GetPitch(), r->w, r->h}; ImFontAtlasTextureBlockPostProcess(&pp_data); ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); } @@ -5133,65 +5776,70 @@ void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint) } // Find glyph, load if necessary, return fallback if missing -ImFontGlyph* ImFontBaked::FindGlyph(ImWchar c) +ImFontGlyph *ImFontBaked::FindGlyph(ImWchar c) { - if (c < (size_t)IndexLookup.Size) IM_LIKELY - { - const int i = (int)IndexLookup.Data[c]; - if (i == IM_FONTGLYPH_INDEX_NOT_FOUND) - return &Glyphs.Data[FallbackGlyphIndex]; - if (i != IM_FONTGLYPH_INDEX_UNUSED) - return &Glyphs.Data[i]; - } - ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c); + if (c < (size_t)IndexLookup.Size) + IM_LIKELY + { + const int i = (int)IndexLookup.Data[c]; + if (i == IM_FONTGLYPH_INDEX_NOT_FOUND) + return &Glyphs.Data[FallbackGlyphIndex]; + if (i != IM_FONTGLYPH_INDEX_UNUSED) + return &Glyphs.Data[i]; + } + ImFontGlyph *glyph = ImFontBaked_BuildLoadGlyph(this, c); return glyph ? glyph : &Glyphs.Data[FallbackGlyphIndex]; } // Attempt to load but when missing, return NULL instead of FallbackGlyph -ImFontGlyph* ImFontBaked::FindGlyphNoFallback(ImWchar c) +ImFontGlyph *ImFontBaked::FindGlyphNoFallback(ImWchar c) { - if (c < (size_t)IndexLookup.Size) IM_LIKELY - { - const int i = (int)IndexLookup.Data[c]; - if (i == IM_FONTGLYPH_INDEX_NOT_FOUND) - return NULL; - if (i != IM_FONTGLYPH_INDEX_UNUSED) - return &Glyphs.Data[i]; - } - LockLoadingFallback = true; // This is actually a rare call, not done in hot-loop, so we prioritize not adding extra cruft to ImFontBaked_BuildLoadGlyph() call sites. - ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c); + if (c < (size_t)IndexLookup.Size) + IM_LIKELY + { + const int i = (int)IndexLookup.Data[c]; + if (i == IM_FONTGLYPH_INDEX_NOT_FOUND) + return NULL; + if (i != IM_FONTGLYPH_INDEX_UNUSED) + return &Glyphs.Data[i]; + } + LockLoadingFallback = true; // This is actually a rare call, not done in hot-loop, so we prioritize not adding extra + // cruft to ImFontBaked_BuildLoadGlyph() call sites. + ImFontGlyph *glyph = ImFontBaked_BuildLoadGlyph(this, c); LockLoadingFallback = false; return glyph; } bool ImFontBaked::IsGlyphLoaded(ImWchar c) { - if (c < (size_t)IndexLookup.Size) IM_LIKELY - { - const int i = (int)IndexLookup.Data[c]; - if (i == IM_FONTGLYPH_INDEX_NOT_FOUND) - return false; - if (i != IM_FONTGLYPH_INDEX_UNUSED) - return true; - } + if (c < (size_t)IndexLookup.Size) + IM_LIKELY + { + const int i = (int)IndexLookup.Data[c]; + if (i == IM_FONTGLYPH_INDEX_NOT_FOUND) + return false; + if (i != IM_FONTGLYPH_INDEX_UNUSED) + return true; + } return false; } // This is not fast query bool ImFont::IsGlyphInFont(ImWchar c) { - ImFontAtlas* atlas = ContainerAtlas; + ImFontAtlas *atlas = ContainerAtlas; ImFontAtlas_FontHookRemapCodepoint(atlas, this, &c); - for (ImFontConfig* src : Sources) + for (ImFontConfig *src : Sources) { - const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + const ImFontLoader *loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (loader->FontSrcContainsGlyph != NULL && loader->FontSrcContainsGlyph(atlas, src, c)) return true; } return false; } -// This is manually inlined in CalcTextSizeA() and CalcWordWrapPosition(), with a non-inline call to BuildLoadGlyphGetAdvanceOrFallback(). +// This is manually inlined in CalcTextSizeA() and CalcWordWrapPosition(), with a non-inline call to +// BuildLoadGlyphGetAdvanceOrFallback(). IM_MSVC_RUNTIME_CHECKS_OFF float ImFontBaked::GetCharAdvance(ImWchar c) { @@ -5204,14 +5852,19 @@ float ImFontBaked::GetCharAdvance(ImWchar c) } // Same as BuildLoadGlyphGetAdvanceOrFallback(): - const ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c); + const ImFontGlyph *glyph = ImFontBaked_BuildLoadGlyph(this, c); return glyph ? glyph->AdvanceX : FallbackAdvanceX; } IM_MSVC_RUNTIME_CHECKS_RESTORE ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size, float rasterizer_density) { - struct { ImGuiID FontId; float BakedSize; float RasterizerDensity; } hashed_data; + struct + { + ImGuiID FontId; + float BakedSize; + float RasterizerDensity; + } hashed_data; hashed_data.FontId = font_id; hashed_data.BakedSize = baked_size; hashed_data.RasterizerDensity = rasterizer_density; @@ -5219,12 +5872,13 @@ ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size, float rasterize } // ImFontBaked pointers are valid for the entire frame but shall never be kept between frames. -ImFontBaked* ImFont::GetFontBaked(float size, float density) +ImFontBaked *ImFont::GetFontBaked(float size, float density) { - ImFontBaked* baked = LastBaked; + ImFontBaked *baked = LastBaked; // Round font size - // - ImGui::PushFontSize() will already round, but other paths calling GetFontBaked() directly also needs it (e.g. ImFontAtlasBuildPreloadAllGlyphRanges) + // - ImGui::PushFontSize() will already round, but other paths calling GetFontBaked() directly also needs it (e.g. + // ImFontAtlasBuildPreloadAllGlyphRanges) size = ImGui::GetRoundedFontSize(size); if (density < 0.0f) @@ -5232,8 +5886,8 @@ ImFontBaked* ImFont::GetFontBaked(float size, float density) if (baked && baked->Size == size && baked->RasterizerDensity == density) return baked; - ImFontAtlas* atlas = ContainerAtlas; - ImFontAtlasBuilder* builder = atlas->Builder; + ImFontAtlas *atlas = ContainerAtlas; + ImFontAtlasBuilder *builder = atlas->Builder; baked = ImFontAtlasBakedGetOrAdd(atlas, this, size, density); if (baked == NULL) return NULL; @@ -5242,15 +5896,15 @@ ImFontBaked* ImFont::GetFontBaked(float size, float density) return baked; } -ImFontBaked* ImFontAtlasBakedGetOrAdd(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density) +ImFontBaked *ImFontAtlasBakedGetOrAdd(ImFontAtlas *atlas, ImFont *font, float font_size, float font_rasterizer_density) { // FIXME-NEWATLAS: Design for picking a nearest size based on some criteria? // FIXME-NEWATLAS: Altering font density won't work right away. IM_ASSERT(font_size > 0.0f && font_rasterizer_density > 0.0f); ImGuiID baked_id = ImFontAtlasBakedGetId(font->FontId, font_size, font_rasterizer_density); - ImFontAtlasBuilder* builder = atlas->Builder; - ImFontBaked** p_baked_in_map = (ImFontBaked**)builder->BakedMap.GetVoidPtrRef(baked_id); - ImFontBaked* baked = *p_baked_in_map; + ImFontAtlasBuilder *builder = atlas->Builder; + ImFontBaked **p_baked_in_map = (ImFontBaked **)builder->BakedMap.GetVoidPtrRef(baked_id); + ImFontBaked *baked = *p_baked_in_map; if (baked != NULL) { IM_ASSERT(baked->Size == font_size && baked->ContainerFont == font && baked->BakedId == baked_id); @@ -5266,7 +5920,11 @@ ImFontBaked* ImFontAtlasBakedGetOrAdd(ImFontAtlas* atlas, ImFont* font, float fo return baked; if (atlas->Locked) { - IM_ASSERT(!atlas->Locked && "Cannot use dynamic font size with a locked ImFontAtlas!"); // Locked because rendering backend does not support ImGuiBackendFlags_RendererHasTextures! + IM_ASSERT( + !atlas->Locked && + "Cannot use dynamic font size with a locked ImFontAtlas!"); // Locked because rendering backend does not + // support + // ImGuiBackendFlags_RendererHasTextures! return NULL; } } @@ -5278,7 +5936,7 @@ ImFontBaked* ImFontAtlasBakedGetOrAdd(ImFontAtlas* atlas, ImFont* font, float fo } // Trim trailing space and find beginning of next line -static inline const char* CalcWordWrapNextLineStartA(const char* text, const char* text_end) +static inline const char *CalcWordWrapNextLineStartA(const char *text, const char *text_end) { while (text < text_end && ImCharIsBlankA(*text)) text++; @@ -5288,9 +5946,11 @@ static inline const char* CalcWordWrapNextLineStartA(const char* text, const cha } // Simple word-wrapping for English, not full-featured. Please submit failing cases! -// This will return the next location to wrap from. If no wrapping if necessary, this will fast-forward to e.g. text_end. -// FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.) -const char* ImFont::CalcWordWrapPosition(float size, const char* text, const char* text_end, float wrap_width) +// This will return the next location to wrap from. If no wrapping if necessary, this will fast-forward to e.g. +// text_end. +// FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible +// support for punctuations, support for Unicode punctuations, etc.) +const char *ImFont::CalcWordWrapPosition(float size, const char *text, const char *text_end, float wrap_width) { // For references, possible wrap point marked with ^ // "aaa bbb, ccc,ddd. eee fff. ggg!" @@ -5304,7 +5964,7 @@ const char* ImFont::CalcWordWrapPosition(float size, const char* text, const cha // Cut words that cannot possibly fit within one line. // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish" - ImFontBaked* baked = GetFontBaked(size); + ImFontBaked *baked = GetFontBaked(size); const float scale = size / baked->Size; float line_width = 0.0f; @@ -5312,16 +5972,16 @@ const char* ImFont::CalcWordWrapPosition(float size, const char* text, const cha float blank_width = 0.0f; wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters - const char* word_end = text; - const char* prev_word_end = NULL; + const char *word_end = text; + const char *prev_word_end = NULL; bool inside_word = true; - const char* s = text; + const char *s = text; IM_ASSERT(text_end != NULL); while (s < text_end) { unsigned int c = (unsigned int)*s; - const char* next_s; + const char *next_s; if (c < 0x80) next_s = s + 1; else @@ -5374,7 +6034,8 @@ const char* ImFont::CalcWordWrapPosition(float size, const char* text, const cha } // Allow wrapping after punctuation. - inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"' && c != 0x3001 && c != 0x3002); + inside_word = + (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"' && c != 0x3001 && c != 0x3002); } // We ignore blank width at the end of the line (they can be skipped) @@ -5396,27 +6057,29 @@ const char* ImFont::CalcWordWrapPosition(float size, const char* text, const cha return s; } -ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) +ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char *text_begin, + const char *text_end, const char **remaining) { if (!text_end) text_end = text_begin + ImStrlen(text_begin); // FIXME-OPT: Need to avoid this. const float line_height = size; - ImFontBaked* baked = GetFontBaked(size); + ImFontBaked *baked = GetFontBaked(size); const float scale = size / baked->Size; ImVec2 text_size = ImVec2(0, 0); float line_width = 0.0f; const bool word_wrap_enabled = (wrap_width > 0.0f); - const char* word_wrap_eol = NULL; + const char *word_wrap_eol = NULL; - const char* s = text_begin; + const char *s = text_begin; while (s < text_end) { if (word_wrap_enabled) { - // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. + // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not + // intrusive for what's essentially an uncommon feature. if (!word_wrap_eol) word_wrap_eol = CalcWordWrapPosition(size, s, text_end, wrap_width - line_width); @@ -5433,7 +6096,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons } // Decode and advance source - const char* prev_s = s; + const char *prev_s = s; unsigned int c = (unsigned int)*s; if (c < 0x80) s += 1; @@ -5481,10 +6144,11 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons } // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. -void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c, const ImVec4* cpu_fine_clip) +void ImFont::RenderChar(ImDrawList *draw_list, float size, const ImVec2 &pos, ImU32 col, ImWchar c, + const ImVec4 *cpu_fine_clip) { - ImFontBaked* baked = GetFontBaked(size); - const ImFontGlyph* glyph = baked->FindGlyph(c); + ImFontBaked *baked = GetFontBaked(size); + const ImFontGlyph *glyph = baked->FindGlyph(c); if (!glyph || !glyph->Visible) return; if (glyph->Colored) @@ -5505,13 +6169,30 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, Im float v2 = glyph->V1; // Always CPU fine clip. Code extracted from RenderText(). - // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads. + // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis + // aligned quads. if (cpu_fine_clip != NULL) { - if (x1 < cpu_fine_clip->x) { u1 = u1 + (1.0f - (x2 - cpu_fine_clip->x) / (x2 - x1)) * (u2 - u1); x1 = cpu_fine_clip->x; } - if (y1 < cpu_fine_clip->y) { v1 = v1 + (1.0f - (y2 - cpu_fine_clip->y) / (y2 - y1)) * (v2 - v1); y1 = cpu_fine_clip->y; } - if (x2 > cpu_fine_clip->z) { u2 = u1 + ((cpu_fine_clip->z - x1) / (x2 - x1)) * (u2 - u1); x2 = cpu_fine_clip->z; } - if (y2 > cpu_fine_clip->w) { v2 = v1 + ((cpu_fine_clip->w - y1) / (y2 - y1)) * (v2 - v1); y2 = cpu_fine_clip->w; } + if (x1 < cpu_fine_clip->x) + { + u1 = u1 + (1.0f - (x2 - cpu_fine_clip->x) / (x2 - x1)) * (u2 - u1); + x1 = cpu_fine_clip->x; + } + if (y1 < cpu_fine_clip->y) + { + v1 = v1 + (1.0f - (y2 - cpu_fine_clip->y) / (y2 - y1)) * (v2 - v1); + y1 = cpu_fine_clip->y; + } + if (x2 > cpu_fine_clip->z) + { + u2 = u1 + ((cpu_fine_clip->z - x1) / (x2 - x1)) * (u2 - u1); + x2 = cpu_fine_clip->z; + } + if (y2 > cpu_fine_clip->w) + { + v2 = v1 + ((cpu_fine_clip->w - y1) / (y2 - y1)) * (v2 - v1); + y2 = cpu_fine_clip->w; + } if (y1 >= y2) return; } @@ -5520,7 +6201,8 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, Im } // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. -void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) +void ImFont::RenderText(ImDrawList *draw_list, float size, const ImVec2 &pos, ImU32 col, const ImVec4 &clip_rect, + const char *text_begin, const char *text_end, float wrap_width, bool cpu_fine_clip) { // Align to be pixel perfect begin: @@ -5530,26 +6212,27 @@ begin: return; if (!text_end) - text_end = text_begin + ImStrlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. + text_end = text_begin + ImStrlen(text_begin); // ImGui:: functions generally already provides a valid text_end, + // so this is merely to handle direct calls. const float line_height = size; - ImFontBaked* baked = GetFontBaked(size); + ImFontBaked *baked = GetFontBaked(size); const float scale = size / baked->Size; const float origin_x = x; const bool word_wrap_enabled = (wrap_width > 0.0f); // Fast-forward to first visible line - const char* s = text_begin; + const char *s = text_begin; if (y + line_height < clip_rect.y) while (y + line_height < clip_rect.y && s < text_end) { - const char* line_end = (const char*)ImMemchr(s, '\n', text_end - s); + const char *line_end = (const char *)ImMemchr(s, '\n', text_end - s); if (word_wrap_enabled) { // FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPosition(). - // If the specs for CalcWordWrapPosition() were reworked to optionally return on \n we could combine both. - // However it is still better than nothing performing the fast-forward! + // If the specs for CalcWordWrapPosition() were reworked to optionally return on \n we could combine + // both. However it is still better than nothing performing the fast-forward! s = CalcWordWrapPosition(size, s, line_end ? line_end : text_end, wrap_width); s = CalcWordWrapNextLineStartA(s, text_end); } @@ -5561,14 +6244,15 @@ begin: } // For large text, scan for the last visible line in order to avoid over-reserving in the call to PrimReserve() - // Note that very large horizontal line will still be affected by the issue (e.g. a one megabyte string buffer without a newline will likely crash atm) + // Note that very large horizontal line will still be affected by the issue (e.g. a one megabyte string buffer + // without a newline will likely crash atm) if (text_end - s > 10000 && !word_wrap_enabled) { - const char* s_end = s; + const char *s_end = s; float y_end = y; while (y_end < clip_rect.w && s_end < text_end) { - s_end = (const char*)ImMemchr(s_end, '\n', text_end - s_end); + s_end = (const char *)ImMemchr(s_end, '\n', text_end - s_end); s_end = s_end ? s_end + 1 : text_end; y_end += line_height; } @@ -5583,18 +6267,19 @@ begin: const int idx_count_max = (int)(text_end - s) * 6; const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max; draw_list->PrimReserve(idx_count_max, vtx_count_max); - ImDrawVert* vtx_write = draw_list->_VtxWritePtr; - ImDrawIdx* idx_write = draw_list->_IdxWritePtr; + ImDrawVert *vtx_write = draw_list->_VtxWritePtr; + ImDrawIdx *idx_write = draw_list->_IdxWritePtr; unsigned int vtx_index = draw_list->_VtxCurrentIdx; const ImU32 col_untinted = col | ~IM_COL32_A_MASK; - const char* word_wrap_eol = NULL; + const char *word_wrap_eol = NULL; while (s < text_end) { if (word_wrap_enabled) { - // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. + // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not + // intrusive for what's essentially an uncommon feature. if (!word_wrap_eol) word_wrap_eol = CalcWordWrapPosition(size, s, text_end, wrap_width - (x - origin_x)); @@ -5631,14 +6316,15 @@ begin: continue; } - const ImFontGlyph* glyph = baked->FindGlyph((ImWchar)c); - //if (glyph == NULL) - // continue; + const ImFontGlyph *glyph = baked->FindGlyph((ImWchar)c); + // if (glyph == NULL) + // continue; float char_width = glyph->AdvanceX * scale; if (glyph->Visible) { - // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w + // We don't do a second finer clipping test on the Y axis as we've already skipped anything before + // clip_rect.y and exit once we pass clip_rect.w float x1 = x + glyph->X0 * scale; float x2 = x + glyph->X1 * scale; float y1 = y + glyph->Y0 * scale; @@ -5651,7 +6337,8 @@ begin: float u2 = glyph->U1; float v2 = glyph->V1; - // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads. + // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for + // axis aligned quads. if (cpu_fine_clip) { if (x1 < clip_rect.x) @@ -5684,14 +6371,35 @@ begin: // Support for untinted glyphs ImU32 glyph_col = glyph->Colored ? col_untinted : col; - // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here: + // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. + // Inlined here: { - vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = glyph_col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1; - vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = glyph_col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1; - vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = glyph_col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2; - vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = glyph_col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2; - idx_write[0] = (ImDrawIdx)(vtx_index); idx_write[1] = (ImDrawIdx)(vtx_index + 1); idx_write[2] = (ImDrawIdx)(vtx_index + 2); - idx_write[3] = (ImDrawIdx)(vtx_index); idx_write[4] = (ImDrawIdx)(vtx_index + 2); idx_write[5] = (ImDrawIdx)(vtx_index + 3); + vtx_write[0].pos.x = x1; + vtx_write[0].pos.y = y1; + vtx_write[0].col = glyph_col; + vtx_write[0].uv.x = u1; + vtx_write[0].uv.y = v1; + vtx_write[1].pos.x = x2; + vtx_write[1].pos.y = y1; + vtx_write[1].col = glyph_col; + vtx_write[1].uv.x = u2; + vtx_write[1].uv.y = v1; + vtx_write[2].pos.x = x2; + vtx_write[2].pos.y = y2; + vtx_write[2].col = glyph_col; + vtx_write[2].uv.x = u2; + vtx_write[2].uv.y = v2; + vtx_write[3].pos.x = x1; + vtx_write[3].pos.y = y2; + vtx_write[3].col = glyph_col; + vtx_write[3].uv.x = u1; + vtx_write[3].uv.y = v2; + idx_write[0] = (ImDrawIdx)(vtx_index); + idx_write[1] = (ImDrawIdx)(vtx_index + 1); + idx_write[2] = (ImDrawIdx)(vtx_index + 2); + idx_write[3] = (ImDrawIdx)(vtx_index); + idx_write[4] = (ImDrawIdx)(vtx_index + 2); + idx_write[5] = (ImDrawIdx)(vtx_index + 3); vtx_write += 4; vtx_index += 4; idx_write += 6; @@ -5701,7 +6409,8 @@ begin: x += char_width; } - // Edge case: calling RenderText() with unloaded glyphs triggering texture change. It doesn't happen via ImGui:: calls because CalcTextSize() is always used. + // Edge case: calling RenderText() with unloaded glyphs triggering texture change. It doesn't happen via ImGui:: + // calls because CalcTextSize() is always used. if (cmd_count != draw_list->CmdBuffer.Size) { IM_ASSERT(draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount == 0); @@ -5709,8 +6418,8 @@ begin: draw_list->PrimUnreserve(idx_count_max, vtx_count_max); draw_list->AddDrawCmd(); goto begin; - //RenderText(draw_list, size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip); // FIXME-OPT: Would a 'goto begin' be better for code-gen? - //return; + // RenderText(draw_list, size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip); // + // FIXME-OPT: Would a 'goto begin' be better for code-gen? return; } // Give back unused vertices (clipped ones, blanks) ~ this is essentially a PrimUnreserve() action. @@ -5737,8 +6446,9 @@ begin: // - RenderColorRectWithAlphaCheckerboard() //----------------------------------------------------------------------------- -// Render an arrow aimed to be aligned with text (p_min is a position in the same space text would be positioned). To e.g. denote expanded/collapsed state -void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale) +// Render an arrow aimed to be aligned with text (p_min is a position in the same space text would be positioned). To +// e.g. denote expanded/collapsed state +void ImGui::RenderArrow(ImDrawList *draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale) { const float h = draw_list->_Data->FontSize * 1.00f; float r = h * 0.40f * scale; @@ -5749,14 +6459,16 @@ void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir d { case ImGuiDir_Up: case ImGuiDir_Down: - if (dir == ImGuiDir_Up) r = -r; + if (dir == ImGuiDir_Up) + r = -r; a = ImVec2(+0.000f, +0.750f) * r; b = ImVec2(-0.866f, -0.750f) * r; c = ImVec2(+0.866f, -0.750f) * r; break; case ImGuiDir_Left: case ImGuiDir_Right: - if (dir == ImGuiDir_Left) r = -r; + if (dir == ImGuiDir_Left) + r = -r; a = ImVec2(+0.750f, +0.000f) * r; b = ImVec2(-0.750f, +0.866f) * r; c = ImVec2(-0.750f, -0.866f) * r; @@ -5769,13 +6481,13 @@ void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir d draw_list->AddTriangleFilled(center + a, center + b, center + c, col); } -void ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col) +void ImGui::RenderBullet(ImDrawList *draw_list, ImVec2 pos, ImU32 col) { // FIXME-OPT: This should be baked in font. draw_list->AddCircleFilled(pos, draw_list->_Data->FontSize * 0.20f, col, 8); } -void ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz) +void ImGui::RenderCheckMark(ImDrawList *draw_list, ImVec2 pos, ImU32 col, float sz) { float thickness = ImMax(sz / 5.0f, 1.0f); sz -= thickness * 0.5f; @@ -5790,29 +6502,48 @@ void ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float draw_list->PathStroke(col, 0, thickness); } -// Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side. -void ImGui::RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col) +// Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on +// each side. +void ImGui::RenderArrowPointingAt(ImDrawList *draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col) { switch (direction) { - case ImGuiDir_Left: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), pos, col); return; - case ImGuiDir_Right: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), pos, col); return; - case ImGuiDir_Up: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), pos, col); return; - case ImGuiDir_Down: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), pos, col); return; - case ImGuiDir_None: case ImGuiDir_COUNT: break; // Fix warnings + case ImGuiDir_Left: + draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), + ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), pos, col); + return; + case ImGuiDir_Right: + draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), + ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), pos, col); + return; + case ImGuiDir_Up: + draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), + ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), pos, col); + return; + case ImGuiDir_Down: + draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), + ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), pos, col); + return; + case ImGuiDir_None: + case ImGuiDir_COUNT: + break; // Fix warnings } } static inline float ImAcos01(float x) { - if (x <= 0.0f) return IM_PI * 0.5f; - if (x >= 1.0f) return 0.0f; + if (x <= 0.0f) + return IM_PI * 0.5f; + if (x >= 1.0f) + return 0.0f; return ImAcos(x); - //return (-0.69813170079773212f * x * x - 0.87266462599716477f) * x + 1.5707963267948966f; // Cheap approximation, may be enough for what we do. + // return (-0.69813170079773212f * x * x - 0.87266462599716477f) * x + 1.5707963267948966f; // Cheap approximation, + // may be enough for what we do. } // FIXME: Cleanup and move code to ImDrawList. -void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding) +void ImGui::RenderRectFilledRangeH(ImDrawList *draw_list, const ImRect &rect, ImU32 col, float x_start_norm, + float x_end_norm, float rounding) { if (x_end_norm == x_start_norm) return; @@ -5827,11 +6558,13 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im return; } - rounding = ImClamp(ImMin((rect.Max.x - rect.Min.x) * 0.5f, (rect.Max.y - rect.Min.y) * 0.5f) - 1.0f, 0.0f, rounding); + rounding = + ImClamp(ImMin((rect.Max.x - rect.Min.x) * 0.5f, (rect.Max.y - rect.Min.y) * 0.5f) - 1.0f, 0.0f, rounding); const float inv_rounding = 1.0f / rounding; const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding); const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding); - const float half_pi = IM_PI * 0.5f; // We will == compare to this because we know this is the exact value ImAcos01 can return. + const float half_pi = + IM_PI * 0.5f; // We will == compare to this because we know this is the exact value ImAcos01 can return. const float x0 = ImMax(p0.x, rect.Min.x + rounding); if (arc0_b == arc0_e) { @@ -5872,27 +6605,51 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im draw_list->PathFillConvex(col); } -void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, const ImRect& inner, ImU32 col, float rounding) +void ImGui::RenderRectFilledWithHole(ImDrawList *draw_list, const ImRect &outer, const ImRect &inner, ImU32 col, + float rounding) { const bool fill_L = (inner.Min.x > outer.Min.x); 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, ImDrawFlags_RoundCornersNone | (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, ImDrawFlags_RoundCornersNone | (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, ImDrawFlags_RoundCornersNone | (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, ImDrawFlags_RoundCornersNone | (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); + if (fill_L) + draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, + ImDrawFlags_RoundCornersNone | (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, + ImDrawFlags_RoundCornersNone | (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, + ImDrawFlags_RoundCornersNone | (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, + ImDrawFlags_RoundCornersNone | (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. +// 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, ImDrawFlags 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_; @@ -5914,11 +6671,25 @@ void ImGui::RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p if (x2 <= x1) continue; 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; } + 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); + 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); } } @@ -5950,37 +6721,66 @@ static void stb__match(const unsigned char *data, unsigned int length) { // INVERSE of memmove... write each byte before copying the next... IM_ASSERT(stb__dout + length <= stb__barrier_out_e); - if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; } - if (data < stb__barrier_out_b) { stb__dout = stb__barrier_out_e+1; return; } - while (length--) *stb__dout++ = *data++; + if (stb__dout + length > stb__barrier_out_e) + { + stb__dout += length; + return; + } + if (data < stb__barrier_out_b) + { + stb__dout = stb__barrier_out_e + 1; + return; + } + while (length--) + *stb__dout++ = *data++; } static void stb__lit(const unsigned char *data, unsigned int length) { IM_ASSERT(stb__dout + length <= stb__barrier_out_e); - if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; } - if (data < stb__barrier_in_b) { stb__dout = stb__barrier_out_e+1; return; } + if (stb__dout + length > stb__barrier_out_e) + { + stb__dout += length; + return; + } + if (data < stb__barrier_in_b) + { + stb__dout = stb__barrier_out_e + 1; + return; + } memcpy(stb__dout, data, length); stb__dout += length; } -#define stb__in2(x) ((i[x] << 8) + i[(x)+1]) -#define stb__in3(x) ((i[x] << 16) + stb__in2((x)+1)) -#define stb__in4(x) ((i[x] << 24) + stb__in3((x)+1)) +#define stb__in2(x) ((i[x] << 8) + i[(x) + 1]) +#define stb__in3(x) ((i[x] << 16) + stb__in2((x) + 1)) +#define stb__in4(x) ((i[x] << 24) + stb__in3((x) + 1)) static const unsigned char *stb_decompress_token(const unsigned char *i) { - if (*i >= 0x20) { // use fewer if's for cases that expand small - if (*i >= 0x80) stb__match(stb__dout-i[1]-1, i[0] - 0x80 + 1), i += 2; - else if (*i >= 0x40) stb__match(stb__dout-(stb__in2(0) - 0x4000 + 1), i[2]+1), i += 3; - else /* *i >= 0x20 */ stb__lit(i+1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1); - } else { // more ifs for cases that expand large, since overhead is amortized - if (*i >= 0x18) stb__match(stb__dout-(stb__in3(0) - 0x180000 + 1), i[3]+1), i += 4; - else if (*i >= 0x10) stb__match(stb__dout-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i += 5; - else if (*i >= 0x08) stb__lit(i+2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1); - else if (*i == 0x07) stb__lit(i+3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1); - else if (*i == 0x06) stb__match(stb__dout-(stb__in3(1)+1), i[4]+1), i += 5; - else if (*i == 0x04) stb__match(stb__dout-(stb__in3(1)+1), stb__in2(4)+1), i += 6; + if (*i >= 0x20) + { // use fewer if's for cases that expand small + if (*i >= 0x80) + stb__match(stb__dout - i[1] - 1, i[0] - 0x80 + 1), i += 2; + else if (*i >= 0x40) + stb__match(stb__dout - (stb__in2(0) - 0x4000 + 1), i[2] + 1), i += 3; + else /* *i >= 0x20 */ + stb__lit(i + 1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1); + } + else + { // more ifs for cases that expand large, since overhead is amortized + if (*i >= 0x18) + stb__match(stb__dout - (stb__in3(0) - 0x180000 + 1), i[3] + 1), i += 4; + else if (*i >= 0x10) + stb__match(stb__dout - (stb__in3(0) - 0x100000 + 1), stb__in2(3) + 1), i += 5; + else if (*i >= 0x08) + stb__lit(i + 2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1); + else if (*i == 0x07) + stb__lit(i + 3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1); + else if (*i == 0x06) + stb__match(stb__dout - (stb__in3(1) + 1), i[4] + 1), i += 5; + else if (*i == 0x04) + stb__match(stb__dout - (stb__in3(1) + 1), stb__in2(4) + 1), i += 6; } return i; } @@ -5992,8 +6792,10 @@ static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, uns unsigned long blocklen = buflen % 5552; unsigned long i; - while (buflen) { - for (i=0; i + 7 < blocklen; i += 8) { + while (buflen) + { + for (i = 0; i + 7 < blocklen; i += 8) + { s1 += buffer[0], s2 += s1; s1 += buffer[1], s2 += s1; s1 += buffer[2], s2 += s1; @@ -6018,8 +6820,10 @@ static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, uns static unsigned int stb_decompress(unsigned char *output, const unsigned char *i, unsigned int /*length*/) { - if (stb__in4(0) != 0x57bC0000) return 0; - if (stb__in4(4) != 0) return 0; // error! stream is > 4GB + if (stb__in4(0) != 0x57bC0000) + return 0; + if (stb__in4(4) != 0) + return 0; // error! stream is > 4GB const unsigned int olen = stb_decompress_length(i); stb__barrier_in_b = i; stb__barrier_out_e = output + olen; @@ -6027,17 +6831,23 @@ static unsigned int stb_decompress(unsigned char *output, const unsigned char *i i += 16; stb__dout = output; - for (;;) { + for (;;) + { const unsigned char *old_i = i; i = stb_decompress_token(i); - if (i == old_i) { - if (*i == 0x05 && i[1] == 0xfa) { + if (i == old_i) + { + if (*i == 0x05 && i[1] == 0xfa) + { IM_ASSERT(stb__dout == output + olen); - if (stb__dout != output + olen) return 0; - if (stb_adler32(1, output, olen) != (unsigned int) stb__in4(2)) + if (stb__dout != output + olen) + return 0; + if (stb_adler32(1, output, olen) != (unsigned int)stb__in4(2)) return 0; return olen; - } else { + } + else + { IM_ASSERT(0); /* NOTREACHED */ return 0; } @@ -6062,180 +6872,430 @@ static unsigned int stb_decompress(unsigned char *output, const unsigned char *i // File: 'ProggyClean.ttf' (41208 bytes) // Exported using binary_to_compressed_c.exe -u8 "ProggyClean.ttf" proggy_clean_ttf static const unsigned int proggy_clean_ttf_compressed_size = 9583; -static const unsigned char proggy_clean_ttf_compressed_data[9583] = -{ - 87,188,0,0,0,0,0,0,0,0,160,248,0,4,0,0,55,0,1,0,0,0,12,0,128,0,3,0,64,79,83,47,50,136,235,116,144,0,0,1,72,130,21,44,78,99,109,97,112,2,18,35,117,0,0,3,160,130,19,36,82,99,118,116, - 32,130,23,130,2,33,4,252,130,4,56,2,103,108,121,102,18,175,137,86,0,0,7,4,0,0,146,128,104,101,97,100,215,145,102,211,130,27,32,204,130,3,33,54,104,130,16,39,8,66,1,195,0,0,1,4,130, - 15,59,36,104,109,116,120,138,0,126,128,0,0,1,152,0,0,2,6,108,111,99,97,140,115,176,216,0,0,5,130,30,41,2,4,109,97,120,112,1,174,0,218,130,31,32,40,130,16,44,32,110,97,109,101,37,89, - 187,150,0,0,153,132,130,19,44,158,112,111,115,116,166,172,131,239,0,0,155,36,130,51,44,210,112,114,101,112,105,2,1,18,0,0,4,244,130,47,32,8,132,203,46,1,0,0,60,85,233,213,95,15,60, - 245,0,3,8,0,131,0,34,183,103,119,130,63,43,0,0,189,146,166,215,0,0,254,128,3,128,131,111,130,241,33,2,0,133,0,32,1,130,65,38,192,254,64,0,0,3,128,131,16,130,5,32,1,131,7,138,3,33,2, - 0,130,17,36,1,1,0,144,0,130,121,130,23,38,2,0,8,0,64,0,10,130,9,32,118,130,9,130,6,32,0,130,59,33,1,144,131,200,35,2,188,2,138,130,16,32,143,133,7,37,1,197,0,50,2,0,131,0,33,4,9,131, - 5,145,3,43,65,108,116,115,0,64,0,0,32,172,8,0,131,0,35,5,0,1,128,131,77,131,3,33,3,128,191,1,33,1,128,130,184,35,0,0,128,0,130,3,131,11,32,1,130,7,33,0,128,131,1,32,1,136,9,32,0,132, - 15,135,5,32,1,131,13,135,27,144,35,32,1,149,25,131,21,32,0,130,0,32,128,132,103,130,35,132,39,32,0,136,45,136,97,133,17,130,5,33,0,0,136,19,34,0,128,1,133,13,133,5,32,128,130,15,132, - 131,32,3,130,5,32,3,132,27,144,71,32,0,133,27,130,29,130,31,136,29,131,63,131,3,65,63,5,132,5,132,205,130,9,33,0,0,131,9,137,119,32,3,132,19,138,243,130,55,32,1,132,35,135,19,131,201, - 136,11,132,143,137,13,130,41,32,0,131,3,144,35,33,128,0,135,1,131,223,131,3,141,17,134,13,136,63,134,15,136,53,143,15,130,96,33,0,3,131,4,130,3,34,28,0,1,130,5,34,0,0,76,130,17,131, - 9,36,28,0,4,0,48,130,17,46,8,0,8,0,2,0,0,0,127,0,255,32,172,255,255,130,9,34,0,0,129,132,9,130,102,33,223,213,134,53,132,22,33,1,6,132,6,64,4,215,32,129,165,216,39,177,0,1,141,184, - 1,255,133,134,45,33,198,0,193,1,8,190,244,1,28,1,158,2,20,2,136,2,252,3,20,3,88,3,156,3,222,4,20,4,50,4,80,4,98,4,162,5,22,5,102,5,188,6,18,6,116,6,214,7,56,7,126,7,236,8,78,8,108, - 8,150,8,208,9,16,9,74,9,136,10,22,10,128,11,4,11,86,11,200,12,46,12,130,12,234,13,94,13,164,13,234,14,80,14,150,15,40,15,176,16,18,16,116,16,224,17,82,17,182,18,4,18,110,18,196,19, - 76,19,172,19,246,20,88,20,174,20,234,21,64,21,128,21,166,21,184,22,18,22,126,22,198,23,52,23,142,23,224,24,86,24,186,24,238,25,54,25,150,25,212,26,72,26,156,26,240,27,92,27,200,28, - 4,28,76,28,150,28,234,29,42,29,146,29,210,30,64,30,142,30,224,31,36,31,118,31,166,31,166,32,16,130,1,52,46,32,138,32,178,32,200,33,20,33,116,33,152,33,238,34,98,34,134,35,12,130,1, - 33,128,35,131,1,60,152,35,176,35,216,36,0,36,74,36,104,36,144,36,174,37,6,37,96,37,130,37,248,37,248,38,88,38,170,130,1,8,190,216,39,64,39,154,40,10,40,104,40,168,41,14,41,32,41,184, - 41,248,42,54,42,96,42,96,43,2,43,42,43,94,43,172,43,230,44,32,44,52,44,154,45,40,45,92,45,120,45,170,45,232,46,38,46,166,47,38,47,182,47,244,48,94,48,200,49,62,49,180,50,30,50,158, - 51,30,51,130,51,238,52,92,52,206,53,58,53,134,53,212,54,38,54,114,54,230,55,118,55,216,56,58,56,166,57,18,57,116,57,174,58,46,58,154,59,6,59,124,59,232,60,58,60,150,61,34,61,134,61, - 236,62,86,62,198,63,42,63,154,64,18,64,106,64,208,65,54,65,162,66,8,66,64,66,122,66,184,66,240,67,98,67,204,68,42,68,138,68,238,69,88,69,182,69,226,70,84,70,180,71,20,71,122,71,218, - 72,84,72,198,73,64,0,36,70,21,8,8,77,3,0,7,0,11,0,15,0,19,0,23,0,27,0,31,0,35,0,39,0,43,0,47,0,51,0,55,0,59,0,63,0,67,0,71,0,75,0,79,0,83,0,87,0,91,0,95,0,99,0,103,0,107,0,111,0,115, - 0,119,0,123,0,127,0,131,0,135,0,139,0,143,0,0,17,53,51,21,49,150,3,32,5,130,23,32,33,130,3,211,7,151,115,32,128,133,0,37,252,128,128,2,128,128,190,5,133,74,32,4,133,6,206,5,42,0,7, - 1,128,0,0,2,0,4,0,0,65,139,13,37,0,1,53,51,21,7,146,3,32,3,130,19,32,1,141,133,32,3,141,14,131,13,38,255,0,128,128,0,6,1,130,84,35,2,128,4,128,140,91,132,89,32,51,65,143,6,139,7,33, - 1,0,130,57,32,254,130,3,32,128,132,4,32,4,131,14,138,89,35,0,0,24,0,130,0,33,3,128,144,171,66,55,33,148,115,65,187,19,32,5,130,151,143,155,163,39,32,1,136,182,32,253,134,178,132,7, - 132,200,145,17,32,3,65,48,17,165,17,39,0,0,21,0,128,255,128,3,65,175,17,65,3,27,132,253,131,217,139,201,155,233,155,27,131,67,131,31,130,241,33,255,0,131,181,137,232,132,15,132,4,138, - 247,34,255,0,128,179,238,32,0,130,0,32,20,65,239,48,33,0,19,67,235,10,32,51,65,203,14,65,215,11,32,7,154,27,135,39,32,33,130,35,33,128,128,130,231,32,253,132,231,32,128,132,232,34, - 128,128,254,133,13,136,8,32,253,65,186,5,130,36,130,42,176,234,133,231,34,128,0,0,66,215,44,33,0,1,68,235,6,68,211,19,32,49,68,239,14,139,207,139,47,66,13,7,32,51,130,47,33,1,0,130, - 207,35,128,128,1,0,131,222,131,5,130,212,130,6,131,212,32,0,130,10,133,220,130,233,130,226,32,254,133,255,178,233,39,3,1,128,3,0,2,0,4,68,15,7,68,99,12,130,89,130,104,33,128,4,133, - 93,130,10,38,0,0,11,1,0,255,0,68,63,16,70,39,9,66,215,8,32,7,68,77,6,68,175,14,32,29,68,195,6,132,7,35,2,0,128,255,131,91,132,4,65,178,5,141,111,67,129,23,165,135,140,107,142,135,33, - 21,5,69,71,6,131,7,33,1,0,140,104,132,142,130,4,137,247,140,30,68,255,12,39,11,0,128,0,128,3,0,3,69,171,15,67,251,7,65,15,8,66,249,11,65,229,7,67,211,7,66,13,7,35,1,128,128,254,133, - 93,32,254,131,145,132,4,132,18,32,2,151,128,130,23,34,0,0,9,154,131,65,207,8,68,107,15,68,51,7,32,7,70,59,7,135,121,130,82,32,128,151,111,41,0,0,4,0,128,255,0,1,128,1,137,239,33,0, - 37,70,145,10,65,77,10,65,212,14,37,0,0,0,5,0,128,66,109,5,70,123,10,33,0,19,72,33,18,133,237,70,209,11,33,0,2,130,113,137,119,136,115,33,1,0,133,43,130,5,34,0,0,10,69,135,6,70,219, - 13,66,155,7,65,9,12,66,157,11,66,9,11,32,7,130,141,132,252,66,151,9,137,9,66,15,30,36,0,20,0,128,0,130,218,71,11,42,68,51,8,65,141,7,73,19,15,69,47,23,143,39,66,81,7,32,1,66,55,6,34, - 1,128,128,68,25,5,69,32,6,137,6,136,25,32,254,131,42,32,3,66,88,26,148,26,32,0,130,0,32,14,164,231,70,225,12,66,233,7,67,133,19,71,203,15,130,161,32,255,130,155,32,254,139,127,134, - 12,164,174,33,0,15,164,159,33,59,0,65,125,20,66,25,7,32,5,68,191,6,66,29,7,144,165,65,105,9,35,128,128,255,0,137,2,133,182,164,169,33,128,128,197,171,130,155,68,235,7,32,21,70,77,19, - 66,21,10,68,97,8,66,30,5,66,4,43,34,0,17,0,71,19,41,65,253,20,71,25,23,65,91,15,65,115,7,34,2,128,128,66,9,8,130,169,33,1,0,66,212,13,132,28,72,201,43,35,0,0,0,18,66,27,38,76,231,5, - 68,157,20,135,157,32,7,68,185,13,65,129,28,66,20,5,32,253,66,210,11,65,128,49,133,61,32,0,65,135,6,74,111,37,72,149,12,66,203,19,65,147,19,68,93,7,68,85,8,76,4,5,33,255,0,133,129,34, - 254,0,128,68,69,8,181,197,34,0,0,12,65,135,32,65,123,20,69,183,27,133,156,66,50,5,72,87,10,67,137,32,33,0,19,160,139,78,251,13,68,55,20,67,119,19,65,91,36,69,177,15,32,254,143,16,65, - 98,53,32,128,130,0,32,0,66,43,54,70,141,23,66,23,15,131,39,69,47,11,131,15,70,129,19,74,161,9,36,128,255,0,128,254,130,153,65,148,32,67,41,9,34,0,0,4,79,15,5,73,99,10,71,203,8,32,3, - 72,123,6,72,43,8,32,2,133,56,131,99,130,9,34,0,0,6,72,175,5,73,159,14,144,63,135,197,132,189,133,66,33,255,0,73,6,7,70,137,12,35,0,0,0,10,130,3,73,243,25,67,113,12,65,73,7,69,161,7, - 138,7,37,21,2,0,128,128,254,134,3,73,116,27,33,128,128,130,111,39,12,0,128,1,0,3,128,2,72,219,21,35,43,0,47,0,67,47,20,130,111,33,21,1,68,167,13,81,147,8,133,230,32,128,77,73,6,32, - 128,131,142,134,18,130,6,32,255,75,18,12,131,243,37,128,0,128,3,128,3,74,231,21,135,123,32,29,134,107,135,7,32,21,74,117,7,135,7,134,96,135,246,74,103,23,132,242,33,0,10,67,151,28, - 67,133,20,66,141,11,131,11,32,3,77,71,6,32,128,130,113,32,1,81,4,6,134,218,66,130,24,131,31,34,0,26,0,130,0,77,255,44,83,15,11,148,155,68,13,7,32,49,78,231,18,79,7,11,73,243,11,32, - 33,65,187,10,130,63,65,87,8,73,239,19,35,0,128,1,0,131,226,32,252,65,100,6,32,128,139,8,33,1,0,130,21,32,253,72,155,44,73,255,20,32,128,71,67,8,81,243,39,67,15,20,74,191,23,68,121, - 27,32,1,66,150,6,32,254,79,19,11,131,214,32,128,130,215,37,2,0,128,253,0,128,136,5,65,220,24,147,212,130,210,33,0,24,72,219,42,84,255,13,67,119,16,69,245,19,72,225,19,65,3,15,69,93, - 19,131,55,132,178,71,115,14,81,228,6,142,245,33,253,0,132,43,172,252,65,16,11,75,219,8,65,219,31,66,223,24,75,223,10,33,29,1,80,243,10,66,175,8,131,110,134,203,133,172,130,16,70,30, - 7,164,183,130,163,32,20,65,171,48,65,163,36,65,143,23,65,151,19,65,147,13,65,134,17,133,17,130,216,67,114,5,164,217,65,137,12,72,147,48,79,71,19,74,169,22,80,251,8,65,173,7,66,157, - 15,74,173,15,32,254,65,170,8,71,186,45,72,131,6,77,143,40,187,195,152,179,65,123,38,68,215,57,68,179,15,65,85,7,69,187,14,32,21,66,95,15,67,19,25,32,1,83,223,6,32,2,76,240,7,77,166, - 43,65,8,5,130,206,32,0,67,39,54,143,167,66,255,19,82,193,11,151,47,85,171,5,67,27,17,132,160,69,172,11,69,184,56,66,95,6,33,12,1,130,237,32,2,68,179,27,68,175,16,80,135,15,72,55,7, - 71,87,12,73,3,12,132,12,66,75,32,76,215,5,169,139,147,135,148,139,81,12,12,81,185,36,75,251,7,65,23,27,76,215,9,87,165,12,65,209,15,72,157,7,65,245,31,32,128,71,128,6,32,1,82,125,5, - 34,0,128,254,131,169,32,254,131,187,71,180,9,132,27,32,2,88,129,44,32,0,78,47,40,65,79,23,79,171,14,32,21,71,87,8,72,15,14,65,224,33,130,139,74,27,62,93,23,7,68,31,7,75,27,7,139,15, - 74,3,7,74,23,27,65,165,11,65,177,15,67,123,5,32,1,130,221,32,252,71,96,5,74,12,12,133,244,130,25,34,1,0,128,130,2,139,8,93,26,8,65,9,32,65,57,14,140,14,32,0,73,79,67,68,119,11,135, - 11,32,51,90,75,14,139,247,65,43,7,131,19,139,11,69,159,11,65,247,6,36,1,128,128,253,0,90,71,9,33,1,0,132,14,32,128,89,93,14,69,133,6,130,44,131,30,131,6,65,20,56,33,0,16,72,179,40, - 75,47,12,65,215,19,74,95,19,65,43,11,131,168,67,110,5,75,23,17,69,106,6,75,65,5,71,204,43,32,0,80,75,47,71,203,15,159,181,68,91,11,67,197,7,73,101,13,68,85,6,33,128,128,130,214,130, - 25,32,254,74,236,48,130,194,37,0,18,0,128,255,128,77,215,40,65,139,64,32,51,80,159,10,65,147,39,130,219,84,212,43,130,46,75,19,97,74,33,11,65,201,23,65,173,31,33,1,0,79,133,6,66,150, - 5,67,75,48,85,187,6,70,207,37,32,71,87,221,13,73,163,14,80,167,15,132,15,83,193,19,82,209,8,78,99,9,72,190,11,77,110,49,89,63,5,80,91,35,99,63,32,70,235,23,81,99,10,69,148,10,65,110, - 36,32,0,65,99,47,95,219,11,68,171,51,66,87,7,72,57,7,74,45,17,143,17,65,114,50,33,14,0,65,111,40,159,195,98,135,15,35,7,53,51,21,100,78,9,95,146,16,32,254,82,114,6,32,128,67,208,37, - 130,166,99,79,58,32,17,96,99,14,72,31,19,72,87,31,82,155,7,67,47,14,32,21,131,75,134,231,72,51,17,72,78,8,133,8,80,133,6,33,253,128,88,37,9,66,124,36,72,65,12,134,12,71,55,43,66,139, - 27,85,135,10,91,33,12,65,35,11,66,131,11,71,32,8,90,127,6,130,244,71,76,11,168,207,33,0,12,66,123,32,32,0,65,183,15,68,135,11,66,111,7,67,235,11,66,111,15,32,254,97,66,12,160,154,67, - 227,52,80,33,15,87,249,15,93,45,31,75,111,12,93,45,11,77,99,9,160,184,81,31,12,32,15,98,135,30,104,175,7,77,249,36,69,73,15,78,5,12,32,254,66,151,19,34,128,128,4,87,32,12,149,35,133, - 21,96,151,31,32,19,72,35,5,98,173,15,143,15,32,21,143,99,158,129,33,0,0,65,35,52,65,11,15,147,15,98,75,11,33,1,0,143,151,132,15,32,254,99,200,37,132,43,130,4,39,0,10,0,128,1,128,3, - 0,104,151,14,97,187,20,69,131,15,67,195,11,87,227,7,33,128,128,132,128,33,254,0,68,131,9,65,46,26,42,0,0,0,7,0,0,255,128,3,128,0,88,223,15,33,0,21,89,61,22,66,209,12,65,2,12,37,0,2, - 1,0,3,128,101,83,8,36,0,1,53,51,29,130,3,34,21,1,0,66,53,8,32,0,68,215,6,100,55,25,107,111,9,66,193,11,72,167,8,73,143,31,139,31,33,1,0,131,158,32,254,132,5,33,253,128,65,16,9,133, - 17,89,130,25,141,212,33,0,0,93,39,8,90,131,25,93,39,14,66,217,6,106,179,8,159,181,71,125,15,139,47,138,141,87,11,14,76,23,14,65,231,26,140,209,66,122,8,81,179,5,101,195,26,32,47,74, - 75,13,69,159,11,83,235,11,67,21,16,136,167,131,106,130,165,130,15,32,128,101,90,24,134,142,32,0,65,103,51,108,23,11,101,231,15,75,173,23,74,237,23,66,15,6,66,46,17,66,58,17,65,105, - 49,66,247,55,71,179,12,70,139,15,86,229,7,84,167,15,32,1,95,72,12,89,49,6,33,128,128,65,136,38,66,30,9,32,0,100,239,7,66,247,29,70,105,20,65,141,19,69,81,15,130,144,32,128,83,41,5, - 32,255,131,177,68,185,5,133,126,65,97,37,32,0,130,0,33,21,0,130,55,66,195,28,67,155,13,34,79,0,83,66,213,13,73,241,19,66,59,19,65,125,11,135,201,66,249,16,32,128,66,44,11,66,56,17, - 68,143,8,68,124,38,67,183,12,96,211,9,65,143,29,112,171,5,32,0,68,131,63,34,33,53,51,71,121,11,32,254,98,251,16,32,253,74,231,10,65,175,37,133,206,37,0,0,8,1,0,0,107,123,11,113,115, - 9,33,0,1,130,117,131,3,73,103,7,66,51,18,66,44,5,133,75,70,88,5,32,254,65,39,12,68,80,9,34,12,0,128,107,179,28,68,223,6,155,111,86,147,15,32,2,131,82,141,110,33,254,0,130,15,32,4,103, - 184,15,141,35,87,176,5,83,11,5,71,235,23,114,107,11,65,189,16,70,33,15,86,153,31,135,126,86,145,30,65,183,41,32,0,130,0,32,10,65,183,24,34,35,0,39,67,85,9,65,179,15,143,15,33,1,0,65, - 28,17,157,136,130,123,32,20,130,3,32,0,97,135,24,115,167,19,80,71,12,32,51,110,163,14,78,35,19,131,19,155,23,77,229,8,78,9,17,151,17,67,231,46,94,135,8,73,31,31,93,215,56,82,171,25, - 72,77,8,162,179,169,167,99,131,11,69,85,19,66,215,15,76,129,13,68,115,22,72,79,35,67,113,5,34,0,0,19,70,31,46,65,89,52,73,223,15,85,199,33,95,33,8,132,203,73,29,32,67,48,16,177,215, - 101,13,15,65,141,43,69,141,15,75,89,5,70,0,11,70,235,21,178,215,36,10,0,128,0,0,71,207,24,33,0,19,100,67,6,80,215,11,66,67,7,80,43,12,71,106,7,80,192,5,65,63,5,66,217,26,33,0,13,156, - 119,68,95,5,72,233,12,134,129,85,81,11,76,165,20,65,43,8,73,136,8,75,10,31,38,128,128,0,0,0,13,1,130,4,32,3,106,235,29,114,179,12,66,131,23,32,7,77,133,6,67,89,12,131,139,116,60,9, - 89,15,37,32,0,74,15,7,103,11,22,65,35,5,33,55,0,93,81,28,67,239,23,78,85,5,107,93,14,66,84,17,65,193,26,74,183,10,66,67,34,143,135,79,91,15,32,7,117,111,8,75,56,9,84,212,9,154,134, - 32,0,130,0,32,18,130,3,70,171,41,83,7,16,70,131,19,84,191,15,84,175,19,84,167,30,84,158,12,154,193,68,107,15,33,0,0,65,79,42,65,71,7,73,55,7,118,191,16,83,180,9,32,255,76,166,9,154, - 141,32,0,130,0,69,195,52,65,225,15,151,15,75,215,31,80,56,10,68,240,17,100,32,9,70,147,39,65,93,12,71,71,41,92,85,15,84,135,23,78,35,15,110,27,10,84,125,8,107,115,29,136,160,38,0,0, - 14,0,128,255,0,82,155,24,67,239,8,119,255,11,69,131,11,77,29,6,112,31,8,134,27,105,203,8,32,2,75,51,11,75,195,12,74,13,29,136,161,37,128,0,0,0,11,1,130,163,82,115,8,125,191,17,69,35, - 12,74,137,15,143,15,32,1,65,157,12,136,12,161,142,65,43,40,65,199,6,65,19,24,102,185,11,76,123,11,99,6,12,135,12,32,254,130,8,161,155,101,23,9,39,8,0,0,1,128,3,128,2,78,63,17,72,245, - 12,67,41,11,90,167,9,32,128,97,49,9,32,128,109,51,14,132,97,81,191,8,130,97,125,99,12,121,35,9,127,75,15,71,79,12,81,151,23,87,97,7,70,223,15,80,245,16,105,97,15,32,254,113,17,6,32, - 128,130,8,105,105,8,76,122,18,65,243,21,74,63,7,38,4,1,0,255,0,2,0,119,247,28,133,65,32,255,141,91,35,0,0,0,16,67,63,36,34,59,0,63,77,59,9,119,147,11,143,241,66,173,15,66,31,11,67, - 75,8,81,74,16,32,128,131,255,87,181,42,127,43,5,34,255,128,2,120,235,11,37,19,0,23,0,0,37,109,191,14,118,219,7,127,43,14,65,79,14,35,0,0,0,3,73,91,5,130,5,38,3,0,7,0,11,0,0,70,205, - 11,88,221,12,32,0,73,135,7,87,15,22,73,135,10,79,153,15,97,71,19,65,49,11,32,1,131,104,121,235,11,80,65,11,142,179,144,14,81,123,46,32,1,88,217,5,112,5,8,65,201,15,83,29,15,122,147, - 11,135,179,142,175,143,185,67,247,39,66,199,7,35,5,0,128,3,69,203,15,123,163,12,67,127,7,130,119,71,153,10,141,102,70,175,8,32,128,121,235,30,136,89,100,191,11,116,195,11,111,235,15, - 72,39,7,32,2,97,43,5,132,5,94,67,8,131,8,125,253,10,32,3,65,158,16,146,16,130,170,40,0,21,0,128,0,0,3,128,5,88,219,15,24,64,159,32,135,141,65,167,15,68,163,10,97,73,49,32,255,82,58, - 7,93,80,8,97,81,16,24,67,87,52,34,0,0,5,130,231,33,128,2,80,51,13,65,129,8,113,61,6,132,175,65,219,5,130,136,77,152,17,32,0,95,131,61,70,215,6,33,21,51,90,53,10,78,97,23,105,77,31, - 65,117,7,139,75,24,68,195,9,24,64,22,9,33,0,128,130,11,33,128,128,66,25,5,121,38,5,134,5,134,45,66,40,36,66,59,18,34,128,0,0,66,59,81,135,245,123,103,19,120,159,19,77,175,12,33,255, - 0,87,29,10,94,70,21,66,59,54,39,3,1,128,3,0,2,128,4,24,65,7,15,66,47,7,72,98,12,37,0,0,0,3,1,0,24,65,55,21,131,195,32,1,67,178,6,33,4,0,77,141,8,32,6,131,47,74,67,16,24,69,3,20,24, - 65,251,7,133,234,130,229,94,108,17,35,0,0,6,0,141,175,86,59,5,162,79,85,166,8,70,112,13,32,13,24,64,67,26,24,71,255,7,123,211,12,80,121,11,69,215,15,66,217,11,69,71,10,131,113,132, - 126,119,90,9,66,117,19,132,19,32,0,130,0,24,64,47,59,33,7,0,73,227,5,68,243,15,85,13,12,76,37,22,74,254,15,130,138,33,0,4,65,111,6,137,79,65,107,16,32,1,77,200,6,34,128,128,3,75,154, - 12,37,0,16,0,0,2,0,104,115,36,140,157,68,67,19,68,51,15,106,243,15,134,120,70,37,10,68,27,10,140,152,65,121,24,32,128,94,155,7,67,11,8,24,74,11,25,65,3,12,83,89,18,82,21,37,67,200, - 5,130,144,24,64,172,12,33,4,0,134,162,74,80,14,145,184,32,0,130,0,69,251,20,32,19,81,243,5,82,143,8,33,5,53,89,203,5,133,112,79,109,15,33,0,21,130,71,80,175,41,36,75,0,79,0,83,121, - 117,9,87,89,27,66,103,11,70,13,15,75,191,11,135,67,87,97,20,109,203,5,69,246,8,108,171,5,78,195,38,65,51,13,107,203,11,77,3,17,24,75,239,17,65,229,28,79,129,39,130,175,32,128,123,253, - 7,132,142,24,65,51,15,65,239,41,36,128,128,0,0,13,65,171,5,66,163,28,136,183,118,137,11,80,255,15,67,65,7,74,111,8,32,0,130,157,32,253,24,76,35,10,103,212,5,81,175,9,69,141,7,66,150, - 29,131,158,24,75,199,28,124,185,7,76,205,15,68,124,14,32,3,123,139,16,130,16,33,128,128,108,199,6,33,0,3,65,191,35,107,11,6,73,197,11,24,70,121,15,83,247,15,24,70,173,23,69,205,14, - 32,253,131,140,32,254,136,4,94,198,9,32,3,78,4,13,66,127,13,143,13,32,0,130,0,33,16,0,24,69,59,39,109,147,12,76,253,19,24,69,207,15,69,229,15,130,195,71,90,10,139,10,130,152,73,43, - 40,91,139,10,65,131,37,35,75,0,79,0,84,227,12,143,151,68,25,15,80,9,23,95,169,11,34,128,2,128,112,186,5,130,6,83,161,19,76,50,6,130,37,65,145,44,110,83,5,32,16,67,99,6,71,67,15,76, - 55,17,140,215,67,97,23,76,69,15,77,237,11,104,211,23,77,238,11,65,154,43,33,0,10,83,15,28,83,13,20,67,145,19,67,141,14,97,149,21,68,9,15,86,251,5,66,207,5,66,27,37,82,1,23,127,71,12, - 94,235,10,110,175,24,98,243,15,132,154,132,4,24,66,69,10,32,4,67,156,43,130,198,35,2,1,0,4,75,27,9,69,85,9,95,240,7,32,128,130,35,32,28,66,43,40,24,82,63,23,83,123,12,72,231,15,127, - 59,23,116,23,19,117,71,7,24,77,99,15,67,111,15,71,101,8,36,2,128,128,252,128,127,60,11,32,1,132,16,130,18,141,24,67,107,9,32,3,68,194,15,175,15,38,0,11,0,128,1,128,2,80,63,25,32,0, - 24,65,73,11,69,185,15,83,243,16,32,0,24,81,165,8,130,86,77,35,6,155,163,88,203,5,24,66,195,30,70,19,19,24,80,133,15,32,1,75,211,8,32,254,108,133,8,79,87,20,65,32,9,41,0,0,7,0,128,0, - 0,2,128,2,68,87,15,66,1,16,92,201,16,24,76,24,17,133,17,34,128,0,30,66,127,64,34,115,0,119,73,205,9,66,43,11,109,143,15,24,79,203,11,90,143,15,131,15,155,31,65,185,15,86,87,11,35,128, - 128,253,0,69,7,6,130,213,33,1,0,119,178,15,142,17,66,141,74,83,28,6,36,7,0,0,4,128,82,39,18,76,149,12,67,69,21,32,128,79,118,15,32,0,130,0,32,8,131,206,32,2,79,83,9,100,223,14,102, - 113,23,115,115,7,24,65,231,12,130,162,32,4,68,182,19,130,102,93,143,8,69,107,29,24,77,255,12,143,197,72,51,7,76,195,15,132,139,85,49,15,130,152,131,18,71,81,23,70,14,11,36,0,10,0,128, - 2,69,59,9,89,151,15,66,241,11,76,165,12,71,43,15,75,49,13,65,12,23,132,37,32,0,179,115,130,231,95,181,16,132,77,32,254,67,224,8,65,126,20,79,171,8,32,2,89,81,5,75,143,6,80,41,8,34, - 2,0,128,24,81,72,9,32,0,130,0,35,17,0,0,255,77,99,39,95,65,36,67,109,15,24,69,93,11,77,239,5,95,77,23,35,128,1,0,128,24,86,7,8,132,167,32,2,69,198,41,130,202,33,0,26,120,75,44,24,89, - 51,15,71,243,12,70,239,11,24,84,3,11,66,7,11,71,255,10,32,21,69,155,35,88,151,12,32,128,74,38,10,65,210,8,74,251,5,65,226,5,75,201,13,32,3,65,9,41,146,41,40,0,0,0,9,1,0,1,0,2,91,99, - 19,32,35,106,119,13,70,219,15,83,239,12,137,154,32,2,67,252,19,36,128,0,0,4,1,130,196,32,2,130,8,91,107,8,32,0,135,81,24,73,211,8,132,161,73,164,13,36,0,8,0,128,2,105,123,26,139,67, - 76,99,15,34,1,0,128,135,76,83,156,20,92,104,8,67,251,30,24,86,47,27,123,207,12,24,86,7,15,71,227,8,32,4,65,20,20,131,127,32,0,130,123,32,0,71,223,26,32,19,90,195,22,71,223,15,84,200, - 6,32,128,133,241,24,84,149,9,67,41,25,36,0,0,0,22,0,88,111,49,32,87,66,21,5,77,3,27,123,75,7,71,143,19,135,183,71,183,19,130,171,74,252,5,131,5,89,87,17,32,1,132,18,130,232,68,11,10, - 33,1,128,70,208,16,66,230,18,147,18,130,254,223,255,75,27,23,65,59,15,135,39,155,255,34,128,128,254,104,92,8,33,0,128,65,32,11,65,1,58,33,26,0,130,0,72,71,18,78,55,17,76,11,19,86,101, - 12,75,223,11,89,15,11,24,76,87,15,75,235,15,131,15,72,95,7,85,71,11,72,115,11,73,64,6,34,1,128,128,66,215,9,34,128,254,128,134,14,33,128,255,67,102,5,32,0,130,16,70,38,11,66,26,57, - 88,11,8,24,76,215,34,78,139,7,95,245,7,32,7,24,73,75,23,32,128,131,167,130,170,101,158,9,82,49,22,118,139,6,32,18,67,155,44,116,187,9,108,55,14,80,155,23,66,131,15,93,77,10,131,168, - 32,128,73,211,12,24,75,187,22,32,4,96,71,20,67,108,19,132,19,120,207,8,32,5,76,79,15,66,111,21,66,95,8,32,3,190,211,111,3,8,211,212,32,20,65,167,44,34,75,0,79,97,59,13,32,33,112,63, - 10,65,147,19,69,39,19,143,39,24,66,71,9,130,224,65,185,43,94,176,12,65,183,24,71,38,8,24,72,167,7,65,191,38,136,235,24,96,167,12,65,203,62,115,131,13,65,208,42,175,235,67,127,6,32, - 4,76,171,29,114,187,5,32,71,65,211,5,65,203,68,72,51,8,164,219,32,0,172,214,71,239,58,78,3,27,66,143,15,77,19,15,147,31,35,33,53,51,21,66,183,10,173,245,66,170,30,150,30,34,0,0,23, - 80,123,54,76,1,16,73,125,15,82,245,11,167,253,24,76,85,12,70,184,5,32,254,131,185,37,254,0,128,1,0,128,133,16,117,158,18,92,27,38,65,3,17,130,251,35,17,0,128,254,24,69,83,39,140,243, - 121,73,19,109,167,7,81,41,15,24,95,175,12,102,227,15,121,96,11,24,95,189,7,32,3,145,171,154,17,24,77,47,9,33,0,5,70,71,37,68,135,7,32,29,117,171,11,69,87,15,24,79,97,19,24,79,149,23, - 131,59,32,1,75,235,5,72,115,11,72,143,7,132,188,71,27,46,131,51,32,0,69,95,6,175,215,32,21,131,167,81,15,19,151,191,151,23,131,215,71,43,5,32,254,24,79,164,24,74,109,8,77,166,13,65, - 176,26,88,162,5,98,159,6,171,219,120,247,6,79,29,8,99,169,10,103,59,19,65,209,35,131,35,91,25,19,112,94,15,83,36,8,173,229,33,20,0,88,75,43,71,31,12,65,191,71,33,1,0,130,203,32,254, - 131,4,68,66,7,67,130,6,104,61,13,173,215,38,13,1,0,0,0,2,128,67,111,28,74,129,16,104,35,19,79,161,16,87,14,7,138,143,132,10,67,62,36,114,115,5,162,151,67,33,16,108,181,15,143,151,67, - 5,5,24,100,242,15,170,153,34,0,0,14,65,51,34,32,55,79,75,9,32,51,74,7,10,65,57,38,132,142,32,254,72,0,14,139,163,32,128,80,254,8,67,158,21,65,63,7,32,4,72,227,27,95,155,12,67,119,19, - 124,91,24,149,154,72,177,34,97,223,8,155,151,24,108,227,15,88,147,16,72,117,19,68,35,11,92,253,15,70,199,15,24,87,209,17,32,2,87,233,7,32,1,24,88,195,10,119,24,8,32,3,81,227,24,65, - 125,21,35,128,128,0,25,76,59,48,24,90,187,9,97,235,12,66,61,11,91,105,19,24,79,141,11,24,79,117,15,24,79,129,27,90,53,13,130,13,32,253,131,228,24,79,133,40,69,70,8,66,137,31,65,33, - 19,96,107,8,68,119,29,66,7,5,68,125,16,65,253,19,65,241,27,24,90,179,13,24,79,143,18,33,128,128,130,246,32,254,130,168,68,154,36,77,51,9,97,47,5,167,195,32,21,131,183,78,239,27,155, - 195,78,231,14,201,196,77,11,6,32,5,73,111,37,97,247,12,77,19,31,155,207,78,215,19,162,212,69,17,14,66,91,19,80,143,57,78,203,39,159,215,32,128,93,134,8,24,80,109,24,66,113,15,169,215, - 66,115,6,32,4,69,63,33,32,0,101,113,7,86,227,35,143,211,36,49,53,51,21,1,77,185,14,65,159,28,69,251,34,67,56,8,33,9,0,24,107,175,25,90,111,12,110,251,11,119,189,24,119,187,34,87,15, - 9,32,4,66,231,37,90,39,7,66,239,8,84,219,15,69,105,23,24,85,27,27,87,31,11,33,1,128,76,94,6,32,1,85,241,7,33,128,128,106,48,10,33,128,128,69,136,11,133,13,24,79,116,49,84,236,8,24, - 91,87,9,32,5,165,255,69,115,12,66,27,15,159,15,24,72,247,12,74,178,5,24,80,64,15,33,0,128,143,17,77,89,51,130,214,24,81,43,7,170,215,74,49,8,159,199,143,31,139,215,69,143,5,32,254, - 24,81,50,35,181,217,84,123,70,143,195,159,15,65,187,16,66,123,7,65,175,15,65,193,29,68,207,39,79,27,5,70,131,6,32,4,68,211,33,33,67,0,83,143,14,159,207,143,31,140,223,33,0,128,24,80, - 82,14,24,93,16,23,32,253,65,195,5,68,227,40,133,214,107,31,7,32,5,67,115,27,87,9,8,107,31,43,66,125,6,32,0,103,177,23,131,127,72,203,36,32,0,110,103,8,155,163,73,135,6,32,19,24,112, - 99,10,65,71,11,73,143,19,143,31,126,195,5,24,85,21,9,24,76,47,14,32,254,24,93,77,36,68,207,11,39,25,0,0,255,128,3,128,4,66,51,37,95,247,13,82,255,24,76,39,19,147,221,66,85,27,24,118, - 7,8,24,74,249,12,76,74,8,91,234,8,67,80,17,131,222,33,253,0,121,30,44,73,0,16,69,15,6,32,0,65,23,38,69,231,12,65,179,6,98,131,16,86,31,27,24,108,157,14,80,160,8,24,65,46,17,33,4,0, - 96,2,18,144,191,65,226,8,68,19,5,171,199,80,9,15,180,199,67,89,5,32,255,24,79,173,28,174,201,24,79,179,50,32,1,24,122,5,10,82,61,10,180,209,83,19,8,32,128,24,80,129,27,111,248,43,131, - 71,24,115,103,8,67,127,41,78,213,24,100,247,19,66,115,39,75,107,5,32,254,165,219,78,170,40,24,112,163,49,32,1,97,203,6,65,173,64,32,0,83,54,7,133,217,88,37,12,32,254,131,28,33,128, - 3,67,71,44,84,183,6,32,5,69,223,33,96,7,7,123,137,16,192,211,24,112,14,9,32,255,67,88,29,68,14,10,84,197,38,33,0,22,116,47,50,32,87,106,99,9,116,49,15,89,225,15,97,231,23,70,41,19, - 82,85,8,93,167,6,32,253,132,236,108,190,7,89,251,5,116,49,58,33,128,128,131,234,32,15,24,74,67,38,70,227,24,24,83,45,23,89,219,12,70,187,12,89,216,19,32,2,69,185,24,141,24,70,143,66, - 24,82,119,56,78,24,10,32,253,133,149,132,6,24,106,233,7,69,198,48,178,203,81,243,12,68,211,15,106,255,23,66,91,15,69,193,7,100,39,10,24,83,72,16,176,204,33,19,0,88,207,45,68,21,12, - 68,17,10,65,157,53,68,17,6,32,254,92,67,10,65,161,25,69,182,43,24,118,91,47,69,183,18,181,209,111,253,12,89,159,8,66,112,12,69,184,45,35,0,0,0,9,24,80,227,26,73,185,16,118,195,15,131, - 15,33,1,0,65,59,15,66,39,27,160,111,66,205,12,148,111,143,110,33,128,128,156,112,24,81,199,8,75,199,23,66,117,20,155,121,32,254,68,126,12,72,213,29,134,239,149,123,89,27,16,148,117, - 65,245,8,24,71,159,14,141,134,134,28,73,51,55,109,77,15,105,131,11,68,67,11,76,169,27,107,209,12,102,174,8,32,128,72,100,18,116,163,56,79,203,11,75,183,44,85,119,19,71,119,23,151,227, - 32,1,93,27,8,65,122,5,77,102,8,110,120,20,66,23,8,66,175,17,66,63,12,133,12,79,35,8,74,235,33,67,149,16,69,243,15,78,57,15,69,235,16,67,177,7,151,192,130,23,67,84,29,141,192,174,187, - 77,67,15,69,11,12,159,187,77,59,10,199,189,24,70,235,50,96,83,19,66,53,23,105,65,19,77,47,12,163,199,66,67,37,78,207,50,67,23,23,174,205,67,228,6,71,107,13,67,22,14,66,85,11,83,187, - 38,124,47,49,95,7,19,66,83,23,67,23,19,24,96,78,17,80,101,16,71,98,40,33,0,7,88,131,22,24,89,245,12,84,45,12,102,213,5,123,12,9,32,2,126,21,14,43,255,0,128,128,0,0,20,0,128,255,128, - 3,126,19,39,32,75,106,51,7,113,129,15,24,110,135,19,126,47,15,115,117,11,69,47,11,32,2,109,76,9,102,109,9,32,128,75,2,10,130,21,32,254,69,47,6,32,3,94,217,47,32,0,65,247,10,69,15,46, - 65,235,31,65,243,15,101,139,10,66,174,14,65,247,16,72,102,28,69,17,14,84,243,9,165,191,88,47,48,66,53,12,32,128,71,108,6,203,193,32,17,75,187,42,73,65,16,65,133,52,114,123,9,167,199, - 69,21,37,86,127,44,75,171,11,180,197,78,213,12,148,200,81,97,46,24,95,243,9,32,4,66,75,33,113,103,9,87,243,36,143,225,24,84,27,31,90,145,8,148,216,67,49,5,24,84,34,14,75,155,27,67, - 52,13,140,13,36,0,20,0,128,255,24,135,99,46,88,59,43,155,249,80,165,7,136,144,71,161,23,32,253,132,33,32,254,88,87,44,136,84,35,128,0,0,21,81,103,5,94,47,44,76,51,12,143,197,151,15, - 65,215,31,24,64,77,13,65,220,20,65,214,14,71,4,40,65,213,13,32,0,130,0,35,21,1,2,0,135,0,34,36,0,72,134,10,36,1,0,26,0,130,134,11,36,2,0,14,0,108,134,11,32,3,138,23,32,4,138,11,34, - 5,0,20,134,33,34,0,0,6,132,23,32,1,134,15,32,18,130,25,133,11,37,1,0,13,0,49,0,133,11,36,2,0,7,0,38,134,11,36,3,0,17,0,45,134,11,32,4,138,35,36,5,0,10,0,62,134,23,32,6,132,23,36,3, - 0,1,4,9,130,87,131,167,133,11,133,167,133,11,133,167,133,11,37,3,0,34,0,122,0,133,11,133,167,133,11,133,167,133,11,133,167,34,50,0,48,130,1,34,52,0,47,134,5,8,49,49,0,53,98,121,32, - 84,114,105,115,116,97,110,32,71,114,105,109,109,101,114,82,101,103,117,108,97,114,84,84,88,32,80,114,111,103,103,121,67,108,101,97,110,84,84,50,48,48,52,47,130,2,53,49,53,0,98,0,121, - 0,32,0,84,0,114,0,105,0,115,0,116,0,97,0,110,130,15,32,71,132,15,36,109,0,109,0,101,130,9,32,82,130,5,36,103,0,117,0,108,130,29,32,114,130,43,34,84,0,88,130,35,32,80,130,25,34,111, - 0,103,130,1,34,121,0,67,130,27,32,101,132,59,32,84,130,31,33,0,0,65,155,9,34,20,0,0,65,11,6,130,8,135,2,33,1,1,130,9,8,120,1,1,2,1,3,1,4,1,5,1,6,1,7,1,8,1,9,1,10,1,11,1,12,1,13,1,14, - 1,15,1,16,1,17,1,18,1,19,1,20,1,21,1,22,1,23,1,24,1,25,1,26,1,27,1,28,1,29,1,30,1,31,1,32,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,13,0,14,0,15,0,16,0,17,0,18,0,19,0,20,0,21,0, - 22,0,23,0,24,0,25,0,26,0,27,0,28,0,29,0,30,0,31,130,187,8,66,33,0,34,0,35,0,36,0,37,0,38,0,39,0,40,0,41,0,42,0,43,0,44,0,45,0,46,0,47,0,48,0,49,0,50,0,51,0,52,0,53,0,54,0,55,0,56,0, - 57,0,58,0,59,0,60,0,61,0,62,0,63,0,64,0,65,0,66,130,243,9,75,68,0,69,0,70,0,71,0,72,0,73,0,74,0,75,0,76,0,77,0,78,0,79,0,80,0,81,0,82,0,83,0,84,0,85,0,86,0,87,0,88,0,89,0,90,0,91,0, - 92,0,93,0,94,0,95,0,96,0,97,1,33,1,34,1,35,1,36,1,37,1,38,1,39,1,40,1,41,1,42,1,43,1,44,1,45,1,46,1,47,1,48,1,49,1,50,1,51,1,52,1,53,1,54,1,55,1,56,1,57,1,58,1,59,1,60,1,61,1,62,1, - 63,1,64,1,65,0,172,0,163,0,132,0,133,0,189,0,150,0,232,0,134,0,142,0,139,0,157,0,169,0,164,0,239,0,138,0,218,0,131,0,147,0,242,0,243,0,141,0,151,0,136,0,195,0,222,0,241,0,158,0,170, - 0,245,0,244,0,246,0,162,0,173,0,201,0,199,0,174,0,98,0,99,0,144,0,100,0,203,0,101,0,200,0,202,0,207,0,204,0,205,0,206,0,233,0,102,0,211,0,208,0,209,0,175,0,103,0,240,0,145,0,214,0, - 212,0,213,0,104,0,235,0,237,0,137,0,106,0,105,0,107,0,109,0,108,0,110,0,160,0,111,0,113,0,112,0,114,0,115,0,117,0,116,0,118,0,119,0,234,0,120,0,122,0,121,0,123,0,125,0,124,0,184,0, - 161,0,127,0,126,0,128,0,129,0,236,0,238,0,186,14,117,110,105,99,111,100,101,35,48,120,48,48,48,49,141,14,32,50,141,14,32,51,141,14,32,52,141,14,32,53,141,14,32,54,141,14,32,55,141, - 14,32,56,141,14,32,57,141,14,32,97,141,14,32,98,141,14,32,99,141,14,32,100,141,14,32,101,141,14,32,102,140,14,33,49,48,141,14,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49, - 141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,45,49,102,6,100,101,108,101,116,101,4,69,117,114, - 111,140,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236, - 32,56,141,236,32,56,141,236,32,56,65,220,13,32,57,65,220,13,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141, - 239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,35,57,102,0,0,5,250,72,249,98,247, +static const unsigned char proggy_clean_ttf_compressed_data[9583] = { + 87, 188, 0, 0, 0, 0, 0, 0, 0, 0, 160, 248, 0, 4, 0, 0, 55, 0, 1, 0, 0, 0, 12, + 0, 128, 0, 3, 0, 64, 79, 83, 47, 50, 136, 235, 116, 144, 0, 0, 1, 72, 130, 21, 44, 78, 99, + 109, 97, 112, 2, 18, 35, 117, 0, 0, 3, 160, 130, 19, 36, 82, 99, 118, 116, 32, 130, 23, 130, 2, + 33, 4, 252, 130, 4, 56, 2, 103, 108, 121, 102, 18, 175, 137, 86, 0, 0, 7, 4, 0, 0, 146, 128, + 104, 101, 97, 100, 215, 145, 102, 211, 130, 27, 32, 204, 130, 3, 33, 54, 104, 130, 16, 39, 8, 66, 1, + 195, 0, 0, 1, 4, 130, 15, 59, 36, 104, 109, 116, 120, 138, 0, 126, 128, 0, 0, 1, 152, 0, 0, + 2, 6, 108, 111, 99, 97, 140, 115, 176, 216, 0, 0, 5, 130, 30, 41, 2, 4, 109, 97, 120, 112, 1, + 174, 0, 218, 130, 31, 32, 40, 130, 16, 44, 32, 110, 97, 109, 101, 37, 89, 187, 150, 0, 0, 153, 132, + 130, 19, 44, 158, 112, 111, 115, 116, 166, 172, 131, 239, 0, 0, 155, 36, 130, 51, 44, 210, 112, 114, 101, + 112, 105, 2, 1, 18, 0, 0, 4, 244, 130, 47, 32, 8, 132, 203, 46, 1, 0, 0, 60, 85, 233, 213, + 95, 15, 60, 245, 0, 3, 8, 0, 131, 0, 34, 183, 103, 119, 130, 63, 43, 0, 0, 189, 146, 166, 215, + 0, 0, 254, 128, 3, 128, 131, 111, 130, 241, 33, 2, 0, 133, 0, 32, 1, 130, 65, 38, 192, 254, 64, + 0, 0, 3, 128, 131, 16, 130, 5, 32, 1, 131, 7, 138, 3, 33, 2, 0, 130, 17, 36, 1, 1, 0, + 144, 0, 130, 121, 130, 23, 38, 2, 0, 8, 0, 64, 0, 10, 130, 9, 32, 118, 130, 9, 130, 6, 32, + 0, 130, 59, 33, 1, 144, 131, 200, 35, 2, 188, 2, 138, 130, 16, 32, 143, 133, 7, 37, 1, 197, 0, + 50, 2, 0, 131, 0, 33, 4, 9, 131, 5, 145, 3, 43, 65, 108, 116, 115, 0, 64, 0, 0, 32, 172, + 8, 0, 131, 0, 35, 5, 0, 1, 128, 131, 77, 131, 3, 33, 3, 128, 191, 1, 33, 1, 128, 130, 184, + 35, 0, 0, 128, 0, 130, 3, 131, 11, 32, 1, 130, 7, 33, 0, 128, 131, 1, 32, 1, 136, 9, 32, + 0, 132, 15, 135, 5, 32, 1, 131, 13, 135, 27, 144, 35, 32, 1, 149, 25, 131, 21, 32, 0, 130, 0, + 32, 128, 132, 103, 130, 35, 132, 39, 32, 0, 136, 45, 136, 97, 133, 17, 130, 5, 33, 0, 0, 136, 19, + 34, 0, 128, 1, 133, 13, 133, 5, 32, 128, 130, 15, 132, 131, 32, 3, 130, 5, 32, 3, 132, 27, 144, + 71, 32, 0, 133, 27, 130, 29, 130, 31, 136, 29, 131, 63, 131, 3, 65, 63, 5, 132, 5, 132, 205, 130, + 9, 33, 0, 0, 131, 9, 137, 119, 32, 3, 132, 19, 138, 243, 130, 55, 32, 1, 132, 35, 135, 19, 131, + 201, 136, 11, 132, 143, 137, 13, 130, 41, 32, 0, 131, 3, 144, 35, 33, 128, 0, 135, 1, 131, 223, 131, + 3, 141, 17, 134, 13, 136, 63, 134, 15, 136, 53, 143, 15, 130, 96, 33, 0, 3, 131, 4, 130, 3, 34, + 28, 0, 1, 130, 5, 34, 0, 0, 76, 130, 17, 131, 9, 36, 28, 0, 4, 0, 48, 130, 17, 46, 8, + 0, 8, 0, 2, 0, 0, 0, 127, 0, 255, 32, 172, 255, 255, 130, 9, 34, 0, 0, 129, 132, 9, 130, + 102, 33, 223, 213, 134, 53, 132, 22, 33, 1, 6, 132, 6, 64, 4, 215, 32, 129, 165, 216, 39, 177, 0, + 1, 141, 184, 1, 255, 133, 134, 45, 33, 198, 0, 193, 1, 8, 190, 244, 1, 28, 1, 158, 2, 20, 2, + 136, 2, 252, 3, 20, 3, 88, 3, 156, 3, 222, 4, 20, 4, 50, 4, 80, 4, 98, 4, 162, 5, 22, + 5, 102, 5, 188, 6, 18, 6, 116, 6, 214, 7, 56, 7, 126, 7, 236, 8, 78, 8, 108, 8, 150, 8, + 208, 9, 16, 9, 74, 9, 136, 10, 22, 10, 128, 11, 4, 11, 86, 11, 200, 12, 46, 12, 130, 12, 234, + 13, 94, 13, 164, 13, 234, 14, 80, 14, 150, 15, 40, 15, 176, 16, 18, 16, 116, 16, 224, 17, 82, 17, + 182, 18, 4, 18, 110, 18, 196, 19, 76, 19, 172, 19, 246, 20, 88, 20, 174, 20, 234, 21, 64, 21, 128, + 21, 166, 21, 184, 22, 18, 22, 126, 22, 198, 23, 52, 23, 142, 23, 224, 24, 86, 24, 186, 24, 238, 25, + 54, 25, 150, 25, 212, 26, 72, 26, 156, 26, 240, 27, 92, 27, 200, 28, 4, 28, 76, 28, 150, 28, 234, + 29, 42, 29, 146, 29, 210, 30, 64, 30, 142, 30, 224, 31, 36, 31, 118, 31, 166, 31, 166, 32, 16, 130, + 1, 52, 46, 32, 138, 32, 178, 32, 200, 33, 20, 33, 116, 33, 152, 33, 238, 34, 98, 34, 134, 35, 12, + 130, 1, 33, 128, 35, 131, 1, 60, 152, 35, 176, 35, 216, 36, 0, 36, 74, 36, 104, 36, 144, 36, 174, + 37, 6, 37, 96, 37, 130, 37, 248, 37, 248, 38, 88, 38, 170, 130, 1, 8, 190, 216, 39, 64, 39, 154, + 40, 10, 40, 104, 40, 168, 41, 14, 41, 32, 41, 184, 41, 248, 42, 54, 42, 96, 42, 96, 43, 2, 43, + 42, 43, 94, 43, 172, 43, 230, 44, 32, 44, 52, 44, 154, 45, 40, 45, 92, 45, 120, 45, 170, 45, 232, + 46, 38, 46, 166, 47, 38, 47, 182, 47, 244, 48, 94, 48, 200, 49, 62, 49, 180, 50, 30, 50, 158, 51, + 30, 51, 130, 51, 238, 52, 92, 52, 206, 53, 58, 53, 134, 53, 212, 54, 38, 54, 114, 54, 230, 55, 118, + 55, 216, 56, 58, 56, 166, 57, 18, 57, 116, 57, 174, 58, 46, 58, 154, 59, 6, 59, 124, 59, 232, 60, + 58, 60, 150, 61, 34, 61, 134, 61, 236, 62, 86, 62, 198, 63, 42, 63, 154, 64, 18, 64, 106, 64, 208, + 65, 54, 65, 162, 66, 8, 66, 64, 66, 122, 66, 184, 66, 240, 67, 98, 67, 204, 68, 42, 68, 138, 68, + 238, 69, 88, 69, 182, 69, 226, 70, 84, 70, 180, 71, 20, 71, 122, 71, 218, 72, 84, 72, 198, 73, 64, + 0, 36, 70, 21, 8, 8, 77, 3, 0, 7, 0, 11, 0, 15, 0, 19, 0, 23, 0, 27, 0, 31, 0, + 35, 0, 39, 0, 43, 0, 47, 0, 51, 0, 55, 0, 59, 0, 63, 0, 67, 0, 71, 0, 75, 0, 79, + 0, 83, 0, 87, 0, 91, 0, 95, 0, 99, 0, 103, 0, 107, 0, 111, 0, 115, 0, 119, 0, 123, 0, + 127, 0, 131, 0, 135, 0, 139, 0, 143, 0, 0, 17, 53, 51, 21, 49, 150, 3, 32, 5, 130, 23, 32, + 33, 130, 3, 211, 7, 151, 115, 32, 128, 133, 0, 37, 252, 128, 128, 2, 128, 128, 190, 5, 133, 74, 32, + 4, 133, 6, 206, 5, 42, 0, 7, 1, 128, 0, 0, 2, 0, 4, 0, 0, 65, 139, 13, 37, 0, 1, + 53, 51, 21, 7, 146, 3, 32, 3, 130, 19, 32, 1, 141, 133, 32, 3, 141, 14, 131, 13, 38, 255, 0, + 128, 128, 0, 6, 1, 130, 84, 35, 2, 128, 4, 128, 140, 91, 132, 89, 32, 51, 65, 143, 6, 139, 7, + 33, 1, 0, 130, 57, 32, 254, 130, 3, 32, 128, 132, 4, 32, 4, 131, 14, 138, 89, 35, 0, 0, 24, + 0, 130, 0, 33, 3, 128, 144, 171, 66, 55, 33, 148, 115, 65, 187, 19, 32, 5, 130, 151, 143, 155, 163, + 39, 32, 1, 136, 182, 32, 253, 134, 178, 132, 7, 132, 200, 145, 17, 32, 3, 65, 48, 17, 165, 17, 39, + 0, 0, 21, 0, 128, 255, 128, 3, 65, 175, 17, 65, 3, 27, 132, 253, 131, 217, 139, 201, 155, 233, 155, + 27, 131, 67, 131, 31, 130, 241, 33, 255, 0, 131, 181, 137, 232, 132, 15, 132, 4, 138, 247, 34, 255, 0, + 128, 179, 238, 32, 0, 130, 0, 32, 20, 65, 239, 48, 33, 0, 19, 67, 235, 10, 32, 51, 65, 203, 14, + 65, 215, 11, 32, 7, 154, 27, 135, 39, 32, 33, 130, 35, 33, 128, 128, 130, 231, 32, 253, 132, 231, 32, + 128, 132, 232, 34, 128, 128, 254, 133, 13, 136, 8, 32, 253, 65, 186, 5, 130, 36, 130, 42, 176, 234, 133, + 231, 34, 128, 0, 0, 66, 215, 44, 33, 0, 1, 68, 235, 6, 68, 211, 19, 32, 49, 68, 239, 14, 139, + 207, 139, 47, 66, 13, 7, 32, 51, 130, 47, 33, 1, 0, 130, 207, 35, 128, 128, 1, 0, 131, 222, 131, + 5, 130, 212, 130, 6, 131, 212, 32, 0, 130, 10, 133, 220, 130, 233, 130, 226, 32, 254, 133, 255, 178, 233, + 39, 3, 1, 128, 3, 0, 2, 0, 4, 68, 15, 7, 68, 99, 12, 130, 89, 130, 104, 33, 128, 4, 133, + 93, 130, 10, 38, 0, 0, 11, 1, 0, 255, 0, 68, 63, 16, 70, 39, 9, 66, 215, 8, 32, 7, 68, + 77, 6, 68, 175, 14, 32, 29, 68, 195, 6, 132, 7, 35, 2, 0, 128, 255, 131, 91, 132, 4, 65, 178, + 5, 141, 111, 67, 129, 23, 165, 135, 140, 107, 142, 135, 33, 21, 5, 69, 71, 6, 131, 7, 33, 1, 0, + 140, 104, 132, 142, 130, 4, 137, 247, 140, 30, 68, 255, 12, 39, 11, 0, 128, 0, 128, 3, 0, 3, 69, + 171, 15, 67, 251, 7, 65, 15, 8, 66, 249, 11, 65, 229, 7, 67, 211, 7, 66, 13, 7, 35, 1, 128, + 128, 254, 133, 93, 32, 254, 131, 145, 132, 4, 132, 18, 32, 2, 151, 128, 130, 23, 34, 0, 0, 9, 154, + 131, 65, 207, 8, 68, 107, 15, 68, 51, 7, 32, 7, 70, 59, 7, 135, 121, 130, 82, 32, 128, 151, 111, + 41, 0, 0, 4, 0, 128, 255, 0, 1, 128, 1, 137, 239, 33, 0, 37, 70, 145, 10, 65, 77, 10, 65, + 212, 14, 37, 0, 0, 0, 5, 0, 128, 66, 109, 5, 70, 123, 10, 33, 0, 19, 72, 33, 18, 133, 237, + 70, 209, 11, 33, 0, 2, 130, 113, 137, 119, 136, 115, 33, 1, 0, 133, 43, 130, 5, 34, 0, 0, 10, + 69, 135, 6, 70, 219, 13, 66, 155, 7, 65, 9, 12, 66, 157, 11, 66, 9, 11, 32, 7, 130, 141, 132, + 252, 66, 151, 9, 137, 9, 66, 15, 30, 36, 0, 20, 0, 128, 0, 130, 218, 71, 11, 42, 68, 51, 8, + 65, 141, 7, 73, 19, 15, 69, 47, 23, 143, 39, 66, 81, 7, 32, 1, 66, 55, 6, 34, 1, 128, 128, + 68, 25, 5, 69, 32, 6, 137, 6, 136, 25, 32, 254, 131, 42, 32, 3, 66, 88, 26, 148, 26, 32, 0, + 130, 0, 32, 14, 164, 231, 70, 225, 12, 66, 233, 7, 67, 133, 19, 71, 203, 15, 130, 161, 32, 255, 130, + 155, 32, 254, 139, 127, 134, 12, 164, 174, 33, 0, 15, 164, 159, 33, 59, 0, 65, 125, 20, 66, 25, 7, + 32, 5, 68, 191, 6, 66, 29, 7, 144, 165, 65, 105, 9, 35, 128, 128, 255, 0, 137, 2, 133, 182, 164, + 169, 33, 128, 128, 197, 171, 130, 155, 68, 235, 7, 32, 21, 70, 77, 19, 66, 21, 10, 68, 97, 8, 66, + 30, 5, 66, 4, 43, 34, 0, 17, 0, 71, 19, 41, 65, 253, 20, 71, 25, 23, 65, 91, 15, 65, 115, + 7, 34, 2, 128, 128, 66, 9, 8, 130, 169, 33, 1, 0, 66, 212, 13, 132, 28, 72, 201, 43, 35, 0, + 0, 0, 18, 66, 27, 38, 76, 231, 5, 68, 157, 20, 135, 157, 32, 7, 68, 185, 13, 65, 129, 28, 66, + 20, 5, 32, 253, 66, 210, 11, 65, 128, 49, 133, 61, 32, 0, 65, 135, 6, 74, 111, 37, 72, 149, 12, + 66, 203, 19, 65, 147, 19, 68, 93, 7, 68, 85, 8, 76, 4, 5, 33, 255, 0, 133, 129, 34, 254, 0, + 128, 68, 69, 8, 181, 197, 34, 0, 0, 12, 65, 135, 32, 65, 123, 20, 69, 183, 27, 133, 156, 66, 50, + 5, 72, 87, 10, 67, 137, 32, 33, 0, 19, 160, 139, 78, 251, 13, 68, 55, 20, 67, 119, 19, 65, 91, + 36, 69, 177, 15, 32, 254, 143, 16, 65, 98, 53, 32, 128, 130, 0, 32, 0, 66, 43, 54, 70, 141, 23, + 66, 23, 15, 131, 39, 69, 47, 11, 131, 15, 70, 129, 19, 74, 161, 9, 36, 128, 255, 0, 128, 254, 130, + 153, 65, 148, 32, 67, 41, 9, 34, 0, 0, 4, 79, 15, 5, 73, 99, 10, 71, 203, 8, 32, 3, 72, + 123, 6, 72, 43, 8, 32, 2, 133, 56, 131, 99, 130, 9, 34, 0, 0, 6, 72, 175, 5, 73, 159, 14, + 144, 63, 135, 197, 132, 189, 133, 66, 33, 255, 0, 73, 6, 7, 70, 137, 12, 35, 0, 0, 0, 10, 130, + 3, 73, 243, 25, 67, 113, 12, 65, 73, 7, 69, 161, 7, 138, 7, 37, 21, 2, 0, 128, 128, 254, 134, + 3, 73, 116, 27, 33, 128, 128, 130, 111, 39, 12, 0, 128, 1, 0, 3, 128, 2, 72, 219, 21, 35, 43, + 0, 47, 0, 67, 47, 20, 130, 111, 33, 21, 1, 68, 167, 13, 81, 147, 8, 133, 230, 32, 128, 77, 73, + 6, 32, 128, 131, 142, 134, 18, 130, 6, 32, 255, 75, 18, 12, 131, 243, 37, 128, 0, 128, 3, 128, 3, + 74, 231, 21, 135, 123, 32, 29, 134, 107, 135, 7, 32, 21, 74, 117, 7, 135, 7, 134, 96, 135, 246, 74, + 103, 23, 132, 242, 33, 0, 10, 67, 151, 28, 67, 133, 20, 66, 141, 11, 131, 11, 32, 3, 77, 71, 6, + 32, 128, 130, 113, 32, 1, 81, 4, 6, 134, 218, 66, 130, 24, 131, 31, 34, 0, 26, 0, 130, 0, 77, + 255, 44, 83, 15, 11, 148, 155, 68, 13, 7, 32, 49, 78, 231, 18, 79, 7, 11, 73, 243, 11, 32, 33, + 65, 187, 10, 130, 63, 65, 87, 8, 73, 239, 19, 35, 0, 128, 1, 0, 131, 226, 32, 252, 65, 100, 6, + 32, 128, 139, 8, 33, 1, 0, 130, 21, 32, 253, 72, 155, 44, 73, 255, 20, 32, 128, 71, 67, 8, 81, + 243, 39, 67, 15, 20, 74, 191, 23, 68, 121, 27, 32, 1, 66, 150, 6, 32, 254, 79, 19, 11, 131, 214, + 32, 128, 130, 215, 37, 2, 0, 128, 253, 0, 128, 136, 5, 65, 220, 24, 147, 212, 130, 210, 33, 0, 24, + 72, 219, 42, 84, 255, 13, 67, 119, 16, 69, 245, 19, 72, 225, 19, 65, 3, 15, 69, 93, 19, 131, 55, + 132, 178, 71, 115, 14, 81, 228, 6, 142, 245, 33, 253, 0, 132, 43, 172, 252, 65, 16, 11, 75, 219, 8, + 65, 219, 31, 66, 223, 24, 75, 223, 10, 33, 29, 1, 80, 243, 10, 66, 175, 8, 131, 110, 134, 203, 133, + 172, 130, 16, 70, 30, 7, 164, 183, 130, 163, 32, 20, 65, 171, 48, 65, 163, 36, 65, 143, 23, 65, 151, + 19, 65, 147, 13, 65, 134, 17, 133, 17, 130, 216, 67, 114, 5, 164, 217, 65, 137, 12, 72, 147, 48, 79, + 71, 19, 74, 169, 22, 80, 251, 8, 65, 173, 7, 66, 157, 15, 74, 173, 15, 32, 254, 65, 170, 8, 71, + 186, 45, 72, 131, 6, 77, 143, 40, 187, 195, 152, 179, 65, 123, 38, 68, 215, 57, 68, 179, 15, 65, 85, + 7, 69, 187, 14, 32, 21, 66, 95, 15, 67, 19, 25, 32, 1, 83, 223, 6, 32, 2, 76, 240, 7, 77, + 166, 43, 65, 8, 5, 130, 206, 32, 0, 67, 39, 54, 143, 167, 66, 255, 19, 82, 193, 11, 151, 47, 85, + 171, 5, 67, 27, 17, 132, 160, 69, 172, 11, 69, 184, 56, 66, 95, 6, 33, 12, 1, 130, 237, 32, 2, + 68, 179, 27, 68, 175, 16, 80, 135, 15, 72, 55, 7, 71, 87, 12, 73, 3, 12, 132, 12, 66, 75, 32, + 76, 215, 5, 169, 139, 147, 135, 148, 139, 81, 12, 12, 81, 185, 36, 75, 251, 7, 65, 23, 27, 76, 215, + 9, 87, 165, 12, 65, 209, 15, 72, 157, 7, 65, 245, 31, 32, 128, 71, 128, 6, 32, 1, 82, 125, 5, + 34, 0, 128, 254, 131, 169, 32, 254, 131, 187, 71, 180, 9, 132, 27, 32, 2, 88, 129, 44, 32, 0, 78, + 47, 40, 65, 79, 23, 79, 171, 14, 32, 21, 71, 87, 8, 72, 15, 14, 65, 224, 33, 130, 139, 74, 27, + 62, 93, 23, 7, 68, 31, 7, 75, 27, 7, 139, 15, 74, 3, 7, 74, 23, 27, 65, 165, 11, 65, 177, + 15, 67, 123, 5, 32, 1, 130, 221, 32, 252, 71, 96, 5, 74, 12, 12, 133, 244, 130, 25, 34, 1, 0, + 128, 130, 2, 139, 8, 93, 26, 8, 65, 9, 32, 65, 57, 14, 140, 14, 32, 0, 73, 79, 67, 68, 119, + 11, 135, 11, 32, 51, 90, 75, 14, 139, 247, 65, 43, 7, 131, 19, 139, 11, 69, 159, 11, 65, 247, 6, + 36, 1, 128, 128, 253, 0, 90, 71, 9, 33, 1, 0, 132, 14, 32, 128, 89, 93, 14, 69, 133, 6, 130, + 44, 131, 30, 131, 6, 65, 20, 56, 33, 0, 16, 72, 179, 40, 75, 47, 12, 65, 215, 19, 74, 95, 19, + 65, 43, 11, 131, 168, 67, 110, 5, 75, 23, 17, 69, 106, 6, 75, 65, 5, 71, 204, 43, 32, 0, 80, + 75, 47, 71, 203, 15, 159, 181, 68, 91, 11, 67, 197, 7, 73, 101, 13, 68, 85, 6, 33, 128, 128, 130, + 214, 130, 25, 32, 254, 74, 236, 48, 130, 194, 37, 0, 18, 0, 128, 255, 128, 77, 215, 40, 65, 139, 64, + 32, 51, 80, 159, 10, 65, 147, 39, 130, 219, 84, 212, 43, 130, 46, 75, 19, 97, 74, 33, 11, 65, 201, + 23, 65, 173, 31, 33, 1, 0, 79, 133, 6, 66, 150, 5, 67, 75, 48, 85, 187, 6, 70, 207, 37, 32, + 71, 87, 221, 13, 73, 163, 14, 80, 167, 15, 132, 15, 83, 193, 19, 82, 209, 8, 78, 99, 9, 72, 190, + 11, 77, 110, 49, 89, 63, 5, 80, 91, 35, 99, 63, 32, 70, 235, 23, 81, 99, 10, 69, 148, 10, 65, + 110, 36, 32, 0, 65, 99, 47, 95, 219, 11, 68, 171, 51, 66, 87, 7, 72, 57, 7, 74, 45, 17, 143, + 17, 65, 114, 50, 33, 14, 0, 65, 111, 40, 159, 195, 98, 135, 15, 35, 7, 53, 51, 21, 100, 78, 9, + 95, 146, 16, 32, 254, 82, 114, 6, 32, 128, 67, 208, 37, 130, 166, 99, 79, 58, 32, 17, 96, 99, 14, + 72, 31, 19, 72, 87, 31, 82, 155, 7, 67, 47, 14, 32, 21, 131, 75, 134, 231, 72, 51, 17, 72, 78, + 8, 133, 8, 80, 133, 6, 33, 253, 128, 88, 37, 9, 66, 124, 36, 72, 65, 12, 134, 12, 71, 55, 43, + 66, 139, 27, 85, 135, 10, 91, 33, 12, 65, 35, 11, 66, 131, 11, 71, 32, 8, 90, 127, 6, 130, 244, + 71, 76, 11, 168, 207, 33, 0, 12, 66, 123, 32, 32, 0, 65, 183, 15, 68, 135, 11, 66, 111, 7, 67, + 235, 11, 66, 111, 15, 32, 254, 97, 66, 12, 160, 154, 67, 227, 52, 80, 33, 15, 87, 249, 15, 93, 45, + 31, 75, 111, 12, 93, 45, 11, 77, 99, 9, 160, 184, 81, 31, 12, 32, 15, 98, 135, 30, 104, 175, 7, + 77, 249, 36, 69, 73, 15, 78, 5, 12, 32, 254, 66, 151, 19, 34, 128, 128, 4, 87, 32, 12, 149, 35, + 133, 21, 96, 151, 31, 32, 19, 72, 35, 5, 98, 173, 15, 143, 15, 32, 21, 143, 99, 158, 129, 33, 0, + 0, 65, 35, 52, 65, 11, 15, 147, 15, 98, 75, 11, 33, 1, 0, 143, 151, 132, 15, 32, 254, 99, 200, + 37, 132, 43, 130, 4, 39, 0, 10, 0, 128, 1, 128, 3, 0, 104, 151, 14, 97, 187, 20, 69, 131, 15, + 67, 195, 11, 87, 227, 7, 33, 128, 128, 132, 128, 33, 254, 0, 68, 131, 9, 65, 46, 26, 42, 0, 0, + 0, 7, 0, 0, 255, 128, 3, 128, 0, 88, 223, 15, 33, 0, 21, 89, 61, 22, 66, 209, 12, 65, 2, + 12, 37, 0, 2, 1, 0, 3, 128, 101, 83, 8, 36, 0, 1, 53, 51, 29, 130, 3, 34, 21, 1, 0, + 66, 53, 8, 32, 0, 68, 215, 6, 100, 55, 25, 107, 111, 9, 66, 193, 11, 72, 167, 8, 73, 143, 31, + 139, 31, 33, 1, 0, 131, 158, 32, 254, 132, 5, 33, 253, 128, 65, 16, 9, 133, 17, 89, 130, 25, 141, + 212, 33, 0, 0, 93, 39, 8, 90, 131, 25, 93, 39, 14, 66, 217, 6, 106, 179, 8, 159, 181, 71, 125, + 15, 139, 47, 138, 141, 87, 11, 14, 76, 23, 14, 65, 231, 26, 140, 209, 66, 122, 8, 81, 179, 5, 101, + 195, 26, 32, 47, 74, 75, 13, 69, 159, 11, 83, 235, 11, 67, 21, 16, 136, 167, 131, 106, 130, 165, 130, + 15, 32, 128, 101, 90, 24, 134, 142, 32, 0, 65, 103, 51, 108, 23, 11, 101, 231, 15, 75, 173, 23, 74, + 237, 23, 66, 15, 6, 66, 46, 17, 66, 58, 17, 65, 105, 49, 66, 247, 55, 71, 179, 12, 70, 139, 15, + 86, 229, 7, 84, 167, 15, 32, 1, 95, 72, 12, 89, 49, 6, 33, 128, 128, 65, 136, 38, 66, 30, 9, + 32, 0, 100, 239, 7, 66, 247, 29, 70, 105, 20, 65, 141, 19, 69, 81, 15, 130, 144, 32, 128, 83, 41, + 5, 32, 255, 131, 177, 68, 185, 5, 133, 126, 65, 97, 37, 32, 0, 130, 0, 33, 21, 0, 130, 55, 66, + 195, 28, 67, 155, 13, 34, 79, 0, 83, 66, 213, 13, 73, 241, 19, 66, 59, 19, 65, 125, 11, 135, 201, + 66, 249, 16, 32, 128, 66, 44, 11, 66, 56, 17, 68, 143, 8, 68, 124, 38, 67, 183, 12, 96, 211, 9, + 65, 143, 29, 112, 171, 5, 32, 0, 68, 131, 63, 34, 33, 53, 51, 71, 121, 11, 32, 254, 98, 251, 16, + 32, 253, 74, 231, 10, 65, 175, 37, 133, 206, 37, 0, 0, 8, 1, 0, 0, 107, 123, 11, 113, 115, 9, + 33, 0, 1, 130, 117, 131, 3, 73, 103, 7, 66, 51, 18, 66, 44, 5, 133, 75, 70, 88, 5, 32, 254, + 65, 39, 12, 68, 80, 9, 34, 12, 0, 128, 107, 179, 28, 68, 223, 6, 155, 111, 86, 147, 15, 32, 2, + 131, 82, 141, 110, 33, 254, 0, 130, 15, 32, 4, 103, 184, 15, 141, 35, 87, 176, 5, 83, 11, 5, 71, + 235, 23, 114, 107, 11, 65, 189, 16, 70, 33, 15, 86, 153, 31, 135, 126, 86, 145, 30, 65, 183, 41, 32, + 0, 130, 0, 32, 10, 65, 183, 24, 34, 35, 0, 39, 67, 85, 9, 65, 179, 15, 143, 15, 33, 1, 0, + 65, 28, 17, 157, 136, 130, 123, 32, 20, 130, 3, 32, 0, 97, 135, 24, 115, 167, 19, 80, 71, 12, 32, + 51, 110, 163, 14, 78, 35, 19, 131, 19, 155, 23, 77, 229, 8, 78, 9, 17, 151, 17, 67, 231, 46, 94, + 135, 8, 73, 31, 31, 93, 215, 56, 82, 171, 25, 72, 77, 8, 162, 179, 169, 167, 99, 131, 11, 69, 85, + 19, 66, 215, 15, 76, 129, 13, 68, 115, 22, 72, 79, 35, 67, 113, 5, 34, 0, 0, 19, 70, 31, 46, + 65, 89, 52, 73, 223, 15, 85, 199, 33, 95, 33, 8, 132, 203, 73, 29, 32, 67, 48, 16, 177, 215, 101, + 13, 15, 65, 141, 43, 69, 141, 15, 75, 89, 5, 70, 0, 11, 70, 235, 21, 178, 215, 36, 10, 0, 128, + 0, 0, 71, 207, 24, 33, 0, 19, 100, 67, 6, 80, 215, 11, 66, 67, 7, 80, 43, 12, 71, 106, 7, + 80, 192, 5, 65, 63, 5, 66, 217, 26, 33, 0, 13, 156, 119, 68, 95, 5, 72, 233, 12, 134, 129, 85, + 81, 11, 76, 165, 20, 65, 43, 8, 73, 136, 8, 75, 10, 31, 38, 128, 128, 0, 0, 0, 13, 1, 130, + 4, 32, 3, 106, 235, 29, 114, 179, 12, 66, 131, 23, 32, 7, 77, 133, 6, 67, 89, 12, 131, 139, 116, + 60, 9, 89, 15, 37, 32, 0, 74, 15, 7, 103, 11, 22, 65, 35, 5, 33, 55, 0, 93, 81, 28, 67, + 239, 23, 78, 85, 5, 107, 93, 14, 66, 84, 17, 65, 193, 26, 74, 183, 10, 66, 67, 34, 143, 135, 79, + 91, 15, 32, 7, 117, 111, 8, 75, 56, 9, 84, 212, 9, 154, 134, 32, 0, 130, 0, 32, 18, 130, 3, + 70, 171, 41, 83, 7, 16, 70, 131, 19, 84, 191, 15, 84, 175, 19, 84, 167, 30, 84, 158, 12, 154, 193, + 68, 107, 15, 33, 0, 0, 65, 79, 42, 65, 71, 7, 73, 55, 7, 118, 191, 16, 83, 180, 9, 32, 255, + 76, 166, 9, 154, 141, 32, 0, 130, 0, 69, 195, 52, 65, 225, 15, 151, 15, 75, 215, 31, 80, 56, 10, + 68, 240, 17, 100, 32, 9, 70, 147, 39, 65, 93, 12, 71, 71, 41, 92, 85, 15, 84, 135, 23, 78, 35, + 15, 110, 27, 10, 84, 125, 8, 107, 115, 29, 136, 160, 38, 0, 0, 14, 0, 128, 255, 0, 82, 155, 24, + 67, 239, 8, 119, 255, 11, 69, 131, 11, 77, 29, 6, 112, 31, 8, 134, 27, 105, 203, 8, 32, 2, 75, + 51, 11, 75, 195, 12, 74, 13, 29, 136, 161, 37, 128, 0, 0, 0, 11, 1, 130, 163, 82, 115, 8, 125, + 191, 17, 69, 35, 12, 74, 137, 15, 143, 15, 32, 1, 65, 157, 12, 136, 12, 161, 142, 65, 43, 40, 65, + 199, 6, 65, 19, 24, 102, 185, 11, 76, 123, 11, 99, 6, 12, 135, 12, 32, 254, 130, 8, 161, 155, 101, + 23, 9, 39, 8, 0, 0, 1, 128, 3, 128, 2, 78, 63, 17, 72, 245, 12, 67, 41, 11, 90, 167, 9, + 32, 128, 97, 49, 9, 32, 128, 109, 51, 14, 132, 97, 81, 191, 8, 130, 97, 125, 99, 12, 121, 35, 9, + 127, 75, 15, 71, 79, 12, 81, 151, 23, 87, 97, 7, 70, 223, 15, 80, 245, 16, 105, 97, 15, 32, 254, + 113, 17, 6, 32, 128, 130, 8, 105, 105, 8, 76, 122, 18, 65, 243, 21, 74, 63, 7, 38, 4, 1, 0, + 255, 0, 2, 0, 119, 247, 28, 133, 65, 32, 255, 141, 91, 35, 0, 0, 0, 16, 67, 63, 36, 34, 59, + 0, 63, 77, 59, 9, 119, 147, 11, 143, 241, 66, 173, 15, 66, 31, 11, 67, 75, 8, 81, 74, 16, 32, + 128, 131, 255, 87, 181, 42, 127, 43, 5, 34, 255, 128, 2, 120, 235, 11, 37, 19, 0, 23, 0, 0, 37, + 109, 191, 14, 118, 219, 7, 127, 43, 14, 65, 79, 14, 35, 0, 0, 0, 3, 73, 91, 5, 130, 5, 38, + 3, 0, 7, 0, 11, 0, 0, 70, 205, 11, 88, 221, 12, 32, 0, 73, 135, 7, 87, 15, 22, 73, 135, + 10, 79, 153, 15, 97, 71, 19, 65, 49, 11, 32, 1, 131, 104, 121, 235, 11, 80, 65, 11, 142, 179, 144, + 14, 81, 123, 46, 32, 1, 88, 217, 5, 112, 5, 8, 65, 201, 15, 83, 29, 15, 122, 147, 11, 135, 179, + 142, 175, 143, 185, 67, 247, 39, 66, 199, 7, 35, 5, 0, 128, 3, 69, 203, 15, 123, 163, 12, 67, 127, + 7, 130, 119, 71, 153, 10, 141, 102, 70, 175, 8, 32, 128, 121, 235, 30, 136, 89, 100, 191, 11, 116, 195, + 11, 111, 235, 15, 72, 39, 7, 32, 2, 97, 43, 5, 132, 5, 94, 67, 8, 131, 8, 125, 253, 10, 32, + 3, 65, 158, 16, 146, 16, 130, 170, 40, 0, 21, 0, 128, 0, 0, 3, 128, 5, 88, 219, 15, 24, 64, + 159, 32, 135, 141, 65, 167, 15, 68, 163, 10, 97, 73, 49, 32, 255, 82, 58, 7, 93, 80, 8, 97, 81, + 16, 24, 67, 87, 52, 34, 0, 0, 5, 130, 231, 33, 128, 2, 80, 51, 13, 65, 129, 8, 113, 61, 6, + 132, 175, 65, 219, 5, 130, 136, 77, 152, 17, 32, 0, 95, 131, 61, 70, 215, 6, 33, 21, 51, 90, 53, + 10, 78, 97, 23, 105, 77, 31, 65, 117, 7, 139, 75, 24, 68, 195, 9, 24, 64, 22, 9, 33, 0, 128, + 130, 11, 33, 128, 128, 66, 25, 5, 121, 38, 5, 134, 5, 134, 45, 66, 40, 36, 66, 59, 18, 34, 128, + 0, 0, 66, 59, 81, 135, 245, 123, 103, 19, 120, 159, 19, 77, 175, 12, 33, 255, 0, 87, 29, 10, 94, + 70, 21, 66, 59, 54, 39, 3, 1, 128, 3, 0, 2, 128, 4, 24, 65, 7, 15, 66, 47, 7, 72, 98, + 12, 37, 0, 0, 0, 3, 1, 0, 24, 65, 55, 21, 131, 195, 32, 1, 67, 178, 6, 33, 4, 0, 77, + 141, 8, 32, 6, 131, 47, 74, 67, 16, 24, 69, 3, 20, 24, 65, 251, 7, 133, 234, 130, 229, 94, 108, + 17, 35, 0, 0, 6, 0, 141, 175, 86, 59, 5, 162, 79, 85, 166, 8, 70, 112, 13, 32, 13, 24, 64, + 67, 26, 24, 71, 255, 7, 123, 211, 12, 80, 121, 11, 69, 215, 15, 66, 217, 11, 69, 71, 10, 131, 113, + 132, 126, 119, 90, 9, 66, 117, 19, 132, 19, 32, 0, 130, 0, 24, 64, 47, 59, 33, 7, 0, 73, 227, + 5, 68, 243, 15, 85, 13, 12, 76, 37, 22, 74, 254, 15, 130, 138, 33, 0, 4, 65, 111, 6, 137, 79, + 65, 107, 16, 32, 1, 77, 200, 6, 34, 128, 128, 3, 75, 154, 12, 37, 0, 16, 0, 0, 2, 0, 104, + 115, 36, 140, 157, 68, 67, 19, 68, 51, 15, 106, 243, 15, 134, 120, 70, 37, 10, 68, 27, 10, 140, 152, + 65, 121, 24, 32, 128, 94, 155, 7, 67, 11, 8, 24, 74, 11, 25, 65, 3, 12, 83, 89, 18, 82, 21, + 37, 67, 200, 5, 130, 144, 24, 64, 172, 12, 33, 4, 0, 134, 162, 74, 80, 14, 145, 184, 32, 0, 130, + 0, 69, 251, 20, 32, 19, 81, 243, 5, 82, 143, 8, 33, 5, 53, 89, 203, 5, 133, 112, 79, 109, 15, + 33, 0, 21, 130, 71, 80, 175, 41, 36, 75, 0, 79, 0, 83, 121, 117, 9, 87, 89, 27, 66, 103, 11, + 70, 13, 15, 75, 191, 11, 135, 67, 87, 97, 20, 109, 203, 5, 69, 246, 8, 108, 171, 5, 78, 195, 38, + 65, 51, 13, 107, 203, 11, 77, 3, 17, 24, 75, 239, 17, 65, 229, 28, 79, 129, 39, 130, 175, 32, 128, + 123, 253, 7, 132, 142, 24, 65, 51, 15, 65, 239, 41, 36, 128, 128, 0, 0, 13, 65, 171, 5, 66, 163, + 28, 136, 183, 118, 137, 11, 80, 255, 15, 67, 65, 7, 74, 111, 8, 32, 0, 130, 157, 32, 253, 24, 76, + 35, 10, 103, 212, 5, 81, 175, 9, 69, 141, 7, 66, 150, 29, 131, 158, 24, 75, 199, 28, 124, 185, 7, + 76, 205, 15, 68, 124, 14, 32, 3, 123, 139, 16, 130, 16, 33, 128, 128, 108, 199, 6, 33, 0, 3, 65, + 191, 35, 107, 11, 6, 73, 197, 11, 24, 70, 121, 15, 83, 247, 15, 24, 70, 173, 23, 69, 205, 14, 32, + 253, 131, 140, 32, 254, 136, 4, 94, 198, 9, 32, 3, 78, 4, 13, 66, 127, 13, 143, 13, 32, 0, 130, + 0, 33, 16, 0, 24, 69, 59, 39, 109, 147, 12, 76, 253, 19, 24, 69, 207, 15, 69, 229, 15, 130, 195, + 71, 90, 10, 139, 10, 130, 152, 73, 43, 40, 91, 139, 10, 65, 131, 37, 35, 75, 0, 79, 0, 84, 227, + 12, 143, 151, 68, 25, 15, 80, 9, 23, 95, 169, 11, 34, 128, 2, 128, 112, 186, 5, 130, 6, 83, 161, + 19, 76, 50, 6, 130, 37, 65, 145, 44, 110, 83, 5, 32, 16, 67, 99, 6, 71, 67, 15, 76, 55, 17, + 140, 215, 67, 97, 23, 76, 69, 15, 77, 237, 11, 104, 211, 23, 77, 238, 11, 65, 154, 43, 33, 0, 10, + 83, 15, 28, 83, 13, 20, 67, 145, 19, 67, 141, 14, 97, 149, 21, 68, 9, 15, 86, 251, 5, 66, 207, + 5, 66, 27, 37, 82, 1, 23, 127, 71, 12, 94, 235, 10, 110, 175, 24, 98, 243, 15, 132, 154, 132, 4, + 24, 66, 69, 10, 32, 4, 67, 156, 43, 130, 198, 35, 2, 1, 0, 4, 75, 27, 9, 69, 85, 9, 95, + 240, 7, 32, 128, 130, 35, 32, 28, 66, 43, 40, 24, 82, 63, 23, 83, 123, 12, 72, 231, 15, 127, 59, + 23, 116, 23, 19, 117, 71, 7, 24, 77, 99, 15, 67, 111, 15, 71, 101, 8, 36, 2, 128, 128, 252, 128, + 127, 60, 11, 32, 1, 132, 16, 130, 18, 141, 24, 67, 107, 9, 32, 3, 68, 194, 15, 175, 15, 38, 0, + 11, 0, 128, 1, 128, 2, 80, 63, 25, 32, 0, 24, 65, 73, 11, 69, 185, 15, 83, 243, 16, 32, 0, + 24, 81, 165, 8, 130, 86, 77, 35, 6, 155, 163, 88, 203, 5, 24, 66, 195, 30, 70, 19, 19, 24, 80, + 133, 15, 32, 1, 75, 211, 8, 32, 254, 108, 133, 8, 79, 87, 20, 65, 32, 9, 41, 0, 0, 7, 0, + 128, 0, 0, 2, 128, 2, 68, 87, 15, 66, 1, 16, 92, 201, 16, 24, 76, 24, 17, 133, 17, 34, 128, + 0, 30, 66, 127, 64, 34, 115, 0, 119, 73, 205, 9, 66, 43, 11, 109, 143, 15, 24, 79, 203, 11, 90, + 143, 15, 131, 15, 155, 31, 65, 185, 15, 86, 87, 11, 35, 128, 128, 253, 0, 69, 7, 6, 130, 213, 33, + 1, 0, 119, 178, 15, 142, 17, 66, 141, 74, 83, 28, 6, 36, 7, 0, 0, 4, 128, 82, 39, 18, 76, + 149, 12, 67, 69, 21, 32, 128, 79, 118, 15, 32, 0, 130, 0, 32, 8, 131, 206, 32, 2, 79, 83, 9, + 100, 223, 14, 102, 113, 23, 115, 115, 7, 24, 65, 231, 12, 130, 162, 32, 4, 68, 182, 19, 130, 102, 93, + 143, 8, 69, 107, 29, 24, 77, 255, 12, 143, 197, 72, 51, 7, 76, 195, 15, 132, 139, 85, 49, 15, 130, + 152, 131, 18, 71, 81, 23, 70, 14, 11, 36, 0, 10, 0, 128, 2, 69, 59, 9, 89, 151, 15, 66, 241, + 11, 76, 165, 12, 71, 43, 15, 75, 49, 13, 65, 12, 23, 132, 37, 32, 0, 179, 115, 130, 231, 95, 181, + 16, 132, 77, 32, 254, 67, 224, 8, 65, 126, 20, 79, 171, 8, 32, 2, 89, 81, 5, 75, 143, 6, 80, + 41, 8, 34, 2, 0, 128, 24, 81, 72, 9, 32, 0, 130, 0, 35, 17, 0, 0, 255, 77, 99, 39, 95, + 65, 36, 67, 109, 15, 24, 69, 93, 11, 77, 239, 5, 95, 77, 23, 35, 128, 1, 0, 128, 24, 86, 7, + 8, 132, 167, 32, 2, 69, 198, 41, 130, 202, 33, 0, 26, 120, 75, 44, 24, 89, 51, 15, 71, 243, 12, + 70, 239, 11, 24, 84, 3, 11, 66, 7, 11, 71, 255, 10, 32, 21, 69, 155, 35, 88, 151, 12, 32, 128, + 74, 38, 10, 65, 210, 8, 74, 251, 5, 65, 226, 5, 75, 201, 13, 32, 3, 65, 9, 41, 146, 41, 40, + 0, 0, 0, 9, 1, 0, 1, 0, 2, 91, 99, 19, 32, 35, 106, 119, 13, 70, 219, 15, 83, 239, 12, + 137, 154, 32, 2, 67, 252, 19, 36, 128, 0, 0, 4, 1, 130, 196, 32, 2, 130, 8, 91, 107, 8, 32, + 0, 135, 81, 24, 73, 211, 8, 132, 161, 73, 164, 13, 36, 0, 8, 0, 128, 2, 105, 123, 26, 139, 67, + 76, 99, 15, 34, 1, 0, 128, 135, 76, 83, 156, 20, 92, 104, 8, 67, 251, 30, 24, 86, 47, 27, 123, + 207, 12, 24, 86, 7, 15, 71, 227, 8, 32, 4, 65, 20, 20, 131, 127, 32, 0, 130, 123, 32, 0, 71, + 223, 26, 32, 19, 90, 195, 22, 71, 223, 15, 84, 200, 6, 32, 128, 133, 241, 24, 84, 149, 9, 67, 41, + 25, 36, 0, 0, 0, 22, 0, 88, 111, 49, 32, 87, 66, 21, 5, 77, 3, 27, 123, 75, 7, 71, 143, + 19, 135, 183, 71, 183, 19, 130, 171, 74, 252, 5, 131, 5, 89, 87, 17, 32, 1, 132, 18, 130, 232, 68, + 11, 10, 33, 1, 128, 70, 208, 16, 66, 230, 18, 147, 18, 130, 254, 223, 255, 75, 27, 23, 65, 59, 15, + 135, 39, 155, 255, 34, 128, 128, 254, 104, 92, 8, 33, 0, 128, 65, 32, 11, 65, 1, 58, 33, 26, 0, + 130, 0, 72, 71, 18, 78, 55, 17, 76, 11, 19, 86, 101, 12, 75, 223, 11, 89, 15, 11, 24, 76, 87, + 15, 75, 235, 15, 131, 15, 72, 95, 7, 85, 71, 11, 72, 115, 11, 73, 64, 6, 34, 1, 128, 128, 66, + 215, 9, 34, 128, 254, 128, 134, 14, 33, 128, 255, 67, 102, 5, 32, 0, 130, 16, 70, 38, 11, 66, 26, + 57, 88, 11, 8, 24, 76, 215, 34, 78, 139, 7, 95, 245, 7, 32, 7, 24, 73, 75, 23, 32, 128, 131, + 167, 130, 170, 101, 158, 9, 82, 49, 22, 118, 139, 6, 32, 18, 67, 155, 44, 116, 187, 9, 108, 55, 14, + 80, 155, 23, 66, 131, 15, 93, 77, 10, 131, 168, 32, 128, 73, 211, 12, 24, 75, 187, 22, 32, 4, 96, + 71, 20, 67, 108, 19, 132, 19, 120, 207, 8, 32, 5, 76, 79, 15, 66, 111, 21, 66, 95, 8, 32, 3, + 190, 211, 111, 3, 8, 211, 212, 32, 20, 65, 167, 44, 34, 75, 0, 79, 97, 59, 13, 32, 33, 112, 63, + 10, 65, 147, 19, 69, 39, 19, 143, 39, 24, 66, 71, 9, 130, 224, 65, 185, 43, 94, 176, 12, 65, 183, + 24, 71, 38, 8, 24, 72, 167, 7, 65, 191, 38, 136, 235, 24, 96, 167, 12, 65, 203, 62, 115, 131, 13, + 65, 208, 42, 175, 235, 67, 127, 6, 32, 4, 76, 171, 29, 114, 187, 5, 32, 71, 65, 211, 5, 65, 203, + 68, 72, 51, 8, 164, 219, 32, 0, 172, 214, 71, 239, 58, 78, 3, 27, 66, 143, 15, 77, 19, 15, 147, + 31, 35, 33, 53, 51, 21, 66, 183, 10, 173, 245, 66, 170, 30, 150, 30, 34, 0, 0, 23, 80, 123, 54, + 76, 1, 16, 73, 125, 15, 82, 245, 11, 167, 253, 24, 76, 85, 12, 70, 184, 5, 32, 254, 131, 185, 37, + 254, 0, 128, 1, 0, 128, 133, 16, 117, 158, 18, 92, 27, 38, 65, 3, 17, 130, 251, 35, 17, 0, 128, + 254, 24, 69, 83, 39, 140, 243, 121, 73, 19, 109, 167, 7, 81, 41, 15, 24, 95, 175, 12, 102, 227, 15, + 121, 96, 11, 24, 95, 189, 7, 32, 3, 145, 171, 154, 17, 24, 77, 47, 9, 33, 0, 5, 70, 71, 37, + 68, 135, 7, 32, 29, 117, 171, 11, 69, 87, 15, 24, 79, 97, 19, 24, 79, 149, 23, 131, 59, 32, 1, + 75, 235, 5, 72, 115, 11, 72, 143, 7, 132, 188, 71, 27, 46, 131, 51, 32, 0, 69, 95, 6, 175, 215, + 32, 21, 131, 167, 81, 15, 19, 151, 191, 151, 23, 131, 215, 71, 43, 5, 32, 254, 24, 79, 164, 24, 74, + 109, 8, 77, 166, 13, 65, 176, 26, 88, 162, 5, 98, 159, 6, 171, 219, 120, 247, 6, 79, 29, 8, 99, + 169, 10, 103, 59, 19, 65, 209, 35, 131, 35, 91, 25, 19, 112, 94, 15, 83, 36, 8, 173, 229, 33, 20, + 0, 88, 75, 43, 71, 31, 12, 65, 191, 71, 33, 1, 0, 130, 203, 32, 254, 131, 4, 68, 66, 7, 67, + 130, 6, 104, 61, 13, 173, 215, 38, 13, 1, 0, 0, 0, 2, 128, 67, 111, 28, 74, 129, 16, 104, 35, + 19, 79, 161, 16, 87, 14, 7, 138, 143, 132, 10, 67, 62, 36, 114, 115, 5, 162, 151, 67, 33, 16, 108, + 181, 15, 143, 151, 67, 5, 5, 24, 100, 242, 15, 170, 153, 34, 0, 0, 14, 65, 51, 34, 32, 55, 79, + 75, 9, 32, 51, 74, 7, 10, 65, 57, 38, 132, 142, 32, 254, 72, 0, 14, 139, 163, 32, 128, 80, 254, + 8, 67, 158, 21, 65, 63, 7, 32, 4, 72, 227, 27, 95, 155, 12, 67, 119, 19, 124, 91, 24, 149, 154, + 72, 177, 34, 97, 223, 8, 155, 151, 24, 108, 227, 15, 88, 147, 16, 72, 117, 19, 68, 35, 11, 92, 253, + 15, 70, 199, 15, 24, 87, 209, 17, 32, 2, 87, 233, 7, 32, 1, 24, 88, 195, 10, 119, 24, 8, 32, + 3, 81, 227, 24, 65, 125, 21, 35, 128, 128, 0, 25, 76, 59, 48, 24, 90, 187, 9, 97, 235, 12, 66, + 61, 11, 91, 105, 19, 24, 79, 141, 11, 24, 79, 117, 15, 24, 79, 129, 27, 90, 53, 13, 130, 13, 32, + 253, 131, 228, 24, 79, 133, 40, 69, 70, 8, 66, 137, 31, 65, 33, 19, 96, 107, 8, 68, 119, 29, 66, + 7, 5, 68, 125, 16, 65, 253, 19, 65, 241, 27, 24, 90, 179, 13, 24, 79, 143, 18, 33, 128, 128, 130, + 246, 32, 254, 130, 168, 68, 154, 36, 77, 51, 9, 97, 47, 5, 167, 195, 32, 21, 131, 183, 78, 239, 27, + 155, 195, 78, 231, 14, 201, 196, 77, 11, 6, 32, 5, 73, 111, 37, 97, 247, 12, 77, 19, 31, 155, 207, + 78, 215, 19, 162, 212, 69, 17, 14, 66, 91, 19, 80, 143, 57, 78, 203, 39, 159, 215, 32, 128, 93, 134, + 8, 24, 80, 109, 24, 66, 113, 15, 169, 215, 66, 115, 6, 32, 4, 69, 63, 33, 32, 0, 101, 113, 7, + 86, 227, 35, 143, 211, 36, 49, 53, 51, 21, 1, 77, 185, 14, 65, 159, 28, 69, 251, 34, 67, 56, 8, + 33, 9, 0, 24, 107, 175, 25, 90, 111, 12, 110, 251, 11, 119, 189, 24, 119, 187, 34, 87, 15, 9, 32, + 4, 66, 231, 37, 90, 39, 7, 66, 239, 8, 84, 219, 15, 69, 105, 23, 24, 85, 27, 27, 87, 31, 11, + 33, 1, 128, 76, 94, 6, 32, 1, 85, 241, 7, 33, 128, 128, 106, 48, 10, 33, 128, 128, 69, 136, 11, + 133, 13, 24, 79, 116, 49, 84, 236, 8, 24, 91, 87, 9, 32, 5, 165, 255, 69, 115, 12, 66, 27, 15, + 159, 15, 24, 72, 247, 12, 74, 178, 5, 24, 80, 64, 15, 33, 0, 128, 143, 17, 77, 89, 51, 130, 214, + 24, 81, 43, 7, 170, 215, 74, 49, 8, 159, 199, 143, 31, 139, 215, 69, 143, 5, 32, 254, 24, 81, 50, + 35, 181, 217, 84, 123, 70, 143, 195, 159, 15, 65, 187, 16, 66, 123, 7, 65, 175, 15, 65, 193, 29, 68, + 207, 39, 79, 27, 5, 70, 131, 6, 32, 4, 68, 211, 33, 33, 67, 0, 83, 143, 14, 159, 207, 143, 31, + 140, 223, 33, 0, 128, 24, 80, 82, 14, 24, 93, 16, 23, 32, 253, 65, 195, 5, 68, 227, 40, 133, 214, + 107, 31, 7, 32, 5, 67, 115, 27, 87, 9, 8, 107, 31, 43, 66, 125, 6, 32, 0, 103, 177, 23, 131, + 127, 72, 203, 36, 32, 0, 110, 103, 8, 155, 163, 73, 135, 6, 32, 19, 24, 112, 99, 10, 65, 71, 11, + 73, 143, 19, 143, 31, 126, 195, 5, 24, 85, 21, 9, 24, 76, 47, 14, 32, 254, 24, 93, 77, 36, 68, + 207, 11, 39, 25, 0, 0, 255, 128, 3, 128, 4, 66, 51, 37, 95, 247, 13, 82, 255, 24, 76, 39, 19, + 147, 221, 66, 85, 27, 24, 118, 7, 8, 24, 74, 249, 12, 76, 74, 8, 91, 234, 8, 67, 80, 17, 131, + 222, 33, 253, 0, 121, 30, 44, 73, 0, 16, 69, 15, 6, 32, 0, 65, 23, 38, 69, 231, 12, 65, 179, + 6, 98, 131, 16, 86, 31, 27, 24, 108, 157, 14, 80, 160, 8, 24, 65, 46, 17, 33, 4, 0, 96, 2, + 18, 144, 191, 65, 226, 8, 68, 19, 5, 171, 199, 80, 9, 15, 180, 199, 67, 89, 5, 32, 255, 24, 79, + 173, 28, 174, 201, 24, 79, 179, 50, 32, 1, 24, 122, 5, 10, 82, 61, 10, 180, 209, 83, 19, 8, 32, + 128, 24, 80, 129, 27, 111, 248, 43, 131, 71, 24, 115, 103, 8, 67, 127, 41, 78, 213, 24, 100, 247, 19, + 66, 115, 39, 75, 107, 5, 32, 254, 165, 219, 78, 170, 40, 24, 112, 163, 49, 32, 1, 97, 203, 6, 65, + 173, 64, 32, 0, 83, 54, 7, 133, 217, 88, 37, 12, 32, 254, 131, 28, 33, 128, 3, 67, 71, 44, 84, + 183, 6, 32, 5, 69, 223, 33, 96, 7, 7, 123, 137, 16, 192, 211, 24, 112, 14, 9, 32, 255, 67, 88, + 29, 68, 14, 10, 84, 197, 38, 33, 0, 22, 116, 47, 50, 32, 87, 106, 99, 9, 116, 49, 15, 89, 225, + 15, 97, 231, 23, 70, 41, 19, 82, 85, 8, 93, 167, 6, 32, 253, 132, 236, 108, 190, 7, 89, 251, 5, + 116, 49, 58, 33, 128, 128, 131, 234, 32, 15, 24, 74, 67, 38, 70, 227, 24, 24, 83, 45, 23, 89, 219, + 12, 70, 187, 12, 89, 216, 19, 32, 2, 69, 185, 24, 141, 24, 70, 143, 66, 24, 82, 119, 56, 78, 24, + 10, 32, 253, 133, 149, 132, 6, 24, 106, 233, 7, 69, 198, 48, 178, 203, 81, 243, 12, 68, 211, 15, 106, + 255, 23, 66, 91, 15, 69, 193, 7, 100, 39, 10, 24, 83, 72, 16, 176, 204, 33, 19, 0, 88, 207, 45, + 68, 21, 12, 68, 17, 10, 65, 157, 53, 68, 17, 6, 32, 254, 92, 67, 10, 65, 161, 25, 69, 182, 43, + 24, 118, 91, 47, 69, 183, 18, 181, 209, 111, 253, 12, 89, 159, 8, 66, 112, 12, 69, 184, 45, 35, 0, + 0, 0, 9, 24, 80, 227, 26, 73, 185, 16, 118, 195, 15, 131, 15, 33, 1, 0, 65, 59, 15, 66, 39, + 27, 160, 111, 66, 205, 12, 148, 111, 143, 110, 33, 128, 128, 156, 112, 24, 81, 199, 8, 75, 199, 23, 66, + 117, 20, 155, 121, 32, 254, 68, 126, 12, 72, 213, 29, 134, 239, 149, 123, 89, 27, 16, 148, 117, 65, 245, + 8, 24, 71, 159, 14, 141, 134, 134, 28, 73, 51, 55, 109, 77, 15, 105, 131, 11, 68, 67, 11, 76, 169, + 27, 107, 209, 12, 102, 174, 8, 32, 128, 72, 100, 18, 116, 163, 56, 79, 203, 11, 75, 183, 44, 85, 119, + 19, 71, 119, 23, 151, 227, 32, 1, 93, 27, 8, 65, 122, 5, 77, 102, 8, 110, 120, 20, 66, 23, 8, + 66, 175, 17, 66, 63, 12, 133, 12, 79, 35, 8, 74, 235, 33, 67, 149, 16, 69, 243, 15, 78, 57, 15, + 69, 235, 16, 67, 177, 7, 151, 192, 130, 23, 67, 84, 29, 141, 192, 174, 187, 77, 67, 15, 69, 11, 12, + 159, 187, 77, 59, 10, 199, 189, 24, 70, 235, 50, 96, 83, 19, 66, 53, 23, 105, 65, 19, 77, 47, 12, + 163, 199, 66, 67, 37, 78, 207, 50, 67, 23, 23, 174, 205, 67, 228, 6, 71, 107, 13, 67, 22, 14, 66, + 85, 11, 83, 187, 38, 124, 47, 49, 95, 7, 19, 66, 83, 23, 67, 23, 19, 24, 96, 78, 17, 80, 101, + 16, 71, 98, 40, 33, 0, 7, 88, 131, 22, 24, 89, 245, 12, 84, 45, 12, 102, 213, 5, 123, 12, 9, + 32, 2, 126, 21, 14, 43, 255, 0, 128, 128, 0, 0, 20, 0, 128, 255, 128, 3, 126, 19, 39, 32, 75, + 106, 51, 7, 113, 129, 15, 24, 110, 135, 19, 126, 47, 15, 115, 117, 11, 69, 47, 11, 32, 2, 109, 76, + 9, 102, 109, 9, 32, 128, 75, 2, 10, 130, 21, 32, 254, 69, 47, 6, 32, 3, 94, 217, 47, 32, 0, + 65, 247, 10, 69, 15, 46, 65, 235, 31, 65, 243, 15, 101, 139, 10, 66, 174, 14, 65, 247, 16, 72, 102, + 28, 69, 17, 14, 84, 243, 9, 165, 191, 88, 47, 48, 66, 53, 12, 32, 128, 71, 108, 6, 203, 193, 32, + 17, 75, 187, 42, 73, 65, 16, 65, 133, 52, 114, 123, 9, 167, 199, 69, 21, 37, 86, 127, 44, 75, 171, + 11, 180, 197, 78, 213, 12, 148, 200, 81, 97, 46, 24, 95, 243, 9, 32, 4, 66, 75, 33, 113, 103, 9, + 87, 243, 36, 143, 225, 24, 84, 27, 31, 90, 145, 8, 148, 216, 67, 49, 5, 24, 84, 34, 14, 75, 155, + 27, 67, 52, 13, 140, 13, 36, 0, 20, 0, 128, 255, 24, 135, 99, 46, 88, 59, 43, 155, 249, 80, 165, + 7, 136, 144, 71, 161, 23, 32, 253, 132, 33, 32, 254, 88, 87, 44, 136, 84, 35, 128, 0, 0, 21, 81, + 103, 5, 94, 47, 44, 76, 51, 12, 143, 197, 151, 15, 65, 215, 31, 24, 64, 77, 13, 65, 220, 20, 65, + 214, 14, 71, 4, 40, 65, 213, 13, 32, 0, 130, 0, 35, 21, 1, 2, 0, 135, 0, 34, 36, 0, 72, + 134, 10, 36, 1, 0, 26, 0, 130, 134, 11, 36, 2, 0, 14, 0, 108, 134, 11, 32, 3, 138, 23, 32, + 4, 138, 11, 34, 5, 0, 20, 134, 33, 34, 0, 0, 6, 132, 23, 32, 1, 134, 15, 32, 18, 130, 25, + 133, 11, 37, 1, 0, 13, 0, 49, 0, 133, 11, 36, 2, 0, 7, 0, 38, 134, 11, 36, 3, 0, 17, + 0, 45, 134, 11, 32, 4, 138, 35, 36, 5, 0, 10, 0, 62, 134, 23, 32, 6, 132, 23, 36, 3, 0, + 1, 4, 9, 130, 87, 131, 167, 133, 11, 133, 167, 133, 11, 133, 167, 133, 11, 37, 3, 0, 34, 0, 122, + 0, 133, 11, 133, 167, 133, 11, 133, 167, 133, 11, 133, 167, 34, 50, 0, 48, 130, 1, 34, 52, 0, 47, + 134, 5, 8, 49, 49, 0, 53, 98, 121, 32, 84, 114, 105, 115, 116, 97, 110, 32, 71, 114, 105, 109, 109, + 101, 114, 82, 101, 103, 117, 108, 97, 114, 84, 84, 88, 32, 80, 114, 111, 103, 103, 121, 67, 108, 101, 97, + 110, 84, 84, 50, 48, 48, 52, 47, 130, 2, 53, 49, 53, 0, 98, 0, 121, 0, 32, 0, 84, 0, 114, + 0, 105, 0, 115, 0, 116, 0, 97, 0, 110, 130, 15, 32, 71, 132, 15, 36, 109, 0, 109, 0, 101, 130, + 9, 32, 82, 130, 5, 36, 103, 0, 117, 0, 108, 130, 29, 32, 114, 130, 43, 34, 84, 0, 88, 130, 35, + 32, 80, 130, 25, 34, 111, 0, 103, 130, 1, 34, 121, 0, 67, 130, 27, 32, 101, 132, 59, 32, 84, 130, + 31, 33, 0, 0, 65, 155, 9, 34, 20, 0, 0, 65, 11, 6, 130, 8, 135, 2, 33, 1, 1, 130, 9, + 8, 120, 1, 1, 2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1, 10, 1, 11, + 1, 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, 19, 1, 20, 1, 21, 1, 22, 1, + 23, 1, 24, 1, 25, 1, 26, 1, 27, 1, 28, 1, 29, 1, 30, 1, 31, 1, 32, 0, 3, 0, 4, + 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, + 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, + 0, 28, 0, 29, 0, 30, 0, 31, 130, 187, 8, 66, 33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, + 0, 39, 0, 40, 0, 41, 0, 42, 0, 43, 0, 44, 0, 45, 0, 46, 0, 47, 0, 48, 0, 49, 0, + 50, 0, 51, 0, 52, 0, 53, 0, 54, 0, 55, 0, 56, 0, 57, 0, 58, 0, 59, 0, 60, 0, 61, + 0, 62, 0, 63, 0, 64, 0, 65, 0, 66, 130, 243, 9, 75, 68, 0, 69, 0, 70, 0, 71, 0, 72, + 0, 73, 0, 74, 0, 75, 0, 76, 0, 77, 0, 78, 0, 79, 0, 80, 0, 81, 0, 82, 0, 83, 0, + 84, 0, 85, 0, 86, 0, 87, 0, 88, 0, 89, 0, 90, 0, 91, 0, 92, 0, 93, 0, 94, 0, 95, + 0, 96, 0, 97, 1, 33, 1, 34, 1, 35, 1, 36, 1, 37, 1, 38, 1, 39, 1, 40, 1, 41, 1, + 42, 1, 43, 1, 44, 1, 45, 1, 46, 1, 47, 1, 48, 1, 49, 1, 50, 1, 51, 1, 52, 1, 53, + 1, 54, 1, 55, 1, 56, 1, 57, 1, 58, 1, 59, 1, 60, 1, 61, 1, 62, 1, 63, 1, 64, 1, + 65, 0, 172, 0, 163, 0, 132, 0, 133, 0, 189, 0, 150, 0, 232, 0, 134, 0, 142, 0, 139, 0, 157, + 0, 169, 0, 164, 0, 239, 0, 138, 0, 218, 0, 131, 0, 147, 0, 242, 0, 243, 0, 141, 0, 151, 0, + 136, 0, 195, 0, 222, 0, 241, 0, 158, 0, 170, 0, 245, 0, 244, 0, 246, 0, 162, 0, 173, 0, 201, + 0, 199, 0, 174, 0, 98, 0, 99, 0, 144, 0, 100, 0, 203, 0, 101, 0, 200, 0, 202, 0, 207, 0, + 204, 0, 205, 0, 206, 0, 233, 0, 102, 0, 211, 0, 208, 0, 209, 0, 175, 0, 103, 0, 240, 0, 145, + 0, 214, 0, 212, 0, 213, 0, 104, 0, 235, 0, 237, 0, 137, 0, 106, 0, 105, 0, 107, 0, 109, 0, + 108, 0, 110, 0, 160, 0, 111, 0, 113, 0, 112, 0, 114, 0, 115, 0, 117, 0, 116, 0, 118, 0, 119, + 0, 234, 0, 120, 0, 122, 0, 121, 0, 123, 0, 125, 0, 124, 0, 184, 0, 161, 0, 127, 0, 126, 0, + 128, 0, 129, 0, 236, 0, 238, 0, 186, 14, 117, 110, 105, 99, 111, 100, 101, 35, 48, 120, 48, 48, 48, + 49, 141, 14, 32, 50, 141, 14, 32, 51, 141, 14, 32, 52, 141, 14, 32, 53, 141, 14, 32, 54, 141, 14, + 32, 55, 141, 14, 32, 56, 141, 14, 32, 57, 141, 14, 32, 97, 141, 14, 32, 98, 141, 14, 32, 99, 141, + 14, 32, 100, 141, 14, 32, 101, 141, 14, 32, 102, 140, 14, 33, 49, 48, 141, 14, 141, 239, 32, 49, 141, + 239, 32, 49, 141, 239, 32, 49, 141, 239, 32, 49, 141, 239, 32, 49, 141, 239, 32, 49, 141, 239, 32, 49, + 141, 239, 32, 49, 141, 239, 32, 49, 141, 239, 32, 49, 141, 239, 32, 49, 141, 239, 32, 49, 141, 239, 32, + 49, 141, 239, 45, 49, 102, 6, 100, 101, 108, 101, 116, 101, 4, 69, 117, 114, 111, 140, 236, 32, 56, 141, + 236, 32, 56, 141, 236, 32, 56, 141, 236, 32, 56, 141, 236, 32, 56, 141, 236, 32, 56, 141, 236, 32, 56, + 141, 236, 32, 56, 141, 236, 32, 56, 141, 236, 32, 56, 141, 236, 32, 56, 141, 236, 32, 56, 141, 236, 32, + 56, 141, 236, 32, 56, 141, 236, 32, 56, 65, 220, 13, 32, 57, 65, 220, 13, 32, 57, 141, 239, 32, 57, + 141, 239, 32, 57, 141, 239, 32, 57, 141, 239, 32, 57, 141, 239, 32, 57, 141, 239, 32, 57, 141, 239, 32, + 57, 141, 239, 32, 57, 141, 239, 32, 57, 141, 239, 32, 57, 141, 239, 32, 57, 141, 239, 32, 57, 141, 239, + 32, 57, 141, 239, 35, 57, 102, 0, 0, 5, 250, 72, 249, 98, 247, }; -static const char* GetDefaultCompressedFontDataTTF(int* out_size) +static const char *GetDefaultCompressedFontDataTTF(int *out_size) { *out_size = proggy_clean_ttf_compressed_size; - return (const char*)proggy_clean_ttf_compressed_data; + return (const char *)proggy_clean_ttf_compressed_data; } #endif // #ifndef IMGUI_DISABLE_DEFAULT_FONT diff --git a/firmware/components/imgui/imgui_widgets.cpp b/firmware/components/imgui/imgui_widgets.cpp index 2e80564..d945aed 100644 --- a/firmware/components/imgui/imgui_widgets.cpp +++ b/firmware/components/imgui/imgui_widgets.cpp @@ -45,7 +45,7 @@ Index of this file: #include "imgui_internal.h" // System includes -#include // intptr_t +#include // intptr_t //------------------------------------------------------------------------- // Warnings @@ -53,45 +53,75 @@ Index of this file: // Visual Studio warnings #ifdef _MSC_VER -#pragma warning (disable: 4127) // condition expression is constant -#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 : 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen #if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later -#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types +#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). +#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 #if defined(__clang__) #if __has_warning("-Wunknown-warning-option") -#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! +#pragma clang diagnostic ignored \ + "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are + // known by all Clang versions and they tend to be rename-happy.. so ignoring warnings + // triggers new warnings on some configuration. Great! #endif -#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' -#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. -#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. -#pragma clang diagnostic ignored "-Wformat" // warning: format specifies type 'int' but the argument has type 'unsigned int' -#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. -#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness -#pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used. -#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 -#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. -#pragma clang diagnostic ignored "-Wenum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') -#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated -#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision -#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access -#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type -#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored \ + "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing + // and comparing against same constants (typically 0.0f) is ok. +#pragma clang diagnostic ignored \ + "-Wformat" // warning: format specifies type 'int' but the argument has type 'unsigned int' +#pragma clang diagnostic ignored \ + "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to + // vsnformat(). yes, user passing incorrect format strings can crash the code. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#pragma clang diagnostic ignored \ + "-Wunused-macros" // warning: macro is not used // we define snprintf/vsnprintf on + // Windows so they are available, but not always used. +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some + // standard header variations use #define NULL 0 +#pragma clang diagnostic ignored \ + "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // + // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#pragma clang diagnostic ignored "-Wenum-enum-conversion" // warning: bitwise operation between different enumeration + // types ('XXXFlags_' and 'XXXFlagsPrivate_') +#pragma clang diagnostic ignored \ + "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' + // and 'XXXFlagsPrivate_') is deprecated +#pragma clang diagnostic ignored \ + "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access +#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to + // non-trivially copyable type +#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label #elif defined(__GNUC__) -#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe -#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*' -#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked -#pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated -#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function -#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1 -#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead -#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe +#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X + // has type 'unsigned int'/'ImGuiWindow*' +#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked +#pragma GCC diagnostic ignored \ + "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' + // and 'XXXFlagsPrivate_') is deprecated +#pragma GCC diagnostic ignored \ + "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying + // division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1 +#pragma GCC diagnostic ignored \ + "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no + // trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored \ + "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers #endif //------------------------------------------------------------------------- @@ -99,34 +129,36 @@ Index of this file: //------------------------------------------------------------------------- // Widgets -static const float DRAGDROP_HOLD_TO_OPEN_TIMER = 0.70f; // Time for drag-hold to activate items accepting the ImGuiButtonFlags_PressedOnDragDropHold button behavior. -static const float DRAG_MOUSE_THRESHOLD_FACTOR = 0.50f; // Multiplier for the default value of io.MouseDragThreshold to make DragFloat/DragInt react faster to mouse drags. +static const float DRAGDROP_HOLD_TO_OPEN_TIMER = + 0.70f; // Time for drag-hold to activate items accepting the ImGuiButtonFlags_PressedOnDragDropHold button behavior. +static const float DRAG_MOUSE_THRESHOLD_FACTOR = 0.50f; // Multiplier for the default value of io.MouseDragThreshold to + // make DragFloat/DragInt react faster to mouse drags. // Those MIN/MAX values are not define because we need to point to them -static const signed char IM_S8_MIN = -128; -static const signed char IM_S8_MAX = 127; -static const unsigned char IM_U8_MIN = 0; -static const unsigned char IM_U8_MAX = 0xFF; -static const signed short IM_S16_MIN = -32768; -static const signed short IM_S16_MAX = 32767; +static const signed char IM_S8_MIN = -128; +static const signed char IM_S8_MAX = 127; +static const unsigned char IM_U8_MIN = 0; +static const unsigned char IM_U8_MAX = 0xFF; +static const signed short IM_S16_MIN = -32768; +static const signed short IM_S16_MAX = 32767; static const unsigned short IM_U16_MIN = 0; static const unsigned short IM_U16_MAX = 0xFFFF; -static const ImS32 IM_S32_MIN = INT_MIN; // (-2147483647 - 1), (0x80000000); -static const ImS32 IM_S32_MAX = INT_MAX; // (2147483647), (0x7FFFFFFF) -static const ImU32 IM_U32_MIN = 0; -static const ImU32 IM_U32_MAX = UINT_MAX; // (0xFFFFFFFF) +static const ImS32 IM_S32_MIN = INT_MIN; // (-2147483647 - 1), (0x80000000); +static const ImS32 IM_S32_MAX = INT_MAX; // (2147483647), (0x7FFFFFFF) +static const ImU32 IM_U32_MIN = 0; +static const ImU32 IM_U32_MAX = UINT_MAX; // (0xFFFFFFFF) #ifdef LLONG_MIN -static const ImS64 IM_S64_MIN = LLONG_MIN; // (-9223372036854775807ll - 1ll); -static const ImS64 IM_S64_MAX = LLONG_MAX; // (9223372036854775807ll); +static const ImS64 IM_S64_MIN = LLONG_MIN; // (-9223372036854775807ll - 1ll); +static const ImS64 IM_S64_MAX = LLONG_MAX; // (9223372036854775807ll); #else -static const ImS64 IM_S64_MIN = -9223372036854775807LL - 1; -static const ImS64 IM_S64_MAX = 9223372036854775807LL; +static const ImS64 IM_S64_MIN = -9223372036854775807LL - 1; +static const ImS64 IM_S64_MAX = 9223372036854775807LL; #endif -static const ImU64 IM_U64_MIN = 0; +static const ImU64 IM_U64_MIN = 0; #ifdef ULLONG_MAX -static const ImU64 IM_U64_MAX = ULLONG_MAX; // (0xFFFFFFFFFFFFFFFFull); +static const ImU64 IM_U64_MAX = ULLONG_MAX; // (0xFFFFFFFFFFFFFFFFull); #else -static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1); +static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1); #endif //------------------------------------------------------------------------- @@ -134,9 +166,13 @@ static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1); //------------------------------------------------------------------------- // For InputTextEx() -static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, bool input_source_is_clipboard = false); -static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end); -static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, const char* text_end, const char** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); +static bool InputTextFilterCharacter(ImGuiContext *ctx, unsigned int *p_char, ImGuiInputTextFlags flags, + ImGuiInputTextCallback callback, void *user_data, + bool input_source_is_clipboard = false); +static int InputTextCalcTextLenAndLineCount(const char *text_begin, const char **out_text_end); +static ImVec2 InputTextCalcTextSize(ImGuiContext *ctx, const char *text_begin, const char *text_end, + const char **remaining = NULL, ImVec2 *out_offset = NULL, + bool stop_on_new_line = false); //------------------------------------------------------------------------- // [SECTION] Widgets: Text, etc. @@ -157,19 +193,19 @@ static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, // - BulletTextV() //------------------------------------------------------------------------- -void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) +void ImGui::TextEx(const char *text, const char *text_end, ImGuiTextFlags flags) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return; - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; // Accept null ranges if (text == text_end) text = text_end = ""; // Calculate length - const char* text_begin = text; + const char *text_begin = text; if (text_end == NULL) text_end = text + ImStrlen(text); // FIXME-OPT @@ -194,10 +230,13 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) { // Long text! // Perform manual coarse clipping to optimize for long multi-line text - // - From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled. - // - We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line. - // - We use memchr(), pay attention that well optimized versions of those str/mem functions are much faster than a casually written loop. - const char* line = text; + // - From this point we will only compute the width of lines that are visible. Optimization only available when + // word-wrapping is disabled. + // - We also don't vertically center the text within the line full height, which is unlikely to matter because + // we are likely the biggest and only item on the line. + // - We use memchr(), pay attention that well optimized versions of those str/mem functions are much faster than + // a casually written loop. + const char *line = text; const float line_height = GetTextLineHeight(); ImVec2 text_size(0, 0); @@ -211,7 +250,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) int lines_skipped = 0; while (line < text_end && lines_skipped < lines_skippable) { - const char* line_end = (const char*)ImMemchr(line, '\n', text_end - line); + const char *line_end = (const char *)ImMemchr(line, '\n', text_end - line); if (!line_end) line_end = text_end; if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0) @@ -232,7 +271,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) if (IsClippedEx(line_rect, 0)) break; - const char* line_end = (const char*)ImMemchr(line, '\n', text_end - line); + const char *line_end = (const char *)ImMemchr(line, '\n', text_end - line); if (!line_end) line_end = text_end; text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x); @@ -247,7 +286,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) int lines_skipped = 0; while (line < text_end) { - const char* line_end = (const char*)ImMemchr(line, '\n', text_end - line); + const char *line_end = (const char *)ImMemchr(line, '\n', text_end - line); if (!line_end) line_end = text_end; if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0) @@ -265,12 +304,12 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) } } -void ImGui::TextUnformatted(const char* text, const char* text_end) +void ImGui::TextUnformatted(const char *text, const char *text_end) { TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText); } -void ImGui::Text(const char* fmt, ...) +void ImGui::Text(const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -278,18 +317,18 @@ void ImGui::Text(const char* fmt, ...) va_end(args); } -void ImGui::TextV(const char* fmt, va_list args) +void ImGui::TextV(const char *fmt, va_list args) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return; - const char* text, *text_end; + const char *text, *text_end; ImFormatStringToTempBufferV(&text, &text_end, fmt, args); TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText); } -void ImGui::TextColored(const ImVec4& col, const char* fmt, ...) +void ImGui::TextColored(const ImVec4 &col, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -297,14 +336,14 @@ void ImGui::TextColored(const ImVec4& col, const char* fmt, ...) va_end(args); } -void ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args) +void ImGui::TextColoredV(const ImVec4 &col, const char *fmt, va_list args) { PushStyleColor(ImGuiCol_Text, col); TextV(fmt, args); PopStyleColor(); } -void ImGui::TextDisabled(const char* fmt, ...) +void ImGui::TextDisabled(const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -312,15 +351,15 @@ void ImGui::TextDisabled(const char* fmt, ...) va_end(args); } -void ImGui::TextDisabledV(const char* fmt, va_list args) +void ImGui::TextDisabledV(const char *fmt, va_list args) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); TextV(fmt, args); PopStyleColor(); } -void ImGui::TextWrapped(const char* fmt, ...) +void ImGui::TextWrapped(const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -328,10 +367,11 @@ void ImGui::TextWrapped(const char* fmt, ...) va_end(args); } -void ImGui::TextWrappedV(const char* fmt, va_list args) +void ImGui::TextWrappedV(const char *fmt, va_list args) { - ImGuiContext& g = *GImGui; - const bool need_backup = (g.CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set + ImGuiContext &g = *GImGui; + const bool need_backup = + (g.CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set if (need_backup) PushTextWrapPos(0.0f); TextV(fmt, args); @@ -339,7 +379,7 @@ void ImGui::TextWrappedV(const char* fmt, va_list args) PopTextWrapPos(); } -void ImGui::TextAligned(float align_x, float size_x, const char* fmt, ...) +void ImGui::TextAligned(float align_x, float size_x, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -350,13 +390,13 @@ void ImGui::TextAligned(float align_x, float size_x, const char* fmt, ...) // align_x: 0.0f = left, 0.5f = center, 1.0f = right. // size_x : 0.0f = shortcut for GetContentRegionAvail().x // FIXME-WIP: Works but API is likely to be reworked. This is designed for 1 item on the line. (#7024) -void ImGui::TextAlignedV(float align_x, float size_x, const char* fmt, va_list args) +void ImGui::TextAlignedV(float align_x, float size_x, const char *fmt, va_list args) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return; - const char* text, *text_end; + const char *text, *text_end; ImFormatStringToTempBufferV(&text, &text_end, fmt, args); const ImVec2 text_size = CalcTextSize(text, text_end); size_x = CalcItemSize(ImVec2(size_x, 0.0f), 0.0f, text_size.y).x; @@ -373,13 +413,15 @@ void ImGui::TextAlignedV(float align_x, float size_x, const char* fmt, va_list a const ImVec2 backup_max_pos = window->DC.CursorMaxPos; ItemSize(size); ItemAdd(ImRect(pos, pos + size), 0); - window->DC.CursorMaxPos.x = backup_max_pos.x; // Cancel out extending content size because right-aligned text would otherwise mess it up. + window->DC.CursorMaxPos.x = + backup_max_pos.x; // Cancel out extending content size because right-aligned text would otherwise mess it up. - if (size_x < text_size.x && IsItemHovered(ImGuiHoveredFlags_NoNavOverride | ImGuiHoveredFlags_AllowWhenDisabled | ImGuiHoveredFlags_ForTooltip)) + if (size_x < text_size.x && IsItemHovered(ImGuiHoveredFlags_NoNavOverride | ImGuiHoveredFlags_AllowWhenDisabled | + ImGuiHoveredFlags_ForTooltip)) SetTooltip("%.*s", (int)(text_end - text), text); } -void ImGui::LabelText(const char* label, const char* fmt, ...) +void ImGui::LabelText(const char *label, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -388,35 +430,37 @@ void ImGui::LabelText(const char* label, const char* fmt, ...) } // Add a label+text combo aligned to other label+value widgets -void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) +void ImGui::LabelTextV(const char *label, const char *fmt, va_list args) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return; - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; + ImGuiContext &g = *GImGui; + const ImGuiStyle &style = g.Style; const float w = CalcItemWidth(); - const char* value_text_begin, *value_text_end; + const char *value_text_begin, *value_text_end; ImFormatStringToTempBufferV(&value_text_begin, &value_text_end, fmt, args); const ImVec2 value_size = CalcTextSize(value_text_begin, value_text_end, false); const ImVec2 label_size = CalcTextSize(label, NULL, true); 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)); + 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 - RenderTextClipped(value_bb.Min + style.FramePadding, value_bb.Max, value_text_begin, value_text_end, &value_size, ImVec2(0.0f, 0.0f)); + 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); } -void ImGui::BulletText(const char* fmt, ...) +void ImGui::BulletText(const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -425,19 +469,21 @@ void ImGui::BulletText(const char* fmt, ...) } // Text with a little bullet aligned to the typical tree node. -void ImGui::BulletTextV(const char* fmt, va_list args) +void ImGui::BulletTextV(const char *fmt, va_list args) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return; - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; + ImGuiContext &g = *GImGui; + const ImGuiStyle &style = g.Style; - const char* text_begin, *text_end; + const char *text_begin, *text_end; ImFormatStringToTempBufferV(&text_begin, &text_end, fmt, args); const ImVec2 label_size = CalcTextSize(text_begin, text_end, false); - const ImVec2 total_size = ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x * 2) : 0.0f), label_size.y); // Empty text doesn't add padding + const ImVec2 total_size = + ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x * 2) : 0.0f), + label_size.y); // Empty text doesn't add padding ImVec2 pos = window->DC.CursorPos; pos.y += window->DC.CurrLineTextBaseOffset; ItemSize(total_size, 0.0f); @@ -447,7 +493,8 @@ void ImGui::BulletTextV(const char* fmt, va_list args) // Render ImU32 text_col = GetColorU32(ImGuiCol_Text); - RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize * 0.5f, g.FontSize * 0.5f), text_col); + RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize * 0.5f, g.FontSize * 0.5f), + text_col); RenderText(bb.Min + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0f), text_begin, text_end, false); } @@ -477,51 +524,57 @@ void ImGui::BulletTextV(const char* fmt, va_list args) //------------------------------------------------------------------------- // The ButtonBehavior() function is key to many interactions and used by many/most widgets. -// Because we handle so many cases (keyboard/gamepad navigation, drag and drop) and many specific behavior (via ImGuiButtonFlags_), -// this code is a little complex. -// By far the most common path is interacting with the Mouse using the default ImGuiButtonFlags_PressedOnClickRelease button behavior. -// See the series of events below and the corresponding state reported by dear imgui: +// Because we handle so many cases (keyboard/gamepad navigation, drag and drop) and many specific behavior (via +// ImGuiButtonFlags_), this code is a little complex. By far the most common path is interacting with the Mouse using +// the default ImGuiButtonFlags_PressedOnClickRelease button behavior. See the series of events below and the +// corresponding state reported by dear imgui: //------------------------------------------------------------------------------------------------------------------------------------------------ -// with PressedOnClickRelease: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked() -// Frame N+0 (mouse is outside bb) - - - - - - -// Frame N+1 (mouse moves inside bb) - true - - - - -// Frame N+2 (mouse button is down) - true true true - true -// Frame N+3 (mouse button is down) - true true - - - -// Frame N+4 (mouse moves outside bb) - - true - - - -// Frame N+5 (mouse moves inside bb) - true true - - - -// Frame N+6 (mouse button is released) true true - - true - -// Frame N+7 (mouse button is released) - true - - - - -// Frame N+8 (mouse moves outside bb) - - - - - - +// with PressedOnClickRelease: return-value IsItemHovered() IsItemActive() IsItemActivated() +// IsItemDeactivated() IsItemClicked() +// Frame N+0 (mouse is outside bb) - - - - - - Frame +// N+1 (mouse moves inside bb) - true - - - - Frame N+2 +// (mouse button is down) - true true true - true Frame N+3 +// (mouse button is down) - true true - - - Frame N+4 (mouse +// moves outside bb) - - true - - - +// Frame N+5 (mouse moves inside bb) - true true - - - Frame +// N+6 (mouse button is released) true true - - true - Frame N+7 +// (mouse button is released) - true - - - - Frame N+8 (mouse +// moves outside bb) - - - - - - //------------------------------------------------------------------------------------------------------------------------------------------------ -// with PressedOnClick: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked() -// Frame N+2 (mouse button is down) true true true true - true -// Frame N+3 (mouse button is down) - true true - - - -// Frame N+6 (mouse button is released) - true - - true - -// Frame N+7 (mouse button is released) - true - - - - +// with PressedOnClick: return-value IsItemHovered() IsItemActive() IsItemActivated() +// IsItemDeactivated() IsItemClicked() +// Frame N+2 (mouse button is down) true true true true - true +// Frame N+3 (mouse button is down) - true true - - - Frame +// N+6 (mouse button is released) - true - - true - Frame N+7 +// (mouse button is released) - true - - - - //------------------------------------------------------------------------------------------------------------------------------------------------ -// with PressedOnRelease: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked() -// Frame N+2 (mouse button is down) - true - - - true -// Frame N+3 (mouse button is down) - true - - - - -// Frame N+6 (mouse button is released) true true - - - - -// Frame N+7 (mouse button is released) - true - - - - +// with PressedOnRelease: return-value IsItemHovered() IsItemActive() IsItemActivated() +// IsItemDeactivated() IsItemClicked() +// Frame N+2 (mouse button is down) - true - - - true +// Frame N+3 (mouse button is down) - true - - - - Frame +// N+6 (mouse button is released) true true - - - - Frame N+7 +// (mouse button is released) - true - - - - //------------------------------------------------------------------------------------------------------------------------------------------------ -// with PressedOnDoubleClick: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked() -// Frame N+0 (mouse button is down) - true - - - true -// Frame N+1 (mouse button is down) - true - - - - -// Frame N+2 (mouse button is released) - true - - - - -// Frame N+3 (mouse button is released) - true - - - - -// Frame N+4 (mouse button is down) true true true true - true -// Frame N+5 (mouse button is down) - true true - - - -// Frame N+6 (mouse button is released) - true - - true - -// Frame N+7 (mouse button is released) - true - - - - +// with PressedOnDoubleClick: return-value IsItemHovered() IsItemActive() IsItemActivated() +// IsItemDeactivated() IsItemClicked() +// Frame N+0 (mouse button is down) - true - - - true +// Frame N+1 (mouse button is down) - true - - - - Frame +// N+2 (mouse button is released) - true - - - - Frame N+3 +// (mouse button is released) - true - - - - Frame N+4 (mouse +// button is down) true true true true - true +// Frame N+5 (mouse button is down) - true true - - - Frame +// N+6 (mouse button is released) - true - - true - Frame N+7 +// (mouse button is released) - true - - - - //------------------------------------------------------------------------------------------------------------------------------------------------ // Note that some combinations are supported, // - PressedOnDragDropHold can generally be associated with any flag. -// - PressedOnDoubleClick can be associated by PressedOnClickRelease/PressedOnRelease, in which case the second release event won't be reported. +// - PressedOnDoubleClick can be associated by PressedOnClickRelease/PressedOnRelease, in which case the second release +// event won't be reported. //------------------------------------------------------------------------------------------------------------------------------------------------ // The behavior of the return-value changes when ImGuiItemFlags_ButtonRepeat is set: // Repeat+ Repeat+ Repeat+ Repeat+ -// PressedOnClickRelease PressedOnClick PressedOnRelease PressedOnDoubleClick +// PressedOnClickRelease PressedOnClick PressedOnRelease +// PressedOnDoubleClick //------------------------------------------------------------------------------------------------------------------------------------------------- // Frame N+0 (mouse button is down) - true - true // ... - - - - @@ -531,20 +584,22 @@ void ImGui::BulletTextV(const char* fmt, va_list args) //------------------------------------------------------------------------------------------------------------------------------------------------- // - FIXME: For refactor we could output flags, incl mouse hovered vs nav keyboard vs nav triggered etc. -// And better standardize how widgets use 'GetColor32((held && hovered) ? ... : hovered ? ...)' vs 'GetColor32(held ? ... : hovered ? ...);' -// For mouse feedback we typically prefer the 'held && hovered' test, but for nav feedback not always. Outputting hovered=true on Activation may be misleading. +// And better standardize how widgets use 'GetColor32((held && hovered) ? ... : hovered ? ...)' vs 'GetColor32(held ? +// ... : hovered ? ...);' For mouse feedback we typically prefer the 'held && hovered' test, but for nav feedback not +// always. Outputting hovered=true on Activation may be misleading. // - Since v1.91.2 (Sept 2024) we included io.ConfigDebugHighlightIdConflicts feature. // One idiom which was previously valid which will now emit a warning is when using multiple overlaid ButtonBehavior() // with same ID and different MouseButton (see #8030). You can fix it by: // (1) switching to use a single ButtonBehavior() with multiple _MouseButton flags. // or (2) surrounding those calls with PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true); ... PopItemFlag() -bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags) +bool ImGui::ButtonBehavior(const ImRect &bb, ImGuiID id, bool *out_hovered, bool *out_held, ImGuiButtonFlags flags) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); + ImGuiContext &g = *GImGui; + ImGuiWindow *window = GetCurrentWindow(); // Default behavior inherited from item flags - // Note that _both_ ButtonFlags and ItemFlags are valid sources, so copy one into the item_flags and only check that. + // Note that _both_ ButtonFlags and ItemFlags are valid sources, so copy one into the item_flags and only check + // that. ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.ItemFlags : g.CurrentItemFlags); if (flags & ImGuiButtonFlags_AllowOverlap) item_flags |= ImGuiItemFlags_AllowOverlap; @@ -557,10 +612,12 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool // Default behavior requires click + release inside bounding box if ((flags & ImGuiButtonFlags_PressedOnMask_) == 0) - flags |= (item_flags & ImGuiItemFlags_ButtonRepeat) ? ImGuiButtonFlags_PressedOnClick : ImGuiButtonFlags_PressedOnDefault_; + flags |= (item_flags & ImGuiItemFlags_ButtonRepeat) ? ImGuiButtonFlags_PressedOnClick + : ImGuiButtonFlags_PressedOnDefault_; - ImGuiWindow* backup_hovered_window = g.HoveredWindow; - const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindow == window->RootWindow; + ImGuiWindow *backup_hovered_window = g.HoveredWindow; + const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && + g.HoveredWindow->RootWindow == window->RootWindow; if (flatten_hovered_children) g.HoveredWindow = window; @@ -573,13 +630,16 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool bool pressed = false; bool hovered = ItemHoverable(bb, id, item_flags); - // Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button - if (g.DragDropActive && (flags & ImGuiButtonFlags_PressedOnDragDropHold) && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) + // Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers + // the button + if (g.DragDropActive && (flags & ImGuiButtonFlags_PressedOnDragDropHold) && + !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) if (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) { hovered = true; SetHoveredID(id); - if (g.HoveredIdTimer - g.IO.DeltaTime <= DRAGDROP_HOLD_TO_OPEN_TIMER && g.HoveredIdTimer >= DRAGDROP_HOLD_TO_OPEN_TIMER) + if (g.HoveredIdTimer - g.IO.DeltaTime <= DRAGDROP_HOLD_TO_OPEN_TIMER && + g.HoveredIdTimer >= DRAGDROP_HOLD_TO_OPEN_TIMER) { pressed = true; g.DragDropHoldJustPressedId = id; @@ -598,18 +658,28 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool // Poll mouse buttons // - 'mouse_button_clicked' is generally carried into ActiveIdMouseButton when setting ActiveId. - // - Technically we only need some values in one code path, but since this is gated by hovered test this is fine. + // - Technically we only need some values in one code path, but since this is gated by hovered test this is + // fine. int mouse_button_clicked = -1; int mouse_button_released = -1; for (int button = 0; button < 3; button++) - if (flags & (ImGuiButtonFlags_MouseButtonLeft << button)) // Handle ImGuiButtonFlags_MouseButtonRight and ImGuiButtonFlags_MouseButtonMiddle here. + if (flags & + (ImGuiButtonFlags_MouseButtonLeft + << button)) // Handle ImGuiButtonFlags_MouseButtonRight and ImGuiButtonFlags_MouseButtonMiddle here. { - if (IsMouseClicked(button, ImGuiInputFlags_None, test_owner_id) && mouse_button_clicked == -1) { mouse_button_clicked = button; } - if (IsMouseReleased(button, test_owner_id) && mouse_button_released == -1) { mouse_button_released = button; } + if (IsMouseClicked(button, ImGuiInputFlags_None, test_owner_id) && mouse_button_clicked == -1) + { + mouse_button_clicked = button; + } + if (IsMouseReleased(button, test_owner_id) && mouse_button_released == -1) + { + mouse_button_released = button; + } } // Process initial action - const bool mods_ok = !(flags & ImGuiButtonFlags_NoKeyModsAllowed) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt); + const bool mods_ok = + !(flags & ImGuiButtonFlags_NoKeyModsAllowed) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt); if (mods_ok) { if (mouse_button_clicked != -1 && g.ActiveId != id) @@ -627,10 +697,14 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool } else if (!(flags & ImGuiButtonFlags_NoFocus)) { - FocusWindow(window, ImGuiFocusRequestFlags_RestoreFocusedChild); // Still need to focus and bring to front, but try to avoid losing NavId when navigating a child + FocusWindow(window, + ImGuiFocusRequestFlags_RestoreFocusedChild); // Still need to focus and bring to + // front, but try to avoid losing NavId + // when navigating a child } } - if ((flags & ImGuiButtonFlags_PressedOnClick) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseClickedCount[mouse_button_clicked] == 2)) + if ((flags & ImGuiButtonFlags_PressedOnClick) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && + g.IO.MouseClickedCount[mouse_button_clicked] == 2)) { pressed = true; if (flags & ImGuiButtonFlags_NoHoldingActiveId) @@ -645,7 +719,10 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool } else if (!(flags & ImGuiButtonFlags_NoFocus)) { - FocusWindow(window, ImGuiFocusRequestFlags_RestoreFocusedChild); // Still need to focus and bring to front, but try to avoid losing NavId when navigating a child + FocusWindow(window, + ImGuiFocusRequestFlags_RestoreFocusedChild); // Still need to focus and bring to + // front, but try to avoid losing NavId + // when navigating a child } } } @@ -653,19 +730,25 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool { if (mouse_button_released != -1) { - const bool has_repeated_at_least_once = (item_flags & ImGuiItemFlags_ButtonRepeat) && g.IO.MouseDownDurationPrev[mouse_button_released] >= g.IO.KeyRepeatDelay; // Repeat mode trumps on release behavior + const bool has_repeated_at_least_once = + (item_flags & ImGuiItemFlags_ButtonRepeat) && + g.IO.MouseDownDurationPrev[mouse_button_released] >= + g.IO.KeyRepeatDelay; // Repeat mode trumps on release behavior if (!has_repeated_at_least_once) pressed = true; if (!(flags & ImGuiButtonFlags_NoNavFocus)) - SetFocusID(id, window); // FIXME: Lack of FocusWindow() call here is inconsistent with other paths. Research why. + SetFocusID(id, window); // FIXME: Lack of FocusWindow() call here is inconsistent with other + // paths. Research why. ClearActiveID(); } } // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above). - // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings. + // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer + // RepeatDelay/RepeatRate settings. if (g.ActiveId == id && (item_flags & ImGuiItemFlags_ButtonRepeat)) - if (g.IO.MouseDownDuration[g.ActiveIdMouseButton] > 0.0f && IsMouseClicked(g.ActiveIdMouseButton, ImGuiInputFlags_Repeat, test_owner_id)) + if (g.IO.MouseDownDuration[g.ActiveIdMouseButton] > 0.0f && + IsMouseClicked(g.ActiveIdMouseButton, ImGuiInputFlags_Repeat, test_owner_id)) pressed = true; } @@ -674,7 +757,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool } // Keyboard/Gamepad navigation handling - // We report navigated and navigation-activated items as hovered but we don't set g.HoveredId to not interfere with mouse. + // We report navigated and navigation-activated items as hovered but we don't set g.HoveredId to not interfere with + // mouse. if (g.NavId == id && g.NavCursorVisible && g.NavHighlightItemUnderNav) if (!(flags & ImGuiButtonFlags_NoHoveredOnFocus)) hovered = true; @@ -685,11 +769,12 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if (!nav_activated_by_inputs && (item_flags & ImGuiItemFlags_ButtonRepeat)) { // Avoid pressing multiple keys from triggering excessive amount of repeat events - const ImGuiKeyData* key1 = GetKeyData(ImGuiKey_Space); - const ImGuiKeyData* key2 = GetKeyData(ImGuiKey_Enter); - const ImGuiKeyData* key3 = GetKeyData(ImGuiKey_NavGamepadActivate); + const ImGuiKeyData *key1 = GetKeyData(ImGuiKey_Space); + const ImGuiKeyData *key2 = GetKeyData(ImGuiKey_Enter); + const ImGuiKeyData *key3 = GetKeyData(ImGuiKey_NavGamepadActivate); const float t1 = ImMax(ImMax(key1->DownDuration, key2->DownDuration), key3->DownDuration); - nav_activated_by_inputs = CalcTypematicRepeatAmount(t1 - g.IO.DeltaTime, t1, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0; + nav_activated_by_inputs = + CalcTypematicRepeatAmount(t1 - g.IO.DeltaTime, t1, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0; } if (nav_activated_by_code || nav_activated_by_inputs) { @@ -716,7 +801,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool const int mouse_button = g.ActiveIdMouseButton; if (mouse_button == -1) { - // Fallback for the rare situation were g.ActiveId was set programmatically or from another widget (e.g. #6304). + // Fallback for the rare situation were g.ActiveId was set programmatically or from another widget (e.g. + // #6304). ClearActiveID(); } else if (IsMouseDown(mouse_button, test_owner_id)) @@ -730,8 +816,12 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if ((release_in || release_anywhere) && !g.DragDropActive) { // Report as pressed when releasing the mouse (this is the most common path) - bool is_double_click_release = (flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseReleased[mouse_button] && g.IO.MouseClickedLastCount[mouse_button] == 2; - bool is_repeating_already = (item_flags & ImGuiItemFlags_ButtonRepeat) && g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay; // Repeat mode trumps + bool is_double_click_release = (flags & ImGuiButtonFlags_PressedOnDoubleClick) && + g.IO.MouseReleased[mouse_button] && + g.IO.MouseClickedLastCount[mouse_button] == 2; + bool is_repeating_already = (item_flags & ImGuiItemFlags_ButtonRepeat) && + g.IO.MouseDownDurationPrev[mouse_button] >= + g.IO.KeyRepeatDelay; // Repeat mode trumps bool is_button_avail_or_owned = TestKeyOwner(MouseButtonToKey(mouse_button), test_owner_id); if (!is_double_click_release && !is_repeating_already && is_button_avail_or_owned) pressed = true; @@ -757,27 +847,33 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if (g.NavHighlightActivatedId == id) hovered = true; - if (out_hovered) *out_hovered = hovered; - if (out_held) *out_held = held; + if (out_hovered) + *out_hovered = hovered; + if (out_held) + *out_held = held; return pressed; } -bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags) +bool ImGui::ButtonEx(const char *label, const ImVec2 &size_arg, ImGuiButtonFlags flags) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; + ImGuiContext &g = *GImGui; + const ImGuiStyle &style = g.Style; const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); ImVec2 pos = window->DC.CursorPos; - if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag) + if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && + style.FramePadding.y < + window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so + // that text baseline matches (bit hacky, since it shouldn't be a flag) pos.y += window->DC.CurrLineTextBaseOffset - style.FramePadding.y; - ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f); + ImVec2 size = + CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f); const ImRect bb(pos, pos + size); ItemSize(size, style.FramePadding.y); @@ -788,31 +884,34 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); // Render - const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive + : hovered ? ImGuiCol_ButtonHovered + : ImGuiCol_Button); RenderNavCursor(bb, id); RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); if (g.LogEnabled) LogSetNextTextDecoration("[", "]"); - RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb); + RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, + style.ButtonTextAlign, &bb); // Automatically close popups - //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) + // if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) // CloseCurrentPopup(); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); return pressed; } -bool ImGui::Button(const char* label, const ImVec2& size_arg) +bool ImGui::Button(const char *label, const ImVec2 &size_arg) { return ButtonEx(label, size_arg, ImGuiButtonFlags_None); } // Small buttons fits within text without additional vertical spacing. -bool ImGui::SmallButton(const char* label) +bool ImGui::SmallButton(const char *label) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; float backup_padding_y = g.Style.FramePadding.y; g.Style.FramePadding.y = 0.0f; bool pressed = ButtonEx(label, ImVec2(0, 0), ImGuiButtonFlags_AlignTextBaseLine); @@ -821,11 +920,12 @@ bool ImGui::SmallButton(const char* label) } // Tip: use ImGui::PushID()/PopID() to push indices or pointers in the ID stack. -// Then you can keep 'str_id' empty or the same for all your buttons (instead of creating a string based on a non-string id) -bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg, ImGuiButtonFlags flags) +// Then you can keep 'str_id' empty or the same for all your buttons (instead of creating a string based on a non-string +// id) +bool ImGui::InvisibleButton(const char *str_id, const ImVec2 &size_arg, ImGuiButtonFlags flags) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); + ImGuiContext &g = *GImGui; + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; @@ -847,10 +947,10 @@ bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg, ImGuiBut return pressed; } -bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiButtonFlags flags) +bool ImGui::ArrowButtonEx(const char *str_id, ImGuiDir dir, ImVec2 size, ImGuiButtonFlags flags) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); + ImGuiContext &g = *GImGui; + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; @@ -865,38 +965,44 @@ bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiBu bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); // Render - const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive + : hovered ? ImGuiCol_ButtonHovered + : ImGuiCol_Button); const ImU32 text_col = GetColorU32(ImGuiCol_Text); RenderNavCursor(bb, id); RenderFrame(bb.Min, bb.Max, bg_col, true, g.Style.FrameRounding); - RenderArrow(window->DrawList, bb.Min + ImVec2(ImMax(0.0f, (size.x - g.FontSize) * 0.5f), ImMax(0.0f, (size.y - g.FontSize) * 0.5f)), text_col, dir); + RenderArrow(window->DrawList, + bb.Min + ImVec2(ImMax(0.0f, (size.x - g.FontSize) * 0.5f), ImMax(0.0f, (size.y - g.FontSize) * 0.5f)), + text_col, dir); IMGUI_TEST_ENGINE_ITEM_INFO(id, str_id, g.LastItemData.StatusFlags); return pressed; } -bool ImGui::ArrowButton(const char* str_id, ImGuiDir dir) +bool ImGui::ArrowButton(const char *str_id, ImGuiDir dir) { float sz = GetFrameHeight(); return ArrowButtonEx(str_id, dir, ImVec2(sz, sz), ImGuiButtonFlags_None); } // Button to close a window -bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos) +bool ImGui::CloseButton(ImGuiID id, const ImVec2 &pos) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; - // 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? + // 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)); 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(ImTrunc(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 common behavior of buttons, but it doesn't affect the user because navigation tends to keep items visible in scrolling layer). + // 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 common behavior of buttons, but it doesn't affect the user because + // navigation tends to keep items visible in scrolling layer). bool is_clipped = !ItemAdd(bb_interact, id); bool hovered, held; @@ -913,16 +1019,18 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos) const ImVec2 cross_center = bb.GetCenter() - ImVec2(0.5f, 0.5f); const float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f; const float cross_thickness = 1.0f; // FIXME-DPI - window->DrawList->AddLine(cross_center + ImVec2(+cross_extent, +cross_extent), cross_center + ImVec2(-cross_extent, -cross_extent), cross_col, cross_thickness); - window->DrawList->AddLine(cross_center + ImVec2(+cross_extent, -cross_extent), cross_center + ImVec2(-cross_extent, +cross_extent), cross_col, cross_thickness); + window->DrawList->AddLine(cross_center + ImVec2(+cross_extent, +cross_extent), + cross_center + ImVec2(-cross_extent, -cross_extent), cross_col, cross_thickness); + window->DrawList->AddLine(cross_center + ImVec2(+cross_extent, -cross_extent), + cross_center + ImVec2(-cross_extent, +cross_extent), cross_col, cross_thickness); return pressed; } -bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) +bool ImGui::CollapseButton(ImGuiID id, const ImVec2 &pos) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize)); bool is_clipped = !ItemAdd(bb, id); @@ -932,7 +1040,9 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) return pressed; // Render - ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive + : hovered ? ImGuiCol_ButtonHovered + : ImGuiCol_Button); ImU32 text_col = GetColorU32(ImGuiCol_Text); if (hovered || held) window->DrawList->AddRectFilled(bb.Min, bb.Max, bg_col); @@ -946,31 +1056,36 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) return pressed; } -ImGuiID ImGui::GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis) +ImGuiID ImGui::GetWindowScrollbarID(ImGuiWindow *window, ImGuiAxis axis) { return window->GetID(axis == ImGuiAxis_X ? "#SCROLLX" : "#SCROLLY"); } // Return scrollbar rectangle, must only be called for corresponding axis if window->ScrollbarX/Y is set. -ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis) +ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow *window, ImGuiAxis axis) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; const ImRect outer_rect = window->Rect(); const ImRect inner_rect = window->InnerRect; - const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; // (ScrollbarSizes.x = width of Y scrollbar; ScrollbarSizes.y = height of X scrollbar) + const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; // (ScrollbarSizes.x = width of Y scrollbar; + // ScrollbarSizes.y = height of X scrollbar) IM_ASSERT(scrollbar_size >= 0.0f); const float border_size = IM_ROUND(window->WindowBorderSize * 0.5f); - const float border_top = (window->Flags & ImGuiWindowFlags_MenuBar) ? IM_ROUND(g.Style.FrameBorderSize * 0.5f) : 0.0f; + const float border_top = + (window->Flags & ImGuiWindowFlags_MenuBar) ? IM_ROUND(g.Style.FrameBorderSize * 0.5f) : 0.0f; if (axis == ImGuiAxis_X) - return ImRect(inner_rect.Min.x + border_size, ImMax(outer_rect.Min.y + border_size, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x - border_size, outer_rect.Max.y - border_size); + return ImRect(inner_rect.Min.x + border_size, + ImMax(outer_rect.Min.y + border_size, outer_rect.Max.y - border_size - scrollbar_size), + inner_rect.Max.x - border_size, outer_rect.Max.y - border_size); else - return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y + border_top, outer_rect.Max.x - border_size, inner_rect.Max.y - border_size); + return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), + inner_rect.Min.y + border_top, outer_rect.Max.x - border_size, inner_rect.Max.y - border_size); } void ImGui::Scrollbar(ImGuiAxis axis) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; const ImGuiID id = GetWindowScrollbarID(window, axis); // Calculate scrollbar bounding box @@ -998,14 +1113,17 @@ void ImGui::Scrollbar(ImGuiAxis axis) // Vertical/Horizontal scrollbar // The entire piece of code below is rather confusing because: -// - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab) -// - 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 absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when +// clicking inside the grab) +// - 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, ImS64* p_scroll_v, ImS64 size_visible_v, ImS64 size_contents_v, ImDrawFlags draw_rounding_flags) +bool ImGui::ScrollbarEx(const ImRect &bb_frame, ImGuiID id, ImGuiAxis axis, ImS64 *p_scroll_v, ImS64 size_visible_v, + ImS64 size_contents_v, ImDrawFlags draw_rounding_flags) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; if (window->SkipItems) return false; @@ -1014,28 +1132,32 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6 if (bb_frame_width <= 0.0f || bb_frame_height <= 0.0f) return false; - // When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the window resize grab) + // When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and + // facilitate using the window resize grab) float alpha = 1.0f; if ((axis == ImGuiAxis_Y) && bb_frame_height < bb_frame_width) alpha = ImSaturate(bb_frame_height / ImMax(bb_frame_width * 2.0f, 1.0f)); if (alpha <= 0.0f) return false; - const ImGuiStyle& style = g.Style; + const ImGuiStyle &style = g.Style; const bool allow_interaction = (alpha >= 1.0f); ImRect bb = bb_frame; - bb.Expand(ImVec2(-ImClamp(IM_TRUNC((bb_frame_width - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp(IM_TRUNC((bb_frame_height - 2.0f) * 0.5f), 0.0f, 3.0f))); + bb.Expand(ImVec2(-ImClamp(IM_TRUNC((bb_frame_width - 2.0f) * 0.5f), 0.0f, 3.0f), + -ImClamp(IM_TRUNC((bb_frame_height - 2.0f) * 0.5f), 0.0f, 3.0f))); // V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar) const float scrollbar_size_v = (axis == ImGuiAxis_X) ? bb.GetWidth() : bb.GetHeight(); - // Calculate the height of our grabbable box. It generally represent the amount visible (vs the total scrollable amount) - // But we maintain a minimum size in pixel to allow for the user to still aim inside. - IM_ASSERT(ImMax(size_contents_v, size_visible_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers. + // Calculate the height of our grabbable box. It generally represent the amount visible (vs the total scrollable + // amount) But we maintain a minimum size in pixel to allow for the user to still aim inside. + IM_ASSERT(ImMax(size_contents_v, size_visible_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is + // still needed. PLEASE CONTACT ME if this triggers. const ImS64 win_size_v = ImMax(ImMax(size_contents_v, size_visible_v), (ImS64)1); const float grab_h_minsize = ImMin(bb.GetSize()[axis], style.GrabMinSize); - const float grab_h_pixels = ImClamp(scrollbar_size_v * ((float)size_visible_v / (float)win_size_v), grab_h_minsize, scrollbar_size_v); + const float grab_h_pixels = + ImClamp(scrollbar_size_v * ((float)size_visible_v / (float)win_size_v), grab_h_minsize, scrollbar_size_v); const float grab_h_norm = grab_h_pixels / scrollbar_size_v; // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar(). @@ -1046,7 +1168,8 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6 const ImS64 scroll_max = ImMax((ImS64)1, size_contents_v - size_visible_v); float scroll_ratio = ImSaturate((float)*p_scroll_v / (float)scroll_max); - float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; // Grab position in normalized space + float grab_v_norm = + scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; // Grab position in normalized space if (held && allow_interaction && grab_h_norm < 1.0f) { const float scrollbar_pos_v = bb.Min[axis]; @@ -1055,21 +1178,28 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6 // Click position in scrollbar normalized space (0.0f->1.0f) const float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v); - const int held_dir = (clicked_v_norm < grab_v_norm) ? -1 : (clicked_v_norm > grab_v_norm + grab_h_norm) ? +1 : 0; + const int held_dir = (clicked_v_norm < grab_v_norm) ? -1 + : (clicked_v_norm > grab_v_norm + grab_h_norm) ? +1 + : 0; if (g.ActiveIdIsJustActivated) { - // On initial click when held_dir == 0 (clicked over grab): calculate the distance between mouse and the center of the grab - const bool scroll_to_clicked_location = (g.IO.ConfigScrollbarScrollByPage == false || g.IO.KeyShift || held_dir == 0); + // On initial click when held_dir == 0 (clicked over grab): calculate the distance between mouse and the + // center of the grab + const bool scroll_to_clicked_location = + (g.IO.ConfigScrollbarScrollByPage == false || g.IO.KeyShift || held_dir == 0); g.ScrollbarSeekMode = scroll_to_clicked_location ? 0 : (short)held_dir; - g.ScrollbarClickDeltaToGrabCenter = (held_dir == 0 && !g.IO.KeyShift) ? clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f : 0.0f; + g.ScrollbarClickDeltaToGrabCenter = + (held_dir == 0 && !g.IO.KeyShift) ? clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f : 0.0f; } // Apply scroll (p_scroll_v will generally point on one member of window->Scroll) - // It is ok to modify Scroll here because we are being called in Begin() after the calculation of ContentSize and before setting up our starting position + // It is ok to modify Scroll here because we are being called in Begin() after the calculation of ContentSize + // and before setting up our starting position if (g.ScrollbarSeekMode == 0) { // Absolute seeking - const float scroll_v_norm = ImSaturate((clicked_v_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm * 0.5f) / (1.0f - grab_h_norm)); + const float scroll_v_norm = ImSaturate( + (clicked_v_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm * 0.5f) / (1.0f - grab_h_norm)); *p_scroll_v = (ImS64)(scroll_v_norm * scroll_max); } else @@ -1087,30 +1217,37 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6 grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; // Update distance to grab now that we have seek'ed and saturated - //if (seek_absolute) + // if (seek_absolute) // g.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f; } // Render const ImU32 bg_col = GetColorU32(ImGuiCol_ScrollbarBg); - const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab, alpha); + 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, draw_rounding_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); + 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); else - grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels); + grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, + ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels); window->DrawList->AddRectFilled(grab_rect.Min, grab_rect.Max, grab_col, style.ScrollbarRounding); return held; } -// - Read about ImTextureID/ImTextureRef here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples +// - Read about ImTextureID/ImTextureRef here: +// https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples // - 'uv0' and 'uv1' are texture coordinates. Read about them from the same link above. -void ImGui::ImageWithBg(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col) +void ImGui::ImageWithBg(ImTextureRef tex_ref, const ImVec2 &image_size, const ImVec2 &uv0, const ImVec2 &uv1, + const ImVec4 &bg_col, const ImVec4 &tint_col) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); + ImGuiContext &g = *GImGui; + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return; @@ -1122,23 +1259,30 @@ void ImGui::ImageWithBg(ImTextureRef tex_ref, const ImVec2& image_size, const Im // Render if (g.Style.ImageBorderSize > 0.0f) - window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border), 0.0f, ImDrawFlags_None, g.Style.ImageBorderSize); + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border), 0.0f, ImDrawFlags_None, + g.Style.ImageBorderSize); if (bg_col.w > 0.0f) window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, GetColorU32(bg_col)); window->DrawList->AddImage(tex_ref, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); } -void ImGui::Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1) +void ImGui::Image(ImTextureRef tex_ref, const ImVec2 &image_size, const ImVec2 &uv0, const ImVec2 &uv1) { ImageWithBg(tex_ref, image_size, uv0, uv1); } -// 1.91.9 (February 2025) removed 'tint_col' and 'border_col' parameters, made border size not depend on color value. (#8131, #8238) +// 1.91.9 (February 2025) removed 'tint_col' and 'border_col' parameters, made border size not depend on color value. +// (#8131, #8238) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -void ImGui::Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) +void ImGui::Image(ImTextureRef tex_ref, const ImVec2 &image_size, const ImVec2 &uv0, const ImVec2 &uv1, + const ImVec4 &tint_col, const ImVec4 &border_col) { - ImGuiContext& g = *GImGui; - PushStyleVar(ImGuiStyleVar_ImageBorderSize, (border_col.w > 0.0f) ? ImMax(1.0f, g.Style.ImageBorderSize) : 0.0f); // Preserve legacy behavior where border is always visible when border_col's Alpha is >0.0f + ImGuiContext &g = *GImGui; + PushStyleVar( + ImGuiStyleVar_ImageBorderSize, + (border_col.w > 0.0f) + ? ImMax(1.0f, g.Style.ImageBorderSize) + : 0.0f); // Preserve legacy behavior where border is always visible when border_col's Alpha is >0.0f PushStyleColor(ImGuiCol_Border, border_col); ImageWithBg(tex_ref, image_size, uv0, uv1, ImVec4(0, 0, 0, 0), tint_col); PopStyleColor(); @@ -1146,10 +1290,11 @@ void ImGui::Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& } #endif -bool ImGui::ImageButtonEx(ImGuiID id, ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags) +bool ImGui::ImageButtonEx(ImGuiID id, ImTextureRef tex_ref, const ImVec2 &image_size, const ImVec2 &uv0, + const ImVec2 &uv1, const ImVec4 &bg_col, const ImVec4 &tint_col, ImGuiButtonFlags flags) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); + ImGuiContext &g = *GImGui; + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; @@ -1163,7 +1308,9 @@ bool ImGui::ImageButtonEx(ImGuiID id, ImTextureRef tex_ref, const ImVec2& image_ bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); // Render - const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive + : hovered ? ImGuiCol_ButtonHovered + : ImGuiCol_Button); RenderNavCursor(bb, id); RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, g.Style.FrameRounding)); if (bg_col.w > 0.0f) @@ -1173,12 +1320,15 @@ bool ImGui::ImageButtonEx(ImGuiID id, ImTextureRef tex_ref, const ImVec2& image_ return pressed; } -// - ImageButton() adds style.FramePadding*2.0f to provided size. This is in order to facilitate fitting an image in a button. -// - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified. (#8165) // FIXME: Maybe that's not the best design? -bool ImGui::ImageButton(const char* str_id, ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col) +// - ImageButton() adds style.FramePadding*2.0f to provided size. This is in order to facilitate fitting an image in a +// button. +// - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified. +// (#8165) // FIXME: Maybe that's not the best design? +bool ImGui::ImageButton(const char *str_id, ImTextureRef tex_ref, const ImVec2 &image_size, const ImVec2 &uv0, + const ImVec2 &uv1, const ImVec4 &bg_col, const ImVec4 &tint_col) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; if (window->SkipItems) return false; @@ -1187,12 +1337,14 @@ bool ImGui::ImageButton(const char* str_id, ImTextureRef tex_ref, const ImVec2& #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Legacy API obsoleted in 1.89. Two differences with new ImageButton() -// - old ImageButton() used ImTextureID as item id (created issue with multiple buttons with same image, transient texture id values, opaque computation of ID) +// - old ImageButton() used ImTextureID as item id (created issue with multiple buttons with same image, transient +// texture id values, opaque computation of ID) // - new ImageButton() requires an explicit 'const char* str_id' // - old ImageButton() had frame_padding' override argument. // - new ImageButton() always use style.FramePadding. /* -bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) +bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int +frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) { // Default to using texture ID as ID. User can still push string/integer prefixes. PushID((ImTextureID)(intptr_t)user_texture_id); @@ -1207,27 +1359,32 @@ bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const I */ #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -bool ImGui::Checkbox(const char* label, bool* v) +bool ImGui::Checkbox(const char *label, bool *v) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; + ImGuiContext &g = *GImGui; + const ImGuiStyle &style = g.Style; const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); const float square_sz = GetFrameHeight(); const ImVec2 pos = window->DC.CursorPos; - const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f)); + const ImRect total_bb( + pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), + label_size.y + style.FramePadding.y * 2.0f)); ItemSize(total_bb, style.FramePadding.y); const bool is_visible = ItemAdd(total_bb, id); const bool is_multi_select = (g.LastItemData.ItemFlags & ImGuiItemFlags_IsMultiSelect) != 0; if (!is_visible) - if (!is_multi_select || !g.BoxSelectState.UnclipMode || !g.BoxSelectState.UnclipRect.Overlaps(total_bb)) // Extra layer of "no logic clip" for box-select support + if (!is_multi_select || !g.BoxSelectState.UnclipMode || + !g.BoxSelectState.UnclipRect.Overlaps(total_bb)) // Extra layer of "no logic clip" for box-select support { - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, + g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | + (*v ? ImGuiItemStatusFlags_Checked : 0)); return false; } @@ -1257,12 +1414,17 @@ bool ImGui::Checkbox(const char* label, bool* v) if (is_visible) { RenderNavCursor(total_bb, id); - RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); + 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); if (mixed_value) { // Undocumented tristate/mixed/indeterminate checkbox (#2644) - // This may seem awkwardly designed because the aim is to make ImGuiItemFlags_MixedValue supported by all widgets (not just checkbox) + // This may seem awkwardly designed because the aim is to make ImGuiItemFlags_MixedValue supported by all + // widgets (not just checkbox) ImVec2 pad(ImMax(1.0f, IM_TRUNC(square_sz / 3.6f)), ImMax(1.0f, IM_TRUNC(square_sz / 3.6f))); window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding); } @@ -1278,26 +1440,26 @@ bool ImGui::Checkbox(const char* label, bool* v) if (is_visible && label_size.x > 0.0f) RenderText(label_pos, label); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, + g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | + (*v ? ImGuiItemStatusFlags_Checked : 0)); return pressed; } -template -bool ImGui::CheckboxFlagsT(const char* label, T* flags, T flags_value) +template bool ImGui::CheckboxFlagsT(const char *label, T *flags, T flags_value) { bool all_on = (*flags & flags_value) == flags_value; bool any_on = (*flags & flags_value) != 0; bool pressed; if (!all_on && any_on) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; g.NextItemData.ItemFlags |= ImGuiItemFlags_MixedValue; pressed = Checkbox(label, &all_on); } else { pressed = Checkbox(label, &all_on); - } if (pressed) { @@ -1309,41 +1471,43 @@ bool ImGui::CheckboxFlagsT(const char* label, T* flags, T flags_value) return pressed; } -bool ImGui::CheckboxFlags(const char* label, int* flags, int flags_value) +bool ImGui::CheckboxFlags(const char *label, int *flags, int flags_value) { return CheckboxFlagsT(label, flags, flags_value); } -bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value) +bool ImGui::CheckboxFlags(const char *label, unsigned int *flags, unsigned int flags_value) { return CheckboxFlagsT(label, flags, flags_value); } -bool ImGui::CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value) +bool ImGui::CheckboxFlags(const char *label, ImS64 *flags, ImS64 flags_value) { return CheckboxFlagsT(label, flags, flags_value); } -bool ImGui::CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value) +bool ImGui::CheckboxFlags(const char *label, ImU64 *flags, ImU64 flags_value) { return CheckboxFlagsT(label, flags, flags_value); } -bool ImGui::RadioButton(const char* label, bool active) +bool ImGui::RadioButton(const char *label, bool active) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; + ImGuiContext &g = *GImGui; + const ImGuiStyle &style = g.Style; const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); const float square_sz = GetFrameHeight(); const ImVec2 pos = window->DC.CursorPos; const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); - const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f)); + const ImRect total_bb( + pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), + label_size.y + style.FramePadding.y * 2.0f)); ItemSize(total_bb, style.FramePadding.y); if (!ItemAdd(total_bb, id)) return false; @@ -1360,7 +1524,11 @@ bool ImGui::RadioButton(const char* label, bool active) RenderNavCursor(total_bb, id); const int num_segment = window->DrawList->_CalcCircleAutoSegmentCount(radius); - window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), num_segment); + window->DrawList->AddCircleFilled(center, radius, + GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive + : hovered ? ImGuiCol_FrameBgHovered + : ImGuiCol_FrameBg), + num_segment); if (active) { const float pad = ImMax(1.0f, IM_TRUNC(square_sz / 6.0f)); @@ -1369,7 +1537,8 @@ bool ImGui::RadioButton(const char* label, bool active) if (style.FrameBorderSize > 0.0f) { - window->DrawList->AddCircle(center + ImVec2(1, 1), radius, GetColorU32(ImGuiCol_BorderShadow), num_segment, style.FrameBorderSize); + window->DrawList->AddCircle(center + ImVec2(1, 1), radius, GetColorU32(ImGuiCol_BorderShadow), num_segment, + style.FrameBorderSize); window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), num_segment, style.FrameBorderSize); } @@ -1383,8 +1552,9 @@ bool ImGui::RadioButton(const char* label, bool active) return pressed; } -// FIXME: This would work nicely if it was a public template, e.g. 'template RadioButton(const char* label, T* v, T v_button)', but I'm not sure how we would expose it.. -bool ImGui::RadioButton(const char* label, int* v, int v_button) +// FIXME: This would work nicely if it was a public template, e.g. 'template RadioButton(const char* label, T* v, T +// v_button)', but I'm not sure how we would expose it.. +bool ImGui::RadioButton(const char *label, int *v, int v_button) { const bool pressed = RadioButton(label, *v == v_button); if (pressed) @@ -1393,14 +1563,14 @@ bool ImGui::RadioButton(const char* label, int* v, int v_button) } // size_arg (for each axis) < 0.0f: align to end, 0.0f: auto, > 0.0f: specified size -void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* overlay) +void ImGui::ProgressBar(float fraction, const ImVec2 &size_arg, const char *overlay) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return; - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; + ImGuiContext &g = *GImGui; + const ImGuiStyle &style = g.Style; ImVec2 pos = window->DC.CursorPos; ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y * 2.0f); @@ -1430,7 +1600,8 @@ void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* over // Render RenderFrame(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); bb.Expand(ImVec2(-style.FrameBorderSize, -style.FrameBorderSize)); - RenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_PlotHistogram), fill_n0, fill_n1, style.FrameRounding); + RenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_PlotHistogram), fill_n0, fill_n1, + style.FrameRounding); // Default displaying the fraction as percentage string, but user can override it // Don't display text for indeterminate bars by default @@ -1446,21 +1617,25 @@ void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* over ImVec2 overlay_size = CalcTextSize(overlay, NULL); if (overlay_size.x > 0.0f) { - float text_x = is_indeterminate ? (bb.Min.x + bb.Max.x - overlay_size.x) * 0.5f : ImLerp(bb.Min.x, bb.Max.x, fill_n1) + style.ItemSpacing.x; - RenderTextClipped(ImVec2(ImClamp(text_x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f, 0.5f), &bb); + float text_x = is_indeterminate ? (bb.Min.x + bb.Max.x - overlay_size.x) * 0.5f + : ImLerp(bb.Min.x, bb.Max.x, fill_n1) + style.ItemSpacing.x; + RenderTextClipped( + ImVec2(ImClamp(text_x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), + bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f, 0.5f), &bb); } } } void ImGui::Bullet() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return; - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; - const float line_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), g.FontSize); + ImGuiContext &g = *GImGui; + const ImGuiStyle &style = g.Style; + const float line_height = + ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), g.FontSize); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height)); ItemSize(bb); if (!ItemAdd(bb, 0)) @@ -1471,7 +1646,8 @@ void ImGui::Bullet() // Render and stay on same line ImU32 text_col = GetColorU32(ImGuiCol_Text); - RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize * 0.5f, line_height * 0.5f), text_col); + RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize * 0.5f, line_height * 0.5f), + text_col); SameLine(0, style.FramePadding.x * 2.0f); } @@ -1479,15 +1655,15 @@ void ImGui::Bullet() // FIXME-STYLE: we delayed adding as there is a larger plan to revamp the styling system. // Because of this we currently don't provide many styling options for this widget // (e.g. hovered/active colors are automatically inferred from a single color). -bool ImGui::TextLink(const char* label) +bool ImGui::TextLink(const char *label) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; const ImGuiID id = window->GetID(label); - const char* label_end = FindRenderedTextEnd(label); + const char *label_end = FindRenderedTextEnd(label); ImVec2 pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); ImVec2 size = CalcTextSize(label, label_end, true); @@ -1521,7 +1697,8 @@ bool ImGui::TextLink(const char* label) } float line_y = bb.Max.y + ImFloor(g.FontBaked->Descent * g.FontBakedScale * 0.20f); - window->DrawList->AddLine(ImVec2(bb.Min.x, line_y), ImVec2(bb.Max.x, line_y), GetColorU32(line_colf)); // FIXME-TEXT: Underline mode // FIXME-DPI + window->DrawList->AddLine(ImVec2(bb.Min.x, line_y), ImVec2(bb.Max.x, line_y), + GetColorU32(line_colf)); // FIXME-TEXT: Underline mode // FIXME-DPI PushStyleColor(ImGuiCol_Text, GetColorU32(text_colf)); RenderText(bb.Min, label, label_end); @@ -1531,15 +1708,16 @@ bool ImGui::TextLink(const char* label) return pressed; } -bool ImGui::TextLinkOpenURL(const char* label, const char* url) +bool ImGui::TextLinkOpenURL(const char *label, const char *url) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; if (url == NULL) url = label; bool pressed = TextLink(label); if (pressed && g.PlatformIO.Platform_OpenInShellFn != NULL) g.PlatformIO.Platform_OpenInShellFn(&g, url); - SetItemTooltip(LocalizeGetMsg(ImGuiLocKey_OpenLink_s), url); // It is more reassuring for user to _always_ display URL when we same as label + SetItemTooltip(LocalizeGetMsg(ImGuiLocKey_OpenLink_s), + url); // It is more reassuring for user to _always_ display URL when we same as label if (BeginPopupContextItem()) { if (MenuItem(LocalizeGetMsg(ImGuiLocKey_CopyLink))) @@ -1564,15 +1742,15 @@ bool ImGui::TextLinkOpenURL(const char* label, const char* url) void ImGui::Spacing() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return; ItemSize(ImVec2(0, 0)); } -void ImGui::Dummy(const ImVec2& size) +void ImGui::Dummy(const ImVec2 &size) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return; @@ -1583,15 +1761,16 @@ void ImGui::Dummy(const ImVec2& size) void ImGui::NewLine() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return; - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; const ImGuiLayoutType backup_layout_type = window->DC.LayoutType; window->DC.LayoutType = ImGuiLayoutType_Vertical; window->DC.IsSameLine = false; - if (window->DC.CurrLineSize.y > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height. + if (window->DC.CurrLineSize.y > 0.0f) // In the event that we are on a line with items that is smaller that FontSize + // high, we will preserve its height. ItemSize(ImVec2(0, 0)); else ItemSize(ImVec2(0.0f, g.FontSize)); @@ -1600,11 +1779,11 @@ void ImGui::NewLine() void ImGui::AlignTextToFramePadding() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return; - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; window->DC.CurrLineSize.y = ImMax(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y * 2); window->DC.CurrLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, g.Style.FramePadding.y); } @@ -1614,12 +1793,13 @@ void ImGui::AlignTextToFramePadding() // Note how thickness == 1.0f is handled specifically as not moving CursorPos by 'thickness', but other values are. void ImGui::SeparatorEx(ImGuiSeparatorFlags flags, float thickness) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return; - ImGuiContext& g = *GImGui; - IM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical))); // Check that only 1 option is selected + ImGuiContext &g = *GImGui; + IM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | + ImGuiSeparatorFlags_Vertical))); // Check that only 1 option is selected IM_ASSERT(thickness > 0.0f); if (flags & ImGuiSeparatorFlags_Vertical) @@ -1646,7 +1826,7 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags, float thickness) // Preserve legacy behavior inside Columns() // Before Tables API happened, we relied on Separator() to span all columns of a Columns() set. // We currently don't need to provide the same feature for tables because tables naturally have border features. - ImGuiOldColumns* columns = (flags & ImGuiSeparatorFlags_SpanAllColumns) ? window->DC.CurrentColumns : NULL; + ImGuiOldColumns *columns = (flags & ImGuiSeparatorFlags_SpanAllColumns) ? window->DC.CurrentColumns : NULL; if (columns) { x1 = window->Pos.x + window->DC.Indent.x; // Used to be Pos.x before 2023/10/03 @@ -1656,7 +1836,9 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags, float thickness) // We don't provide our width to the layout so that it doesn't get feed back into AutoFit // FIXME: This prevents ->CursorMaxPos based bounding box evaluation from working (e.g. TableEndCell) - const float thickness_for_layout = (thickness == 1.0f) ? 0.0f : thickness; // FIXME: See 1.70/1.71 Separator() change: makes legacy 1-px separator not affect layout yet. Should change. + const float thickness_for_layout = + (thickness == 1.0f) ? 0.0f : thickness; // FIXME: See 1.70/1.71 Separator() change: makes legacy 1-px + // separator not affect layout yet. Should change. const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness)); ItemSize(ImVec2(0.0f, thickness_for_layout)); @@ -1666,7 +1848,6 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags, float thickness) window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Separator)); if (g.LogEnabled) LogRenderedText(&bb.Min, "--------------------------------\n"); - } if (columns) { @@ -1678,14 +1859,16 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags, float thickness) void ImGui::Separator() { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; if (window->SkipItems) return; // Those flags should eventually be configurable by the user - // FIXME: We cannot g.Style.SeparatorTextBorderSize for thickness as it relates to SeparatorText() which is a decorated separator, not defaulting to 1.0f. - ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal; + // FIXME: We cannot g.Style.SeparatorTextBorderSize for thickness as it relates to SeparatorText() which is a + // decorated separator, not defaulting to 1.0f. + ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical + : ImGuiSeparatorFlags_Horizontal; // Only applies to legacy Columns() api as they relied on Separator() a lot. if (window->DC.CurrentColumns) @@ -1694,20 +1877,23 @@ void ImGui::Separator() SeparatorEx(flags, 1.0f); } -void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_w) +void ImGui::SeparatorTextEx(ImGuiID id, const char *label, const char *label_end, float extra_w) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - ImGuiStyle& style = g.Style; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; + ImGuiStyle &style = g.Style; const ImVec2 label_size = CalcTextSize(label, label_end, false); const ImVec2 pos = window->DC.CursorPos; const ImVec2 padding = style.SeparatorTextPadding; const float separator_thickness = style.SeparatorTextBorderSize; - const ImVec2 min_size(label_size.x + extra_w + padding.x * 2.0f, ImMax(label_size.y + padding.y * 2.0f, separator_thickness)); + const ImVec2 min_size(label_size.x + extra_w + padding.x * 2.0f, + ImMax(label_size.y + padding.y * 2.0f, separator_thickness)); const ImRect bb(pos, ImVec2(window->WorkRect.Max.x, pos.y + min_size.y)); - const float text_baseline_y = ImTrunc((bb.GetHeight() - label_size.y) * style.SeparatorTextAlign.y + 0.99999f); //ImMax(padding.y, ImFloor((style.SeparatorTextSize - label_size.y) * 0.5f)); + const float text_baseline_y = + ImTrunc((bb.GetHeight() - label_size.y) * style.SeparatorTextAlign.y + + 0.99999f); // ImMax(padding.y, ImFloor((style.SeparatorTextSize - label_size.y) * 0.5f)); ItemSize(min_size, text_baseline_y); if (!ItemAdd(bb, id)) return; @@ -1717,7 +1903,9 @@ void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end const float seps_y = ImTrunc((bb.Min.y + bb.Max.y) * 0.5f + 0.99999f); const float label_avail_w = ImMax(0.0f, sep2_x2 - sep1_x1 - padding.x * 2.0f); - const ImVec2 label_pos(pos.x + padding.x + ImMax(0.0f, (label_avail_w - label_size.x - extra_w) * style.SeparatorTextAlign.x), pos.y + text_baseline_y); // FIXME-ALIGN + const ImVec2 label_pos(pos.x + padding.x + + ImMax(0.0f, (label_avail_w - label_size.x - extra_w) * style.SeparatorTextAlign.x), + pos.y + text_baseline_y); // FIXME-ALIGN // This allows using SameLine() to position something in the 'extra_w' window->DC.CursorPosPrevLine.x = label_pos.x + label_size.x; @@ -1728,25 +1916,29 @@ void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end const float sep1_x2 = label_pos.x - style.ItemSpacing.x; const float sep2_x1 = label_pos.x + label_size.x + extra_w + style.ItemSpacing.x; if (sep1_x2 > sep1_x1 && separator_thickness > 0.0f) - window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep1_x2, seps_y), separator_col, separator_thickness); + window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep1_x2, seps_y), separator_col, + separator_thickness); if (sep2_x2 > sep2_x1 && separator_thickness > 0.0f) - window->DrawList->AddLine(ImVec2(sep2_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness); + window->DrawList->AddLine(ImVec2(sep2_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, + separator_thickness); if (g.LogEnabled) LogSetNextTextDecoration("---", NULL); - RenderTextEllipsis(window->DrawList, label_pos, ImVec2(bb.Max.x, bb.Max.y + style.ItemSpacing.y), bb.Max.x, label, label_end, &label_size); + RenderTextEllipsis(window->DrawList, label_pos, ImVec2(bb.Max.x, bb.Max.y + style.ItemSpacing.y), bb.Max.x, + label, label_end, &label_size); } else { if (g.LogEnabled) LogText("---"); if (separator_thickness > 0.0f) - window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness); + window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, + separator_thickness); } } -void ImGui::SeparatorText(const char* label) +void ImGui::SeparatorText(const char *label) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return; @@ -1759,11 +1951,13 @@ void ImGui::SeparatorText(const char* label) SeparatorTextEx(0, label, FindRenderedTextEnd(label), 0.0f); } -// Using 'hover_visibility_delay' allows us to hide the highlight and mouse cursor for a short time, which can be convenient to reduce visual noise. -bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend, float hover_visibility_delay, ImU32 bg_col) +// Using 'hover_visibility_delay' allows us to hide the highlight and mouse cursor for a short time, which can be +// convenient to reduce visual noise. +bool ImGui::SplitterBehavior(const ImRect &bb, ImGuiID id, ImGuiAxis axis, float *size1, float *size2, float min_size1, + float min_size2, float hover_extend, float hover_visibility_delay, ImU32 bg_col) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; if (!ItemAdd(bb, id, NULL, ImGuiItemFlags_NoNav)) return false; @@ -1781,7 +1975,8 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f)); ButtonBehavior(bb_interact, id, &hovered, &held, button_flags); if (hovered) - g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect; // for IsItemHovered(), because bb_interact is larger than bb + g.LastItemData.StatusFlags |= + ImGuiItemStatusFlags_HoveredRect; // for IsItemHovered(), because bb_interact is larger than bb if (held || (hovered && g.HoveredIdPreviousFrame == id && g.HoveredIdTimer >= hover_visibility_delay)) SetMouseCursor(axis == ImGuiAxis_Y ? ImGuiMouseCursor_ResizeNS : ImGuiMouseCursor_ResizeEW); @@ -1812,16 +2007,18 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float // Render at new position if (bg_col & IM_COL32_A_MASK) window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, bg_col, 0.0f); - const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : (hovered && g.HoveredIdTimer >= hover_visibility_delay) ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); + const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive + : (hovered && g.HoveredIdTimer >= hover_visibility_delay) ? ImGuiCol_SeparatorHovered + : ImGuiCol_Separator); window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, col, 0.0f); return held; } -static int IMGUI_CDECL ShrinkWidthItemComparer(const void* lhs, const void* rhs) +static int IMGUI_CDECL ShrinkWidthItemComparer(const void *lhs, const void *rhs) { - const ImGuiShrinkWidthItem* a = (const ImGuiShrinkWidthItem*)lhs; - const ImGuiShrinkWidthItem* b = (const ImGuiShrinkWidthItem*)rhs; + const ImGuiShrinkWidthItem *a = (const ImGuiShrinkWidthItem *)lhs; + const ImGuiShrinkWidthItem *b = (const ImGuiShrinkWidthItem *)rhs; if (int d = (int)(b->Width - a->Width)) return d; return (b->Index - a->Index); @@ -1829,7 +2026,7 @@ static int IMGUI_CDECL ShrinkWidthItemComparer(const void* lhs, const void* rhs) // Shrink excess width from a set of item, by removing width from the larger items first. // Set items Width to -1.0f to disable shrinking this item. -void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess) +void ImGui::ShrinkWidths(ImGuiShrinkWidthItem *items, int count, float width_excess) { if (count == 1) { @@ -1843,7 +2040,9 @@ void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_exc { while (count_same_width < count && items[0].Width <= items[count_same_width].Width) count_same_width++; - float max_width_to_remove_per_item = (count_same_width < count && items[count_same_width].Width >= 0.0f) ? (items[0].Width - items[count_same_width].Width) : (items[0].Width - 1.0f); + float max_width_to_remove_per_item = (count_same_width < count && items[count_same_width].Width >= 0.0f) + ? (items[0].Width - items[count_same_width].Width) + : (items[0].Width - 1.0f); if (max_width_to_remove_per_item <= 0.0f) break; float width_to_remove_per_item = ImMin(width_excess / count_same_width, max_width_to_remove_per_item); @@ -1853,7 +2052,8 @@ void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_exc } // Round width and redistribute remainder - // Ensure that e.g. the right-most tab of a shrunk tab-bar always reaches exactly at the same distance from the right-most edge of the tab bar separator. + // Ensure that e.g. the right-most tab of a shrunk tab-bar always reaches exactly at the same distance from the + // right-most edge of the tab bar separator. width_excess = 0.0f; for (int n = 0; n < count; n++) { @@ -1884,34 +2084,42 @@ void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_exc static float CalcMaxPopupHeightFromItemCount(int items_count) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; if (items_count <= 0) return FLT_MAX; return (g.FontSize + g.Style.ItemSpacing.y) * items_count - g.Style.ItemSpacing.y + (g.Style.WindowPadding.y * 2); } -bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags) +bool ImGui::BeginCombo(const char *label, const char *preview_value, ImGuiComboFlags flags) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); + ImGuiContext &g = *GImGui; + ImGuiWindow *window = GetCurrentWindow(); ImGuiNextWindowDataFlags backup_next_window_data_flags = g.NextWindowData.HasFlags; g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values if (window->SkipItems) return false; - const ImGuiStyle& style = g.Style; + const ImGuiStyle &style = g.Style; const ImGuiID id = window->GetID(label); - IM_ASSERT((flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)); // Can't use both flags together + IM_ASSERT((flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != + (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)); // Can't use both flags together if (flags & ImGuiComboFlags_WidthFitPreview) IM_ASSERT((flags & (ImGuiComboFlags_NoPreview | (ImGuiComboFlags)ImGuiComboFlags_CustomPreview)) == 0); const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight(); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const float preview_width = ((flags & ImGuiComboFlags_WidthFitPreview) && (preview_value != NULL)) ? CalcTextSize(preview_value, NULL, true).x : 0.0f; - const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : ((flags & ImGuiComboFlags_WidthFitPreview) ? (arrow_size + preview_width + style.FramePadding.x * 2.0f) : CalcItemWidth()); + const float preview_width = ((flags & ImGuiComboFlags_WidthFitPreview) && (preview_value != NULL)) + ? CalcTextSize(preview_value, NULL, true).x + : 0.0f; + const float w = + (flags & ImGuiComboFlags_NoPreview) + ? arrow_size + : ((flags & ImGuiComboFlags_WidthFitPreview) ? (arrow_size + preview_width + style.FramePadding.x * 2.0f) + : CalcItemWidth()); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); - const ImRect total_bb(bb.Min, bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + const ImRect total_bb(bb.Min, + bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); ItemSize(total_bb, style.FramePadding.y); if (!ItemAdd(total_bb, id, &bb)) return false; @@ -1932,14 +2140,19 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF const float value_x2 = ImMax(bb.Min.x, bb.Max.x - arrow_size); RenderNavCursor(bb, id); if (!(flags & ImGuiComboFlags_NoPreview)) - window->DrawList->AddRectFilled(bb.Min, ImVec2(value_x2, bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersLeft); + window->DrawList->AddRectFilled(bb.Min, ImVec2(value_x2, 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, bb.Min.y), bb.Max, bg_col, style.FrameRounding, (w <= arrow_size) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersRight); + window->DrawList->AddRectFilled(ImVec2(value_x2, bb.Min.y), bb.Max, bg_col, style.FrameRounding, + (w <= arrow_size) ? ImDrawFlags_RoundCornersAll + : ImDrawFlags_RoundCornersRight); if (value_x2 + arrow_size - style.FramePadding.x <= bb.Max.x) - RenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, bb.Min.y + style.FramePadding.y), text_col, ImGuiDir_Down, 1.0f); + RenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, bb.Min.y + style.FramePadding.y), + text_col, ImGuiDir_Down, 1.0f); } RenderFrameBorder(bb.Min, bb.Max, style.FrameRounding); @@ -1968,9 +2181,9 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF return BeginComboPopup(popup_id, bb, flags); } -bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags) +bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect &bb, ImGuiComboFlags flags) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; if (!IsPopupOpen(popup_id, ImGuiPopupFlags_None)) { g.NextWindowData.ClearFlags(); @@ -1989,11 +2202,15 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags |= ImGuiComboFlags_HeightRegular; IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiComboFlags_HeightMask_)); // Only one int popup_max_height_in_items = -1; - if (flags & ImGuiComboFlags_HeightRegular) popup_max_height_in_items = 8; - else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4; - else if (flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20; + if (flags & ImGuiComboFlags_HeightRegular) + popup_max_height_in_items = 8; + else if (flags & ImGuiComboFlags_HeightSmall) + popup_max_height_in_items = 4; + else if (flags & ImGuiComboFlags_HeightLarge) + popup_max_height_in_items = 20; ImVec2 constraint_min(0.0f, 0.0f), constraint_max(FLT_MAX, FLT_MAX); - if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.x <= 0.0f) // Don't apply constraints if user specified a size + if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSize) == 0 || + g.NextWindowData.SizeVal.x <= 0.0f) // Don't apply constraints if user specified a size constraint_min.x = w; if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.y <= 0.0f) constraint_max.y = CalcMaxPopupHeightFromItemCount(popup_max_height_in_items); @@ -2006,27 +2223,36 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags // Set position given a custom constraint (peak into expected window size so we can position it) // FIXME: This might be easier to express with an hypothetical SetNextWindowPosConstraints() function? - // FIXME: This might be moved to Begin() or at least around the same spot where Tooltips and other Popups are calling FindBestWindowPosForPopupEx()? - if (ImGuiWindow* popup_window = FindWindowByName(name)) + // FIXME: This might be moved to Begin() or at least around the same spot where Tooltips and other Popups are + // calling FindBestWindowPosForPopupEx()? + if (ImGuiWindow *popup_window = FindWindowByName(name)) if (popup_window->WasActive) { // Always override 'AutoPosLastDirection' to not leave a chance for a past value to affect us. ImVec2 size_expected = CalcWindowNextAutoFitSize(popup_window); - popup_window->AutoPosLastDirection = (flags & ImGuiComboFlags_PopupAlignLeft) ? ImGuiDir_Left : ImGuiDir_Down; // Left = "Below, Toward Left", Down = "Below, Toward Right (default)" + popup_window->AutoPosLastDirection = + (flags & ImGuiComboFlags_PopupAlignLeft) + ? ImGuiDir_Left + : ImGuiDir_Down; // Left = "Below, Toward Left", Down = "Below, Toward Right (default)" ImRect r_outer = GetPopupAllowedExtentRect(popup_window); - ImVec2 pos = FindBestWindowPosForPopupEx(bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, r_outer, bb, ImGuiPopupPositionPolicy_ComboBox); + ImVec2 pos = FindBestWindowPosForPopupEx(bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, + r_outer, bb, ImGuiPopupPositionPolicy_ComboBox); SetNextWindowPos(pos); } - // We don't use BeginPopupEx() solely because we have a custom name string, which we could make an argument to BeginPopupEx() - ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove; - PushStyleVarX(ImGuiStyleVar_WindowPadding, g.Style.FramePadding.x); // Horizontally align ourselves with the framed text + // We don't use BeginPopupEx() solely because we have a custom name string, which we could make an argument to + // BeginPopupEx() + ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove; + PushStyleVarX(ImGuiStyleVar_WindowPadding, + g.Style.FramePadding.x); // Horizontally align ourselves with the framed text bool ret = Begin(name, NULL, window_flags); PopStyleVar(); if (!ret) { EndPopup(); - IM_ASSERT(0); // This should never happen as we tested for IsPopupOpen() above + IM_ASSERT(0); // This should never happen as we tested for IsPopupOpen() above return false; } g.BeginComboDepth++; @@ -2035,7 +2261,7 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags void ImGui::EndCombo() { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; EndPopup(); g.BeginComboDepth--; } @@ -2044,13 +2270,16 @@ void ImGui::EndCombo() // (Experimental, see GitHub issues: #1658, #4168) bool ImGui::BeginComboPreview() { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - ImGuiComboPreviewData* preview_data = &g.ComboPreviewData; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; + ImGuiComboPreviewData *preview_data = &g.ComboPreviewData; if (window->SkipItems || !(g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible)) return false; - IM_ASSERT(g.LastItemData.Rect.Min.x == preview_data->PreviewRect.Min.x && g.LastItemData.Rect.Min.y == preview_data->PreviewRect.Min.y); // Didn't call after BeginCombo/EndCombo block or forgot to pass ImGuiComboFlags_CustomPreview flag? + IM_ASSERT(g.LastItemData.Rect.Min.x == preview_data->PreviewRect.Min.x && + g.LastItemData.Rect.Min.y == + preview_data->PreviewRect.Min.y); // Didn't call after BeginCombo/EndCombo block or forgot to pass + // ImGuiComboFlags_CustomPreview flag? if (!window->ClipRect.Overlaps(preview_data->PreviewRect)) // Narrower test (optional) return false; @@ -2071,16 +2300,18 @@ bool ImGui::BeginComboPreview() void ImGui::EndComboPreview() { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - ImGuiComboPreviewData* preview_data = &g.ComboPreviewData; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; + ImGuiComboPreviewData *preview_data = &g.ComboPreviewData; // FIXME: Using CursorMaxPos approximation instead of correct AABB which we will store in ImDrawCmd in the future - ImDrawList* draw_list = window->DrawList; - if (window->DC.CursorMaxPos.x < preview_data->PreviewRect.Max.x && window->DC.CursorMaxPos.y < preview_data->PreviewRect.Max.y) + ImDrawList *draw_list = window->DrawList; + if (window->DC.CursorMaxPos.x < preview_data->PreviewRect.Max.x && + window->DC.CursorMaxPos.y < preview_data->PreviewRect.Max.y) if (draw_list->CmdBuffer.Size > 1) // Unlikely case that the PushClipRect() didn't create a command { - draw_list->_CmdHeader.ClipRect = draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ClipRect = draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 2].ClipRect; + draw_list->_CmdHeader.ClipRect = draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ClipRect = + draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 2].ClipRect; draw_list->_TryMergeDrawCmds(); } PopClipRect(); @@ -2094,18 +2325,18 @@ void ImGui::EndComboPreview() } // Getter for the old Combo() API: const char*[] -static const char* Items_ArrayGetter(void* data, int idx) +static const char *Items_ArrayGetter(void *data, int idx) { - const char* const* items = (const char* const*)data; + const char *const *items = (const char *const *)data; return items[idx]; } // Getter for the old Combo() API: "item1\0item2\0item3\0" -static const char* Items_SingleStringGetter(void* data, int idx) +static const char *Items_SingleStringGetter(void *data, int idx) { - const char* items_separated_by_zeros = (const char*)data; + const char *items_separated_by_zeros = (const char *)data; int items_count = 0; - const char* p = items_separated_by_zeros; + const char *p = items_separated_by_zeros; while (*p) { if (idx == items_count) @@ -2117,18 +2348,21 @@ static const char* Items_SingleStringGetter(void* data, int idx) } // Old API, prefer using BeginCombo() nowadays if you can. -bool ImGui::Combo(const char* label, int* current_item, const char* (*getter)(void* user_data, int idx), void* user_data, int items_count, int popup_max_height_in_items) +bool ImGui::Combo(const char *label, int *current_item, const char *(*getter)(void *user_data, int idx), + void *user_data, int items_count, int popup_max_height_in_items) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; // Call the getter to obtain the preview string which is a parameter to BeginCombo() - const char* preview_value = NULL; + const char *preview_value = NULL; if (*current_item >= 0 && *current_item < items_count) preview_value = getter(user_data, *current_item); - // The old Combo() API exposed "popup_max_height_in_items". The new more general BeginCombo() API doesn't have/need it, but we emulate it here. + // The old Combo() API exposed "popup_max_height_in_items". The new more general BeginCombo() API doesn't have/need + // it, but we emulate it here. if (popup_max_height_in_items != -1 && !(g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSizeConstraint)) - SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); + SetNextWindowSizeConstraints(ImVec2(0, 0), + ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); if (!BeginCombo(label, preview_value, ImGuiComboFlags_None)) return false; @@ -2141,7 +2375,7 @@ bool ImGui::Combo(const char* label, int* current_item, const char* (*getter)(vo while (clipper.Step()) for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - const char* item_text = getter(user_data, i); + const char *item_text = getter(user_data, i); if (item_text == NULL) item_text = "*Unknown item*"; @@ -2165,46 +2399,57 @@ bool ImGui::Combo(const char* label, int* current_item, const char* (*getter)(vo } // Combo box helper allowing to pass an array of strings. -bool ImGui::Combo(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items) +bool ImGui::Combo(const char *label, int *current_item, const char *const items[], int items_count, int height_in_items) { - const bool value_changed = Combo(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_in_items); + const bool value_changed = + Combo(label, current_item, Items_ArrayGetter, (void *)items, items_count, height_in_items); return value_changed; } -// Combo box helper allowing to pass all items in a single string literal holding multiple zero-terminated items "item1\0item2\0" -bool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items) +// Combo box helper allowing to pass all items in a single string literal holding multiple zero-terminated items +// "item1\0item2\0" +bool ImGui::Combo(const char *label, int *current_item, const char *items_separated_by_zeros, int height_in_items) { int items_count = 0; - const char* p = items_separated_by_zeros; // FIXME-OPT: Avoid computing this, or at least only when combo is open + const char *p = items_separated_by_zeros; // FIXME-OPT: Avoid computing this, or at least only when combo is open while (*p) { p += ImStrlen(p) + 1; items_count++; } - bool value_changed = Combo(label, current_item, Items_SingleStringGetter, (void*)items_separated_by_zeros, items_count, height_in_items); + bool value_changed = Combo(label, current_item, Items_SingleStringGetter, (void *)items_separated_by_zeros, + items_count, height_in_items); return value_changed; } #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -struct ImGuiGetNameFromIndexOldToNewCallbackData { void* UserData; bool (*OldCallback)(void*, int, const char**); }; -static const char* ImGuiGetNameFromIndexOldToNewCallback(void* user_data, int idx) +struct ImGuiGetNameFromIndexOldToNewCallbackData { - ImGuiGetNameFromIndexOldToNewCallbackData* data = (ImGuiGetNameFromIndexOldToNewCallbackData*)user_data; - const char* s = NULL; + void *UserData; + bool (*OldCallback)(void *, int, const char **); +}; +static const char *ImGuiGetNameFromIndexOldToNewCallback(void *user_data, int idx) +{ + ImGuiGetNameFromIndexOldToNewCallbackData *data = (ImGuiGetNameFromIndexOldToNewCallbackData *)user_data; + const char *s = NULL; data->OldCallback(data->UserData, idx, &s); return s; } -bool ImGui::ListBox(const char* label, int* current_item, bool (*old_getter)(void*, int, const char**), void* user_data, int items_count, int height_in_items) +bool ImGui::ListBox(const char *label, int *current_item, bool (*old_getter)(void *, int, const char **), + void *user_data, int items_count, int height_in_items) { - ImGuiGetNameFromIndexOldToNewCallbackData old_to_new_data = { user_data, old_getter }; - return ListBox(label, current_item, ImGuiGetNameFromIndexOldToNewCallback, &old_to_new_data, items_count, height_in_items); + ImGuiGetNameFromIndexOldToNewCallbackData old_to_new_data = {user_data, old_getter}; + return ListBox(label, current_item, ImGuiGetNameFromIndexOldToNewCallback, &old_to_new_data, items_count, + height_in_items); } -bool ImGui::Combo(const char* label, int* current_item, bool (*old_getter)(void*, int, const char**), void* user_data, int items_count, int popup_max_height_in_items) +bool ImGui::Combo(const char *label, int *current_item, bool (*old_getter)(void *, int, const char **), void *user_data, + int items_count, int popup_max_height_in_items) { - ImGuiGetNameFromIndexOldToNewCallbackData old_to_new_data = { user_data, old_getter }; - return Combo(label, current_item, ImGuiGetNameFromIndexOldToNewCallback, &old_to_new_data, items_count, popup_max_height_in_items); + ImGuiGetNameFromIndexOldToNewCallbackData old_to_new_data = {user_data, old_getter}; + return Combo(label, current_item, ImGuiGetNameFromIndexOldToNewCallback, &old_to_new_data, items_count, + popup_max_height_in_items); } #endif @@ -2222,113 +2467,175 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*old_getter)(void* // - RoundScalarWithFormat<>() //------------------------------------------------------------------------- -static const ImGuiDataTypeInfo GDataTypeInfo[] = -{ - { sizeof(char), "S8", "%d", "%d" }, // ImGuiDataType_S8 - { sizeof(unsigned char), "U8", "%u", "%u" }, - { sizeof(short), "S16", "%d", "%d" }, // ImGuiDataType_S16 - { sizeof(unsigned short), "U16", "%u", "%u" }, - { sizeof(int), "S32", "%d", "%d" }, // ImGuiDataType_S32 - { sizeof(unsigned int), "U32", "%u", "%u" }, +static const ImGuiDataTypeInfo GDataTypeInfo[] = { + {sizeof(char), "S8", "%d", "%d"}, // ImGuiDataType_S8 + {sizeof(unsigned char), "U8", "%u", "%u"}, + {sizeof(short), "S16", "%d", "%d"}, // ImGuiDataType_S16 + {sizeof(unsigned short), "U16", "%u", "%u"}, + {sizeof(int), "S32", "%d", "%d"}, // ImGuiDataType_S32 + {sizeof(unsigned int), "U32", "%u", "%u"}, #ifdef _MSC_VER - { sizeof(ImS64), "S64", "%I64d","%I64d" }, // ImGuiDataType_S64 - { sizeof(ImU64), "U64", "%I64u","%I64u" }, + {sizeof(ImS64), "S64", "%I64d", "%I64d"}, // ImGuiDataType_S64 + {sizeof(ImU64), "U64", "%I64u", "%I64u"}, #else - { sizeof(ImS64), "S64", "%lld", "%lld" }, // ImGuiDataType_S64 - { sizeof(ImU64), "U64", "%llu", "%llu" }, + {sizeof(ImS64), "S64", "%lld", "%lld"}, // ImGuiDataType_S64 + {sizeof(ImU64), "U64", "%llu", "%llu"}, #endif - { sizeof(float), "float", "%.3f","%f" }, // ImGuiDataType_Float (float are promoted to double in va_arg) - { sizeof(double), "double","%f", "%lf" }, // ImGuiDataType_Double - { sizeof(bool), "bool", "%d", "%d" }, // ImGuiDataType_Bool - { 0, "char*","%s", "%s" }, // ImGuiDataType_String + {sizeof(float), "float", "%.3f", "%f"}, // ImGuiDataType_Float (float are promoted to double in va_arg) + {sizeof(double), "double", "%f", "%lf"}, // ImGuiDataType_Double + {sizeof(bool), "bool", "%d", "%d"}, // ImGuiDataType_Bool + {0, "char*", "%s", "%s"}, // ImGuiDataType_String }; IM_STATIC_ASSERT(IM_ARRAYSIZE(GDataTypeInfo) == ImGuiDataType_COUNT); -const ImGuiDataTypeInfo* ImGui::DataTypeGetInfo(ImGuiDataType data_type) +const ImGuiDataTypeInfo *ImGui::DataTypeGetInfo(ImGuiDataType data_type) { IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); return &GDataTypeInfo[data_type]; } -int ImGui::DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format) +int ImGui::DataTypeFormatString(char *buf, int buf_size, ImGuiDataType data_type, const void *p_data, + const char *format) { // Signedness doesn't matter when pushing integer arguments if (data_type == ImGuiDataType_S32 || data_type == ImGuiDataType_U32) - return ImFormatString(buf, buf_size, format, *(const ImU32*)p_data); + return ImFormatString(buf, buf_size, format, *(const ImU32 *)p_data); if (data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64) - return ImFormatString(buf, buf_size, format, *(const ImU64*)p_data); + return ImFormatString(buf, buf_size, format, *(const ImU64 *)p_data); if (data_type == ImGuiDataType_Float) - return ImFormatString(buf, buf_size, format, *(const float*)p_data); + return ImFormatString(buf, buf_size, format, *(const float *)p_data); if (data_type == ImGuiDataType_Double) - return ImFormatString(buf, buf_size, format, *(const double*)p_data); + return ImFormatString(buf, buf_size, format, *(const double *)p_data); if (data_type == ImGuiDataType_S8) - return ImFormatString(buf, buf_size, format, *(const ImS8*)p_data); + return ImFormatString(buf, buf_size, format, *(const ImS8 *)p_data); if (data_type == ImGuiDataType_U8) - return ImFormatString(buf, buf_size, format, *(const ImU8*)p_data); + return ImFormatString(buf, buf_size, format, *(const ImU8 *)p_data); if (data_type == ImGuiDataType_S16) - return ImFormatString(buf, buf_size, format, *(const ImS16*)p_data); + return ImFormatString(buf, buf_size, format, *(const ImS16 *)p_data); if (data_type == ImGuiDataType_U16) - return ImFormatString(buf, buf_size, format, *(const ImU16*)p_data); + return ImFormatString(buf, buf_size, format, *(const ImU16 *)p_data); IM_ASSERT(0); return 0; } -void ImGui::DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, const void* arg1, const void* arg2) +void ImGui::DataTypeApplyOp(ImGuiDataType data_type, int op, void *output, const void *arg1, const void *arg2) { IM_ASSERT(op == '+' || op == '-'); switch (data_type) { - case ImGuiDataType_S8: - if (op == '+') { *(ImS8*)output = ImAddClampOverflow(*(const ImS8*)arg1, *(const ImS8*)arg2, IM_S8_MIN, IM_S8_MAX); } - if (op == '-') { *(ImS8*)output = ImSubClampOverflow(*(const ImS8*)arg1, *(const ImS8*)arg2, IM_S8_MIN, IM_S8_MAX); } - return; - case ImGuiDataType_U8: - if (op == '+') { *(ImU8*)output = ImAddClampOverflow(*(const ImU8*)arg1, *(const ImU8*)arg2, IM_U8_MIN, IM_U8_MAX); } - if (op == '-') { *(ImU8*)output = ImSubClampOverflow(*(const ImU8*)arg1, *(const ImU8*)arg2, IM_U8_MIN, IM_U8_MAX); } - return; - case ImGuiDataType_S16: - if (op == '+') { *(ImS16*)output = ImAddClampOverflow(*(const ImS16*)arg1, *(const ImS16*)arg2, IM_S16_MIN, IM_S16_MAX); } - if (op == '-') { *(ImS16*)output = ImSubClampOverflow(*(const ImS16*)arg1, *(const ImS16*)arg2, IM_S16_MIN, IM_S16_MAX); } - return; - case ImGuiDataType_U16: - if (op == '+') { *(ImU16*)output = ImAddClampOverflow(*(const ImU16*)arg1, *(const ImU16*)arg2, IM_U16_MIN, IM_U16_MAX); } - if (op == '-') { *(ImU16*)output = ImSubClampOverflow(*(const ImU16*)arg1, *(const ImU16*)arg2, IM_U16_MIN, IM_U16_MAX); } - return; - case ImGuiDataType_S32: - if (op == '+') { *(ImS32*)output = ImAddClampOverflow(*(const ImS32*)arg1, *(const ImS32*)arg2, IM_S32_MIN, IM_S32_MAX); } - if (op == '-') { *(ImS32*)output = ImSubClampOverflow(*(const ImS32*)arg1, *(const ImS32*)arg2, IM_S32_MIN, IM_S32_MAX); } - return; - case ImGuiDataType_U32: - if (op == '+') { *(ImU32*)output = ImAddClampOverflow(*(const ImU32*)arg1, *(const ImU32*)arg2, IM_U32_MIN, IM_U32_MAX); } - if (op == '-') { *(ImU32*)output = ImSubClampOverflow(*(const ImU32*)arg1, *(const ImU32*)arg2, IM_U32_MIN, IM_U32_MAX); } - return; - case ImGuiDataType_S64: - if (op == '+') { *(ImS64*)output = ImAddClampOverflow(*(const ImS64*)arg1, *(const ImS64*)arg2, IM_S64_MIN, IM_S64_MAX); } - if (op == '-') { *(ImS64*)output = ImSubClampOverflow(*(const ImS64*)arg1, *(const ImS64*)arg2, IM_S64_MIN, IM_S64_MAX); } - return; - case ImGuiDataType_U64: - if (op == '+') { *(ImU64*)output = ImAddClampOverflow(*(const ImU64*)arg1, *(const ImU64*)arg2, IM_U64_MIN, IM_U64_MAX); } - if (op == '-') { *(ImU64*)output = ImSubClampOverflow(*(const ImU64*)arg1, *(const ImU64*)arg2, IM_U64_MIN, IM_U64_MAX); } - return; - case ImGuiDataType_Float: - if (op == '+') { *(float*)output = *(const float*)arg1 + *(const float*)arg2; } - if (op == '-') { *(float*)output = *(const float*)arg1 - *(const float*)arg2; } - return; - case ImGuiDataType_Double: - if (op == '+') { *(double*)output = *(const double*)arg1 + *(const double*)arg2; } - if (op == '-') { *(double*)output = *(const double*)arg1 - *(const double*)arg2; } - return; - case ImGuiDataType_COUNT: break; + case ImGuiDataType_S8: + if (op == '+') + { + *(ImS8 *)output = ImAddClampOverflow(*(const ImS8 *)arg1, *(const ImS8 *)arg2, IM_S8_MIN, IM_S8_MAX); + } + if (op == '-') + { + *(ImS8 *)output = ImSubClampOverflow(*(const ImS8 *)arg1, *(const ImS8 *)arg2, IM_S8_MIN, IM_S8_MAX); + } + return; + case ImGuiDataType_U8: + if (op == '+') + { + *(ImU8 *)output = ImAddClampOverflow(*(const ImU8 *)arg1, *(const ImU8 *)arg2, IM_U8_MIN, IM_U8_MAX); + } + if (op == '-') + { + *(ImU8 *)output = ImSubClampOverflow(*(const ImU8 *)arg1, *(const ImU8 *)arg2, IM_U8_MIN, IM_U8_MAX); + } + return; + case ImGuiDataType_S16: + if (op == '+') + { + *(ImS16 *)output = ImAddClampOverflow(*(const ImS16 *)arg1, *(const ImS16 *)arg2, IM_S16_MIN, IM_S16_MAX); + } + if (op == '-') + { + *(ImS16 *)output = ImSubClampOverflow(*(const ImS16 *)arg1, *(const ImS16 *)arg2, IM_S16_MIN, IM_S16_MAX); + } + return; + case ImGuiDataType_U16: + if (op == '+') + { + *(ImU16 *)output = ImAddClampOverflow(*(const ImU16 *)arg1, *(const ImU16 *)arg2, IM_U16_MIN, IM_U16_MAX); + } + if (op == '-') + { + *(ImU16 *)output = ImSubClampOverflow(*(const ImU16 *)arg1, *(const ImU16 *)arg2, IM_U16_MIN, IM_U16_MAX); + } + return; + case ImGuiDataType_S32: + if (op == '+') + { + *(ImS32 *)output = ImAddClampOverflow(*(const ImS32 *)arg1, *(const ImS32 *)arg2, IM_S32_MIN, IM_S32_MAX); + } + if (op == '-') + { + *(ImS32 *)output = ImSubClampOverflow(*(const ImS32 *)arg1, *(const ImS32 *)arg2, IM_S32_MIN, IM_S32_MAX); + } + return; + case ImGuiDataType_U32: + if (op == '+') + { + *(ImU32 *)output = ImAddClampOverflow(*(const ImU32 *)arg1, *(const ImU32 *)arg2, IM_U32_MIN, IM_U32_MAX); + } + if (op == '-') + { + *(ImU32 *)output = ImSubClampOverflow(*(const ImU32 *)arg1, *(const ImU32 *)arg2, IM_U32_MIN, IM_U32_MAX); + } + return; + case ImGuiDataType_S64: + if (op == '+') + { + *(ImS64 *)output = ImAddClampOverflow(*(const ImS64 *)arg1, *(const ImS64 *)arg2, IM_S64_MIN, IM_S64_MAX); + } + if (op == '-') + { + *(ImS64 *)output = ImSubClampOverflow(*(const ImS64 *)arg1, *(const ImS64 *)arg2, IM_S64_MIN, IM_S64_MAX); + } + return; + case ImGuiDataType_U64: + if (op == '+') + { + *(ImU64 *)output = ImAddClampOverflow(*(const ImU64 *)arg1, *(const ImU64 *)arg2, IM_U64_MIN, IM_U64_MAX); + } + if (op == '-') + { + *(ImU64 *)output = ImSubClampOverflow(*(const ImU64 *)arg1, *(const ImU64 *)arg2, IM_U64_MIN, IM_U64_MAX); + } + return; + case ImGuiDataType_Float: + if (op == '+') + { + *(float *)output = *(const float *)arg1 + *(const float *)arg2; + } + if (op == '-') + { + *(float *)output = *(const float *)arg1 - *(const float *)arg2; + } + return; + case ImGuiDataType_Double: + if (op == '+') + { + *(double *)output = *(const double *)arg1 + *(const double *)arg2; + } + if (op == '-') + { + *(double *)output = *(const double *)arg1 - *(const double *)arg2; + } + return; + case ImGuiDataType_COUNT: + break; } IM_ASSERT(0); } // User can input math operators (e.g. +100) to edit a numerical values. // NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess.. -bool ImGui::DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void* p_data, const char* format, void* p_data_when_empty) +bool ImGui::DataTypeApplyFromText(const char *buf, ImGuiDataType data_type, void *p_data, const char *format, + void *p_data_when_empty) { // Copy the value in an opaque buffer so we can compare at the end of the function if it changed at all. - const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type); + const ImGuiDataTypeInfo *type_info = DataTypeGetInfo(data_type); ImGuiDataTypeStorage data_backup; memcpy(&data_backup, p_data, type_info->Size); @@ -2345,8 +2652,10 @@ bool ImGui::DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void } // Sanitize format - // - For float/double we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in, so force them into %f and %lf - // - In theory could treat empty format as using default, but this would only cover rare/bizarre case of using InputScalar() + integer + format string without %. + // - For float/double we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in, so + // force them into %f and %lf + // - In theory could treat empty format as using default, but this would only cover rare/bizarre case of using + // InputScalar() + integer + format string without %. char format_sanitized[32]; if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) format = type_info->ScanFmt; @@ -2360,13 +2669,13 @@ bool ImGui::DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void if (type_info->Size < 4) { if (data_type == ImGuiDataType_S8) - *(ImS8*)p_data = (ImS8)ImClamp(v32, (int)IM_S8_MIN, (int)IM_S8_MAX); + *(ImS8 *)p_data = (ImS8)ImClamp(v32, (int)IM_S8_MIN, (int)IM_S8_MAX); else if (data_type == ImGuiDataType_U8) - *(ImU8*)p_data = (ImU8)ImClamp(v32, (int)IM_U8_MIN, (int)IM_U8_MAX); + *(ImU8 *)p_data = (ImU8)ImClamp(v32, (int)IM_U8_MIN, (int)IM_U8_MAX); else if (data_type == ImGuiDataType_S16) - *(ImS16*)p_data = (ImS16)ImClamp(v32, (int)IM_S16_MIN, (int)IM_S16_MAX); + *(ImS16 *)p_data = (ImS16)ImClamp(v32, (int)IM_S16_MIN, (int)IM_S16_MAX); else if (data_type == ImGuiDataType_U16) - *(ImU16*)p_data = (ImU16)ImClamp(v32, (int)IM_U16_MIN, (int)IM_U16_MAX); + *(ImU16 *)p_data = (ImU16)ImClamp(v32, (int)IM_U16_MIN, (int)IM_U16_MAX); else IM_ASSERT(0); } @@ -2374,83 +2683,114 @@ bool ImGui::DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void return memcmp(&data_backup, p_data, type_info->Size) != 0; } -template -static int DataTypeCompareT(const T* lhs, const T* rhs) +template static int DataTypeCompareT(const T *lhs, const T *rhs) { - if (*lhs < *rhs) return -1; - if (*lhs > *rhs) return +1; + if (*lhs < *rhs) + return -1; + if (*lhs > *rhs) + return +1; return 0; } -int ImGui::DataTypeCompare(ImGuiDataType data_type, const void* arg_1, const void* arg_2) +int ImGui::DataTypeCompare(ImGuiDataType data_type, const void *arg_1, const void *arg_2) { switch (data_type) { - case ImGuiDataType_S8: return DataTypeCompareT((const ImS8* )arg_1, (const ImS8* )arg_2); - case ImGuiDataType_U8: return DataTypeCompareT((const ImU8* )arg_1, (const ImU8* )arg_2); - case ImGuiDataType_S16: return DataTypeCompareT((const ImS16* )arg_1, (const ImS16* )arg_2); - case ImGuiDataType_U16: return DataTypeCompareT((const ImU16* )arg_1, (const ImU16* )arg_2); - case ImGuiDataType_S32: return DataTypeCompareT((const ImS32* )arg_1, (const ImS32* )arg_2); - case ImGuiDataType_U32: return DataTypeCompareT((const ImU32* )arg_1, (const ImU32* )arg_2); - case ImGuiDataType_S64: return DataTypeCompareT((const ImS64* )arg_1, (const ImS64* )arg_2); - case ImGuiDataType_U64: return DataTypeCompareT((const ImU64* )arg_1, (const ImU64* )arg_2); - case ImGuiDataType_Float: return DataTypeCompareT((const float* )arg_1, (const float* )arg_2); - case ImGuiDataType_Double: return DataTypeCompareT((const double*)arg_1, (const double*)arg_2); - case ImGuiDataType_COUNT: break; + case ImGuiDataType_S8: + return DataTypeCompareT((const ImS8 *)arg_1, (const ImS8 *)arg_2); + case ImGuiDataType_U8: + return DataTypeCompareT((const ImU8 *)arg_1, (const ImU8 *)arg_2); + case ImGuiDataType_S16: + return DataTypeCompareT((const ImS16 *)arg_1, (const ImS16 *)arg_2); + case ImGuiDataType_U16: + return DataTypeCompareT((const ImU16 *)arg_1, (const ImU16 *)arg_2); + case ImGuiDataType_S32: + return DataTypeCompareT((const ImS32 *)arg_1, (const ImS32 *)arg_2); + case ImGuiDataType_U32: + return DataTypeCompareT((const ImU32 *)arg_1, (const ImU32 *)arg_2); + case ImGuiDataType_S64: + return DataTypeCompareT((const ImS64 *)arg_1, (const ImS64 *)arg_2); + case ImGuiDataType_U64: + return DataTypeCompareT((const ImU64 *)arg_1, (const ImU64 *)arg_2); + case ImGuiDataType_Float: + return DataTypeCompareT((const float *)arg_1, (const float *)arg_2); + case ImGuiDataType_Double: + return DataTypeCompareT((const double *)arg_1, (const double *)arg_2); + case ImGuiDataType_COUNT: + break; } IM_ASSERT(0); return 0; } -template -static bool DataTypeClampT(T* v, const T* v_min, const T* v_max) +template static bool DataTypeClampT(T *v, const T *v_min, const T *v_max) { // Clamp, both sides are optional, return true if modified - if (v_min && *v < *v_min) { *v = *v_min; return true; } - if (v_max && *v > *v_max) { *v = *v_max; return true; } + if (v_min && *v < *v_min) + { + *v = *v_min; + return true; + } + if (v_max && *v > *v_max) + { + *v = *v_max; + return true; + } return false; } -bool ImGui::DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max) +bool ImGui::DataTypeClamp(ImGuiDataType data_type, void *p_data, const void *p_min, const void *p_max) { switch (data_type) { - case ImGuiDataType_S8: return DataTypeClampT((ImS8* )p_data, (const ImS8* )p_min, (const ImS8* )p_max); - case ImGuiDataType_U8: return DataTypeClampT((ImU8* )p_data, (const ImU8* )p_min, (const ImU8* )p_max); - case ImGuiDataType_S16: return DataTypeClampT((ImS16* )p_data, (const ImS16* )p_min, (const ImS16* )p_max); - case ImGuiDataType_U16: return DataTypeClampT((ImU16* )p_data, (const ImU16* )p_min, (const ImU16* )p_max); - case ImGuiDataType_S32: return DataTypeClampT((ImS32* )p_data, (const ImS32* )p_min, (const ImS32* )p_max); - case ImGuiDataType_U32: return DataTypeClampT((ImU32* )p_data, (const ImU32* )p_min, (const ImU32* )p_max); - case ImGuiDataType_S64: return DataTypeClampT((ImS64* )p_data, (const ImS64* )p_min, (const ImS64* )p_max); - case ImGuiDataType_U64: return DataTypeClampT((ImU64* )p_data, (const ImU64* )p_min, (const ImU64* )p_max); - case ImGuiDataType_Float: return DataTypeClampT((float* )p_data, (const float* )p_min, (const float* )p_max); - case ImGuiDataType_Double: return DataTypeClampT((double*)p_data, (const double*)p_min, (const double*)p_max); - case ImGuiDataType_COUNT: break; + case ImGuiDataType_S8: + return DataTypeClampT((ImS8 *)p_data, (const ImS8 *)p_min, (const ImS8 *)p_max); + case ImGuiDataType_U8: + return DataTypeClampT((ImU8 *)p_data, (const ImU8 *)p_min, (const ImU8 *)p_max); + case ImGuiDataType_S16: + return DataTypeClampT((ImS16 *)p_data, (const ImS16 *)p_min, (const ImS16 *)p_max); + case ImGuiDataType_U16: + return DataTypeClampT((ImU16 *)p_data, (const ImU16 *)p_min, (const ImU16 *)p_max); + case ImGuiDataType_S32: + return DataTypeClampT((ImS32 *)p_data, (const ImS32 *)p_min, (const ImS32 *)p_max); + case ImGuiDataType_U32: + return DataTypeClampT((ImU32 *)p_data, (const ImU32 *)p_min, (const ImU32 *)p_max); + case ImGuiDataType_S64: + return DataTypeClampT((ImS64 *)p_data, (const ImS64 *)p_min, (const ImS64 *)p_max); + case ImGuiDataType_U64: + return DataTypeClampT((ImU64 *)p_data, (const ImU64 *)p_min, (const ImU64 *)p_max); + case ImGuiDataType_Float: + return DataTypeClampT((float *)p_data, (const float *)p_min, (const float *)p_max); + case ImGuiDataType_Double: + return DataTypeClampT((double *)p_data, (const double *)p_min, (const double *)p_max); + case ImGuiDataType_COUNT: + break; } IM_ASSERT(0); return false; } -bool ImGui::DataTypeIsZero(ImGuiDataType data_type, const void* p_data) +bool ImGui::DataTypeIsZero(ImGuiDataType data_type, const void *p_data) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; return DataTypeCompare(data_type, p_data, &g.DataTypeZeroValue) == 0; } static float GetMinimumStepAtDecimalPrecision(int decimal_precision) { - static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f }; + static const float min_steps[10] = {1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, + 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f}; if (decimal_precision < 0) return FLT_MIN; - return (decimal_precision < IM_ARRAYSIZE(min_steps)) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision); + return (decimal_precision < IM_ARRAYSIZE(min_steps)) ? min_steps[decimal_precision] + : ImPow(10.0f, (float)-decimal_precision); } -template -TYPE ImGui::RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, TYPE v) +template TYPE ImGui::RoundScalarWithFormatT(const char *format, ImGuiDataType data_type, TYPE v) { IM_UNUSED(data_type); IM_ASSERT(data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double); - const char* fmt_start = ImParseFormatFindStart(format); + 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; @@ -2462,7 +2802,7 @@ TYPE ImGui::RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, // 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; + const char *p = v_str; while (*p == ' ') p++; v = (TYPE)ImAtof(p); @@ -2490,12 +2830,14 @@ TYPE ImGui::RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, //------------------------------------------------------------------------- // This is called by DragBehavior() when the widget is active (held by mouse or being manipulated with Nav controls) -template -bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, ImGuiSliderFlags flags) +template +bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE *v, float v_speed, const TYPE v_min, const TYPE v_max, + const char *format, ImGuiSliderFlags flags) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; - const bool is_bounded = (v_min < v_max) || ((v_min == v_max) && (v_min != 0.0f || (flags & ImGuiSliderFlags_ClampZeroRange))); + const bool is_bounded = + (v_min < v_max) || ((v_min == v_max) && (v_min != 0.0f || (flags & ImGuiSliderFlags_ClampZeroRange))); const bool is_wrapped = is_bounded && (flags & ImGuiSliderFlags_WrapAround); const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0; const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); @@ -2504,9 +2846,11 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const if (v_speed == 0.0f && is_bounded && (v_max - v_min < FLT_MAX)) v_speed = (float)((v_max - v_min) * g.DragSpeedDefaultRatio); - // Inputs accumulates into g.DragCurrentAccum, which is flushed into the current value as soon as it makes a difference with our precision settings + // Inputs accumulates into g.DragCurrentAccum, which is flushed into the current value as soon as it makes a + // difference with our precision settings float adjust_delta = 0.0f; - if (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid() && IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR)) + if (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid() && + IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR)) { adjust_delta = g.IO.MouseDelta[axis]; if (g.IO.KeyAlt && !(flags & ImGuiSliderFlags_NoSpeedTweaks)) @@ -2517,15 +2861,23 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) { const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0; - const bool tweak_slow = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow); - const bool tweak_fast = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast : ImGuiKey_NavKeyboardTweakFast); - const float tweak_factor = (flags & ImGuiSliderFlags_NoSpeedTweaks) ? 1.0f : tweak_slow ? 1.0f / 10.0f : tweak_fast ? 10.0f : 1.0f; + const bool tweak_slow = + IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow + : ImGuiKey_NavKeyboardTweakSlow); + const bool tweak_fast = + IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast + : ImGuiKey_NavKeyboardTweakFast); + const float tweak_factor = (flags & ImGuiSliderFlags_NoSpeedTweaks) ? 1.0f + : tweak_slow ? 1.0f / 10.0f + : tweak_fast ? 10.0f + : 1.0f; adjust_delta = GetNavTweakPressedAmount(axis) * tweak_factor; v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision)); } adjust_delta *= v_speed; - // For vertical drag we currently assume that Up=higher value (like we do with vertical sliders). This may become a parameter. + // For vertical drag we currently assume that Up=higher value (like we do with vertical sliders). This may become a + // parameter. if (axis == ImGuiAxis_Y) adjust_delta = -adjust_delta; @@ -2534,9 +2886,11 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const adjust_delta /= (float)(v_max - v_min); // Clear current value on activation - // Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300. + // Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so + // e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300. const bool is_just_activated = g.ActiveIdIsJustActivated; - const bool is_already_past_limits_and_pushing_outward = is_bounded && !is_wrapped && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f)); + const bool is_already_past_limits_and_pushing_outward = + is_bounded && !is_wrapped && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f)); if (is_just_activated || is_already_past_limits_and_pushing_outward) { g.DragCurrentAccum = 0.0f; @@ -2554,18 +2908,22 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_cur = *v; FLOATTYPE v_old_ref_for_accum_remainder = (FLOATTYPE)0.0f; - float logarithmic_zero_epsilon = 0.0f; // Only valid when is_logarithmic is true + float logarithmic_zero_epsilon = 0.0f; // Only valid when is_logarithmic is true const float zero_deadzone_halfsize = 0.0f; // Drag widgets have no deadzone (as it doesn't make sense) 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. + // 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_floating_point ? ImParseFormatPrecision(format, 3) : 1; logarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision); // Convert to parametric space, apply delta, convert back - float v_old_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float v_old_parametric = ScaleRatioFromValueT( + data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); float v_new_parametric = v_old_parametric + g.DragCurrentAccum; - v_cur = ScaleValueFromRatioT(data_type, v_new_parametric, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + v_cur = + ScaleValueFromRatioT(data_type, v_new_parametric, v_min, v_max, is_logarithmic, + logarithmic_zero_epsilon, zero_deadzone_halfsize); v_old_ref_for_accum_remainder = v_old_parametric; } else @@ -2582,7 +2940,8 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const if (is_logarithmic) { // Convert to parametric space, apply delta, convert back - float v_new_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float v_new_parametric = ScaleRatioFromValueT( + data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); g.DragCurrentAccum -= (float)(v_new_parametric - v_old_ref_for_accum_remainder); } else @@ -2621,18 +2980,22 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const return true; } -bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void *p_v, float v_speed, const void *p_min, + const void *p_max, const char *format, ImGuiSliderFlags flags) { // Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert. - IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flags! Has the legacy 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead."); + IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && + "Invalid ImGuiSliderFlags flags! Has the legacy 'float power' argument been mistakenly cast to flags? " + "Call function with ImGuiSliderFlags_Logarithmic flags instead."); - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; if (g.ActiveId == id) { // Those are the things we can do easily outside the DragBehaviorT<> template, saves code generation. if (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0]) ClearActiveID(); - else if ((g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) + else if ((g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) && + g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) ClearActiveID(); } if (g.ActiveId != id) @@ -2642,38 +3005,94 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v switch (data_type) { - case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS8*) p_min : IM_S8_MIN, p_max ? *(const ImS8*)p_max : IM_S8_MAX, format, flags); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } - case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU8*) p_min : IM_U8_MIN, p_max ? *(const ImU8*)p_max : IM_U8_MAX, format, flags); if (r) *(ImU8*)p_v = (ImU8)v32; return r; } - case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS16*)p_min : IM_S16_MIN, p_max ? *(const ImS16*)p_max : IM_S16_MAX, format, flags); if (r) *(ImS16*)p_v = (ImS16)v32; return r; } - case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU16*)p_min : IM_U16_MIN, p_max ? *(const ImU16*)p_max : IM_U16_MAX, format, flags); if (r) *(ImU16*)p_v = (ImU16)v32; return r; } - case ImGuiDataType_S32: return DragBehaviorT(data_type, (ImS32*)p_v, v_speed, p_min ? *(const ImS32* )p_min : IM_S32_MIN, p_max ? *(const ImS32* )p_max : IM_S32_MAX, format, flags); - case ImGuiDataType_U32: return DragBehaviorT(data_type, (ImU32*)p_v, v_speed, p_min ? *(const ImU32* )p_min : IM_U32_MIN, p_max ? *(const ImU32* )p_max : IM_U32_MAX, format, flags); - case ImGuiDataType_S64: return DragBehaviorT(data_type, (ImS64*)p_v, v_speed, p_min ? *(const ImS64* )p_min : IM_S64_MIN, p_max ? *(const ImS64* )p_max : IM_S64_MAX, format, flags); - case ImGuiDataType_U64: return DragBehaviorT(data_type, (ImU64*)p_v, v_speed, p_min ? *(const ImU64* )p_min : IM_U64_MIN, p_max ? *(const ImU64* )p_max : IM_U64_MAX, format, flags); - case ImGuiDataType_Float: return DragBehaviorT(data_type, (float*)p_v, v_speed, p_min ? *(const float* )p_min : -FLT_MAX, p_max ? *(const float* )p_max : FLT_MAX, format, flags); - case ImGuiDataType_Double: return DragBehaviorT(data_type, (double*)p_v, v_speed, p_min ? *(const double*)p_min : -DBL_MAX, p_max ? *(const double*)p_max : DBL_MAX, format, flags); - case ImGuiDataType_COUNT: break; + case ImGuiDataType_S8: { + ImS32 v32 = (ImS32) * (ImS8 *)p_v; + bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, + p_min ? *(const ImS8 *)p_min : IM_S8_MIN, + p_max ? *(const ImS8 *)p_max : IM_S8_MAX, format, flags); + if (r) + *(ImS8 *)p_v = (ImS8)v32; + return r; + } + case ImGuiDataType_U8: { + ImU32 v32 = (ImU32) * (ImU8 *)p_v; + bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, + p_min ? *(const ImU8 *)p_min : IM_U8_MIN, + p_max ? *(const ImU8 *)p_max : IM_U8_MAX, format, flags); + if (r) + *(ImU8 *)p_v = (ImU8)v32; + return r; + } + case ImGuiDataType_S16: { + ImS32 v32 = (ImS32) * (ImS16 *)p_v; + bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, + p_min ? *(const ImS16 *)p_min : IM_S16_MIN, + p_max ? *(const ImS16 *)p_max : IM_S16_MAX, format, flags); + if (r) + *(ImS16 *)p_v = (ImS16)v32; + return r; + } + case ImGuiDataType_U16: { + ImU32 v32 = (ImU32) * (ImU16 *)p_v; + bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, + p_min ? *(const ImU16 *)p_min : IM_U16_MIN, + p_max ? *(const ImU16 *)p_max : IM_U16_MAX, format, flags); + if (r) + *(ImU16 *)p_v = (ImU16)v32; + return r; + } + case ImGuiDataType_S32: + return DragBehaviorT(data_type, (ImS32 *)p_v, v_speed, + p_min ? *(const ImS32 *)p_min : IM_S32_MIN, + p_max ? *(const ImS32 *)p_max : IM_S32_MAX, format, flags); + case ImGuiDataType_U32: + return DragBehaviorT(data_type, (ImU32 *)p_v, v_speed, + p_min ? *(const ImU32 *)p_min : IM_U32_MIN, + p_max ? *(const ImU32 *)p_max : IM_U32_MAX, format, flags); + case ImGuiDataType_S64: + return DragBehaviorT(data_type, (ImS64 *)p_v, v_speed, + p_min ? *(const ImS64 *)p_min : IM_S64_MIN, + p_max ? *(const ImS64 *)p_max : IM_S64_MAX, format, flags); + case ImGuiDataType_U64: + return DragBehaviorT(data_type, (ImU64 *)p_v, v_speed, + p_min ? *(const ImU64 *)p_min : IM_U64_MIN, + p_max ? *(const ImU64 *)p_max : IM_U64_MAX, format, flags); + case ImGuiDataType_Float: + return DragBehaviorT(data_type, (float *)p_v, v_speed, + p_min ? *(const float *)p_min : -FLT_MAX, + p_max ? *(const float *)p_max : FLT_MAX, format, flags); + case ImGuiDataType_Double: + return DragBehaviorT(data_type, (double *)p_v, v_speed, + p_min ? *(const double *)p_min : -DBL_MAX, + p_max ? *(const double *)p_max : DBL_MAX, format, flags); + case ImGuiDataType_COUNT: + break; } IM_ASSERT(0); return false; } -// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a Drag widget, p_min and p_max are optional. -// Read code of e.g. DragFloat(), DragInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. -bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) +// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a Drag widget, p_min and p_max +// are optional. Read code of e.g. DragFloat(), DragInt() etc. or examples in 'Demo->Widgets->Data Types' to understand +// how to use this function directly. +bool ImGui::DragScalar(const char *label, ImGuiDataType data_type, void *p_data, float v_speed, const void *p_min, + const void *p_max, const char *format, ImGuiSliderFlags flags) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; + ImGuiContext &g = *GImGui; + 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 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); @@ -2695,12 +3114,14 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, if (make_active && (clicked || double_clicked)) SetKeyOwner(ImGuiKey_MouseLeft, id); if (make_active && temp_input_allowed) - if ((clicked && g.IO.KeyCtrl) || double_clicked || (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput))) + if ((clicked && g.IO.KeyCtrl) || double_clicked || + (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput))) temp_input_is_active = true; // (Optional) simple click (without moving) turns Drag into an InputText if (g.IO.ConfigDragClickToInputText && temp_input_allowed && !temp_input_is_active) - if (g.ActiveId == id && hovered && g.IO.MouseReleased[0] && !IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR)) + if (g.ActiveId == id && hovered && g.IO.MouseReleased[0] && + !IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR)) { g.NavActivateId = id; g.NavActivateFlags = ImGuiActivateFlags_PreferInput; @@ -2722,21 +3143,28 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, if (temp_input_is_active) { - // Only clamp CTRL+Click input when ImGuiSliderFlags_ClampOnInput is set (generally via ImGuiSliderFlags_AlwaysClamp) + // Only clamp CTRL+Click input when ImGuiSliderFlags_ClampOnInput is set (generally via + // ImGuiSliderFlags_AlwaysClamp) bool clamp_enabled = false; if ((flags & ImGuiSliderFlags_ClampOnInput) && (p_min != NULL || p_max != NULL)) { - const int clamp_range_dir = (p_min != NULL && p_max != NULL) ? DataTypeCompare(data_type, p_min, p_max) : 0; // -1 when *p_min < *p_max, == 0 when *p_min == *p_max + const int clamp_range_dir = (p_min != NULL && p_max != NULL) + ? DataTypeCompare(data_type, p_min, p_max) + : 0; // -1 when *p_min < *p_max, == 0 when *p_min == *p_max if (p_min == NULL || p_max == NULL || clamp_range_dir < 0) clamp_enabled = true; else if (clamp_range_dir == 0) - clamp_enabled = DataTypeIsZero(data_type, p_min) ? ((flags & ImGuiSliderFlags_ClampZeroRange) != 0) : true; + clamp_enabled = + DataTypeIsZero(data_type, p_min) ? ((flags & ImGuiSliderFlags_ClampZeroRange) != 0) : true; } - return TempInputScalar(frame_bb, id, label, data_type, p_data, format, clamp_enabled ? p_min : NULL, clamp_enabled ? p_max : NULL); + return TempInputScalar(frame_bb, id, label, data_type, p_data, format, clamp_enabled ? p_min : NULL, + clamp_enabled ? p_max : NULL); } // Draw frame - const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive + : hovered ? ImGuiCol_FrameBgHovered + : ImGuiCol_FrameBg); RenderNavCursor(frame_bb, id); RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding); @@ -2747,7 +3175,8 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; - const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + const char *value_buf_end = + value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); if (g.LogEnabled) LogSetNextTextDecoration("{", "}"); RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); @@ -2755,17 +3184,19 @@ 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, g.LastItemData.StatusFlags | (temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, + g.LastItemData.StatusFlags | (temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0)); return value_changed; } -bool ImGui::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, ImGuiSliderFlags flags) +bool ImGui::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, ImGuiSliderFlags flags) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; bool value_changed = false; BeginGroup(); PushID(label); @@ -2779,11 +3210,11 @@ bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data value_changed |= DragScalar("", data_type, p_data, v_speed, p_min, p_max, format, flags); PopID(); PopItemWidth(); - p_data = (void*)((char*)p_data + type_size); + p_data = (void *)((char *)p_data + type_size); } PopID(); - const char* label_end = FindRenderedTextEnd(label); + const char *label_end = FindRenderedTextEnd(label); if (label != label_end) { SameLine(0, g.Style.ItemInnerSpacing.x); @@ -2794,34 +3225,39 @@ bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data return value_changed; } -bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::DragFloat(const char *label, float *v, float v_speed, float v_min, float v_max, const char *format, + ImGuiSliderFlags flags) { return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, flags); } -bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::DragFloat2(const char *label, float v[2], float v_speed, float v_min, float v_max, const char *format, + ImGuiSliderFlags flags) { return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, flags); } -bool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::DragFloat3(const char *label, float v[3], float v_speed, float v_min, float v_max, const char *format, + ImGuiSliderFlags flags) { return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, flags); } -bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::DragFloat4(const char *label, float v[4], float v_speed, float v_min, float v_max, const char *format, + ImGuiSliderFlags flags) { return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, flags); } // NB: You likely want to specify the ImGuiSliderFlags_AlwaysClamp when using this. -bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, ImGuiSliderFlags flags) +bool ImGui::DragFloatRange2(const char *label, float *v_current_min, float *v_current_max, float v_speed, float v_min, + float v_max, const char *format, const char *format_max, ImGuiSliderFlags flags) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; PushID(label); BeginGroup(); PushMultiItemsWidths(2, CalcItemWidth()); @@ -2829,14 +3265,16 @@ bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_cu float min_min = (v_min >= v_max) ? -FLT_MAX : v_min; float min_max = (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max); ImGuiSliderFlags min_flags = flags | ((min_min == min_max) ? ImGuiSliderFlags_ReadOnly : 0); - bool value_changed = DragScalar("##min", ImGuiDataType_Float, v_current_min, v_speed, &min_min, &min_max, format, min_flags); + bool value_changed = + DragScalar("##min", ImGuiDataType_Float, v_current_min, v_speed, &min_min, &min_max, format, min_flags); PopItemWidth(); SameLine(0, g.Style.ItemInnerSpacing.x); float max_min = (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min); float max_max = (v_min >= v_max) ? FLT_MAX : v_max; ImGuiSliderFlags max_flags = flags | ((max_min == max_max) ? ImGuiSliderFlags_ReadOnly : 0); - value_changed |= DragScalar("##max", ImGuiDataType_Float, v_current_max, v_speed, &max_min, &max_max, format_max ? format_max : format, max_flags); + value_changed |= DragScalar("##max", ImGuiDataType_Float, v_current_max, v_speed, &max_min, &max_max, + format_max ? format_max : format, max_flags); PopItemWidth(); SameLine(0, g.Style.ItemInnerSpacing.x); @@ -2848,34 +3286,39 @@ bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_cu } // NB: v_speed is float to allow adjusting the drag speed with more precision -bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::DragInt(const char *label, int *v, float v_speed, int v_min, int v_max, const char *format, + ImGuiSliderFlags flags) { return DragScalar(label, ImGuiDataType_S32, v, v_speed, &v_min, &v_max, format, flags); } -bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::DragInt2(const char *label, int v[2], float v_speed, int v_min, int v_max, const char *format, + ImGuiSliderFlags flags) { return DragScalarN(label, ImGuiDataType_S32, v, 2, v_speed, &v_min, &v_max, format, flags); } -bool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::DragInt3(const char *label, int v[3], float v_speed, int v_min, int v_max, const char *format, + ImGuiSliderFlags flags) { return DragScalarN(label, ImGuiDataType_S32, v, 3, v_speed, &v_min, &v_max, format, flags); } -bool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::DragInt4(const char *label, int v[4], float v_speed, int v_min, int v_max, const char *format, + ImGuiSliderFlags flags) { return DragScalarN(label, ImGuiDataType_S32, v, 4, v_speed, &v_min, &v_max, format, flags); } // NB: You likely want to specify the ImGuiSliderFlags_AlwaysClamp when using this. -bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed, int v_min, int v_max, const char* format, const char* format_max, ImGuiSliderFlags flags) +bool ImGui::DragIntRange2(const char *label, int *v_current_min, int *v_current_max, float v_speed, int v_min, + int v_max, const char *format, const char *format_max, ImGuiSliderFlags flags) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; PushID(label); BeginGroup(); PushMultiItemsWidths(2, CalcItemWidth()); @@ -2890,7 +3333,8 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_ int max_min = (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min); int max_max = (v_min >= v_max) ? INT_MAX : v_max; ImGuiSliderFlags max_flags = flags | ((max_min == max_max) ? ImGuiSliderFlags_ReadOnly : 0); - value_changed |= DragInt("##max", v_current_max, v_speed, max_min, max_max, format_max ? format_max : format, max_flags); + value_changed |= + DragInt("##max", v_current_max, v_speed, max_min, max_max, format_max ? format_max : format, max_flags); PopItemWidth(); SameLine(0, g.Style.ItemInnerSpacing.x); @@ -2924,9 +3368,11 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_ // - VSliderInt() //------------------------------------------------------------------------- -// Convert a value v in the output space of a slider into a parametric position on the slider itself (the logical opposite of ScaleValueFromRatioT) -template -float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) +// Convert a value v in the output space of a slider into a parametric position on the slider itself (the logical +// opposite of ScaleValueFromRatioT) +template +float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, bool is_logarithmic, + float logarithmic_zero_epsilon, float zero_deadzone_halfsize) { if (v_min == v_max) return 0.0f; @@ -2941,10 +3387,15 @@ float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, T ImSwap(v_min, v_max); // Fudge min/max to avoid getting close to log(0) - FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min; - FLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_max; + FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) + ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) + : (FLOATTYPE)v_min; + FLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) + ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) + : (FLOATTYPE)v_max; - // Awkward special cases - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. epsilon) + // Awkward special cases - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. + // epsilon) if ((v_min == 0.0f) && (v_max < 0.0f)) v_min_fudged = -logarithmic_zero_epsilon; else if ((v_max == 0.0f) && (v_min < 0.0f)) @@ -2954,21 +3405,31 @@ float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, T if (v_clamped <= v_min_fudged) result = 0.0f; // Workaround for values that are in-range but below our fudge else if (v_clamped >= v_max_fudged) - result = 1.0f; // Workaround for values that are in-range but above our fudge + result = 1.0f; // Workaround for values that are in-range but above our fudge else if ((v_min * v_max) < 0.0f) // Range crosses zero, so split into two portions { - float zero_point_center = (-(float)v_min) / ((float)v_max - (float)v_min); // The zero point in parametric space. There's an argument we should take the logarithmic nature into account when calculating this, but for now this should do (and the most common case of a symmetrical range works fine) + float zero_point_center = + (-(float)v_min) / + ((float)v_max - + (float)v_min); // The zero point in parametric space. There's an argument we should take the + // logarithmic nature into account when calculating this, but for now this should do + // (and the most common case of a symmetrical range works fine) float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize; float zero_point_snap_R = zero_point_center + zero_deadzone_halfsize; if (v == 0.0f) result = zero_point_center; // Special case for exactly zero else if (v < 0.0f) - result = (1.0f - (float)(ImLog(-(FLOATTYPE)v_clamped / logarithmic_zero_epsilon) / ImLog(-v_min_fudged / logarithmic_zero_epsilon))) * zero_point_snap_L; + result = (1.0f - (float)(ImLog(-(FLOATTYPE)v_clamped / logarithmic_zero_epsilon) / + ImLog(-v_min_fudged / logarithmic_zero_epsilon))) * + zero_point_snap_L; else - result = zero_point_snap_R + ((float)(ImLog((FLOATTYPE)v_clamped / logarithmic_zero_epsilon) / ImLog(v_max_fudged / logarithmic_zero_epsilon)) * (1.0f - zero_point_snap_R)); + result = zero_point_snap_R + ((float)(ImLog((FLOATTYPE)v_clamped / logarithmic_zero_epsilon) / + ImLog(v_max_fudged / logarithmic_zero_epsilon)) * + (1.0f - zero_point_snap_R)); } else if ((v_min < 0.0f) || (v_max < 0.0f)) // Entirely negative slider - result = 1.0f - (float)(ImLog(-(FLOATTYPE)v_clamped / -v_max_fudged) / ImLog(-v_min_fudged / -v_max_fudged)); + result = + 1.0f - (float)(ImLog(-(FLOATTYPE)v_clamped / -v_max_fudged) / ImLog(-v_min_fudged / -v_max_fudged)); else result = (float)(ImLog((FLOATTYPE)v_clamped / v_min_fudged) / ImLog(v_max_fudged / v_min_fudged)); @@ -2981,12 +3442,15 @@ float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, T } } -// Convert a parametric position on a slider into a value v in the output space (the logical opposite of ScaleRatioFromValueT) -template -TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) +// Convert a parametric position on a slider into a value v in the output space (the logical opposite of +// ScaleRatioFromValueT) +template +TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, bool is_logarithmic, + float logarithmic_zero_epsilon, float zero_deadzone_halfsize) { // We special-case the extents because otherwise our logarithmic fudging can lead to "mathematically correct" - // but non-intuitive behaviors like a fully-left slider not actually reaching the minimum value. Also generally simpler. + // but non-intuitive behaviors like a fully-left slider not actually reaching the minimum value. Also generally + // simpler. if (t <= 0.0f || v_min == v_max) return v_min; if (t >= 1.0f) @@ -2996,33 +3460,45 @@ TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, T if (is_logarithmic) { // Fudge min/max to avoid getting silly results close to zero - FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min; - FLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_max; + FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) + ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) + : (FLOATTYPE)v_min; + FLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) + ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) + : (FLOATTYPE)v_max; const bool flipped = v_max < v_min; // Check if range is "backwards" if (flipped) ImSwap(v_min_fudged, v_max_fudged); - // Awkward special case - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. epsilon) + // Awkward special case - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. + // epsilon) if ((v_max == 0.0f) && (v_min < 0.0f)) v_max_fudged = -logarithmic_zero_epsilon; - float t_with_flip = flipped ? (1.0f - t) : t; // t, but flipped if necessary to account for us flipping the range + float t_with_flip = + flipped ? (1.0f - t) : t; // t, but flipped if necessary to account for us flipping the range if ((v_min * v_max) < 0.0f) // Range crosses zero, so we have to do this in two parts { - float zero_point_center = (-(float)ImMin(v_min, v_max)) / ImAbs((float)v_max - (float)v_min); // The zero point in parametric space + float zero_point_center = (-(float)ImMin(v_min, v_max)) / + ImAbs((float)v_max - (float)v_min); // The zero point in parametric space float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize; float zero_point_snap_R = zero_point_center + zero_deadzone_halfsize; if (t_with_flip >= zero_point_snap_L && t_with_flip <= zero_point_snap_R) - result = (TYPE)0.0f; // Special case to make getting exactly zero possible (the epsilon prevents it otherwise) + result = (TYPE)0.0f; // Special case to make getting exactly zero possible (the epsilon prevents it + // otherwise) else if (t_with_flip < zero_point_center) - result = (TYPE)-(logarithmic_zero_epsilon * ImPow(-v_min_fudged / logarithmic_zero_epsilon, (FLOATTYPE)(1.0f - (t_with_flip / zero_point_snap_L)))); + result = + (TYPE) - (logarithmic_zero_epsilon * ImPow(-v_min_fudged / logarithmic_zero_epsilon, + (FLOATTYPE)(1.0f - (t_with_flip / zero_point_snap_L)))); else - result = (TYPE)(logarithmic_zero_epsilon * ImPow(v_max_fudged / logarithmic_zero_epsilon, (FLOATTYPE)((t_with_flip - zero_point_snap_R) / (1.0f - zero_point_snap_R)))); + result = (TYPE)(logarithmic_zero_epsilon * + ImPow(v_max_fudged / logarithmic_zero_epsilon, + (FLOATTYPE)((t_with_flip - zero_point_snap_R) / (1.0f - zero_point_snap_R)))); } else if ((v_min < 0.0f) || (v_max < 0.0f)) // Entirely negative slider - result = (TYPE)-(-v_max_fudged * ImPow(-v_min_fudged / -v_max_fudged, (FLOATTYPE)(1.0f - t_with_flip))); + result = (TYPE) - (-v_max_fudged * ImPow(-v_min_fudged / -v_max_fudged, (FLOATTYPE)(1.0f - t_with_flip))); else result = (TYPE)(v_min_fudged * ImPow(v_max_fudged / v_min_fudged, (FLOATTYPE)t_with_flip)); } @@ -3037,9 +3513,12 @@ TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, T else if (t < 1.0) { // - For integer values we want the clicking position to match the grab box so we round above - // This code is carefully tuned to work with large values (e.g. high ranges of U64) while preserving this property.. - // - Not doing a *1.0 multiply at the end of a range as it tends to be lossy. While absolute aiming at a large s64/u64 - // range is going to be imprecise anyway, with this check we at least make the edge values matches expected limits. + // This code is carefully tuned to work with large values (e.g. high ranges of U64) while preserving this + // property.. + // - Not doing a *1.0 multiply at the end of a range as it tends to be lossy. While absolute aiming at a + // large s64/u64 + // range is going to be imprecise anyway, with this check we at least make the edge values matches + // expected limits. FLOATTYPE v_new_off_f = (SIGNEDTYPE)(v_max - v_min) * t; result = (TYPE)((SIGNEDTYPE)v_min + (SIGNEDTYPE)(v_new_off_f + (FLOATTYPE)(v_min > v_max ? -0.5 : 0.5))); } @@ -3049,33 +3528,37 @@ TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, T } // FIXME: Try to move more of the code into shared SliderBehavior() -template -bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb) +template +bool ImGui::SliderBehaviorT(const ImRect &bb, ImGuiID id, ImGuiDataType data_type, TYPE *v, const TYPE v_min, + const TYPE v_max, const char *format, ImGuiSliderFlags flags, ImRect *out_grab_bb) { - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; + ImGuiContext &g = *GImGui; + const ImGuiStyle &style = g.Style; const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0; const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); - const float v_range_f = (float)(v_min < v_max ? v_max - v_min : v_min - v_max); // We don't need high precision for what we do with it. + const float v_range_f = + (float)(v_min < v_max ? v_max - v_min : v_min - v_max); // We don't need high precision for what we do with it. // Calculate bounds const float grab_padding = 2.0f; // FIXME: Should be part of style. const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f; float grab_sz = style.GrabMinSize; - if (!is_floating_point && v_range_f >= 0.0f) // v_range_f < 0 may happen on integer overflows - grab_sz = ImMax(slider_sz / (v_range_f + 1), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit + if (!is_floating_point && v_range_f >= 0.0f) // v_range_f < 0 may happen on integer overflows + grab_sz = ImMax(slider_sz / (v_range_f + 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; const float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz * 0.5f; const float slider_usable_pos_max = bb.Max[axis] - grab_padding - grab_sz * 0.5f; float logarithmic_zero_epsilon = 0.0f; // Only valid when is_logarithmic is true - float zero_deadzone_halfsize = 0.0f; // Only valid when is_logarithmic is true + float zero_deadzone_halfsize = 0.0f; // Only valid when is_logarithmic is true 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. + // 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_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); @@ -3098,15 +3581,20 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ const float mouse_abs_pos = g.IO.MousePos[axis]; if (g.ActiveIdIsJustActivated) { - float grab_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float grab_t = ScaleRatioFromValueT( + data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); if (axis == ImGuiAxis_Y) grab_t = 1.0f - grab_t; const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); - const bool clicked_around_grab = (mouse_abs_pos >= grab_pos - grab_sz * 0.5f - 1.0f) && (mouse_abs_pos <= grab_pos + grab_sz * 0.5f + 1.0f); // No harm being extra generous here. - g.SliderGrabClickOffset = (clicked_around_grab && is_floating_point) ? mouse_abs_pos - grab_pos : 0.0f; + const bool clicked_around_grab = + (mouse_abs_pos >= grab_pos - grab_sz * 0.5f - 1.0f) && + (mouse_abs_pos <= grab_pos + grab_sz * 0.5f + 1.0f); // No harm being extra generous here. + g.SliderGrabClickOffset = + (clicked_around_grab && is_floating_point) ? mouse_abs_pos - grab_pos : 0.0f; } if (slider_usable_sz > 0.0f) - clicked_t = ImSaturate((mouse_abs_pos - g.SliderGrabClickOffset - slider_usable_pos_min) / slider_usable_sz); + clicked_t = ImSaturate((mouse_abs_pos - g.SliderGrabClickOffset - slider_usable_pos_min) / + slider_usable_sz); if (axis == ImGuiAxis_Y) clicked_t = 1.0f - clicked_t; set_new_value = true; @@ -3120,11 +3608,16 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ g.SliderCurrentAccumDirty = false; } - float input_delta = (axis == ImGuiAxis_X) ? GetNavTweakPressedAmount(axis) : -GetNavTweakPressedAmount(axis); + float input_delta = + (axis == ImGuiAxis_X) ? GetNavTweakPressedAmount(axis) : -GetNavTweakPressedAmount(axis); if (input_delta != 0.0f) { - const bool tweak_slow = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow); - const bool tweak_fast = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast : ImGuiKey_NavKeyboardTweakFast); + const bool tweak_slow = + IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow + : ImGuiKey_NavKeyboardTweakSlow); + const bool tweak_fast = + IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast + : ImGuiKey_NavKeyboardTweakFast); const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0; if (decimal_precision > 0) { @@ -3135,7 +3628,8 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ else { if ((v_range_f >= -100.0f && v_range_f <= 100.0f && v_range_f != 0.0f) || tweak_slow) - input_delta = ((input_delta < 0.0f) ? -1.0f : +1.0f) / v_range_f; // Keyboard/Gamepad tweak speeds in integer steps + input_delta = ((input_delta < 0.0f) ? -1.0f : +1.0f) / + v_range_f; // Keyboard/Gamepad tweak speeds in integer steps else input_delta /= 100.0f; } @@ -3153,9 +3647,12 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ } else if (g.SliderCurrentAccumDirty) { - clicked_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + clicked_t = ScaleRatioFromValueT( + data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); - if ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f)) // This is to avoid applying the saturation when already past the limits + if ((clicked_t >= 1.0f && delta > 0.0f) || + (clicked_t <= 0.0f && + delta < 0.0f)) // This is to avoid applying the saturation when already past the limits { set_new_value = false; g.SliderCurrentAccum = 0.0f; // If pushing up against the limits, don't continue to accumulate @@ -3166,11 +3663,16 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ float old_clicked_t = clicked_t; clicked_t = ImSaturate(clicked_t + delta); - // Calculate what our "new" clicked_t will be, and thus how far we actually moved the slider, and subtract this from the accumulator - TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + // Calculate what our "new" clicked_t will be, and thus how far we actually moved the slider, and + // subtract this from the accumulator + TYPE v_new = ScaleValueFromRatioT( + data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, + zero_deadzone_halfsize); if (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat)) v_new = RoundScalarWithFormatT(format, data_type, v_new); - float new_clicked_t = ScaleRatioFromValueT(data_type, v_new, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float new_clicked_t = ScaleRatioFromValueT( + data_type, v_new, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, + zero_deadzone_halfsize); if (delta > 0) g.SliderCurrentAccum -= ImMin(new_clicked_t - old_clicked_t, delta); @@ -3188,7 +3690,8 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ if (set_new_value) { - TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + TYPE v_new = ScaleValueFromRatioT( + data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); // Round to user desired precision based on format string if (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat)) @@ -3210,74 +3713,121 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ else { // Output grab position so it can be displayed by the caller - float grab_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float grab_t = ScaleRatioFromValueT( + data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); if (axis == ImGuiAxis_Y) grab_t = 1.0f - grab_t; const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); if (axis == ImGuiAxis_X) - *out_grab_bb = ImRect(grab_pos - grab_sz * 0.5f, bb.Min.y + grab_padding, grab_pos + grab_sz * 0.5f, bb.Max.y - grab_padding); + *out_grab_bb = ImRect(grab_pos - grab_sz * 0.5f, bb.Min.y + grab_padding, grab_pos + grab_sz * 0.5f, + bb.Max.y - grab_padding); else - *out_grab_bb = ImRect(bb.Min.x + grab_padding, grab_pos - grab_sz * 0.5f, bb.Max.x - grab_padding, grab_pos + grab_sz * 0.5f); + *out_grab_bb = ImRect(bb.Min.x + grab_padding, grab_pos - grab_sz * 0.5f, bb.Max.x - grab_padding, + grab_pos + grab_sz * 0.5f); } return value_changed; } // For 32-bit and larger types, slider bounds are limited to half the natural type range. -// So e.g. an integer Slider between INT_MAX-10 and INT_MAX will fail, but an integer Slider between INT_MAX/2-10 and INT_MAX/2 will be ok. -// It would be possible to lift that limitation with some work but it doesn't seem to be worth it for sliders. -bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb) +// So e.g. an integer Slider between INT_MAX-10 and INT_MAX will fail, but an integer Slider between INT_MAX/2-10 and +// INT_MAX/2 will be ok. It would be possible to lift that limitation with some work but it doesn't seem to be worth it +// for sliders. +bool ImGui::SliderBehavior(const ImRect &bb, ImGuiID id, ImGuiDataType data_type, void *p_v, const void *p_min, + const void *p_max, const char *format, ImGuiSliderFlags flags, ImRect *out_grab_bb) { // Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert. - IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flags! Has the legacy 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead."); + IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && + "Invalid ImGuiSliderFlags flags! Has the legacy 'float power' argument been mistakenly cast to flags? " + "Call function with ImGuiSliderFlags_Logarithmic flags instead."); IM_ASSERT((flags & ImGuiSliderFlags_WrapAround) == 0); // Not supported by SliderXXX(), only by DragXXX() switch (data_type) { - case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)p_min, *(const ImS8*)p_max, format, flags, out_grab_bb); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } - case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU8*)p_min, *(const ImU8*)p_max, format, flags, out_grab_bb); if (r) *(ImU8*)p_v = (ImU8)v32; return r; } - case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS16*)p_min, *(const ImS16*)p_max, format, flags, out_grab_bb); if (r) *(ImS16*)p_v = (ImS16)v32; return r; } - case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU16*)p_min, *(const ImU16*)p_max, format, flags, out_grab_bb); if (r) *(ImU16*)p_v = (ImU16)v32; return r; } + case ImGuiDataType_S8: { + ImS32 v32 = (ImS32) * (ImS8 *)p_v; + bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS8 *)p_min, + *(const ImS8 *)p_max, format, flags, out_grab_bb); + if (r) + *(ImS8 *)p_v = (ImS8)v32; + return r; + } + case ImGuiDataType_U8: { + ImU32 v32 = (ImU32) * (ImU8 *)p_v; + bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU8 *)p_min, + *(const ImU8 *)p_max, format, flags, out_grab_bb); + if (r) + *(ImU8 *)p_v = (ImU8)v32; + return r; + } + case ImGuiDataType_S16: { + ImS32 v32 = (ImS32) * (ImS16 *)p_v; + bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS16 *)p_min, + *(const ImS16 *)p_max, format, flags, out_grab_bb); + if (r) + *(ImS16 *)p_v = (ImS16)v32; + return r; + } + case ImGuiDataType_U16: { + ImU32 v32 = (ImU32) * (ImU16 *)p_v; + bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU16 *)p_min, + *(const ImU16 *)p_max, format, flags, out_grab_bb); + if (r) + *(ImU16 *)p_v = (ImU16)v32; + return r; + } case ImGuiDataType_S32: - IM_ASSERT(*(const ImS32*)p_min >= IM_S32_MIN / 2 && *(const ImS32*)p_max <= IM_S32_MAX / 2); - return SliderBehaviorT(bb, id, data_type, (ImS32*)p_v, *(const ImS32*)p_min, *(const ImS32*)p_max, format, flags, out_grab_bb); + IM_ASSERT(*(const ImS32 *)p_min >= IM_S32_MIN / 2 && *(const ImS32 *)p_max <= IM_S32_MAX / 2); + return SliderBehaviorT(bb, id, data_type, (ImS32 *)p_v, *(const ImS32 *)p_min, + *(const ImS32 *)p_max, format, flags, out_grab_bb); case ImGuiDataType_U32: - IM_ASSERT(*(const ImU32*)p_max <= IM_U32_MAX / 2); - return SliderBehaviorT(bb, id, data_type, (ImU32*)p_v, *(const ImU32*)p_min, *(const ImU32*)p_max, format, flags, out_grab_bb); + IM_ASSERT(*(const ImU32 *)p_max <= IM_U32_MAX / 2); + return SliderBehaviorT(bb, id, data_type, (ImU32 *)p_v, *(const ImU32 *)p_min, + *(const ImU32 *)p_max, format, flags, out_grab_bb); case ImGuiDataType_S64: - IM_ASSERT(*(const ImS64*)p_min >= IM_S64_MIN / 2 && *(const ImS64*)p_max <= IM_S64_MAX / 2); - return SliderBehaviorT(bb, id, data_type, (ImS64*)p_v, *(const ImS64*)p_min, *(const ImS64*)p_max, format, flags, out_grab_bb); + IM_ASSERT(*(const ImS64 *)p_min >= IM_S64_MIN / 2 && *(const ImS64 *)p_max <= IM_S64_MAX / 2); + return SliderBehaviorT(bb, id, data_type, (ImS64 *)p_v, *(const ImS64 *)p_min, + *(const ImS64 *)p_max, format, flags, out_grab_bb); case ImGuiDataType_U64: - IM_ASSERT(*(const ImU64*)p_max <= IM_U64_MAX / 2); - return SliderBehaviorT(bb, id, data_type, (ImU64*)p_v, *(const ImU64*)p_min, *(const ImU64*)p_max, format, flags, out_grab_bb); + IM_ASSERT(*(const ImU64 *)p_max <= IM_U64_MAX / 2); + return SliderBehaviorT(bb, id, data_type, (ImU64 *)p_v, *(const ImU64 *)p_min, + *(const ImU64 *)p_max, format, flags, out_grab_bb); case ImGuiDataType_Float: - IM_ASSERT(*(const float*)p_min >= -FLT_MAX / 2.0f && *(const float*)p_max <= FLT_MAX / 2.0f); - return SliderBehaviorT(bb, id, data_type, (float*)p_v, *(const float*)p_min, *(const float*)p_max, format, flags, out_grab_bb); + IM_ASSERT(*(const float *)p_min >= -FLT_MAX / 2.0f && *(const float *)p_max <= FLT_MAX / 2.0f); + return SliderBehaviorT(bb, id, data_type, (float *)p_v, *(const float *)p_min, + *(const float *)p_max, format, flags, out_grab_bb); case ImGuiDataType_Double: - IM_ASSERT(*(const double*)p_min >= -DBL_MAX / 2.0f && *(const double*)p_max <= DBL_MAX / 2.0f); - return SliderBehaviorT(bb, id, data_type, (double*)p_v, *(const double*)p_min, *(const double*)p_max, format, flags, out_grab_bb); - case ImGuiDataType_COUNT: break; + IM_ASSERT(*(const double *)p_min >= -DBL_MAX / 2.0f && *(const double *)p_max <= DBL_MAX / 2.0f); + return SliderBehaviorT(bb, id, data_type, (double *)p_v, *(const double *)p_min, + *(const double *)p_max, format, flags, out_grab_bb); + case ImGuiDataType_COUNT: + break; } IM_ASSERT(0); return false; } -// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a slider, they are all required. -// Read code of e.g. SliderFloat(), SliderInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. -bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) +// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a slider, they are all +// required. Read code of e.g. SliderFloat(), SliderInt() etc. or examples in 'Demo->Widgets->Data Types' to understand +// how to use this function directly. +bool ImGui::SliderScalar(const char *label, ImGuiDataType data_type, void *p_data, const void *p_min, const void *p_max, + const char *format, ImGuiSliderFlags flags) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; + ImGuiContext &g = *GImGui; + 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 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); @@ -3298,7 +3848,8 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat if (make_active && clicked) SetKeyOwner(ImGuiKey_MouseLeft, id); if (make_active && temp_input_allowed) - if ((clicked && g.IO.KeyCtrl) || (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput))) + if ((clicked && g.IO.KeyCtrl) || + (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput))) temp_input_is_active = true; // Store initial value (not used by main lib but available as a convenience but some mods e.g. to revert) @@ -3316,13 +3867,17 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat if (temp_input_is_active) { - // Only clamp CTRL+Click input when ImGuiSliderFlags_ClampOnInput is set (generally via ImGuiSliderFlags_AlwaysClamp) + // Only clamp CTRL+Click input when ImGuiSliderFlags_ClampOnInput is set (generally via + // ImGuiSliderFlags_AlwaysClamp) const bool clamp_enabled = (flags & ImGuiSliderFlags_ClampOnInput) != 0; - return TempInputScalar(frame_bb, id, label, data_type, p_data, format, clamp_enabled ? p_min : NULL, clamp_enabled ? p_max : NULL); + return TempInputScalar(frame_bb, id, label, data_type, p_data, format, clamp_enabled ? p_min : NULL, + clamp_enabled ? p_max : NULL); } // Draw frame - const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive + : hovered ? ImGuiCol_FrameBgHovered + : ImGuiCol_FrameBg); RenderNavCursor(frame_bb, id); RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); @@ -3334,11 +3889,14 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat // Render grab if (grab_bb.Max.x > grab_bb.Min.x) - window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, + GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), + style.GrabRounding); // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; - const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + const char *value_buf_end = + value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); if (g.LogEnabled) LogSetNextTextDecoration("{", "}"); RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); @@ -3346,18 +3904,20 @@ 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, g.LastItemData.StatusFlags | (temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, + g.LastItemData.StatusFlags | (temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0)); return value_changed; } // Add multiple sliders on 1 line for compact edition of multiple components -bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::SliderScalarN(const char *label, ImGuiDataType data_type, void *v, int components, const void *v_min, + const void *v_max, const char *format, ImGuiSliderFlags flags) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; bool value_changed = false; BeginGroup(); PushID(label); @@ -3371,11 +3931,11 @@ bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, i value_changed |= SliderScalar("", data_type, v, v_min, v_max, format, flags); PopID(); PopItemWidth(); - v = (void*)((char*)v + type_size); + v = (void *)((char *)v + type_size); } PopID(); - const char* label_end = FindRenderedTextEnd(label); + const char *label_end = FindRenderedTextEnd(label); if (label != label_end) { SameLine(0, g.Style.ItemInnerSpacing.x); @@ -3386,27 +3946,32 @@ bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, i return value_changed; } -bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::SliderFloat(const char *label, float *v, float v_min, float v_max, const char *format, + ImGuiSliderFlags flags) { return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, flags); } -bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::SliderFloat2(const char *label, float v[2], float v_min, float v_max, const char *format, + ImGuiSliderFlags flags) { return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, flags); } -bool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::SliderFloat3(const char *label, float v[3], float v_min, float v_max, const char *format, + ImGuiSliderFlags flags) { return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, flags); } -bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::SliderFloat4(const char *label, float v[4], float v_min, float v_max, const char *format, + ImGuiSliderFlags flags) { return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, flags); } -bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::SliderAngle(const char *label, float *v_rad, float v_degrees_min, float v_degrees_max, const char *format, + ImGuiSliderFlags flags) { if (format == NULL) format = "%.0f deg"; @@ -3417,39 +3982,41 @@ bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, fl return value_changed; } -bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::SliderInt(const char *label, int *v, int v_min, int v_max, const char *format, ImGuiSliderFlags flags) { return SliderScalar(label, ImGuiDataType_S32, v, &v_min, &v_max, format, flags); } -bool ImGui::SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::SliderInt2(const char *label, int v[2], int v_min, int v_max, const char *format, ImGuiSliderFlags flags) { return SliderScalarN(label, ImGuiDataType_S32, v, 2, &v_min, &v_max, format, flags); } -bool ImGui::SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::SliderInt3(const char *label, int v[3], int v_min, int v_max, const char *format, ImGuiSliderFlags flags) { return SliderScalarN(label, ImGuiDataType_S32, v, 3, &v_min, &v_max, format, flags); } -bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::SliderInt4(const char *label, int v[4], int v_min, int v_max, const char *format, ImGuiSliderFlags flags) { return SliderScalarN(label, ImGuiDataType_S32, v, 4, &v_min, &v_max, format, flags); } -bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::VSliderScalar(const char *label, const ImVec2 &size, ImGuiDataType data_type, void *p_data, + const void *p_min, const void *p_max, const char *format, ImGuiSliderFlags flags) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; + ImGuiContext &g = *GImGui; + const ImGuiStyle &style = g.Style; const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size); - const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + const ImRect bb(frame_bb.Min, + frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); ItemSize(bb, style.FramePadding.y); if (!ItemAdd(frame_bb, id)) @@ -3472,37 +4039,46 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d } // Draw frame - const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive + : hovered ? ImGuiCol_FrameBgHovered + : ImGuiCol_FrameBg); RenderNavCursor(frame_bb, id); RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); // Slider behavior ImRect grab_bb; - const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, flags | ImGuiSliderFlags_Vertical, &grab_bb); + const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, + flags | ImGuiSliderFlags_Vertical, &grab_bb); if (value_changed) MarkItemEdited(id); // Render grab if (grab_bb.Max.y > grab_bb.Min.y) - window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, + GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), + style.GrabRounding); // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. // For the vertical slider we allow centered text to overlap the frame padding char value_buf[64]; - const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); - RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.0f)); + const char *value_buf_end = + value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, + value_buf_end, NULL, ImVec2(0.5f, 0.0f)); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); return value_changed; } -bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::VSliderFloat(const char *label, const ImVec2 &size, float *v, float v_min, float v_max, const char *format, + ImGuiSliderFlags flags) { return VSliderScalar(label, size, ImGuiDataType_Float, v, &v_min, &v_max, format, flags); } -bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::VSliderInt(const char *label, const ImVec2 &size, int *v, int v_min, int v_max, const char *format, + ImGuiSliderFlags flags) { return VSliderScalar(label, size, ImGuiDataType_S32, v, &v_min, &v_max, format, flags); } @@ -3531,7 +4107,7 @@ bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, //------------------------------------------------------------------------- // We don't use strchr() because our strings are usually very short and often start with '%' -const char* ImParseFormatFindStart(const char* fmt) +const char *ImParseFormatFindStart(const char *fmt) { while (char c = fmt[0]) { @@ -3544,13 +4120,14 @@ const char* ImParseFormatFindStart(const char* fmt) return fmt; } -const char* ImParseFormatFindEnd(const char* fmt) +const char *ImParseFormatFindEnd(const char *fmt) { // Printf/scanf types modifiers: I/L/h/j/l/t/w/z. Other uppercase letters qualify as types aka end of the format. if (fmt[0] != '%') return fmt; - const unsigned int ignored_uppercase_mask = (1 << ('I'-'A')) | (1 << ('L'-'A')); - const unsigned int ignored_lowercase_mask = (1 << ('h'-'a')) | (1 << ('j'-'a')) | (1 << ('l'-'a')) | (1 << ('t'-'a')) | (1 << ('w'-'a')) | (1 << ('z'-'a')); + const unsigned int ignored_uppercase_mask = (1 << ('I' - 'A')) | (1 << ('L' - 'A')); + const unsigned int ignored_lowercase_mask = (1 << ('h' - 'a')) | (1 << ('j' - 'a')) | (1 << ('l' - 'a')) | + (1 << ('t' - 'a')) | (1 << ('w' - 'a')) | (1 << ('z' - 'a')); for (char c; (c = *fmt) != 0; fmt++) { if (c >= 'A' && c <= 'Z' && ((1 << (c - 'A')) & ignored_uppercase_mask) == 0) @@ -3566,12 +4143,12 @@ const char* ImParseFormatFindEnd(const char* fmt) // fmt = "%.3f" -> return fmt // fmt = "hello %.3f" -> return fmt + 6 // fmt = "%.3f hello" -> return buf written with "%.3f" -const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, size_t buf_size) +const char *ImParseFormatTrimDecorations(const char *fmt, char *buf, size_t buf_size) { - const char* fmt_start = ImParseFormatFindStart(fmt); + const char *fmt_start = ImParseFormatFindStart(fmt); if (fmt_start[0] != '%') return ""; - const char* fmt_end = ImParseFormatFindEnd(fmt_start); + const char *fmt_end = ImParseFormatFindEnd(fmt_start); if (fmt_end[0] == 0) // If we only have leading decoration, we don't need to copy the data. return fmt_start; ImStrncpy(buf, fmt_start, ImMin((size_t)(fmt_end - fmt_start) + 1, buf_size)); @@ -3580,10 +4157,11 @@ const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, size_t buf_ // 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. -void ImParseFormatSanitizeForPrinting(const char* fmt_in, char* fmt_out, size_t fmt_out_size) +// - stb_sprintf.h supports several new modifiers which format numbers in a way that also makes them incompatible +// atof/atoi. +void ImParseFormatSanitizeForPrinting(const char *fmt_in, char *fmt_out, size_t fmt_out_size) { - const char* fmt_end = ImParseFormatFindEnd(fmt_in); + const char *fmt_end = ImParseFormatFindEnd(fmt_in); IM_UNUSED(fmt_out_size); IM_ASSERT((size_t)(fmt_end - fmt_in + 1) < fmt_out_size); // Format is too long, let us know if this happens to you! while (fmt_in < fmt_end) @@ -3595,11 +4173,12 @@ void ImParseFormatSanitizeForPrinting(const char* fmt_in, char* fmt_out, size_t *fmt_out = 0; // Zero-terminate } -// - For scanning we need to remove all width and precision fields and flags "%+3.7f" -> "%f". BUT don't strip types like "%I64d" which includes digits. ! "%07I64d" -> "%I64d" -const char* ImParseFormatSanitizeForScanning(const char* fmt_in, char* fmt_out, size_t fmt_out_size) +// - For scanning we need to remove all width and precision fields and flags "%+3.7f" -> "%f". BUT don't strip types +// like "%I64d" which includes digits. ! "%07I64d" -> "%I64d" +const char *ImParseFormatSanitizeForScanning(const char *fmt_in, char *fmt_out, size_t fmt_out_size) { - const char* fmt_end = ImParseFormatFindEnd(fmt_in); - const char* fmt_out_begin = fmt_out; + const char *fmt_end = ImParseFormatFindEnd(fmt_in); + const char *fmt_out_begin = fmt_out; IM_UNUSED(fmt_out_size); IM_ASSERT((size_t)(fmt_end - fmt_in + 1) < fmt_out_size); // Format is too long, let us know if this happens to you! bool has_type = false; @@ -3616,12 +4195,18 @@ const char* ImParseFormatSanitizeForScanning(const char* fmt_in, char* fmt_out, return fmt_out_begin; } -template -static const char* ImAtoi(const char* src, TYPE* output) +template static const char *ImAtoi(const char *src, TYPE *output) { int negative = 0; - if (*src == '-') { negative = 1; src++; } - if (*src == '+') { src++; } + if (*src == '-') + { + negative = 1; + src++; + } + if (*src == '+') + { + src++; + } TYPE v = 0; while (*src >= '0' && *src <= '9') v = (v * 10) + (*src++ - '0'); @@ -3630,8 +4215,9 @@ static const char* ImAtoi(const char* src, TYPE* output) } // Parse display precision back from the display format string -// FIXME: This is still used by some navigation code path to infer a minimum tweak step, but we should aim to rework widgets so it isn't needed. -int ImParseFormatPrecision(const char* fmt, int default_precision) +// FIXME: This is still used by some navigation code path to infer a minimum tweak step, but we should aim to rework +// widgets so it isn't needed. +int ImParseFormatPrecision(const char *fmt, int default_precision) { fmt = ImParseFormatFindStart(fmt); if (fmt[0] != '%') @@ -3657,11 +4243,12 @@ int ImParseFormatPrecision(const char* fmt, int default_precision) // FIXME: Facilitate using this in variety of other situations. // FIXME: Among other things, setting ImGuiItemFlags_AllowDuplicateId in LastItemData is currently correct but // the expected relationship between TempInputXXX functions and LastItemData is a little fishy. -bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags) +bool ImGui::TempInputText(const ImRect &bb, ImGuiID id, const char *label, char *buf, int buf_size, + ImGuiInputTextFlags flags) { // On the first frame, g.TempInputTextId == 0, then on subsequent frames it becomes == id. // We clear ActiveID on the first frame to allow the InputText() taking it back. - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; const bool init = (g.TempInputId != id); if (init) ClearActiveID(); @@ -3678,15 +4265,17 @@ bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* return value_changed; } -// Note that Drag/Slider functions are only forwarding the min/max values clamping values if the ImGuiSliderFlags_AlwaysClamp flag is set! -// This is intended: this way we allow CTRL+Click manual input to set a value out of bounds, for maximum flexibility. -// However this may not be ideal for all uses, as some user code may break on out of bound values. -bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min, const void* p_clamp_max) +// Note that Drag/Slider functions are only forwarding the min/max values clamping values if the +// ImGuiSliderFlags_AlwaysClamp flag is set! This is intended: this way we allow CTRL+Click manual input to set a value +// out of bounds, for maximum flexibility. However this may not be ideal for all uses, as some user code may break on +// out of bound values. +bool ImGui::TempInputScalar(const ImRect &bb, ImGuiID id, const char *label, ImGuiDataType data_type, void *p_data, + const char *format, const void *p_clamp_min, const void *p_clamp_max) { // FIXME: May need to clarify display behavior if format doesn't contain %. // "%d" -> "%d" / "There are %d items" -> "%d" / "items" -> "%d" (fallback). Also see #6405 - ImGuiContext& g = *GImGui; - const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type); + ImGuiContext &g = *GImGui; + const ImGuiDataTypeInfo *type_info = DataTypeGetInfo(data_type); char fmt_buf[32]; char data_buf[32]; format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf)); @@ -3695,8 +4284,11 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, p_data, format); ImStrTrimBlanks(data_buf); - ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint; - g.LastItemData.ItemFlags |= ImGuiItemFlags_NoMarkEdited; // Because TempInputText() uses ImGuiInputTextFlags_MergedItem it doesn't submit a new item, so we poke LastItemData. + ImGuiInputTextFlags flags = + ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint; + g.LastItemData.ItemFlags |= + ImGuiItemFlags_NoMarkEdited; // Because TempInputText() uses ImGuiInputTextFlags_MergedItem it doesn't submit a + // new item, so we poke LastItemData. bool value_changed = false; if (TempInputText(bb, id, label, data_buf, IM_ARRAYSIZE(data_buf), flags)) { @@ -3723,29 +4315,34 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG return value_changed; } -void ImGui::SetNextItemRefVal(ImGuiDataType data_type, void* p_data) +void ImGui::SetNextItemRefVal(ImGuiDataType data_type, void *p_data) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; g.NextItemData.HasFlags |= ImGuiNextItemDataFlags_HasRefVal; memcpy(&g.NextItemData.RefVal, p_data, DataTypeGetInfo(data_type)->Size); } -// Note: p_data, p_step, p_step_fast are _pointers_ to a memory address holding the data. For an Input widget, p_step and p_step_fast are optional. -// Read code of e.g. InputFloat(), InputInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. -bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_step, const void* p_step_fast, const char* format, ImGuiInputTextFlags flags) +// Note: p_data, p_step, p_step_fast are _pointers_ to a memory address holding the data. For an Input widget, p_step +// and p_step_fast are optional. Read code of e.g. InputFloat(), InputInt() etc. or examples in 'Demo->Widgets->Data +// Types' to understand how to use this function directly. +bool ImGui::InputScalar(const char *label, ImGuiDataType data_type, void *p_data, const void *p_step, + const void *p_step_fast, const char *format, ImGuiInputTextFlags flags) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; - ImGuiStyle& style = g.Style; - IM_ASSERT((flags & ImGuiInputTextFlags_EnterReturnsTrue) == 0); // Not supported by InputScalar(). Please open an issue if you this would be useful to you. Otherwise use IsItemDeactivatedAfterEdit()! + ImGuiContext &g = *GImGui; + ImGuiStyle &style = g.Style; + IM_ASSERT((flags & ImGuiInputTextFlags_EnterReturnsTrue) == + 0); // Not supported by InputScalar(). Please open an issue if you this would be useful to you. Otherwise + // use IsItemDeactivatedAfterEdit()! if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - void* p_data_default = (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasRefVal) ? &g.NextItemData.RefVal : &g.DataTypeZeroValue; + void *p_data_default = + (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasRefVal) ? &g.NextItemData.RefVal : &g.DataTypeZeroValue; char buf[64]; if ((flags & ImGuiInputTextFlags_DisplayEmptyRefVal) && DataTypeCompare(data_type, p_data, p_data_default) == 0) @@ -3762,18 +4359,23 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data if (p_step == NULL) { if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) - value_changed = DataTypeApplyFromText(buf, data_type, p_data, format, (flags & ImGuiInputTextFlags_ParseEmptyRefVal) ? p_data_default : NULL); + value_changed = DataTypeApplyFromText( + buf, data_type, p_data, format, (flags & ImGuiInputTextFlags_ParseEmptyRefVal) ? p_data_default : NULL); } else { const float button_size = GetFrameHeight(); - BeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. IsItemActive() + BeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. + // IsItemActive() PushID(label); SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); - if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view - value_changed = DataTypeApplyFromText(buf, data_type, p_data, format, (flags & ImGuiInputTextFlags_ParseEmptyRefVal) ? p_data_default : NULL); - IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Inputable); + if (InputText("", buf, IM_ARRAYSIZE(buf), + flags)) // PushId(label) + "" gives us the expected ID from outside point of view + value_changed = DataTypeApplyFromText( + buf, data_type, p_data, format, (flags & ImGuiInputTextFlags_ParseEmptyRefVal) ? p_data_default : NULL); + IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, + g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Inputable); // Step buttons const ImVec2 backup_frame_padding = style.FramePadding; @@ -3797,7 +4399,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data if (flags & ImGuiInputTextFlags_ReadOnly) EndDisabled(); - const char* label_end = FindRenderedTextEnd(label); + const char *label_end = FindRenderedTextEnd(label); if (label != label_end) { SameLine(0, style.ItemInnerSpacing.x); @@ -3816,13 +4418,14 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data return value_changed; } -bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_step, const void* p_step_fast, const char* format, ImGuiInputTextFlags flags) +bool ImGui::InputScalarN(const char *label, ImGuiDataType data_type, void *p_data, int components, const void *p_step, + const void *p_step_fast, const char *format, ImGuiInputTextFlags flags) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; bool value_changed = false; BeginGroup(); PushID(label); @@ -3836,11 +4439,11 @@ bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* p_dat value_changed |= InputScalar("", data_type, p_data, p_step, p_step_fast, format, flags); PopID(); PopItemWidth(); - p_data = (void*)((char*)p_data + type_size); + p_data = (void *)((char *)p_data + type_size); } PopID(); - const char* label_end = FindRenderedTextEnd(label); + const char *label_end = FindRenderedTextEnd(label); if (label != label_end) { SameLine(0.0f, g.Style.ItemInnerSpacing.x); @@ -3851,51 +4454,57 @@ bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* p_dat return value_changed; } -bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, const char* format, ImGuiInputTextFlags flags) +bool ImGui::InputFloat(const char *label, float *v, float step, float step_fast, const char *format, + ImGuiInputTextFlags flags) { - return InputScalar(label, ImGuiDataType_Float, (void*)v, (void*)(step > 0.0f ? &step : NULL), (void*)(step_fast > 0.0f ? &step_fast : NULL), format, flags); + return InputScalar(label, ImGuiDataType_Float, (void *)v, (void *)(step > 0.0f ? &step : NULL), + (void *)(step_fast > 0.0f ? &step_fast : NULL), format, flags); } -bool ImGui::InputFloat2(const char* label, float v[2], const char* format, ImGuiInputTextFlags flags) +bool ImGui::InputFloat2(const char *label, float v[2], const char *format, ImGuiInputTextFlags flags) { return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, flags); } -bool ImGui::InputFloat3(const char* label, float v[3], const char* format, ImGuiInputTextFlags flags) +bool ImGui::InputFloat3(const char *label, float v[3], const char *format, ImGuiInputTextFlags flags) { return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, flags); } -bool ImGui::InputFloat4(const char* label, float v[4], const char* format, ImGuiInputTextFlags flags) +bool ImGui::InputFloat4(const char *label, float v[4], const char *format, ImGuiInputTextFlags flags) { return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, flags); } -bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags flags) +bool ImGui::InputInt(const char *label, int *v, int step, int step_fast, ImGuiInputTextFlags flags) { - // Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to parse your own data, if you want to handle prefixes. - const char* format = (flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d"; - return InputScalar(label, ImGuiDataType_S32, (void*)v, (void*)(step > 0 ? &step : NULL), (void*)(step_fast > 0 ? &step_fast : NULL), format, flags); + // Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to + // parse your own data, if you want to handle prefixes. + const char *format = (flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d"; + return InputScalar(label, ImGuiDataType_S32, (void *)v, (void *)(step > 0 ? &step : NULL), + (void *)(step_fast > 0 ? &step_fast : NULL), format, flags); } -bool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags) +bool ImGui::InputInt2(const char *label, int v[2], ImGuiInputTextFlags flags) { return InputScalarN(label, ImGuiDataType_S32, v, 2, NULL, NULL, "%d", flags); } -bool ImGui::InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags) +bool ImGui::InputInt3(const char *label, int v[3], ImGuiInputTextFlags flags) { return InputScalarN(label, ImGuiDataType_S32, v, 3, NULL, NULL, "%d", flags); } -bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags) +bool ImGui::InputInt4(const char *label, int v[4], ImGuiInputTextFlags flags) { return InputScalarN(label, ImGuiDataType_S32, v, 4, NULL, NULL, "%d", flags); } -bool ImGui::InputDouble(const char* label, double* v, double step, double step_fast, const char* format, ImGuiInputTextFlags flags) +bool ImGui::InputDouble(const char *label, double *v, double step, double step_fast, const char *format, + ImGuiInputTextFlags flags) { - return InputScalar(label, ImGuiDataType_Double, (void*)v, (void*)(step > 0.0 ? &step : NULL), (void*)(step_fast > 0.0 ? &step_fast : NULL), format, flags); + return InputScalar(label, ImGuiDataType_Double, (void *)v, (void *)(step > 0.0 ? &step : NULL), + (void *)(step_fast > 0.0 ? &step_fast : NULL), format, flags); } //------------------------------------------------------------------------- @@ -3917,31 +4526,36 @@ namespace ImStb #include "imstb_textedit.h" } -bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +bool ImGui::InputText(const char *label, char *buf, size_t buf_size, ImGuiInputTextFlags flags, + ImGuiInputTextCallback callback, void *user_data) { IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() return InputTextEx(label, NULL, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data); } -bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +bool ImGui::InputTextMultiline(const char *label, char *buf, size_t buf_size, const ImVec2 &size, + ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void *user_data) { - return InputTextEx(label, NULL, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data); + return InputTextEx(label, NULL, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, + user_data); } -bool ImGui::InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +bool ImGui::InputTextWithHint(const char *label, const char *hint, char *buf, size_t buf_size, + ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void *user_data) { - IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() or InputTextEx() manually if you need multi-line + hint. + IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() or InputTextEx() manually if you + // need multi-line + hint. return InputTextEx(label, hint, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data); } // This is only used in the path where the multiline widget is inactive. -static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end) +static int InputTextCalcTextLenAndLineCount(const char *text_begin, const char **out_text_end) { int line_count = 0; - const char* s = text_begin; + const char *s = text_begin; while (true) { - const char* s_eol = strchr(s, '\n'); + const char *s_eol = strchr(s, '\n'); line_count++; if (s_eol == NULL) { @@ -3955,18 +4569,19 @@ static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** } // FIXME: Ideally we'd share code with ImFont::CalcTextSizeA() -static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, const char* text_end, const char** remaining, ImVec2* out_offset, bool stop_on_new_line) +static ImVec2 InputTextCalcTextSize(ImGuiContext *ctx, const char *text_begin, const char *text_end, + const char **remaining, ImVec2 *out_offset, bool stop_on_new_line) { - ImGuiContext& g = *ctx; - //ImFont* font = g.Font; - ImFontBaked* baked = g.FontBaked; + ImGuiContext &g = *ctx; + // ImFont* font = g.Font; + ImFontBaked *baked = g.FontBaked; const float line_height = g.FontSize; const float scale = line_height / baked->Size; ImVec2 text_size = ImVec2(0, 0); float line_width = 0.0f; - const char* s = text_begin; + const char *s = text_begin; while (s < text_end) { unsigned int c = (unsigned int)*s; @@ -3994,9 +4609,10 @@ static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, c text_size.x = line_width; if (out_offset) - *out_offset = ImVec2(line_width, text_size.y + line_height); // offset allow for the possibility of sitting after a trailing \n + *out_offset = ImVec2( + line_width, text_size.y + line_height); // offset allow for the possibility of sitting after a trailing \n - if (line_width > 0 || text_size.y == 0.0f) // whereas size.y will ignore the trailing \n + if (line_width > 0 || text_size.y == 0.0f) // whereas size.y will ignore the trailing \n text_size.y += line_height; if (remaining) @@ -4005,22 +4621,40 @@ static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, c return text_size; } -// Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, wchar characters. InputText converts between UTF-8 and wchar) -// With our UTF-8 use of stb_textedit: -// - STB_TEXTEDIT_GETCHAR is nothing more than a a "GETBYTE". It's only used to compare to ascii or to copy blocks of text so we are fine. -// - One exception is the STB_TEXTEDIT_IS_SPACE feature which would expect a full char in order to handle full-width space such as 0x3000 (see ImCharIsBlankW). +// Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, wchar characters. +// InputText converts between UTF-8 and wchar) With our UTF-8 use of stb_textedit: +// - STB_TEXTEDIT_GETCHAR is nothing more than a a "GETBYTE". It's only used to compare to ascii or to copy blocks of +// text so we are fine. +// - One exception is the STB_TEXTEDIT_IS_SPACE feature which would expect a full char in order to handle full-width +// space such as 0x3000 (see ImCharIsBlankW). // - ...but we don't use that feature. namespace ImStb { -static int STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj) { return obj->TextLen; } -static char STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { IM_ASSERT(idx <= obj->TextLen); return obj->TextSrc[idx]; } -static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { unsigned int c; ImTextCharFromUtf8(&c, obj->TextSrc + line_start_idx + char_idx, obj->TextSrc + obj->TextLen); if ((ImWchar)c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.FontBaked->GetCharAdvance((ImWchar)c) * g.FontBakedScale; } -static char STB_TEXTEDIT_NEWLINE = '\n'; -static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx) +static int STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState *obj) { - const char* text = obj->TextSrc; - const char* text_remaining = NULL; - const ImVec2 size = InputTextCalcTextSize(obj->Ctx, text + line_start_idx, text + obj->TextLen, &text_remaining, NULL, true); + return obj->TextLen; +} +static char STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState *obj, int idx) +{ + IM_ASSERT(idx <= obj->TextLen); + return obj->TextSrc[idx]; +} +static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState *obj, int line_start_idx, int char_idx) +{ + unsigned int c; + ImTextCharFromUtf8(&c, obj->TextSrc + line_start_idx + char_idx, obj->TextSrc + obj->TextLen); + if ((ImWchar)c == '\n') + return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; + ImGuiContext &g = *obj->Ctx; + return g.FontBaked->GetCharAdvance((ImWchar)c) * g.FontBakedScale; +} +static char STB_TEXTEDIT_NEWLINE = '\n'; +static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow *r, ImGuiInputTextState *obj, int line_start_idx) +{ + const char *text = obj->TextSrc; + const char *text_remaining = NULL; + const ImVec2 size = + InputTextCalcTextSize(obj->Ctx, text + line_start_idx, text + obj->TextLen, &text_remaining, NULL, true); r->x0 = 0.0f; r->x1 = size.x; r->baseline_y_delta = size.y; @@ -4029,10 +4663,10 @@ static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* ob r->num_chars = (int)(text_remaining - (text + line_start_idx)); } -#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL -#define IMSTB_TEXTEDIT_GETPREVCHARINDEX IMSTB_TEXTEDIT_GETPREVCHARINDEX_IMPL +#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL +#define IMSTB_TEXTEDIT_GETPREVCHARINDEX IMSTB_TEXTEDIT_GETPREVCHARINDEX_IMPL -static int IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL(ImGuiInputTextState* obj, int idx) +static int IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL(ImGuiInputTextState *obj, int idx) { if (idx >= obj->TextLen) return obj->TextLen + 1; @@ -4040,21 +4674,19 @@ static int IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL(ImGuiInputTextState* obj, int id return idx + ImTextCharFromUtf8(&c, obj->TextSrc + idx, obj->TextSrc + obj->TextLen); } -static int IMSTB_TEXTEDIT_GETPREVCHARINDEX_IMPL(ImGuiInputTextState* obj, int idx) +static int IMSTB_TEXTEDIT_GETPREVCHARINDEX_IMPL(ImGuiInputTextState *obj, int idx) { if (idx <= 0) return -1; - const char* p = ImTextFindPreviousUtf8Codepoint(obj->TextSrc, obj->TextSrc + idx); + const char *p = ImTextFindPreviousUtf8Codepoint(obj->TextSrc, obj->TextSrc + idx); return (int)(p - obj->TextSrc); } static bool ImCharIsSeparatorW(unsigned int c) { - static const unsigned int separator_list[] = - { - ',', 0x3001, '.', 0x3002, ';', 0xFF1B, '(', 0xFF08, ')', 0xFF09, '{', 0xFF5B, '}', 0xFF5D, - '[', 0x300C, ']', 0x300D, '|', 0xFF5C, '!', 0xFF01, '\\', 0xFFE5, '/', 0x30FB, 0xFF0F, - '\n', '\r', + static const unsigned int separator_list[] = { + ',', 0x3001, '.', 0x3002, ';', 0xFF1B, '(', 0xFF08, ')', 0xFF09, '{', 0xFF5B, '}', 0xFF5D, '[', 0x300C, + ']', 0x300D, '|', 0xFF5C, '!', 0xFF01, '\\', 0xFFE5, '/', 0x30FB, 0xFF0F, '\n', '\r', }; for (unsigned int separator : separator_list) if (c == separator) @@ -4062,16 +4694,19 @@ static bool ImCharIsSeparatorW(unsigned int c) return false; } -static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) +static int is_word_boundary_from_right(ImGuiInputTextState *obj, int 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. + // 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. if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0) return 0; - const char* curr_p = obj->TextSrc + idx; - const char* prev_p = ImTextFindPreviousUtf8Codepoint(obj->TextSrc, curr_p); - unsigned int curr_c; ImTextCharFromUtf8(&curr_c, curr_p, obj->TextSrc + obj->TextLen); - unsigned int prev_c; ImTextCharFromUtf8(&prev_c, prev_p, obj->TextSrc + obj->TextLen); + const char *curr_p = obj->TextSrc + idx; + const char *prev_p = ImTextFindPreviousUtf8Codepoint(obj->TextSrc, curr_p); + unsigned int curr_c; + ImTextCharFromUtf8(&curr_c, curr_p, obj->TextSrc + obj->TextLen); + unsigned int prev_c; + ImTextCharFromUtf8(&prev_c, prev_p, obj->TextSrc + obj->TextLen); bool prev_white = ImCharIsBlankW(prev_c); bool prev_separ = ImCharIsSeparatorW(prev_c); @@ -4079,15 +4714,17 @@ static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) bool curr_separ = ImCharIsSeparatorW(curr_c); return ((prev_white || prev_separ) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ); } -static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) +static int is_word_boundary_from_left(ImGuiInputTextState *obj, int idx) { if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0) return 0; - const char* curr_p = obj->TextSrc + idx; - const char* prev_p = ImTextFindPreviousUtf8Codepoint(obj->TextSrc, curr_p); - unsigned int prev_c; ImTextCharFromUtf8(&prev_c, curr_p, obj->TextSrc + obj->TextLen); - unsigned int curr_c; ImTextCharFromUtf8(&curr_c, prev_p, obj->TextSrc + obj->TextLen); + const char *curr_p = obj->TextSrc + idx; + const char *prev_p = ImTextFindPreviousUtf8Codepoint(obj->TextSrc, curr_p); + unsigned int prev_c; + ImTextCharFromUtf8(&prev_c, curr_p, obj->TextSrc + obj->TextLen); + unsigned int curr_c; + ImTextCharFromUtf8(&curr_c, prev_p, obj->TextSrc + obj->TextLen); bool prev_white = ImCharIsBlankW(prev_c); bool prev_separ = ImCharIsSeparatorW(prev_c); @@ -4095,14 +4732,14 @@ static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) bool curr_separ = ImCharIsSeparatorW(curr_c); return ((prev_white) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ); } -static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx) +static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState *obj, int idx) { idx = IMSTB_TEXTEDIT_GETPREVCHARINDEX(obj, idx); while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx = IMSTB_TEXTEDIT_GETPREVCHARINDEX(obj, idx); return idx < 0 ? 0 : idx; } -static int STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx) +static int STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState *obj, int idx) { int len = obj->TextLen; idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx); @@ -4110,7 +4747,7 @@ static int STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx) idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx); return idx > len ? len : idx; } -static int STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx) +static int STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState *obj, int idx) { idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx); int len = obj->TextLen; @@ -4118,22 +4755,29 @@ static int STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx) idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx); return idx > len ? len : idx; } -static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx) { ImGuiContext& g = *obj->Ctx; if (g.IO.ConfigMacOSXBehaviors) return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx); else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx); } -#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 int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState *obj, int idx) +{ + ImGuiContext &g = *obj->Ctx; + if (g.IO.ConfigMacOSXBehaviors) + return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx); + else + return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx); +} +#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(ImGuiInputTextState* obj, int pos, int n) +static void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState *obj, int pos, int n) { // Offset remaining text (+ copy zero terminator) IM_ASSERT(obj->TextSrc == obj->TextA.Data); - char* dst = obj->TextA.Data + pos; - char* src = obj->TextA.Data + pos + n; + char *dst = obj->TextA.Data + pos; + char *src = obj->TextA.Data + pos + n; memmove(dst, src, obj->TextLen - n - pos + 1); obj->Edited = true; obj->TextLen -= n; } -static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const char* new_text, int new_text_len) +static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState *obj, int pos, const char *new_text, int new_text_len) { const bool is_resizable = (obj->Flags & ImGuiInputTextFlags_CallbackResize) != 0; const int text_len = obj->TextLen; @@ -4152,7 +4796,7 @@ static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const ch obj->TextSrc = obj->TextA.Data; } - char* text = obj->TextA.Data; + char *text = obj->TextA.Data; if (pos != text_len) memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos)); memcpy(text + pos, new_text, (size_t)new_text_len); @@ -4164,32 +4808,35 @@ static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const ch return true; } -// We don't use an enum so we can build even with conflicting symbols (if another user of stb_textedit.h leak their STB_TEXTEDIT_K_* symbols) -#define STB_TEXTEDIT_K_LEFT 0x200000 // keyboard input to move cursor left -#define STB_TEXTEDIT_K_RIGHT 0x200001 // keyboard input to move cursor right -#define STB_TEXTEDIT_K_UP 0x200002 // keyboard input to move cursor up -#define STB_TEXTEDIT_K_DOWN 0x200003 // keyboard input to move cursor down -#define STB_TEXTEDIT_K_LINESTART 0x200004 // keyboard input to move cursor to start of line -#define STB_TEXTEDIT_K_LINEEND 0x200005 // keyboard input to move cursor to end of line -#define STB_TEXTEDIT_K_TEXTSTART 0x200006 // keyboard input to move cursor to start of text -#define STB_TEXTEDIT_K_TEXTEND 0x200007 // keyboard input to move cursor to end of text -#define STB_TEXTEDIT_K_DELETE 0x200008 // keyboard input to delete selection or character under cursor -#define STB_TEXTEDIT_K_BACKSPACE 0x200009 // keyboard input to delete selection or character left of cursor -#define STB_TEXTEDIT_K_UNDO 0x20000A // keyboard input to perform undo -#define STB_TEXTEDIT_K_REDO 0x20000B // keyboard input to perform redo -#define STB_TEXTEDIT_K_WORDLEFT 0x20000C // keyboard input to move cursor left one word -#define STB_TEXTEDIT_K_WORDRIGHT 0x20000D // keyboard input to move cursor right one word -#define STB_TEXTEDIT_K_PGUP 0x20000E // keyboard input to move cursor up a page -#define STB_TEXTEDIT_K_PGDOWN 0x20000F // keyboard input to move cursor down a page -#define STB_TEXTEDIT_K_SHIFT 0x400000 +// We don't use an enum so we can build even with conflicting symbols (if another user of stb_textedit.h leak their +// STB_TEXTEDIT_K_* symbols) +#define STB_TEXTEDIT_K_LEFT 0x200000 // keyboard input to move cursor left +#define STB_TEXTEDIT_K_RIGHT 0x200001 // keyboard input to move cursor right +#define STB_TEXTEDIT_K_UP 0x200002 // keyboard input to move cursor up +#define STB_TEXTEDIT_K_DOWN 0x200003 // keyboard input to move cursor down +#define STB_TEXTEDIT_K_LINESTART 0x200004 // keyboard input to move cursor to start of line +#define STB_TEXTEDIT_K_LINEEND 0x200005 // keyboard input to move cursor to end of line +#define STB_TEXTEDIT_K_TEXTSTART 0x200006 // keyboard input to move cursor to start of text +#define STB_TEXTEDIT_K_TEXTEND 0x200007 // keyboard input to move cursor to end of text +#define STB_TEXTEDIT_K_DELETE 0x200008 // keyboard input to delete selection or character under cursor +#define STB_TEXTEDIT_K_BACKSPACE 0x200009 // keyboard input to delete selection or character left of cursor +#define STB_TEXTEDIT_K_UNDO 0x20000A // keyboard input to perform undo +#define STB_TEXTEDIT_K_REDO 0x20000B // keyboard input to perform redo +#define STB_TEXTEDIT_K_WORDLEFT 0x20000C // keyboard input to move cursor left one word +#define STB_TEXTEDIT_K_WORDRIGHT 0x20000D // keyboard input to move cursor right one word +#define STB_TEXTEDIT_K_PGUP 0x20000E // keyboard input to move cursor up a page +#define STB_TEXTEDIT_K_PGDOWN 0x20000F // keyboard input to move cursor down a page +#define STB_TEXTEDIT_K_SHIFT 0x400000 #define IMSTB_TEXTEDIT_IMPLEMENTATION #define IMSTB_TEXTEDIT_memmove memmove #include "imstb_textedit.h" // 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(ImGuiInputTextState* str, STB_TexteditState* state, const IMSTB_TEXTEDIT_CHARTYPE* text, int text_len) +// the stb_textedit_paste() function creates two separate records, so we perform it manually. (FIXME: Report to +// nothings/stb?) +static void stb_textedit_replace(ImGuiInputTextState *str, STB_TexteditState *state, + const IMSTB_TEXTEDIT_CHARTYPE *text, int text_len) { stb_text_makeundo_replace(str, state, 0, str->TextLen, text_len); ImStb::STB_TEXTEDIT_DELETECHARS(str, 0, str->TextLen); @@ -4202,7 +4849,8 @@ static void stb_textedit_replace(ImGuiInputTextState* str, STB_TexteditState* st state->has_preferred_x = 0; return; } - IM_ASSERT(0); // Failed to insert character, normally shouldn't happen because of how we currently use stb_textedit_replace() + IM_ASSERT(0); // Failed to insert character, normally shouldn't happen because of how we currently use + // stb_textedit_replace() } } // namespace ImStb @@ -4239,17 +4887,59 @@ void ImGuiInputTextState::OnCharPressed(unsigned int c) } // Those functions are not inlined in imgui_internal.h, allowing us to hide ImStbTexteditState from that header. -void ImGuiInputTextState::CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking -void ImGuiInputTextState::CursorClamp() { Stb->cursor = ImMin(Stb->cursor, TextLen); Stb->select_start = ImMin(Stb->select_start, TextLen); Stb->select_end = ImMin(Stb->select_end, TextLen); } -bool ImGuiInputTextState::HasSelection() const { return Stb->select_start != Stb->select_end; } -void ImGuiInputTextState::ClearSelection() { Stb->select_start = Stb->select_end = Stb->cursor; } -int ImGuiInputTextState::GetCursorPos() const { return Stb->cursor; } -int ImGuiInputTextState::GetSelectionStart() const { return Stb->select_start; } -int ImGuiInputTextState::GetSelectionEnd() const { return Stb->select_end; } -void ImGuiInputTextState::SelectAll() { Stb->select_start = 0; Stb->cursor = Stb->select_end = TextLen; Stb->has_preferred_x = 0; } -void ImGuiInputTextState::ReloadUserBufAndSelectAll() { WantReloadUserBuf = true; ReloadSelectionStart = 0; ReloadSelectionEnd = INT_MAX; } -void ImGuiInputTextState::ReloadUserBufAndKeepSelection() { WantReloadUserBuf = true; ReloadSelectionStart = Stb->select_start; ReloadSelectionEnd = Stb->select_end; } -void ImGuiInputTextState::ReloadUserBufAndMoveToEnd() { WantReloadUserBuf = true; ReloadSelectionStart = ReloadSelectionEnd = INT_MAX; } +void ImGuiInputTextState::CursorAnimReset() +{ + CursorAnim = -0.30f; +} // After a user-input the cursor stays on for a while without blinking +void ImGuiInputTextState::CursorClamp() +{ + Stb->cursor = ImMin(Stb->cursor, TextLen); + Stb->select_start = ImMin(Stb->select_start, TextLen); + Stb->select_end = ImMin(Stb->select_end, TextLen); +} +bool ImGuiInputTextState::HasSelection() const +{ + return Stb->select_start != Stb->select_end; +} +void ImGuiInputTextState::ClearSelection() +{ + Stb->select_start = Stb->select_end = Stb->cursor; +} +int ImGuiInputTextState::GetCursorPos() const +{ + return Stb->cursor; +} +int ImGuiInputTextState::GetSelectionStart() const +{ + return Stb->select_start; +} +int ImGuiInputTextState::GetSelectionEnd() const +{ + return Stb->select_end; +} +void ImGuiInputTextState::SelectAll() +{ + Stb->select_start = 0; + Stb->cursor = Stb->select_end = TextLen; + Stb->has_preferred_x = 0; +} +void ImGuiInputTextState::ReloadUserBufAndSelectAll() +{ + WantReloadUserBuf = true; + ReloadSelectionStart = 0; + ReloadSelectionEnd = INT_MAX; +} +void ImGuiInputTextState::ReloadUserBufAndKeepSelection() +{ + WantReloadUserBuf = true; + ReloadSelectionStart = Stb->select_start; + ReloadSelectionEnd = Stb->select_end; +} +void ImGuiInputTextState::ReloadUserBufAndMoveToEnd() +{ + WantReloadUserBuf = true; + ReloadSelectionStart = ReloadSelectionEnd = INT_MAX; +} ImGuiInputTextCallbackData::ImGuiInputTextCallbackData() { @@ -4263,8 +4953,8 @@ ImGuiInputTextCallbackData::ImGuiInputTextCallbackData() void ImGuiInputTextCallbackData::DeleteChars(int pos, int bytes_count) { IM_ASSERT(pos + bytes_count <= BufTextLen); - char* dst = Buf + pos; - const char* src = Buf + pos + bytes_count; + char *dst = Buf + pos; + const char *src = Buf + pos + bytes_count; memmove(dst, src, BufTextLen - bytes_count - pos + 1); if (CursorPos >= pos + bytes_count) @@ -4276,7 +4966,7 @@ void ImGuiInputTextCallbackData::DeleteChars(int pos, int bytes_count) BufTextLen -= bytes_count; } -void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end) +void ImGuiInputTextCallbackData::InsertChars(int pos, const char *new_text, const char *new_text_end) { // Accept null ranges if (new_text == new_text_end) @@ -4290,8 +4980,8 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons if (!is_resizable) return; - ImGuiContext& g = *Ctx; - ImGuiInputTextState* edit_state = &g.InputTextState; + ImGuiContext &g = *Ctx; + ImGuiInputTextState *edit_state = &g.InputTextState; IM_ASSERT(edit_state->ID != 0 && g.ActiveId == edit_state->ID); IM_ASSERT(Buf == edit_state->TextA.Data); int new_buf_size = BufTextLen + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1; @@ -4315,10 +5005,10 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons void ImGui::PushPasswordFont() { - ImGuiContext& g = *GImGui; - ImFontBaked* backup = &g.InputTextPasswordFontBackupBaked; + ImGuiContext &g = *GImGui; + ImFontBaked *backup = &g.InputTextPasswordFontBackupBaked; IM_ASSERT(backup->IndexAdvanceX.Size == 0 && backup->IndexLookup.Size == 0); - ImFontGlyph* glyph = g.FontBaked->FindGlyph('*'); + ImFontGlyph *glyph = g.FontBaked->FindGlyph('*'); g.InputTextPasswordFontBackupFlags = g.Font->Flags; backup->FallbackGlyphIndex = g.FontBaked->FallbackGlyphIndex; backup->FallbackAdvanceX = g.FontBaked->FallbackAdvanceX; @@ -4331,8 +5021,8 @@ void ImGui::PushPasswordFont() void ImGui::PopPasswordFont() { - ImGuiContext& g = *GImGui; - ImFontBaked* backup = &g.InputTextPasswordFontBackupBaked; + ImGuiContext &g = *GImGui; + ImFontBaked *backup = &g.InputTextPasswordFontBackupBaked; g.Font->Flags = g.InputTextPasswordFontBackupFlags; g.FontBaked->FallbackGlyphIndex = backup->FallbackGlyphIndex; g.FontBaked->FallbackAdvanceX = backup->FallbackAdvanceX; @@ -4342,7 +5032,8 @@ void ImGui::PopPasswordFont() } // Return false to discard a character. -static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, bool input_source_is_clipboard) +static bool InputTextFilterCharacter(ImGuiContext *ctx, unsigned int *p_char, ImGuiInputTextFlags flags, + ImGuiInputTextCallback callback, void *user_data, bool input_source_is_clipboard) { unsigned int c = *p_char; @@ -4351,8 +5042,11 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im if (c < 0x20) { bool pass = false; - pass |= (c == '\n') && (flags & ImGuiInputTextFlags_Multiline) != 0; // Note that an Enter KEY will emit \r and be ignored (we poll for KEY in InputText() code) - if (c == '\n' && input_source_is_clipboard && (flags & ImGuiInputTextFlags_Multiline) == 0) // In single line mode, replace \n with a space + pass |= (c == '\n') && + (flags & ImGuiInputTextFlags_Multiline) != + 0; // Note that an Enter KEY will emit \r and be ignored (we poll for KEY in InputText() code) + if (c == '\n' && input_source_is_clipboard && + (flags & ImGuiInputTextFlags_Multiline) == 0) // In single line mode, replace \n with a space { c = *p_char = ' '; pass = true; @@ -4370,7 +5064,8 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im if (c == 127) return false; - // Filter private Unicode range. GLFW on OSX seems to send private characters for special keys like arrow keys (FIXME) + // 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; } @@ -4380,35 +5075,46 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im return false; // Generic named filters - if (apply_named_filters && (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint))) + if (apply_named_filters && + (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | + ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | + ImGuiInputTextFlags_CharsScientific | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint))) { - // The libc allows overriding locale, with e.g. 'setlocale(LC_NUMERIC, "de_DE.UTF-8");' which affect the output/input of printf/scanf to use e.g. ',' instead of '.'. - // The standard mandate that programs starts in the "C" locale where the decimal point is '.'. - // We don't really intend to provide widespread support for it, but out of empathy for people stuck with using odd API, we support the bare minimum aka overriding the decimal point. - // Change the default decimal_point with: + // The libc allows overriding locale, with e.g. 'setlocale(LC_NUMERIC, "de_DE.UTF-8");' which affect the + // output/input of printf/scanf to use e.g. ',' instead of '.'. The standard mandate that programs starts in the + // "C" locale where the decimal point is '.'. We don't really intend to provide widespread support for it, but + // out of empathy for people stuck with using odd API, we support the bare minimum aka overriding the decimal + // point. Change the default decimal_point with: // ImGui::GetPlatformIO()->Platform_LocaleDecimalPoint = *localeconv()->decimal_point; - // Users of non-default decimal point (in particular ',') may be affected by word-selection logic (is_word_boundary_from_right/is_word_boundary_from_left) functions. - ImGuiContext& g = *ctx; + // Users of non-default decimal point (in particular ',') may be affected by word-selection logic + // (is_word_boundary_from_right/is_word_boundary_from_left) functions. + ImGuiContext &g = *ctx; const unsigned c_decimal_point = (unsigned int)g.PlatformIO.Platform_LocaleDecimalPoint; - if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint)) + if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific | + (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint)) if (c == '.' || c == ',') c = c_decimal_point; - // Full-width -> half-width conversion for numeric fields (https://en.wikipedia.org/wiki/Halfwidth_and_Fullwidth_Forms_(Unicode_block) - // While this is mostly convenient, this has the side-effect for uninformed users accidentally inputting full-width characters that they may - // scratch their head as to why it works in numerical fields vs in generic text fields it would require support in the font. - if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific | ImGuiInputTextFlags_CharsHexadecimal)) + // Full-width -> half-width conversion for numeric fields + // (https://en.wikipedia.org/wiki/Halfwidth_and_Fullwidth_Forms_(Unicode_block) While this is mostly convenient, + // this has the side-effect for uninformed users accidentally inputting full-width characters that they may + // scratch their head as to why it works in numerical fields vs in generic text fields it would require support + // in the font. + if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific | + ImGuiInputTextFlags_CharsHexadecimal)) if (c >= 0xFF01 && c <= 0xFF5E) c = c - 0xFF01 + 0x21; // Allow 0-9 . - + * / if (flags & ImGuiInputTextFlags_CharsDecimal) - if (!(c >= '0' && c <= '9') && (c != c_decimal_point) && (c != '-') && (c != '+') && (c != '*') && (c != '/')) + if (!(c >= '0' && c <= '9') && (c != c_decimal_point) && (c != '-') && (c != '+') && (c != '*') && + (c != '/')) return false; // Allow 0-9 . - + * / e E if (flags & ImGuiInputTextFlags_CharsScientific) - if (!(c >= '0' && c <= '9') && (c != c_decimal_point) && (c != '-') && (c != '+') && (c != '*') && (c != '/') && (c != 'e') && (c != 'E')) + if (!(c >= '0' && c <= '9') && (c != c_decimal_point) && (c != '-') && (c != '+') && (c != '*') && + (c != '/') && (c != 'e') && (c != 'E')) return false; // Allow 0-9 a-F A-F @@ -4431,7 +5137,7 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im // Custom callback filter if (flags & ImGuiInputTextFlags_CallbackCharFilter) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; ImGuiInputTextCallbackData callback_data; callback_data.Ctx = &g; callback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter; @@ -4450,8 +5156,10 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im // Find the shortest single replacement we can make to get from old_buf to new_buf // Note that this doesn't directly alter state->TextA, state->TextLen. They are expected to be made valid separately. -// FIXME: Ideally we should transition toward (1) making InsertChars()/DeleteChars() update undo-stack (2) discourage (and keep reconcile) or obsolete (and remove reconcile) accessing buffer directly. -static void InputTextReconcileUndoState(ImGuiInputTextState* state, const char* old_buf, int old_length, const char* new_buf, int new_length) +// FIXME: Ideally we should transition toward (1) making InsertChars()/DeleteChars() update undo-stack (2) discourage +// (and keep reconcile) or obsolete (and remove reconcile) accessing buffer directly. +static void InputTextReconcileUndoState(ImGuiInputTextState *state, const char *old_buf, int old_length, + const char *new_buf, int new_length) { const int shorter_length = ImMin(old_length, new_length); int first_diff; @@ -4461,7 +5169,7 @@ static void InputTextReconcileUndoState(ImGuiInputTextState* state, const char* if (first_diff == old_length && first_diff == new_length) return; - int old_last_diff = old_length - 1; + int old_last_diff = old_length - 1; int new_last_diff = new_length - 1; for (; old_last_diff >= first_diff && new_last_diff >= first_diff; old_last_diff--, new_last_diff--) if (old_buf[old_last_diff] != new_buf[new_last_diff]) @@ -4470,7 +5178,8 @@ static void InputTextReconcileUndoState(ImGuiInputTextState* state, const char* const int insert_len = new_last_diff - first_diff + 1; const int delete_len = old_last_diff - first_diff + 1; if (insert_len > 0 || delete_len > 0) - if (IMSTB_TEXTEDIT_CHARTYPE* p = stb_text_createundo(&state->Stb->undostate, first_diff, delete_len, insert_len)) + if (IMSTB_TEXTEDIT_CHARTYPE *p = + stb_text_createundo(&state->Stb->undostate, first_diff, delete_len, insert_len)) for (int i = 0; i < delete_len; i++) p[i] = old_buf[first_diff + i]; } @@ -4481,8 +5190,8 @@ static void InputTextReconcileUndoState(ImGuiInputTextState* state, const char* // but that more likely be attractive when we do have _NoLiveEdit flag available. void ImGui::InputTextDeactivateHook(ImGuiID id) { - ImGuiContext& g = *GImGui; - ImGuiInputTextState* state = &g.InputTextState; + ImGuiContext &g = *GImGui; + ImGuiInputTextState *state = &g.InputTextState; if (id == 0 || state->ID != id) return; g.InputTextDeactivatedState.ID = state->ID; @@ -4503,39 +5212,51 @@ void ImGui::InputTextDeactivateHook(ImGuiID id) // - buf_size account for the zero-terminator, so a buf_size of 6 can hold "Hello" but not "Hello!". // This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match // Note that in std::string world, capacity() would omit 1 byte used by the zero-terminator. -// - When active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while the InputText is active has no effect. +// - When active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while the +// InputText is active has no effect. // - If you want to use ImGui::InputText() with std::string, see misc/cpp/imgui_stdlib.h -// (FIXME: Rather confusing and messy function, among the worse part of our codebase, expecting to rewrite a V2 at some point.. Partly because we are -// doing UTF8 > U16 > UTF8 conversions on the go to easily interface with stb_textedit. Ideally should stay in UTF-8 all the time. See https://github.com/nothings/stb/issues/188) -bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* callback_user_data) +// (FIXME: Rather confusing and messy function, among the worse part of our codebase, expecting to rewrite a V2 at some +// point.. Partly because we are +// doing UTF8 > U16 > UTF8 conversions on the go to easily interface with stb_textedit. Ideally should stay in UTF-8 +// all the time. See https://github.com/nothings/stb/issues/188) +bool ImGui::InputTextEx(const char *label, const char *hint, char *buf, int buf_size, const ImVec2 &size_arg, + ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void *callback_user_data) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; IM_ASSERT(buf != NULL && buf_size >= 0); - IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys) - IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key) - IM_ASSERT(!((flags & ImGuiInputTextFlags_ElideLeft) && (flags & ImGuiInputTextFlags_Multiline))); // Multiline will not work with left-trimming + IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && + (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys) + IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && + (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key) + IM_ASSERT(!((flags & ImGuiInputTextFlags_ElideLeft) && + (flags & ImGuiInputTextFlags_Multiline))); // Multiline will not work with left-trimming - ImGuiContext& g = *GImGui; - ImGuiIO& io = g.IO; - const ImGuiStyle& style = g.Style; + ImGuiContext &g = *GImGui; + ImGuiIO &io = g.IO; + const ImGuiStyle &style = g.Style; const bool RENDER_SELECTION_WHEN_INACTIVE = false; const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; - if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope (including the scrollbar) + if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope + // (including the scrollbar) BeginGroup(); const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? g.FontSize * 8.0f : label_size.y) + style.FramePadding.y * 2.0f); // Arbitrary default of 8 lines high for multi-line - const ImVec2 total_size = ImVec2(frame_size.x + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), frame_size.y); + const ImVec2 frame_size = + CalcItemSize(size_arg, CalcItemWidth(), + (is_multiline ? g.FontSize * 8.0f : label_size.y) + + style.FramePadding.y * 2.0f); // Arbitrary default of 8 lines high for multi-line + const ImVec2 total_size = + ImVec2(frame_size.x + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), frame_size.y); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); const ImRect total_bb(frame_bb.Min, frame_bb.Min + total_size); - ImGuiWindow* draw_window = window; + ImGuiWindow *draw_window = window; ImVec2 inner_size = frame_size; ImGuiLastItemData item_data_backup; if (is_multiline) @@ -4550,8 +5271,10 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ item_data_backup = g.LastItemData; window->DC.CursorPos = backup_pos; - // Prevent NavActivation from Tabbing when our widget accepts Tab inputs: this allows cycling through widgets without stopping. - if (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_FromTabbing) && (flags & ImGuiInputTextFlags_AllowTabInput)) + // Prevent NavActivation from Tabbing when our widget accepts Tab inputs: this allows cycling through widgets + // without stopping. + if (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_FromTabbing) && + (flags & ImGuiInputTextFlags_AllowTabInput)) g.NavActivateId = 0; // Prevent NavActivate reactivating in BeginChild() when we are already active. @@ -4559,12 +5282,15 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (g.ActiveId == id) // Prevent reactivation g.NavActivateId = 0; - // We reproduce the contents of BeginChildFrame() in order to provide 'label' so our window internal data are easier to read/debug. + // We reproduce the contents of BeginChildFrame() in order to provide 'label' so our window internal data are + // easier to read/debug. PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); - PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Ensure no clip rect so mouse hover can reach FramePadding edges - bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove); + PushStyleVar(ImGuiStyleVar_WindowPadding, + ImVec2(0, 0)); // Ensure no clip rect so mouse hover can reach FramePadding edges + bool child_visible = + BeginChildEx(label, id, frame_bb.GetSize(), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove); g.NavActivateId = backup_activate_id; PopStyleVar(3); PopStyleColor(); @@ -4575,13 +5301,16 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ return false; } draw_window = g.CurrentWindow; // Child window - 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.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) + // 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 (!(flags & ImGuiInputTextFlags_MergedItem)) if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable)) @@ -4596,7 +5325,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ hovered = false; // We are only allowed to access the state if we are already the active widget. - ImGuiInputTextState* state = GetInputTextState(id); + ImGuiInputTextState *state = GetInputTextState(id); if (g.LastItemData.ItemFlags & ImGuiItemFlags_ReadOnly) flags |= ImGuiInputTextFlags_ReadOnly; @@ -4607,18 +5336,23 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_resizable) IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag! - const bool input_requested_by_nav = (g.ActiveId != id) && ((g.NavActivateId == id) && ((g.NavActivateFlags & ImGuiActivateFlags_PreferInput) || (g.NavInputSource == ImGuiInputSource_Keyboard))); + const bool input_requested_by_nav = + (g.ActiveId != id) && ((g.NavActivateId == id) && ((g.NavActivateFlags & ImGuiActivateFlags_PreferInput) || + (g.NavInputSource == ImGuiInputSource_Keyboard))); const bool user_clicked = hovered && io.MouseClicked[0]; - 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); + const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && + g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); + const bool user_scroll_active = + is_multiline && state != NULL && g.ActiveId == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); bool clear_active_id = false; bool select_all = false; float scroll_y = is_multiline ? draw_window->Scroll.y : FLT_MAX; const bool init_reload_from_user_buf = (state != NULL && state->WantReloadUserBuf); - const bool init_changed_specs = (state != NULL && state->Stb->single_line != !is_multiline); // state != NULL means its our state. + const bool init_changed_specs = + (state != NULL && state->Stb->single_line != !is_multiline); // state != NULL means its our state. const bool init_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav); const bool init_state = (init_make_active || user_scroll_active); if (init_reload_from_user_buf) @@ -4627,7 +5361,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ IM_ASSERT(new_len + 1 <= buf_size && "Is your input buffer properly zero-terminated?"); state->WantReloadUserBuf = false; InputTextReconcileUndoState(state, state->TextA.Data, state->TextLen, buf, new_len); - state->TextA.resize(buf_size + 1); // we use +1 to make sure that .Data is always pointing to at least an empty string. + state->TextA.resize(buf_size + + 1); // we use +1 to make sure that .Data is always pointing to at least an empty string. state->TextLen = new_len; memcpy(state->TextA.Data, buf, state->TextLen + 1); state->Stb->select_start = state->ReloadSelectionStart; @@ -4640,20 +5375,23 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state = &g.InputTextState; state->CursorAnimReset(); - // Backup state of deactivating item so they'll have a chance to do a write to output buffer on the same frame they report IsItemDeactivatedAfterEdit (#4714) + // Backup state of deactivating item so they'll have a chance to do a write to output buffer on the same frame + // they report IsItemDeactivatedAfterEdit (#4714) InputTextDeactivateHook(state->ID); // Take a copy of the initial buffer value. // From the moment we focused we are normally ignoring the content of 'buf' (unless we are in read-only mode) const int buf_len = (int)ImStrlen(buf); IM_ASSERT(buf_len + 1 <= buf_size && "Is your input buffer properly zero-terminated?"); - state->TextToRevertTo.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string. + state->TextToRevertTo.resize( + buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string. memcpy(state->TextToRevertTo.Data, buf, buf_len + 1); // Preserve cursor position and undo/redo stack if we come back to same widget // FIXME: Since we reworked this on 2022/06, may want to differentiate recycle_cursor vs recycle_undostate? bool recycle_state = (state->ID == id && !init_changed_specs); - if (recycle_state && (state->TextLen != buf_len || (state->TextA.Data == NULL || strncmp(state->TextA.Data, buf, buf_len) != 0))) + if (recycle_state && + (state->TextLen != buf_len || (state->TextA.Data == NULL || strncmp(state->TextA.Data, buf, buf_len) != 0))) recycle_state = false; // Start edition @@ -4661,7 +5399,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state->TextLen = buf_len; if (!is_readonly) { - state->TextA.resize(buf_size + 1); // we use +1 to make sure that .Data is always pointing to at least an empty string. + state->TextA.resize(buf_size + + 1); // we use +1 to make sure that .Data is always pointing to at least an empty string. memcpy(state->TextA.Data, buf, state->TextLen + 1); } @@ -4671,7 +5410,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state->Scroll.x += ImMax(0.0f, CalcTextSize(buf).x - frame_size.x + style.FramePadding.x * 2.0f); // Recycle existing cursor/selection/undo stack but clamp position - // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler. + // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click + // handler. if (recycle_state) state->CursorClamp(); else @@ -4681,7 +5421,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { if (flags & ImGuiInputTextFlags_AutoSelectAll) select_all = true; - if (input_requested_by_nav && (!recycle_state || !(g.NavActivateFlags & ImGuiActivateFlags_TryToPreserveState))) + if (input_requested_by_nav && + (!recycle_state || !(g.NavActivateFlags & ImGuiActivateFlags_TryToPreserveState))) select_all = true; if (user_clicked && io.KeyCtrl) select_all = true; @@ -4702,8 +5443,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (g.ActiveId == id) { // Declare some inputs, the other are registered and polled via Shortcut() routing system. - // FIXME: The reason we don't use Shortcut() is we would need a routing flag to specify multiple mods, or to all mods combination into individual shortcuts. - const ImGuiKey always_owned_keys[] = { ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_Enter, ImGuiKey_KeypadEnter, ImGuiKey_Delete, ImGuiKey_Backspace, ImGuiKey_Home, ImGuiKey_End }; + // FIXME: The reason we don't use Shortcut() is we would need a routing flag to specify multiple mods, or to all + // mods combination into individual shortcuts. + const ImGuiKey always_owned_keys[] = {ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_Enter, + ImGuiKey_KeypadEnter, ImGuiKey_Delete, ImGuiKey_Backspace, + ImGuiKey_Home, ImGuiKey_End}; for (ImGuiKey key : always_owned_keys) SetKeyOwner(key, id); if (user_clicked) @@ -4720,7 +5464,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ SetKeyOwner(ImGuiKey_PageUp, id); SetKeyOwner(ImGuiKey_PageDown, id); } - // FIXME: May be a problem to always steal Alt on OSX, would ideally still allow an uninterrupted Alt down-up to toggle menu + // FIXME: May be a problem to always steal Alt on OSX, would ideally still allow an uninterrupted Alt down-up to + // toggle menu if (is_osx) SetKeyOwner(ImGuiMod_Alt, id); @@ -4731,13 +5476,15 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Read-only mode always ever read from source buffer. Refresh TextLen when active. if (is_readonly && state != NULL) state->TextLen = (int)ImStrlen(buf); - //if (is_readonly && state != NULL) - // state->TextA.clear(); // Uncomment to facilitate debugging, but we otherwise prefer to keep/amortize th allocation. + // if (is_readonly && state != NULL) + // state->TextA.clear(); // Uncomment to facilitate debugging, but we otherwise prefer to keep/amortize th + // allocation. } if (state != NULL) state->TextSrc = is_readonly ? buf : state->TextA.Data; - // We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately (don't wait until the end of the function) + // We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately + // (don't wait until the end of the function) if (g.ActiveId == id && state == NULL) ClearActiveID(); @@ -4747,12 +5494,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Lock the decision of whether we are going to take the path displaying the cursor or selection bool render_cursor = (g.ActiveId == id) || (state && user_scroll_active); - bool render_selection = state && (state->HasSelection() || select_all) && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor); + bool render_selection = + state && (state->HasSelection() || select_all) && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor); bool value_changed = false; bool validated = false; // Select the buffer to render. - const bool buf_display_from_state = (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state; + const bool buf_display_from_state = + (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state; bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0); // Password pushes a temporary font with only a fallback glyph @@ -4767,8 +5516,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state->BufCapacity = buf_size; state->Flags = flags; - // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget. - // Down the line we should have a cleaner library-wide concept of Selected vs Active. + // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right + // now with the widget. Down the line we should have a cleaner library-wide concept of Selected vs Active. g.ActiveIdAllowOverlap = !io.MouseDown[0]; // Edit in progress @@ -4787,12 +5536,15 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if ((multiclick_count % 2) == 0) { // Double-click: Select word - // We always use the "Mac" word advance for double-click select vs CTRL+Right which use the platform dependent variant: - // FIXME: There are likely many ways to improve this behavior, but there's no "right" behavior (depends on use-case, software, OS) - const bool is_bol = (state->Stb->cursor == 0) || ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb->cursor - 1) == '\n'; + // We always use the "Mac" word advance for double-click select vs CTRL+Right which use the platform + // dependent variant: + // FIXME: There are likely many ways to improve this behavior, but there's no "right" behavior (depends + // on use-case, software, OS) + const bool is_bol = + (state->Stb->cursor == 0) || ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb->cursor - 1) == '\n'; if (STB_TEXT_HAS_SELECTION(state->Stb) || !is_bol) state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT); - //state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); + // state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); if (!STB_TEXT_HAS_SELECTION(state->Stb)) ImStb::stb_textedit_prep_selection_at_cursor(state->Stb); state->Stb->cursor = ImStb::STB_TEXTEDIT_MOVEWORDRIGHT_MAC(state, state->Stb->cursor); @@ -4826,7 +5578,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state->CursorAnimReset(); } } - else if (io.MouseDown[0] && !state->SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f)) + else if (io.MouseDown[0] && !state->SelectedAllMouseLock && + (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f)) { stb_textedit_drag(state, state->Stb, mouse_x, mouse_y); state->CursorAnimReset(); @@ -4836,7 +5589,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state->SelectedAllMouseLock = false; // We expect backends to emit a Tab key but some also emit a Tab character which we ignore (#2467, #1336) - // (For Tab and Enter: Win32/SFML/Allegro are sending both keys and chars, GLFW and SDL are only sending keys. For Space they all send all threes) + // (For Tab and Enter: Win32/SFML/Allegro are sending both keys and chars, GLFW and SDL are only sending keys. + // For Space they all send all threes) if ((flags & ImGuiInputTextFlags_AllowTabInput) && !is_readonly) { if (Shortcut(ImGuiKey_Tab, ImGuiInputFlags_Repeat, id)) @@ -4853,8 +5607,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ */ } - // Process regular text input (before we check for Return because using some IME will effectively send a Return?) - // We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters. + // Process regular text input (before we check for Return because using some IME will effectively send a + // Return?) We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which + // _is_ Alt+Ctrl) to input certain characters. const bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeyCtrl); if (io.InputQueueCharacters.Size > 0) { @@ -4884,40 +5639,97 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state->Stb->row_count_per_page = row_count_per_page; const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0); - const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl - const bool is_startend_key_down = is_osx && io.KeyCtrl && !io.KeySuper && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End + const bool is_wordmove_key_down = + is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl + const bool is_startend_key_down = + is_osx && io.KeyCtrl && !io.KeySuper && + !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End - // Using Shortcut() with ImGuiInputFlags_RouteFocused (default policy) to allow routing operations for other code (e.g. calling window trying to use CTRL+A and CTRL+B: former would be handled by InputText) - // Otherwise we could simply assume that we own the keys as we are active. + // Using Shortcut() with ImGuiInputFlags_RouteFocused (default policy) to allow routing operations for other + // code (e.g. calling window trying to use CTRL+A and CTRL+B: former would be handled by InputText) Otherwise we + // could simply assume that we own the keys as we are active. const ImGuiInputFlags f_repeat = ImGuiInputFlags_Repeat; - const bool is_cut = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_X, f_repeat, id) || Shortcut(ImGuiMod_Shift | ImGuiKey_Delete, f_repeat, id)) && !is_readonly && !is_password && (!is_multiline || state->HasSelection()); - const bool is_copy = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_C, 0, id) || Shortcut(ImGuiMod_Ctrl | ImGuiKey_Insert, 0, id)) && !is_password && (!is_multiline || state->HasSelection()); - const bool is_paste = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_V, f_repeat, id) || Shortcut(ImGuiMod_Shift | ImGuiKey_Insert, f_repeat, id)) && !is_readonly; - const bool is_undo = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_Z, f_repeat, id)) && !is_readonly && is_undoable; - const bool is_redo = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_Y, f_repeat, id) || Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Z, f_repeat, id)) && !is_readonly && is_undoable; + const bool is_cut = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_X, f_repeat, id) || + Shortcut(ImGuiMod_Shift | ImGuiKey_Delete, f_repeat, id)) && + !is_readonly && !is_password && (!is_multiline || state->HasSelection()); + const bool is_copy = + (Shortcut(ImGuiMod_Ctrl | ImGuiKey_C, 0, id) || Shortcut(ImGuiMod_Ctrl | ImGuiKey_Insert, 0, id)) && + !is_password && (!is_multiline || state->HasSelection()); + const bool is_paste = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_V, f_repeat, id) || + Shortcut(ImGuiMod_Shift | ImGuiKey_Insert, f_repeat, id)) && + !is_readonly; + const bool is_undo = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_Z, f_repeat, id)) && !is_readonly && is_undoable; + const bool is_redo = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_Y, f_repeat, id) || + Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Z, f_repeat, id)) && + !is_readonly && is_undoable; const bool is_select_all = Shortcut(ImGuiMod_Ctrl | ImGuiKey_A, 0, id); - // We allow validate/cancel with Nav source (gamepad) to makes it easier to undo an accidental NavInput press with no keyboard wired, but otherwise it isn't very useful. - const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + // We allow validate/cancel with Nav source (gamepad) to makes it easier to undo an accidental NavInput press + // with no keyboard wired, but otherwise it isn't very useful. + const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && + (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; const bool is_enter_pressed = IsKeyPressed(ImGuiKey_Enter, true) || IsKeyPressed(ImGuiKey_KeypadEnter, true); - const bool is_gamepad_validate = nav_gamepad_active && (IsKeyPressed(ImGuiKey_NavGamepadActivate, false) || IsKeyPressed(ImGuiKey_NavGamepadInput, false)); - const bool is_cancel = Shortcut(ImGuiKey_Escape, f_repeat, id) || (nav_gamepad_active && Shortcut(ImGuiKey_NavGamepadCancel, f_repeat, id)); + const bool is_gamepad_validate = nav_gamepad_active && (IsKeyPressed(ImGuiKey_NavGamepadActivate, false) || + IsKeyPressed(ImGuiKey_NavGamepadInput, false)); + const bool is_cancel = Shortcut(ImGuiKey_Escape, f_repeat, id) || + (nav_gamepad_active && Shortcut(ImGuiKey_NavGamepadCancel, f_repeat, id)); - // FIXME: Should use more Shortcut() and reduce IsKeyPressed()+SetKeyOwner(), but requires modifiers combination to be taken account of. - // FIXME-OSX: Missing support for Alt(option)+Right/Left = go to end of line, or next line if already in end of line. - if (IsKeyPressed(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } - else if (IsKeyPressed(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } - else if (IsKeyPressed(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } - else if (IsKeyPressed(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } - else if (IsKeyPressed(ImGuiKey_PageUp) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGUP | k_mask); scroll_y -= row_count_per_page * g.FontSize; } - else if (IsKeyPressed(ImGuiKey_PageDown) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page * g.FontSize; } - else if (IsKeyPressed(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } - else if (IsKeyPressed(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } + // FIXME: Should use more Shortcut() and reduce IsKeyPressed()+SetKeyOwner(), but requires modifiers combination + // to be taken account of. + // FIXME-OSX: Missing support for Alt(option)+Right/Left = go to end of line, or next line if already in end of + // line. + if (IsKeyPressed(ImGuiKey_LeftArrow)) + { + state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART + : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT + : STB_TEXTEDIT_K_LEFT) | + k_mask); + } + else if (IsKeyPressed(ImGuiKey_RightArrow)) + { + state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND + : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT + : STB_TEXTEDIT_K_RIGHT) | + k_mask); + } + else if (IsKeyPressed(ImGuiKey_UpArrow) && is_multiline) + { + if (io.KeyCtrl) + SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); + else + state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); + } + else if (IsKeyPressed(ImGuiKey_DownArrow) && is_multiline) + { + if (io.KeyCtrl) + SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); + else + state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); + } + else if (IsKeyPressed(ImGuiKey_PageUp) && is_multiline) + { + state->OnKeyPressed(STB_TEXTEDIT_K_PGUP | k_mask); + scroll_y -= row_count_per_page * g.FontSize; + } + else if (IsKeyPressed(ImGuiKey_PageDown) && is_multiline) + { + state->OnKeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); + scroll_y += row_count_per_page * g.FontSize; + } + else if (IsKeyPressed(ImGuiKey_Home)) + { + state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); + } + else if (IsKeyPressed(ImGuiKey_End)) + { + state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); + } else if (IsKeyPressed(ImGuiKey_Delete) && !is_readonly && !is_cut) { if (!state->HasSelection()) { - // OSX doesn't seem to have Super+Delete to delete until end-of-line, so we don't emulate that (as opposed to Super+Backspace) + // OSX doesn't seem to have Super+Delete to delete until end-of-line, so we don't emulate that (as + // opposed to Super+Backspace) if (is_wordmove_key_down) state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); } @@ -4938,7 +5750,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { // Determine if we turn Enter into a \n character bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0; - if (!is_multiline || is_gamepad_validate || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl)) + if (!is_multiline || is_gamepad_validate || (ctrl_enter_for_new_line && !io.KeyCtrl) || + (!ctrl_enter_for_new_line && io.KeyCtrl)) { validated = true; if (io.ConfigInputTextEnterKeepActive && !is_multiline) @@ -4988,9 +5801,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Cut, Copy if (g.PlatformIO.Platform_SetClipboardTextFn != NULL) { - // SetClipboardText() only takes null terminated strings + state->TextSrc may point to read-only user buffer, so we need to make a copy. + // SetClipboardText() only takes null terminated strings + state->TextSrc may point to read-only user + // buffer, so we need to make a copy. const int ib = state->HasSelection() ? ImMin(state->Stb->select_start, state->Stb->select_end) : 0; - const int ie = state->HasSelection() ? ImMax(state->Stb->select_start, state->Stb->select_end) : state->TextLen; + const int ie = + state->HasSelection() ? ImMax(state->Stb->select_start, state->Stb->select_end) : state->TextLen; g.TempBuffer.reserve(ie - ib + 1); memcpy(g.TempBuffer.Data, state->TextSrc + ib, ie - ib); g.TempBuffer.Data[ie - ib] = 0; @@ -5006,13 +5821,13 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } else if (is_paste) { - if (const char* clipboard = GetClipboardText()) + if (const char *clipboard = GetClipboardText()) { // Filter pasted buffer const int clipboard_len = (int)ImStrlen(clipboard); ImVector clipboard_filtered; clipboard_filtered.reserve(clipboard_len + 1); - for (const char* s = clipboard; *s != 0; ) + for (const char *s = clipboard; *s != 0;) { unsigned int c; int in_len = ImTextCharFromUtf8(&c, s, NULL); @@ -5034,12 +5849,13 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } } - // Update render selection flag after events have been handled, so selection highlight can be displayed during the same frame. + // Update render selection flag after events have been handled, so selection highlight can be displayed during + // the same frame. render_selection |= state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor); } // Process callbacks and apply result back to user's buffer. - const char* apply_new_text = NULL; + const char *apply_new_text = NULL; int apply_new_text_length = 0; if (g.ActiveId == id) { @@ -5061,31 +5877,36 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ apply_new_text = state->TextToRevertTo.Data; apply_new_text_length = state->TextToRevertTo.Size - 1; - // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents. - // Push records into the undo stack so we can CTRL+Z the revert operation itself + // Restore initial value. Only return true if restoring to the initial value changes the current buffer + // contents. Push records into the undo stack so we can CTRL+Z the revert operation itself value_changed = true; stb_textedit_replace(state, state->Stb, state->TextToRevertTo.Data, state->TextToRevertTo.Size - 1); } } // FIXME-OPT: We always reapply the live buffer back to the input buffer before clearing ActiveId, - // even though strictly speaking it wasn't modified on this frame. Should mark dirty state from the stb_textedit callbacks. - // If we do that, need to ensure that as special case, 'validated == true' also writes back. - // This also allows the user to use InputText() without maintaining any user-side storage. - // (please note that if you use this property along ImGuiInputTextFlags_CallbackResize you can end up with your temporary string object - // unnecessarily allocating once a frame, either store your string data, either if you don't then don't use ImGuiInputTextFlags_CallbackResize). - const bool apply_edit_back_to_user_buffer = true;// !revert_edit || (validated && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0); + // even though strictly speaking it wasn't modified on this frame. Should mark dirty state from the stb_textedit + // callbacks. If we do that, need to ensure that as special case, 'validated == true' also writes back. This + // also allows the user to use InputText() without maintaining any user-side storage. (please note that if you + // use this property along ImGuiInputTextFlags_CallbackResize you can end up with your temporary string object + // unnecessarily allocating once a frame, either store your string data, either if you don't then don't use + // ImGuiInputTextFlags_CallbackResize). + const bool apply_edit_back_to_user_buffer = + true; // !revert_edit || (validated && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0); if (apply_edit_back_to_user_buffer) { // Apply current edited text immediately. - // Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer + // Note that as soon as the input box is active, the in-widget value gets priority over any underlying + // modification of the input buffer // User callback - if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackAlways)) != 0) + if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | + ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackAlways)) != 0) { IM_ASSERT(callback != NULL); - // The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment. + // The reason we specify the usage semantic (Completion/History) is that Completion needs to disable + // keyboard TABBING at the moment. ImGuiInputTextFlags event_flag = 0; ImGuiKey event_key = ImGuiKey_None; if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && Shortcut(ImGuiKey_Tab, 0, id)) @@ -5121,7 +5942,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ callback_data.UserData = callback_user_data; // FIXME-OPT: Undo stack reconcile needs a backup of the data until we rework API, see #7925 - char* callback_buf = is_readonly ? buf : state->TextA.Data; + char *callback_buf = is_readonly ? buf : state->TextA.Data; IM_ASSERT(callback_buf == state->TextSrc); state->CallbackTextBackup.resize(state->TextLen + 1); memcpy(state->CallbackTextBackup.Data, callback_buf, state->TextLen + 1); @@ -5140,20 +5961,40 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ callback(&callback_data); // Read back what user may have modified - callback_buf = is_readonly ? buf : state->TextA.Data; // Pointer may have been invalidated by a resize callback - IM_ASSERT(callback_data.Buf == callback_buf); // Invalid to modify those fields + callback_buf = + is_readonly ? buf : state->TextA.Data; // Pointer may have been invalidated by a resize callback + IM_ASSERT(callback_data.Buf == callback_buf); // Invalid to modify those fields IM_ASSERT(callback_data.BufSize == state->BufCapacity); IM_ASSERT(callback_data.Flags == flags); const bool buf_dirty = callback_data.BufDirty; - if (callback_data.CursorPos != utf8_cursor_pos || buf_dirty) { state->Stb->cursor = callback_data.CursorPos; state->CursorFollow = true; } - if (callback_data.SelectionStart != utf8_selection_start || buf_dirty) { state->Stb->select_start = (callback_data.SelectionStart == callback_data.CursorPos) ? state->Stb->cursor : callback_data.SelectionStart; } - if (callback_data.SelectionEnd != utf8_selection_end || buf_dirty) { state->Stb->select_end = (callback_data.SelectionEnd == callback_data.SelectionStart) ? state->Stb->select_start : callback_data.SelectionEnd; } + if (callback_data.CursorPos != utf8_cursor_pos || buf_dirty) + { + state->Stb->cursor = callback_data.CursorPos; + state->CursorFollow = true; + } + if (callback_data.SelectionStart != utf8_selection_start || buf_dirty) + { + state->Stb->select_start = (callback_data.SelectionStart == callback_data.CursorPos) + ? state->Stb->cursor + : callback_data.SelectionStart; + } + if (callback_data.SelectionEnd != utf8_selection_end || buf_dirty) + { + state->Stb->select_end = (callback_data.SelectionEnd == callback_data.SelectionStart) + ? state->Stb->select_start + : callback_data.SelectionEnd; + } if (buf_dirty) { // Callback may update buffer and thus set buf_dirty even in read-only mode. - IM_ASSERT(callback_data.BufTextLen == (int)ImStrlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! - InputTextReconcileUndoState(state, state->CallbackTextBackup.Data, state->CallbackTextBackup.Size - 1, callback_data.Buf, callback_data.BufTextLen); - state->TextLen = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen() + IM_ASSERT(callback_data.BufTextLen == + (int)ImStrlen( + callback_data.Buf)); // You need to maintain BufTextLen if you change the text! + InputTextReconcileUndoState(state, state->CallbackTextBackup.Data, + state->CallbackTextBackup.Size - 1, callback_data.Buf, + callback_data.BufTextLen); + state->TextLen = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, + // saves us an extra strlen() state->CursorAnimReset(); } } @@ -5172,12 +6013,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Handle reapplying final data on deactivation (see InputTextDeactivateHook() for details) if (g.InputTextDeactivatedState.ID == id) { - if (g.ActiveId != id && IsItemDeactivatedAfterEdit() && !is_readonly && strcmp(g.InputTextDeactivatedState.TextA.Data, buf) != 0) + if (g.ActiveId != id && IsItemDeactivatedAfterEdit() && !is_readonly && + strcmp(g.InputTextDeactivatedState.TextA.Data, buf) != 0) { apply_new_text = g.InputTextDeactivatedState.TextA.Data; apply_new_text_length = g.InputTextDeactivatedState.TextA.Size - 1; value_changed = true; - //IMGUI_DEBUG_LOG("InputText(): apply Deactivated data for 0x%08X: \"%.*s\".\n", id, apply_new_text_length, apply_new_text); + // IMGUI_DEBUG_LOG("InputText(): apply Deactivated data for 0x%08X: \"%.*s\".\n", id, apply_new_text_length, + // apply_new_text); } g.InputTextDeactivatedState.ID = 0; } @@ -5185,9 +6028,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Copy result to user buffer. This can currently only happen when (g.ActiveId == id) if (apply_new_text != NULL) { - //// We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee that the size - //// of our owned buffer matches the size of the string object held by the user, and by design we allow InputText() to be used - //// without any storage on user's side. + //// We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee + ///that the size / of our owned buffer matches the size of the string object held by the user, and by design we + ///allow InputText() to be used / without any storage on user's side. IM_ASSERT(apply_new_text_length >= 0); if (is_resizable) { @@ -5205,14 +6048,15 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ apply_new_text_length = ImMin(callback_data.BufTextLen, buf_size - 1); IM_ASSERT(apply_new_text_length <= buf_size); } - //IMGUI_DEBUG_PRINT("InputText(\"%s\"): apply_new_text length %d\n", label, apply_new_text_length); + // IMGUI_DEBUG_PRINT("InputText(\"%s\"): apply_new_text length %d\n", label, apply_new_text_length); - // If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size. + // If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be + // >= buf_size. ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size)); } - // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value) - // Otherwise request text input ahead for next frame. + // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the + // value) Otherwise request text input ahead for next frame. if (g.ActiveId == id && clear_active_id) ClearActiveID(); @@ -5223,16 +6067,18 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); } - const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + inner_size.x, frame_bb.Min.y + inner_size.y); // Not using frame_bb.Max because we have adjusted size + const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + inner_size.x, + frame_bb.Min.y + inner_size.y); // Not using frame_bb.Max because we have adjusted size ImVec2 draw_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding; ImVec2 text_size(0.0f, 0.0f); - // Set upper limit of single-line InputTextEx() at 2 million characters strings. The current pathological worst case is a long line - // without any carriage return, which would makes ImFont::RenderText() reserve too many vertices and probably crash. Avoid it altogether. - // Note that we only use this limit on single-line InputText(), so a pathologically large line on a InputTextMultiline() would still crash. + // Set upper limit of single-line InputTextEx() at 2 million characters strings. The current pathological worst case + // is a long line without any carriage return, which would makes ImFont::RenderText() reserve too many vertices and + // probably crash. Avoid it altogether. Note that we only use this limit on single-line InputText(), so a + // pathologically large line on a InputTextMultiline() would still crash. const int buf_display_max_length = 2 * 1024 * 1024; - const char* buf_display = buf_display_from_state ? state->TextA.Data : buf; //-V595 - const char* buf_display_end = NULL; // We have specialized paths below for setting the length + const char *buf_display = buf_display_from_state ? state->TextA.Data : buf; //-V595 + const char *buf_display_end = NULL; // We have specialized paths below for setting the length // Display hint when contents is empty // At this point we need to handle the possibility that a callback could have modified the underlying buffer (#8368) @@ -5262,29 +6108,40 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Render text (with cursor and selection) // This is going to be messy. We need to: // - Display the text (this alone can be more easily clipped) - // - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation) + // - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor + // position calculation) // - Measure text height (for scrollbar) - // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort) + // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible + // for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring + // effort) // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8. - const char* text_begin = buf_display; - const char* text_end = text_begin + state->TextLen; + const char *text_begin = buf_display; + const char *text_end = text_begin + state->TextLen; ImVec2 cursor_offset, select_start_offset; { // Find lines numbers straddling cursor and selection min position int cursor_line_no = render_cursor ? -1 : -1000; int selmin_line_no = render_selection ? -1 : -1000; - const char* cursor_ptr = render_cursor ? text_begin + state->Stb->cursor : NULL; - const char* selmin_ptr = render_selection ? text_begin + ImMin(state->Stb->select_start, state->Stb->select_end) : NULL; + const char *cursor_ptr = render_cursor ? text_begin + state->Stb->cursor : NULL; + const char *selmin_ptr = + render_selection ? text_begin + ImMin(state->Stb->select_start, state->Stb->select_end) : NULL; // Count lines and find line number for cursor and selection ends int line_count = 1; if (is_multiline) { - for (const char* s = text_begin; (s = (const char*)ImMemchr(s, '\n', (size_t)(text_end - s))) != NULL; s++) + for (const char *s = text_begin; (s = (const char *)ImMemchr(s, '\n', (size_t)(text_end - s))) != NULL; + s++) { - if (cursor_line_no == -1 && s >= cursor_ptr) { cursor_line_no = line_count; } - if (selmin_line_no == -1 && s >= selmin_ptr) { selmin_line_no = line_count; } + if (cursor_line_no == -1 && s >= cursor_ptr) + { + cursor_line_no = line_count; + } + if (selmin_line_no == -1 && s >= selmin_ptr) + { + selmin_line_no = line_count; + } line_count++; } } @@ -5335,7 +6192,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ scroll_y = cursor_offset.y - inner_size.y + style.FramePadding.y * 2.0f; const float scroll_max_y = ImMax((text_size.y + style.FramePadding.y * 2.0f) - inner_size.y, 0.0f); scroll_y = ImClamp(scroll_y, 0.0f, scroll_max_y); - draw_pos.y += (draw_window->Scroll.y - scroll_y); // Manipulate cursor pos immediately avoid a frame of lag + draw_pos.y += + (draw_window->Scroll.y - scroll_y); // Manipulate cursor pos immediately avoid a frame of lag draw_window->Scroll.y = scroll_y; } @@ -5346,27 +6204,34 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const ImVec2 draw_scroll = ImVec2(state->Scroll.x, 0.0f); if (render_selection) { - const char* text_selected_begin = text_begin + ImMin(state->Stb->select_start, state->Stb->select_end); - const char* text_selected_end = text_begin + ImMax(state->Stb->select_start, state->Stb->select_end); + const char *text_selected_begin = text_begin + ImMin(state->Stb->select_start, state->Stb->select_end); + const char *text_selected_end = text_begin + ImMax(state->Stb->select_start, state->Stb->select_end); - ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg, render_cursor ? 1.0f : 0.6f); // FIXME: current code flow mandate that render_cursor is always true here, we are leaving the transparent one for tests. - float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection. + ImU32 bg_color = GetColorU32( + ImGuiCol_TextSelectedBg, + render_cursor ? 1.0f : 0.6f); // FIXME: current code flow mandate that render_cursor is always true + // here, we are leaving the transparent one for tests. + float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they + // don't play so well with multi-line selection. float bg_offy_dn = is_multiline ? 0.0f : 2.0f; ImVec2 rect_pos = draw_pos + select_start_offset - draw_scroll; - for (const char* p = text_selected_begin; p < text_selected_end; ) + for (const char *p = text_selected_begin; p < text_selected_end;) { if (rect_pos.y > clip_rect.w + g.FontSize) break; if (rect_pos.y < clip_rect.y) { - p = (const char*)ImMemchr((void*)p, '\n', text_selected_end - p); + p = (const char *)ImMemchr((void *)p, '\n', text_selected_end - p); p = p ? p + 1 : text_selected_end; } else { ImVec2 rect_size = InputTextCalcTextSize(&g, p, text_selected_end, &p, NULL, true); - if (rect_size.x <= 0.0f) rect_size.x = IM_TRUNC(g.FontBaked->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines - ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos + ImVec2(rect_size.x, bg_offy_dn)); + if (rect_size.x <= 0.0f) + rect_size.x = IM_TRUNC(g.FontBaked->GetCharAdvance((ImWchar)' ') * + 0.50f); // So we can see selected empty lines + ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), + rect_pos + ImVec2(rect_size.x, bg_offy_dn)); rect.ClipWith(clip_rect); if (rect.Overlaps(clip_rect)) draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color); @@ -5376,30 +6241,38 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } } - // We test for 'buf_display_max_length' as a way to avoid some pathological cases (e.g. single-line 1 MB string) which would make ImDrawList crash. - // FIXME-OPT: Multiline could submit a smaller amount of contents to AddText() since we already iterated through it. + // We test for 'buf_display_max_length' as a way to avoid some pathological cases (e.g. single-line 1 MB string) + // which would make ImDrawList crash. + // FIXME-OPT: Multiline could submit a smaller amount of contents to AddText() since we already iterated through + // it. if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) { ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); - draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); + draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, + buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); } // Draw blinking cursor if (render_cursor) { state->CursorAnim += io.DeltaTime; - bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f; + bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || + ImFmod(state->CursorAnim, 1.20f) <= 0.80f; ImVec2 cursor_screen_pos = ImTrunc(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); + 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_InputTextCursor), 1.0f); // FIXME-DPI: Cursor thickness (#7031) + draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), + GetColorU32(ImGuiCol_InputTextCursor), + 1.0f); // FIXME-DPI: Cursor thickness (#7031) - // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) - // This is required for some backends (SDL3) to start emitting character/text inputs. - // As per #6341, make sure we don't set that on the deactivating frame. + // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. + // Bit of an extra nicety.) This is required for some backends (SDL3) to start emitting character/text + // inputs. As per #6341, make sure we don't set that on the deactivating frame. if (!is_readonly && g.ActiveId == id) { - ImGuiPlatformImeData* ime_data = &g.PlatformImeData; // (this is a public struct, passed to io.Platform_SetImeDataFn() handler) + ImGuiPlatformImeData *ime_data = + &g.PlatformImeData; // (this is a public struct, passed to io.Platform_SetImeDataFn() handler) ime_data->WantVisible = true; ime_data->WantTextInput = true; ime_data->InputPos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize); @@ -5412,7 +6285,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { // Render text only (no selection, no cursor) if (is_multiline) - text_size = ImVec2(inner_size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_display_end) * g.FontSize); // We don't need width + text_size = ImVec2(inner_size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_display_end) * + g.FontSize); // We don't need width else if (!is_displaying_hint && g.ActiveId == id) buf_display_end = buf_display + state->TextLen; else if (!is_displaying_hint) @@ -5422,11 +6296,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { // Find render position for right alignment if (flags & ImGuiInputTextFlags_ElideLeft) - draw_pos.x = ImMin(draw_pos.x, frame_bb.Max.x - CalcTextSize(buf_display, NULL).x - style.FramePadding.x); + draw_pos.x = + ImMin(draw_pos.x, frame_bb.Max.x - CalcTextSize(buf_display, NULL).x - style.FramePadding.x); - const ImVec2 draw_scroll = /*state ? ImVec2(state->Scroll.x, 0.0f) :*/ ImVec2(0.0f, 0.0f); // Preserve scroll when inactive? + const ImVec2 draw_scroll = + /*state ? ImVec2(state->Scroll.x, 0.0f) :*/ ImVec2(0.0f, 0.0f); // Preserve scroll when inactive? ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); - draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); + draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, + buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); } } @@ -5435,13 +6312,15 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_multiline) { - // For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (see #4761, #7870)... + // For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the + // ImGuiItemFlags_Inputable (see #4761, #7870)... Dummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y)); g.NextItemData.ItemFlags |= (ImGuiItemFlags)ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop; EndChild(); item_data_backup.StatusFlags |= (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredWindow); - // ...and then we need to undo the group overriding last item data, which gets a bit messy as EndGroup() tries to forward scrollbar being active... + // ...and then we need to undo the group overriding last item data, which gets a bit messy as EndGroup() tries + // to forward scrollbar being active... // FIXME: This quite messy/tricky, should attempt to get rid of the child window. EndGroup(); if (g.LastItemData.ID == 0 || g.LastItemData.ID != GetWindowScrollbarID(draw_window, ImGuiAxis_Y)) @@ -5474,32 +6353,37 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ return value_changed; } -void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state) +void ImGui::DebugNodeInputTextState(ImGuiInputTextState *state) { #ifndef IMGUI_DISABLE_DEBUG_TOOLS - ImGuiContext& g = *GImGui; - ImStb::STB_TexteditState* stb_state = state->Stb; - ImStb::StbUndoState* undo_state = &stb_state->undostate; + ImGuiContext &g = *GImGui; + ImStb::STB_TexteditState *stb_state = state->Stb; + ImStb::StbUndoState *undo_state = &stb_state->undostate; Text("ID: 0x%08X, ActiveID: 0x%08X", state->ID, g.ActiveId); DebugLocateItemOnHover(state->ID); - Text("CurLenA: %d, Cursor: %d, Selection: %d..%d", state->TextLen, stb_state->cursor, stb_state->select_start, stb_state->select_end); + Text("CurLenA: %d, Cursor: %d, Selection: %d..%d", state->TextLen, stb_state->cursor, stb_state->select_start, + stb_state->select_end); Text("BufCapacityA: %d", state->BufCapacity); Text("(Internal Buffer: TextA Size: %d, Capacity: %d)", state->TextA.Size, state->TextA.Capacity); Text("has_preferred_x: %d (%.2f)", stb_state->has_preferred_x, stb_state->preferred_x); - Text("undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d", undo_state->undo_point, undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point); - if (BeginChild("undopoints", ImVec2(0.0f, GetTextLineHeight() * 10), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY)) // Visualize undo state + Text("undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d", undo_state->undo_point, + undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point); + if (BeginChild("undopoints", ImVec2(0.0f, GetTextLineHeight() * 10), + ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY)) // Visualize undo state { PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); for (int n = 0; n < IMSTB_TEXTEDIT_UNDOSTATECOUNT; n++) { - ImStb::StbUndoRecord* undo_rec = &undo_state->undo_rec[n]; + ImStb::StbUndoRecord *undo_rec = &undo_state->undo_rec[n]; const char undo_rec_type = (n < undo_state->undo_point) ? 'u' : (n >= undo_state->redo_point) ? 'r' : ' '; if (undo_rec_type == ' ') BeginDisabled(); - const int buf_preview_len = (undo_rec_type != ' ' && undo_rec->char_storage != -1) ? undo_rec->insert_length : 0; - const char* buf_preview_str = undo_state->undo_char + undo_rec->char_storage; - Text("%c [%02d] where %03d, insert %03d, delete %03d, char_storage %03d \"%.*s\"", - undo_rec_type, n, undo_rec->where, undo_rec->insert_length, undo_rec->delete_length, undo_rec->char_storage, buf_preview_len, buf_preview_str); + const int buf_preview_len = + (undo_rec_type != ' ' && undo_rec->char_storage != -1) ? undo_rec->insert_length : 0; + const char *buf_preview_str = undo_state->undo_char + undo_rec->char_storage; + Text("%c [%02d] where %03d, insert %03d, delete %03d, char_storage %03d \"%.*s\"", undo_rec_type, n, + undo_rec->where, undo_rec->insert_length, undo_rec->delete_length, undo_rec->char_storage, + buf_preview_len, buf_preview_str); if (undo_rec_type == ' ') EndDisabled(); } @@ -5526,27 +6410,29 @@ void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state) // - ColorPickerOptionsPopup() [Internal] //------------------------------------------------------------------------- -bool ImGui::ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags) +bool ImGui::ColorEdit3(const char *label, float col[3], ImGuiColorEditFlags flags) { return ColorEdit4(label, col, flags | ImGuiColorEditFlags_NoAlpha); } -static void ColorEditRestoreH(const float* col, float* H) +static void ColorEditRestoreH(const float *col, float *H) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; IM_ASSERT(g.ColorEditCurrentID != 0); - if (g.ColorEditSavedID != g.ColorEditCurrentID || g.ColorEditSavedColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0))) + if (g.ColorEditSavedID != g.ColorEditCurrentID || + g.ColorEditSavedColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0))) return; *H = g.ColorEditSavedHue; } // ColorEdit supports RGB and HSV inputs. In case of RGB input resulting color may have undefined hue and/or saturation. // Since widget displays both RGB and HSV values we must preserve hue and saturation to prevent these values resetting. -static void ColorEditRestoreHS(const float* col, float* H, float* S, float* V) +static void ColorEditRestoreHS(const float *col, float *H, float *S, float *V) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; IM_ASSERT(g.ColorEditCurrentID != 0); - if (g.ColorEditSavedID != g.ColorEditCurrentID || g.ColorEditSavedColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0))) + if (g.ColorEditSavedID != g.ColorEditCurrentID || + g.ColorEditSavedColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0))) return; // When S == 0, H is undefined. @@ -5560,18 +6446,19 @@ static void ColorEditRestoreHS(const float* col, float* H, float* S, float* V) } // Edit colors components (each component in 0.0f..1.0f range). -// See enum ImGuiColorEditFlags_ for available options. e.g. Only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. -// With typical options: Left-click on color square to open color picker. Right-click to open option menu. CTRL+Click over input fields to edit them and TAB to go to next item. -bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags) +// See enum ImGuiColorEditFlags_ for available options. e.g. Only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is +// set. With typical options: Left-click on color square to open color picker. Right-click to open option menu. +// CTRL+Click over input fields to edit them and TAB to go to next item. +bool ImGui::ColorEdit4(const char *label, float col[4], ImGuiColorEditFlags flags) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; + ImGuiContext &g = *GImGui; + const ImGuiStyle &style = g.Style; const float square_sz = GetFrameHeight(); - const char* label_display_end = FindRenderedTextEnd(label); + const char *label_display_end = FindRenderedTextEnd(label); float w_full = CalcItemWidth(); g.NextItemData.ClearFlags(); @@ -5584,7 +6471,8 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag // If we're not showing any slider there's no point in doing any HSV conversions const ImGuiColorEditFlags flags_untouched = flags; if (flags & ImGuiColorEditFlags_NoInputs) - flags = (flags & (~ImGuiColorEditFlags_DisplayMask_)) | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_NoOptions; + flags = (flags & (~ImGuiColorEditFlags_DisplayMask_)) | ImGuiColorEditFlags_DisplayRGB | + ImGuiColorEditFlags_NoOptions; // Context menu: display and modify options (before defaults are applied) if (!(flags & ImGuiColorEditFlags_NoOptions)) @@ -5599,7 +6487,8 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag flags |= (g.ColorEditOptions & ImGuiColorEditFlags_PickerMask_); if (!(flags & ImGuiColorEditFlags_InputMask_)) flags |= (g.ColorEditOptions & ImGuiColorEditFlags_InputMask_); - flags |= (g.ColorEditOptions & ~(ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_)); + flags |= (g.ColorEditOptions & ~(ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_DataTypeMask_ | + ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_)); IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DisplayMask_)); // Check that only 1 is selected IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check that only 1 is selected @@ -5611,7 +6500,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag w_full = w_inputs + w_button; // Convert to the formats we need - float f[4] = { col[0], col[1], col[2], alpha ? col[3] : 1.0f }; + float f[4] = {col[0], col[1], col[2], alpha ? col[3] : 1.0f}; if ((flags & ImGuiColorEditFlags_InputHSV) && (flags & ImGuiColorEditFlags_DisplayRGB)) ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); else if ((flags & ImGuiColorEditFlags_InputRGB) && (flags & ImGuiColorEditFlags_DisplayHSV)) @@ -5620,7 +6509,8 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); ColorEditRestoreHS(col, &f[0], &f[1], &f[2]); } - int i[4] = { IM_F32_TO_INT8_UNBOUND(f[0]), IM_F32_TO_INT8_UNBOUND(f[1]), IM_F32_TO_INT8_UNBOUND(f[2]), IM_F32_TO_INT8_UNBOUND(f[3]) }; + int i[4] = {IM_F32_TO_INT8_UNBOUND(f[0]), IM_F32_TO_INT8_UNBOUND(f[1]), IM_F32_TO_INT8_UNBOUND(f[2]), + IM_F32_TO_INT8_UNBOUND(f[3])}; bool value_changed = false; bool value_changed_as_float = false; @@ -5629,24 +6519,24 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag const float inputs_offset_x = (style.ColorButtonPosition == ImGuiDir_Left) ? w_button : 0.0f; window->DC.CursorPos.x = pos.x + inputs_offset_x; - if ((flags & (ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV)) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0) + if ((flags & (ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV)) != 0 && + (flags & ImGuiColorEditFlags_NoInputs) == 0) { // RGB/HSV 0..255 Sliders const float w_items = w_inputs - style.ItemInnerSpacing.x * (components - 1); - const bool hide_prefix = (IM_TRUNC(w_items / components) <= CalcTextSize((flags & ImGuiColorEditFlags_Float) ? "M:0.000" : "M:000").x); - static const char* ids[4] = { "##X", "##Y", "##Z", "##W" }; - static const char* fmt_table_int[3][4] = - { - { "%3d", "%3d", "%3d", "%3d" }, // Short display - { "R:%3d", "G:%3d", "B:%3d", "A:%3d" }, // Long display for RGBA - { "H:%3d", "S:%3d", "V:%3d", "A:%3d" } // Long display for HSVA + const bool hide_prefix = (IM_TRUNC(w_items / components) <= + CalcTextSize((flags & ImGuiColorEditFlags_Float) ? "M:0.000" : "M:000").x); + static const char *ids[4] = {"##X", "##Y", "##Z", "##W"}; + static const char *fmt_table_int[3][4] = { + {"%3d", "%3d", "%3d", "%3d"}, // Short display + {"R:%3d", "G:%3d", "B:%3d", "A:%3d"}, // Long display for RGBA + {"H:%3d", "S:%3d", "V:%3d", "A:%3d"} // Long display for HSVA }; - static const char* fmt_table_float[3][4] = - { - { "%0.3f", "%0.3f", "%0.3f", "%0.3f" }, // Short display - { "R:%0.3f", "G:%0.3f", "B:%0.3f", "A:%0.3f" }, // Long display for RGBA - { "H:%0.3f", "S:%0.3f", "V:%0.3f", "A:%0.3f" } // Long display for HSVA + static const char *fmt_table_float[3][4] = { + {"%0.3f", "%0.3f", "%0.3f", "%0.3f"}, // Short display + {"R:%0.3f", "G:%0.3f", "B:%0.3f", "A:%0.3f"}, // Long display for RGBA + {"H:%0.3f", "S:%0.3f", "V:%0.3f", "A:%0.3f"} // Long display for HSVA }; const int fmt_idx = hide_prefix ? 0 : (flags & ImGuiColorEditFlags_DisplayHSV) ? 2 : 1; @@ -5659,10 +6549,12 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag SetNextItemWidth(ImMax(next_split - prev_split, 1.0f)); prev_split = next_split; - // FIXME: When ImGuiColorEditFlags_HDR flag is passed HS values snap in weird ways when SV values go below 0. + // FIXME: When ImGuiColorEditFlags_HDR flag is passed HS values snap in weird ways when SV values go below + // 0. if (flags & ImGuiColorEditFlags_Float) { - value_changed |= DragFloat(ids[n], &f[n], 1.0f / 255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); + value_changed |= + DragFloat(ids[n], &f[n], 1.0f / 255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); value_changed_as_float |= value_changed; } else @@ -5678,33 +6570,39 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag // RGB Hexadecimal Input char buf[64]; if (alpha) - ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255), ImClamp(i[3], 0, 255)); + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), + ImClamp(i[2], 0, 255), ImClamp(i[3], 0, 255)); else - ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255)); + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), + ImClamp(i[2], 0, 255)); SetNextItemWidth(w_inputs); if (InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsUppercase)) { value_changed = true; - char* p = buf; + char *p = buf; while (*p == '#' || ImCharIsBlankA(*p)) p++; 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) - 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) + 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 - r = 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", ImGuiPopupFlags_MouseButtonRight); } - ImGuiWindow* picker_active_window = NULL; + ImGuiWindow *picker_active_window = NULL; if (!(flags & ImGuiColorEditFlags_NoSmallPreview)) { - const float button_offset_x = ((flags & ImGuiColorEditFlags_NoInputs) || (style.ColorButtonPosition == ImGuiDir_Left)) ? 0.0f : w_inputs + style.ItemInnerSpacing.x; + const float button_offset_x = + ((flags & ImGuiColorEditFlags_NoInputs) || (style.ColorButtonPosition == ImGuiDir_Left)) + ? 0.0f + : w_inputs + style.ItemInnerSpacing.x; window->DC.CursorPos = ImVec2(pos.x + button_offset_x, pos.y); const ImVec4 col_v4(col[0], col[1], col[2], alpha ? col[3] : 1.0f); @@ -5731,8 +6629,13 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag TextEx(label, label_display_end); Spacing(); } - ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar; - ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf; + ImGuiColorEditFlags picker_flags_to_forward = + ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | + ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | + ImGuiColorEditFlags_AlphaBar; + ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | + ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_NoLabel | + ImGuiColorEditFlags_AlphaPreviewHalf; SetNextItemWidth(square_sz * 12.0f); // Use 256 + bar sizes? value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x); } @@ -5743,9 +6646,11 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag if (label != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel)) { // Position not necessarily next to last submitted button (e.g. if style.ColorButtonPosition == ImGuiDir_Left), - // but we need to use SameLine() to setup baseline correctly. Might want to refactor SameLine() to simplify this. + // but we need to use SameLine() to setup baseline correctly. Might want to refactor SameLine() to simplify + // this. SameLine(0.0f, style.ItemInnerSpacing.x); - window->DC.CursorPos.x = pos.x + ((flags & ImGuiColorEditFlags_NoInputs) ? w_button : w_full + style.ItemInnerSpacing.x); + window->DC.CursorPos.x = + pos.x + ((flags & ImGuiColorEditFlags_NoInputs) ? w_button : w_full + style.ItemInnerSpacing.x); TextEx(label, label_display_end); } @@ -5780,17 +6685,19 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag // Drag and Drop Target // NB: The flag test is merely an optional micro-optimization, BeginDragDropTarget() does the same test. - if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) && !(g.LastItemData.ItemFlags & ImGuiItemFlags_ReadOnly) && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget()) + if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) && + !(g.LastItemData.ItemFlags & ImGuiItemFlags_ReadOnly) && !(flags & ImGuiColorEditFlags_NoDragDrop) && + BeginDragDropTarget()) { bool accepted_drag_drop = false; - if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + if (const ImGuiPayload *payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) { - memcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any //-V512 //-V1086 + memcpy((float *)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any //-V512 //-V1086 value_changed = accepted_drag_drop = true; } - if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + if (const ImGuiPayload *payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) { - memcpy((float*)col, payload->Data, sizeof(float) * components); + memcpy((float *)col, payload->Data, sizeof(float) * components); value_changed = accepted_drag_drop = true; } @@ -5804,45 +6711,55 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag if (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window) g.LastItemData.ID = g.ActiveId; - if (value_changed && g.LastItemData.ID != 0) // In case of ID collision, the second EndGroup() won't catch g.ActiveId + if (value_changed && + g.LastItemData.ID != 0) // In case of ID collision, the second EndGroup() won't catch g.ActiveId MarkItemEdited(g.LastItemData.ID); return value_changed; } -bool ImGui::ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags) +bool ImGui::ColorPicker3(const char *label, float col[3], ImGuiColorEditFlags flags) { - float col4[4] = { col[0], col[1], col[2], 1.0f }; + float col4[4] = {col[0], col[1], col[2], 1.0f}; if (!ColorPicker4(label, col4, flags | ImGuiColorEditFlags_NoAlpha)) return false; - col[0] = col4[0]; col[1] = col4[1]; col[2] = col4[2]; + col[0] = col4[0]; + col[1] = col4[1]; + col[2] = col4[2]; return true; } // Helper for ColorPicker4() -static void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w, float alpha) +static void RenderArrowsForVerticalBar(ImDrawList *draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w, float alpha) { ImU32 alpha8 = IM_F32_TO_INT8_SAT(alpha); - ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x + 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Right, IM_COL32(0,0,0,alpha8)); - ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir_Right, IM_COL32(255,255,255,alpha8)); - ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x - 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Left, IM_COL32(0,0,0,alpha8)); - ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir_Left, IM_COL32(255,255,255,alpha8)); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x + 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), + ImGuiDir_Right, IM_COL32(0, 0, 0, alpha8)); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir_Right, + IM_COL32(255, 255, 255, alpha8)); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x - 1, pos.y), + ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Left, IM_COL32(0, 0, 0, alpha8)); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir_Left, + IM_COL32(255, 255, 255, alpha8)); } // Note: ColorPicker4() only accesses 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. -// (In C++ the 'float col[4]' notation for a function argument is equivalent to 'float* col', we only specify a size to facilitate understanding of the code.) -// FIXME: we adjust the big color square height based on item width, which may cause a flickering feedback loop (if automatic height makes a vertical scrollbar appears, affecting automatic width..) -// FIXME: this is trying to be aware of style.Alpha but not fully correct. Also, the color wheel will have overlapping glitches with (style.Alpha < 1.0) -bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags, const float* ref_col) +// (In C++ the 'float col[4]' notation for a function argument is equivalent to 'float* col', we only specify a size to +// facilitate understanding of the code.) +// FIXME: we adjust the big color square height based on item width, which may cause a flickering feedback loop (if +// automatic height makes a vertical scrollbar appears, affecting automatic width..) +// FIXME: this is trying to be aware of style.Alpha but not fully correct. Also, the color wheel will have overlapping +// glitches with (style.Alpha < 1.0) +bool ImGui::ColorPicker4(const char *label, float col[4], ImGuiColorEditFlags flags, const float *ref_col) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); + ImGuiContext &g = *GImGui; + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImDrawList* draw_list = window->DrawList; - ImGuiStyle& style = g.Style; - ImGuiIO& io = g.IO; + ImDrawList *draw_list = window->DrawList; + ImGuiStyle &style = g.Style; + ImGuiIO &io = g.IO; const float width = CalcItemWidth(); const bool is_readonly = ((g.NextItemData.ItemFlags | g.CurrentItemFlags) & ImGuiItemFlags_ReadOnly) != 0; @@ -5863,9 +6780,13 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl // Read stored options if (!(flags & ImGuiColorEditFlags_PickerMask_)) - flags |= ((g.ColorEditOptions & ImGuiColorEditFlags_PickerMask_) ? g.ColorEditOptions : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_PickerMask_; + flags |= ((g.ColorEditOptions & ImGuiColorEditFlags_PickerMask_) ? g.ColorEditOptions + : ImGuiColorEditFlags_DefaultOptions_) & + ImGuiColorEditFlags_PickerMask_; if (!(flags & ImGuiColorEditFlags_InputMask_)) - flags |= ((g.ColorEditOptions & ImGuiColorEditFlags_InputMask_) ? g.ColorEditOptions : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_InputMask_; + flags |= ((g.ColorEditOptions & ImGuiColorEditFlags_InputMask_) ? g.ColorEditOptions + : ImGuiColorEditFlags_DefaultOptions_) & + ImGuiColorEditFlags_InputMask_; IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_PickerMask_)); // Check that only 1 is selected IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check that only 1 is selected if (!(flags & ImGuiColorEditFlags_NoOptions)) @@ -5877,7 +6798,9 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl ImVec2 picker_pos = window->DC.CursorPos; float square_sz = GetFrameHeight(); float bars_width = square_sz; // Arbitrary smallish width of Hue/Alpha picking bars - float sv_picker_size = ImMax(bars_width * 1, width - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box + float sv_picker_size = + ImMax(bars_width * 1, + width - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box float bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x; float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x; float bars_triangles_half_sz = IM_TRUNC(bars_width * 0.20f); @@ -5888,11 +6811,12 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl float wheel_thickness = sv_picker_size * 0.08f; float wheel_r_outer = sv_picker_size * 0.50f; float wheel_r_inner = wheel_r_outer - wheel_thickness; - ImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width)*0.5f, picker_pos.y + sv_picker_size * 0.5f); + ImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width) * 0.5f, picker_pos.y + sv_picker_size * 0.5f); - // Note: the triangle is displayed rotated with triangle_pa pointing to Hue, but most coordinates stays unrotated for logic. + // Note: the triangle is displayed rotated with triangle_pa pointing to Hue, but most coordinates stays unrotated + // for logic. float triangle_r = wheel_r_inner - (int)(sv_picker_size * 0.027f); - ImVec2 triangle_pa = ImVec2(triangle_r, 0.0f); // Hue point. + ImVec2 triangle_pa = ImVec2(triangle_r, 0.0f); // Hue point. ImVec2 triangle_pb = ImVec2(triangle_r * -0.5f, triangle_r * -0.866025f); // Black point. ImVec2 triangle_pc = ImVec2(triangle_r * -0.5f, triangle_r * +0.866025f); // White point. @@ -5921,7 +6845,8 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl ImVec2 initial_off = g.IO.MouseClickedPos[0] - wheel_center; ImVec2 current_off = g.IO.MousePos - wheel_center; float initial_dist2 = ImLengthSqr(initial_off); - if (initial_dist2 >= (wheel_r_inner - 1) * (wheel_r_inner - 1) && initial_dist2 <= (wheel_r_outer + 1) * (wheel_r_outer + 1)) + if (initial_dist2 >= (wheel_r_inner - 1) * (wheel_r_inner - 1) && + initial_dist2 <= (wheel_r_outer + 1) * (wheel_r_outer + 1)) { // Interactive with Hue wheel H = ImAtan2(current_off.y, current_off.x) / IM_PI * 0.5f; @@ -5931,12 +6856,14 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl } float cos_hue_angle = ImCos(-H * 2.0f * IM_PI); float sin_hue_angle = ImSin(-H * 2.0f * IM_PI); - if (ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, ImRotate(initial_off, cos_hue_angle, sin_hue_angle))) + if (ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, + ImRotate(initial_off, cos_hue_angle, sin_hue_angle))) { // Interacting with SV triangle ImVec2 current_off_unrotated = ImRotate(current_off, cos_hue_angle, sin_hue_angle); if (!ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated)) - current_off_unrotated = ImTriangleClosestPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated); + current_off_unrotated = + ImTriangleClosestPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated); float uu, vv, ww; ImTriangleBarycentricCoords(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated, uu, vv, ww); V = ImClamp(1.0f - vv, 0.0001f, 1.0f); @@ -5955,7 +6882,8 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl { S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size - 1)); V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1)); - ColorEditRestoreH(col, &H); // Greatly reduces hue jitter and reset to 0 when hue == 255 and color is rapidly modified using SV square. + ColorEditRestoreH(col, &H); // Greatly reduces hue jitter and reset to 0 when hue == 255 and color is + // rapidly modified using SV square. value_changed = value_changed_sv = true; } if (!(flags & ImGuiColorEditFlags_NoOptions)) @@ -5992,7 +6920,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl if (!(flags & ImGuiColorEditFlags_NoLabel)) { - const char* label_display_end = FindRenderedTextEnd(label); + const char *label_display_end = FindRenderedTextEnd(label); if (label != label_display_end) { if ((flags & ImGuiColorEditFlags_NoSidePreview)) @@ -6008,13 +6936,16 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl if ((flags & ImGuiColorEditFlags_NoLabel)) Text("Current"); - ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaMask_ | ImGuiColorEditFlags_NoTooltip; + ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | + ImGuiColorEditFlags_AlphaMask_ | ImGuiColorEditFlags_NoTooltip; ColorButton("##current", col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2)); if (ref_col != NULL) { Text("Original"); - ImVec4 ref_col_v4(ref_col[0], ref_col[1], ref_col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : ref_col[3]); - if (ColorButton("##original", ref_col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2))) + ImVec4 ref_col_v4(ref_col[0], ref_col[1], ref_col[2], + (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : ref_col[3]); + if (ColorButton("##original", ref_col_v4, (flags & sub_flags_to_forward), + ImVec2(square_sz * 3, square_sz * 2))) { memcpy(col, ref_col, components * sizeof(float)); value_changed = true; @@ -6048,13 +6979,17 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl if ((flags & ImGuiColorEditFlags_NoInputs) == 0) { PushItemWidth((alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x); - ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaMask_ | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoSmallPreview; + ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_InputMask_ | + ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaMask_ | + ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoTooltip | + ImGuiColorEditFlags_NoSmallPreview; ImGuiColorEditFlags sub_flags = (flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker; if (flags & ImGuiColorEditFlags_DisplayRGB || (flags & ImGuiColorEditFlags_DisplayMask_) == 0) if (ColorEdit4("##rgb", col, sub_flags | ImGuiColorEditFlags_DisplayRGB)) { - // FIXME: Hackily differentiating using the DragInt (ActiveId != 0 && !ActiveIdAllowOverlap) vs. using the InputText or DropTarget. - // For the later we don't want to run the hue-wrap canceling code. If you are well versed in HSV picker please provide your input! (See #2050) + // FIXME: Hackily differentiating using the DragInt (ActiveId != 0 && !ActiveIdAllowOverlap) vs. using + // the InputText or DropTarget. For the later we don't want to run the hue-wrap canceling code. If you + // are well versed in HSV picker please provide your input! (See #2050) value_changed_fix_hue_wrap = (g.ActiveId != 0 && !g.ActiveIdAllowOverlap); value_changed = true; } @@ -6087,7 +7022,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl G = col[1]; B = col[2]; ColorConvertRGBtoHSV(R, G, B, H, S, V); - ColorEditRestoreHS(col, &H, &S, &V); // Fix local Hue as display below will use it immediately. + ColorEditRestoreHS(col, &H, &S, &V); // Fix local Hue as display below will use it immediately. } else if (flags & ImGuiColorEditFlags_InputHSV) { @@ -6099,14 +7034,19 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl } const int style_alpha8 = IM_F32_TO_INT8_SAT(style.Alpha); - const ImU32 col_black = IM_COL32(0,0,0,style_alpha8); - const ImU32 col_white = IM_COL32(255,255,255,style_alpha8); - const ImU32 col_midgrey = IM_COL32(128,128,128,style_alpha8); - const ImU32 col_hues[6 + 1] = { IM_COL32(255,0,0,style_alpha8), IM_COL32(255,255,0,style_alpha8), IM_COL32(0,255,0,style_alpha8), IM_COL32(0,255,255,style_alpha8), IM_COL32(0,0,255,style_alpha8), IM_COL32(255,0,255,style_alpha8), IM_COL32(255,0,0,style_alpha8) }; + const ImU32 col_black = IM_COL32(0, 0, 0, style_alpha8); + const ImU32 col_white = IM_COL32(255, 255, 255, style_alpha8); + const ImU32 col_midgrey = IM_COL32(128, 128, 128, style_alpha8); + const ImU32 col_hues[6 + 1] = {IM_COL32(255, 0, 0, style_alpha8), IM_COL32(255, 255, 0, style_alpha8), + IM_COL32(0, 255, 0, style_alpha8), IM_COL32(0, 255, 255, style_alpha8), + IM_COL32(0, 0, 255, style_alpha8), IM_COL32(255, 0, 255, style_alpha8), + IM_COL32(255, 0, 0, style_alpha8)}; - ImVec4 hue_color_f(1, 1, 1, style.Alpha); ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z); + ImVec4 hue_color_f(1, 1, 1, style.Alpha); + ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z); ImU32 hue_color32 = ColorConvertFloat4ToU32(hue_color_f); - ImU32 user_col32_striped_of_alpha = ColorConvertFloat4ToU32(ImVec4(R, G, B, style.Alpha)); // Important: this is still including the main rendering/style alpha!! + ImU32 user_col32_striped_of_alpha = ColorConvertFloat4ToU32( + ImVec4(R, G, B, style.Alpha)); // Important: this is still including the main rendering/style alpha!! ImVec2 sv_cursor_pos; @@ -6117,25 +7057,28 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl const int segment_per_arc = ImMax(4, (int)wheel_r_outer / 12); for (int n = 0; n < 6; n++) { - const float a0 = (n) /6.0f * 2.0f * IM_PI - aeps; - const float a1 = (n+1.0f)/6.0f * 2.0f * IM_PI + aeps; + const float a0 = (n) / 6.0f * 2.0f * IM_PI - aeps; + 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->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer) * 0.5f, a0, a1, segment_per_arc); draw_list->PathStroke(col_white, 0, wheel_thickness); const int vert_end_idx = draw_list->VtxBuffer.Size; // Paint colors over existing vertices ImVec2 gradient_p0(wheel_center.x + ImCos(a0) * wheel_r_inner, wheel_center.y + ImSin(a0) * wheel_r_inner); ImVec2 gradient_p1(wheel_center.x + ImCos(a1) * wheel_r_inner, wheel_center.y + ImSin(a1) * wheel_r_inner); - ShadeVertsLinearColorGradientKeepAlpha(draw_list, vert_start_idx, vert_end_idx, gradient_p0, gradient_p1, col_hues[n], col_hues[n + 1]); + ShadeVertsLinearColorGradientKeepAlpha(draw_list, vert_start_idx, vert_end_idx, gradient_p0, gradient_p1, + col_hues[n], col_hues[n + 1]); } // Render Cursor + preview on Hue Wheel float cos_hue_angle = ImCos(H * 2.0f * IM_PI); float sin_hue_angle = ImSin(H * 2.0f * IM_PI); - ImVec2 hue_cursor_pos(wheel_center.x + cos_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f, wheel_center.y + sin_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f); + ImVec2 hue_cursor_pos(wheel_center.x + cos_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f, + wheel_center.y + sin_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f); float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f; - int hue_cursor_segments = draw_list->_CalcCircleAutoSegmentCount(hue_cursor_rad); // Lock segment count so the +1 one matches others. + int hue_cursor_segments = + draw_list->_CalcCircleAutoSegmentCount(hue_cursor_rad); // Lock segment count so the +1 one matches others. draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments); draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad + 1, col_midgrey, hue_cursor_segments); draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, col_white, hue_cursor_segments); @@ -6155,23 +7098,36 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl else if (flags & ImGuiColorEditFlags_PickerHueBar) { // Render SV Square - draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), col_white, hue_color32, hue_color32, col_white); - draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0, 0, col_black, col_black); + draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), col_white, + hue_color32, hue_color32, col_white); + draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0, 0, + col_black, col_black); RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0.0f); - sv_cursor_pos.x = ImClamp(IM_ROUND(picker_pos.x + ImSaturate(S) * sv_picker_size), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2); // Sneakily prevent the circle to stick out too much - sv_cursor_pos.y = ImClamp(IM_ROUND(picker_pos.y + ImSaturate(1 - V) * sv_picker_size), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2); + sv_cursor_pos.x = + ImClamp(IM_ROUND(picker_pos.x + ImSaturate(S) * sv_picker_size), picker_pos.x + 2, + picker_pos.x + sv_picker_size - 2); // Sneakily prevent the circle to stick out too much + sv_cursor_pos.y = ImClamp(IM_ROUND(picker_pos.y + ImSaturate(1 - V) * sv_picker_size), picker_pos.y + 2, + picker_pos.y + sv_picker_size - 2); // Render Hue Bar for (int i = 0; i < 6; ++i) - draw_list->AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), col_hues[i], col_hues[i], col_hues[i + 1], col_hues[i + 1]); + draw_list->AddRectFilledMultiColor( + ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), + ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), col_hues[i], + col_hues[i], col_hues[i + 1], col_hues[i + 1]); float bar0_line_y = IM_ROUND(picker_pos.y + H * sv_picker_size); - RenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0f); - RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha); + RenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), + ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0f); + RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), + ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, + style.Alpha); } - // Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to be out of range) + // Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to + // be out of range) float sv_cursor_rad = value_changed_sv ? wheel_thickness * 0.55f : wheel_thickness * 0.40f; - int sv_cursor_segments = draw_list->_CalcCircleAutoSegmentCount(sv_cursor_rad); // Lock segment count so the +1 one matches others. + int sv_cursor_segments = + draw_list->_CalcCircleAutoSegmentCount(sv_cursor_rad); // Lock segment count so the +1 one matches others. draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, user_col32_striped_of_alpha, sv_cursor_segments); draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad + 1, col_midgrey, sv_cursor_segments); draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, col_white, sv_cursor_segments); @@ -6181,18 +7137,24 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl { float alpha = ImSaturate(col[3]); ImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size); - RenderColorRectWithAlphaCheckerboard(draw_list, bar1_bb.Min, bar1_bb.Max, 0, bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f)); - draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, user_col32_striped_of_alpha, user_col32_striped_of_alpha, user_col32_striped_of_alpha & ~IM_COL32_A_MASK, user_col32_striped_of_alpha & ~IM_COL32_A_MASK); + RenderColorRectWithAlphaCheckerboard(draw_list, bar1_bb.Min, bar1_bb.Max, 0, bar1_bb.GetWidth() / 2.0f, + ImVec2(0.0f, 0.0f)); + draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, user_col32_striped_of_alpha, + user_col32_striped_of_alpha, user_col32_striped_of_alpha & ~IM_COL32_A_MASK, + user_col32_striped_of_alpha & ~IM_COL32_A_MASK); float bar1_line_y = IM_ROUND(picker_pos.y + (1.0f - alpha) * sv_picker_size); RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f); - RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha); + RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), + ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, + style.Alpha); } EndGroup(); if (value_changed && memcmp(backup_initial_col, col, components * sizeof(float)) == 0) value_changed = false; - if (value_changed && g.LastItemData.ID != 0) // In case of ID collision, the second EndGroup() won't catch g.ActiveId + if (value_changed && + g.LastItemData.ID != 0) // In case of ID collision, the second EndGroup() won't catch g.ActiveId MarkItemEdited(g.LastItemData.ID); if (set_current_color_edit_id) @@ -6206,13 +7168,13 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl // FIXME: May want to display/ignore the alpha component in the color display? Yet show it in the tooltip. // 'desc_id' is not called 'label' because we don't display it next to the button, but only in the tooltip. // Note that 'col' may be encoded in HSV if ImGuiColorEditFlags_InputHSV is set. -bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags, const ImVec2& size_arg) +bool ImGui::ColorButton(const char *desc_id, const ImVec4 &col, ImGuiColorEditFlags flags, const ImVec2 &size_arg) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; const ImGuiID id = window->GetID(desc_id); const float default_size = GetFrameHeight(); const ImVec2 size(size_arg.x == 0.0f ? default_size : size_arg.x, size_arg.y == 0.0f ? default_size : size_arg.y); @@ -6238,24 +7200,32 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl float off = 0.0f; if ((flags & ImGuiColorEditFlags_NoBorder) == 0) { - off = -0.75f; // The border (using Col_FrameBg) tends to look off when color is near-opaque and rounding is enabled. This offset seemed like a good middle ground to reduce those artifacts. + off = -0.75f; // The border (using Col_FrameBg) tends to look off when color is near-opaque and rounding is + // enabled. This offset seemed like a good middle ground to reduce those artifacts. bb_inner.Expand(off); } if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb.w < 1.0f) { float mid_x = IM_ROUND((bb_inner.Min.x + bb_inner.Max.x) * 0.5f); if ((flags & ImGuiColorEditFlags_AlphaNoBg) == 0) - 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); + 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); else - window->DrawList->AddRectFilled(ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), rounding, ImDrawFlags_RoundCornersRight); - window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawFlags_RoundCornersLeft); + window->DrawList->AddRectFilled(ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, + GetColorU32(col_rgb), 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 { - // Because GetColorU32() multiplies by the global style Alpha and we don't want to display a checkerboard if the source code had no alpha + // Because GetColorU32() multiplies by the global style Alpha and we don't want to display a checkerboard if the + // source code had no alpha ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaOpaque) ? col_rgb_without_alpha : col_rgb; if (col_source.w < 1.0f && (flags & ImGuiColorEditFlags_AlphaNoBg) == 0) - RenderColorRectWithAlphaCheckerboard(window->DrawList, bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding); + 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); } @@ -6265,7 +7235,8 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl if (g.Style.FrameBorderSize > 0.0f) RenderFrameBorder(bb.Min, bb.Max, rounding); else - window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color buttons are often in need of some sort of border // FIXME-DPI + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), + rounding); // Color buttons are often in need of some sort of border // FIXME-DPI } // Drag and Drop Source @@ -6292,7 +7263,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl // Initialize/override default color options void ImGui::SetColorEditOptions(ImGuiColorEditFlags flags) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; if ((flags & ImGuiColorEditFlags_DisplayMask_) == 0) flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DisplayMask_; if ((flags & ImGuiColorEditFlags_DataTypeMask_) == 0) @@ -6301,21 +7272,21 @@ void ImGui::SetColorEditOptions(ImGuiColorEditFlags flags) flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_PickerMask_; if ((flags & ImGuiColorEditFlags_InputMask_) == 0) flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_InputMask_; - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DisplayMask_)); // Check only 1 option is selected - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DataTypeMask_)); // Check only 1 option is selected - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_PickerMask_)); // Check only 1 option is selected - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DisplayMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DataTypeMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_PickerMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check only 1 option is selected g.ColorEditOptions = flags; } // Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. -void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags) +void ImGui::ColorTooltip(const char *text, const float *col, ImGuiColorEditFlags flags) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; if (!BeginTooltipEx(ImGuiTooltipFlags_OverridePrevious, ImGuiWindowFlags_None)) return; - const char* text_end = text ? FindRenderedTextEnd(text, NULL) : text; + const char *text_end = text ? FindRenderedTextEnd(text, NULL) : text; if (text_end > text) { TextEx(text, text_end); @@ -6324,16 +7295,19 @@ void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags ImVec2 sz(g.FontSize * 3 + g.Style.FramePadding.y * 2, g.FontSize * 3 + g.Style.FramePadding.y * 2); ImVec4 cf(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); - int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); + int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), + ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); ImGuiColorEditFlags flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_AlphaMask_; ColorButton("##preview", cf, (flags & flags_to_forward) | ImGuiColorEditFlags_NoTooltip, sz); SameLine(); if ((flags & ImGuiColorEditFlags_InputRGB) || !(flags & ImGuiColorEditFlags_InputMask_)) { if (flags & ImGuiColorEditFlags_NoAlpha) - Text("#%02X%02X%02X\nR: %d, G: %d, B: %d\n(%.3f, %.3f, %.3f)", cr, cg, cb, cr, cg, cb, col[0], col[1], col[2]); + Text("#%02X%02X%02X\nR: %d, G: %d, B: %d\n(%.3f, %.3f, %.3f)", cr, cg, cb, cr, cg, cb, col[0], col[1], + col[2]); else - Text("#%02X%02X%02X%02X\nR:%d, G:%d, B:%d, A:%d\n(%.3f, %.3f, %.3f, %.3f)", cr, cg, cb, ca, cr, cg, cb, ca, col[0], col[1], col[2], col[3]); + Text("#%02X%02X%02X%02X\nR:%d, G:%d, B:%d, A:%d\n(%.3f, %.3f, %.3f, %.3f)", cr, cg, cb, ca, cr, cg, cb, ca, + col[0], col[1], col[2], col[3]); } else if (flags & ImGuiColorEditFlags_InputHSV) { @@ -6345,27 +7319,33 @@ void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags EndTooltip(); } -void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) +void ImGui::ColorEditOptionsPopup(const float *col, ImGuiColorEditFlags flags) { bool allow_opt_inputs = !(flags & ImGuiColorEditFlags_DisplayMask_); bool allow_opt_datatype = !(flags & ImGuiColorEditFlags_DataTypeMask_); if ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup("context")) return; - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; PushItemFlag(ImGuiItemFlags_NoMarkEdited, true); ImGuiColorEditFlags opts = g.ColorEditOptions; if (allow_opt_inputs) { - if (RadioButton("RGB", (opts & ImGuiColorEditFlags_DisplayRGB) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayRGB; - if (RadioButton("HSV", (opts & ImGuiColorEditFlags_DisplayHSV) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayHSV; - if (RadioButton("Hex", (opts & ImGuiColorEditFlags_DisplayHex) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayHex; + if (RadioButton("RGB", (opts & ImGuiColorEditFlags_DisplayRGB) != 0)) + opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayRGB; + if (RadioButton("HSV", (opts & ImGuiColorEditFlags_DisplayHSV) != 0)) + opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayHSV; + if (RadioButton("Hex", (opts & ImGuiColorEditFlags_DisplayHex) != 0)) + opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayHex; } if (allow_opt_datatype) { - if (allow_opt_inputs) Separator(); - if (RadioButton("0..255", (opts & ImGuiColorEditFlags_Uint8) != 0)) opts = (opts & ~ImGuiColorEditFlags_DataTypeMask_) | ImGuiColorEditFlags_Uint8; - if (RadioButton("0.00..1.00", (opts & ImGuiColorEditFlags_Float) != 0)) opts = (opts & ~ImGuiColorEditFlags_DataTypeMask_) | ImGuiColorEditFlags_Float; + if (allow_opt_inputs) + Separator(); + if (RadioButton("0..255", (opts & ImGuiColorEditFlags_Uint8) != 0)) + opts = (opts & ~ImGuiColorEditFlags_DataTypeMask_) | ImGuiColorEditFlags_Uint8; + if (RadioButton("0.00..1.00", (opts & ImGuiColorEditFlags_Float) != 0)) + opts = (opts & ~ImGuiColorEditFlags_DataTypeMask_) | ImGuiColorEditFlags_Float; } if (allow_opt_inputs || allow_opt_datatype) @@ -6374,9 +7354,11 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) OpenPopup("Copy"); if (BeginPopup("Copy")) { - int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); + int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), + ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); char buf[64]; - ImFormatString(buf, IM_ARRAYSIZE(buf), "(%.3ff, %.3ff, %.3ff, %.3ff)", col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); + ImFormatString(buf, IM_ARRAYSIZE(buf), "(%.3ff, %.3ff, %.3ff, %.3ff)", col[0], col[1], col[2], + (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); if (Selectable(buf)) SetClipboardText(buf); ImFormatString(buf, IM_ARRAYSIZE(buf), "(%d,%d,%d,%d)", cr, cg, cb, ca); @@ -6399,33 +7381,41 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) EndPopup(); } -void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags) +void ImGui::ColorPickerOptionsPopup(const float *ref_col, ImGuiColorEditFlags flags) { bool allow_opt_picker = !(flags & ImGuiColorEditFlags_PickerMask_); bool allow_opt_alpha_bar = !(flags & ImGuiColorEditFlags_NoAlpha) && !(flags & ImGuiColorEditFlags_AlphaBar); if ((!allow_opt_picker && !allow_opt_alpha_bar) || !BeginPopup("context")) return; - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; PushItemFlag(ImGuiItemFlags_NoMarkEdited, true); if (allow_opt_picker) { - ImVec2 picker_size(g.FontSize * 8, ImMax(g.FontSize * 8 - (GetFrameHeight() + g.Style.ItemInnerSpacing.x), 1.0f)); // FIXME: Picker size copied from main picker function + ImVec2 picker_size(g.FontSize * 8, ImMax(g.FontSize * 8 - (GetFrameHeight() + g.Style.ItemInnerSpacing.x), + 1.0f)); // FIXME: Picker size copied from main picker function PushItemWidth(picker_size.x); for (int picker_type = 0; picker_type < 2; picker_type++) { // Draw small/thumbnail version of each picker type (over an invisible button for selection) - if (picker_type > 0) Separator(); + if (picker_type > 0) + Separator(); PushID(picker_type); - ImGuiColorEditFlags picker_flags = ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoSidePreview | (flags & ImGuiColorEditFlags_NoAlpha); - if (picker_type == 0) picker_flags |= ImGuiColorEditFlags_PickerHueBar; - if (picker_type == 1) picker_flags |= ImGuiColorEditFlags_PickerHueWheel; + ImGuiColorEditFlags picker_flags = ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoOptions | + ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoSidePreview | + (flags & ImGuiColorEditFlags_NoAlpha); + if (picker_type == 0) + picker_flags |= ImGuiColorEditFlags_PickerHueBar; + if (picker_type == 1) + picker_flags |= ImGuiColorEditFlags_PickerHueWheel; ImVec2 backup_pos = GetCursorScreenPos(); if (Selectable("##selectable", false, 0, picker_size)) // By default, Selectable() is closing popup - g.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags_PickerMask_) | (picker_flags & ImGuiColorEditFlags_PickerMask_); + g.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags_PickerMask_) | + (picker_flags & ImGuiColorEditFlags_PickerMask_); SetCursorScreenPos(backup_pos); ImVec4 previewing_ref_col; - memcpy(&previewing_ref_col, ref_col, sizeof(float) * ((picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4)); + memcpy(&previewing_ref_col, ref_col, + sizeof(float) * ((picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4)); ColorPicker4("##previewing_picker", &previewing_ref_col.x, picker_flags); PopID(); } @@ -6433,7 +7423,8 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl } if (allow_opt_alpha_bar) { - if (allow_opt_picker) Separator(); + if (allow_opt_picker) + Separator(); CheckboxFlags("Alpha Bar", &g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar); } PopItemFlag(); @@ -6456,7 +7447,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl // - CollapsingHeader() //------------------------------------------------------------------------- -bool ImGui::TreeNode(const char* str_id, const char* fmt, ...) +bool ImGui::TreeNode(const char *str_id, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -6465,7 +7456,7 @@ bool ImGui::TreeNode(const char* str_id, const char* fmt, ...) return is_open; } -bool ImGui::TreeNode(const void* ptr_id, const char* fmt, ...) +bool ImGui::TreeNode(const void *ptr_id, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -6474,35 +7465,35 @@ bool ImGui::TreeNode(const void* ptr_id, const char* fmt, ...) return is_open; } -bool ImGui::TreeNode(const char* label) +bool ImGui::TreeNode(const char *label) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; ImGuiID id = window->GetID(label); return TreeNodeBehavior(id, ImGuiTreeNodeFlags_None, label, NULL); } -bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args) +bool ImGui::TreeNodeV(const char *str_id, const char *fmt, va_list args) { return TreeNodeExV(str_id, 0, fmt, args); } -bool ImGui::TreeNodeV(const void* ptr_id, const char* fmt, va_list args) +bool ImGui::TreeNodeV(const void *ptr_id, const char *fmt, va_list args) { return TreeNodeExV(ptr_id, 0, fmt, args); } -bool ImGui::TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags) +bool ImGui::TreeNodeEx(const char *label, ImGuiTreeNodeFlags flags) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; ImGuiID id = window->GetID(label); return TreeNodeBehavior(id, flags, label, NULL); } -bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) +bool ImGui::TreeNodeEx(const char *str_id, ImGuiTreeNodeFlags flags, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -6511,7 +7502,7 @@ bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* return is_open; } -bool ImGui::TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) +bool ImGui::TreeNodeEx(const void *ptr_id, ImGuiTreeNodeFlags flags, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -6520,41 +7511,41 @@ bool ImGui::TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* return is_open; } -bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) +bool ImGui::TreeNodeExV(const char *str_id, ImGuiTreeNodeFlags flags, const char *fmt, va_list args) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; ImGuiID id = window->GetID(str_id); - const char* label, *label_end; + const char *label, *label_end; ImFormatStringToTempBufferV(&label, &label_end, fmt, args); return TreeNodeBehavior(id, flags, label, label_end); } -bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) +bool ImGui::TreeNodeExV(const void *ptr_id, ImGuiTreeNodeFlags flags, const char *fmt, va_list args) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; ImGuiID id = window->GetID(ptr_id); - const char* label, *label_end; + const char *label, *label_end; ImFormatStringToTempBufferV(&label, &label_end, fmt, args); return TreeNodeBehavior(id, flags, label, label_end); } bool ImGui::TreeNodeGetOpen(ImGuiID storage_id) { - ImGuiContext& g = *GImGui; - ImGuiStorage* storage = g.CurrentWindow->DC.StateStorage; + ImGuiContext &g = *GImGui; + ImGuiStorage *storage = g.CurrentWindow->DC.StateStorage; return storage->GetInt(storage_id, 0) != 0; } void ImGui::TreeNodeSetOpen(ImGuiID storage_id, bool open) { - ImGuiContext& g = *GImGui; - ImGuiStorage* storage = g.CurrentWindow->DC.StateStorage; + ImGuiContext &g = *GImGui; + ImGuiStorage *storage = g.CurrentWindow->DC.StateStorage; storage->SetInt(storage_id, open ? 1 : 0); } @@ -6564,9 +7555,9 @@ bool ImGui::TreeNodeUpdateNextOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags) return true; // We only write to the tree storage if the user clicks, or explicitly use the SetNextItemOpen function - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - ImGuiStorage* storage = window->DC.StateStorage; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; + ImGuiStorage *storage = window->DC.StateStorage; bool is_open; if (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasOpen) @@ -6578,7 +7569,8 @@ bool ImGui::TreeNodeUpdateNextOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags) } else { - // We treat ImGuiCond_Once and ImGuiCond_FirstUseEver the same because tree node state are not saved persistently. + // We treat ImGuiCond_Once and ImGuiCond_FirstUseEver the same because tree node state are not saved + // persistently. const int stored_value = storage->GetInt(storage_id, -1); if (stored_value == -1) { @@ -6596,9 +7588,10 @@ bool ImGui::TreeNodeUpdateNextOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags) is_open = storage->GetInt(storage_id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0; } - // When logging is enabled, we automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behavior). - // NB- If we are above max depth we still allow manually opened nodes to be logged. - if (g.LogEnabled && !(flags & ImGuiTreeNodeFlags_NoAutoOpenOnLog) && (window->DC.TreeDepth - g.LogDepthRef) < g.LogDepthToExpand) + // When logging is enabled, we automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible + // behavior). NB- If we are above max depth we still allow manually opened nodes to be logged. + if (g.LogEnabled && !(flags & ImGuiTreeNodeFlags_NoAutoOpenOnLog) && + (window->DC.TreeDepth - g.LogDepthRef) < g.LogDepthToExpand) is_open = true; return is_open; @@ -6608,58 +7601,72 @@ bool ImGui::TreeNodeUpdateNextOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags) // Currently only supports 32 level deep and we are fine with (1 << Depth) overflowing into a zero, easy to increase. static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags, float x1) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; g.TreeNodeStack.resize(g.TreeNodeStack.Size + 1); - ImGuiTreeNodeStackData* tree_node_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; + ImGuiTreeNodeStackData *tree_node_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; tree_node_data->ID = g.LastItemData.ID; tree_node_data->TreeFlags = flags; tree_node_data->ItemFlags = g.LastItemData.ItemFlags; tree_node_data->NavRect = g.LastItemData.NavRect; - // Initially I tried to latch value for GetColorU32(ImGuiCol_TreeLines) but it's not a good trade-off for very large trees. + // Initially I tried to latch value for GetColorU32(ImGuiCol_TreeLines) but it's not a good trade-off for very large + // trees. const bool draw_lines = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) != 0; tree_node_data->DrawLinesX1 = draw_lines ? (x1 + g.FontSize * 0.5f + g.Style.FramePadding.x) : +FLT_MAX; - tree_node_data->DrawLinesTableColumn = (draw_lines && g.CurrentTable) ? (ImGuiTableColumnIdx)g.CurrentTable->CurrentColumn : -1; + tree_node_data->DrawLinesTableColumn = + (draw_lines && g.CurrentTable) ? (ImGuiTableColumnIdx)g.CurrentTable->CurrentColumn : -1; tree_node_data->DrawLinesToNodesY2 = -FLT_MAX; window->DC.TreeHasStackDataDepthMask |= (1 << window->DC.TreeDepth); if (flags & ImGuiTreeNodeFlags_DrawLinesToNodes) window->DC.TreeRecordsClippedNodesY2Mask |= (1 << window->DC.TreeDepth); } -// When using public API, currently 'id == storage_id' is always true, but we separate the values to facilitate advanced user code doing storage queries outside of UI loop. -bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end) +// When using public API, currently 'id == storage_id' is always true, but we separate the values to facilitate advanced +// user code doing storage queries outside of UI loop. +bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char *label, const char *label_end) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; + ImGuiContext &g = *GImGui; + const ImGuiStyle &style = g.Style; const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0; - const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, ImMin(window->DC.CurrLineTextBaseOffset, style.FramePadding.y)); + const ImVec2 padding = + (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) + ? style.FramePadding + : ImVec2(style.FramePadding.x, ImMin(window->DC.CurrLineTextBaseOffset, style.FramePadding.y)); if (!label_end) label_end = FindRenderedTextEnd(label); const ImVec2 label_size = CalcTextSize(label, label_end, false); - const float text_offset_x = g.FontSize + (display_frame ? padding.x * 3 : padding.x * 2); // Collapsing arrow width + Spacing - const float text_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it - const float text_width = g.FontSize + label_size.x + padding.x * 2; // Include collapsing arrow + const float text_offset_x = + g.FontSize + (display_frame ? padding.x * 3 : padding.x * 2); // Collapsing arrow width + Spacing + const float text_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it + const float text_width = g.FontSize + label_size.x + padding.x * 2; // Include collapsing arrow // We vertically grow up to current line height up the typical widget height. - const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), label_size.y + padding.y * 2); + const float frame_height = + ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), label_size.y + padding.y * 2); const bool span_all_columns = (flags & ImGuiTreeNodeFlags_SpanAllColumns) != 0 && (g.CurrentTable != NULL); - const bool span_all_columns_label = (flags & ImGuiTreeNodeFlags_LabelSpanAllColumns) != 0 && (g.CurrentTable != NULL); + const bool span_all_columns_label = + (flags & ImGuiTreeNodeFlags_LabelSpanAllColumns) != 0 && (g.CurrentTable != NULL); ImRect frame_bb; - frame_bb.Min.x = span_all_columns ? window->ParentWorkRect.Min.x : (flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window->WorkRect.Min.x : window->DC.CursorPos.x; + frame_bb.Min.x = span_all_columns ? window->ParentWorkRect.Min.x + : (flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window->WorkRect.Min.x + : window->DC.CursorPos.x; frame_bb.Min.y = window->DC.CursorPos.y; - frame_bb.Max.x = span_all_columns ? window->ParentWorkRect.Max.x : (flags & ImGuiTreeNodeFlags_SpanLabelWidth) ? window->DC.CursorPos.x + text_width + padding.x : window->WorkRect.Max.x; + frame_bb.Max.x = span_all_columns ? window->ParentWorkRect.Max.x + : (flags & ImGuiTreeNodeFlags_SpanLabelWidth) ? window->DC.CursorPos.x + text_width + padding.x + : window->WorkRect.Max.x; frame_bb.Max.y = window->DC.CursorPos.y + frame_height; if (display_frame) { - const float outer_extend = IM_TRUNC(window->WindowPadding.x * 0.5f); // Framed header expand a little outside of current limits + const float outer_extend = + IM_TRUNC(window->WindowPadding.x * 0.5f); // Framed header expand a little outside of current limits frame_bb.Min.x -= outer_extend; frame_bb.Max.x += outer_extend; } @@ -6669,17 +7676,20 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing ImRect interact_bb = frame_bb; - if ((flags & (ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_SpanLabelWidth | ImGuiTreeNodeFlags_SpanAllColumns)) == 0) + if ((flags & (ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth | + ImGuiTreeNodeFlags_SpanLabelWidth | ImGuiTreeNodeFlags_SpanAllColumns)) == 0) interact_bb.Max.x = frame_bb.Min.x + text_width + (label_size.x > 0.0f ? style.ItemSpacing.x * 2.0f : 0.0f); // Compute open and multi-select states before ItemAdd() as it clear NextItem data. - ImGuiID storage_id = (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasStorageID) ? g.NextItemData.StorageId : id; + ImGuiID storage_id = + (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasStorageID) ? g.NextItemData.StorageId : id; bool is_open = TreeNodeUpdateNextOpen(storage_id, flags); bool is_visible; if (span_all_columns || span_all_columns_label) { - // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for every Selectable.. + // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for + // every Selectable.. const float backup_clip_rect_min_x = window->ClipRect.Min.x; const float backup_clip_rect_max_x = window->ClipRect.Max.x; window->ClipRect.Min.x = window->ParentWorkRect.Min.x; @@ -6702,7 +7712,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l bool store_tree_node_stack_data = false; if ((flags & ImGuiTreeNodeFlags_DrawLinesMask_) == 0) flags |= g.Style.TreeLinesFlags; - const bool draw_tree_lines = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) && (frame_bb.Min.y < window->ClipRect.Max.y) && (g.Style.TreeLinesSize > 0.0f); + const bool draw_tree_lines = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) && + (frame_bb.Min.y < window->ClipRect.Max.y) && (g.Style.TreeLinesSize > 0.0f); if (!(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) { store_tree_node_stack_data = draw_tree_lines; @@ -6714,10 +7725,13 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; if (!is_visible) { - if ((flags & ImGuiTreeNodeFlags_DrawLinesToNodes) && (window->DC.TreeRecordsClippedNodesY2Mask & (1 << (window->DC.TreeDepth - 1)))) + if ((flags & ImGuiTreeNodeFlags_DrawLinesToNodes) && + (window->DC.TreeRecordsClippedNodesY2Mask & (1 << (window->DC.TreeDepth - 1)))) { - ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; - parent_data->DrawLinesToNodesY2 = ImMax(parent_data->DrawLinesToNodesY2, window->DC.CursorPos.y); // Don't need to aim to mid Y position as we are clipped anyway. + ImGuiTreeNodeStackData *parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; + parent_data->DrawLinesToNodesY2 = + ImMax(parent_data->DrawLinesToNodesY2, + window->DC.CursorPos.y); // Don't need to aim to mid Y position as we are clipped anyway. if (frame_bb.Min.y >= window->ClipRect.Max.y) window->DC.TreeRecordsClippedNodesY2Mask &= ~(1 << (window->DC.TreeDepth - 1)); // Done } @@ -6725,7 +7739,9 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l TreeNodeStoreStackData(flags, text_pos.x - text_offset_x); // Call before TreePushOverrideID() if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) TreePushOverrideID(id); - IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, + g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | + (is_open ? ImGuiItemStatusFlags_Opened : 0)); return is_open; } @@ -6746,22 +7762,27 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // allow browsing a tree while preserving selection with code implementing multi-selection patterns. // When clicking on the rest of the tree node we always disallow keyboard modifiers. const float arrow_hit_x1 = (text_pos.x - text_offset_x) - style.TouchExtraPadding.x; - const float arrow_hit_x2 = (text_pos.x - text_offset_x) + (g.FontSize + padding.x * 2.0f) + style.TouchExtraPadding.x; + const float arrow_hit_x2 = + (text_pos.x - text_offset_x) + (g.FontSize + padding.x * 2.0f) + style.TouchExtraPadding.x; const bool is_mouse_x_over_arrow = (g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2); const bool is_multi_select = (g.LastItemData.ItemFlags & ImGuiItemFlags_IsMultiSelect) != 0; if (is_multi_select) // We absolutely need to distinguish open vs select so _OpenOnArrow comes by default - flags |= (flags & ImGuiTreeNodeFlags_OpenOnMask_) == 0 ? ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick : ImGuiTreeNodeFlags_OpenOnArrow; + flags |= (flags & ImGuiTreeNodeFlags_OpenOnMask_) == 0 + ? ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick + : ImGuiTreeNodeFlags_OpenOnArrow; // Open behaviors can be altered with the _OpenOnArrow and _OnOnDoubleClick flags. - // Some alteration have subtle effects (e.g. toggle on MouseUp vs MouseDown events) due to requirements for multi-selection and drag and drop support. + // Some alteration have subtle effects (e.g. toggle on MouseUp vs MouseDown events) due to requirements for + // multi-selection and drag and drop support. // - Single-click on label = Toggle on MouseUp (default, when _OpenOnArrow=0) // - Single-click on arrow = Toggle on MouseDown (when _OpenOnArrow=0) // - Single-click on arrow = Toggle on MouseDown (when _OpenOnArrow=1) // - Double-click on label = Toggle on MouseDoubleClick (when _OpenOnDoubleClick=1) // - Double-click on arrow = Toggle on MouseDoubleClick (when _OpenOnDoubleClick=1 and _OpenOnArrow=0) // It is rather standard that arrow click react on Down rather than Up. - // We set ImGuiButtonFlags_PressedOnClickRelease on OpenOnDoubleClick because we want the item to be active on the initial MouseDown in order for drag and drop to work. + // We set ImGuiButtonFlags_PressedOnClickRelease on OpenOnDoubleClick because we want the item to be active on the + // initial MouseDown in order for drag and drop to work. if (is_mouse_x_over_arrow) button_flags |= ImGuiButtonFlags_PressedOnClick; else if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) @@ -6798,14 +7819,17 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if ((flags & ImGuiTreeNodeFlags_OpenOnMask_) == 0 || (g.NavActivateId == id && !is_multi_select)) toggled = true; // Single click if (flags & ImGuiTreeNodeFlags_OpenOnArrow) - toggled |= is_mouse_x_over_arrow && !g.NavHighlightItemUnderNav; // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job + toggled |= is_mouse_x_over_arrow && + !g.NavHighlightItemUnderNav; // Lightweight equivalent of IsMouseHoveringRect() since + // ButtonBehavior() already did the job if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseClickedCount[0] == 2) toggled = true; // Double click } else if (pressed && g.DragDropHoldJustPressedId == id) { IM_ASSERT(button_flags & ImGuiButtonFlags_PressedOnDragDropHold); - if (!is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again. + if (!is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but + // never close it again. toggled = true; else pressed = false; // Cancel press so it doesn't trigger selection. @@ -6817,7 +7841,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l NavClearPreferredPosForAxis(ImGuiAxis_X); NavMoveRequestCancel(); } - if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority? + if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right && + !is_open) // If there's something upcoming on the line we may want to give it the priority? { toggled = true; NavClearPreferredPosForAxis(ImGuiAxis_X); @@ -6853,15 +7878,21 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (display_frame) { // Framed type - const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive + : hovered ? ImGuiCol_HeaderHovered + : ImGuiCol_Header); RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, true, style.FrameRounding); RenderNavCursor(frame_bb, id, nav_render_cursor_flags); if (span_all_columns && !span_all_columns_label) TablePopBackgroundChannel(); if (flags & ImGuiTreeNodeFlags_Bullet) - RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y + g.FontSize * 0.5f), text_col); + RenderBullet(window->DrawList, + ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y + g.FontSize * 0.5f), text_col); else if (!is_leaf) - RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 1.0f); + RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, + is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) + : ImGuiDir_Right, + 1.0f); else // Leaf without bullet, left-adjusted text text_pos.x -= text_offset_x - padding.x; if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton) @@ -6874,16 +7905,23 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // Unframed typed for tree nodes if (hovered || selected) { - const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive + : hovered ? ImGuiCol_HeaderHovered + : ImGuiCol_Header); RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false); } RenderNavCursor(frame_bb, id, nav_render_cursor_flags); if (span_all_columns && !span_all_columns_label) TablePopBackgroundChannel(); if (flags & ImGuiTreeNodeFlags_Bullet) - RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col); + RenderBullet(window->DrawList, + ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col); else if (!is_leaf) - RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 0.70f); + RenderArrow(window->DrawList, + ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, + is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) + : ImGuiDir_Right, + 0.70f); if (g.LogEnabled) LogSetNextTextDecoration(">", NULL); } @@ -6906,20 +7944,22 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) TreePushOverrideID(id); // Could use TreePush(label) but this avoid computing twice - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, + g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | + (is_open ? ImGuiItemStatusFlags_Opened : 0)); return is_open; } // Draw horizontal line from our parent node // This is only called for visible child nodes so we are not too fussy anymore about performances -void ImGui::TreeNodeDrawLineToChildNode(const ImVec2& target_pos) +void ImGui::TreeNodeDrawLineToChildNode(const ImVec2 &target_pos) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; if (window->DC.TreeDepth == 0 || (window->DC.TreeHasStackDataDepthMask & (1 << (window->DC.TreeDepth - 1))) == 0) return; - ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; + ImGuiTreeNodeStackData *parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; float x1 = ImTrunc(parent_data->DrawLinesX1); float x2 = ImTrunc(target_pos.x - g.Style.ItemInnerSpacing.x); float y = ImTrunc(target_pos.y); @@ -6942,10 +7982,10 @@ void ImGui::TreeNodeDrawLineToChildNode(const ImVec2& target_pos) } // Draw vertical line of the hierarchy -void ImGui::TreeNodeDrawLineToTreePop(const ImGuiTreeNodeStackData* data) +void ImGui::TreeNodeDrawLineToTreePop(const ImGuiTreeNodeStackData *data) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; float y1 = ImMax(data->NavRect.Max.y, window->ClipRect.Min.y); float y2 = data->DrawLinesToNodesY2; if (data->TreeFlags & ImGuiTreeNodeFlags_DrawLinesFull) @@ -6954,7 +7994,8 @@ void ImGui::TreeNodeDrawLineToTreePop(const ImGuiTreeNodeStackData* data) if (g.CurrentTable) y2_full = ImMax(g.CurrentTable->RowPosY2, y2_full); y2_full = ImTrunc(y2_full - g.Style.ItemSpacing.y - g.FontSize * 0.5f); - if (y2 + (g.Style.ItemSpacing.y + g.Style.TreeLinesRounding) < y2_full) // FIXME: threshold to use ToNodes Y2 instead of Full Y2 when close by ItemSpacing.y + if (y2 + (g.Style.ItemSpacing.y + g.Style.TreeLinesRounding) < + y2_full) // FIXME: threshold to use ToNodes Y2 instead of Full Y2 when close by ItemSpacing.y y2 = y2_full; } y2 = ImMin(y2, window->ClipRect.Max.y); @@ -6968,17 +8009,17 @@ void ImGui::TreeNodeDrawLineToTreePop(const ImGuiTreeNodeStackData* data) TablePopColumnChannel(); } -void ImGui::TreePush(const char* str_id) +void ImGui::TreePush(const char *str_id) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); Indent(); window->DC.TreeDepth++; PushID(str_id); } -void ImGui::TreePush(const void* ptr_id) +void ImGui::TreePush(const void *ptr_id) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); Indent(); window->DC.TreeDepth++; PushID(ptr_id); @@ -6986,8 +8027,8 @@ void ImGui::TreePush(const void* ptr_id) void ImGui::TreePushOverrideID(ImGuiID id) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; Indent(); window->DC.TreeDepth++; PushOverrideID(id); @@ -6995,8 +8036,8 @@ void ImGui::TreePushOverrideID(ImGuiID id) void ImGui::TreePop() { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; Unindent(); window->DC.TreeDepth--; @@ -7004,12 +8045,13 @@ void ImGui::TreePop() if (window->DC.TreeHasStackDataDepthMask & tree_depth_mask) { - const ImGuiTreeNodeStackData* data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; + const ImGuiTreeNodeStackData *data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; IM_ASSERT(data->ID == window->IDStack.back()); // Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsToParent is enabled) if (data->TreeFlags & ImGuiTreeNodeFlags_NavLeftJumpsToParent) - if (g.NavIdIsAlive && g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) + if (g.NavIdIsAlive && g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && + NavMoveRequestButNoResultYet()) NavMoveRequestResolveWithPastTreeNode(&g.NavMoveResultLocal, data); // Draw hierarchy lines @@ -7021,21 +8063,22 @@ void ImGui::TreePop() window->DC.TreeRecordsClippedNodesY2Mask &= ~tree_depth_mask; } - IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much. + IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window + // creation). If this triggers you called TreePop/PopID too much. PopID(); } // Horizontal distance preceding label when using TreeNode() or Bullet() float ImGui::GetTreeNodeToLabelSpacing() { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; return g.FontSize + (g.Style.FramePadding.x * 2.0f); } // Set next TreeNode/CollapsingHeader open state. void ImGui::SetNextItemOpen(bool is_open, ImGuiCond cond) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; if (g.CurrentWindow->SkipItems) return; g.NextItemData.HasFlags |= ImGuiNextItemDataFlags_HasOpen; @@ -7046,18 +8089,20 @@ void ImGui::SetNextItemOpen(bool is_open, ImGuiCond cond) // Set next TreeNode/CollapsingHeader storage id. void ImGui::SetNextItemStorageID(ImGuiID storage_id) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; if (g.CurrentWindow->SkipItems) return; g.NextItemData.HasFlags |= ImGuiNextItemDataFlags_HasStorageID; g.NextItemData.StorageId = storage_id; } -// CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag). -// This is basically the same as calling TreeNodeEx(label, ImGuiTreeNodeFlags_CollapsingHeader). You can remove the _NoTreePushOnOpen flag if you want behavior closer to normal TreeNode(). -bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags) +// CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the +// ImGuiTreeNodeFlags_NoTreePushOnOpen flag). This is basically the same as calling TreeNodeEx(label, +// ImGuiTreeNodeFlags_CollapsingHeader). You can remove the _NoTreePushOnOpen flag if you want behavior closer to normal +// TreeNode(). +bool ImGui::CollapsingHeader(const char *label, ImGuiTreeNodeFlags flags) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; ImGuiID id = window->GetID(label); @@ -7065,12 +8110,13 @@ bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags) } // p_visible == NULL : regular collapsing header -// p_visible != NULL && *p_visible == true : show a small close button on the corner of the header, clicking the button will set *p_visible = false -// p_visible != NULL && *p_visible == false : do not show the header at all -// Do not mistake this with the Open state of the header itself, which you can adjust with SetNextItemOpen() or ImGuiTreeNodeFlags_DefaultOpen. -bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFlags flags) +// p_visible != NULL && *p_visible == true : show a small close button on the corner of the header, clicking the button +// will set *p_visible = false p_visible != NULL && *p_visible == false : do not show the header at all Do not mistake +// this with the Open state of the header itself, which you can adjust with SetNextItemOpen() or +// ImGuiTreeNodeFlags_DefaultOpen. +bool ImGui::CollapsingHeader(const char *label, bool *p_visible, ImGuiTreeNodeFlags flags) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; @@ -7087,10 +8133,11 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFl // Create a small overlapping close button // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc. // FIXME: CloseButton can overlap into text, need find a way to clip the text somehow. - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; ImGuiLastItemData last_item_backup = g.LastItemData; float button_size = g.FontSize; - float button_x = ImMax(g.LastItemData.Rect.Min.x, g.LastItemData.Rect.Max.x - g.Style.FramePadding.x - button_size); + float button_x = + ImMax(g.LastItemData.Rect.Min.x, g.LastItemData.Rect.Max.x - g.Style.FramePadding.x - button_size); float button_y = g.LastItemData.Rect.Min.y + g.Style.FramePadding.y; ImGuiID close_button_id = GetIDWithSeed("#CLOSE", NULL, id); if (CloseButton(close_button_id, ImVec2(button_x, button_y))) @@ -7109,16 +8156,18 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFl // Tip: pass a non-visible label (e.g. "##hello") then you can use the space to draw other text or image. // But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID or use ##unique_id. -// With this scheme, ImGuiSelectableFlags_SpanAllColumns and ImGuiSelectableFlags_AllowOverlap are also frequently used flags. -// FIXME: Selectable() with (size.x == 0.0f) and (SelectableTextAlign.x > 0.0f) followed by SameLine() is currently not supported. -bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) +// With this scheme, ImGuiSelectableFlags_SpanAllColumns and ImGuiSelectableFlags_AllowOverlap are also frequently used +// flags. +// FIXME: Selectable() with (size.x == 0.0f) and (SelectableTextAlign.x > 0.0f) followed by SameLine() is currently not +// supported. +bool ImGui::Selectable(const char *label, bool selected, ImGuiSelectableFlags flags, const ImVec2 &size_arg) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; + ImGuiContext &g = *GImGui; + const ImGuiStyle &style = g.Style; // Submit label or explicit size to ItemSize(), whereas ItemAdd() will submit a larger/spanning rectangle. ImGuiID id = window->GetID(label); @@ -7129,15 +8178,18 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl ItemSize(size, 0.0f); // Fill horizontal space - // We don't support (size < 0.0f) in Selectable() because the ItemSpacing extension would make explicitly right-aligned sizes not visibly match other widgets. + // We don't support (size < 0.0f) in Selectable() because the ItemSpacing extension would make explicitly + // right-aligned sizes not visibly match other widgets. const bool span_all_columns = (flags & ImGuiSelectableFlags_SpanAllColumns) != 0; const float min_x = span_all_columns ? window->ParentWorkRect.Min.x : pos.x; const float max_x = span_all_columns ? window->ParentWorkRect.Max.x : window->WorkRect.Max.x; if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_SpanAvailWidth)) size.x = ImMax(label_size.x, max_x - min_x); - // Selectables are meant to be tightly packed together with no click-gap, so we extend their box to cover spacing between selectable. - // FIXME: Not part of layout so not included in clipper calculation, but ItemSize currently doesn't allow offsetting CursorPos. + // Selectables are meant to be tightly packed together with no click-gap, so we extend their box to cover spacing + // between selectable. + // FIXME: Not part of layout so not included in clipper calculation, but ItemSize currently doesn't allow offsetting + // CursorPos. ImRect bb(min_x, pos.y, min_x + size.x, pos.y + size.y); if ((flags & ImGuiSelectableFlags_NoPadWithHalfSpacing) == 0) { @@ -7150,14 +8202,16 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl bb.Max.x += (spacing_x - spacing_L); bb.Max.y += (spacing_y - spacing_U); } - //if (g.IO.KeyCtrl) { GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(0, 255, 0, 255)); } + // if (g.IO.KeyCtrl) { GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(0, 255, 0, 255)); } const bool disabled_item = (flags & ImGuiSelectableFlags_Disabled) != 0; - const ImGuiItemFlags extra_item_flags = disabled_item ? (ImGuiItemFlags)ImGuiItemFlags_Disabled : ImGuiItemFlags_None; + const ImGuiItemFlags extra_item_flags = + disabled_item ? (ImGuiItemFlags)ImGuiItemFlags_Disabled : ImGuiItemFlags_None; bool is_visible; if (span_all_columns) { - // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for every Selectable.. + // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for + // every Selectable.. const float backup_clip_rect_min_x = window->ClipRect.Min.x; const float backup_clip_rect_max_x = window->ClipRect.Max.x; window->ClipRect.Min.x = window->ParentWorkRect.Min.x; @@ -7173,15 +8227,17 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl const bool is_multi_select = (g.LastItemData.ItemFlags & ImGuiItemFlags_IsMultiSelect) != 0; if (!is_visible) - if (!is_multi_select || !g.BoxSelectState.UnclipMode || !g.BoxSelectState.UnclipRect.Overlaps(bb)) // Extra layer of "no logic clip" for box-select support (would be more overhead to add to ItemAdd) + if (!is_multi_select || !g.BoxSelectState.UnclipMode || + !g.BoxSelectState.UnclipRect.Overlaps( + bb)) // Extra layer of "no logic clip" for box-select support (would be more overhead to add to ItemAdd) return false; const bool disabled_global = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; if (disabled_item && !disabled_global) // Only testing this as an optimization BeginDisabled(); - // FIXME: We can standardize the behavior of those two, we could also keep the fast path of override ClipRect + full push on render only, - // which would be advantageous since most selectable are not selected. + // FIXME: We can standardize the behavior of those two, we could also keep the fast path of override ClipRect + full + // push on render only, which would be advantageous since most selectable are not selected. if (span_all_columns) { if (g.CurrentTable) @@ -7194,12 +8250,30 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl // We use NoHoldingActiveID on menus so user can click and _hold_ on a menu then drag to browse child entries ImGuiButtonFlags button_flags = 0; - if (flags & ImGuiSelectableFlags_NoHoldingActiveID) { button_flags |= ImGuiButtonFlags_NoHoldingActiveId; } - if (flags & ImGuiSelectableFlags_NoSetKeyOwner) { button_flags |= ImGuiButtonFlags_NoSetKeyOwner; } - if (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; } - if (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; } - if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; } - if ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.ItemFlags & ImGuiItemFlags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; } + if (flags & ImGuiSelectableFlags_NoHoldingActiveID) + { + button_flags |= ImGuiButtonFlags_NoHoldingActiveId; + } + if (flags & ImGuiSelectableFlags_NoSetKeyOwner) + { + button_flags |= ImGuiButtonFlags_NoSetKeyOwner; + } + if (flags & ImGuiSelectableFlags_SelectOnClick) + { + button_flags |= ImGuiButtonFlags_PressedOnClick; + } + if (flags & ImGuiSelectableFlags_SelectOnRelease) + { + button_flags |= ImGuiButtonFlags_PressedOnRelease; + } + if (flags & ImGuiSelectableFlags_AllowDoubleClick) + { + button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; + } + if ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.ItemFlags & ImGuiItemFlags_AllowOverlap)) + { + button_flags |= ImGuiButtonFlags_AllowOverlap; + } // Multi-selection support (header) const bool was_selected = selected; @@ -7223,20 +8297,24 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl // - This will be more fully fleshed in the range-select branch // - This is not exposed as it won't nicely work with some user side handling of shift/control // - We cannot do 'if (g.NavJustMovedToId != id) { selected = false; pressed = was_selected; }' for two reasons - // - (1) it would require focus scope to be set, need exposing PushFocusScope() or equivalent (e.g. BeginSelection() calling PushFocusScope()) + // - (1) it would require focus scope to be set, need exposing PushFocusScope() or equivalent (e.g. + // BeginSelection() calling PushFocusScope()) // - (2) usage will fail with clipped items // The multi-select API aim to fix those issues, e.g. may be replaced with a BeginSelection() API. - if ((flags & ImGuiSelectableFlags_SelectOnNav) && g.NavJustMovedToId != 0 && g.NavJustMovedToFocusScopeId == g.CurrentFocusScopeId) + if ((flags & ImGuiSelectableFlags_SelectOnNav) && g.NavJustMovedToId != 0 && + g.NavJustMovedToFocusScopeId == g.CurrentFocusScopeId) if (g.NavJustMovedToId == id) selected = pressed = true; } - // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with keyboard/gamepad + // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed + // with keyboard/gamepad if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover))) { if (!g.NavHighlightItemUnderNav && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) { - SetNavID(id, window->DC.NavLayerCurrent, g.CurrentFocusScopeId, WindowRectAbsToRel(window, bb)); // (bb == NavRect) + SetNavID(id, window->DC.NavLayerCurrent, g.CurrentFocusScopeId, + WindowRectAbsToRel(window, bb)); // (bb == NavRect) if (g.IO.ConfigNavCursorVisibleAuto) g.NavCursorVisible = false; } @@ -7253,13 +8331,17 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl const bool highlighted = hovered || (flags & ImGuiSelectableFlags_Highlight); if (highlighted || selected) { - // Between 1.91.0 and 1.91.4 we made selected Selectable use an arbitrary lerp between _Header and _HeaderHovered. Removed that now. (#8106) - ImU32 col = GetColorU32((held && highlighted) ? ImGuiCol_HeaderActive : highlighted ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + // Between 1.91.0 and 1.91.4 we made selected Selectable use an arbitrary lerp between _Header and + // _HeaderHovered. Removed that now. (#8106) + ImU32 col = GetColorU32((held && highlighted) ? ImGuiCol_HeaderActive + : highlighted ? ImGuiCol_HeaderHovered + : ImGuiCol_Header); RenderFrame(bb.Min, bb.Max, col, false, 0.0f); } if (g.NavId == id) { - ImGuiNavRenderCursorFlags nav_render_cursor_flags = ImGuiNavRenderCursorFlags_Compact | ImGuiNavRenderCursorFlags_NoRounding; + ImGuiNavRenderCursorFlags nav_render_cursor_flags = + ImGuiNavRenderCursorFlags_Compact | ImGuiNavRenderCursorFlags_NoRounding; if (is_multi_select) nav_render_cursor_flags |= ImGuiNavRenderCursorFlags_AlwaysDraw; // Always show the nav rectangle RenderNavCursor(bb, id, nav_render_cursor_flags); @@ -7276,10 +8358,12 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl // Text stays at the submission position. Alignment/clipping extents ignore SpanAllColumns. if (is_visible) - RenderTextClipped(pos, ImVec2(ImMin(pos.x + size.x, window->WorkRect.Max.x), pos.y + size.y), label, NULL, &label_size, style.SelectableTextAlign, &bb); + RenderTextClipped(pos, ImVec2(ImMin(pos.x + size.x, window->WorkRect.Max.x), pos.y + size.y), label, NULL, + &label_size, style.SelectableTextAlign, &bb); // Automatically close popups - if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_NoAutoClosePopups) && (g.LastItemData.ItemFlags & ImGuiItemFlags_AutoClosePopups)) + if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_NoAutoClosePopups) && + (g.LastItemData.ItemFlags & ImGuiItemFlags_AutoClosePopups)) CloseCurrentPopup(); if (disabled_item && !disabled_global) @@ -7287,12 +8371,13 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl // Selectable() always returns a pressed state! // Users of BeginMultiSelect()/EndMultiSelect() scope: you may call ImGui::IsItemToggledSelection() to retrieve - // selection toggle, only useful if you need that state updated (e.g. for rendering purpose) before reaching EndMultiSelect(). + // selection toggle, only useful if you need that state updated (e.g. for rendering purpose) before reaching + // EndMultiSelect(). IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); return pressed; //-V1020 } -bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) +bool ImGui::Selectable(const char *label, bool *p_selected, ImGuiSelectableFlags flags, const ImVec2 &size_arg) { if (Selectable(label, *p_selected, flags, size_arg)) { @@ -7302,7 +8387,6 @@ bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags return false; } - //------------------------------------------------------------------------- // [SECTION] Widgets: Typing-Select support //------------------------------------------------------------------------- @@ -7312,17 +8396,19 @@ bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags // This would typically only be called on the focused window or location you want to grab inputs for, e.g. // if (ImGui::IsWindowFocused(...)) // if (ImGuiTypingSelectRequest* req = ImGui::GetTypingSelectRequest()) -// focus_idx = ImGui::TypingSelectFindMatch(req, my_items.size(), [](void*, int n) { return my_items[n]->Name; }, &my_items, -1); +// focus_idx = ImGui::TypingSelectFindMatch(req, my_items.size(), [](void*, int n) { return my_items[n]->Name; +// }, &my_items, -1); // However the code is written in a way where calling it from multiple locations is safe (e.g. to obtain buffer). -ImGuiTypingSelectRequest* ImGui::GetTypingSelectRequest(ImGuiTypingSelectFlags flags) +ImGuiTypingSelectRequest *ImGui::GetTypingSelectRequest(ImGuiTypingSelectFlags flags) { - ImGuiContext& g = *GImGui; - ImGuiTypingSelectState* data = &g.TypingSelectState; - ImGuiTypingSelectRequest* out_request = &data->Request; + ImGuiContext &g = *GImGui; + ImGuiTypingSelectState *data = &g.TypingSelectState; + ImGuiTypingSelectRequest *out_request = &data->Request; // Clear buffer - const float TYPING_SELECT_RESET_TIMER = 1.80f; // FIXME: Potentially move to IO config. - const int TYPING_SELECT_SINGLE_CHAR_COUNT_FOR_LOCK = 4; // Lock single char matching when repeating same char 4 times + const float TYPING_SELECT_RESET_TIMER = 1.80f; // FIXME: Potentially move to IO config. + const int TYPING_SELECT_SINGLE_CHAR_COUNT_FOR_LOCK = + 4; // Lock single char matching when repeating same char 4 times if (data->SearchBuffer[0] != 0) { bool clear_buffer = false; @@ -7332,7 +8418,7 @@ ImGuiTypingSelectRequest* ImGui::GetTypingSelectRequest(ImGuiTypingSelectFlags f clear_buffer |= g.ActiveId != 0 && g.NavActivateId == 0; // Allow temporary SPACE activation to not interfere clear_buffer |= IsKeyPressed(ImGuiKey_Escape) || IsKeyPressed(ImGuiKey_Enter); clear_buffer |= IsKeyPressed(ImGuiKey_Backspace) && (flags & ImGuiTypingSelectFlags_AllowBackspace) == 0; - //if (clear_buffer) { IMGUI_DEBUG_LOG("GetTypingSelectRequest(): Clear SearchBuffer.\n"); } + // if (clear_buffer) { IMGUI_DEBUG_LOG("GetTypingSelectRequest(): Clear SearchBuffer.\n"); } if (clear_buffer) data->Clear(); } @@ -7344,11 +8430,13 @@ ImGuiTypingSelectRequest* ImGui::GetTypingSelectRequest(ImGuiTypingSelectFlags f for (ImWchar w : g.IO.InputQueueCharacters) { const int w_len = ImTextCountUtf8BytesFromStr(&w, &w + 1); - if (w < 32 || (buffer_len == 0 && ImCharIsBlankW(w)) || (buffer_len + w_len > buffer_max_len)) // Ignore leading blanks + if (w < 32 || (buffer_len == 0 && ImCharIsBlankW(w)) || + (buffer_len + w_len > buffer_max_len)) // Ignore leading blanks continue; char w_buf[5]; ImTextCharToUtf8(w_buf, (unsigned int)w); - if (data->SingleCharModeLock && w_len == out_request->SingleCharSize && memcmp(w_buf, data->SearchBuffer, w_len) == 0) + if (data->SingleCharModeLock && w_len == out_request->SingleCharSize && + memcmp(w_buf, data->SearchBuffer, w_len) == 0) { select_request = true; // Same character: don't need to append to buffer. continue; @@ -7367,7 +8455,7 @@ ImGuiTypingSelectRequest* ImGui::GetTypingSelectRequest(ImGuiTypingSelectFlags f // Handle backspace if ((flags & ImGuiTypingSelectFlags_AllowBackspace) && IsKeyPressed(ImGuiKey_Backspace, ImGuiInputFlags_Repeat)) { - char* p = (char*)(void*)ImTextFindPreviousUtf8Codepoint(data->SearchBuffer, data->SearchBuffer + buffer_len); + char *p = (char *)(void *)ImTextFindPreviousUtf8Codepoint(data->SearchBuffer, data->SearchBuffer + buffer_len); *p = 0; buffer_len = (int)(p - data->SearchBuffer); } @@ -7394,23 +8482,25 @@ ImGuiTypingSelectRequest* ImGui::GetTypingSelectRequest(ImGuiTypingSelectFlags f // - SingleCharMode is always set for first input character, because it usually leads to a "next". if (flags & ImGuiTypingSelectFlags_AllowSingleCharMode) { - const char* buf_begin = out_request->SearchBuffer; - const char* buf_end = out_request->SearchBuffer + out_request->SearchBufferLen; + const char *buf_begin = out_request->SearchBuffer; + const char *buf_end = out_request->SearchBuffer + out_request->SearchBufferLen; const int c0_len = ImTextCountUtf8BytesFromChar(buf_begin, buf_end); - const char* p = buf_begin + c0_len; + const char *p = buf_begin + c0_len; for (; p < buf_end; p += c0_len) if (memcmp(buf_begin, p, (size_t)c0_len) != 0) break; const int single_char_count = (p == buf_end) ? (out_request->SearchBufferLen / c0_len) : 0; out_request->SingleCharMode = (single_char_count > 0 || data->SingleCharModeLock); out_request->SingleCharSize = (ImS8)c0_len; - data->SingleCharModeLock |= (single_char_count >= TYPING_SELECT_SINGLE_CHAR_COUNT_FOR_LOCK); // From now on we stop search matching to lock to single char mode. + data->SingleCharModeLock |= + (single_char_count >= TYPING_SELECT_SINGLE_CHAR_COUNT_FOR_LOCK); // From now on we stop search matching to + // lock to single char mode. } return out_request; } -static int ImStrimatchlen(const char* s1, const char* s1_end, const char* s2) +static int ImStrimatchlen(const char *s1, const char *s1_end, const char *s2) { int match_len = 0; while (s1 < s1_end && ImToUpper(*s1++) == ImToUpper(*s2++)) @@ -7423,8 +8513,10 @@ static int ImStrimatchlen(const char* s1, const char* s1_end, const char* s2) // When SingleCharMode is set: // - it is better to NOT display a tooltip of other on-screen display indicator. // - the index of the currently focused item is required. -// if your SetNextItemSelectionUserData() values are indices, you can obtain it from ImGuiMultiSelectIO::NavIdItem, otherwise from g.NavLastValidSelectionUserData. -int ImGui::TypingSelectFindMatch(ImGuiTypingSelectRequest* req, int items_count, const char* (*get_item_name_func)(void*, int), void* user_data, int nav_item_idx) +// if your SetNextItemSelectionUserData() values are indices, you can obtain it from ImGuiMultiSelectIO::NavIdItem, +// otherwise from g.NavLastValidSelectionUserData. +int ImGui::TypingSelectFindMatch(ImGuiTypingSelectRequest *req, int items_count, + const char *(*get_item_name_func)(void *, int), void *user_data, int nav_item_idx) { if (req == NULL || req->SelectRequest == false) // Support NULL parameter so both calls can be done from same spot. return -1; @@ -7439,38 +8531,42 @@ int ImGui::TypingSelectFindMatch(ImGuiTypingSelectRequest* req, int items_count, } // Special handling when a single character is repeated: perform search on a single letter and goes to next. -int ImGui::TypingSelectFindNextSingleCharMatch(ImGuiTypingSelectRequest* req, int items_count, const char* (*get_item_name_func)(void*, int), void* user_data, int nav_item_idx) +int ImGui::TypingSelectFindNextSingleCharMatch(ImGuiTypingSelectRequest *req, int items_count, + const char *(*get_item_name_func)(void *, int), void *user_data, + int nav_item_idx) { // FIXME: Assume selection user data is index. Would be extremely practical. - //if (nav_item_idx == -1) + // if (nav_item_idx == -1) // nav_item_idx = (int)g.NavLastValidSelectionUserData; int first_match_idx = -1; bool return_next_match = false; for (int idx = 0; idx < items_count; idx++) { - const char* item_name = get_item_name_func(user_data, idx); + const char *item_name = get_item_name_func(user_data, idx); if (ImStrimatchlen(req->SearchBuffer, req->SearchBuffer + req->SingleCharSize, item_name) < req->SingleCharSize) continue; - if (return_next_match) // Return next matching item after current item. + if (return_next_match) // Return next matching item after current item. return idx; - if (first_match_idx == -1 && nav_item_idx == -1) // Return first match immediately if we don't have a nav_item_idx value. + if (first_match_idx == -1 && + nav_item_idx == -1) // Return first match immediately if we don't have a nav_item_idx value. return idx; - if (first_match_idx == -1) // Record first match for wrapping. + if (first_match_idx == -1) // Record first match for wrapping. first_match_idx = idx; - if (nav_item_idx == idx) // Record that we encountering nav_item so we can return next match. + if (nav_item_idx == idx) // Record that we encountering nav_item so we can return next match. return_next_match = true; } return first_match_idx; // First result } -int ImGui::TypingSelectFindBestLeadingMatch(ImGuiTypingSelectRequest* req, int items_count, const char* (*get_item_name_func)(void*, int), void* user_data) +int ImGui::TypingSelectFindBestLeadingMatch(ImGuiTypingSelectRequest *req, int items_count, + const char *(*get_item_name_func)(void *, int), void *user_data) { int longest_match_idx = -1; int longest_match_len = 0; for (int idx = 0; idx < items_count; idx++) { - const char* item_name = get_item_name_func(user_data, idx); + const char *item_name = get_item_name_func(user_data, idx); const int match_len = ImStrimatchlen(req->SearchBuffer, req->SearchBuffer + req->SearchBufferLen, item_name); if (match_len <= longest_match_len) continue; @@ -7482,11 +8578,12 @@ int ImGui::TypingSelectFindBestLeadingMatch(ImGuiTypingSelectRequest* req, int i return longest_match_idx; } -void ImGui::DebugNodeTypingSelectState(ImGuiTypingSelectState* data) +void ImGui::DebugNodeTypingSelectState(ImGuiTypingSelectState *data) { #ifndef IMGUI_DISABLE_DEBUG_TOOLS Text("SearchBuffer = \"%s\"", data->SearchBuffer); - Text("SingleCharMode = %d, Size = %d, Lock = %d", data->Request.SingleCharMode, data->Request.SingleCharSize, data->SingleCharModeLock); + Text("SingleCharMode = %d, Size = %d, Lock = %d", data->Request.SingleCharMode, data->Request.SingleCharSize, + data->SingleCharModeLock); Text("LastRequest = time: %.2f, frame: %d", data->LastRequestTime, data->LastRequestFrame); #else IM_UNUSED(data); @@ -7495,7 +8592,8 @@ void ImGui::DebugNodeTypingSelectState(ImGuiTypingSelectState* data) //------------------------------------------------------------------------- // [SECTION] Widgets: Box-Select support -// This has been extracted away from Multi-Select logic in the hope that it could eventually be used elsewhere, but hasn't been yet. +// This has been extracted away from Multi-Select logic in the hope that it could eventually be used elsewhere, but +// hasn't been yet. //------------------------------------------------------------------------- // Extra logic in MultiSelectItemFooter() and ImGuiListClipper::Step() //------------------------------------------------------------------------- @@ -7510,8 +8608,8 @@ void ImGui::DebugNodeTypingSelectState(ImGuiTypingSelectState* data) // Call on the initial click. static void BoxSelectPreStartDrag(ImGuiID id, ImGuiSelectionUserData clicked_item) { - ImGuiContext& g = *GImGui; - ImGuiBoxSelectState* bs = &g.BoxSelectState; + ImGuiContext &g = *GImGui; + ImGuiBoxSelectState *bs = &g.BoxSelectState; bs->ID = id; bs->IsStarting = true; // Consider starting box-select. bs->IsStartedFromVoid = (clicked_item == ImGuiSelectionUserData_Invalid); @@ -7521,9 +8619,9 @@ static void BoxSelectPreStartDrag(ImGuiID id, ImGuiSelectionUserData clicked_ite bs->ScrollAccum = ImVec2(0.0f, 0.0f); } -static void BoxSelectActivateDrag(ImGuiBoxSelectState* bs, ImGuiWindow* window) +static void BoxSelectActivateDrag(ImGuiBoxSelectState *bs, ImGuiWindow *window) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; IMGUI_DEBUG_LOG_SELECTION("[selection] BeginBoxSelect() 0X%08X: Activate\n", bs->ID); bs->IsActive = true; bs->Window = window; @@ -7534,9 +8632,9 @@ static void BoxSelectActivateDrag(ImGuiBoxSelectState* bs, ImGuiWindow* window) bs->RequestClear = true; } -static void BoxSelectDeactivateDrag(ImGuiBoxSelectState* bs) +static void BoxSelectDeactivateDrag(ImGuiBoxSelectState *bs) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; bs->IsActive = bs->IsStarting = false; if (g.ActiveId == bs->ID) { @@ -7546,19 +8644,22 @@ static void BoxSelectDeactivateDrag(ImGuiBoxSelectState* bs) bs->ID = 0; } -static void BoxSelectScrollWithMouseDrag(ImGuiBoxSelectState* bs, ImGuiWindow* window, const ImRect& inner_r) +static void BoxSelectScrollWithMouseDrag(ImGuiBoxSelectState *bs, ImGuiWindow *window, const ImRect &inner_r) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; IM_ASSERT(bs->Window == window); for (int n = 0; n < 2; n++) // each axis { const float mouse_pos = g.IO.MousePos[n]; - const float dist = (mouse_pos > inner_r.Max[n]) ? mouse_pos - inner_r.Max[n] : (mouse_pos < inner_r.Min[n]) ? mouse_pos - inner_r.Min[n] : 0.0f; + const float dist = (mouse_pos > inner_r.Max[n]) ? mouse_pos - inner_r.Max[n] + : (mouse_pos < inner_r.Min[n]) ? mouse_pos - inner_r.Min[n] + : 0.0f; const float scroll_curr = window->Scroll[n]; if (dist == 0.0f || (dist < 0.0f && scroll_curr < 0.0f) || (dist > 0.0f && scroll_curr >= window->ScrollMax[n])) continue; - const float speed_multiplier = ImLinearRemapClamp(g.FontSize, g.FontSize * 5.0f, 1.0f, 4.0f, ImAbs(dist)); // x1 to x4 depending on distance + const float speed_multiplier = ImLinearRemapClamp(g.FontSize, g.FontSize * 5.0f, 1.0f, 4.0f, + ImAbs(dist)); // x1 to x4 depending on distance const float scroll_step = g.FontSize * 35.0f * speed_multiplier * ImSign(dist) * g.IO.DeltaTime; bs->ScrollAccum[n] += scroll_step; @@ -7574,15 +8675,17 @@ static void BoxSelectScrollWithMouseDrag(ImGuiBoxSelectState* bs, ImGuiWindow* w } } -bool ImGui::BeginBoxSelect(const ImRect& scope_rect, ImGuiWindow* window, ImGuiID box_select_id, ImGuiMultiSelectFlags ms_flags) +bool ImGui::BeginBoxSelect(const ImRect &scope_rect, ImGuiWindow *window, ImGuiID box_select_id, + ImGuiMultiSelectFlags ms_flags) { - ImGuiContext& g = *GImGui; - ImGuiBoxSelectState* bs = &g.BoxSelectState; + ImGuiContext &g = *GImGui; + ImGuiBoxSelectState *bs = &g.BoxSelectState; KeepAliveID(box_select_id); if (bs->ID != box_select_id) return false; - // IsStarting is set by MultiSelectItemFooter() when considering a possible box-select. We validate it here and lock geometry. + // IsStarting is set by MultiSelectItemFooter() when considering a possible box-select. We validate it here and lock + // geometry. bs->UnclipMode = false; bs->RequestClear = false; if (bs->IsStarting && IsMouseDragPastThreshold(0)) @@ -7607,41 +8710,49 @@ bool ImGui::BeginBoxSelect(const ImRect& scope_rect, ImGuiWindow* window, ImGuiI // Box-select 2D mode detects horizontal changes (vertical ones are already picked by Clipper) // Storing an extra rect used by widgets supporting box-select. if (ms_flags & ImGuiMultiSelectFlags_BoxSelect2d) - if (bs->BoxSelectRectPrev.Min.x != bs->BoxSelectRectCurr.Min.x || bs->BoxSelectRectPrev.Max.x != bs->BoxSelectRectCurr.Max.x) + if (bs->BoxSelectRectPrev.Min.x != bs->BoxSelectRectCurr.Min.x || + bs->BoxSelectRectPrev.Max.x != bs->BoxSelectRectCurr.Max.x) { bs->UnclipMode = true; - bs->UnclipRect = bs->BoxSelectRectPrev; // FIXME-OPT: UnclipRect x coordinates could be intersection of Prev and Curr rect on X axis. + bs->UnclipRect = bs->BoxSelectRectPrev; // FIXME-OPT: UnclipRect x coordinates could be intersection of Prev + // and Curr rect on X axis. bs->UnclipRect.Add(bs->BoxSelectRectCurr); } - //GetForegroundDrawList()->AddRect(bs->UnclipRect.Min, bs->UnclipRect.Max, IM_COL32(255,0,0,200), 0.0f, 0, 3.0f); - //GetForegroundDrawList()->AddRect(bs->BoxSelectRectPrev.Min, bs->BoxSelectRectPrev.Max, IM_COL32(255,0,0,200), 0.0f, 0, 3.0f); - //GetForegroundDrawList()->AddRect(bs->BoxSelectRectCurr.Min, bs->BoxSelectRectCurr.Max, IM_COL32(0,255,0,200), 0.0f, 0, 1.0f); + // GetForegroundDrawList()->AddRect(bs->UnclipRect.Min, bs->UnclipRect.Max, IM_COL32(255,0,0,200), 0.0f, 0, 3.0f); + // GetForegroundDrawList()->AddRect(bs->BoxSelectRectPrev.Min, bs->BoxSelectRectPrev.Max, IM_COL32(255,0,0,200), + // 0.0f, 0, 3.0f); GetForegroundDrawList()->AddRect(bs->BoxSelectRectCurr.Min, bs->BoxSelectRectCurr.Max, + // IM_COL32(0,255,0,200), 0.0f, 0, 1.0f); return true; } -void ImGui::EndBoxSelect(const ImRect& scope_rect, ImGuiMultiSelectFlags ms_flags) +void ImGui::EndBoxSelect(const ImRect &scope_rect, ImGuiMultiSelectFlags ms_flags) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - ImGuiBoxSelectState* bs = &g.BoxSelectState; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; + ImGuiBoxSelectState *bs = &g.BoxSelectState; IM_ASSERT(bs->IsActive); bs->UnclipMode = false; // Render selection rectangle - bs->EndPosRel = WindowPosAbsToRel(window, ImClamp(g.IO.MousePos, scope_rect.Min, scope_rect.Max)); // Clamp stored position according to current scrolling view + bs->EndPosRel = + WindowPosAbsToRel(window, ImClamp(g.IO.MousePos, scope_rect.Min, + scope_rect.Max)); // Clamp stored position according to current scrolling view ImRect box_select_r = bs->BoxSelectRectCurr; box_select_r.ClipWith(scope_rect); - window->DrawList->AddRectFilled(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_SeparatorHovered, 0.30f)); // FIXME-MULTISELECT: Styling - window->DrawList->AddRect(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_NavCursor)); // FIXME-MULTISELECT FIXME-DPI: Styling + window->DrawList->AddRectFilled(box_select_r.Min, box_select_r.Max, + GetColorU32(ImGuiCol_SeparatorHovered, 0.30f)); // FIXME-MULTISELECT: Styling + window->DrawList->AddRect(box_select_r.Min, box_select_r.Max, + GetColorU32(ImGuiCol_NavCursor)); // FIXME-MULTISELECT FIXME-DPI: Styling // Scroll - const bool enable_scroll = (ms_flags & ImGuiMultiSelectFlags_ScopeWindow) && (ms_flags & ImGuiMultiSelectFlags_BoxSelectNoScroll) == 0; + const bool enable_scroll = + (ms_flags & ImGuiMultiSelectFlags_ScopeWindow) && (ms_flags & ImGuiMultiSelectFlags_BoxSelectNoScroll) == 0; if (enable_scroll) { ImRect scroll_r = scope_rect; scroll_r.Expand(-g.FontSize); - //GetForegroundDrawList()->AddRect(scroll_r.Min, scroll_r.Max, IM_COL32(0, 255, 0, 255)); + // GetForegroundDrawList()->AddRect(scroll_r.Min, scroll_r.Max, IM_COL32(0, 255, 0, 255)); if (!scroll_r.Contains(g.IO.MousePos)) BoxSelectScrollWithMouseDrag(bs, window, scroll_r); } @@ -7660,20 +8771,26 @@ void ImGui::EndBoxSelect(const ImRect& scope_rect, ImGuiMultiSelectFlags ms_flag // - DebugNodeMultiSelectState() [Internal] //------------------------------------------------------------------------- -static void DebugLogMultiSelectRequests(const char* function, const ImGuiMultiSelectIO* io) +static void DebugLogMultiSelectRequests(const char *function, const ImGuiMultiSelectIO *io) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; IM_UNUSED(function); - for (const ImGuiSelectionRequest& req : io->Requests) + for (const ImGuiSelectionRequest &req : io->Requests) { - if (req.Type == ImGuiSelectionRequestType_SetAll) IMGUI_DEBUG_LOG_SELECTION("[selection] %s: Request: SetAll %d (= %s)\n", function, req.Selected, req.Selected ? "SelectAll" : "Clear"); - if (req.Type == ImGuiSelectionRequestType_SetRange) IMGUI_DEBUG_LOG_SELECTION("[selection] %s: Request: SetRange %" IM_PRId64 "..%" IM_PRId64 " (0x%" IM_PRIX64 "..0x%" IM_PRIX64 ") = %d (dir %d)\n", function, req.RangeFirstItem, req.RangeLastItem, req.RangeFirstItem, req.RangeLastItem, req.Selected, req.RangeDirection); + if (req.Type == ImGuiSelectionRequestType_SetAll) + IMGUI_DEBUG_LOG_SELECTION("[selection] %s: Request: SetAll %d (= %s)\n", function, req.Selected, + req.Selected ? "SelectAll" : "Clear"); + if (req.Type == ImGuiSelectionRequestType_SetRange) + IMGUI_DEBUG_LOG_SELECTION("[selection] %s: Request: SetRange %" IM_PRId64 "..%" IM_PRId64 " (0x%" IM_PRIX64 + "..0x%" IM_PRIX64 ") = %d (dir %d)\n", + function, req.RangeFirstItem, req.RangeLastItem, req.RangeFirstItem, + req.RangeLastItem, req.Selected, req.RangeDirection); } } -static ImRect CalcScopeRect(ImGuiMultiSelectTempData* ms, ImGuiWindow* window) +static ImRect CalcScopeRect(ImGuiMultiSelectTempData *ms, ImGuiWindow *window) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; if (ms->Flags & ImGuiMultiSelectFlags_ScopeRect) { // Warning: this depends on CursorMaxPos so it means to be called by EndMultiSelect() only @@ -7681,33 +8798,39 @@ static ImRect CalcScopeRect(ImGuiMultiSelectTempData* ms, ImGuiWindow* window) } else { - // When a table, pull HostClipRect, which allows us to predict ClipRect before first row/layout is performed. (#7970) + // When a table, pull HostClipRect, which allows us to predict ClipRect before first row/layout is performed. + // (#7970) ImRect scope_rect = window->InnerClipRect; if (g.CurrentTable != NULL) scope_rect = g.CurrentTable->HostClipRect; // Add inner table decoration (#7821) // FIXME: Why not baking in InnerClipRect? - scope_rect.Min = ImMin(scope_rect.Min + ImVec2(window->DecoInnerSizeX1, window->DecoInnerSizeY1), scope_rect.Max); + scope_rect.Min = + ImMin(scope_rect.Min + ImVec2(window->DecoInnerSizeX1, window->DecoInnerSizeY1), scope_rect.Max); return scope_rect; } } // Return ImGuiMultiSelectIO structure. -// Lifetime: don't hold on ImGuiMultiSelectIO* pointers over multiple frames or past any subsequent call to BeginMultiSelect() or EndMultiSelect(). -// Passing 'selection_size' and 'items_count' parameters is currently optional. -// - 'selection_size' is useful to disable some shortcut routing: e.g. ImGuiMultiSelectFlags_ClearOnEscape won't claim Escape key when selection_size 0, +// Lifetime: don't hold on ImGuiMultiSelectIO* pointers over multiple frames or past any subsequent call to +// BeginMultiSelect() or EndMultiSelect(). Passing 'selection_size' and 'items_count' parameters is currently optional. +// - 'selection_size' is useful to disable some shortcut routing: e.g. ImGuiMultiSelectFlags_ClearOnEscape won't claim +// Escape key when selection_size 0, // allowing a first press to clear selection THEN the second press to leave child window and return to parent. -// - 'items_count' is stored in ImGuiMultiSelectIO which makes it a convenient way to pass the information to your ApplyRequest() handler (but you may pass it differently). -// - If they are costly for you to compute (e.g. external intrusive selection without maintaining size), you may avoid them and pass -1. -// - If you can easily tell if your selection is empty or not, you may pass 0/1, or you may enable ImGuiMultiSelectFlags_ClearOnEscape flag dynamically. -ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int selection_size, int items_count) +// - 'items_count' is stored in ImGuiMultiSelectIO which makes it a convenient way to pass the information to your +// ApplyRequest() handler (but you may pass it differently). +// - If they are costly for you to compute (e.g. external intrusive selection without maintaining size), you may avoid +// them and pass -1. +// - If you can easily tell if your selection is empty or not, you may pass 0/1, or you may enable +// ImGuiMultiSelectFlags_ClearOnEscape flag dynamically. +ImGuiMultiSelectIO *ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int selection_size, int items_count) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; if (++g.MultiSelectTempDataStacked > g.MultiSelectTempData.Size) g.MultiSelectTempData.resize(g.MultiSelectTempDataStacked, ImGuiMultiSelectTempData()); - ImGuiMultiSelectTempData* ms = &g.MultiSelectTempData[g.MultiSelectTempDataStacked - 1]; + ImGuiMultiSelectTempData *ms = &g.MultiSelectTempData[g.MultiSelectTempDataStacked - 1]; IM_STATIC_ASSERT(offsetof(ImGuiMultiSelectTempData, IO) == 0); // Clear() relies on that. g.CurrentMultiSelect = ms; if ((flags & (ImGuiMultiSelectFlags_ScopeWindow | ImGuiMultiSelectFlags_ScopeRect)) == 0) @@ -7719,9 +8842,10 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel // FIXME: Workaround to the fact we override CursorMaxPos, meaning size measurement are lost. (#8250) // They should perhaps be stacked properly? - if (ImGuiTable* table = g.CurrentTable) + if (ImGuiTable *table = g.CurrentTable) if (table->CurrentColumn != -1) - TableEndCell(table); // This is currently safe to call multiple time. If that properly is lost we can extract the "save measurement" part of it. + TableEndCell(table); // This is currently safe to call multiple time. If that properly is lost we can + // extract the "save measurement" part of it. // FIXME: BeginFocusScope() const ImGuiID id = window->IDStack.back(); @@ -7732,16 +8856,18 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel ms->BackupCursorMaxPos = window->DC.CursorMaxPos; ms->ScopeRectMin = window->DC.CursorMaxPos = window->DC.CursorPos; PushFocusScope(ms->FocusScopeId); - if (flags & ImGuiMultiSelectFlags_ScopeWindow) // Mark parent child window as navigable into, with highlight. Assume user will always submit interactive items. + if (flags & ImGuiMultiSelectFlags_ScopeWindow) // Mark parent child window as navigable into, with highlight. Assume + // user will always submit interactive items. window->DC.NavLayersActiveMask |= 1 << ImGuiNavLayer_Main; - // Use copy of keyboard mods at the time of the request, otherwise we would requires mods to be held for an extra frame. + // Use copy of keyboard mods at the time of the request, otherwise we would requires mods to be held for an extra + // frame. ms->KeyMods = g.NavJustMovedToId ? (g.NavJustMovedToIsTabbing ? 0 : g.NavJustMovedToKeyMods) : g.IO.KeyMods; if (flags & ImGuiMultiSelectFlags_NoRangeSelect) ms->KeyMods &= ~ImGuiMod_Shift; // Bind storage - ImGuiMultiSelectState* storage = g.MultiSelectStorage.GetOrAddByKey(id); + ImGuiMultiSelectState *storage = g.MultiSelectStorage.GetOrAddByKey(id); storage->ID = id; storage->LastFrameActive = g.FrameCount; storage->LastSelectionSize = selection_size; @@ -7765,18 +8891,20 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel ms->IsKeyboardSetRange = true; if (ms->IsKeyboardSetRange) IM_ASSERT(storage->RangeSrcItem != ImGuiSelectionUserData_Invalid); // Not ready -> could clear? - if ((ms->KeyMods & (ImGuiMod_Ctrl | ImGuiMod_Shift)) == 0 && (flags & (ImGuiMultiSelectFlags_NoAutoClear | ImGuiMultiSelectFlags_NoAutoSelect)) == 0) + if ((ms->KeyMods & (ImGuiMod_Ctrl | ImGuiMod_Shift)) == 0 && + (flags & (ImGuiMultiSelectFlags_NoAutoClear | ImGuiMultiSelectFlags_NoAutoSelect)) == 0) request_clear = true; } else if (g.NavJustMovedFromFocusScopeId == ms->FocusScopeId) { // Also clear on leaving scope (may be optional?) - if ((ms->KeyMods & (ImGuiMod_Ctrl | ImGuiMod_Shift)) == 0 && (flags & (ImGuiMultiSelectFlags_NoAutoClear | ImGuiMultiSelectFlags_NoAutoSelect)) == 0) + if ((ms->KeyMods & (ImGuiMod_Ctrl | ImGuiMod_Shift)) == 0 && + (flags & (ImGuiMultiSelectFlags_NoAutoClear | ImGuiMultiSelectFlags_NoAutoSelect)) == 0) request_clear = true; } // Box-select handling: update active state. - ImGuiBoxSelectState* bs = &g.BoxSelectState; + ImGuiBoxSelectState *bs = &g.BoxSelectState; if (flags & (ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d)) { ms->BoxSelectId = GetID("##BoxSelect"); @@ -7787,7 +8915,8 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel if (ms->IsFocused) { // Shortcut: Clear selection (Escape) - // - Only claim shortcut if selection is not empty, allowing further presses on Escape to e.g. leave current child window. + // - Only claim shortcut if selection is not empty, allowing further presses on Escape to e.g. leave current + // child window. // - Box select also handle Escape and needs to pass an id to bypass ActiveIdUsingAllKeyboardKeys lock. if (flags & ImGuiMultiSelectFlags_ClearOnEscape) { @@ -7822,22 +8951,29 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel } // Return updated ImGuiMultiSelectIO structure. -// Lifetime: don't hold on ImGuiMultiSelectIO* pointers over multiple frames or past any subsequent call to BeginMultiSelect() or EndMultiSelect(). -ImGuiMultiSelectIO* ImGui::EndMultiSelect() +// Lifetime: don't hold on ImGuiMultiSelectIO* pointers over multiple frames or past any subsequent call to +// BeginMultiSelect() or EndMultiSelect(). +ImGuiMultiSelectIO *ImGui::EndMultiSelect() { - ImGuiContext& g = *GImGui; - ImGuiMultiSelectTempData* ms = g.CurrentMultiSelect; - ImGuiMultiSelectState* storage = ms->Storage; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiMultiSelectTempData *ms = g.CurrentMultiSelect; + ImGuiMultiSelectState *storage = ms->Storage; + ImGuiWindow *window = g.CurrentWindow; IM_ASSERT_USER_ERROR(ms->FocusScopeId == g.CurrentFocusScopeId, "EndMultiSelect() FocusScope mismatch!"); IM_ASSERT(g.CurrentMultiSelect != NULL && storage->Window == g.CurrentWindow); - IM_ASSERT(g.MultiSelectTempDataStacked > 0 && &g.MultiSelectTempData[g.MultiSelectTempDataStacked - 1] == g.CurrentMultiSelect); + IM_ASSERT(g.MultiSelectTempDataStacked > 0 && + &g.MultiSelectTempData[g.MultiSelectTempDataStacked - 1] == g.CurrentMultiSelect); ImRect scope_rect = CalcScopeRect(ms, window); if (ms->IsFocused) { - // We currently don't allow user code to modify RangeSrcItem by writing to BeginIO's version, but that would be an easy change here. - if (ms->IO.RangeSrcReset || (ms->RangeSrcPassedBy == false && ms->IO.RangeSrcItem != ImGuiSelectionUserData_Invalid)) // Can't read storage->RangeSrcItem here -> we want the state at beginning of the scope (see tests for easy failure) + // We currently don't allow user code to modify RangeSrcItem by writing to BeginIO's version, but that would be + // an easy change here. + if (ms->IO.RangeSrcReset || + (ms->RangeSrcPassedBy == false && + ms->IO.RangeSrcItem != + ImGuiSelectionUserData_Invalid)) // Can't read storage->RangeSrcItem here -> we want the state at + // beginning of the scope (see tests for easy failure) { IMGUI_DEBUG_LOG_SELECTION("[selection] EndMultiSelect: Reset RangeSrcItem.\n"); // Will set be to NavId. storage->RangeSrcItem = ImGuiSelectionUserData_Invalid; @@ -7849,7 +8985,8 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect() storage->NavIdSelected = -1; } - if ((ms->Flags & (ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d)) && GetBoxSelectState(ms->BoxSelectId)) + if ((ms->Flags & (ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d)) && + GetBoxSelectState(ms->BoxSelectId)) EndBoxSelect(scope_rect, ms->Flags); } @@ -7872,7 +9009,9 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect() FocusWindow(window, ImGuiFocusRequestFlags_UnlessBelowModal); SetHoveredID(ms->BoxSelectId); if (ms->Flags & ImGuiMultiSelectFlags_ScopeRect) - SetNavID(0, ImGuiNavLayer_Main, ms->FocusScopeId, ImRect(g.IO.MousePos, g.IO.MousePos)); // Automatically switch FocusScope for initial click from void to box-select. + SetNavID(0, ImGuiNavLayer_Main, ms->FocusScopeId, + ImRect(g.IO.MousePos, g.IO.MousePos)); // Automatically switch FocusScope for initial click + // from void to box-select. } } @@ -7897,7 +9036,8 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect() ms->FocusScopeId = 0; ms->Flags = ImGuiMultiSelectFlags_None; - g.CurrentMultiSelect = (--g.MultiSelectTempDataStacked > 0) ? &g.MultiSelectTempData[g.MultiSelectTempDataStacked - 1] : NULL; + g.CurrentMultiSelect = + (--g.MultiSelectTempDataStacked > 0) ? &g.MultiSelectTempData[g.MultiSelectTempDataStacked - 1] : NULL; return &ms->IO; } @@ -7905,12 +9045,13 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect() void ImGui::SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_data) { // Note that flags will be cleared by ItemAdd(), so it's only useful for Navigation code! - // This designed so widgets can also cheaply set this before calling ItemAdd(), so we are not tied to MultiSelect api. - ImGuiContext& g = *GImGui; + // This designed so widgets can also cheaply set this before calling ItemAdd(), so we are not tied to MultiSelect + // api. + ImGuiContext &g = *GImGui; g.NextItemData.SelectionUserData = selection_user_data; g.NextItemData.FocusScopeId = g.CurrentFocusScopeId; - if (ImGuiMultiSelectTempData* ms = g.CurrentMultiSelect) + if (ImGuiMultiSelectTempData *ms = g.CurrentMultiSelect) { // Auto updating RangeSrcPassedBy for cases were clipper is not used (done before ItemAdd() clipping) g.NextItemData.ItemFlags |= ImGuiItemFlags_HasSelectionUserData | ImGuiItemFlags_IsMultiSelect; @@ -7927,33 +9068,40 @@ void ImGui::SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_d // - Applying SetAll for submitted items. // - Applying SetRange for submitted items and record end points. // - Altering button behavior flags to facilitate use with drag and drop. -void ImGui::MultiSelectItemHeader(ImGuiID id, bool* p_selected, ImGuiButtonFlags* p_button_flags) +void ImGui::MultiSelectItemHeader(ImGuiID id, bool *p_selected, ImGuiButtonFlags *p_button_flags) { - ImGuiContext& g = *GImGui; - ImGuiMultiSelectTempData* ms = g.CurrentMultiSelect; + ImGuiContext &g = *GImGui; + ImGuiMultiSelectTempData *ms = g.CurrentMultiSelect; bool selected = *p_selected; if (ms->IsFocused) { - ImGuiMultiSelectState* storage = ms->Storage; + ImGuiMultiSelectState *storage = ms->Storage; ImGuiSelectionUserData item_data = g.NextItemData.SelectionUserData; - IM_ASSERT(g.NextItemData.FocusScopeId == g.CurrentFocusScopeId && "Forgot to call SetNextItemSelectionUserData() prior to item, required in BeginMultiSelect()/EndMultiSelect() scope"); + IM_ASSERT(g.NextItemData.FocusScopeId == g.CurrentFocusScopeId && + "Forgot to call SetNextItemSelectionUserData() prior to item, required in " + "BeginMultiSelect()/EndMultiSelect() scope"); // Apply SetAll (Clear/SelectAll) requests requested by BeginMultiSelect(). - // This is only useful if the user hasn't processed them already, and this only works if the user isn't using the clipper. - // If you are using a clipper you need to process the SetAll request after calling BeginMultiSelect() + // This is only useful if the user hasn't processed them already, and this only works if the user isn't using + // the clipper. If you are using a clipper you need to process the SetAll request after calling + // BeginMultiSelect() if (ms->LoopRequestSetAll != -1) selected = (ms->LoopRequestSetAll == 1); - // When using SHIFT+Nav: because it can incur scrolling we cannot afford a frame of lag with the selection highlight (otherwise scrolling would happen before selection) - // For this to work, we need someone to set 'RangeSrcPassedBy = true' at some point (either clipper either SetNextItemSelectionUserData() function) + // When using SHIFT+Nav: because it can incur scrolling we cannot afford a frame of lag with the selection + // highlight (otherwise scrolling would happen before selection) For this to work, we need someone to set + // 'RangeSrcPassedBy = true' at some point (either clipper either SetNextItemSelectionUserData() function) if (ms->IsKeyboardSetRange) { IM_ASSERT(id != 0 && (ms->KeyMods & ImGuiMod_Shift) != 0); - const bool is_range_dst = (ms->RangeDstPassedBy == false) && g.NavJustMovedToId == id; // Assume that g.NavJustMovedToId is not clipped. + const bool is_range_dst = (ms->RangeDstPassedBy == false) && + g.NavJustMovedToId == id; // Assume that g.NavJustMovedToId is not clipped. if (is_range_dst) ms->RangeDstPassedBy = true; - if (is_range_dst && storage->RangeSrcItem == ImGuiSelectionUserData_Invalid) // If we don't have RangeSrc, assign RangeSrc = RangeDst + if (is_range_dst && + storage->RangeSrcItem == + ImGuiSelectionUserData_Invalid) // If we don't have RangeSrc, assign RangeSrc = RangeDst { storage->RangeSrcItem = item_data; storage->RangeSelected = selected ? 1 : 0; @@ -7976,12 +9124,14 @@ void ImGui::MultiSelectItemHeader(ImGuiID id, bool* p_selected, ImGuiButtonFlags // Alter button behavior flags // To handle drag and drop of multiple items we need to avoid clearing selection on click. - // Enabling this test makes actions using CTRL+SHIFT delay their effect on MouseUp which is annoying, but it allows drag and drop of multiple items. + // Enabling this test makes actions using CTRL+SHIFT delay their effect on MouseUp which is annoying, but it allows + // drag and drop of multiple items. if (p_button_flags != NULL) { ImGuiButtonFlags button_flags = *p_button_flags; button_flags |= ImGuiButtonFlags_NoHoveredOnFocus; - if ((!selected || (g.ActiveId == id && g.ActiveIdHasBeenPressedBefore)) && !(ms->Flags & ImGuiMultiSelectFlags_SelectOnClickRelease)) + if ((!selected || (g.ActiveId == id && g.ActiveIdHasBeenPressedBefore)) && + !(ms->Flags & ImGuiMultiSelectFlags_SelectOnClickRelease)) button_flags = (button_flags | ImGuiButtonFlags_PressedOnClick) & ~ImGuiButtonFlags_PressedOnClickRelease; else button_flags |= ImGuiButtonFlags_PressedOnClickRelease; @@ -7996,15 +9146,15 @@ void ImGui::MultiSelectItemHeader(ImGuiID id, bool* p_selected, ImGuiButtonFlags // - Altering selection based on Ctrl/Shift modifiers, both for keyboard and mouse. // - Record current selection state for RangeSrc // This is all rather complex, best to run and refer to "widgets_multiselect_xxx" tests in imgui_test_suite. -void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) +void ImGui::MultiSelectItemFooter(ImGuiID id, bool *p_selected, bool *p_pressed) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; bool selected = *p_selected; bool pressed = *p_pressed; - ImGuiMultiSelectTempData* ms = g.CurrentMultiSelect; - ImGuiMultiSelectState* storage = ms->Storage; + ImGuiMultiSelectTempData *ms = g.CurrentMultiSelect; + ImGuiMultiSelectState *storage = ms->Storage; if (pressed) ms->IsFocused = true; @@ -8059,7 +9209,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) // Box-select toggle handling if (ms->BoxSelectId != 0) - if (ImGuiBoxSelectState* bs = GetBoxSelectState(ms->BoxSelectId)) + if (ImGuiBoxSelectState *bs = GetBoxSelectState(ms->BoxSelectId)) { const bool rect_overlap_curr = bs->BoxSelectRectCurr.Overlaps(g.LastItemData.Rect); const bool rect_overlap_prev = bs->BoxSelectRectPrev.Overlaps(g.LastItemData.Rect); @@ -8067,7 +9217,8 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) { if (storage->LastSelectionSize <= 0 && bs->IsStartedSetNavIdOnce) { - pressed = true; // First item act as a pressed: code below will emit selection request and set NavId (whatever we emit here will be overridden anyway) + pressed = true; // First item act as a pressed: code below will emit selection request and set NavId + // (whatever we emit here will be overridden anyway) bs->IsStartedSetNavIdOnce = false; } else @@ -8080,7 +9231,8 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) } // Right-click handling. - // FIXME-MULTISELECT: Currently filtered out by ImGuiMultiSelectFlags_NoAutoSelect but maybe should be moved to Selectable(). See https://github.com/ocornut/imgui/pull/5816 + // FIXME-MULTISELECT: Currently filtered out by ImGuiMultiSelectFlags_NoAutoSelect but maybe should be moved to + // Selectable(). See https://github.com/ocornut/imgui/pull/5816 if (hovered && IsMouseClicked(1) && (flags & ImGuiMultiSelectFlags_NoAutoSelect) == 0) { if (g.ActiveId != 0 && g.ActiveId != id) @@ -8094,17 +9246,21 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) } // Unlike Space, Enter doesn't alter selection (but can still return a press) unless current item is not selected. - // The later, "unless current item is not select", may become optional? It seems like a better default if Enter doesn't necessarily open something - // (unlike e.g. Windows explorer). For use case where Enter always open something, we might decide to make this optional? - const bool enter_pressed = pressed && (g.NavActivateId == id) && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput); + // The later, "unless current item is not select", may become optional? It seems like a better default if Enter + // doesn't necessarily open something (unlike e.g. Windows explorer). For use case where Enter always open + // something, we might decide to make this optional? + const bool enter_pressed = + pressed && (g.NavActivateId == id) && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput); // Alter selection if (pressed && (!enter_pressed || !selected)) { // Box-select - ImGuiInputSource input_source = (g.NavJustMovedToId == id || g.NavActivateId == id) ? g.NavInputSource : ImGuiInputSource_Mouse; + ImGuiInputSource input_source = + (g.NavJustMovedToId == id || g.NavActivateId == id) ? g.NavInputSource : ImGuiInputSource_Mouse; if (flags & (ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d)) - if (selected == false && !g.BoxSelectState.IsActive && !g.BoxSelectState.IsStarting && input_source == ImGuiInputSource_Mouse && g.IO.MouseClickedCount[0] == 1) + if (selected == false && !g.BoxSelectState.IsActive && !g.BoxSelectState.IsStarting && + input_source == ImGuiInputSource_Mouse && g.IO.MouseClickedCount[0] == 1) BoxSelectPreStartDrag(ms->BoxSelectId, item_data); //---------------------------------------------------------------------------------------- @@ -8131,8 +9287,10 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) request_clear = true; else if ((input_source == ImGuiInputSource_Mouse || g.NavActivateId == id) && !is_ctrl) request_clear = (flags & ImGuiMultiSelectFlags_NoAutoClearOnReselect) ? !selected : true; - else if ((input_source == ImGuiInputSource_Keyboard || input_source == ImGuiInputSource_Gamepad) && is_shift && !is_ctrl) - request_clear = true; // With is_shift==false the RequestClear was done in BeginIO, not necessary to do again. + else if ((input_source == ImGuiInputSource_Keyboard || input_source == ImGuiInputSource_Gamepad) && + is_shift && !is_ctrl) + request_clear = + true; // With is_shift==false the RequestClear was done in BeginIO, not necessary to do again. if (request_clear) MultiSelectAddSetAll(ms, false); } @@ -8141,13 +9299,14 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) bool range_selected; if (is_shift && !is_singleselect) { - //IM_ASSERT(storage->HasRangeSrc && storage->HasRangeValue); + // IM_ASSERT(storage->HasRangeSrc && storage->HasRangeValue); if (storage->RangeSrcItem == ImGuiSelectionUserData_Invalid) storage->RangeSrcItem = item_data; if ((flags & ImGuiMultiSelectFlags_NoAutoSelect) == 0) { // Shift+Arrow always select - // Ctrl+Shift+Arrow copy source selection state (already stored by BeginMultiSelect() in storage->RangeSelected) + // Ctrl+Shift+Arrow copy source selection state (already stored by BeginMultiSelect() in + // storage->RangeSelected) range_selected = (is_ctrl && storage->RangeSelected != -1) ? (storage->RangeSelected != 0) : true; } else @@ -8175,7 +9334,8 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) MultiSelectAddSetRange(ms, range_selected, range_direction, storage->RangeSrcItem, item_data); } - // Update/store the selection state of the Source item (used by CTRL+SHIFT, when Source is unselected we perform a range unselect) + // Update/store the selection state of the Source item (used by CTRL+SHIFT, when Source is unselected we perform a + // range unselect) if (storage->RangeSrcItem == item_data) storage->RangeSelected = selected ? 1 : 0; @@ -8193,41 +9353,56 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) *p_pressed = pressed; } -void ImGui::MultiSelectAddSetAll(ImGuiMultiSelectTempData* ms, bool selected) +void ImGui::MultiSelectAddSetAll(ImGuiMultiSelectTempData *ms, bool selected) { - ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetAll, selected, 0, ImGuiSelectionUserData_Invalid, ImGuiSelectionUserData_Invalid }; + ImGuiSelectionRequest req = {ImGuiSelectionRequestType_SetAll, selected, 0, ImGuiSelectionUserData_Invalid, + ImGuiSelectionUserData_Invalid}; ms->IO.Requests.resize(0); // Can always clear previous requests ms->IO.Requests.push_back(req); // Add new request } -void ImGui::MultiSelectAddSetRange(ImGuiMultiSelectTempData* ms, bool selected, int range_dir, ImGuiSelectionUserData first_item, ImGuiSelectionUserData last_item) +void ImGui::MultiSelectAddSetRange(ImGuiMultiSelectTempData *ms, bool selected, int range_dir, + ImGuiSelectionUserData first_item, ImGuiSelectionUserData last_item) { // Merge contiguous spans into same request (unless NoRangeSelect is set which guarantees single-item ranges) if (ms->IO.Requests.Size > 0 && first_item == last_item && (ms->Flags & ImGuiMultiSelectFlags_NoRangeSelect) == 0) { - ImGuiSelectionRequest* prev = &ms->IO.Requests.Data[ms->IO.Requests.Size - 1]; - if (prev->Type == ImGuiSelectionRequestType_SetRange && prev->RangeLastItem == ms->LastSubmittedItem && prev->Selected == selected) + ImGuiSelectionRequest *prev = &ms->IO.Requests.Data[ms->IO.Requests.Size - 1]; + if (prev->Type == ImGuiSelectionRequestType_SetRange && prev->RangeLastItem == ms->LastSubmittedItem && + prev->Selected == selected) { prev->RangeLastItem = last_item; return; } } - ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetRange, selected, (ImS8)range_dir, (range_dir > 0) ? first_item : last_item, (range_dir > 0) ? last_item : first_item }; + ImGuiSelectionRequest req = {ImGuiSelectionRequestType_SetRange, selected, (ImS8)range_dir, + (range_dir > 0) ? first_item : last_item, (range_dir > 0) ? last_item : first_item}; ms->IO.Requests.push_back(req); // Add new request } -void ImGui::DebugNodeMultiSelectState(ImGuiMultiSelectState* storage) +void ImGui::DebugNodeMultiSelectState(ImGuiMultiSelectState *storage) { #ifndef IMGUI_DISABLE_DEBUG_TOOLS - const bool is_active = (storage->LastFrameActive >= GetFrameCount() - 2); // Note that fully clipped early out scrolling tables will appear as inactive here. - if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } - bool open = TreeNode((void*)(intptr_t)storage->ID, "MultiSelect 0x%08X in '%s'%s", storage->ID, storage->Window ? storage->Window->Name : "N/A", is_active ? "" : " *Inactive*"); - if (!is_active) { PopStyleColor(); } + const bool is_active = + (storage->LastFrameActive >= + GetFrameCount() - 2); // Note that fully clipped early out scrolling tables will appear as inactive here. + if (!is_active) + { + PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); + } + bool open = TreeNode((void *)(intptr_t)storage->ID, "MultiSelect 0x%08X in '%s'%s", storage->ID, + storage->Window ? storage->Window->Name : "N/A", is_active ? "" : " *Inactive*"); + if (!is_active) + { + PopStyleColor(); + } if (!open) return; - Text("RangeSrcItem = %" IM_PRId64 " (0x%" IM_PRIX64 "), RangeSelected = %d", storage->RangeSrcItem, storage->RangeSrcItem, storage->RangeSelected); - Text("NavIdItem = %" IM_PRId64 " (0x%" IM_PRIX64 "), NavIdSelected = %d", storage->NavIdItem, storage->NavIdItem, storage->NavIdSelected); + Text("RangeSrcItem = %" IM_PRId64 " (0x%" IM_PRIX64 "), RangeSelected = %d", storage->RangeSrcItem, + storage->RangeSrcItem, storage->RangeSelected); + Text("NavIdItem = %" IM_PRId64 " (0x%" IM_PRIX64 "), NavIdSelected = %d", storage->NavIdItem, storage->NavIdItem, + storage->NavIdSelected); Text("LastSelectionSize = %d", storage->LastSelectionSize); // Provided by user TreePop(); #else @@ -8247,7 +9422,7 @@ ImGuiSelectionBasicStorage::ImGuiSelectionBasicStorage() Size = 0; PreserveOrder = false; UserData = NULL; - AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage*, int idx) { return (ImGuiID)idx; }; + AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage *, int idx) { return (ImGuiID)idx; }; _SelectionOrder = 1; // Always >0 } @@ -8258,7 +9433,7 @@ void ImGuiSelectionBasicStorage::Clear() _Storage.Data.resize(0); } -void ImGuiSelectionBasicStorage::Swap(ImGuiSelectionBasicStorage& r) +void ImGuiSelectionBasicStorage::Swap(ImGuiSelectionBasicStorage &r) { ImSwap(Size, r.Size); ImSwap(_SelectionOrder, r._SelectionOrder); @@ -8270,21 +9445,23 @@ bool ImGuiSelectionBasicStorage::Contains(ImGuiID id) const return _Storage.GetInt(id, 0) != 0; } -static int IMGUI_CDECL PairComparerByValueInt(const void* lhs, const void* rhs) +static int IMGUI_CDECL PairComparerByValueInt(const void *lhs, const void *rhs) { - int lhs_v = ((const ImGuiStoragePair*)lhs)->val_i; - int rhs_v = ((const ImGuiStoragePair*)rhs)->val_i; + int lhs_v = ((const ImGuiStoragePair *)lhs)->val_i; + int rhs_v = ((const ImGuiStoragePair *)rhs)->val_i; return (lhs_v > rhs_v ? +1 : lhs_v < rhs_v ? -1 : 0); } -// GetNextSelectedItem() is an abstraction allowing us to change our underlying actual storage system without impacting user. -// (e.g. store unselected vs compact down, compact down on demand, use raw ImVector instead of ImGuiStorage...) -bool ImGuiSelectionBasicStorage::GetNextSelectedItem(void** opaque_it, ImGuiID* out_id) +// GetNextSelectedItem() is an abstraction allowing us to change our underlying actual storage system without impacting +// user. (e.g. store unselected vs compact down, compact down on demand, use raw ImVector instead of +// ImGuiStorage...) +bool ImGuiSelectionBasicStorage::GetNextSelectedItem(void **opaque_it, ImGuiID *out_id) { - ImGuiStoragePair* it = (ImGuiStoragePair*)*opaque_it; - ImGuiStoragePair* it_end = _Storage.Data.Data + _Storage.Data.Size; + ImGuiStoragePair *it = (ImGuiStoragePair *)*opaque_it; + ImGuiStoragePair *it_end = _Storage.Data.Data + _Storage.Data.Size; if (PreserveOrder && it == NULL && it_end != NULL) - ImQsort(_Storage.Data.Data, (size_t)_Storage.Data.Size, sizeof(ImGuiStoragePair), PairComparerByValueInt); // ~ImGuiStorage::BuildSortByValueInt() + ImQsort(_Storage.Data.Data, (size_t)_Storage.Data.Size, sizeof(ImGuiStoragePair), + PairComparerByValueInt); // ~ImGuiStorage::BuildSortByValueInt() if (it == NULL) it = _Storage.Data.Data; IM_ASSERT(it >= _Storage.Data.Data && it <= it_end); @@ -8292,7 +9469,7 @@ bool ImGuiSelectionBasicStorage::GetNextSelectedItem(void** opaque_it, ImGuiID* while (it->val_i == 0 && it < it_end) it++; const bool has_more = (it != it_end); - *opaque_it = has_more ? (void**)(it + 1) : (void**)(it); + *opaque_it = has_more ? (void **)(it + 1) : (void **)(it); *out_id = has_more ? it->key : 0; if (PreserveOrder && !has_more) _Storage.BuildSortByKey(); @@ -8301,29 +9478,40 @@ bool ImGuiSelectionBasicStorage::GetNextSelectedItem(void** opaque_it, ImGuiID* void ImGuiSelectionBasicStorage::SetItemSelected(ImGuiID id, bool selected) { - int* p_int = _Storage.GetIntRef(id, 0); - if (selected && *p_int == 0) { *p_int = _SelectionOrder++; Size++; } - else if (!selected && *p_int != 0) { *p_int = 0; Size--; } + int *p_int = _Storage.GetIntRef(id, 0); + if (selected && *p_int == 0) + { + *p_int = _SelectionOrder++; + Size++; + } + else if (!selected && *p_int != 0) + { + *p_int = 0; + Size--; + } } // Optimized for batch edits (with same value of 'selected') -static void ImGuiSelectionBasicStorage_BatchSetItemSelected(ImGuiSelectionBasicStorage* selection, ImGuiID id, bool selected, int size_before_amends, int selection_order) +static void ImGuiSelectionBasicStorage_BatchSetItemSelected(ImGuiSelectionBasicStorage *selection, ImGuiID id, + bool selected, int size_before_amends, int selection_order) { - ImGuiStorage* storage = &selection->_Storage; - ImGuiStoragePair* it = ImLowerBound(storage->Data.Data, storage->Data.Data + size_before_amends, id); + ImGuiStorage *storage = &selection->_Storage; + ImGuiStoragePair *it = ImLowerBound(storage->Data.Data, storage->Data.Data + size_before_amends, id); const bool is_contained = (it != storage->Data.Data + size_before_amends) && (it->key == id); if (selected == (is_contained && it->val_i != 0)) return; if (selected && !is_contained) - storage->Data.push_back(ImGuiStoragePair(id, selection_order)); // Push unsorted at end of vector, will be sorted in SelectionMultiAmendsFinish() + storage->Data.push_back(ImGuiStoragePair( + id, selection_order)); // Push unsorted at end of vector, will be sorted in SelectionMultiAmendsFinish() else if (is_contained) it->val_i = selected ? selection_order : 0; // Modify in-place. selection->Size += selected ? +1 : -1; } -static void ImGuiSelectionBasicStorage_BatchFinish(ImGuiSelectionBasicStorage* selection, bool selected, int size_before_amends) +static void ImGuiSelectionBasicStorage_BatchFinish(ImGuiSelectionBasicStorage *selection, bool selected, + int size_before_amends) { - ImGuiStorage* storage = &selection->_Storage; + ImGuiStorage *storage = &selection->_Storage; if (selected && selection->Size != size_before_amends) storage->BuildSortByKey(); // When done selecting: sort everything } @@ -8331,20 +9519,24 @@ static void ImGuiSelectionBasicStorage_BatchFinish(ImGuiSelectionBasicStorage* s // Apply requests coming from BeginMultiSelect() and EndMultiSelect(). // - Enable 'Demo->Tools->Debug Log->Selection' to see selection requests as they happen. // - Honoring SetRange requests requires that you can iterate/interpolate between RangeFirstItem and RangeLastItem. -// - In this demo we often submit indices to SetNextItemSelectionUserData() + store the same indices in persistent selection. -// - Your code may do differently. If you store pointers or objects ID in ImGuiSelectionUserData you may need to perform +// - In this demo we often submit indices to SetNextItemSelectionUserData() + store the same indices in persistent +// selection. +// - Your code may do differently. If you store pointers or objects ID in ImGuiSelectionUserData you may need to +// perform // a lookup in order to have some way to iterate/interpolate between two items. // - A full-featured application is likely to allow search/filtering which is likely to lead to using indices // and constructing a view index <> object id/ptr data structure anyway. -// WHEN YOUR APPLICATION SETTLES ON A CHOICE, YOU WILL PROBABLY PREFER TO GET RID OF THIS UNNECESSARY 'ImGuiSelectionBasicStorage' INDIRECTION LOGIC. -// Notice that with the simplest adapter (using indices everywhere), all functions return their parameters. -// The most simple implementation (using indices everywhere) would look like: +// WHEN YOUR APPLICATION SETTLES ON A CHOICE, YOU WILL PROBABLY PREFER TO GET RID OF THIS UNNECESSARY +// 'ImGuiSelectionBasicStorage' INDIRECTION LOGIC. Notice that with the simplest adapter (using indices everywhere), all +// functions return their parameters. The most simple implementation (using indices everywhere) would look like: // for (ImGuiSelectionRequest& req : ms_io->Requests) // { -// if (req.Type == ImGuiSelectionRequestType_SetAll) { Clear(); if (req.Selected) { for (int n = 0; n < items_count; n++) { SetItemSelected(n, true); } } -// if (req.Type == ImGuiSelectionRequestType_SetRange) { for (int n = (int)ms_io->RangeFirstItem; n <= (int)ms_io->RangeLastItem; n++) { SetItemSelected(n, ms_io->Selected); } } +// if (req.Type == ImGuiSelectionRequestType_SetAll) { Clear(); if (req.Selected) { for (int n = 0; n < +// items_count; n++) { SetItemSelected(n, true); } } if (req.Type == ImGuiSelectionRequestType_SetRange) { for +// (int n = (int)ms_io->RangeFirstItem; n <= (int)ms_io->RangeLastItem; n++) { SetItemSelected(n, ms_io->Selected); +// } } // } -void ImGuiSelectionBasicStorage::ApplyRequests(ImGuiMultiSelectIO* ms_io) +void ImGuiSelectionBasicStorage::ApplyRequests(ImGuiMultiSelectIO *ms_io) { // For convenience we obtain ItemsCount as passed to BeginMultiSelect(), which is optional. // It makes sense when using ImGuiSelectionBasicStorage to simply pass your items count to BeginMultiSelect(). @@ -8353,15 +9545,19 @@ void ImGuiSelectionBasicStorage::ApplyRequests(ImGuiMultiSelectIO* ms_io) IM_ASSERT(AdapterIndexToStorageId != NULL); // This is optimized/specialized to cope with very large selections (e.g. 100k+ items) - // - A simpler version could call SetItemSelected() directly instead of ImGuiSelectionBasicStorage_BatchSetItemSelected() + ImGuiSelectionBasicStorage_BatchFinish(). - // - Optimized select can append unsorted, then sort in a second pass. Optimized unselect can clear in-place then compact in a second pass. - // - A more optimal version wouldn't even use ImGuiStorage but directly a ImVector to reduce bandwidth, but this is a reasonable trade off to reuse code. - // - There are many ways this could be better optimized. The worse case scenario being: using BoxSelect2d in a grid, box-select scrolling down while wiggling + // - A simpler version could call SetItemSelected() directly instead of + // ImGuiSelectionBasicStorage_BatchSetItemSelected() + ImGuiSelectionBasicStorage_BatchFinish(). + // - Optimized select can append unsorted, then sort in a second pass. Optimized unselect can clear in-place then + // compact in a second pass. + // - A more optimal version wouldn't even use ImGuiStorage but directly a ImVector to reduce bandwidth, but + // this is a reasonable trade off to reuse code. + // - There are many ways this could be better optimized. The worse case scenario being: using BoxSelect2d in a grid, + // box-select scrolling down while wiggling // left and right: it affects coarse clipping + can emit multiple SetRange with 1 item each.) // FIXME-OPT: For each block of consecutive SetRange request: // - add all requests to a sorted list, store ID, selected, offset in ImGuiStorage. // - rewrite sorted storage a single time. - for (ImGuiSelectionRequest& req : ms_io->Requests) + for (ImGuiSelectionRequest &req : ms_io->Requests) { if (req.Type == ImGuiSelectionRequestType_SetAll) { @@ -8371,14 +9567,16 @@ void ImGuiSelectionBasicStorage::ApplyRequests(ImGuiMultiSelectIO* ms_io) _Storage.Data.reserve(ms_io->ItemsCount); const int size_before_amends = _Storage.Data.Size; for (int idx = 0; idx < ms_io->ItemsCount; idx++, _SelectionOrder++) - ImGuiSelectionBasicStorage_BatchSetItemSelected(this, GetStorageIdFromIndex(idx), req.Selected, size_before_amends, _SelectionOrder); + ImGuiSelectionBasicStorage_BatchSetItemSelected(this, GetStorageIdFromIndex(idx), req.Selected, + size_before_amends, _SelectionOrder); ImGuiSelectionBasicStorage_BatchFinish(this, req.Selected, size_before_amends); } } else if (req.Type == ImGuiSelectionRequestType_SetRange) { const int selection_changes = (int)req.RangeLastItem - (int)req.RangeFirstItem + 1; - //ImGuiContext& g = *GImGui; IMGUI_DEBUG_LOG_SELECTION("Req %d/%d: set %d to %d\n", ms_io->Requests.index_from_ptr(&req), ms_io->Requests.Size, selection_changes, req.Selected); + // ImGuiContext& g = *GImGui; IMGUI_DEBUG_LOG_SELECTION("Req %d/%d: set %d to %d\n", + // ms_io->Requests.index_from_ptr(&req), ms_io->Requests.Size, selection_changes, req.Selected); if (selection_changes == 1 || (selection_changes < Size / 100)) { // Multiple sorted insertion + copy likely to be faster. @@ -8389,11 +9587,14 @@ void ImGuiSelectionBasicStorage::ApplyRequests(ImGuiMultiSelectIO* ms_io) else { // Append insertion + single sort likely be faster. - // Use req.RangeDirection to set order field so that shift+clicking from 1 to 5 is different than shift+clicking from 5 to 1 + // Use req.RangeDirection to set order field so that shift+clicking from 1 to 5 is different than + // shift+clicking from 5 to 1 const int size_before_amends = _Storage.Data.Size; int selection_order = _SelectionOrder + ((req.RangeDirection < 0) ? selection_changes - 1 : 0); - for (int idx = (int)req.RangeFirstItem; idx <= (int)req.RangeLastItem; idx++, selection_order += req.RangeDirection) - ImGuiSelectionBasicStorage_BatchSetItemSelected(this, GetStorageIdFromIndex(idx), req.Selected, size_before_amends, selection_order); + for (int idx = (int)req.RangeFirstItem; idx <= (int)req.RangeLastItem; + idx++, selection_order += req.RangeDirection) + ImGuiSelectionBasicStorage_BatchSetItemSelected(this, GetStorageIdFromIndex(idx), req.Selected, + size_before_amends, selection_order); if (req.Selected) _SelectionOrder += selection_changes; ImGuiSelectionBasicStorage_BatchFinish(this, req.Selected, size_before_amends); @@ -8413,10 +9614,10 @@ ImGuiSelectionExternalStorage::ImGuiSelectionExternalStorage() // Apply requests coming from BeginMultiSelect() and EndMultiSelect(). // We also pull 'ms_io->ItemsCount' as passed for BeginMultiSelect() for consistency with ImGuiSelectionBasicStorage // This makes no assumption about underlying storage. -void ImGuiSelectionExternalStorage::ApplyRequests(ImGuiMultiSelectIO* ms_io) +void ImGuiSelectionExternalStorage::ApplyRequests(ImGuiMultiSelectIO *ms_io) { IM_ASSERT(AdapterSetItemSelected); - for (ImGuiSelectionRequest& req : ms_io->Requests) + for (ImGuiSelectionRequest &req : ms_io->Requests) { if (req.Type == ImGuiSelectionRequestType_SetAll) for (int idx = 0; idx < ms_io->ItemsCount; idx++) @@ -8435,28 +9636,31 @@ void ImGuiSelectionExternalStorage::ApplyRequests(ImGuiMultiSelectIO* ms_io) // - ListBox() //------------------------------------------------------------------------- -// This is essentially a thin wrapper to using BeginChild/EndChild with the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label. -// This handle some subtleties with capturing info from the label. -// If you don't need a label you can pretty much directly use ImGui::BeginChild() with ImGuiChildFlags_FrameStyle. -// Tip: To have a list filling the entire window width, use size.x = -FLT_MIN and pass an non-visible label e.g. "##empty" -// Tip: If your vertical size is calculated from an item count (e.g. 10 * item_height) consider adding a fractional part to facilitate seeing scrolling boundaries (e.g. 10.5f * item_height). -bool ImGui::BeginListBox(const char* label, const ImVec2& size_arg) +// This is essentially a thin wrapper to using BeginChild/EndChild with the ImGuiChildFlags_FrameStyle flag for +// stylistic changes + displaying a label. This handle some subtleties with capturing info from the label. If you don't +// need a label you can pretty much directly use ImGui::BeginChild() with ImGuiChildFlags_FrameStyle. Tip: To have a +// list filling the entire window width, use size.x = -FLT_MIN and pass an non-visible label e.g. "##empty" Tip: If your +// vertical size is calculated from an item count (e.g. 10 * item_height) consider adding a fractional part to +// facilitate seeing scrolling boundaries (e.g. 10.5f * item_height). +bool ImGui::BeginListBox(const char *label, const ImVec2 &size_arg) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); + ImGuiContext &g = *GImGui; + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - const ImGuiStyle& style = g.Style; + const ImGuiStyle &style = g.Style; const ImGuiID id = GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); // Size default to hold ~7.25 items. // Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. - ImVec2 size = ImTrunc(CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.25f + style.FramePadding.y * 2.0f)); + ImVec2 size = ImTrunc( + CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.25f + style.FramePadding.y * 2.0f)); ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); - ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + ImRect bb(frame_bb.Min, + frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); g.NextItemData.ClearFlags(); if (!IsRectVisible(bb.Min, bb.Max)) @@ -8483,26 +9687,29 @@ bool ImGui::BeginListBox(const char* label, const ImVec2& size_arg) 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?"); + 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); EndChild(); EndGroup(); // This is only required to be able to do IsItemXXX query on the whole ListBox including label } -bool ImGui::ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_items) +bool ImGui::ListBox(const char *label, int *current_item, const char *const items[], int items_count, int height_items) { - const bool value_changed = ListBox(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_items); + const bool value_changed = + ListBox(label, current_item, Items_ArrayGetter, (void *)items, items_count, height_items); return value_changed; } // This is merely a helper around BeginListBox(), EndListBox(). // Considering using those directly to submit custom data or store selection differently. -bool ImGui::ListBox(const char* label, int* current_item, const char* (*getter)(void* user_data, int idx), void* user_data, int items_count, int height_in_items) +bool ImGui::ListBox(const char *label, int *current_item, const char *(*getter)(void *user_data, int idx), + void *user_data, int items_count, int height_in_items) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; // Calculate size from "height_in_items" if (height_in_items < 0) @@ -8517,12 +9724,14 @@ bool ImGui::ListBox(const char* label, int* current_item, const char* (*getter)( // you can create a custom version of ListBox() in your code without using the clipper. bool value_changed = false; ImGuiListClipper clipper; - clipper.Begin(items_count, GetTextLineHeightWithSpacing()); // We know exactly our line height here so we pass it as a minor optimization, but generally you don't need to. + clipper.Begin(items_count, + GetTextLineHeightWithSpacing()); // We know exactly our line height here so we pass it as a minor + // optimization, but generally you don't need to. clipper.IncludeItemByIndex(*current_item); while (clipper.Step()) for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - const char* item_text = getter(user_data, i); + const char *item_text = getter(user_data, i); if (item_text == NULL) item_text = "*Unknown item*"; @@ -8558,14 +9767,16 @@ bool ImGui::ListBox(const char* label, int* current_item, const char* (*getter)( // - 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, const ImVec2& size_arg) +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, + const ImVec2 &size_arg) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); + ImGuiContext &g = *GImGui; + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return -1; - const ImGuiStyle& style = g.Style; + const ImGuiStyle &style = g.Style; const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); @@ -8573,7 +9784,8 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); - 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)); + 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)); ItemSize(total_bb, style.FramePadding.y); if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_NoNav)) return -1; @@ -8611,7 +9823,8 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get // Tooltip on hover if (hovered && inner_bb.Contains(g.IO.MousePos)) { - const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f); + const float t = + ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f); const int v_idx = (int)(t * item_count); IM_ASSERT(v_idx >= 0 && v_idx < values_count); @@ -8629,11 +9842,16 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get float v0 = values_getter(data, (0 + values_offset) % values_count); float t0 = 0.0f; - ImVec2 tp0 = ImVec2( t0, 1.0f - ImSaturate((v0 - scale_min) * inv_scale) ); // Point in the normalized space of our target rectangle - float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (1 + scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f); // Where does the zero line stands + ImVec2 tp0 = ImVec2(t0, 1.0f - ImSaturate((v0 - scale_min) * + inv_scale)); // Point in the normalized space of our target rectangle + float histogram_zero_line_t = (scale_min * scale_max < 0.0f) + ? (1 + scale_min * inv_scale) + : (scale_min < 0.0f ? 0.0f : 1.0f); // Where does the zero line stands - const ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram); - const ImU32 col_hovered = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered); + const ImU32 col_base = + GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram); + const ImU32 col_hovered = + GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered); for (int n = 0; n < res_w; n++) { @@ -8641,11 +9859,13 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get const int v1_idx = (int)(t0 * item_count + 0.5f); IM_ASSERT(v1_idx >= 0 && v1_idx < values_count); const float v1 = values_getter(data, (v1_idx + values_offset + 1) % values_count); - const ImVec2 tp1 = ImVec2( t1, 1.0f - ImSaturate((v1 - scale_min) * inv_scale) ); + const ImVec2 tp1 = ImVec2(t1, 1.0f - ImSaturate((v1 - scale_min) * inv_scale)); - // NB: Draw calls are merged together by the DrawList system. Still, we should render our batch are lower level to save a bit of CPU. + // NB: Draw calls are merged together by the DrawList system. Still, we should render our batch are lower + // level to save a bit of CPU. ImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0); - ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, histogram_zero_line_t)); + ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, + (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, histogram_zero_line_t)); if (plot_type == ImGuiPlotType_Lines) { window->DrawList->AddLine(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base); @@ -8664,51 +9884,67 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get // Text overlay if (overlay_text) - RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImVec2(0.5f, 0.0f)); + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, + NULL, NULL, ImVec2(0.5f, 0.0f)); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); // Return hovered index or -1 if none are hovered. - // This is currently not exposed in the public API because we need a larger redesign of the whole thing, but in the short-term we are making it available in PlotEx(). + // This is currently not exposed in the public API because we need a larger redesign of the whole thing, but in the + // short-term we are making it available in PlotEx(). return idx_hovered; } struct ImGuiPlotArrayGetterData { - const float* Values; + const float *Values; int Stride; - ImGuiPlotArrayGetterData(const float* values, int stride) { Values = values; Stride = stride; } + ImGuiPlotArrayGetterData(const float *values, int stride) + { + Values = values; + Stride = stride; + } }; -static float Plot_ArrayGetter(void* data, int idx) +static float Plot_ArrayGetter(void *data, int idx) { - ImGuiPlotArrayGetterData* plot_data = (ImGuiPlotArrayGetterData*)data; - const float v = *(const float*)(const void*)((const unsigned char*)plot_data->Values + (size_t)idx * plot_data->Stride); + ImGuiPlotArrayGetterData *plot_data = (ImGuiPlotArrayGetterData *)data; + const float v = + *(const float *)(const void *)((const unsigned char *)plot_data->Values + (size_t)idx * plot_data->Stride); return v; } -void ImGui::PlotLines(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride) +void ImGui::PlotLines(const char *label, const float *values, int values_count, int values_offset, + const char *overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride) { ImGuiPlotArrayGetterData data(values, stride); - PlotEx(ImGuiPlotType_Lines, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); + PlotEx(ImGuiPlotType_Lines, label, &Plot_ArrayGetter, (void *)&data, values_count, values_offset, overlay_text, + scale_min, scale_max, graph_size); } -void ImGui::PlotLines(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 graph_size) +void ImGui::PlotLines(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 graph_size) { - PlotEx(ImGuiPlotType_Lines, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); + PlotEx(ImGuiPlotType_Lines, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, + scale_max, graph_size); } -void ImGui::PlotHistogram(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride) +void ImGui::PlotHistogram(const char *label, const float *values, int values_count, int values_offset, + const char *overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride) { ImGuiPlotArrayGetterData data(values, stride); - PlotEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); + PlotEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void *)&data, values_count, values_offset, overlay_text, + scale_min, scale_max, graph_size); } -void ImGui::PlotHistogram(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 graph_size) +void ImGui::PlotHistogram(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 graph_size) { - PlotEx(ImGuiPlotType_Histogram, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); + PlotEx(ImGuiPlotType_Histogram, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, + scale_max, graph_size); } //------------------------------------------------------------------------- @@ -8718,22 +9954,22 @@ void ImGui::PlotHistogram(const char* label, float (*values_getter)(void* data, // - Value() //------------------------------------------------------------------------- -void ImGui::Value(const char* prefix, bool b) +void ImGui::Value(const char *prefix, bool b) { Text("%s: %s", prefix, (b ? "true" : "false")); } -void ImGui::Value(const char* prefix, int v) +void ImGui::Value(const char *prefix, int v) { Text("%s: %d", prefix, v); } -void ImGui::Value(const char* prefix, unsigned int v) +void ImGui::Value(const char *prefix, unsigned int v) { Text("%s: %d", prefix, v); } -void ImGui::Value(const char* prefix, float v, const char* float_format) +void ImGui::Value(const char *prefix, float v, const char *float_format) { if (float_format) { @@ -8785,9 +10021,18 @@ void ImGuiMenuColumns::CalcNextTotalWidth(bool update_offsets) want_spacing |= (width > 0); if (update_offsets) { - if (i == 1) { OffsetLabel = offset; } - if (i == 2) { OffsetShortcut = offset; } - if (i == 3) { OffsetMark = offset; } + if (i == 1) + { + OffsetLabel = offset; + } + if (i == 2) + { + OffsetShortcut = offset; + } + if (i == 3) + { + OffsetMark = offset; + } } offset += width; } @@ -8805,12 +10050,13 @@ float ImGuiMenuColumns::DeclColumns(float w_icon, float w_label, float w_shortcu } // FIXME: Provided a rectangle perhaps e.g. a BeginMenuBarEx() could be used anywhere.. -// Currently the main responsibility of this function being to setup clip-rect + horizontal layout + menu navigation layer. -// Ideally we also want this to be responsible for claiming space out of the main window scrolling rectangle, in which case ImGuiWindowFlags_MenuBar will become unnecessary. -// Then later the same system could be used for multiple menu-bars, scrollbars, side-bars. +// Currently the main responsibility of this function being to setup clip-rect + horizontal layout + menu navigation +// layer. Ideally we also want this to be responsible for claiming space out of the main window scrolling rectangle, in +// which case ImGuiWindowFlags_MenuBar will become unnecessary. Then later the same system could be used for multiple +// menu-bars, scrollbars, side-bars. bool ImGui::BeginMenuBar() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; if (!(window->Flags & ImGuiWindowFlags_MenuBar)) @@ -8820,16 +10066,22 @@ bool ImGui::BeginMenuBar() BeginGroup(); // Backup position on layer 0 // FIXME: Misleading to use a group for that backup/restore PushID("##MenuBar"); - // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect. - // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy. + // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with + // window full rect. We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend + // to display over the lower-right rounded area, which looks particularly glitchy. const float border_top = ImMax(window->WindowBorderSize * 0.5f - window->TitleBarHeight, 0.0f); ImRect bar_rect = window->MenuBarRect(); - ImRect clip_rect(IM_ROUND(bar_rect.Min.x + window->WindowBorderSize * 0.5f), IM_ROUND(bar_rect.Min.y + border_top), IM_ROUND(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize * 0.5f))), IM_ROUND(bar_rect.Max.y)); + ImRect clip_rect(IM_ROUND(bar_rect.Min.x + window->WindowBorderSize * 0.5f), IM_ROUND(bar_rect.Min.y + border_top), + IM_ROUND(ImMax(bar_rect.Min.x, + bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize * 0.5f))), + IM_ROUND(bar_rect.Max.y)); clip_rect.ClipWith(window->OuterRectClipped); PushClipRect(clip_rect.Min, clip_rect.Max, false); - // We overwrite CursorMaxPos because BeginGroup sets it to CursorPos (essentially the .EmitItem hack in EndMenuBar() would need something analogous here, maybe a BeginGroupEx() with flags). - window->DC.CursorPos = window->DC.CursorMaxPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffset.x, bar_rect.Min.y + window->DC.MenuBarOffset.y); + // We overwrite CursorMaxPos because BeginGroup sets it to CursorPos (essentially the .EmitItem hack in EndMenuBar() + // would need something analogous here, maybe a BeginGroupEx() with flags). + window->DC.CursorPos = window->DC.CursorMaxPos = + ImVec2(bar_rect.Min.x + window->DC.MenuBarOffset.x, bar_rect.Min.y + window->DC.MenuBarOffset.y); window->DC.LayoutType = ImGuiLayoutType_Horizontal; window->DC.IsSameLine = false; window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; @@ -8840,26 +10092,32 @@ bool ImGui::BeginMenuBar() void ImGui::EndMenuBar() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return; - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; - IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'" + 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); // Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings. - if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) + if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && + (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) { // Try to find out if the request is for one of our child menu - ImGuiWindow* nav_earliest_child = g.NavWindow; - while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu)) + ImGuiWindow *nav_earliest_child = g.NavWindow; + while (nav_earliest_child->ParentWindow && + (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu)) nav_earliest_child = nav_earliest_child->ParentWindow; - if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0) + if (nav_earliest_child->ParentWindow == window && + nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && + (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0) { // 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 bothering) + // 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 bothering) const ImGuiNavLayer layer = ImGuiNavLayer_Menu; IM_ASSERT(window->DC.NavLayersActiveMaskNext & (1 << layer)); // Sanity check (FIXME: Seems unnecessary) FocusWindow(window); @@ -8867,7 +10125,8 @@ void ImGui::EndMenuBar() // FIXME-NAV: How to deal with this when not using g.IO.ConfigNavCursorVisibleAuto? if (g.NavCursorVisible) { - g.NavCursorVisible = false; // Hide nav cursor for the current frame so we don't see the intermediary selection. Will be set again + g.NavCursorVisible = false; // Hide nav cursor for the current frame so we don't see the intermediary + // selection. Will be set again g.NavCursorHideFrames = 2; } g.NavHighlightItemUnderNav = g.NavMousePosDirty = true; @@ -8877,13 +10136,18 @@ void ImGui::EndMenuBar() PopClipRect(); PopID(); - 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. + 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. - // FIXME: Extremely confusing, cleanup by (a) working on WorkRect stack system (b) not using a Group confusingly here. - ImGuiGroupData& group_data = g.GroupStack.back(); + // FIXME: Extremely confusing, cleanup by (a) working on WorkRect stack system (b) not using a Group confusingly + // here. + ImGuiGroupData &group_data = g.GroupStack.back(); group_data.EmitItem = false; ImVec2 restore_cursor_max_pos = group_data.BackupCursorMaxPos; - window->DC.IdealMaxPos.x = ImMax(window->DC.IdealMaxPos.x, window->DC.CursorMaxPos.x - window->Scroll.x); // Convert ideal extents for scrolling layer equivalent. + window->DC.IdealMaxPos.x = + ImMax(window->DC.IdealMaxPos.x, + window->DC.CursorMaxPos.x - window->Scroll.x); // Convert ideal extents for scrolling layer equivalent. EndGroup(); // Restore position on layer 0 // FIXME: Misleading to use a group for that backup/restore window->DC.LayoutType = ImGuiLayoutType_Vertical; window->DC.IsSameLine = false; @@ -8894,16 +10158,18 @@ void ImGui::EndMenuBar() // 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) +// 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) { IM_ASSERT(dir != ImGuiDir_None); - ImGuiWindow* bar_window = FindWindowByName(name); + ImGuiWindow *bar_window = FindWindowByName(name); if (bar_window == NULL || bar_window->BeginCount == 0) { // Calculate and set window size/position - ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)(viewport_p ? viewport_p : GetMainViewport()); + 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; @@ -8932,14 +10198,18 @@ bool ImGui::BeginViewportSideBar(const char* name, ImGuiViewport* viewport_p, Im bool ImGui::BeginMainMenuBar() { - ImGuiContext& g = *GImGui; - ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport(); + 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. + // 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; + // 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); @@ -8949,7 +10219,8 @@ bool ImGui::BeginMainMenuBar() return false; } - // Temporarily disable _NoSavedSettings, in the off-chance that tables or child windows submitted within the menu-bar may want to use settings. (#8356) + // Temporarily disable _NoSavedSettings, in the off-chance that tables or child windows submitted within the + // menu-bar may want to use settings. (#8356) g.CurrentWindow->Flags &= ~ImGuiWindowFlags_NoSavedSettings; BeginMenuBar(); return is_open; @@ -8957,74 +10228,87 @@ bool ImGui::BeginMainMenuBar() void ImGui::EndMainMenuBar() { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; if (!g.CurrentWindow->DC.MenuBarAppending) { - IM_ASSERT_USER_ERROR(0, "Calling EndMainMenuBar() not from a menu-bar!"); // Not technically testing that it is the main menu bar + IM_ASSERT_USER_ERROR( + 0, "Calling EndMainMenuBar() not from a menu-bar!"); // Not technically testing that it is the main menu bar return; } EndMenuBar(); g.CurrentWindow->Flags |= ImGuiWindowFlags_NoSavedSettings; // Restore _NoSavedSettings (#8356) - // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window + // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus + // to the previous window // FIXME: With this strategy we won't be able to restore a NULL focus. if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest && g.ActiveId == 0) - FocusTopMostWindowUnderOne(g.NavWindow, NULL, NULL, ImGuiFocusRequestFlags_UnlessBelowModal | ImGuiFocusRequestFlags_RestoreFocusedChild); + FocusTopMostWindowUnderOne(g.NavWindow, NULL, NULL, + ImGuiFocusRequestFlags_UnlessBelowModal | + ImGuiFocusRequestFlags_RestoreFocusedChild); End(); } static bool IsRootOfOpenMenuSet() { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; if ((g.OpenPopupStack.Size <= g.BeginPopupStack.Size) || (window->Flags & ImGuiWindowFlags_ChildMenu)) return false; - // Initially we used 'upper_popup->OpenParentId == window->IDStack.back()' to differentiate multiple menu sets from each others - // (e.g. inside menu bar vs loose menu items) based on parent ID. - // This would however prevent the use of e.g. PushID() user code submitting menus. - // Previously this worked between popup and a first child menu because the first child menu always had the _ChildWindow flag, - // making hovering on parent popup possible while first child menu was focused - but this was generally a bug with other side effects. - // Instead we don't treat Popup specifically (in order to consistently support menu features in them), maybe the first child menu of a Popup - // doesn't have the _ChildWindow flag, and we rely on this IsRootOfOpenMenuSet() check to allow hovering between root window/popup and first child menu. - // In the end, lack of ID check made it so we could no longer differentiate between separate menu sets. To compensate for that, we at least check parent window nav layer. - // This fixes the most common case of menu opening on hover when moving between window content and menu bar. Multiple different menu sets in same nav layer would still - // open on hover, but that should be a lesser problem, because if such menus are close in proximity in window content then it won't feel weird and if they are far apart - // it likely won't be a problem anyone runs into. - const ImGuiPopupData* upper_popup = &g.OpenPopupStack[g.BeginPopupStack.Size]; + // Initially we used 'upper_popup->OpenParentId == window->IDStack.back()' to differentiate multiple menu sets from + // each others (e.g. inside menu bar vs loose menu items) based on parent ID. This would however prevent the use of + // e.g. PushID() user code submitting menus. Previously this worked between popup and a first child menu because the + // first child menu always had the _ChildWindow flag, making hovering on parent popup possible while first child + // menu was focused - but this was generally a bug with other side effects. Instead we don't treat Popup + // specifically (in order to consistently support menu features in them), maybe the first child menu of a Popup + // doesn't have the _ChildWindow flag, and we rely on this IsRootOfOpenMenuSet() check to allow hovering between + // root window/popup and first child menu. In the end, lack of ID check made it so we could no longer differentiate + // between separate menu sets. To compensate for that, we at least check parent window nav layer. This fixes the + // most common case of menu opening on hover when moving between window content and menu bar. Multiple different + // menu sets in same nav layer would still open on hover, but that should be a lesser problem, because if such menus + // are close in proximity in window content then it won't feel weird and if they are far apart it likely won't be a + // problem anyone runs into. + const ImGuiPopupData *upper_popup = &g.OpenPopupStack[g.BeginPopupStack.Size]; if (window->DC.NavLayerCurrent != upper_popup->ParentNavLayer) return false; - return upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu) && ImGui::IsWindowChildOf(upper_popup->Window, window, true); + return upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu) && + ImGui::IsWindowChildOf(upper_popup->Window, window, true); } -bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) +bool ImGui::BeginMenuEx(const char *label, const char *icon, bool enabled) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; + ImGuiContext &g = *GImGui; + const ImGuiStyle &style = g.Style; const ImGuiID id = window->GetID(label); bool menu_is_open = IsPopupOpen(id, ImGuiPopupFlags_None); - // Sub-menus are ChildWindow so that mouse can be hovering across them (otherwise top-most popup menu would steal focus and not allow hovering on parent menu) - // The first menu in a hierarchy isn't so hovering doesn't get across (otherwise e.g. resizing borders with ImGuiButtonFlags_FlattenChildren would react), but top-most BeginMenu() will bypass that limitation. - ImGuiWindowFlags window_flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus; + // Sub-menus are ChildWindow so that mouse can be hovering across them (otherwise top-most popup menu would steal + // focus and not allow hovering on parent menu) The first menu in a hierarchy isn't so hovering doesn't get across + // (otherwise e.g. resizing borders with ImGuiButtonFlags_FlattenChildren would react), but top-most BeginMenu() + // will bypass that limitation. + ImGuiWindowFlags window_flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | + ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | + ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus; if (window->Flags & ImGuiWindowFlags_ChildMenu) window_flags |= ImGuiWindowFlags_ChildWindow; // If a menu with same the ID was already submitted, we will append to it, matching the behavior of Begin(). - // We are relying on a O(N) search - so O(N log N) over the frame - which seems like the most efficient for the expected small amount of BeginMenu() calls per frame. - // If somehow this is ever becoming a problem we can switch to use e.g. ImGuiStorage mapping key to last frame used. + // We are relying on a O(N) search - so O(N log N) over the frame - which seems like the most efficient for the + // expected small amount of BeginMenu() calls per frame. If somehow this is ever becoming a problem we can switch to + // use e.g. ImGuiStorage mapping key to last frame used. if (g.MenusIdSubmittedThisFrame.contains(id)) { if (menu_is_open) - menu_is_open = BeginPopupMenuEx(id, label, window_flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + menu_is_open = BeginPopupMenuEx(id, label, window_flags); // menu_is_open can be 'false' when the popup is + // completely clipped (e.g. zero size display) else - g.NextWindowData.ClearFlags(); // we behave like Begin() and need to consume those values + g.NextWindowData.ClearFlags(); // we behave like Begin() and need to consume those values return menu_is_open; } @@ -9033,57 +10317,69 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) ImVec2 label_size = CalcTextSize(label, NULL, true); - // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent without always being a Child window) - // This is only done for items for the menu set and not the full parent window. + // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent without + // always being a Child window) This is only done for items for the menu set and not the full parent window. const bool menuset_is_open = IsRootOfOpenMenuSet(); if (menuset_is_open) PushItemFlag(ImGuiItemFlags_NoWindowHoverableCheck, true); - // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu, - // However the final position is going to be different! It is chosen by FindBestWindowPosForPopup(). - // e.g. Menus tend to overlap each other horizontally to amplify relative Z-ordering. + // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child + // menu, However the final position is going to be different! It is chosen by FindBestWindowPosForPopup(). e.g. + // Menus tend to overlap each other horizontally to amplify relative Z-ordering. ImVec2 popup_pos, pos = window->DC.CursorPos; PushID(label); if (!enabled) BeginDisabled(); - const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; + const ImGuiMenuColumns *offsets = &window->DC.MenuColumns; bool pressed; // We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another. - const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_NoAutoClosePopups; + const ImGuiSelectableFlags selectable_flags = + ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_NoSetKeyOwner | + ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_NoAutoClosePopups; if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) { // Menu inside a horizontal menu bar // Selectable extend their highlight by half ItemSpacing in each direction. // For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin() - popup_pos = ImVec2(pos.x - 1.0f - IM_TRUNC(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight); + popup_pos = ImVec2(pos.x - 1.0f - IM_TRUNC(style.ItemSpacing.x * 0.5f), + pos.y - style.FramePadding.y + window->MenuBarHeight); window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * 0.5f); PushStyleVarX(ImGuiStyleVar_ItemSpacing, style.ItemSpacing.x * 2.0f); float w = label_size.x; - ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); + ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, + window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); pressed = Selectable("", menu_is_open, selectable_flags, ImVec2(w, label_size.y)); LogSetNextTextDecoration("[", "]"); RenderText(text_pos, label); PopStyleVar(); - window->DC.CursorPos.x += IM_TRUNC(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(). + window->DC.CursorPos.x += + IM_TRUNC(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(). } else { // Menu inside a regular/vertical menu // (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f. - // Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system. + // Only when they are other items sticking out we're going to add spacing, yet only register minimum width into + // the layout system. popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f; float checkmark_w = IM_TRUNC(g.FontSize * 1.20f); - float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame + float min_w = + window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); - ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); - pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y)); + ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, + window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); + pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, + ImVec2(min_w, label_size.y)); LogSetNextTextDecoration("", ">"); RenderText(text_pos, label); if (icon_w > 0.0f) RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); - RenderArrow(window->DrawList, pos + ImVec2(offsets->OffsetMark + extra_w + g.FontSize * 0.30f, 0.0f), GetColorU32(ImGuiCol_Text), ImGuiDir_Right); + RenderArrow(window->DrawList, pos + ImVec2(offsets->OffsetMark + extra_w + g.FontSize * 0.30f, 0.0f), + GetColorU32(ImGuiCol_Text), ImGuiDir_Right); } if (!enabled) EndDisabled(); @@ -9095,13 +10391,19 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) bool want_open = false; bool want_open_nav_init = false; bool want_close = false; - if (window->DC.LayoutType == ImGuiLayoutType_Vertical) // (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) + if (window->DC.LayoutType == + ImGuiLayoutType_Vertical) // (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) { // Close menu when not hovering it anymore unless we are moving roughly in the direction of the menu - // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive. + // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so + // menus feels more reactive. bool moving_toward_child_menu = false; - ImGuiPopupData* child_popup = (g.BeginPopupStack.Size < g.OpenPopupStack.Size) ? &g.OpenPopupStack[g.BeginPopupStack.Size] : NULL; // Popup candidate (testing below) - ImGuiWindow* child_menu_window = (child_popup && child_popup->Window && child_popup->Window->ParentWindow == window) ? child_popup->Window : NULL; + ImGuiPopupData *child_popup = (g.BeginPopupStack.Size < g.OpenPopupStack.Size) + ? &g.OpenPopupStack[g.BeginPopupStack.Size] + : NULL; // Popup candidate (testing below) + ImGuiWindow *child_menu_window = + (child_popup && child_popup->Window && child_popup->Window->ParentWindow == window) ? child_popup->Window + : NULL; if (g.HoveredWindow == window && child_menu_window != NULL) { const float ref_unit = g.FontSize; // FIXME-DPI @@ -9110,20 +10412,29 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) ImVec2 ta = (g.IO.MousePos - g.IO.MouseDelta); ImVec2 tb = (child_dir > 0.0f) ? next_window_rect.GetTL() : next_window_rect.GetTR(); ImVec2 tc = (child_dir > 0.0f) ? next_window_rect.GetBL() : next_window_rect.GetBR(); - const float pad_farmost_h = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, ref_unit * 0.5f, ref_unit * 2.5f); // Add a bit of extra slack. + const float pad_farmost_h = + ImClamp(ImFabs(ta.x - tb.x) * 0.30f, ref_unit * 0.5f, ref_unit * 2.5f); // Add a bit of extra slack. ta.x += child_dir * -0.5f; tb.x += child_dir * ref_unit; tc.x += child_dir * ref_unit; - tb.y = ta.y + ImMax((tb.y - pad_farmost_h) - ta.y, -ref_unit * 8.0f); // Triangle has maximum height to limit the slope and the bias toward large sub-menus + tb.y = + ta.y + + ImMax((tb.y - pad_farmost_h) - ta.y, + -ref_unit * + 8.0f); // Triangle has maximum height to limit the slope and the bias toward large sub-menus tc.y = ta.y + ImMin((tc.y + pad_farmost_h) - ta.y, +ref_unit * 8.0f); moving_toward_child_menu = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos); - //GetForegroundDrawList()->AddTriangleFilled(ta, tb, tc, moving_toward_child_menu ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); // [DEBUG] + // GetForegroundDrawList()->AddTriangleFilled(ta, tb, tc, moving_toward_child_menu ? IM_COL32(0,128,0,128) : + // IM_COL32(128,0,0,128)); // [DEBUG] } - // The 'HovereWindow == window' check creates an inconsistency (e.g. moving away from menu slowly tends to hit same window, whereas moving away fast does not) - // But we also need to not close the top-menu menu when moving over void. Perhaps we should extend the triangle check to a larger polygon. - // (Remember to test this on BeginPopup("A")->BeginMenu("B") sequence which behaves slightly differently as B isn't a Child of A and hovering isn't shared.) - if (menu_is_open && !hovered && g.HoveredWindow == window && !moving_toward_child_menu && !g.NavHighlightItemUnderNav && g.ActiveId == 0) + // The 'HovereWindow == window' check creates an inconsistency (e.g. moving away from menu slowly tends to hit + // same window, whereas moving away fast does not) But we also need to not close the top-menu menu when moving + // over void. Perhaps we should extend the triangle check to a larger polygon. (Remember to test this on + // BeginPopup("A")->BeginMenu("B") sequence which behaves slightly differently as B isn't a Child of A and + // hovering isn't shared.) + if (menu_is_open && !hovered && g.HoveredWindow == window && !moving_toward_child_menu && + !g.NavHighlightItemUnderNav && g.ActiveId == 0) want_close = true; // Open @@ -9132,7 +10443,8 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) want_open = true; else if (!menu_is_open && hovered && !moving_toward_child_menu) // Hover to open want_open = true; - else if (!menu_is_open && hovered && g.HoveredIdTimer >= 0.30f && g.MouseStationaryTimer >= 0.30f) // Hover to open (timer fallback) + else if (!menu_is_open && hovered && g.HoveredIdTimer >= 0.30f && + g.MouseStationaryTimer >= 0.30f) // Hover to open (timer fallback) want_open = true; if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open { @@ -9149,7 +10461,8 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) want_close = true; want_open = menu_is_open = false; } - else if (pressed || (hovered && menuset_is_open && !menu_is_open)) // First click to open, then hover to open others + else if (pressed || + (hovered && menuset_is_open && !menu_is_open)) // First click to open, then hover to open others { want_open = true; } @@ -9160,31 +10473,40 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) } } - if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }' + if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as + // 'if (BeginMenu("options", has_object)) { ..use object.. }' want_close = true; if (want_close && IsPopupOpen(id, ImGuiPopupFlags_None)) ClosePopupToLevel(g.BeginPopupStack.Size, true); - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, + g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Openable | + (menu_is_open ? ImGuiItemStatusFlags_Opened : 0)); PopID(); if (want_open && !menu_is_open && g.OpenPopupStack.Size > g.BeginPopupStack.Size) { - // Don't reopen/recycle same menu level in the same frame if it is a different menu ID, first close the other menu and yield for a frame. + // Don't reopen/recycle same menu level in the same frame if it is a different menu ID, first close the other + // menu and yield for a frame. OpenPopup(label); } else if (want_open) { menu_is_open = true; - OpenPopup(label, ImGuiPopupFlags_NoReopen);// | (want_open_nav_init ? ImGuiPopupFlags_NoReopenAlwaysNavInit : 0)); + OpenPopup(label, + ImGuiPopupFlags_NoReopen); // | (want_open_nav_init ? ImGuiPopupFlags_NoReopenAlwaysNavInit : 0)); } if (menu_is_open) { ImGuiLastItemData last_item_in_parent = g.LastItemData; - SetNextWindowPos(popup_pos, ImGuiCond_Always); // Note: misleading: the value will serve as reference for FindBestWindowPosForPopup(), not actual pos. - PushStyleVar(ImGuiStyleVar_ChildRounding, style.PopupRounding); // First level will use _PopupRounding, subsequent will use _ChildRounding - menu_is_open = BeginPopupMenuEx(id, label, window_flags); // menu_is_open may be 'false' when the popup is completely clipped (e.g. zero size display) + SetNextWindowPos(popup_pos, ImGuiCond_Always); // Note: misleading: the value will serve as reference for + // FindBestWindowPosForPopup(), not actual pos. + PushStyleVar(ImGuiStyleVar_ChildRounding, + style.PopupRounding); // First level will use _PopupRounding, subsequent will use _ChildRounding + menu_is_open = BeginPopupMenuEx( + id, label, + window_flags); // menu_is_open may be 'false' when the popup is completely clipped (e.g. zero size display) PopStyleVar(); if (menu_is_open) { @@ -9197,7 +10519,8 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) } // Restore LastItemData so IsItemXXXX functions can work after BeginMenu()/EndMenu() - // (This fixes using IsItemClicked() and IsItemHovered(), but IsItemHovered() also relies on its support for ImGuiItemFlags_NoWindowHoverableCheck) + // (This fixes using IsItemClicked() and IsItemHovered(), but IsItemHovered() also relies on its support for + // ImGuiItemFlags_NoWindowHoverableCheck) g.LastItemData = last_item_in_parent; if (g.HoveredWindow == window) g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; @@ -9211,7 +10534,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) return menu_is_open; } -bool ImGui::BeginMenu(const char* label, bool enabled) +bool ImGui::BeginMenu(const char *label, bool enabled) { return BeginMenuEx(label, NULL, enabled); } @@ -9219,13 +10542,14 @@ bool ImGui::BeginMenu(const char* label, bool enabled) void ImGui::EndMenu() { // Nav: When a left move request our menu failed, close ourselves. - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginMenu()/EndMenu() calls - ImGuiWindow* parent_window = window->ParentWindow; // Should always be != NULL is we passed assert. + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; + IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginMenu()/EndMenu() calls + ImGuiWindow *parent_window = window->ParentWindow; // Should always be != NULL is we passed assert. if (window->BeginCount == window->BeginCountPreviousFrame) if (g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet()) - if (g.NavWindow && (g.NavWindow->RootWindowForNav == window) && parent_window->DC.LayoutType == ImGuiLayoutType_Vertical) + if (g.NavWindow && (g.NavWindow->RootWindowForNav == window) && + parent_window->DC.LayoutType == ImGuiLayoutType_Vertical) { ClosePopupToLevel(g.BeginPopupStack.Size - 1, true); NavMoveRequestCancel(); @@ -9234,14 +10558,14 @@ void ImGui::EndMenu() EndPopup(); } -bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut, bool selected, bool enabled) +bool ImGui::MenuItemEx(const char *label, const char *icon, const char *shortcut, bool selected, bool enabled) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow *window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; - ImGuiStyle& style = g.Style; + ImGuiContext &g = *GImGui; + ImGuiStyle &style = g.Style; ImVec2 pos = window->DC.CursorPos; ImVec2 label_size = CalcTextSize(label, NULL, true); @@ -9250,41 +10574,52 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut if (menuset_is_open) PushItemFlag(ImGuiItemFlags_NoWindowHoverableCheck, true); - // We've been using the equivalent of ImGuiSelectableFlags_SetNavIdOnHover on all Selectable() since early Nav system days (commit 43ee5d73), - // but I am unsure whether this should be kept at all. For now moved it to be an opt-in feature used by menus only. + // We've been using the equivalent of ImGuiSelectableFlags_SetNavIdOnHover on all Selectable() since early Nav + // system days (commit 43ee5d73), but I am unsure whether this should be kept at all. For now moved it to be an + // opt-in feature used by menus only. bool pressed; PushID(label); if (!enabled) BeginDisabled(); // We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another. - const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SetNavIdOnHover; - const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; + const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_SelectOnRelease | + ImGuiSelectableFlags_NoSetKeyOwner | + ImGuiSelectableFlags_SetNavIdOnHover; + const ImGuiMenuColumns *offsets = &window->DC.MenuColumns; 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 don't render the shortcut, we render a highlight instead of the selected tick mark. + // 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 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_TRUNC(style.ItemSpacing.x * 0.5f); - ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); + ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, + window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); PushStyleVarX(ImGuiStyleVar_ItemSpacing, style.ItemSpacing.x * 2.0f); pressed = Selectable("", selected, selectable_flags, ImVec2(w, 0.0f)); PopStyleVar(); if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) RenderText(text_pos, label); - window->DC.CursorPos.x += IM_TRUNC(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(). + window->DC.CursorPos.x += + IM_TRUNC(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(). } else { // Menu item inside a vertical menu // (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f. - // Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system. + // Only when they are other items sticking out we're going to add spacing, yet only register minimum width into + // the layout system. float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f; float shortcut_w = (shortcut && shortcut[0]) ? CalcTextSize(shortcut, NULL).x : 0.0f; float checkmark_w = IM_TRUNC(g.FontSize * 1.20f); - float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame + float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, + checkmark_w); // Feedback for next frame float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); - pressed = Selectable("", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y)); + pressed = + Selectable("", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y)); if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) { RenderText(pos + ImVec2(offsets->OffsetLabel, 0.0f), label); @@ -9298,10 +10633,15 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut PopStyleColor(); } if (selected) - RenderCheckMark(window->DrawList, pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f); + RenderCheckMark( + window->DrawList, + pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), + GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f); } } - IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0)); + IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, + g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | + (selected ? ImGuiItemStatusFlags_Checked : 0)); if (!enabled) EndDisabled(); PopID(); @@ -9311,12 +10651,12 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut return pressed; } -bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, bool enabled) +bool ImGui::MenuItem(const char *label, const char *shortcut, bool selected, bool enabled) { return MenuItemEx(label, NULL, shortcut, selected, enabled); } -bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled) +bool ImGui::MenuItem(const char *label, const char *shortcut, bool *p_selected, bool enabled) { if (MenuItemEx(label, NULL, shortcut, p_selected ? *p_selected : false, enabled)) { @@ -9354,23 +10694,26 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, struct ImGuiTabBarSection { - int TabCount; // Number of tabs in this section. - float Width; // Sum of width of tabs in this section (after shrinking down) - float Spacing; // Horizontal spacing at the end of the section. + int TabCount; // Number of tabs in this section. + float Width; // Sum of width of tabs in this section (after shrinking down) + float Spacing; // Horizontal spacing at the end of the section. - ImGuiTabBarSection() { memset(this, 0, sizeof(*this)); } + ImGuiTabBarSection() + { + memset(this, 0, sizeof(*this)); + } }; namespace ImGui { - static void TabBarLayout(ImGuiTabBar* tab_bar); - static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label, ImGuiWindow* docked_window); - static float TabBarCalcMaxTabWidth(); - static float TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling); - static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGuiTabBarSection* sections); - static ImGuiTabItem* TabBarScrollingButtons(ImGuiTabBar* tab_bar); - static ImGuiTabItem* TabBarTabListPopupButton(ImGuiTabBar* tab_bar); -} +static void TabBarLayout(ImGuiTabBar *tab_bar); +static ImU32 TabBarCalcTabID(ImGuiTabBar *tab_bar, const char *label, ImGuiWindow *docked_window); +static float TabBarCalcMaxTabWidth(); +static float TabBarScrollClamp(ImGuiTabBar *tab_bar, float scrolling); +static void TabBarScrollToTab(ImGuiTabBar *tab_bar, ImGuiID tab_id, ImGuiTabBarSection *sections); +static ImGuiTabItem *TabBarScrollingButtons(ImGuiTabBar *tab_bar); +static ImGuiTabItem *TabBarTabListPopupButton(ImGuiTabBar *tab_bar); +} // namespace ImGui ImGuiTabBar::ImGuiTabBar() { @@ -9379,15 +10722,15 @@ ImGuiTabBar::ImGuiTabBar() LastTabItemIdx = -1; } -static inline int TabItemGetSectionIdx(const ImGuiTabItem* tab) +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) +static int IMGUI_CDECL TabItemComparerBySection(const void *lhs, const void *rhs) { - const ImGuiTabItem* a = (const ImGuiTabItem*)lhs; - const ImGuiTabItem* b = (const ImGuiTabItem*)rhs; + const ImGuiTabItem *a = (const ImGuiTabItem *)lhs; + const ImGuiTabItem *b = (const ImGuiTabItem *)rhs; const int a_section = TabItemGetSectionIdx(a); const int b_section = TabItemGetSectionIdx(b); if (a_section != b_section) @@ -9395,49 +10738,50 @@ static int IMGUI_CDECL TabItemComparerBySection(const void* lhs, const void* rhs return (int)(a->IndexDuringLayout - b->IndexDuringLayout); } -static int IMGUI_CDECL TabItemComparerByBeginOrder(const void* lhs, const void* rhs) +static int IMGUI_CDECL TabItemComparerByBeginOrder(const void *lhs, const void *rhs) { - const ImGuiTabItem* a = (const ImGuiTabItem*)lhs; - const ImGuiTabItem* b = (const ImGuiTabItem*)rhs; + const ImGuiTabItem *a = (const ImGuiTabItem *)lhs; + const ImGuiTabItem *b = (const ImGuiTabItem *)rhs; return (int)(a->BeginOrder - b->BeginOrder); } -static ImGuiTabBar* GetTabBarFromTabBarRef(const ImGuiPtrOrIndex& ref) +static ImGuiTabBar *GetTabBarFromTabBarRef(const ImGuiPtrOrIndex &ref) { - ImGuiContext& g = *GImGui; - return ref.Ptr ? (ImGuiTabBar*)ref.Ptr : g.TabBars.GetByIndex(ref.Index); + ImGuiContext &g = *GImGui; + return ref.Ptr ? (ImGuiTabBar *)ref.Ptr : g.TabBars.GetByIndex(ref.Index); } -static ImGuiPtrOrIndex GetTabBarRefFromTabBar(ImGuiTabBar* tab_bar) +static ImGuiPtrOrIndex GetTabBarRefFromTabBar(ImGuiTabBar *tab_bar) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; if (g.TabBars.Contains(tab_bar)) return ImGuiPtrOrIndex(g.TabBars.GetIndex(tab_bar)); return ImGuiPtrOrIndex(tab_bar); } -bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags) +bool ImGui::BeginTabBar(const char *str_id, ImGuiTabBarFlags flags) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; if (window->SkipItems) return false; ImGuiID id = window->GetID(str_id); - ImGuiTabBar* tab_bar = g.TabBars.GetOrAddByKey(id); - ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->WorkRect.Max.x, window->DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2); + ImGuiTabBar *tab_bar = g.TabBars.GetOrAddByKey(id); + ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->WorkRect.Max.x, + window->DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2); tab_bar->ID = id; tab_bar->SeparatorMinX = tab_bar->BarRect.Min.x - IM_TRUNC(window->WindowPadding.x * 0.5f); tab_bar->SeparatorMaxX = tab_bar->BarRect.Max.x + IM_TRUNC(window->WindowPadding.x * 0.5f); - //if (g.NavWindow && IsWindowChildOf(g.NavWindow, window, false, false)) + // if (g.NavWindow && IsWindowChildOf(g.NavWindow, window, false, false)) flags |= ImGuiTabBarFlags_IsFocused; return BeginTabBarEx(tab_bar, tab_bar_bb, flags); } -bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImGuiTabBarFlags flags) +bool ImGui::BeginTabBarEx(ImGuiTabBar *tab_bar, const ImRect &tab_bar_bb, ImGuiTabBarFlags flags) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; if (window->SkipItems) return false; @@ -9459,8 +10803,10 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG return true; } - // Ensure correct ordering when toggling ImGuiTabBarFlags_Reorderable flag, or when a new tab was added while being not reorderable - if ((flags & ImGuiTabBarFlags_Reorderable) != (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (tab_bar->TabsAddedNew && !(flags & ImGuiTabBarFlags_Reorderable))) + // Ensure correct ordering when toggling ImGuiTabBarFlags_Reorderable flag, or when a new tab was added while being + // not reorderable + if ((flags & ImGuiTabBarFlags_Reorderable) != (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || + (tab_bar->TabsAddedNew && !(flags & ImGuiTabBarFlags_Reorderable))) ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder); tab_bar->TabsAddedNew = false; @@ -9481,28 +10827,32 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG tab_bar->LastTabItemIdx = -1; tab_bar->BeginCount = 1; - // Set cursor pos in a way which only be used in the off-chance the user erroneously submits item before BeginTabItem(): items will overlap + // Set cursor pos in a way which only be used in the off-chance the user erroneously submits item before + // BeginTabItem(): items will overlap window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.y + tab_bar->ItemSpacingY); // Draw separator - // (it would be misleading to draw this in EndTabBar() suggesting that it may be drawn over tabs, as tab bar are appendable) - const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabSelected : ImGuiCol_TabDimmedSelected); + // (it would be misleading to draw this in EndTabBar() suggesting that it may be drawn over tabs, as tab bar are + // appendable) + const ImU32 col = + GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabSelected : ImGuiCol_TabDimmedSelected); if (g.Style.TabBarBorderSize > 0.0f) { const float y = tab_bar->BarRect.Max.y; - window->DrawList->AddRectFilled(ImVec2(tab_bar->SeparatorMinX, y - g.Style.TabBarBorderSize), ImVec2(tab_bar->SeparatorMaxX, y), col); + window->DrawList->AddRectFilled(ImVec2(tab_bar->SeparatorMinX, y - g.Style.TabBarBorderSize), + ImVec2(tab_bar->SeparatorMaxX, y), col); } return true; } -void ImGui::EndTabBar() +void ImGui::EndTabBar() { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; if (window->SkipItems) return; - ImGuiTabBar* tab_bar = g.CurrentTabBar; + ImGuiTabBar *tab_bar = g.CurrentTabBar; if (tab_bar == NULL) { IM_ASSERT_USER_ERROR(tab_bar != NULL, "Mismatched BeginTabBar()/EndTabBar()!"); @@ -9513,11 +10863,13 @@ void ImGui::EndTabBar() if (tab_bar->WantLayout) TabBarLayout(tab_bar); - // Restore the last visible height if no tab is visible, this reduce vertical flicker/movement when a tabs gets removed without calling SetTabItemClosed(). + // Restore the last visible height if no tab is visible, this reduce vertical flicker/movement when a tabs gets + // removed without calling SetTabItemClosed(). const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); if (tab_bar->VisibleTabWasSubmitted || tab_bar->VisibleTabId == 0 || tab_bar_appearing) { - tab_bar->CurrTabsContentsHeight = ImMax(window->DC.CursorPos.y - tab_bar->BarRect.Max.y, tab_bar->CurrTabsContentsHeight); + tab_bar->CurrTabsContentsHeight = + ImMax(window->DC.CursorPos.y - tab_bar->BarRect.Max.y, tab_bar->CurrTabsContentsHeight); window->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->CurrTabsContentsHeight; } else @@ -9536,16 +10888,17 @@ void ImGui::EndTabBar() } // Scrolling happens only in the central section (leading/trailing sections are not scrolling) -static float TabBarCalcScrollableWidth(ImGuiTabBar* tab_bar, ImGuiTabBarSection* sections) +static float TabBarCalcScrollableWidth(ImGuiTabBar *tab_bar, ImGuiTabBarSection *sections) { return tab_bar->BarRect.GetWidth() - sections[0].Width - sections[2].Width - sections[1].Spacing; } // This is called only once a frame before by the first call to ItemTab() -// The reason we're not calling it in BeginTabBar() is to leave a chance to the user to call the SetTabItemClosed() functions. -static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) +// The reason we're not calling it in BeginTabBar() is to leave a chance to the user to call the SetTabItemClosed() +// functions. +static void ImGui::TabBarLayout(ImGuiTabBar *tab_bar) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; tab_bar->WantLayout = false; // Garbage collect by compacting list @@ -9555,13 +10908,22 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) ImGuiTabBarSection sections[3]; // Layout sections: Leading, Central, Trailing for (int tab_src_n = 0; tab_src_n < tab_bar->Tabs.Size; tab_src_n++) { - ImGuiTabItem* tab = &tab_bar->Tabs[tab_src_n]; + ImGuiTabItem *tab = &tab_bar->Tabs[tab_src_n]; if (tab->LastFrameVisible < tab_bar->PrevFrameVisible || tab->WantClose) { // Remove tab - if (tab_bar->VisibleTabId == tab->ID) { tab_bar->VisibleTabId = 0; } - if (tab_bar->SelectedTabId == tab->ID) { tab_bar->SelectedTabId = 0; } - if (tab_bar->NextSelectedTabId == tab->ID) { tab_bar->NextSelectedTabId = 0; } + if (tab_bar->VisibleTabId == tab->ID) + { + tab_bar->VisibleTabId = 0; + } + if (tab_bar->SelectedTabId == tab->ID) + { + tab_bar->SelectedTabId = 0; + } + if (tab_bar->NextSelectedTabId == tab->ID) + { + tab_bar->NextSelectedTabId = 0; + } continue; } if (tab_dst_n != tab_src_n) @@ -9570,11 +10932,12 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) tab = &tab_bar->Tabs[tab_dst_n]; 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) + // 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 = TabItemGetSectionIdx(tab); if (tab_dst_n > 0) { - ImGuiTabItem* prev_tab = &tab_bar->Tabs[tab_dst_n - 1]; + ImGuiTabItem *prev_tab = &tab_bar->Tabs[tab_dst_n - 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; @@ -9592,7 +10955,9 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerBySection); // Calculate spacing between sections - sections[0].Spacing = sections[0].TabCount > 0 && (sections[1].TabCount + sections[2].TabCount) > 0 ? g.Style.ItemInnerSpacing.x : 0.0f; + sections[0].Spacing = sections[0].TabCount > 0 && (sections[1].TabCount + sections[2].TabCount) > 0 + ? g.Style.ItemInnerSpacing.x + : 0.0f; sections[1].Spacing = sections[1].TabCount > 0 && sections[2].TabCount > 0 ? g.Style.ItemInnerSpacing.x : 0.0f; // Setup next selected tab @@ -9604,7 +10969,8 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) 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). + // Process order change request (we could probably process it when requested but it's just saner to do it in a + // single spot). if (tab_bar->ReorderRequestTabId != 0) { if (TabBarProcessReorder(tab_bar)) @@ -9616,45 +10982,51 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) // Tab List Popup (will alter tab_bar->BarRect and therefore the available width!) 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! + if (ImGuiTabItem *tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Min.x! 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) - int shrink_buffer_indexes[3] = { 0, sections[0].TabCount + sections[2].TabCount, sections[0].TabCount }; + // 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) + int shrink_buffer_indexes[3] = {0, sections[0].TabCount + sections[2].TabCount, sections[0].TabCount}; g.ShrinkWidthBuffer.resize(tab_bar->Tabs.Size); // Compute ideal tabs widths + store them into shrink buffer - ImGuiTabItem* most_recently_selected_tab = NULL; + ImGuiTabItem *most_recently_selected_tab = NULL; int curr_section_n = -1; bool found_selected_tab_id = false; for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) { - ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + ImGuiTabItem *tab = &tab_bar->Tabs[tab_n]; IM_ASSERT(tab->LastFrameVisible >= tab_bar->PrevFrameVisible); - if ((most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected) && !(tab->Flags & ImGuiTabItemFlags_Button)) + if ((most_recently_selected_tab == NULL || + most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected) && + !(tab->Flags & ImGuiTabItemFlags_Button)) most_recently_selected_tab = tab; if (tab->ID == tab_bar->SelectedTabId) found_selected_tab_id = true; 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, - // and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window. - const char* tab_name = TabBarGetTabName(tab_bar, tab); - const bool has_close_button_or_unsaved_marker = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) == 0 || (tab->Flags & ImGuiTabItemFlags_UnsavedDocument); - tab->ContentWidth = (tab->RequestedWidth >= 0.0f) ? tab->RequestedWidth : TabItemCalcSize(tab_name, has_close_button_or_unsaved_marker).x; + // 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, and we cannot wait for the next BeginTabItem() call. We cannot compute this + // width within TabBarAddTab() because font size depends on the active window. + const char *tab_name = TabBarGetTabName(tab_bar, tab); + const bool has_close_button_or_unsaved_marker = + (tab->Flags & ImGuiTabItemFlags_NoCloseButton) == 0 || (tab->Flags & ImGuiTabItemFlags_UnsavedDocument); + tab->ContentWidth = (tab->RequestedWidth >= 0.0f) + ? tab->RequestedWidth + : TabItemCalcSize(tab_name, has_close_button_or_unsaved_marker).x; int section_n = TabItemGetSectionIdx(tab); - ImGuiTabBarSection* section = §ions[section_n]; + 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); - ImGuiShrinkWidthItem* shrink_width_item = &g.ShrinkWidthBuffer[shrink_buffer_indexes[section_n]++]; + ImGuiShrinkWidthItem *shrink_width_item = &g.ShrinkWidthBuffer[shrink_buffer_indexes[section_n]++]; shrink_width_item->Index = tab_n; shrink_width_item->Width = shrink_width_item->InitialWidth = tab->ContentWidth; tab->Width = ImMax(tab->ContentWidth, 1.0f); @@ -9667,8 +11039,10 @@ 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_and_select_tab = TabBarScrollingButtons(tab_bar)) + 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_and_select_tab = TabBarScrollingButtons(tab_bar)) { scroll_to_tab_id = scroll_and_select_tab->ID; if ((scroll_and_select_tab->Flags & ImGuiTabItemFlags_Button) == 0) @@ -9682,21 +11056,26 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) bool central_section_is_visible = (section_0_w + section_2_w) < tab_bar->BarRect.GetWidth(); float width_excess; if (central_section_is_visible) - width_excess = ImMax(section_1_w - (tab_bar->BarRect.GetWidth() - section_0_w - section_2_w), 0.0f); // Excess used to shrink central section + width_excess = ImMax(section_1_w - (tab_bar->BarRect.GetWidth() - section_0_w - section_2_w), + 0.0f); // Excess used to shrink central section else - width_excess = (section_0_w + section_2_w) - tab_bar->BarRect.GetWidth(); // Excess used to shrink leading/trailing section + width_excess = + (section_0_w + section_2_w) - tab_bar->BarRect.GetWidth(); // Excess used to shrink leading/trailing section - // With ImGuiTabBarFlags_FittingPolicyScroll policy, we will only shrink leading/trailing if the central section is not visible anymore - if (width_excess >= 1.0f && ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || !central_section_is_visible)) + // With ImGuiTabBarFlags_FittingPolicyScroll policy, we will only shrink leading/trailing if the central section is + // not visible anymore + if (width_excess >= 1.0f && + ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || !central_section_is_visible)) { - int shrink_data_count = (central_section_is_visible ? sections[1].TabCount : sections[0].TabCount + sections[2].TabCount); + int shrink_data_count = + (central_section_is_visible ? sections[1].TabCount : sections[0].TabCount + sections[2].TabCount); int shrink_data_offset = (central_section_is_visible ? sections[0].TabCount + sections[2].TabCount : 0); ShrinkWidths(g.ShrinkWidthBuffer.Data + shrink_data_offset, shrink_data_count, width_excess); // Apply shrunk values into tabs and sections for (int tab_n = shrink_data_offset; tab_n < shrink_data_offset + shrink_data_count; tab_n++) { - ImGuiTabItem* tab = &tab_bar->Tabs[g.ShrinkWidthBuffer[tab_n].Index]; + ImGuiTabItem *tab = &tab_bar->Tabs[g.ShrinkWidthBuffer[tab_n].Index]; float shrinked_width = IM_TRUNC(g.ShrinkWidthBuffer[tab_n].Width); if (shrinked_width < 0.0f) continue; @@ -9714,13 +11093,13 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) tab_bar->WidthAllTabs = 0.0f; for (int section_n = 0; section_n < 3; section_n++) { - ImGuiTabBarSection* section = §ions[section_n]; + ImGuiTabBarSection *section = §ions[section_n]; if (section_n == 2) tab_offset = ImMin(ImMax(0.0f, tab_bar->BarRect.GetWidth() - section->Width), tab_offset); for (int tab_n = 0; tab_n < section->TabCount; tab_n++) { - ImGuiTabItem* tab = &tab_bar->Tabs[section_tab_index + tab_n]; + ImGuiTabItem *tab = &tab_bar->Tabs[section_tab_index + tab_n]; tab->Offset = tab_offset; tab->NameOffset = -1; tab_offset += tab->Width + (tab_n < section->TabCount - 1 ? g.Style.ItemInnerSpacing.x : 0.0f); @@ -9746,7 +11125,9 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) // Apply request requests if (scroll_to_tab_id != 0) TabBarScrollToTab(tab_bar, scroll_to_tab_id, sections); - else if ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll) && IsMouseHoveringRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, true) && IsWindowContentHoverable(g.CurrentWindow)) + else if ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll) && + IsMouseHoveringRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, true) && + IsWindowContentHoverable(g.CurrentWindow)) { const float wheel = g.IO.MouseWheelRequestAxisSwap ? g.IO.MouseWheel : g.IO.MouseWheelH; const ImGuiKey wheel_key = g.IO.MouseWheelRequestAxisSwap ? ImGuiKey_MouseWheelY : ImGuiKey_MouseWheelX; @@ -9767,9 +11148,13 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) // Scrolling speed adjust itself so we can always reach our target in 1/3 seconds. // Teleport if we are aiming far off the visible line tab_bar->ScrollingSpeed = ImMax(tab_bar->ScrollingSpeed, 70.0f * g.FontSize); - tab_bar->ScrollingSpeed = ImMax(tab_bar->ScrollingSpeed, ImFabs(tab_bar->ScrollingTarget - tab_bar->ScrollingAnim) / 0.3f); - const bool teleport = (tab_bar->PrevFrameVisible + 1 < g.FrameCount) || (tab_bar->ScrollingTargetDistToVisibility > 10.0f * g.FontSize); - tab_bar->ScrollingAnim = teleport ? tab_bar->ScrollingTarget : ImLinearSweep(tab_bar->ScrollingAnim, tab_bar->ScrollingTarget, g.IO.DeltaTime * tab_bar->ScrollingSpeed); + tab_bar->ScrollingSpeed = + ImMax(tab_bar->ScrollingSpeed, ImFabs(tab_bar->ScrollingTarget - tab_bar->ScrollingAnim) / 0.3f); + const bool teleport = (tab_bar->PrevFrameVisible + 1 < g.FrameCount) || + (tab_bar->ScrollingTargetDistToVisibility > 10.0f * g.FontSize); + tab_bar->ScrollingAnim = teleport ? tab_bar->ScrollingTarget + : ImLinearSweep(tab_bar->ScrollingAnim, tab_bar->ScrollingTarget, + g.IO.DeltaTime * tab_bar->ScrollingSpeed); } else { @@ -9779,14 +11164,14 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) tab_bar->ScrollingRectMaxX = tab_bar->BarRect.Max.x - sections[2].Width - sections[1].Spacing; // Actual layout in host window (we don't do it in BeginTabBar() so as not to waste an extra frame) - ImGuiWindow* window = g.CurrentWindow; + ImGuiWindow *window = g.CurrentWindow; window->DC.CursorPos = tab_bar->BarRect.Min; ItemSize(ImVec2(tab_bar->WidthAllTabs, tab_bar->BarRect.GetHeight()), tab_bar->FramePadding.y); window->DC.IdealMaxPos.x = ImMax(window->DC.IdealMaxPos.x, tab_bar->BarRect.Min.x + tab_bar->WidthAllTabsIdeal); } // Dockable windows uses Name/ID in the global namespace. Non-dockable items use the ID stack. -static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label, ImGuiWindow* docked_window) +static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar *tab_bar, const char *label, ImGuiWindow *docked_window) { IM_ASSERT(docked_window == NULL); // master branch only IM_UNUSED(docked_window); @@ -9798,18 +11183,18 @@ static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label, I } else { - ImGuiWindow* window = GImGui->CurrentWindow; + ImGuiWindow *window = GImGui->CurrentWindow; return window->GetID(label); } } static float ImGui::TabBarCalcMaxTabWidth() { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; return g.FontSize * 20.0f; } -ImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id) +ImGuiTabItem *ImGui::TabBarFindTabByID(ImGuiTabBar *tab_bar, ImGuiID tab_id) { if (tab_id != 0) for (int n = 0; n < tab_bar->Tabs.Size; n++) @@ -9819,21 +11204,21 @@ ImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id) } // Order = visible order, not submission order! (which is tab->BeginOrder) -ImGuiTabItem* ImGui::TabBarFindTabByOrder(ImGuiTabBar* tab_bar, int order) +ImGuiTabItem *ImGui::TabBarFindTabByOrder(ImGuiTabBar *tab_bar, int order) { if (order < 0 || order >= tab_bar->Tabs.Size) return NULL; return &tab_bar->Tabs[order]; } -ImGuiTabItem* ImGui::TabBarGetCurrentTab(ImGuiTabBar* tab_bar) +ImGuiTabItem *ImGui::TabBarGetCurrentTab(ImGuiTabBar *tab_bar) { if (tab_bar->LastTabItemIdx < 0 || tab_bar->LastTabItemIdx >= tab_bar->Tabs.Size) return NULL; return &tab_bar->Tabs[tab_bar->LastTabItemIdx]; } -const char* ImGui::TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) +const char *ImGui::TabBarGetTabName(ImGuiTabBar *tab_bar, ImGuiTabItem *tab) { if (tab->NameOffset == -1) return "N/A"; @@ -9841,18 +11226,28 @@ const char* ImGui::TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) return tab_bar->TabsNames.Buf.Data + tab->NameOffset; } -// The *TabId fields are already set by the docking system _before_ the actual TabItem was created, so we clear them regardless. -void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id) +// The *TabId fields are already set by the docking system _before_ the actual TabItem was created, so we clear them +// regardless. +void ImGui::TabBarRemoveTab(ImGuiTabBar *tab_bar, ImGuiID tab_id) { - if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id)) + if (ImGuiTabItem *tab = TabBarFindTabByID(tab_bar, tab_id)) tab_bar->Tabs.erase(tab); - if (tab_bar->VisibleTabId == tab_id) { tab_bar->VisibleTabId = 0; } - if (tab_bar->SelectedTabId == tab_id) { tab_bar->SelectedTabId = 0; } - if (tab_bar->NextSelectedTabId == tab_id) { tab_bar->NextSelectedTabId = 0; } + if (tab_bar->VisibleTabId == tab_id) + { + tab_bar->VisibleTabId = 0; + } + if (tab_bar->SelectedTabId == tab_id) + { + tab_bar->SelectedTabId = 0; + } + if (tab_bar->NextSelectedTabId == tab_id) + { + tab_bar->NextSelectedTabId = 0; + } } // Called on manual closure attempt -void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) +void ImGui::TabBarCloseTab(ImGuiTabBar *tab_bar, ImGuiTabItem *tab) { if (tab->Flags & ImGuiTabItemFlags_Button) return; // A button appended with TabItemButton(). @@ -9860,7 +11255,8 @@ void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) if ((tab->Flags & (ImGuiTabItemFlags_UnsavedDocument | ImGuiTabItemFlags_NoAssumedClosure)) == 0) { // This will remove a frame of lag for selecting another tab on closure. - // However we don't run it in the case where the 'Unsaved' flag is set, so user gets a chance to fully undo the closure + // However we don't run it in the case where the 'Unsaved' flag is set, so user gets a chance to fully undo the + // closure tab->WantClose = true; if (tab_bar->VisibleTabId == tab->ID) { @@ -9870,29 +11266,31 @@ void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) } else { - // Actually select before expecting closure attempt (on an UnsavedDocument tab user is expect to e.g. show a popup) + // Actually select before expecting closure attempt (on an UnsavedDocument tab user is expect to e.g. show a + // popup) if (tab_bar->VisibleTabId != tab->ID) TabBarQueueFocus(tab_bar, tab); } } -static float ImGui::TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling) +static float ImGui::TabBarScrollClamp(ImGuiTabBar *tab_bar, float scrolling) { scrolling = ImMin(scrolling, tab_bar->WidthAllTabs - tab_bar->BarRect.GetWidth()); return ImMax(scrolling, 0.0f); } // 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) +static void ImGui::TabBarScrollToTab(ImGuiTabBar *tab_bar, ImGuiID tab_id, ImGuiTabBarSection *sections) { - ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id); + ImGuiTabItem *tab = TabBarFindTabByID(tab_bar, tab_id); if (tab == NULL) return; if (tab->Flags & ImGuiTabItemFlags_SectionMask_) return; - ImGuiContext& g = *GImGui; - float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar) + ImGuiContext &g = *GImGui; + float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to + // suggest more scrolling area (since we don't have a scrollbar) int order = TabBarGetTabOrder(tab_bar, tab); // Scrolling happens only in the central section (leading/trailing sections are not scrolling) @@ -9900,7 +11298,8 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGui // We make all tabs positions all relative Sections[0].Width to make code simpler float tab_x1 = tab->Offset - sections[0].Width + (order > sections[0].TabCount - 1 ? -margin : 0.0f); - float tab_x2 = tab->Offset - sections[0].Width + tab->Width + (order + 1 < tab_bar->Tabs.Size - sections[2].TabCount ? margin : 1.0f); + float tab_x2 = tab->Offset - sections[0].Width + tab->Width + + (order + 1 < tab_bar->Tabs.Size - sections[2].TabCount ? margin : 1.0f); tab_bar->ScrollingTargetDistToVisibility = 0.0f; if (tab_bar->ScrollingTarget > tab_x1 || (tab_x2 - tab_x1 >= scrollable_width)) { @@ -9916,19 +11315,19 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGui } } -void ImGui::TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) +void ImGui::TabBarQueueFocus(ImGuiTabBar *tab_bar, ImGuiTabItem *tab) { tab_bar->NextSelectedTabId = tab->ID; } -void ImGui::TabBarQueueFocus(ImGuiTabBar* tab_bar, const char* tab_name) +void ImGui::TabBarQueueFocus(ImGuiTabBar *tab_bar, const char *tab_name) { IM_ASSERT((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0); // Only supported for manual/explicit tab bars ImGuiID tab_id = TabBarCalcTabID(tab_bar, tab_name, NULL); tab_bar->NextSelectedTabId = tab_id; } -void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, int offset) +void ImGui::TabBarQueueReorder(ImGuiTabBar *tab_bar, ImGuiTabItem *tab, int offset) { IM_ASSERT(offset != 0); IM_ASSERT(tab_bar->ReorderRequestTabId == 0); @@ -9936,9 +11335,9 @@ void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, int offs tab_bar->ReorderRequestOffset = (ImS16)offset; } -void ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* src_tab, ImVec2 mouse_pos) +void ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar *tab_bar, ImGuiTabItem *src_tab, ImVec2 mouse_pos) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; IM_ASSERT(tab_bar->ReorderRequestTabId == 0); if ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) == 0) return; @@ -9953,17 +11352,19 @@ void ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* s 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]; + 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. + // 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)); + // 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; } @@ -9972,29 +11373,31 @@ void ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* s TabBarQueueReorder(tab_bar, src_tab, dst_idx - src_idx); } -bool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar) +bool ImGui::TabBarProcessReorder(ImGuiTabBar *tab_bar) { - ImGuiTabItem* tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId); + ImGuiTabItem *tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId); if (tab1 == NULL || (tab1->Flags & ImGuiTabItemFlags_NoReorder)) return false; - //IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools + // IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools int tab2_order = TabBarGetTabOrder(tab_bar, tab1) + tab_bar->ReorderRequestOffset; if (tab2_order < 0 || tab2_order >= tab_bar->Tabs.Size) return false; // 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]; + // (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_SectionMask_) != (tab2->Flags & ImGuiTabItemFlags_SectionMask_)) return false; ImGuiTabItem item_tmp = *tab1; - 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; + 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; @@ -10003,16 +11406,17 @@ bool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar) return true; } -static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) +static ImGuiTabItem *ImGui::TabBarScrollingButtons(ImGuiTabBar *tab_bar) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; const ImVec2 arrow_button_size(g.FontSize - 2.0f, g.FontSize + g.Style.FramePadding.y * 2.0f); const float scrolling_buttons_width = arrow_button_size.x * 2.0f; const ImVec2 backup_cursor_pos = window->DC.CursorPos; - //window->DrawList->AddRect(ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width, tab_bar->BarRect.Min.y), ImVec2(tab_bar->BarRect.Max.x, tab_bar->BarRect.Max.y), IM_COL32(255,0,0,255)); + // window->DrawList->AddRect(ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width, tab_bar->BarRect.Min.y), + // ImVec2(tab_bar->BarRect.Max.x, tab_bar->BarRect.Max.y), IM_COL32(255,0,0,255)); int select_dir = 0; ImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text]; @@ -10037,9 +11441,9 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) g.IO.KeyRepeatRate = backup_repeat_rate; g.IO.KeyRepeatDelay = backup_repeat_delay; - ImGuiTabItem* tab_to_scroll_to = NULL; + ImGuiTabItem *tab_to_scroll_to = NULL; if (select_dir != 0) - if (ImGuiTabItem* tab_item = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId)) + if (ImGuiTabItem *tab_item = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId)) { int selected_order = TabBarGetTabOrder(tab_bar, tab_item); int target_order = selected_order + select_dir; @@ -10048,7 +11452,9 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) while (tab_to_scroll_to == NULL) { // If we are at the end of the list, still scroll to make our tab visible - tab_to_scroll_to = &tab_bar->Tabs[(target_order >= 0 && target_order < tab_bar->Tabs.Size) ? target_order : selected_order]; + tab_to_scroll_to = + &tab_bar->Tabs[(target_order >= 0 && target_order < tab_bar->Tabs.Size) ? target_order + : selected_order]; // Cross through buttons // (even if first/last item is a button, return it so we can update the scroll) @@ -10056,7 +11462,8 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) { target_order += select_dir; selected_order += select_dir; - tab_to_scroll_to = (target_order < 0 || target_order >= tab_bar->Tabs.Size) ? tab_to_scroll_to : NULL; + tab_to_scroll_to = + (target_order < 0 || target_order >= tab_bar->Tabs.Size) ? tab_to_scroll_to : NULL; } } } @@ -10066,10 +11473,10 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) return tab_to_scroll_to; } -static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar) +static ImGuiTabItem *ImGui::TabBarTabListPopupButton(ImGuiTabBar *tab_bar) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; // We use g.Style.FramePadding.y to match the square ArrowButton size const float tab_list_popup_button_width = g.FontSize + g.Style.FramePadding.y; @@ -10084,16 +11491,16 @@ static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar) bool open = BeginCombo("##v", NULL, ImGuiComboFlags_NoPreview | ImGuiComboFlags_HeightLargest); PopStyleColor(2); - ImGuiTabItem* tab_to_select = NULL; + ImGuiTabItem *tab_to_select = NULL; if (open) { for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) { - ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + ImGuiTabItem *tab = &tab_bar->Tabs[tab_n]; if (tab->Flags & ImGuiTabItemFlags_Button) continue; - const char* tab_name = TabBarGetTabName(tab_bar, tab); + const char *tab_name = TabBarGetTabName(tab_bar, tab); if (Selectable(tab_name, tab_bar->SelectedTabId == tab->ID)) tab_to_select = tab; } @@ -10117,57 +11524,59 @@ static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar) // - TabItemLabelAndCloseButton() [Internal] //------------------------------------------------------------------------- -bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags flags) +bool ImGui::BeginTabItem(const char *label, bool *p_open, ImGuiTabItemFlags flags) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; if (window->SkipItems) return false; - ImGuiTabBar* tab_bar = g.CurrentTabBar; + ImGuiTabBar *tab_bar = g.CurrentTabBar; if (tab_bar == NULL) { IM_ASSERT_USER_ERROR(tab_bar, "Needs to be called between BeginTabBar() and EndTabBar()!"); return false; } - IM_ASSERT((flags & ImGuiTabItemFlags_Button) == 0); // BeginTabItem() Can't be used with button flags, use TabItemButton() instead! + IM_ASSERT((flags & ImGuiTabItemFlags_Button) == + 0); // BeginTabItem() Can't be used with button flags, use TabItemButton() instead! bool ret = TabItemEx(tab_bar, label, p_open, flags, NULL); if (ret && !(flags & ImGuiTabItemFlags_NoPushId)) { - ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; - PushOverrideID(tab->ID); // We already hashed 'label' so push into the ID stack directly instead of doing another hash through PushID(label) + ImGuiTabItem *tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; + PushOverrideID(tab->ID); // We already hashed 'label' so push into the ID stack directly instead of doing + // another hash through PushID(label) } return ret; } -void ImGui::EndTabItem() +void ImGui::EndTabItem() { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; if (window->SkipItems) return; - ImGuiTabBar* tab_bar = g.CurrentTabBar; + ImGuiTabBar *tab_bar = g.CurrentTabBar; if (tab_bar == NULL) { IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); return; } IM_ASSERT(tab_bar->LastTabItemIdx >= 0); - ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; + ImGuiTabItem *tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; if (!(tab->Flags & ImGuiTabItemFlags_NoPushId)) PopID(); } -bool ImGui::TabItemButton(const char* label, ImGuiTabItemFlags flags) +bool ImGui::TabItemButton(const char *label, ImGuiTabItemFlags flags) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; if (window->SkipItems) return false; - ImGuiTabBar* tab_bar = g.CurrentTabBar; + ImGuiTabBar *tab_bar = g.CurrentTabBar; if (tab_bar == NULL) { IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); @@ -10176,42 +11585,45 @@ bool ImGui::TabItemButton(const char* label, ImGuiTabItemFlags flags) return TabItemEx(tab_bar, label, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder, NULL); } -void ImGui::TabItemSpacing(const char* str_id, ImGuiTabItemFlags flags, float width) +void ImGui::TabItemSpacing(const char *str_id, ImGuiTabItemFlags flags, float width) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiContext &g = *GImGui; + ImGuiWindow *window = g.CurrentWindow; if (window->SkipItems) return; - ImGuiTabBar* tab_bar = g.CurrentTabBar; + ImGuiTabBar *tab_bar = g.CurrentTabBar; if (tab_bar == NULL) { IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); return; } SetNextItemWidth(width); - TabItemEx(tab_bar, str_id, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder | ImGuiTabItemFlags_Invisible, NULL); + TabItemEx(tab_bar, str_id, NULL, + flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder | ImGuiTabItemFlags_Invisible, NULL); } -bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window) +bool ImGui::TabItemEx(ImGuiTabBar *tab_bar, const char *label, bool *p_open, ImGuiTabItemFlags flags, + ImGuiWindow *docked_window) { // Layout whole tab bar if not already done - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; if (tab_bar->WantLayout) { ImGuiNextItemData backup_next_item_data = g.NextItemData; TabBarLayout(tab_bar); g.NextItemData = backup_next_item_data; } - ImGuiWindow* window = g.CurrentWindow; + ImGuiWindow *window = g.CurrentWindow; if (window->SkipItems) return false; - const ImGuiStyle& style = g.Style; + const ImGuiStyle &style = g.Style; const ImGuiID id = TabBarCalcTabID(tab_bar, label, docked_window); // If the user called us with *p_open == false, we early out and don't render. - // We make a call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an older ID. + // We make a call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an + // older ID. IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); if (p_open && !*p_open) { @@ -10220,16 +11632,18 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, } IM_ASSERT(!p_open || !(flags & ImGuiTabItemFlags_Button)); - IM_ASSERT((flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) != (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)); // Can't use both Leading and Trailing + IM_ASSERT((flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) != + (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)); // Can't use both Leading and Trailing - // Store into ImGuiTabItemFlags_NoCloseButton, also honor ImGuiTabItemFlags_NoCloseButton passed by user (although not documented) + // Store into ImGuiTabItemFlags_NoCloseButton, also honor ImGuiTabItemFlags_NoCloseButton passed by user (although + // not documented) if (flags & ImGuiTabItemFlags_NoCloseButton) p_open = NULL; else if (p_open == NULL) flags |= ImGuiTabItemFlags_NoCloseButton; // Acquire tab data - ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, id); + ImGuiTabItem *tab = TabBarFindTabByID(tab_bar, id); bool tab_is_new = false; if (tab == NULL) { @@ -10253,7 +11667,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); const bool tab_bar_focused = (tab_bar->Flags & ImGuiTabBarFlags_IsFocused) != 0; const bool tab_appearing = (tab->LastFrameVisible + 1 < g.FrameCount); - const bool tab_just_unsaved = (flags & ImGuiTabItemFlags_UnsavedDocument) && !(tab->Flags & ImGuiTabItemFlags_UnsavedDocument); + const bool tab_just_unsaved = + (flags & ImGuiTabItemFlags_UnsavedDocument) && !(tab->Flags & ImGuiTabItemFlags_UnsavedDocument); const bool is_tab_button = (flags & ImGuiTabItemFlags_Button) != 0; tab->LastFrameVisible = g.FrameCount; tab->Flags = flags; @@ -10275,12 +11690,14 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0) if (!tab_bar_appearing || tab_bar->SelectedTabId == 0) TabBarQueueFocus(tab_bar, tab); // New tabs gets activated - if ((flags & ImGuiTabItemFlags_SetSelected) && (tab_bar->SelectedTabId != id)) // _SetSelected can only be passed on explicit tab bar + if ((flags & ImGuiTabItemFlags_SetSelected) && + (tab_bar->SelectedTabId != id)) // _SetSelected can only be passed on explicit tab bar TabBarQueueFocus(tab_bar, tab); } // Lock visibility - // (Note: tab_contents_visible != tab_selected... because CTRL+TAB operations may preview some tabs without selecting them!) + // (Note: tab_contents_visible != tab_selected... because CTRL+TAB operations may preview some tabs without + // selecting them!) bool tab_contents_visible = (tab_bar->VisibleTabId == id); if (tab_contents_visible) tab_bar->VisibleTabWasSubmitted = true; @@ -10316,10 +11733,13 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImVec2 pos = window->DC.CursorPos; ImRect bb(pos, pos + size); - // We don't have CPU clipping primitives to clip the CloseButton (until it becomes a texture), so need to add an extra draw call (temporary in the case of vertical animation) - const bool want_clip_rect = is_central_section && (bb.Min.x < tab_bar->ScrollingRectMinX || bb.Max.x > tab_bar->ScrollingRectMaxX); + // We don't have CPU clipping primitives to clip the CloseButton (until it becomes a texture), so need to add an + // extra draw call (temporary in the case of vertical animation) + const bool want_clip_rect = + is_central_section && (bb.Min.x < tab_bar->ScrollingRectMinX || bb.Max.x > tab_bar->ScrollingRectMaxX); if (want_clip_rect) - PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->ScrollingRectMinX), bb.Min.y - 1), ImVec2(tab_bar->ScrollingRectMaxX, bb.Max.y), true); + PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->ScrollingRectMinX), bb.Min.y - 1), + ImVec2(tab_bar->ScrollingRectMaxX, bb.Max.y), true); ImVec2 backup_cursor_max_pos = window->DC.CursorMaxPos; ItemSize(bb.GetSize(), style.FramePadding.y); @@ -10335,7 +11755,9 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // Click to Select a tab // Allow the close button to overlap - ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowOverlap); + ImGuiButtonFlags button_flags = + ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | + ImGuiButtonFlags_AllowOverlap); if (g.DragDropActive) button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; bool hovered, held, pressed; @@ -10374,18 +11796,24 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, #endif // Render tab shape - const bool is_visible = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) && !(flags & ImGuiTabItemFlags_Invisible); + const bool is_visible = + (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) && !(flags & ImGuiTabItemFlags_Invisible); if (is_visible) { - ImDrawList* display_draw_list = window->DrawList; - const ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabSelected : ImGuiCol_TabDimmedSelected) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabDimmed)); + ImDrawList *display_draw_list = window->DrawList; + const ImU32 tab_col = + GetColorU32((held || hovered) ? ImGuiCol_TabHovered + : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabSelected : ImGuiCol_TabDimmedSelected) + : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabDimmed)); TabItemBackground(display_draw_list, bb, flags, tab_col); - if (tab_contents_visible && (tab_bar->Flags & ImGuiTabBarFlags_DrawSelectedOverline) && style.TabBarOverlineSize > 0.0f) + if (tab_contents_visible && (tab_bar->Flags & ImGuiTabBarFlags_DrawSelectedOverline) && + style.TabBarOverlineSize > 0.0f) { // Might be moved to TabItemBackground() ? ImVec2 tl = bb.GetTL() + ImVec2(0, 1.0f * g.CurrentDpiScale); ImVec2 tr = bb.GetTR() + ImVec2(0, 1.0f * g.CurrentDpiScale); - ImU32 overline_col = GetColorU32(tab_bar_focused ? ImGuiCol_TabSelectedOverline : ImGuiCol_TabDimmedSelectedOverline); + ImU32 overline_col = + GetColorU32(tab_bar_focused ? ImGuiCol_TabSelectedOverline : ImGuiCol_TabDimmedSelectedOverline); if (style.TabRounding > 0.0f) { float rounding = style.TabRounding; @@ -10395,14 +11823,17 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, } else { - display_draw_list->AddLine(tl - ImVec2(0.5f, 0.5f), tr - ImVec2(0.5f, 0.5f), overline_col, style.TabBarOverlineSize); + display_draw_list->AddLine(tl - ImVec2(0.5f, 0.5f), tr - ImVec2(0.5f, 0.5f), overline_col, + style.TabBarOverlineSize); } } RenderNavCursor(bb, id); - // Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget. + // Select with right mouse button. This is so the common idiom for context menu automatically highlight the + // current widget. const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup); - if (tab_bar->SelectedTabId != tab->ID && hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)) && !is_tab_button) + if (tab_bar->SelectedTabId != tab->ID && hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)) && + !is_tab_button) TabBarQueueFocus(tab_bar, tab); if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton) @@ -10412,7 +11843,9 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, id) : 0; bool just_closed; bool text_clipped; - TabItemLabelAndCloseButton(display_draw_list, bb, tab_just_unsaved ? (flags & ~ImGuiTabItemFlags_UnsavedDocument) : flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped); + TabItemLabelAndCloseButton( + display_draw_list, bb, tab_just_unsaved ? (flags & ~ImGuiTabItemFlags_UnsavedDocument) : flags, + tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped); if (just_closed && p_open != NULL) { *p_open = false; @@ -10421,7 +11854,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // Tooltip // (Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer-> seems ok) - // (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which g.HoveredId ignores) + // (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which + // g.HoveredId ignores) // FIXME: This is a mess. // FIXME: We may want disabled tab to still display the tooltip? if (text_clipped && g.HoveredId == id && !held) @@ -10434,54 +11868,59 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, PopClipRect(); window->DC.CursorPos = backup_main_cursor_pos; - IM_ASSERT(!is_tab_button || !(tab_bar->SelectedTabId == tab->ID && is_tab_button)); // TabItemButton should not be selected + IM_ASSERT(!is_tab_button || + !(tab_bar->SelectedTabId == tab->ID && is_tab_button)); // TabItemButton should not be selected if (is_tab_button) return pressed; return tab_contents_visible; } -// [Public] This is call is 100% optional but it allows to remove some one-frame glitches when a tab has been unexpectedly removed. -// To use it to need to call the function SetTabItemClosed() between BeginTabBar() and EndTabBar(). -// Tabs closed by the close button will automatically be flagged to avoid this issue. -void ImGui::SetTabItemClosed(const char* label) +// [Public] This is call is 100% optional but it allows to remove some one-frame glitches when a tab has been +// unexpectedly removed. To use it to need to call the function SetTabItemClosed() between BeginTabBar() and +// EndTabBar(). Tabs closed by the close button will automatically be flagged to avoid this issue. +void ImGui::SetTabItemClosed(const char *label) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; bool is_within_manual_tab_bar = g.CurrentTabBar && !(g.CurrentTabBar->Flags & ImGuiTabBarFlags_DockNode); if (is_within_manual_tab_bar) { - ImGuiTabBar* tab_bar = g.CurrentTabBar; + ImGuiTabBar *tab_bar = g.CurrentTabBar; ImGuiID tab_id = TabBarCalcTabID(tab_bar, label, NULL); - if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id)) + if (ImGuiTabItem *tab = TabBarFindTabByID(tab_bar, tab_id)) tab->WantClose = true; // Will be processed by next call to TabBarLayout() } } -ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker) +ImVec2 ImGui::TabItemCalcSize(const char *label, bool has_close_button_or_unsaved_marker) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; ImVec2 label_size = CalcTextSize(label, NULL, true); ImVec2 size = ImVec2(label_size.x + g.Style.FramePadding.x, label_size.y + g.Style.FramePadding.y * 2.0f); if (has_close_button_or_unsaved_marker) - size.x += g.Style.FramePadding.x + (g.Style.ItemInnerSpacing.x + g.FontSize); // We use Y intentionally to fit the close button circle. + size.x += g.Style.FramePadding.x + + (g.Style.ItemInnerSpacing.x + g.FontSize); // We use Y intentionally to fit the close button circle. else size.x += g.Style.FramePadding.x + 1.0f; return ImVec2(ImMin(size.x, TabBarCalcMaxTabWidth()), size.y); } -ImVec2 ImGui::TabItemCalcSize(ImGuiWindow*) +ImVec2 ImGui::TabItemCalcSize(ImGuiWindow *) { IM_ASSERT(0); // This function exists to facilitate merge with 'docking' branch. return ImVec2(0.0f, 0.0f); } -void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col) +void ImGui::TabItemBackground(ImDrawList *draw_list, const ImRect &bb, ImGuiTabItemFlags flags, ImU32 col) { - // While rendering tabs, we trim 1 pixel off the top of our bounding box so they can fit within a regular frame height while looking "detached" from it. - ImGuiContext& g = *GImGui; + // While rendering tabs, we trim 1 pixel off the top of our bounding box so they can fit within a regular frame + // height while looking "detached" from it. + ImGuiContext &g = *GImGui; const float width = bb.GetWidth(); IM_UNUSED(flags); IM_ASSERT(width > 0.0f); - const float rounding = ImMax(0.0f, ImMin((flags & ImGuiTabItemFlags_Button) ? g.Style.FrameRounding : g.Style.TabRounding, width * 0.5f - 1.0f)); + const float rounding = + ImMax(0.0f, ImMin((flags & ImGuiTabItemFlags_Button) ? g.Style.FrameRounding : g.Style.TabRounding, + width * 0.5f - 1.0f)); const float y1 = bb.Min.y + 1.0f; const float y2 = bb.Max.y - g.Style.TabBarBorderSize; draw_list->PathLineTo(ImVec2(bb.Min.x, y2)); @@ -10501,9 +11940,11 @@ void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabI // Render text label (with custom clipping) + Unsaved Document marker + Close Button logic // We tend to lock style.FramePadding for a given tab-bar, hence the 'frame_padding' parameter. -void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible, bool* out_just_closed, bool* out_text_clipped) +void ImGui::TabItemLabelAndCloseButton(ImDrawList *draw_list, const ImRect &bb, ImGuiTabItemFlags flags, + ImVec2 frame_padding, const char *label, ImGuiID tab_id, ImGuiID close_button_id, + bool is_contents_visible, bool *out_just_closed, bool *out_text_clipped) { - ImGuiContext& g = *GImGui; + ImGuiContext &g = *GImGui; ImVec2 label_size = CalcTextSize(label, NULL, true); if (out_just_closed) @@ -10523,37 +11964,50 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, #endif // Render text label (with clipping + alpha gradient) + unsaved marker - ImRect text_ellipsis_clip_bb(bb.Min.x + frame_padding.x, bb.Min.y + frame_padding.y, bb.Max.x - frame_padding.x, bb.Max.y); + ImRect text_ellipsis_clip_bb(bb.Min.x + frame_padding.x, bb.Min.y + frame_padding.y, bb.Max.x - frame_padding.x, + bb.Max.y); // Return clipped state ignoring the close button if (out_text_clipped) { *out_text_clipped = (text_ellipsis_clip_bb.Min.x + label_size.x) > text_ellipsis_clip_bb.Max.x; - //draw_list->AddCircle(text_ellipsis_clip_bb.Min, 3.0f, *out_text_clipped ? IM_COL32(255, 0, 0, 255) : IM_COL32(0, 255, 0, 255)); + // draw_list->AddCircle(text_ellipsis_clip_bb.Min, 3.0f, *out_text_clipped ? IM_COL32(255, 0, 0, 255) : + // IM_COL32(0, 255, 0, 255)); } const float button_sz = g.FontSize; const ImVec2 button_pos(ImMax(bb.Min.x, bb.Max.x - frame_padding.x - button_sz), bb.Min.y + frame_padding.y); // Close Button & Unsaved Marker - // We are relying on a subtle and confusing distinction between 'hovered' and 'g.HoveredId' which happens because we are using ImGuiButtonFlags_AllowOverlapMode + SetItemAllowOverlap() + // We are relying on a subtle and confusing distinction between 'hovered' and 'g.HoveredId' which happens because we + // are using ImGuiButtonFlags_AllowOverlapMode + SetItemAllowOverlap() // 'hovered' will be true when hovering the Tab but NOT when hovering the close button // 'g.HoveredId==id' will be true when hovering the Tab including when hovering the close button - // 'g.ActiveId==close_button_id' will be true when we are holding on the close button, in which case both hovered booleans are false + // 'g.ActiveId==close_button_id' will be true when we are holding on the close button, in which case both hovered + // booleans are false bool close_button_pressed = false; bool close_button_visible = false; - bool is_hovered = g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == tab_id || g.ActiveId == close_button_id; // Any interaction account for this too. + bool is_hovered = g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == tab_id || + g.ActiveId == close_button_id; // Any interaction account for this too. if (close_button_id != 0) { if (is_contents_visible) - close_button_visible = (g.Style.TabCloseButtonMinWidthSelected < 0.0f) ? true : (is_hovered && bb.GetWidth() >= ImMax(button_sz, g.Style.TabCloseButtonMinWidthSelected)); + close_button_visible = + (g.Style.TabCloseButtonMinWidthSelected < 0.0f) + ? true + : (is_hovered && bb.GetWidth() >= ImMax(button_sz, g.Style.TabCloseButtonMinWidthSelected)); else - close_button_visible = (g.Style.TabCloseButtonMinWidthUnselected < 0.0f) ? true : (is_hovered && bb.GetWidth() >= ImMax(button_sz, g.Style.TabCloseButtonMinWidthUnselected)); + close_button_visible = + (g.Style.TabCloseButtonMinWidthUnselected < 0.0f) + ? true + : (is_hovered && bb.GetWidth() >= ImMax(button_sz, g.Style.TabCloseButtonMinWidthUnselected)); } // When tabs/document is unsaved, the unsaved marker takes priority over the close button. - const bool unsaved_marker_visible = (flags & ImGuiTabItemFlags_UnsavedDocument) != 0 && (button_pos.x + button_sz <= bb.Max.x) && (!close_button_visible || !is_hovered); + const bool unsaved_marker_visible = (flags & ImGuiTabItemFlags_UnsavedDocument) != 0 && + (button_pos.x + button_sz <= bb.Max.x) && + (!close_button_visible || !is_hovered); if (unsaved_marker_visible) { const ImRect bullet_bb(button_pos, button_pos + ImVec2(button_sz, button_sz)); @@ -10572,12 +12026,16 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, } // This is all rather complicated - // (the main idea is that because the close button only appears on hover, we don't want it to alter the ellipsis position) - // FIXME: if FramePadding is noticeably large, ellipsis_max_x will be wrong here (e.g. #3497), maybe for consistency that parameter of RenderTextEllipsis() shouldn't exist.. + // (the main idea is that because the close button only appears on hover, we don't want it to alter the ellipsis + // position) + // FIXME: if FramePadding is noticeably large, ellipsis_max_x will be wrong here (e.g. #3497), maybe for consistency + // that parameter of RenderTextEllipsis() shouldn't exist.. float ellipsis_max_x = text_ellipsis_clip_bb.Max.x; if (close_button_visible || unsaved_marker_visible) { - const bool visible_without_hover = unsaved_marker_visible || (is_contents_visible ? g.Style.TabCloseButtonMinWidthSelected : g.Style.TabCloseButtonMinWidthUnselected) < 0.0f; + const bool visible_without_hover = + unsaved_marker_visible || (is_contents_visible ? g.Style.TabCloseButtonMinWidthSelected + : g.Style.TabCloseButtonMinWidthUnselected) < 0.0f; if (visible_without_hover) { text_ellipsis_clip_bb.Max.x -= button_sz * 0.90f; @@ -10589,7 +12047,8 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, } } LogSetNextTextDecoration("/", "\\"); - RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, ellipsis_max_x, label, NULL, &label_size); + RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, ellipsis_max_x, label, NULL, + &label_size); #if 0 if (!is_contents_visible) @@ -10600,5 +12059,4 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, *out_just_closed = close_button_pressed; } - #endif // #ifndef IMGUI_DISABLE diff --git a/firmware/components/imgui/include/imgui.h b/firmware/components/imgui/include/imgui.h index de0d066..4570e30 100644 --- a/firmware/components/imgui/include/imgui.h +++ b/firmware/components/imgui/include/imgui.h @@ -5,22 +5,27 @@ // - See links below. // - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. // - Read top of imgui.cpp for more details, links and comments. -// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths operators for ImVec2 and ImVec4. +// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths +// operators for ImVec2 and ImVec4. // Resources: // - FAQ ........................ https://dearimgui.com/faq (in repository as docs/FAQ.md) // - Homepage ................... https://github.com/ocornut/imgui // - Releases & changelog ....... https://github.com/ocornut/imgui/releases -// - Gallery .................... https://github.com/ocornut/imgui/issues?q=label%3Agallery (please post your screenshots/video there!) +// - Gallery .................... https://github.com/ocornut/imgui/issues?q=label%3Agallery (please post your +// screenshots/video there!) // - Wiki ....................... https://github.com/ocornut/imgui/wiki (lots of good stuff there) -// - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started (how to integrate in an existing app by adding ~25 lines of code) +// - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started (how to integrate in an existing +// app by adding ~25 lines of code) // - Third-party Extensions https://github.com/ocornut/imgui/wiki/Useful-Extensions (ImPlot & many more) -// - Bindings/Backends https://github.com/ocornut/imgui/wiki/Bindings (language bindings, backends for various tech/engines) +// - Bindings/Backends https://github.com/ocornut/imgui/wiki/Bindings (language bindings, backends for +// various tech/engines) // - Glossary https://github.com/ocornut/imgui/wiki/Glossary // - Debug Tools https://github.com/ocornut/imgui/wiki/Debug-Tools // - Software using Dear ImGui https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui // - Issues & support ........... https://github.com/ocornut/imgui/issues -// - Test Engine & Automation ... https://github.com/ocornut/imgui_test_engine (test suite, test engine to automate your apps) +// - Test Engine & Automation ... https://github.com/ocornut/imgui_test_engine (test suite, test engine to automate your +// apps) // For first-time users having issues compiling/linking/running/loading fonts: // please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above. @@ -28,10 +33,10 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.92.0 WIP" -#define IMGUI_VERSION_NUM 19198 -#define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 -#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 +#define IMGUI_VERSION "1.92.0 WIP" +#define IMGUI_VERSION_NUM 19198 +#define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 +#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 /* @@ -41,16 +46,21 @@ Index of this file: // [SECTION] Texture identifiers (ImTextureID, ImTextureRef) // [SECTION] Dear ImGui end-user API functions // [SECTION] Flags & Enumerations -// [SECTION] Tables API flags and structures (ImGuiTableFlags, ImGuiTableColumnFlags, ImGuiTableRowFlags, ImGuiTableBgTarget, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs) +// [SECTION] Tables API flags and structures (ImGuiTableFlags, ImGuiTableColumnFlags, ImGuiTableRowFlags, +ImGuiTableBgTarget, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs) // [SECTION] Helpers: Debug log, Memory allocations macros, ImVector<> // [SECTION] ImGuiStyle // [SECTION] ImGuiIO // [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload) -// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor) -// [SECTION] Multi-Select API flags and structures (ImGuiMultiSelectFlags, ImGuiMultiSelectIO, ImGuiSelectionRequest, ImGuiSelectionBasicStorage, ImGuiSelectionExternalStorage) -// [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData) +// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math +Operators, ImColor) +// [SECTION] Multi-Select API flags and structures (ImGuiMultiSelectFlags, ImGuiMultiSelectIO, ImGuiSelectionRequest, +ImGuiSelectionBasicStorage, ImGuiSelectionExternalStorage) +// [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, +ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData) // [SECTION] Texture API (ImTextureFormat, ImTextureStatus, ImTextureRect, ImTextureData) -// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFontBaked, ImFont) +// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFontBaked, +ImFont) // [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport) // [SECTION] ImGuiPlatformIO + other Platform Dependent Interfaces (ImGuiPlatformImeData) // [SECTION] Obsolete functions and types @@ -73,50 +83,60 @@ Index of this file: //----------------------------------------------------------------------------- // Includes -#include // FLT_MIN, FLT_MAX -#include // va_list, va_start, va_end -#include // ptrdiff_t, NULL -#include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp +#include // FLT_MIN, FLT_MAX +#include // va_list, va_start, va_end +#include // ptrdiff_t, NULL +#include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp // Define attributes of all API symbols declarations (e.g. for DLL under Windows) // IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default backends files (imgui_impl_xxx.h) -// Using dear imgui via a shared library is not recommended: we don't guarantee backward nor forward ABI compatibility + this is a call-heavy library and function call overhead adds up. +// Using dear imgui via a shared library is not recommended: we don't guarantee backward nor forward ABI compatibility + +// this is a call-heavy library and function call overhead adds up. #ifndef IMGUI_API #define IMGUI_API #endif #ifndef IMGUI_IMPL_API -#define IMGUI_IMPL_API IMGUI_API +#define IMGUI_IMPL_API IMGUI_API #endif // Helper Macros #ifndef IM_ASSERT #include -#define IM_ASSERT(_EXPR) assert(_EXPR) // You can override the default assert handler by editing imconfig.h +#define IM_ASSERT(_EXPR) assert(_EXPR) // You can override the default assert handler by editing imconfig.h #endif -#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR) / sizeof(*(_ARR)))) // Size of a static C-style array. Don't use on pointers! -#define IM_UNUSED(_VAR) ((void)(_VAR)) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds. +#define IM_ARRAYSIZE(_ARR) \ + ((int)(sizeof(_ARR) / sizeof(*(_ARR)))) // Size of a static C-style array. Don't use on pointers! +#define IM_UNUSED(_VAR) \ + ((void)(_VAR)) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final + // builds. -// Check that version and structures layouts are matching between compiled imgui code and caller. Read comments above DebugCheckVersionAndDataLayout() for details. -#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) +// Check that version and structures layouts are matching between compiled imgui code and caller. Read comments above +// DebugCheckVersionAndDataLayout() for details. +#define IMGUI_CHECKVERSION() \ + ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), \ + sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) // Helper Macros - IM_FMTARGS, IM_FMTLIST: Apply printf-style warnings to our formatting functions. // (MSVC provides an equivalent mechanism via SAL Annotations but it would require the macros in a different // location. e.g. #include + void myprintf(_Printf_format_string_ const char* format, ...)) #if !defined(IMGUI_USE_STB_SPRINTF) && defined(__MINGW32__) && !defined(__clang__) -#define IM_FMTARGS(FMT) __attribute__((format(gnu_printf, FMT, FMT+1))) -#define IM_FMTLIST(FMT) __attribute__((format(gnu_printf, FMT, 0))) +#define IM_FMTARGS(FMT) __attribute__((format(gnu_printf, FMT, FMT + 1))) +#define IM_FMTLIST(FMT) __attribute__((format(gnu_printf, FMT, 0))) #elif !defined(IMGUI_USE_STB_SPRINTF) && (defined(__clang__) || defined(__GNUC__)) -#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) -#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0))) +#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT + 1))) +#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0))) #else #define IM_FMTARGS(FMT) #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(__INTEL_COMPILER) && !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)) +// 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(__INTEL_COMPILER) && !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 @@ -124,26 +144,32 @@ Index of this file: // Warnings #ifdef _MSC_VER -#pragma warning (push) -#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6). +#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 #if __has_warning("-Wunknown-warning-option") -#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' +#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 "-Wold-style-cast" // warning: use of old-style cast -#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe -#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant -#pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter -#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access -#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant +#pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts + // with '_' followed by a capital letter +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access +#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to + // non-trivially copyable type #elif defined(__GNUC__) #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe -#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe +#pragma GCC diagnostic ignored \ + "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no + // trivial copy-assignment; use assignment or value-initialization instead #endif //----------------------------------------------------------------------------- @@ -151,119 +177,150 @@ Index of this file: //----------------------------------------------------------------------------- // Scalar data types -typedef unsigned int ImGuiID;// A unique ID used by widgets (typically the result of hashing a stack of string) -typedef signed char ImS8; // 8-bit signed integer -typedef unsigned char ImU8; // 8-bit unsigned integer -typedef signed short ImS16; // 16-bit signed integer -typedef unsigned short ImU16; // 16-bit unsigned integer -typedef signed int ImS32; // 32-bit signed integer == int -typedef unsigned int ImU32; // 32-bit unsigned integer (often used to store packed colors) -typedef signed long long ImS64; // 64-bit signed integer -typedef unsigned long long ImU64; // 64-bit unsigned integer +typedef unsigned int ImGuiID; // A unique ID used by widgets (typically the result of hashing a stack of string) +typedef signed char ImS8; // 8-bit signed integer +typedef unsigned char ImU8; // 8-bit unsigned integer +typedef signed short ImS16; // 16-bit signed integer +typedef unsigned short ImU16; // 16-bit unsigned integer +typedef signed int ImS32; // 32-bit signed integer == int +typedef unsigned int ImU32; // 32-bit unsigned integer (often used to store packed colors) +typedef signed long long ImS64; // 64-bit signed integer +typedef unsigned long long ImU64; // 64-bit unsigned integer // Forward declarations: ImDrawList, ImFontAtlas layer -struct ImDrawChannel; // Temporary storage to output draw commands out of order, used by ImDrawListSplitter and ImDrawList::ChannelsSplit() -struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a callback) -struct ImDrawData; // All draw command lists required to render the frame + pos/size coordinates to use for the projection matrix. -struct ImDrawList; // A single draw command list (generally one per window, conceptually you may see this as a dynamic "mesh" builder) -struct ImDrawListSharedData; // Data shared among multiple draw lists (typically owned by parent ImGui context, but you may create one yourself) -struct ImDrawListSplitter; // Helper to split a draw list into different layers which can be drawn into out of order, then flattened back. -struct ImDrawVert; // A single vertex (pos + uv + col = 20 bytes by default. Override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT) -struct ImFont; // Runtime data for a single font within a parent ImFontAtlas -struct ImFontAtlas; // Runtime data for multiple fonts, bake multiple fonts into a single texture, TTF/OTF font loader -struct ImFontAtlasBuilder; // Opaque storage for building a ImFontAtlas -struct ImFontAtlasRect; // Output of ImFontAtlas::GetCustomRect() when using custom rectangles. -struct ImFontBaked; // Baked data for a ImFont at a given size. -struct ImFontConfig; // Configuration data when adding a font or merging fonts -struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset) -struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data -struct ImFontLoader; // Opaque interface to a font loading backend (stb_truetype, FreeType etc.). -struct ImTextureData; // Specs and pixel storage for a texture used by Dear ImGui. -struct ImTextureRect; // Coordinates of a rectangle within a texture. -struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using) +struct ImDrawChannel; // Temporary storage to output draw commands out of order, used by ImDrawListSplitter and + // ImDrawList::ChannelsSplit() +struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a + // callback) +struct ImDrawData; // All draw command lists required to render the frame + pos/size coordinates to use for the + // projection matrix. +struct ImDrawList; // A single draw command list (generally one per window, conceptually you may see this as a dynamic + // "mesh" builder) +struct ImDrawListSharedData; // Data shared among multiple draw lists (typically owned by parent ImGui context, but you + // may create one yourself) +struct ImDrawListSplitter; // Helper to split a draw list into different layers which can be drawn into out of order, + // then flattened back. +struct ImDrawVert; // A single vertex (pos + uv + col = 20 bytes by default. Override layout with + // IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT) +struct ImFont; // Runtime data for a single font within a parent ImFontAtlas +struct ImFontAtlas; // Runtime data for multiple fonts, bake multiple fonts into a single texture, TTF/OTF font loader +struct ImFontAtlasBuilder; // Opaque storage for building a ImFontAtlas +struct ImFontAtlasRect; // Output of ImFontAtlas::GetCustomRect() when using custom rectangles. +struct ImFontBaked; // Baked data for a ImFont at a given size. +struct ImFontConfig; // Configuration data when adding a font or merging fonts +struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset) +struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data +struct ImFontLoader; // Opaque interface to a font loading backend (stb_truetype, FreeType etc.). +struct ImTextureData; // Specs and pixel storage for a texture used by Dear ImGui. +struct ImTextureRect; // Coordinates of a rectangle within a texture. +struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please + // avoid using) // Forward declarations: ImGui layer -struct ImGuiContext; // Dear ImGui context (opaque structure, unless including imgui_internal.h) -struct ImGuiIO; // Main configuration and I/O between your application and ImGui (also see: ImGuiPlatformIO) -struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use) -struct ImGuiKeyData; // Storage for ImGuiIO and IsKeyDown(), IsKeyPressed() etc functions. -struct ImGuiListClipper; // Helper to manually clip large list of items -struct ImGuiMultiSelectIO; // Structure to interact with a BeginMultiSelect()/EndMultiSelect() block -struct ImGuiOnceUponAFrame; // Helper for running a block of code not more than once a frame -struct ImGuiPayload; // User data payload for drag and drop operations -struct ImGuiPlatformIO; // Interface between platform/renderer backends and ImGui (e.g. Clipboard, IME hooks). Extends ImGuiIO. In docking branch, this gets extended to support multi-viewports. -struct ImGuiPlatformImeData; // Platform IME data for io.PlatformSetImeDataFn() function. -struct ImGuiSelectionBasicStorage; // Optional helper to store multi-selection state + apply multi-selection requests. -struct ImGuiSelectionExternalStorage;//Optional helper to apply multi-selection requests to existing randomly accessible storage. -struct ImGuiSelectionRequest; // A selection request (stored in ImGuiMultiSelectIO) -struct ImGuiSizeCallbackData; // Callback data when using SetNextWindowSizeConstraints() (rare/advanced use) -struct ImGuiStorage; // Helper for key->value storage (container sorted by key) -struct ImGuiStoragePair; // Helper for key->value storage (pair) -struct ImGuiStyle; // Runtime data for styling/colors -struct ImGuiTableSortSpecs; // Sorting specifications for a table (often handling sort specs for a single column, occasionally more) -struct ImGuiTableColumnSortSpecs; // Sorting specification for one column of a table -struct ImGuiTextBuffer; // Helper to hold and append into a text buffer (~string builder) -struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbbb][,ccccc]") -struct ImGuiViewport; // A Platform Window (always only one in 'master' branch), in the future may represent Platform Monitor +struct ImGuiContext; // Dear ImGui context (opaque structure, unless including imgui_internal.h) +struct ImGuiIO; // Main configuration and I/O between your application and ImGui (also see: ImGuiPlatformIO) +struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback + // (rare/advanced use) +struct ImGuiKeyData; // Storage for ImGuiIO and IsKeyDown(), IsKeyPressed() etc functions. +struct ImGuiListClipper; // Helper to manually clip large list of items +struct ImGuiMultiSelectIO; // Structure to interact with a BeginMultiSelect()/EndMultiSelect() block +struct ImGuiOnceUponAFrame; // Helper for running a block of code not more than once a frame +struct ImGuiPayload; // User data payload for drag and drop operations +struct ImGuiPlatformIO; // Interface between platform/renderer backends and ImGui (e.g. Clipboard, IME hooks). Extends + // ImGuiIO. In docking branch, this gets extended to support multi-viewports. +struct ImGuiPlatformImeData; // Platform IME data for io.PlatformSetImeDataFn() function. +struct ImGuiSelectionBasicStorage; // Optional helper to store multi-selection state + apply multi-selection requests. +struct ImGuiSelectionExternalStorage; // Optional helper to apply multi-selection requests to existing randomly + // accessible storage. +struct ImGuiSelectionRequest; // A selection request (stored in ImGuiMultiSelectIO) +struct ImGuiSizeCallbackData; // Callback data when using SetNextWindowSizeConstraints() (rare/advanced use) +struct ImGuiStorage; // Helper for key->value storage (container sorted by key) +struct ImGuiStoragePair; // Helper for key->value storage (pair) +struct ImGuiStyle; // Runtime data for styling/colors +struct ImGuiTableSortSpecs; // Sorting specifications for a table (often handling sort specs for a single column, + // occasionally more) +struct ImGuiTableColumnSortSpecs; // Sorting specification for one column of a table +struct ImGuiTextBuffer; // Helper to hold and append into a text buffer (~string builder) +struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbbb][,ccccc]") +struct ImGuiViewport; // A Platform Window (always only one in 'master' branch), in the future may represent Platform + // Monitor // Enumerations -// - We don't use strongly typed enums much because they add constraints (can't extend in private code, can't store typed in bit fields, extra casting on iteration) -// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists! -// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. -// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments. +// - We don't use strongly typed enums much because they add constraints (can't extend in private code, can't store +// typed in bit fields, extra casting on iteration) +// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual +// flags/enum lists! +// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 +// ("Edit.GoToImplementation") cannot. +// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside +// comments. // - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments. -enum ImGuiDir : int; // -> enum ImGuiDir // Enum: A cardinal direction (Left, Right, Up, Down) -enum ImGuiKey : int; // -> enum ImGuiKey // Enum: A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value) -enum ImGuiMouseSource : int; // -> enum ImGuiMouseSource // Enum; A mouse input source identifier (Mouse, TouchScreen, Pen) -enum ImGuiSortDirection : ImU8; // -> enum ImGuiSortDirection // Enum: A sorting direction (ascending or descending) -typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling -typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for many Set*() functions -typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type -typedef int ImGuiMouseButton; // -> enum ImGuiMouseButton_ // Enum: A mouse button identifier (0=left, 1=right, 2=middle) -typedef int ImGuiMouseCursor; // -> enum ImGuiMouseCursor_ // Enum: A mouse cursor shape -typedef int ImGuiStyleVar; // -> enum ImGuiStyleVar_ // Enum: A variable identifier for styling -typedef int ImGuiTableBgTarget; // -> enum ImGuiTableBgTarget_ // Enum: A color target for TableSetBgColor() +enum ImGuiDir : int; // -> enum ImGuiDir // Enum: A cardinal direction (Left, Right, Up, Down) +enum ImGuiKey : int; // -> enum ImGuiKey // Enum: A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value) +enum ImGuiMouseSource : int; // -> enum ImGuiMouseSource // Enum; A mouse input source identifier (Mouse, + // TouchScreen, Pen) +enum ImGuiSortDirection : ImU8; // -> enum ImGuiSortDirection // Enum: A sorting direction (ascending or descending) +typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling +typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for many Set*() functions +typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type +typedef int + ImGuiMouseButton; // -> enum ImGuiMouseButton_ // Enum: A mouse button identifier (0=left, 1=right, 2=middle) +typedef int ImGuiMouseCursor; // -> enum ImGuiMouseCursor_ // Enum: A mouse cursor shape +typedef int ImGuiStyleVar; // -> enum ImGuiStyleVar_ // Enum: A variable identifier for styling +typedef int ImGuiTableBgTarget; // -> enum ImGuiTableBgTarget_ // Enum: A color target for TableSetBgColor() // Flags (declared as int to allow using as flags without overhead, and to not pollute the top of this file) -// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists! -// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. -// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments. +// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual +// flags/enum lists! +// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 +// ("Edit.GoToImplementation") cannot. +// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside +// comments. // - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments. -typedef int ImDrawFlags; // -> enum ImDrawFlags_ // Flags: for ImDrawList functions -typedef int ImDrawListFlags; // -> enum ImDrawListFlags_ // Flags: for ImDrawList instance -typedef int ImFontFlags; // -> enum ImFontFlags_ // Flags: for ImFont -typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: for ImFontAtlas -typedef int ImGuiBackendFlags; // -> enum ImGuiBackendFlags_ // Flags: for io.BackendFlags -typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for InvisibleButton() -typedef int ImGuiChildFlags; // -> enum ImGuiChildFlags_ // Flags: for BeginChild() -typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: for ColorEdit4(), ColorPicker4() etc. -typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags -typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo() -typedef int ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for BeginDragDropSource(), AcceptDragDropPayload() -typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: for IsWindowFocused() -typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc. -typedef int ImGuiInputFlags; // -> enum ImGuiInputFlags_ // Flags: for Shortcut(), SetNextItemShortcut() -typedef int ImGuiInputTextFlags; // -> enum ImGuiInputTextFlags_ // Flags: for InputText(), InputTextMultiline() -typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag(), shared by all items -typedef int ImGuiKeyChord; // -> ImGuiKey | ImGuiMod_XXX // Flags: for IsKeyChordPressed(), Shortcut() etc. an ImGuiKey optionally OR-ed with one or more ImGuiMod_XXX values. -typedef int ImGuiPopupFlags; // -> enum ImGuiPopupFlags_ // Flags: for OpenPopup*(), BeginPopupContext*(), IsPopupOpen() -typedef int ImGuiMultiSelectFlags; // -> enum ImGuiMultiSelectFlags_// Flags: for BeginMultiSelect() -typedef int ImGuiSelectableFlags; // -> enum ImGuiSelectableFlags_ // Flags: for Selectable() -typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc. -typedef int ImGuiTabBarFlags; // -> enum ImGuiTabBarFlags_ // Flags: for BeginTabBar() -typedef int ImGuiTabItemFlags; // -> enum ImGuiTabItemFlags_ // Flags: for BeginTabItem() -typedef int ImGuiTableFlags; // -> enum ImGuiTableFlags_ // Flags: For BeginTable() -typedef int ImGuiTableColumnFlags; // -> enum ImGuiTableColumnFlags_// Flags: For TableSetupColumn() -typedef int ImGuiTableRowFlags; // -> enum ImGuiTableRowFlags_ // Flags: For TableNextRow() -typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: for TreeNode(), TreeNodeEx(), CollapsingHeader() -typedef int ImGuiViewportFlags; // -> enum ImGuiViewportFlags_ // Flags: for ImGuiViewport -typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin(), BeginChild() +typedef int ImDrawFlags; // -> enum ImDrawFlags_ // Flags: for ImDrawList functions +typedef int ImDrawListFlags; // -> enum ImDrawListFlags_ // Flags: for ImDrawList instance +typedef int ImFontFlags; // -> enum ImFontFlags_ // Flags: for ImFont +typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: for ImFontAtlas +typedef int ImGuiBackendFlags; // -> enum ImGuiBackendFlags_ // Flags: for io.BackendFlags +typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for InvisibleButton() +typedef int ImGuiChildFlags; // -> enum ImGuiChildFlags_ // Flags: for BeginChild() +typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: for ColorEdit4(), ColorPicker4() etc. +typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags +typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo() +typedef int + ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for BeginDragDropSource(), AcceptDragDropPayload() +typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: for IsWindowFocused() +typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc. +typedef int ImGuiInputFlags; // -> enum ImGuiInputFlags_ // Flags: for Shortcut(), SetNextItemShortcut() +typedef int ImGuiInputTextFlags; // -> enum ImGuiInputTextFlags_ // Flags: for InputText(), InputTextMultiline() +typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag(), shared by all items +typedef int ImGuiKeyChord; // -> ImGuiKey | ImGuiMod_XXX // Flags: for IsKeyChordPressed(), Shortcut() etc. an + // ImGuiKey optionally OR-ed with one or more ImGuiMod_XXX values. +typedef int + ImGuiPopupFlags; // -> enum ImGuiPopupFlags_ // Flags: for OpenPopup*(), BeginPopupContext*(), IsPopupOpen() +typedef int ImGuiMultiSelectFlags; // -> enum ImGuiMultiSelectFlags_// Flags: for BeginMultiSelect() +typedef int ImGuiSelectableFlags; // -> enum ImGuiSelectableFlags_ // Flags: for Selectable() +typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for DragFloat(), DragInt(), SliderFloat(), + // SliderInt() etc. +typedef int ImGuiTabBarFlags; // -> enum ImGuiTabBarFlags_ // Flags: for BeginTabBar() +typedef int ImGuiTabItemFlags; // -> enum ImGuiTabItemFlags_ // Flags: for BeginTabItem() +typedef int ImGuiTableFlags; // -> enum ImGuiTableFlags_ // Flags: For BeginTable() +typedef int ImGuiTableColumnFlags; // -> enum ImGuiTableColumnFlags_// Flags: For TableSetupColumn() +typedef int ImGuiTableRowFlags; // -> enum ImGuiTableRowFlags_ // Flags: For TableNextRow() +typedef int + ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: for TreeNode(), TreeNodeEx(), CollapsingHeader() +typedef int ImGuiViewportFlags; // -> enum ImGuiViewportFlags_ // Flags: for ImGuiViewport +typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin(), BeginChild() // 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) -typedef unsigned int ImWchar32; // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings. -typedef unsigned short ImWchar16; // A single decoded U16 character/code point. We encode them as multi bytes UTF-8 when used in strings. -#ifdef IMGUI_USE_WCHAR32 // ImWchar [configurable type: override in imconfig.h with '#define IMGUI_USE_WCHAR32' to support Unicode planes 1-16] +// (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for +// keyboard input and display) +typedef unsigned int + ImWchar32; // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings. +typedef unsigned short + ImWchar16; // A single decoded U16 character/code point. We encode them as multi bytes UTF-8 when used in strings. +#ifdef IMGUI_USE_WCHAR32 // ImWchar [configurable type: override in imconfig.h with '#define IMGUI_USE_WCHAR32' to + // support Unicode planes 1-16] typedef ImWchar32 ImWchar; #else typedef ImWchar16 ImWchar; @@ -271,39 +328,61 @@ typedef ImWchar16 ImWchar; // Multi-Selection item index or identifier when using BeginMultiSelect() // - Used by SetNextItemSelectionUserData() + and inside ImGuiMultiSelectIO structure. -// - Most users are likely to use this store an item INDEX but this may be used to store a POINTER/ID as well. Read comments near ImGuiMultiSelectIO for details. +// - Most users are likely to use this store an item INDEX but this may be used to store a POINTER/ID as well. Read +// comments near ImGuiMultiSelectIO for details. typedef ImS64 ImGuiSelectionUserData; // Callback and functions types -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() +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() // ImVec2: 2D vector used to store positions, sizes etc. [Compile-time configurable type] -// - This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our preferred type. -// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths operators for ImVec2 and ImVec4. +// - This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our +// preferred type. +// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths +// operators for ImVec2 and ImVec4. IM_MSVC_RUNTIME_CHECKS_OFF struct ImVec2 { - float x, y; - constexpr ImVec2() : x(0.0f), y(0.0f) { } - constexpr ImVec2(float _x, float _y) : x(_x), y(_y) { } - float& operator[] (size_t idx) { IM_ASSERT(idx == 0 || idx == 1); return ((float*)(void*)(char*)this)[idx]; } // We very rarely use this [] operator, so the assert overhead is fine. - float operator[] (size_t idx) const { IM_ASSERT(idx == 0 || idx == 1); return ((const float*)(const void*)(const char*)this)[idx]; } + float x, y; + constexpr ImVec2() : x(0.0f), y(0.0f) + { + } + constexpr ImVec2(float _x, float _y) : x(_x), y(_y) + { + } + float &operator[](size_t idx) + { + IM_ASSERT(idx == 0 || idx == 1); + return ((float *)(void *)(char *)this)[idx]; + } // We very rarely use this [] operator, so the assert overhead is fine. + float operator[](size_t idx) const + { + IM_ASSERT(idx == 0 || idx == 1); + return ((const float *)(const void *)(const char *)this)[idx]; + } #ifdef IM_VEC2_CLASS_EXTRA - IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. + IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and + // forth between your math types and ImVec2. #endif }; // ImVec4: 4D vector used to store clipping rectangles, colors etc. [Compile-time configurable type] struct ImVec4 { - float x, y, z, w; - constexpr ImVec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) { } - constexpr ImVec4(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) { } + float x, y, z, w; + constexpr ImVec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) + { + } + constexpr ImVec4(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) + { + } #ifdef IM_VEC4_CLASS_EXTRA - 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. + 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 @@ -326,15 +405,19 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE // - You may decide to store a higher-level structure containing texture, sampler, shader etc. with various // constructors if you like. You will need to implement ==/!= operators. // History: -// - In v1.91.4 (2024/10/08): the default type for ImTextureID was changed from 'void*' to 'ImU64'. This allowed backends requirig 64-bit worth of data to build on 32-bit architectures. Use intermediary intptr_t cast and read FAQ if you have casting warnings. -// - In v1.92.0 (2025/XX/XX): added ImTextureRef which carry either a ImTextureID either a pointer to internal texture atlas. All user facing functions taking ImTextureID changed to ImTextureRef +// - In v1.91.4 (2024/10/08): the default type for ImTextureID was changed from 'void*' to 'ImU64'. This allowed +// backends requirig 64-bit worth of data to build on 32-bit architectures. Use intermediary intptr_t cast and read FAQ +// if you have casting warnings. +// - In v1.92.0 (2025/XX/XX): added ImTextureRef which carry either a ImTextureID either a pointer to internal texture +// atlas. All user facing functions taking ImTextureID changed to ImTextureRef #ifndef ImTextureID -typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or integer). A majority of backends are ok with that. +typedef ImU64 + ImTextureID; // Default: store up to 64-bits (any pointer or integer). A majority of backends are ok with that. #endif // Define this if you need 0 to be a valid ImTextureID for your backend. #ifndef ImTextureID_Invalid -#define ImTextureID_Invalid ((ImTextureID)0) +#define ImTextureID_Invalid ((ImTextureID)0) #endif // ImTextureRef = higher-level identifier for a texture. @@ -348,785 +431,1290 @@ typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or // to be useful to the end-user, and it would be erroneously called by many legacy code. // - If you want to bind the current atlas when using custom rectangle, you can use io.Fonts->TexRef. // - Binding generators for languages such as C (which don't have constructors), should provide a helper, e.g. -// inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = NULL, .TexID = tex_id }; return tex_ref; } +// inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = NULL, .TexID = +// tex_id }; return tex_ref; } // In 1.92 we changed most drawing functions using ImTextureID to use ImTextureRef. -// We intentionally do not provide an implicit ImTextureRef -> ImTextureID cast operator because it is technically lossy to convert ImTextureRef to ImTextureID before rendering. +// We intentionally do not provide an implicit ImTextureRef -> ImTextureID cast operator because it is technically lossy +// to convert ImTextureRef to ImTextureID before rendering. IM_MSVC_RUNTIME_CHECKS_OFF struct ImTextureRef { - ImTextureRef() { _TexData = NULL; _TexID = ImTextureID_Invalid; } - ImTextureRef(ImTextureID tex_id) { _TexData = NULL; _TexID = tex_id; } + ImTextureRef() + { + _TexData = NULL; + _TexID = ImTextureID_Invalid; + } + ImTextureRef(ImTextureID tex_id) + { + _TexData = NULL; + _TexID = tex_id; + } #if !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && !defined(ImTextureID) - ImTextureRef(void* tex_id) { _TexData = NULL; _TexID = (ImTextureID)(size_t)tex_id; } // For legacy backends casting to ImTextureID + ImTextureRef(void *tex_id) + { + _TexData = NULL; + _TexID = (ImTextureID)(size_t)tex_id; + } // For legacy backends casting to ImTextureID #endif - inline ImTextureID GetTexID() const; // == (_TexData ? _TexData->TexID : _TexID) // Implemented below in the file. + inline ImTextureID GetTexID() const; // == (_TexData ? _TexData->TexID : _TexID) // Implemented below in the file. // Members (either are set, never both!) - ImTextureData* _TexData; // A texture, generally owned by a ImFontAtlas. Will convert to ImTextureID during render loop, after texture has been uploaded. - ImTextureID _TexID; // _OR_ Low-level backend texture identifier, if already uploaded or created by user/app. Generally provided to e.g. ImGui::Image() calls. + ImTextureData *_TexData; // A texture, generally owned by a ImFontAtlas. Will convert to ImTextureID during + // render loop, after texture has been uploaded. + ImTextureID _TexID; // _OR_ Low-level backend texture identifier, if already uploaded or created by user/app. + // Generally provided to e.g. ImGui::Image() calls. }; IM_MSVC_RUNTIME_CHECKS_RESTORE //----------------------------------------------------------------------------- // [SECTION] Dear ImGui end-user API functions -// (Note that ImGui:: being a namespace, you can add extra ImGui:: functions in your own separate file. Please don't modify imgui source files!) +// (Note that ImGui:: being a namespace, you can add extra ImGui:: functions in your own separate file. Please don't +// modify imgui source files!) //----------------------------------------------------------------------------- namespace ImGui { - // Context creation and access - // - Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between 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(); - IMGUI_API void SetCurrentContext(ImGuiContext* ctx); +// 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 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(); +IMGUI_API void SetCurrentContext(ImGuiContext *ctx); - // Main - IMGUI_API ImGuiIO& GetIO(); // access the ImGuiIO structure (mouse/keyboard/gamepad inputs, time, various configuration options/flags) - IMGUI_API ImGuiPlatformIO& GetPlatformIO(); // access the ImGuiPlatformIO structure (mostly hooks/functions to connect to platform/renderer and OS Clipboard, IME etc.) - IMGUI_API ImGuiStyle& GetStyle(); // access the Style structure (colors, sizes). Always use PushStyleColor(), PushStyleVar() to modify style mid-frame! - IMGUI_API void NewFrame(); // start a new Dear ImGui frame, you can submit any command from this point until Render()/EndFrame(). - IMGUI_API void EndFrame(); // ends the Dear ImGui frame. automatically called by Render(). If you don't need to render data (skipping rendering) you may call EndFrame() without Render()... but you'll have wasted CPU already! If you don't need to render, better to not create any windows and not call NewFrame() at all! - IMGUI_API void Render(); // ends the Dear ImGui frame, finalize the draw data. You can then get call GetDrawData(). - IMGUI_API ImDrawData* GetDrawData(); // valid after Render() and until the next call to NewFrame(). Call ImGui_ImplXXXX_RenderDrawData() function in your Renderer Backend to render. +// Main +IMGUI_API ImGuiIO &GetIO(); // access the ImGuiIO structure (mouse/keyboard/gamepad inputs, time, various configuration + // options/flags) +IMGUI_API ImGuiPlatformIO &GetPlatformIO(); // access the ImGuiPlatformIO structure (mostly hooks/functions to connect + // to platform/renderer and OS Clipboard, IME etc.) +IMGUI_API ImGuiStyle &GetStyle(); // access the Style structure (colors, sizes). Always use PushStyleColor(), + // PushStyleVar() to modify style mid-frame! +IMGUI_API void NewFrame(); // start a new Dear ImGui frame, you can submit any command from this point until + // Render()/EndFrame(). +IMGUI_API void EndFrame(); // ends the Dear ImGui frame. automatically called by Render(). If you don't need to render + // data (skipping rendering) you may call EndFrame() without Render()... but you'll have + // wasted CPU already! If you don't need to render, better to not create any windows and not + // call NewFrame() at all! +IMGUI_API void Render(); // ends the Dear ImGui frame, finalize the draw data. You can then get call GetDrawData(). +IMGUI_API ImDrawData *GetDrawData(); // valid after Render() and until the next call to NewFrame(). Call + // ImGui_ImplXXXX_RenderDrawData() function in your Renderer Backend to render. - // Demo, Debug, Information - IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create Demo window. demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application! - IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // create Metrics/Debugger window. display Dear ImGui internals: windows, draw commands, various internal state, etc. - IMGUI_API void ShowDebugLogWindow(bool* p_open = NULL); // create Debug Log window. display a simplified log of important dear imgui events. - IMGUI_API void ShowIDStackToolWindow(bool* p_open = NULL); // create Stack Tool window. hover items with mouse to query information about the source of their unique ID. - IMGUI_API void ShowAboutWindow(bool* p_open = NULL); // create About window. display Dear ImGui version, credits and build/system information. - IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style) - IMGUI_API bool ShowStyleSelector(const char* label); // add style selector block (not a window), essentially a combo listing the default styles. - IMGUI_API void ShowFontSelector(const char* label); // add font selector block (not a window), essentially a combo listing the loaded fonts. - IMGUI_API void ShowUserGuide(); // add basic help/info block (not a window): how to manipulate ImGui as an end-user (mouse/keyboard controls). - IMGUI_API const char* GetVersion(); // get the compiled version string e.g. "1.80 WIP" (essentially the value for IMGUI_VERSION from the compiled version of imgui.cpp) +// Demo, Debug, Information +IMGUI_API void ShowDemoWindow( + bool *p_open = NULL); // create Demo window. demonstrate most ImGui features. call this to learn about the library! + // try to make it always available in your application! +IMGUI_API void ShowMetricsWindow(bool *p_open = NULL); // create Metrics/Debugger window. display Dear ImGui internals: + // windows, draw commands, various internal state, etc. +IMGUI_API void ShowDebugLogWindow( + bool *p_open = NULL); // create Debug Log window. display a simplified log of important dear imgui events. +IMGUI_API void ShowIDStackToolWindow(bool *p_open = NULL); // create Stack Tool window. hover items with mouse to query + // information about the source of their unique ID. +IMGUI_API void ShowAboutWindow( + bool *p_open = NULL); // create About window. display Dear ImGui version, credits and build/system information. +IMGUI_API void ShowStyleEditor( + ImGuiStyle *ref = NULL); // add style editor block (not a window). you can pass in a reference ImGuiStyle structure + // to compare to, revert to and save to (else it uses the default style) +IMGUI_API bool ShowStyleSelector( + const char *label); // add style selector block (not a window), essentially a combo listing the default styles. +IMGUI_API void ShowFontSelector( + const char *label); // add font selector block (not a window), essentially a combo listing the loaded fonts. +IMGUI_API void ShowUserGuide(); // add basic help/info block (not a window): how to manipulate ImGui as an end-user + // (mouse/keyboard controls). +IMGUI_API const char *GetVersion(); // get the compiled version string e.g. "1.80 WIP" (essentially the value for + // IMGUI_VERSION from the compiled version of imgui.cpp) - // Styles - IMGUI_API void StyleColorsDark(ImGuiStyle* dst = NULL); // new, recommended style (default) - IMGUI_API void StyleColorsLight(ImGuiStyle* dst = NULL); // best used with borders and a custom, thicker font - IMGUI_API void StyleColorsClassic(ImGuiStyle* dst = NULL); // classic imgui style +// Styles +IMGUI_API void StyleColorsDark(ImGuiStyle *dst = NULL); // new, recommended style (default) +IMGUI_API void StyleColorsLight(ImGuiStyle *dst = NULL); // best used with borders and a custom, thicker font +IMGUI_API void StyleColorsClassic(ImGuiStyle *dst = NULL); // classic imgui style - // Windows - // - Begin() = push window to the stack and start appending to it. End() = pop window from the stack. - // - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window, - // which clicking will set the boolean to false when clicked. - // - You may append multiple times to the same window during the same frame by calling Begin()/End() pairs multiple times. - // Some information such as 'flags' or 'p_open' will only be considered by the first call to Begin(). - // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting - // anything to the window. Always call a matching End() for each Begin() call, regardless of its return value! - // [Important: due to legacy reason, Begin/End and BeginChild/EndChild are inconsistent with all other functions - // such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding - // BeginXXX function returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] - // - Note that the bottom of window stack always contains a window called "Debug". - IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); - IMGUI_API void End(); +// Windows +// - Begin() = push window to the stack and start appending to it. End() = pop window from the stack. +// - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window, +// which clicking will set the boolean to false when clicked. +// - You may append multiple times to the same window during the same frame by calling Begin()/End() pairs multiple +// times. +// Some information such as 'flags' or 'p_open' will only be considered by the first call to Begin(). +// - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting +// anything to the window. Always call a matching End() for each Begin() call, regardless of its return value! +// [Important: due to legacy reason, Begin/End and BeginChild/EndChild are inconsistent with all other functions +// such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the +// corresponding BeginXXX function returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a +// future update.] +// - Note that the bottom of window stack always contains a window called "Debug". +IMGUI_API bool Begin(const char *name, bool *p_open = NULL, ImGuiWindowFlags flags = 0); +IMGUI_API void End(); - // Child Windows - // - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child. - // - Before 1.90 (November 2023), the "ImGuiChildFlags child_flags = 0" parameter was "bool border = false". - // This API is backward compatible with old code, as we guarantee that ImGuiChildFlags_Borders == true. - // Consider updating your old code: - // BeginChild("Name", size, false) -> Begin("Name", size, 0); or Begin("Name", size, ImGuiChildFlags_None); - // BeginChild("Name", size, true) -> Begin("Name", size, ImGuiChildFlags_Borders); - // - Manual sizing (each axis can use a different setting e.g. ImVec2(0.0f, 400.0f)): - // == 0.0f: use remaining parent window size for this axis. - // > 0.0f: use specified size for this axis. - // < 0.0f: right/bottom-align to specified distance from available content boundaries. - // - Specifying ImGuiChildFlags_AutoResizeX or ImGuiChildFlags_AutoResizeY makes the sizing automatic based on child contents. - // Combining both ImGuiChildFlags_AutoResizeX _and_ ImGuiChildFlags_AutoResizeY defeats purpose of a scrolling region and is NOT recommended. - // - BeginChild() returns false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting - // anything to the window. Always call a matching EndChild() for each BeginChild() call, regardless of its return value. - // [Important: due to legacy reason, Begin/End and BeginChild/EndChild are inconsistent with all other functions - // such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding - // BeginXXX function returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] - IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0, 0), ImGuiChildFlags child_flags = 0, ImGuiWindowFlags window_flags = 0); - IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0, 0), ImGuiChildFlags child_flags = 0, ImGuiWindowFlags window_flags = 0); - IMGUI_API void EndChild(); +// Child Windows +// - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child +// windows can embed their own child. +// - Before 1.90 (November 2023), the "ImGuiChildFlags child_flags = 0" parameter was "bool border = false". +// This API is backward compatible with old code, as we guarantee that ImGuiChildFlags_Borders == true. +// Consider updating your old code: +// BeginChild("Name", size, false) -> Begin("Name", size, 0); or Begin("Name", size, ImGuiChildFlags_None); +// BeginChild("Name", size, true) -> Begin("Name", size, ImGuiChildFlags_Borders); +// - Manual sizing (each axis can use a different setting e.g. ImVec2(0.0f, 400.0f)): +// == 0.0f: use remaining parent window size for this axis. +// > 0.0f: use specified size for this axis. +// < 0.0f: right/bottom-align to specified distance from available content boundaries. +// - Specifying ImGuiChildFlags_AutoResizeX or ImGuiChildFlags_AutoResizeY makes the sizing automatic based on child +// contents. +// Combining both ImGuiChildFlags_AutoResizeX _and_ ImGuiChildFlags_AutoResizeY defeats purpose of a scrolling region +// and is NOT recommended. +// - BeginChild() returns false to indicate the window is collapsed or fully clipped, so you may early out and omit +// submitting +// anything to the window. Always call a matching EndChild() for each BeginChild() call, regardless of its return +// value. [Important: due to legacy reason, Begin/End and BeginChild/EndChild are inconsistent with all other +// functions +// such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the +// corresponding BeginXXX function returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a +// future update.] +IMGUI_API bool BeginChild(const char *str_id, const ImVec2 &size = ImVec2(0, 0), ImGuiChildFlags child_flags = 0, + ImGuiWindowFlags window_flags = 0); +IMGUI_API bool BeginChild(ImGuiID id, const ImVec2 &size = ImVec2(0, 0), ImGuiChildFlags child_flags = 0, + ImGuiWindowFlags window_flags = 0); +IMGUI_API void EndChild(); - // Windows Utilities - // - 'current window' = the window we are appending into while inside a Begin()/End() block. 'next window' = next window we will Begin() into. - IMGUI_API bool IsWindowAppearing(); - IMGUI_API bool IsWindowCollapsed(); - IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options. - IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered and hoverable (e.g. not blocked by a popup/modal)? See ImGuiHoveredFlags_ for options. IMPORTANT: If you are trying to check whether your mouse should be dispatched to Dear ImGui or to your underlying app, you should not use this function! Use the 'io.WantCaptureMouse' boolean for that! Refer to FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" for details. - IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives - IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (IT IS UNLIKELY YOU EVER NEED TO USE THIS. Consider always using GetCursorScreenPos() and GetContentRegionAvail() instead) - IMGUI_API ImVec2 GetWindowSize(); // get current window size (IT IS UNLIKELY YOU EVER NEED TO USE THIS. Consider always using GetCursorScreenPos() and GetContentRegionAvail() instead) - IMGUI_API float GetWindowWidth(); // get current window width (IT IS UNLIKELY YOU EVER NEED TO USE THIS). Shortcut for GetWindowSize().x. - IMGUI_API float GetWindowHeight(); // get current window height (IT IS UNLIKELY YOU EVER NEED TO USE THIS). Shortcut for GetWindowSize().y. +// Windows Utilities +// - 'current window' = the window we are appending into while inside a Begin()/End() block. 'next window' = next window +// we will Begin() into. +IMGUI_API bool IsWindowAppearing(); +IMGUI_API bool IsWindowCollapsed(); +IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags = 0); // is current window focused? or its root/child, depending + // on flags. see flags for options. +IMGUI_API bool IsWindowHovered( + ImGuiHoveredFlags flags = + 0); // is current window hovered and hoverable (e.g. not blocked by a popup/modal)? See ImGuiHoveredFlags_ for + // options. IMPORTANT: If you are trying to check whether your mouse should be dispatched to Dear ImGui or + // to your underlying app, you should not use this function! Use the 'io.WantCaptureMouse' boolean for that! + // Refer to FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" + // for details. +IMGUI_API ImDrawList *GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing + // primitives +IMGUI_API ImVec2 +GetWindowPos(); // get current window position in screen space (IT IS UNLIKELY YOU EVER NEED TO USE THIS. Consider + // always using GetCursorScreenPos() and GetContentRegionAvail() instead) +IMGUI_API ImVec2 GetWindowSize(); // get current window size (IT IS UNLIKELY YOU EVER NEED TO USE THIS. Consider always + // using GetCursorScreenPos() and GetContentRegionAvail() instead) +IMGUI_API float GetWindowWidth(); // get current window width (IT IS UNLIKELY YOU EVER NEED TO USE THIS). Shortcut for + // GetWindowSize().x. +IMGUI_API float GetWindowHeight(); // get current window height (IT IS UNLIKELY YOU EVER NEED TO USE THIS). Shortcut for + // GetWindowSize().y. - // Window manipulation - // - Prefer using SetNextXXX functions (before Begin) rather that SetXXX functions (after Begin). - IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0, 0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc. - IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin() - IMGUI_API void SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use 0.0f or FLT_MAX if you don't want limits. Use -1 for both min and max of same axis to preserve current size (which itself is a constraint). Use callback to apply non-trivial programmatic constraints. - IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (~ scrollable client area, which enforce the range of scrollbars). Not including window decorations (title bar, menu bar, etc.) nor WindowPadding. set an axis to 0.0f to leave it automatic. call before Begin() - IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // set next window collapsed state. call before Begin() - IMGUI_API void SetNextWindowFocus(); // set next window to be focused / top-most. call before Begin() - IMGUI_API void SetNextWindowScroll(const ImVec2& scroll); // set next window scrolling value (use < 0.0f to not affect a given axis). - IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily override the Alpha component of ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground. - IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects. - IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0, 0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects. - IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed(). - IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / top-most. prefer using SetNextWindowFocus(). - IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0); // set named window position. - IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis. - IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state - IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / top-most. use NULL to remove focus. +// Window manipulation +// - Prefer using SetNextXXX functions (before Begin) rather that SetXXX functions (after Begin). +IMGUI_API void SetNextWindowPos( + const ImVec2 &pos, ImGuiCond cond = 0, + const ImVec2 &pivot = ImVec2( + 0, 0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc. +IMGUI_API void SetNextWindowSize(const ImVec2 &size, + ImGuiCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on + // this axis. call before Begin() +IMGUI_API void SetNextWindowSizeConstraints( + const ImVec2 &size_min, const ImVec2 &size_max, ImGuiSizeCallback custom_callback = NULL, + void *custom_callback_data = + NULL); // set next window size limits. use 0.0f or FLT_MAX if you don't want limits. Use -1 for both min and max + // of same axis to preserve current size (which itself is a constraint). Use callback to apply + // non-trivial programmatic constraints. +IMGUI_API void SetNextWindowContentSize( + const ImVec2 &size); // set next window content size (~ scrollable client area, which enforce the range of + // scrollbars). Not including window decorations (title bar, menu bar, etc.) nor WindowPadding. + // set an axis to 0.0f to leave it automatic. call before Begin() +IMGUI_API void SetNextWindowCollapsed(bool collapsed, + ImGuiCond cond = 0); // set next window collapsed state. call before Begin() +IMGUI_API void SetNextWindowFocus(); // set next window to be focused / top-most. call before Begin() +IMGUI_API void SetNextWindowScroll( + const ImVec2 &scroll); // set next window scrolling value (use < 0.0f to not affect a given axis). +IMGUI_API void SetNextWindowBgAlpha( + float alpha); // set next window background color alpha. helper to easily override the Alpha component of + // ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground. +IMGUI_API void SetWindowPos( + const ImVec2 &pos, + ImGuiCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using + // SetNextWindowPos(), as this may incur tearing and side-effects. +IMGUI_API void SetWindowSize( + const ImVec2 &size, + ImGuiCond cond = + 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0, 0) to force an + // auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects. +IMGUI_API void SetWindowCollapsed( + bool collapsed, + ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed(). +IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / top-most. prefer using + // SetNextWindowFocus(). +IMGUI_API void SetWindowPos(const char *name, const ImVec2 &pos, ImGuiCond cond = 0); // set named window position. +IMGUI_API void SetWindowSize( + const char *name, const ImVec2 &size, + ImGuiCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis. +IMGUI_API void SetWindowCollapsed(const char *name, bool collapsed, + ImGuiCond cond = 0); // set named window collapsed state +IMGUI_API void SetWindowFocus(const char *name); // set named window to be focused / top-most. use NULL to remove focus. - // Windows Scrolling - // - Any change of Scroll will be applied at the beginning of next frame in the first call to Begin(). - // - You may instead use SetNextWindowScroll() prior to calling Begin() to avoid this delay, as an alternative to using SetScrollX()/SetScrollY(). - IMGUI_API float GetScrollX(); // get scrolling amount [0 .. GetScrollMaxX()] - IMGUI_API float GetScrollY(); // get scrolling amount [0 .. GetScrollMaxY()] - IMGUI_API void SetScrollX(float scroll_x); // set scrolling amount [0 .. GetScrollMaxX()] - IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0 .. GetScrollMaxY()] - IMGUI_API float GetScrollMaxX(); // get maximum scrolling amount ~~ ContentSize.x - WindowSize.x - DecorationsSize.x - IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount ~~ ContentSize.y - WindowSize.y - DecorationsSize.y - IMGUI_API void SetScrollHereX(float center_x_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_x_ratio=0.0: left, 0.5: center, 1.0: right. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. - IMGUI_API void SetScrollHereY(float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. - IMGUI_API void SetScrollFromPosX(float local_x, float center_x_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. - IMGUI_API void SetScrollFromPosY(float local_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. +// Windows Scrolling +// - Any change of Scroll will be applied at the beginning of next frame in the first call to Begin(). +// - You may instead use SetNextWindowScroll() prior to calling Begin() to avoid this delay, as an alternative to using +// SetScrollX()/SetScrollY(). +IMGUI_API float GetScrollX(); // get scrolling amount [0 .. GetScrollMaxX()] +IMGUI_API float GetScrollY(); // get scrolling amount [0 .. GetScrollMaxY()] +IMGUI_API void SetScrollX(float scroll_x); // set scrolling amount [0 .. GetScrollMaxX()] +IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0 .. GetScrollMaxY()] +IMGUI_API float GetScrollMaxX(); // get maximum scrolling amount ~~ ContentSize.x - WindowSize.x - DecorationsSize.x +IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount ~~ ContentSize.y - WindowSize.y - DecorationsSize.y +IMGUI_API void SetScrollHereX( + float center_x_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. + // center_x_ratio=0.0: left, 0.5: center, 1.0: right. When using to make a + // "default/current item" visible, consider using SetItemDefaultFocus() instead. +IMGUI_API void SetScrollHereY( + float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. + // center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a + // "default/current item" visible, consider using SetItemDefaultFocus() instead. +IMGUI_API void SetScrollFromPosX( + float local_x, float center_x_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally + // GetCursorStartPos() + offset to compute a valid position. +IMGUI_API void SetScrollFromPosY( + float local_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally + // GetCursorStartPos() + offset to compute a valid position. - // Parameters stacks (font) - // *IMPORTANT* before 1.92, fonts had a single size. They can now be dynamically be adjusted. - // - Before 1.92: PushFont() always used font default size. - // - Since 1.92: PushFont() preserve the current shared font size. - // - To use old behavior (single size font, size specified in AddFontXXX() call: - // - Use 'PushFont(font, font->LegacySize)' at call site - // - Or set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' before calling AddFont(), and then 'PushFont(font)' will use this size. - // - External scale factors are applied over the provided value. - // *IMPORTANT* If you want to scale an existing font size: - // - OK: PushFontSize(style.FontSizeBase * factor) (= value before external scale factors applied). - // - KO: PushFontSize(GetFontSize() * factor) (= value after external scale factors applied. external scale factors are style.FontScaleMain + per-viewport scales.). - IMGUI_API void PushFont(ImFont* font, float font_size_base = -1); // use NULL as a shortcut to push default font. Use <0.0f to keep current font size. - IMGUI_API void PopFont(); - IMGUI_API void PushFontSize(float font_size_base); - IMGUI_API void PopFontSize(); +// Parameters stacks (font) +// *IMPORTANT* before 1.92, fonts had a single size. They can now be dynamically be adjusted. +// - Before 1.92: PushFont() always used font default size. +// - Since 1.92: PushFont() preserve the current shared font size. +// - To use old behavior (single size font, size specified in AddFontXXX() call: +// - Use 'PushFont(font, font->LegacySize)' at call site +// - Or set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' before calling AddFont(), and then +// 'PushFont(font)' will use this size. +// - External scale factors are applied over the provided value. +// *IMPORTANT* If you want to scale an existing font size: +// - OK: PushFontSize(style.FontSizeBase * factor) (= value before external scale factors applied). +// - KO: PushFontSize(GetFontSize() * factor) (= value after external scale factors applied. external scale +// factors are style.FontScaleMain + per-viewport scales.). +IMGUI_API void PushFont( + ImFont *font, + float font_size_base = -1); // use NULL as a shortcut to push default font. Use <0.0f to keep current font size. +IMGUI_API void PopFont(); +IMGUI_API void PushFontSize(float font_size_base); +IMGUI_API void PopFontSize(); - // Parameters stacks (shared) - IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col); // modify a style color. always use this if you modify the style after NewFrame(). - IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col); - IMGUI_API void PopStyleColor(int count = 1); - 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. " - IMGUI_API void PushStyleVarX(ImGuiStyleVar idx, float val_x); // modify X component of a style ImVec2 variable. " - IMGUI_API void PushStyleVarY(ImGuiStyleVar idx, float val_y); // modify Y component of a style ImVec2 variable. " - IMGUI_API void PopStyleVar(int count = 1); - IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); // modify specified shared item flag, e.g. PushItemFlag(ImGuiItemFlags_NoTabStop, true) - IMGUI_API void PopItemFlag(); +// Parameters stacks (shared) +IMGUI_API void PushStyleColor( + ImGuiCol idx, ImU32 col); // modify a style color. always use this if you modify the style after NewFrame(). +IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4 &col); +IMGUI_API void PopStyleColor(int count = 1); +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. " +IMGUI_API void PushStyleVarX(ImGuiStyleVar idx, float val_x); // modify X component of a style ImVec2 variable. " +IMGUI_API void PushStyleVarY(ImGuiStyleVar idx, float val_y); // modify Y component of a style ImVec2 variable. " +IMGUI_API void PopStyleVar(int count = 1); +IMGUI_API void PushItemFlag( + ImGuiItemFlags option, + bool enabled); // modify specified shared item flag, e.g. PushItemFlag(ImGuiItemFlags_NoTabStop, true) +IMGUI_API void PopItemFlag(); - // Parameters stacks (current window) - IMGUI_API void PushItemWidth(float item_width); // push width of items for common large "item+label" widgets. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -FLT_MIN always align width to the right side). - IMGUI_API void PopItemWidth(); - IMGUI_API void SetNextItemWidth(float item_width); // set width of the _next_ common large "item+label" widget. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -FLT_MIN always align width to the right side) - IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position. NOT necessarily the width of last item unlike most 'Item' functions. - IMGUI_API void PushTextWrapPos(float wrap_local_pos_x = 0.0f); // push word-wrapping position for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space - IMGUI_API void PopTextWrapPos(); +// Parameters stacks (current window) +IMGUI_API void PushItemWidth( + float item_width); // push width of items for common large "item+label" widgets. >0.0f: width in pixels, <0.0f align + // xx pixels to the right of window (so -FLT_MIN always align width to the right side). +IMGUI_API void PopItemWidth(); +IMGUI_API void SetNextItemWidth( + float item_width); // set width of the _next_ common large "item+label" widget. >0.0f: width in pixels, <0.0f align + // xx pixels to the right of window (so -FLT_MIN always align width to the right side) +IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position. NOT necessarily the + // width of last item unlike most 'Item' functions. +IMGUI_API void PushTextWrapPos( + float wrap_local_pos_x = + 0.0f); // push word-wrapping position for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or + // column); > 0.0f: wrap at 'wrap_pos_x' position in window local space +IMGUI_API void PopTextWrapPos(); - // Style read access - // - Use the ShowStyleEditor() function to interactively see/edit the colors. - IMGUI_API ImFont* GetFont(); // get current font - IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with external scale factors applied. Use ImGui::GetStyle().FontSizeBase to get value before external scale factors. - IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a white pixel, useful to draw custom shapes via the ImDrawList API - IMGUI_API ImFontBaked* GetFontBaked(); // get current font bound at current size // == GetFont()->GetFontBaked(GetFontSize()) - IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier, packed as a 32-bit value suitable for ImDrawList - IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList - IMGUI_API ImU32 GetColorU32(ImU32 col, float alpha_mul = 1.0f); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList - IMGUI_API const ImVec4& GetStyleColorVec4(ImGuiCol idx); // retrieve style color as stored in ImGuiStyle structure. use to feed back into PushStyleColor(), otherwise use GetColorU32() to get style color with style alpha baked in. +// Style read access +// - Use the ShowStyleEditor() function to interactively see/edit the colors. +IMGUI_API ImFont *GetFont(); // get current font +IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with external scale factors + // applied. Use ImGui::GetStyle().FontSizeBase to get value before external scale + // factors. +IMGUI_API ImVec2 +GetFontTexUvWhitePixel(); // get UV coordinate for a white pixel, useful to draw custom shapes via the ImDrawList API +IMGUI_API ImFontBaked *GetFontBaked(); // get current font bound at current size // == + // GetFont()->GetFontBaked(GetFontSize()) +IMGUI_API ImU32 GetColorU32( + ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra + // alpha multiplier, packed as a 32-bit value suitable for ImDrawList +IMGUI_API ImU32 GetColorU32(const ImVec4 &col); // retrieve given color with style alpha applied, packed as a 32-bit + // value suitable for ImDrawList +IMGUI_API ImU32 GetColorU32(ImU32 col, float alpha_mul = 1.0f); // retrieve given color with style alpha applied, packed + // as a 32-bit value suitable for ImDrawList +IMGUI_API const ImVec4 &GetStyleColorVec4( + ImGuiCol idx); // retrieve style color as stored in ImGuiStyle structure. use to feed back into PushStyleColor(), + // otherwise use GetColorU32() to get style color with style alpha baked in. - // Layout cursor positioning - // - By "cursor" we mean the current output position. - // - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down. - // - You can call SameLine() between widgets to undo the last carriage return and output at the right of the preceding widget. - // - YOU CAN DO 99% OF WHAT YOU NEED WITH ONLY GetCursorScreenPos() and GetContentRegionAvail(). - // - Attention! We currently have inconsistencies between window-local and absolute positions we will aim to fix with future API: - // - Absolute coordinate: GetCursorScreenPos(), SetCursorScreenPos(), all ImDrawList:: functions. -> this is the preferred way forward. - // - Window-local coordinates: SameLine(offset), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), PushTextWrapPos() - // - Window-local coordinates: GetContentRegionMax(), GetWindowContentRegionMin(), GetWindowContentRegionMax() --> all obsoleted. YOU DON'T NEED THEM. - // - GetCursorScreenPos() = GetCursorPos() + GetWindowPos(). GetWindowPos() is almost only ever useful to convert from window-local to absolute coordinates. Try not to use it. - IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position, absolute coordinates. THIS IS YOUR BEST FRIEND (prefer using this rather than GetCursorPos(), also more useful to work with ImDrawList API). - IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position, absolute coordinates. THIS IS YOUR BEST FRIEND. - IMGUI_API ImVec2 GetContentRegionAvail(); // available space from current position. THIS IS YOUR BEST FRIEND. - IMGUI_API ImVec2 GetCursorPos(); // [window-local] cursor position in window-local coordinates. This is not your best friend. - IMGUI_API float GetCursorPosX(); // [window-local] " - IMGUI_API float GetCursorPosY(); // [window-local] " - IMGUI_API void SetCursorPos(const ImVec2& local_pos); // [window-local] " - IMGUI_API void SetCursorPosX(float local_x); // [window-local] " - IMGUI_API void SetCursorPosY(float local_y); // [window-local] " - IMGUI_API ImVec2 GetCursorStartPos(); // [window-local] initial cursor position, in window-local coordinates. Call GetCursorScreenPos() after Begin() to get the absolute coordinates version. +// Layout cursor positioning +// - By "cursor" we mean the current output position. +// - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line +// down. +// - You can call SameLine() between widgets to undo the last carriage return and output at the right of the preceding +// widget. +// - YOU CAN DO 99% OF WHAT YOU NEED WITH ONLY GetCursorScreenPos() and GetContentRegionAvail(). +// - Attention! We currently have inconsistencies between window-local and absolute positions we will aim to fix with +// future API: +// - Absolute coordinate: GetCursorScreenPos(), SetCursorScreenPos(), all ImDrawList:: functions. -> this is +// the preferred way forward. +// - Window-local coordinates: SameLine(offset), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), +// PushTextWrapPos() +// - Window-local coordinates: GetContentRegionMax(), GetWindowContentRegionMin(), GetWindowContentRegionMax() --> +// all obsoleted. YOU DON'T NEED THEM. +// - GetCursorScreenPos() = GetCursorPos() + GetWindowPos(). GetWindowPos() is almost only ever useful to convert from +// window-local to absolute coordinates. Try not to use it. +IMGUI_API ImVec2 +GetCursorScreenPos(); // cursor position, absolute coordinates. THIS IS YOUR BEST FRIEND (prefer using this rather than + // GetCursorPos(), also more useful to work with ImDrawList API). +IMGUI_API void SetCursorScreenPos( + const ImVec2 &pos); // cursor position, absolute coordinates. THIS IS YOUR BEST FRIEND. +IMGUI_API ImVec2 GetContentRegionAvail(); // available space from current position. THIS IS YOUR BEST FRIEND. +IMGUI_API ImVec2 +GetCursorPos(); // [window-local] cursor position in window-local coordinates. This is not your best friend. +IMGUI_API float GetCursorPosX(); // [window-local] " +IMGUI_API float GetCursorPosY(); // [window-local] " +IMGUI_API void SetCursorPos(const ImVec2 &local_pos); // [window-local] " +IMGUI_API void SetCursorPosX(float local_x); // [window-local] " +IMGUI_API void SetCursorPosY(float local_y); // [window-local] " +IMGUI_API ImVec2 GetCursorStartPos(); // [window-local] initial cursor position, in window-local coordinates. Call + // GetCursorScreenPos() after Begin() to get the absolute coordinates version. - // Other layout functions - IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator. - IMGUI_API void SameLine(float offset_from_start_x=0.0f, float spacing=-1.0f); // call between widgets or groups to layout them horizontally. X position given in window coordinates. - IMGUI_API void NewLine(); // undo a SameLine() or force a new line when in a horizontal-layout context. - IMGUI_API void Spacing(); // add vertical spacing. - IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size. unlike InvisibleButton(), Dummy() won't take the mouse click or be navigable into. - IMGUI_API void Indent(float indent_w = 0.0f); // move content position toward the right, by indent_w, or style.IndentSpacing if indent_w <= 0 - IMGUI_API void Unindent(float indent_w = 0.0f); // move content position back to the left, by indent_w, or style.IndentSpacing if indent_w <= 0 - IMGUI_API void BeginGroup(); // lock horizontal starting position - IMGUI_API void EndGroup(); // unlock horizontal starting position + capture the whole group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) - IMGUI_API void AlignTextToFramePadding(); // vertically align upcoming text baseline to FramePadding.y so that it will align properly to regularly framed items (call if you have text on a line before a framed item) - IMGUI_API float GetTextLineHeight(); // ~ FontSize - IMGUI_API float GetTextLineHeightWithSpacing(); // ~ FontSize + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of text) - IMGUI_API float GetFrameHeight(); // ~ FontSize + style.FramePadding.y * 2 - IMGUI_API float GetFrameHeightWithSpacing(); // ~ FontSize + style.FramePadding.y * 2 + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of framed widgets) +// Other layout functions +IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this + // becomes a vertical separator. +IMGUI_API void SameLine(float offset_from_start_x = 0.0f, + float spacing = -1.0f); // call between widgets or groups to layout them horizontally. X + // position given in window coordinates. +IMGUI_API void NewLine(); // undo a SameLine() or force a new line when in a horizontal-layout context. +IMGUI_API void Spacing(); // add vertical spacing. +IMGUI_API void Dummy(const ImVec2 &size); // add a dummy item of given size. unlike InvisibleButton(), Dummy() won't + // take the mouse click or be navigable into. +IMGUI_API void Indent(float indent_w = 0.0f); // move content position toward the right, by indent_w, or + // style.IndentSpacing if indent_w <= 0 +IMGUI_API void Unindent(float indent_w = 0.0f); // move content position back to the left, by indent_w, or + // style.IndentSpacing if indent_w <= 0 +IMGUI_API void BeginGroup(); // lock horizontal starting position +IMGUI_API void EndGroup(); // unlock horizontal starting position + capture the whole group bounding box into one "item" + // (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, + // etc.) +IMGUI_API void AlignTextToFramePadding(); // vertically align upcoming text baseline to FramePadding.y so that it will + // align properly to regularly framed items (call if you have text on a line + // before a framed item) +IMGUI_API float GetTextLineHeight(); // ~ FontSize +IMGUI_API float GetTextLineHeightWithSpacing(); // ~ FontSize + style.ItemSpacing.y (distance in pixels between 2 + // consecutive lines of text) +IMGUI_API float GetFrameHeight(); // ~ FontSize + style.FramePadding.y * 2 +IMGUI_API float GetFrameHeightWithSpacing(); // ~ FontSize + style.FramePadding.y * 2 + style.ItemSpacing.y (distance in + // pixels between 2 consecutive lines of framed widgets) - // ID stack/scopes - // Read the FAQ (docs/FAQ.md or http://dearimgui.com/faq) for more details about how ID are handled in dear imgui. - // - Those questions are answered and impacted by understanding of the ID stack system: - // - "Q: Why is my widget not reacting when I click on it?" - // - "Q: How can I have widgets with an empty label?" - // - "Q: How can I have multiple widgets with the same label?" - // - Short version: ID are hashes of the entire ID stack. If you are creating widgets in a loop you most likely - // want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them. - // - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others. - // - In this header file we use the "label"/"name" terminology to denote a string that will be displayed + used as an ID, - // whereas "str_id" denote a string that is only used as an ID and not normally displayed. - IMGUI_API void PushID(const char* str_id); // push string into the ID stack (will hash string). - IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); // push string into the ID stack (will hash string). - IMGUI_API void PushID(const void* ptr_id); // push pointer into the ID stack (will hash pointer). - IMGUI_API void PushID(int int_id); // push integer into the ID stack (will hash integer). - IMGUI_API void PopID(); // pop from the ID stack. - IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself - IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end); - IMGUI_API ImGuiID GetID(const void* ptr_id); - IMGUI_API ImGuiID GetID(int int_id); +// ID stack/scopes +// Read the FAQ (docs/FAQ.md or http://dearimgui.com/faq) for more details about how ID are handled in dear imgui. +// - Those questions are answered and impacted by understanding of the ID stack system: +// - "Q: Why is my widget not reacting when I click on it?" +// - "Q: How can I have widgets with an empty label?" +// - "Q: How can I have multiple widgets with the same label?" +// - Short version: ID are hashes of the entire ID stack. If you are creating widgets in a loop you most likely +// want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them. +// - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others. +// - In this header file we use the "label"/"name" terminology to denote a string that will be displayed + used as an +// ID, +// whereas "str_id" denote a string that is only used as an ID and not normally displayed. +IMGUI_API void PushID(const char *str_id); // push string into the ID stack (will hash string). +IMGUI_API void PushID(const char *str_id_begin, + const char *str_id_end); // push string into the ID stack (will hash string). +IMGUI_API void PushID(const void *ptr_id); // push pointer into the ID stack (will hash pointer). +IMGUI_API void PushID(int int_id); // push integer into the ID stack (will hash integer). +IMGUI_API void PopID(); // pop from the ID stack. +IMGUI_API ImGuiID GetID(const char *str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if + // you want to query into ImGuiStorage yourself +IMGUI_API ImGuiID GetID(const char *str_id_begin, const char *str_id_end); +IMGUI_API ImGuiID GetID(const void *ptr_id); +IMGUI_API ImGuiID GetID(int int_id); - // Widgets: Text - IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text. - IMGUI_API void Text(const char* fmt, ...) IM_FMTARGS(1); // formatted text - IMGUI_API void TextV(const char* fmt, va_list args) IM_FMTLIST(1); - IMGUI_API void TextColored(const ImVec4& col, const char* fmt, ...) IM_FMTARGS(2); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor(); - IMGUI_API void TextColoredV(const ImVec4& col, const char* fmt, va_list args) IM_FMTLIST(2); - IMGUI_API void TextDisabled(const char* fmt, ...) IM_FMTARGS(1); // shortcut for PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); Text(fmt, ...); PopStyleColor(); - IMGUI_API void TextDisabledV(const char* fmt, va_list args) IM_FMTLIST(1); - IMGUI_API void TextWrapped(const char* fmt, ...) IM_FMTARGS(1); // shortcut for PushTextWrapPos(0.0f); Text(fmt, ...); PopTextWrapPos();. Note that this won't work on an auto-resizing window if there's no other widgets to extend the window width, yoy may need to set a size using SetNextWindowSize(). - IMGUI_API void TextWrappedV(const char* fmt, va_list args) IM_FMTLIST(1); - IMGUI_API void LabelText(const char* label, const char* fmt, ...) IM_FMTARGS(2); // display text+label aligned the same way as value+label widgets - IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args) IM_FMTLIST(2); - IMGUI_API void BulletText(const char* fmt, ...) IM_FMTARGS(1); // shortcut for Bullet()+Text() - IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1); - IMGUI_API void SeparatorText(const char* label); // currently: formatted text with a horizontal line +// Widgets: Text +IMGUI_API void TextUnformatted( + const char *text, + const char *text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't + // require null terminated string if 'text_end' is specified, B) it's faster, no + // memory copy is done, no buffer size limits, recommended for long chunks of text. +IMGUI_API void Text(const char *fmt, ...) IM_FMTARGS(1); // formatted text +IMGUI_API void TextV(const char *fmt, va_list args) IM_FMTLIST(1); +IMGUI_API void TextColored(const ImVec4 &col, const char *fmt, ...) + IM_FMTARGS(2); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor(); +IMGUI_API void TextColoredV(const ImVec4 &col, const char *fmt, va_list args) IM_FMTLIST(2); +IMGUI_API void TextDisabled(const char *fmt, ...) + IM_FMTARGS(1); // shortcut for PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); Text(fmt, ...); + // PopStyleColor(); +IMGUI_API void TextDisabledV(const char *fmt, va_list args) IM_FMTLIST(1); +IMGUI_API void TextWrapped(const char *fmt, ...) + IM_FMTARGS(1); // shortcut for PushTextWrapPos(0.0f); Text(fmt, ...); PopTextWrapPos();. Note that this won't work + // on an auto-resizing window if there's no other widgets to extend the window width, yoy may need to + // set a size using SetNextWindowSize(). +IMGUI_API void TextWrappedV(const char *fmt, va_list args) IM_FMTLIST(1); +IMGUI_API void LabelText(const char *label, const char *fmt, ...) + IM_FMTARGS(2); // display text+label aligned the same way as value+label widgets +IMGUI_API void LabelTextV(const char *label, const char *fmt, va_list args) IM_FMTLIST(2); +IMGUI_API void BulletText(const char *fmt, ...) IM_FMTARGS(1); // shortcut for Bullet()+Text() +IMGUI_API void BulletTextV(const char *fmt, va_list args) IM_FMTLIST(1); +IMGUI_API void SeparatorText(const char *label); // currently: formatted text with a horizontal line - // Widgets: Main - // - Most widgets return true when the value has been changed or when pressed/selected - // - You may also use one of the many IsItemXXX functions (e.g. IsItemActive, IsItemHovered, etc.) to query widget state. - IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0, 0)); // button - IMGUI_API bool SmallButton(const char* label); // button with (FramePadding.y == 0) to easily embed within text - IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size, ImGuiButtonFlags flags = 0); // flexible button behavior without the visuals, frequently useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.) - IMGUI_API bool ArrowButton(const char* str_id, ImGuiDir dir); // square button with an arrow shape - IMGUI_API bool Checkbox(const char* label, bool* v); - IMGUI_API bool CheckboxFlags(const char* label, int* flags, int flags_value); - IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value); - IMGUI_API bool RadioButton(const char* label, bool active); // use with e.g. if (RadioButton("one", my_value==1)) { my_value = 1; } - IMGUI_API bool RadioButton(const char* label, int* v, int v_button); // shortcut to handle the above pattern when value is an integer - IMGUI_API void ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-FLT_MIN, 0), const char* overlay = NULL); - IMGUI_API void Bullet(); // draw a small circle + keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses - IMGUI_API bool TextLink(const char* label); // hyperlink text button, return true when clicked - IMGUI_API bool TextLinkOpenURL(const char* label, const char* url = NULL); // hyperlink text button, automatically open file/url when clicked +// Widgets: Main +// - Most widgets return true when the value has been changed or when pressed/selected +// - You may also use one of the many IsItemXXX functions (e.g. IsItemActive, IsItemHovered, etc.) to query widget +// state. +IMGUI_API bool Button(const char *label, const ImVec2 &size = ImVec2(0, 0)); // button +IMGUI_API bool SmallButton(const char *label); // button with (FramePadding.y == 0) to easily embed within text +IMGUI_API bool InvisibleButton( + const char *str_id, const ImVec2 &size, + ImGuiButtonFlags flags = 0); // flexible button behavior without the visuals, frequently useful to build custom + // behaviors using the public api (along with IsItemActive, IsItemHovered, etc.) +IMGUI_API bool ArrowButton(const char *str_id, ImGuiDir dir); // square button with an arrow shape +IMGUI_API bool Checkbox(const char *label, bool *v); +IMGUI_API bool CheckboxFlags(const char *label, int *flags, int flags_value); +IMGUI_API bool CheckboxFlags(const char *label, unsigned int *flags, unsigned int flags_value); +IMGUI_API bool RadioButton(const char *label, + bool active); // use with e.g. if (RadioButton("one", my_value==1)) { my_value = 1; } +IMGUI_API bool RadioButton(const char *label, int *v, + int v_button); // shortcut to handle the above pattern when value is an integer +IMGUI_API void ProgressBar(float fraction, const ImVec2 &size_arg = ImVec2(-FLT_MIN, 0), const char *overlay = NULL); +IMGUI_API void Bullet(); // draw a small circle + keep the cursor on the same line. advance cursor x position by + // GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses +IMGUI_API bool TextLink(const char *label); // hyperlink text button, return true when clicked +IMGUI_API bool TextLinkOpenURL( + const char *label, const char *url = NULL); // hyperlink text button, automatically open file/url when clicked - // Widgets: Images - // - Read about ImTextureID/ImTextureRef here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples - // - 'uv0' and 'uv1' are texture coordinates. Read about them from the same link above. - // - Image() pads adds style.ImageBorderSize on each side, ImageButton() adds style.FramePadding on each side. - // - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified. - // - An obsolete version of Image(), before 1.91.9 (March 2025), had a 'tint_col' parameter which is now supported by the ImageWithBg() function. - IMGUI_API void Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1)); - IMGUI_API void ImageWithBg(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); - IMGUI_API bool ImageButton(const char* str_id, ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); +// Widgets: Images +// - Read about ImTextureID/ImTextureRef here: +// https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples +// - 'uv0' and 'uv1' are texture coordinates. Read about them from the same link above. +// - Image() pads adds style.ImageBorderSize on each side, ImageButton() adds style.FramePadding on each side. +// - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified. +// - An obsolete version of Image(), before 1.91.9 (March 2025), had a 'tint_col' parameter which is now supported by +// the ImageWithBg() function. +IMGUI_API void Image(ImTextureRef tex_ref, const ImVec2 &image_size, const ImVec2 &uv0 = ImVec2(0, 0), + const ImVec2 &uv1 = ImVec2(1, 1)); +IMGUI_API void ImageWithBg(ImTextureRef tex_ref, const ImVec2 &image_size, const ImVec2 &uv0 = ImVec2(0, 0), + const ImVec2 &uv1 = ImVec2(1, 1), const ImVec4 &bg_col = ImVec4(0, 0, 0, 0), + const ImVec4 &tint_col = ImVec4(1, 1, 1, 1)); +IMGUI_API bool ImageButton(const char *str_id, ImTextureRef tex_ref, const ImVec2 &image_size, + const ImVec2 &uv0 = ImVec2(0, 0), const ImVec2 &uv1 = ImVec2(1, 1), + const ImVec4 &bg_col = ImVec4(0, 0, 0, 0), const ImVec4 &tint_col = ImVec4(1, 1, 1, 1)); - // Widgets: Combo Box (Dropdown) - // - The BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items. - // - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose. This is analogous to how ListBox are created. - IMGUI_API bool BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0); - IMGUI_API void EndCombo(); // only call EndCombo() if BeginCombo() returns true! - IMGUI_API bool Combo(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1); - IMGUI_API bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int popup_max_height_in_items = -1); // Separate items with \0 within a string, end item-list with \0\0. e.g. "One\0Two\0Three\0" - IMGUI_API bool Combo(const char* label, int* current_item, const char* (*getter)(void* user_data, int idx), void* user_data, int items_count, int popup_max_height_in_items = -1); +// Widgets: Combo Box (Dropdown) +// - The BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by +// creating e.g. Selectable() items. +// - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose. This +// is analogous to how ListBox are created. +IMGUI_API bool BeginCombo(const char *label, const char *preview_value, ImGuiComboFlags flags = 0); +IMGUI_API void EndCombo(); // only call EndCombo() if BeginCombo() returns true! +IMGUI_API bool Combo(const char *label, int *current_item, const char *const items[], int items_count, + int popup_max_height_in_items = -1); +IMGUI_API bool Combo(const char *label, int *current_item, const char *items_separated_by_zeros, + int popup_max_height_in_items = -1); // Separate items with \0 within a string, end item-list with + // \0\0. e.g. "One\0Two\0Three\0" +IMGUI_API bool Combo(const char *label, int *current_item, const char *(*getter)(void *user_data, int idx), + void *user_data, int items_count, int popup_max_height_in_items = -1); - // Widgets: Drag Sliders - // - CTRL+Click on any drag box to turn them into an input box. Manually input values aren't clamped by default and can go off-bounds. Use ImGuiSliderFlags_AlwaysClamp to always clamp. - // - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every function, note that a 'float v[X]' function argument is the same as 'float* v', - // the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x - // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. - // - Format string may also be set to NULL or use the default format ("%f" or "%d"). - // - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For keyboard/gamepad navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). - // - Use v_min < v_max to clamp edits to given limits. Note that CTRL+Click manual input can override those limits if ImGuiSliderFlags_AlwaysClamp is not used. - // - Use v_max = FLT_MAX / INT_MAX etc to avoid clamping to a maximum, same with v_min = -FLT_MAX / INT_MIN to avoid clamping to a minimum. - // - We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them. - // - Legacy: Pre-1.78 there are DragXXX() function signatures that take a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument. - // If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361 - IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); // If v_min >= v_max we have no bound - IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); - IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); - IMGUI_API bool DragFloat4(const char* label, float v[4], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); - IMGUI_API bool DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", const char* format_max = NULL, ImGuiSliderFlags flags = 0); - IMGUI_API bool DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); // If v_min >= v_max we have no bound - IMGUI_API bool DragInt2(const char* label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); - 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 = 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: Drag Sliders +// - CTRL+Click on any drag box to turn them into an input box. Manually input values aren't clamped by default and can +// go off-bounds. Use ImGuiSliderFlags_AlwaysClamp to always clamp. +// - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every function, note that a 'float v[X]' function +// argument is the same as 'float* v', +// the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass +// address of your first element out of a contiguous set, e.g. &myvector.x +// - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. +// "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. +// - Format string may also be set to NULL or use the default format ("%f" or "%d"). +// - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For +// keyboard/gamepad navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). +// - Use v_min < v_max to clamp edits to given limits. Note that CTRL+Click manual input can override those limits if +// ImGuiSliderFlags_AlwaysClamp is not used. +// - Use v_max = FLT_MAX / INT_MAX etc to avoid clamping to a maximum, same with v_min = -FLT_MAX / INT_MIN to avoid +// clamping to a minimum. +// - We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it +// easier to swap them. +// - Legacy: Pre-1.78 there are DragXXX() function signatures that take a final `float power=1.0f' argument instead of +// the `ImGuiSliderFlags flags=0' argument. +// If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361 +IMGUI_API bool DragFloat(const char *label, float *v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, + const char *format = "%.3f", ImGuiSliderFlags flags = 0); // If v_min >= v_max we have no bound +IMGUI_API bool DragFloat2(const char *label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, + const char *format = "%.3f", ImGuiSliderFlags flags = 0); +IMGUI_API bool DragFloat3(const char *label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, + const char *format = "%.3f", ImGuiSliderFlags flags = 0); +IMGUI_API bool DragFloat4(const char *label, float v[4], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, + const char *format = "%.3f", ImGuiSliderFlags flags = 0); +IMGUI_API bool DragFloatRange2(const char *label, float *v_current_min, float *v_current_max, float v_speed = 1.0f, + float v_min = 0.0f, float v_max = 0.0f, const char *format = "%.3f", + const char *format_max = NULL, ImGuiSliderFlags flags = 0); +IMGUI_API bool DragInt(const char *label, int *v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, + const char *format = "%d", ImGuiSliderFlags flags = 0); // If v_min >= v_max we have no bound +IMGUI_API bool DragInt2(const char *label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, + const char *format = "%d", ImGuiSliderFlags flags = 0); +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 = 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 by default and can go off-bounds. Use ImGuiSliderFlags_AlwaysClamp to always clamp. - // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. - // - Format string may also be set to NULL or use the default format ("%f" or "%d"). - // - Legacy: Pre-1.78 there are SliderXXX() function signatures that take a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument. - // If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361 - IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. - IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); - IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); - IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); - IMGUI_API bool SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f, const char* format = "%.0f deg", ImGuiSliderFlags flags = 0); - IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); - IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); - IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); - IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); - IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0); - 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 = NULL, ImGuiSliderFlags flags = 0); - IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); - IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); - IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, 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 by default and can go +// off-bounds. Use ImGuiSliderFlags_AlwaysClamp to always clamp. +// - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. +// "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. +// - Format string may also be set to NULL or use the default format ("%f" or "%d"). +// - Legacy: Pre-1.78 there are SliderXXX() function signatures that take a final `float power=1.0f' argument instead of +// the `ImGuiSliderFlags flags=0' argument. +// If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361 +IMGUI_API bool SliderFloat(const char *label, float *v, float v_min, float v_max, const char *format = "%.3f", + ImGuiSliderFlags flags = 0); // adjust format to decorate the value with a prefix or a suffix + // for in-slider labels or unit display. +IMGUI_API bool SliderFloat2(const char *label, float v[2], float v_min, float v_max, const char *format = "%.3f", + ImGuiSliderFlags flags = 0); +IMGUI_API bool SliderFloat3(const char *label, float v[3], float v_min, float v_max, const char *format = "%.3f", + ImGuiSliderFlags flags = 0); +IMGUI_API bool SliderFloat4(const char *label, float v[4], float v_min, float v_max, const char *format = "%.3f", + ImGuiSliderFlags flags = 0); +IMGUI_API bool SliderAngle(const char *label, float *v_rad, float v_degrees_min = -360.0f, + float v_degrees_max = +360.0f, const char *format = "%.0f deg", ImGuiSliderFlags flags = 0); +IMGUI_API bool SliderInt(const char *label, int *v, int v_min, int v_max, const char *format = "%d", + ImGuiSliderFlags flags = 0); +IMGUI_API bool SliderInt2(const char *label, int v[2], int v_min, int v_max, const char *format = "%d", + ImGuiSliderFlags flags = 0); +IMGUI_API bool SliderInt3(const char *label, int v[3], int v_min, int v_max, const char *format = "%d", + ImGuiSliderFlags flags = 0); +IMGUI_API bool SliderInt4(const char *label, int v[4], int v_min, int v_max, const char *format = "%d", + ImGuiSliderFlags flags = 0); +IMGUI_API bool SliderScalar(const char *label, ImGuiDataType data_type, void *p_data, const void *p_min, + const void *p_max, const char *format = NULL, ImGuiSliderFlags flags = 0); +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 = NULL, + ImGuiSliderFlags flags = 0); +IMGUI_API bool VSliderFloat(const char *label, const ImVec2 &size, float *v, float v_min, float v_max, + const char *format = "%.3f", ImGuiSliderFlags flags = 0); +IMGUI_API bool VSliderInt(const char *label, const ImVec2 &size, int *v, int v_min, int v_max, + const char *format = "%d", ImGuiSliderFlags flags = 0); +IMGUI_API bool VSliderScalar(const char *label, const ImVec2 &size, ImGuiDataType data_type, void *p_data, + const void *p_min, const void *p_max, const char *format = NULL, + ImGuiSliderFlags flags = 0); - // Widgets: Input with Keyboard - // - If you want to use InputText() with std::string or any custom dynamic string type, see misc/cpp/imgui_stdlib.h and comments in imgui_demo.cpp. - // - Most of the ImGuiInputTextFlags flags are only useful for InputText() and not for InputFloatX, InputIntX, InputDouble etc. - IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); - IMGUI_API bool InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); - IMGUI_API bool InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); - IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags flags = 0); - IMGUI_API bool InputFloat2(const char* label, float v[2], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); - IMGUI_API bool InputFloat3(const char* label, float v[3], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); - IMGUI_API bool InputFloat4(const char* label, float v[4], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); - IMGUI_API bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags flags = 0); - IMGUI_API bool InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags = 0); - IMGUI_API bool InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags = 0); - IMGUI_API bool InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags = 0); - IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0, double step_fast = 0.0, const char* format = "%.6f", ImGuiInputTextFlags flags = 0); - IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); - IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); +// Widgets: Input with Keyboard +// - If you want to use InputText() with std::string or any custom dynamic string type, see misc/cpp/imgui_stdlib.h and +// comments in imgui_demo.cpp. +// - Most of the ImGuiInputTextFlags flags are only useful for InputText() and not for InputFloatX, InputIntX, +// InputDouble etc. +IMGUI_API bool InputText(const char *label, char *buf, size_t buf_size, ImGuiInputTextFlags flags = 0, + ImGuiInputTextCallback callback = NULL, void *user_data = NULL); +IMGUI_API bool InputTextMultiline(const char *label, char *buf, size_t buf_size, const ImVec2 &size = ImVec2(0, 0), + ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, + void *user_data = NULL); +IMGUI_API bool InputTextWithHint(const char *label, const char *hint, char *buf, size_t buf_size, + ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, + void *user_data = NULL); +IMGUI_API bool InputFloat(const char *label, float *v, float step = 0.0f, float step_fast = 0.0f, + const char *format = "%.3f", ImGuiInputTextFlags flags = 0); +IMGUI_API bool InputFloat2(const char *label, float v[2], const char *format = "%.3f", ImGuiInputTextFlags flags = 0); +IMGUI_API bool InputFloat3(const char *label, float v[3], const char *format = "%.3f", ImGuiInputTextFlags flags = 0); +IMGUI_API bool InputFloat4(const char *label, float v[4], const char *format = "%.3f", ImGuiInputTextFlags flags = 0); +IMGUI_API bool InputInt(const char *label, int *v, int step = 1, int step_fast = 100, ImGuiInputTextFlags flags = 0); +IMGUI_API bool InputInt2(const char *label, int v[2], ImGuiInputTextFlags flags = 0); +IMGUI_API bool InputInt3(const char *label, int v[3], ImGuiInputTextFlags flags = 0); +IMGUI_API bool InputInt4(const char *label, int v[4], ImGuiInputTextFlags flags = 0); +IMGUI_API bool InputDouble(const char *label, double *v, double step = 0.0, double step_fast = 0.0, + const char *format = "%.6f", ImGuiInputTextFlags flags = 0); +IMGUI_API bool InputScalar(const char *label, ImGuiDataType data_type, void *p_data, const void *p_step = NULL, + const void *p_step_fast = NULL, const char *format = NULL, ImGuiInputTextFlags flags = 0); +IMGUI_API bool InputScalarN(const char *label, ImGuiDataType data_type, void *p_data, int components, + const void *p_step = NULL, const void *p_step_fast = NULL, const char *format = NULL, + ImGuiInputTextFlags flags = 0); - // Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little color square that can be left-clicked to open a picker, and right-clicked to open an option menu.) - // - Note that in C++ a 'float v[X]' function argument is the _same_ as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. - // - You can pass the address of a first float element out of a contiguous structure, e.g. &myvector.x - IMGUI_API bool ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); - IMGUI_API bool ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0); - IMGUI_API bool ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); - IMGUI_API bool ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags = 0, const float* ref_col = NULL); - IMGUI_API bool ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // display a color square/button, hover for details, return true when pressed. - IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags); // initialize current options (generally on application startup) if you want to select a default format, picker type, etc. User will be able to change many settings, unless you pass the _NoOptions flag to your calls. +// Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little color square that can be left-clicked to +// open a picker, and right-clicked to open an option menu.) +// - Note that in C++ a 'float v[X]' function argument is the _same_ as 'float* v', the array syntax is just a way to +// document the number of elements that are expected to be accessible. +// - You can pass the address of a first float element out of a contiguous structure, e.g. &myvector.x +IMGUI_API bool ColorEdit3(const char *label, float col[3], ImGuiColorEditFlags flags = 0); +IMGUI_API bool ColorEdit4(const char *label, float col[4], ImGuiColorEditFlags flags = 0); +IMGUI_API bool ColorPicker3(const char *label, float col[3], ImGuiColorEditFlags flags = 0); +IMGUI_API bool ColorPicker4(const char *label, float col[4], ImGuiColorEditFlags flags = 0, + const float *ref_col = NULL); +IMGUI_API bool ColorButton( + const char *desc_id, const ImVec4 &col, ImGuiColorEditFlags flags = 0, + const ImVec2 &size = ImVec2(0, 0)); // display a color square/button, hover for details, return true when pressed. +IMGUI_API void SetColorEditOptions( + ImGuiColorEditFlags flags); // initialize current options (generally on application startup) if you want to select a + // default format, picker type, etc. User will be able to change many settings, unless + // you pass the _NoOptions flag to your calls. - // Widgets: Trees - // - TreeNode functions return true when the node is open, in which case you need to also call TreePop() when you are finished displaying the tree node contents. - IMGUI_API bool TreeNode(const char* label); - IMGUI_API bool TreeNode(const char* str_id, const char* fmt, ...) IM_FMTARGS(2); // helper variation to easily decorelate the id from the displayed string. Read the FAQ about why and how to use ID. to align arbitrary text at the same level as a TreeNode() you can use Bullet(). - IMGUI_API bool TreeNode(const void* ptr_id, const char* fmt, ...) IM_FMTARGS(2); // " - IMGUI_API bool TreeNodeV(const char* str_id, const char* fmt, va_list args) IM_FMTLIST(2); - IMGUI_API bool TreeNodeV(const void* ptr_id, const char* fmt, va_list args) IM_FMTLIST(2); - IMGUI_API bool TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags = 0); - IMGUI_API bool TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3); - IMGUI_API bool TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3); - IMGUI_API bool TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); - IMGUI_API bool TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); - IMGUI_API void TreePush(const char* str_id); // ~ Indent()+PushID(). Already called by TreeNode() when returning true, but you can call TreePush/TreePop yourself if desired. - IMGUI_API void TreePush(const void* ptr_id); // " - IMGUI_API void TreePop(); // ~ Unindent()+PopID() - IMGUI_API float GetTreeNodeToLabelSpacing(); // horizontal distance preceding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode - IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop(). - IMGUI_API bool CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFlags flags = 0); // when 'p_visible != NULL': if '*p_visible==true' display an additional small close button on upper right of the header which will set the bool to false when clicked, if '*p_visible==false' don't display the header. - IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state. - IMGUI_API void SetNextItemStorageID(ImGuiID storage_id); // set id to use for open/close storage (default to same as item id). +// Widgets: Trees +// - TreeNode functions return true when the node is open, in which case you need to also call TreePop() when you are +// finished displaying the tree node contents. +IMGUI_API bool TreeNode(const char *label); +IMGUI_API bool TreeNode(const char *str_id, const char *fmt, ...) + IM_FMTARGS(2); // helper variation to easily decorelate the id from the displayed string. Read the FAQ about why and + // how to use ID. to align arbitrary text at the same level as a TreeNode() you can use Bullet(). +IMGUI_API bool TreeNode(const void *ptr_id, const char *fmt, ...) IM_FMTARGS(2); // " +IMGUI_API bool TreeNodeV(const char *str_id, const char *fmt, va_list args) IM_FMTLIST(2); +IMGUI_API bool TreeNodeV(const void *ptr_id, const char *fmt, va_list args) IM_FMTLIST(2); +IMGUI_API bool TreeNodeEx(const char *label, ImGuiTreeNodeFlags flags = 0); +IMGUI_API bool TreeNodeEx(const char *str_id, ImGuiTreeNodeFlags flags, const char *fmt, ...) IM_FMTARGS(3); +IMGUI_API bool TreeNodeEx(const void *ptr_id, ImGuiTreeNodeFlags flags, const char *fmt, ...) IM_FMTARGS(3); +IMGUI_API bool TreeNodeExV(const char *str_id, ImGuiTreeNodeFlags flags, const char *fmt, va_list args) IM_FMTLIST(3); +IMGUI_API bool TreeNodeExV(const void *ptr_id, ImGuiTreeNodeFlags flags, const char *fmt, va_list args) IM_FMTLIST(3); +IMGUI_API void TreePush(const char *str_id); // ~ Indent()+PushID(). Already called by TreeNode() when returning true, + // but you can call TreePush/TreePop yourself if desired. +IMGUI_API void TreePush(const void *ptr_id); // " +IMGUI_API void TreePop(); // ~ Unindent()+PopID() +IMGUI_API float GetTreeNodeToLabelSpacing(); // horizontal distance preceding label when using TreeNode*() or Bullet() + // == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode +IMGUI_API bool CollapsingHeader( + const char *label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push + // on ID stack. user doesn't have to call TreePop(). +IMGUI_API bool CollapsingHeader( + const char *label, bool *p_visible, + ImGuiTreeNodeFlags flags = 0); // when 'p_visible != NULL': if '*p_visible==true' display an additional small close + // button on upper right of the header which will set the bool to false when clicked, + // if '*p_visible==false' don't display the header. +IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state. +IMGUI_API void SetNextItemStorageID( + ImGuiID storage_id); // set id to use for open/close storage (default to same as item id). - // Widgets: Selectables - // - A selectable highlights when hovered, and can display another color when selected. - // - Neighbors selectable extend their highlight bounds in order to leave no gap between them. This is so a series of selected Selectable appear contiguous. - IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height - IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. +// Widgets: Selectables +// - A selectable highlights when hovered, and can display another color when selected. +// - Neighbors selectable extend their highlight bounds in order to leave no gap between them. This is so a series of +// selected Selectable appear contiguous. +IMGUI_API bool Selectable( + const char *label, bool selected = false, ImGuiSelectableFlags flags = 0, + const ImVec2 &size = + ImVec2(0, 0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true + // so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify + // width. size.y==0.0: use label height, size.y>0.0: specify height +IMGUI_API bool Selectable(const char *label, bool *p_selected, ImGuiSelectableFlags flags = 0, + const ImVec2 &size = ImVec2(0, 0)); // "bool* p_selected" point to the selection state + // (read-write), as a convenient helper. - // Multi-selection system for Selectable(), Checkbox(), TreeNode() functions [BETA] - // - This enables standard multi-selection/range-selection idioms (CTRL+Mouse/Keyboard, SHIFT+Mouse/Keyboard, etc.) in a way that also allow a clipper to be used. - // - ImGuiSelectionUserData is often used to store your item index within the current view (but may store something else). - // - Read comments near ImGuiMultiSelectIO for instructions/details and see 'Demo->Widgets->Selection State & Multi-Select' for demo. - // - TreeNode() is technically supported but... using this correctly is more complicated. You need some sort of linear/random access to your tree, - // which is suited to advanced trees setups already implementing filters and clipper. We will work simplifying the current demo. - // - 'selection_size' and 'items_count' parameters are optional and used by a few features. If they are costly for you to compute, you may avoid them. - IMGUI_API ImGuiMultiSelectIO* BeginMultiSelect(ImGuiMultiSelectFlags flags, int selection_size = -1, int items_count = -1); - IMGUI_API ImGuiMultiSelectIO* EndMultiSelect(); - IMGUI_API void SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_data); - IMGUI_API bool IsItemToggledSelection(); // Was the last item selection state toggled? Useful if you need the per-item information _before_ reaching EndMultiSelect(). We only returns toggle _event_ in order to handle clipping correctly. +// Multi-selection system for Selectable(), Checkbox(), TreeNode() functions [BETA] +// - This enables standard multi-selection/range-selection idioms (CTRL+Mouse/Keyboard, SHIFT+Mouse/Keyboard, etc.) in a +// way that also allow a clipper to be used. +// - ImGuiSelectionUserData is often used to store your item index within the current view (but may store something +// else). +// - Read comments near ImGuiMultiSelectIO for instructions/details and see 'Demo->Widgets->Selection State & +// Multi-Select' for demo. +// - TreeNode() is technically supported but... using this correctly is more complicated. You need some sort of +// linear/random access to your tree, +// which is suited to advanced trees setups already implementing filters and clipper. We will work simplifying the +// current demo. +// - 'selection_size' and 'items_count' parameters are optional and used by a few features. If they are costly for you +// to compute, you may avoid them. +IMGUI_API ImGuiMultiSelectIO *BeginMultiSelect(ImGuiMultiSelectFlags flags, int selection_size = -1, + int items_count = -1); +IMGUI_API ImGuiMultiSelectIO *EndMultiSelect(); +IMGUI_API void SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_data); +IMGUI_API bool IsItemToggledSelection(); // Was the last item selection state toggled? Useful if you need the per-item + // information _before_ reaching EndMultiSelect(). We only returns toggle + // _event_ in order to handle clipping correctly. - // Widgets: List Boxes - // - This is essentially a thin wrapper to using BeginChild/EndChild with the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label. - // - If you don't need a label you can probably simply use BeginChild() with the ImGuiChildFlags_FrameStyle flag for the same result. - // - You can submit contents and manage your selection state however you want it, by creating e.g. Selectable() or any other items. - // - The simplified/old ListBox() api are helpers over BeginListBox()/EndListBox() which are kept available for convenience purpose. This is analogous to how Combos are created. - // - Choose frame width: size.x > 0.0f: custom / size.x < 0.0f or -FLT_MIN: right-align / size.x = 0.0f (default): use current ItemWidth - // - Choose frame height: size.y > 0.0f: custom / size.y < 0.0f or -FLT_MIN: bottom-align / size.y = 0.0f (default): arbitrary default height which can fit ~7 items - IMGUI_API bool BeginListBox(const char* label, const ImVec2& size = ImVec2(0, 0)); // open a framed scrolling region - IMGUI_API void EndListBox(); // only call EndListBox() if BeginListBox() returned true! - IMGUI_API bool ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items = -1); - IMGUI_API bool ListBox(const char* label, int* current_item, const char* (*getter)(void* user_data, int idx), void* user_data, int items_count, int height_in_items = -1); +// Widgets: List Boxes +// - This is essentially a thin wrapper to using BeginChild/EndChild with the ImGuiChildFlags_FrameStyle flag for +// stylistic changes + displaying a label. +// - If you don't need a label you can probably simply use BeginChild() with the ImGuiChildFlags_FrameStyle flag for the +// same result. +// - You can submit contents and manage your selection state however you want it, by creating e.g. Selectable() or any +// other items. +// - The simplified/old ListBox() api are helpers over BeginListBox()/EndListBox() which are kept available for +// convenience purpose. This is analogous to how Combos are created. +// - Choose frame width: size.x > 0.0f: custom / size.x < 0.0f or -FLT_MIN: right-align / size.x = 0.0f +// (default): use current ItemWidth +// - Choose frame height: size.y > 0.0f: custom / size.y < 0.0f or -FLT_MIN: bottom-align / size.y = 0.0f +// (default): arbitrary default height which can fit ~7 items +IMGUI_API bool BeginListBox(const char *label, const ImVec2 &size = ImVec2(0, 0)); // open a framed scrolling region +IMGUI_API void EndListBox(); // only call EndListBox() if BeginListBox() returned true! +IMGUI_API bool ListBox(const char *label, int *current_item, const char *const items[], int items_count, + int height_in_items = -1); +IMGUI_API bool ListBox(const char *label, int *current_item, const char *(*getter)(void *user_data, int idx), + void *user_data, int items_count, int height_in_items = -1); - // Widgets: Data Plotting - // - Consider using ImPlot (https://github.com/epezent/implot) which is much better! - IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); - IMGUI_API void PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); - IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); - IMGUI_API void PlotHistogram(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); +// Widgets: Data Plotting +// - Consider using ImPlot (https://github.com/epezent/implot) which is much better! +IMGUI_API void PlotLines(const char *label, const float *values, int values_count, int values_offset = 0, + const char *overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, + ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); +IMGUI_API void PlotLines(const char *label, float (*values_getter)(void *data, int idx), void *data, int values_count, + int values_offset = 0, const char *overlay_text = NULL, float scale_min = FLT_MAX, + float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); +IMGUI_API void PlotHistogram(const char *label, const float *values, int values_count, int values_offset = 0, + const char *overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, + ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); +IMGUI_API void PlotHistogram(const char *label, float (*values_getter)(void *data, int idx), void *data, + int values_count, int values_offset = 0, const char *overlay_text = NULL, + float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); - // Widgets: Value() Helpers. - // - Those are merely shortcut to calling Text() with a format string. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace) - IMGUI_API void Value(const char* prefix, bool b); - IMGUI_API void Value(const char* prefix, int v); - IMGUI_API void Value(const char* prefix, unsigned int v); - IMGUI_API void Value(const char* prefix, float v, const char* float_format = NULL); +// Widgets: Value() Helpers. +// - Those are merely shortcut to calling Text() with a format string. Output single value in "name: value" format (tip: +// freely declare more in your code to handle your types. you can add functions to the ImGui namespace) +IMGUI_API void Value(const char *prefix, bool b); +IMGUI_API void Value(const char *prefix, int v); +IMGUI_API void Value(const char *prefix, unsigned int v); +IMGUI_API void Value(const char *prefix, float v, const char *float_format = NULL); - // Widgets: Menus - // - 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. - 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 +// Widgets: Menus +// - 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. +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 - // - Tooltips are windows following the mouse. They do not take focus away. - // - A tooltip window can contain items of any types. - // - SetTooltip() is more or less a shortcut for the 'if (BeginTooltip()) { Text(...); EndTooltip(); }' idiom (with a subtlety that it discard any previously submitted tooltip) - IMGUI_API bool BeginTooltip(); // begin/append a tooltip window. - IMGUI_API void EndTooltip(); // only call EndTooltip() if BeginTooltip()/BeginItemTooltip() returns true! - IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip. Often used after a ImGui::IsItemHovered() check. Override any previous call to SetTooltip(). - IMGUI_API void SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1); +// Tooltips +// - Tooltips are windows following the mouse. They do not take focus away. +// - A tooltip window can contain items of any types. +// - SetTooltip() is more or less a shortcut for the 'if (BeginTooltip()) { Text(...); EndTooltip(); }' idiom (with a +// subtlety that it discard any previously submitted tooltip) +IMGUI_API bool BeginTooltip(); // begin/append a tooltip window. +IMGUI_API void EndTooltip(); // only call EndTooltip() if BeginTooltip()/BeginItemTooltip() returns true! +IMGUI_API void SetTooltip(const char *fmt, ...) + IM_FMTARGS(1); // set a text-only tooltip. Often used after a ImGui::IsItemHovered() check. Override any previous + // call to SetTooltip(). +IMGUI_API void SetTooltipV(const char *fmt, va_list args) IM_FMTLIST(1); - // Tooltips: helpers for showing a tooltip when hovering an item - // - BeginItemTooltip() is a shortcut for the 'if (IsItemHovered(ImGuiHoveredFlags_ForTooltip) && BeginTooltip())' idiom. - // - SetItemTooltip() is a shortcut for the 'if (IsItemHovered(ImGuiHoveredFlags_ForTooltip)) { SetTooltip(...); }' idiom. - // - Where 'ImGuiHoveredFlags_ForTooltip' itself is a shortcut to use 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on active input type. For mouse it defaults to 'ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort'. - IMGUI_API bool BeginItemTooltip(); // begin/append a tooltip window if preceding item was hovered. - IMGUI_API void SetItemTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip if preceding item was hovered. override any previous call to SetTooltip(). - IMGUI_API void SetItemTooltipV(const char* fmt, va_list args) IM_FMTLIST(1); +// Tooltips: helpers for showing a tooltip when hovering an item +// - BeginItemTooltip() is a shortcut for the 'if (IsItemHovered(ImGuiHoveredFlags_ForTooltip) && BeginTooltip())' +// idiom. +// - SetItemTooltip() is a shortcut for the 'if (IsItemHovered(ImGuiHoveredFlags_ForTooltip)) { SetTooltip(...); }' +// idiom. +// - Where 'ImGuiHoveredFlags_ForTooltip' itself is a shortcut to use 'style.HoverFlagsForTooltipMouse' or +// 'style.HoverFlagsForTooltipNav' depending on active input type. For mouse it defaults to +// 'ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort'. +IMGUI_API bool BeginItemTooltip(); // begin/append a tooltip window if preceding item was hovered. +IMGUI_API void SetItemTooltip(const char *fmt, ...) + IM_FMTARGS(1); // set a text-only tooltip if preceding item was hovered. override any previous call to SetTooltip(). +IMGUI_API void SetItemTooltipV(const char *fmt, va_list args) IM_FMTLIST(1); - // Popups, Modals - // - They block normal mouse hovering detection (and therefore most mouse interactions) behind them. - // - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE. - // - Their visibility state (~bool) is held internally instead of being held by the programmer as we are used to with regular Begin*() calls. - // - The 3 properties above are related: we need to retain popup visibility state in the library because popups may be closed as any time. - // - You can bypass the hovering restriction by using ImGuiHoveredFlags_AllowWhenBlockedByPopup when calling IsItemHovered() or IsWindowHovered(). - // - IMPORTANT: Popup identifiers are relative to the current ID stack, so OpenPopup and BeginPopup generally needs to be at the same level of the stack. - // This is sometimes leading to confusing mistakes. May rework this in the future. - // - BeginPopup(): query popup state, if open start appending into the window. Call EndPopup() afterwards if returned true. ImGuiWindowFlags are forwarded to the window. - // - BeginPopupModal(): block every interaction behind the window, cannot be closed by user, add a dimming background, has a title bar. - IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it. - IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // return true if the modal is open, and you can start outputting to it. - IMGUI_API void EndPopup(); // only call EndPopup() if BeginPopupXXX() returns true! +// Popups, Modals +// - They block normal mouse hovering detection (and therefore most mouse interactions) behind them. +// - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE. +// - Their visibility state (~bool) is held internally instead of being held by the programmer as we are used to with +// regular Begin*() calls. +// - The 3 properties above are related: we need to retain popup visibility state in the library because popups may be +// closed as any time. +// - You can bypass the hovering restriction by using ImGuiHoveredFlags_AllowWhenBlockedByPopup when calling +// IsItemHovered() or IsWindowHovered(). +// - IMPORTANT: Popup identifiers are relative to the current ID stack, so OpenPopup and BeginPopup generally needs to +// be at the same level of the stack. +// This is sometimes leading to confusing mistakes. May rework this in the future. +// - BeginPopup(): query popup state, if open start appending into the window. Call EndPopup() afterwards if returned +// true. ImGuiWindowFlags are forwarded to the window. +// - BeginPopupModal(): block every interaction behind the window, cannot be closed by user, add a dimming background, +// has a title bar. +IMGUI_API bool BeginPopup( + const char *str_id, + ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it. +IMGUI_API bool BeginPopupModal( + const char *name, bool *p_open = NULL, + ImGuiWindowFlags flags = 0); // return true if the modal is open, and you can start outputting to it. +IMGUI_API void EndPopup(); // only call EndPopup() if BeginPopupXXX() returns true! - // Popups: open/close functions - // - OpenPopup(): set popup state to open. ImGuiPopupFlags are available for opening options. - // - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE. - // - 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. - // - IMPORTANT: Notice that for OpenPopupOnItemClick() we exceptionally default flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter - 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 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/close functions +// - OpenPopup(): set popup state to open. ImGuiPopupFlags are available for opening options. +// - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE. +// - 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. +// - IMPORTANT: Notice that for OpenPopupOnItemClick() we exceptionally default flags to 1 (== +// ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter +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 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: Notice that 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. 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: 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: Notice that 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. 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: 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. - IMGUI_API bool IsPopupOpen(const char* str_id, ImGuiPopupFlags flags = 0); // return true if the popup is open. +// 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. +IMGUI_API bool IsPopupOpen(const char *str_id, ImGuiPopupFlags flags = 0); // return true if the popup is open. - // Tables - // - Full-featured replacement for old Columns API. - // - See Demo->Tables for demo code. See top of imgui_tables.cpp for general commentary. - // - See ImGuiTableFlags_ and ImGuiTableColumnFlags_ enums for a description of available flags. - // The typical call flow is: - // - 1. Call BeginTable(), early out if returning false. - // - 2. Optionally call TableSetupColumn() to submit column name/flags/defaults. - // - 3. Optionally call TableSetupScrollFreeze() to request scroll freezing of columns/rows. - // - 4. Optionally call TableHeadersRow() to submit a header row. Names are pulled from TableSetupColumn() data. - // - 5. Populate contents: - // - In most situations you can use TableNextRow() + TableSetColumnIndex(N) to start appending into a column. - // - If you are using tables as a sort of grid, where every column is holding the same type of contents, - // you may prefer using TableNextColumn() instead of TableNextRow() + TableSetColumnIndex(). - // TableNextColumn() will automatically wrap-around into the next row if needed. - // - IMPORTANT: Comparatively to the old Columns() API, we need to call TableNextColumn() for the first column! - // - Summary of possible call flow: - // - TableNextRow() -> TableSetColumnIndex(0) -> Text("Hello 0") -> TableSetColumnIndex(1) -> Text("Hello 1") // OK - // - TableNextRow() -> TableNextColumn() -> Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // OK - // - TableNextColumn() -> Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // OK: TableNextColumn() automatically gets to next row! - // - TableNextRow() -> Text("Hello 0") // Not OK! Missing TableSetColumnIndex() or TableNextColumn()! Text will not appear! - // - 5. Call EndTable() - IMGUI_API bool BeginTable(const char* str_id, int columns, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0.0f, 0.0f), float inner_width = 0.0f); - IMGUI_API void EndTable(); // only call EndTable() if BeginTable() returns true! - IMGUI_API void TableNextRow(ImGuiTableRowFlags row_flags = 0, float min_row_height = 0.0f); // append into the first cell of a new row. - IMGUI_API bool TableNextColumn(); // append into the next column (or first column of next row if currently in last column). Return true when column is visible. - IMGUI_API bool TableSetColumnIndex(int column_n); // append into the specified column. Return true when column is visible. +// Tables +// - Full-featured replacement for old Columns API. +// - See Demo->Tables for demo code. See top of imgui_tables.cpp for general commentary. +// - See ImGuiTableFlags_ and ImGuiTableColumnFlags_ enums for a description of available flags. +// The typical call flow is: +// - 1. Call BeginTable(), early out if returning false. +// - 2. Optionally call TableSetupColumn() to submit column name/flags/defaults. +// - 3. Optionally call TableSetupScrollFreeze() to request scroll freezing of columns/rows. +// - 4. Optionally call TableHeadersRow() to submit a header row. Names are pulled from TableSetupColumn() data. +// - 5. Populate contents: +// - In most situations you can use TableNextRow() + TableSetColumnIndex(N) to start appending into a column. +// - If you are using tables as a sort of grid, where every column is holding the same type of contents, +// you may prefer using TableNextColumn() instead of TableNextRow() + TableSetColumnIndex(). +// TableNextColumn() will automatically wrap-around into the next row if needed. +// - IMPORTANT: Comparatively to the old Columns() API, we need to call TableNextColumn() for the first column! +// - Summary of possible call flow: +// - TableNextRow() -> TableSetColumnIndex(0) -> Text("Hello 0") -> TableSetColumnIndex(1) -> Text("Hello 1") // +// OK +// - TableNextRow() -> TableNextColumn() -> Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // +// OK +// - TableNextColumn() -> Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // +// OK: TableNextColumn() automatically gets to next row! +// - TableNextRow() -> Text("Hello 0") // +// Not OK! Missing TableSetColumnIndex() or TableNextColumn()! Text will not appear! +// - 5. Call EndTable() +IMGUI_API bool BeginTable(const char *str_id, int columns, ImGuiTableFlags flags = 0, + const ImVec2 &outer_size = ImVec2(0.0f, 0.0f), float inner_width = 0.0f); +IMGUI_API void EndTable(); // only call EndTable() if BeginTable() returns true! +IMGUI_API void TableNextRow(ImGuiTableRowFlags row_flags = 0, + float min_row_height = 0.0f); // append into the first cell of a new row. +IMGUI_API bool TableNextColumn(); // append into the next column (or first column of next row if currently in last + // column). Return true when column is visible. +IMGUI_API bool TableSetColumnIndex( + int column_n); // append into the specified column. Return true when column is visible. - // Tables: Headers & Columns declaration - // - Use TableSetupColumn() to specify label, resizing policy, default width/weight, id, various other flags etc. - // - Use TableHeadersRow() to create a header row and automatically submit a TableHeader() for each column. - // Headers are required to perform: reordering, sorting, and opening the context menu. - // The context menu can also be made available in columns body using ImGuiTableFlags_ContextMenuInBody. - // - 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, ImGuiID user_id = 0); - IMGUI_API void TableSetupScrollFreeze(int cols, int rows); // lock columns/rows so they stay visible when scrolled. - IMGUI_API void TableHeader(const char* label); // submit one header cell manually (rarely used) - IMGUI_API void TableHeadersRow(); // submit a row with headers cells based on data provided to TableSetupColumn() + submit context menu - IMGUI_API void TableAngledHeadersRow(); // submit a row with angled headers for every column with the ImGuiTableColumnFlags_AngledHeader flag. MUST BE FIRST ROW. +// Tables: Headers & Columns declaration +// - Use TableSetupColumn() to specify label, resizing policy, default width/weight, id, various other flags etc. +// - Use TableHeadersRow() to create a header row and automatically submit a TableHeader() for each column. +// Headers are required to perform: reordering, sorting, and opening the context menu. +// The context menu can also be made available in columns body using ImGuiTableFlags_ContextMenuInBody. +// - 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, + ImGuiID user_id = 0); +IMGUI_API void TableSetupScrollFreeze(int cols, int rows); // lock columns/rows so they stay visible when scrolled. +IMGUI_API void TableHeader(const char *label); // submit one header cell manually (rarely used) +IMGUI_API void TableHeadersRow(); // submit a row with headers cells based on data provided to TableSetupColumn() + + // submit context menu +IMGUI_API void TableAngledHeadersRow(); // submit a row with angled headers for every column with the + // ImGuiTableColumnFlags_AngledHeader flag. MUST BE FIRST ROW. - // Tables: Sorting & Miscellaneous functions - // - Sorting: call TableGetSortSpecs() to retrieve latest sort specs for the table. NULL when not sorting. - // When 'sort_specs->SpecsDirty == true' you should sort your data. It will be true when sorting specs have - // changed since last call, or the first time. Make sure to set 'SpecsDirty = false' after sorting, - // else you may wastefully sort your data every frame! - // - Functions args 'int column_n' treat the default value of -1 as the same as passing the current column index. - IMGUI_API ImGuiTableSortSpecs* TableGetSortSpecs(); // get latest sort specs for the table (NULL if not sorting). Lifetime: don't hold on this pointer over multiple frames or past any subsequent call to BeginTable(). - IMGUI_API int TableGetColumnCount(); // return number of columns (value passed to BeginTable) - IMGUI_API int TableGetColumnIndex(); // return current column index. - 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 user accessible enabled/disabled state of a column. Set to false to hide the column. 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 int TableGetHoveredColumn(); // 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. Can also use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead. - 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. +// Tables: Sorting & Miscellaneous functions +// - Sorting: call TableGetSortSpecs() to retrieve latest sort specs for the table. NULL when not sorting. +// When 'sort_specs->SpecsDirty == true' you should sort your data. It will be true when sorting specs have +// changed since last call, or the first time. Make sure to set 'SpecsDirty = false' after sorting, +// else you may wastefully sort your data every frame! +// - Functions args 'int column_n' treat the default value of -1 as the same as passing the current column index. +IMGUI_API ImGuiTableSortSpecs *TableGetSortSpecs(); // get latest sort specs for the table (NULL if not sorting). + // Lifetime: don't hold on this pointer over multiple frames or past + // any subsequent call to BeginTable(). +IMGUI_API int TableGetColumnCount(); // return number of columns (value passed to BeginTable) +IMGUI_API int TableGetColumnIndex(); // return current column index. +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 user accessible enabled/disabled state of a column. Set to false to hide the + // column. 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 int TableGetHoveredColumn(); // 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. + // Can also use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) + // instead. +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 (prefer using Tables!) - // - You can also use SameLine(pos_x) to mimic simplified columns. - IMGUI_API void Columns(int count = 1, const char* id = NULL, bool borders = true); - IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished - IMGUI_API int GetColumnIndex(); // get current column index - IMGUI_API float GetColumnWidth(int column_index = -1); // get column width (in pixels). pass -1 to use current column - IMGUI_API void SetColumnWidth(int column_index, float width); // set column width (in pixels). pass -1 to use current column - IMGUI_API float GetColumnOffset(int column_index = -1); // get position of column line (in pixels, from the left side of the contents region). pass -1 to use current column, otherwise 0..GetColumnsCount() inclusive. column 0 is typically 0.0f - IMGUI_API void SetColumnOffset(int column_index, float offset_x); // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column - IMGUI_API int GetColumnsCount(); +// Legacy Columns API (prefer using Tables!) +// - You can also use SameLine(pos_x) to mimic simplified columns. +IMGUI_API void Columns(int count = 1, const char *id = NULL, bool borders = true); +IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished +IMGUI_API int GetColumnIndex(); // get current column index +IMGUI_API float GetColumnWidth(int column_index = -1); // get column width (in pixels). pass -1 to use current column +IMGUI_API void SetColumnWidth(int column_index, + float width); // set column width (in pixels). pass -1 to use current column +IMGUI_API float GetColumnOffset( + int column_index = + -1); // get position of column line (in pixels, from the left side of the contents region). pass -1 to use + // current column, otherwise 0..GetColumnsCount() inclusive. column 0 is typically 0.0f +IMGUI_API void SetColumnOffset(int column_index, + float offset_x); // set position of column line (in pixels, from the left side of the + // contents region). pass -1 to use current column +IMGUI_API int GetColumnsCount(); - // Tab Bars, Tabs - // - Note: Tabs are automatically created by the docking system (when in 'docking' branch). Use this to create tab bars/tabs yourself. - IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar - IMGUI_API void EndTabBar(); // only call EndTabBar() if BeginTabBar() returns true! - IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0); // create a Tab. Returns true if the Tab is selected. - IMGUI_API void EndTabItem(); // only call EndTabItem() if BeginTabItem() returns true! - IMGUI_API bool TabItemButton(const char* label, ImGuiTabItemFlags flags = 0); // create a Tab behaving like a button. return true when clicked. cannot be selected in the tab bar. - IMGUI_API void SetTabItemClosed(const char* tab_or_docked_window_label); // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name. +// Tab Bars, Tabs +// - Note: Tabs are automatically created by the docking system (when in 'docking' branch). Use this to create tab +// bars/tabs yourself. +IMGUI_API bool BeginTabBar(const char *str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar +IMGUI_API void EndTabBar(); // only call EndTabBar() if BeginTabBar() returns true! +IMGUI_API bool BeginTabItem(const char *label, bool *p_open = NULL, + ImGuiTabItemFlags flags = 0); // create a Tab. Returns true if the Tab is selected. +IMGUI_API void EndTabItem(); // only call EndTabItem() if BeginTabItem() returns true! +IMGUI_API bool TabItemButton(const char *label, + ImGuiTabItemFlags flags = 0); // create a Tab behaving like a button. return true when + // clicked. cannot be selected in the tab bar. +IMGUI_API void SetTabItemClosed( + const char + *tab_or_docked_window_label); // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce + // visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() + // and before Tab submissions. Otherwise call with a window name. - // Logging/Capture - // - All text output from the interface can be captured into tty/file/clipboard. By default, tree nodes are automatically opened during logging. - IMGUI_API void LogToTTY(int auto_open_depth = -1); // start logging to tty (stdout) - IMGUI_API void LogToFile(int auto_open_depth = -1, const char* filename = NULL); // start logging to file - IMGUI_API void LogToClipboard(int auto_open_depth = -1); // start logging to OS clipboard - 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); +// Logging/Capture +// - All text output from the interface can be captured into tty/file/clipboard. By default, tree nodes are +// automatically opened during logging. +IMGUI_API void LogToTTY(int auto_open_depth = -1); // start logging to tty (stdout) +IMGUI_API void LogToFile(int auto_open_depth = -1, const char *filename = NULL); // start logging to file +IMGUI_API void LogToClipboard(int auto_open_depth = -1); // start logging to OS clipboard +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 - // - 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. Return true when payload has been accepted. - 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() - IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released. - IMGUI_API void EndDragDropTarget(); // only call EndDragDropTarget() if BeginDragDropTarget() returns true! - IMGUI_API const ImGuiPayload* GetDragDropPayload(); // peek directly into the current payload from anywhere. returns NULL when drag and drop is finished or inactive. use ImGuiPayload::IsDataType() to test for the payload type. +// Drag and Drop +// - 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. Return true when payload has been accepted. +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() +IMGUI_API const ImGuiPayload *AcceptDragDropPayload( + const char *type, + ImGuiDragDropFlags flags = 0); // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set + // you can peek into the payload before the mouse button is released. +IMGUI_API void EndDragDropTarget(); // only call EndDragDropTarget() if BeginDragDropTarget() returns true! +IMGUI_API const ImGuiPayload *GetDragDropPayload(); // peek directly into the current payload from anywhere. returns + // NULL when drag and drop is finished or inactive. use + // ImGuiPayload::IsDataType() to test for the payload type. - // Disabling [BETA API] - // - Disable all user interactions and dim items visuals (applying style.DisabledAlpha over current colors) - // - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled) - // - Tooltips windows by exception are opted out of disabling. - // - BeginDisabled(false)/EndDisabled() essentially does nothing but is provided to facilitate use of boolean expressions (as a micro-optimization: if you have tens of thousands of BeginDisabled(false)/EndDisabled() pairs, you might want to reformulate your code to avoid making those calls) - IMGUI_API void BeginDisabled(bool disabled = true); - IMGUI_API void EndDisabled(); +// Disabling [BETA API] +// - Disable all user interactions and dim items visuals (applying style.DisabledAlpha over current colors) +// - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in +// the stack is enough to keep everything disabled) +// - Tooltips windows by exception are opted out of disabling. +// - BeginDisabled(false)/EndDisabled() essentially does nothing but is provided to facilitate use of boolean +// expressions (as a micro-optimization: if you have tens of thousands of BeginDisabled(false)/EndDisabled() pairs, you +// might want to reformulate your code to avoid making those calls) +IMGUI_API void BeginDisabled(bool disabled = true); +IMGUI_API void EndDisabled(); - // Clipping - // - Mouse hovering is affected by ImGui::PushClipRect() calls, unlike direct calls to ImDrawList::PushClipRect() which are render only. - IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect); - IMGUI_API void PopClipRect(); +// Clipping +// - Mouse hovering is affected by ImGui::PushClipRect() calls, unlike direct calls to ImDrawList::PushClipRect() which +// are render only. +IMGUI_API void PushClipRect(const ImVec2 &clip_rect_min, const ImVec2 &clip_rect_max, + bool intersect_with_current_clip_rect); +IMGUI_API void PopClipRect(); - // Focus, Activation - IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a newly appearing 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. +// Focus, Activation +IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a newly appearing 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. - // Keyboard/Gamepad Navigation - IMGUI_API void SetNavCursorVisible(bool visible); // alter visibility of keyboard/gamepad cursor. by default: show when using an arrow key, hide when clicking with mouse. +// Keyboard/Gamepad Navigation +IMGUI_API void SetNavCursorVisible(bool visible); // alter visibility of keyboard/gamepad cursor. by default: show when + // using an arrow key, hide when clicking with mouse. - // Overlapping mode - IMGUI_API void SetNextItemAllowOverlap(); // allow next item to be overlapped by a subsequent item. Useful with invisible buttons, selectable, treenode covering an area where subsequent items may need to be added. Note that both Selectable() and TreeNode() have dedicated flags doing this. +// Overlapping mode +IMGUI_API void SetNextItemAllowOverlap(); // allow next item to be overlapped by a subsequent item. Useful with + // invisible buttons, selectable, treenode covering an area where subsequent + // items may need to be added. Note that both Selectable() and TreeNode() have + // dedicated flags doing this. - // 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 hovered and mouse clicked on? (**) == IsMouseClicked(mouse_button) && IsItemHovered()Important. (**) this is 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). - IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active). Useful for Undo/Redo patterns with widgets that require continuous editing. - IMGUI_API bool IsItemDeactivatedAfterEdit(); // was the last item just made inactive and made a value change when it was active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with widgets that require continuous editing. Note that you may get false positives (some widgets such as Combo()/ListBox()/Selectable() will return true even when clicking an already selected item). - IMGUI_API bool IsItemToggledOpen(); // was the last item open state toggled? set by TreeNode(). - IMGUI_API bool IsAnyItemHovered(); // is any item hovered? - IMGUI_API bool IsAnyItemActive(); // is any item active? - IMGUI_API bool IsAnyItemFocused(); // is any item focused? - IMGUI_API ImGuiID GetItemID(); // get ID of last item (~~ often same ImGui::GetID(label) beforehand) - IMGUI_API ImVec2 GetItemRectMin(); // get upper-left bounding rectangle of the last item (screen space) - IMGUI_API ImVec2 GetItemRectMax(); // get lower-right bounding rectangle of the last item (screen space) - IMGUI_API ImVec2 GetItemRectSize(); // get size of last item +// 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 hovered and mouse clicked on? (**) == IsMouseClicked(mouse_button) && + // IsItemHovered()Important. (**) this is 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). +IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active). Useful for + // Undo/Redo patterns with widgets that require continuous editing. +IMGUI_API bool IsItemDeactivatedAfterEdit(); // was the last item just made inactive and made a value change when it was + // active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with + // widgets that require continuous editing. Note that you may get false + // positives (some widgets such as Combo()/ListBox()/Selectable() will + // return true even when clicking an already selected item). +IMGUI_API bool IsItemToggledOpen(); // was the last item open state toggled? set by TreeNode(). +IMGUI_API bool IsAnyItemHovered(); // is any item hovered? +IMGUI_API bool IsAnyItemActive(); // is any item active? +IMGUI_API bool IsAnyItemFocused(); // is any item focused? +IMGUI_API ImGuiID GetItemID(); // get ID of last item (~~ often same ImGui::GetID(label) beforehand) +IMGUI_API ImVec2 GetItemRectMin(); // get upper-left bounding rectangle of the last item (screen space) +IMGUI_API ImVec2 GetItemRectMax(); // get lower-right bounding rectangle of the last item (screen space) +IMGUI_API ImVec2 GetItemRectSize(); // get size of last item - // Viewports - // - 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. This can never be NULL. +// Viewports +// - 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. This can never be NULL. - // Background/Foreground Draw Lists - IMGUI_API ImDrawList* GetBackgroundDrawList(); // this draw list will be the first rendered one. Useful to quickly draw shapes/text behind dear imgui contents. - IMGUI_API ImDrawList* GetForegroundDrawList(); // this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. +// Background/Foreground Draw Lists +IMGUI_API ImDrawList *GetBackgroundDrawList(); // this draw list will be the first rendered one. Useful to quickly draw + // shapes/text behind dear imgui contents. +IMGUI_API ImDrawList *GetForegroundDrawList(); // this draw list will be the last rendered one. Useful to quickly draw + // shapes/text over dear imgui contents. - // Miscellaneous Utilities - IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped. - IMGUI_API bool IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max); // test if rectangle (in screen space) is visible / not clipped. to perform coarse clipping on user's side. - IMGUI_API double GetTime(); // get global imgui time. incremented by io.DeltaTime every frame. - IMGUI_API int GetFrameCount(); // get global imgui frame count. incremented by 1 every frame. - IMGUI_API ImDrawListSharedData* GetDrawListSharedData(); // you may use this when creating your own ImDrawList instances. - IMGUI_API const char* GetStyleColorName(ImGuiCol idx); // get a string corresponding to the enum value (for display, saving, etc.). - IMGUI_API void SetStateStorage(ImGuiStorage* storage); // replace current window storage with our own (if you want to manipulate it yourself, typically clear subsection of it) - IMGUI_API ImGuiStorage* GetStateStorage(); +// Miscellaneous Utilities +IMGUI_API bool IsRectVisible( + const ImVec2 &size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped. +IMGUI_API bool IsRectVisible(const ImVec2 &rect_min, + const ImVec2 &rect_max); // test if rectangle (in screen space) is visible / not clipped. + // to perform coarse clipping on user's side. +IMGUI_API double GetTime(); // get global imgui time. incremented by io.DeltaTime every frame. +IMGUI_API int GetFrameCount(); // get global imgui frame count. incremented by 1 every frame. +IMGUI_API ImDrawListSharedData *GetDrawListSharedData(); // you may use this when creating your own ImDrawList + // instances. +IMGUI_API const char *GetStyleColorName( + ImGuiCol idx); // get a string corresponding to the enum value (for display, saving, etc.). +IMGUI_API void SetStateStorage(ImGuiStorage *storage); // replace current window storage with our own (if you want to + // manipulate it yourself, typically clear subsection of it) +IMGUI_API ImGuiStorage *GetStateStorage(); - // Text Utilities - IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); +// Text Utilities +IMGUI_API ImVec2 CalcTextSize(const char *text, const char *text_end = NULL, bool hide_text_after_double_hash = false, + float wrap_width = -1.0f); - // Color Utilities - IMGUI_API ImVec4 ColorConvertU32ToFloat4(ImU32 in); - IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4& in); - IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v); - IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b); +// Color Utilities +IMGUI_API ImVec4 ColorConvertU32ToFloat4(ImU32 in); +IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4 &in); +IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float &out_h, float &out_s, float &out_v); +IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float &out_r, float &out_g, float &out_b); - // Inputs Utilities: Keyboard/Mouse/Gamepad - // - the ImGuiKey enum contains all possible keyboard, mouse and gamepad inputs (e.g. ImGuiKey_A, ImGuiKey_MouseLeft, ImGuiKey_GamepadDpadUp...). - // - (legacy: before v1.87, we used ImGuiKey to carry native/user indices as defined by each backends. This was obsoleted in 1.87 (2022-02) and completely removed in 1.91.5 (2024-11). See https://github.com/ocornut/imgui/issues/4921) - // - (legacy: any use of ImGuiKey will assert when key < 512 to detect passing legacy native/user indices) - IMGUI_API bool IsKeyDown(ImGuiKey key); // is key being held. - IMGUI_API bool IsKeyPressed(ImGuiKey key, bool repeat = true); // was key pressed (went from !Down to Down)? if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate - IMGUI_API bool IsKeyReleased(ImGuiKey key); // was key released (went from Down to !Down)? - IMGUI_API bool IsKeyChordPressed(ImGuiKeyChord key_chord); // was key chord (mods + key) pressed, e.g. you can pass 'ImGuiMod_Ctrl | ImGuiKey_S' as a key-chord. This doesn't do any routing or focus check, please consider using Shortcut() function instead. - IMGUI_API int GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate - IMGUI_API const char* GetKeyName(ImGuiKey key); // [DEBUG] returns English name of the key. Those names are provided for debugging purpose and are not meant to be saved persistently nor compared. - IMGUI_API void SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard); // Override io.WantCaptureKeyboard flag next frame (said flag is left for your application to handle, typically when true it instructs your app to ignore inputs). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard"; after the next NewFrame() call. +// Inputs Utilities: Keyboard/Mouse/Gamepad +// - the ImGuiKey enum contains all possible keyboard, mouse and gamepad inputs (e.g. ImGuiKey_A, ImGuiKey_MouseLeft, +// ImGuiKey_GamepadDpadUp...). +// - (legacy: before v1.87, we used ImGuiKey to carry native/user indices as defined by each backends. This was +// obsoleted in 1.87 (2022-02) and completely removed in 1.91.5 (2024-11). See +// https://github.com/ocornut/imgui/issues/4921) +// - (legacy: any use of ImGuiKey will assert when key < 512 to detect passing legacy native/user indices) +IMGUI_API bool IsKeyDown(ImGuiKey key); // is key being held. +IMGUI_API bool IsKeyPressed(ImGuiKey key, bool repeat = true); // was key pressed (went from !Down to Down)? if + // repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate +IMGUI_API bool IsKeyReleased(ImGuiKey key); // was key released (went from Down to !Down)? +IMGUI_API bool IsKeyChordPressed( + ImGuiKeyChord key_chord); // was key chord (mods + key) pressed, e.g. you can pass 'ImGuiMod_Ctrl | ImGuiKey_S' as a + // key-chord. This doesn't do any routing or focus check, please consider using Shortcut() + // function instead. +IMGUI_API int GetKeyPressedAmount(ImGuiKey key, float repeat_delay, + float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but + // might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate +IMGUI_API const char *GetKeyName( + ImGuiKey key); // [DEBUG] returns English name of the key. Those names are provided for debugging purpose and are + // not meant to be saved persistently nor compared. +IMGUI_API void SetNextFrameWantCaptureKeyboard( + bool want_capture_keyboard); // Override io.WantCaptureKeyboard flag next frame (said flag is left for your + // application to handle, typically when true it instructs your app to ignore inputs). + // e.g. force capture keyboard when your widget is being hovered. This is equivalent to + // setting "io.WantCaptureKeyboard = want_capture_keyboard"; after the next NewFrame() + // call. - // Inputs Utilities: Shortcut Testing & Routing [BETA] - // - ImGuiKeyChord = a ImGuiKey + optional ImGuiMod_Alt/ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Super. - // ImGuiKey_C // Accepted by functions taking ImGuiKey or ImGuiKeyChord arguments) - // ImGuiMod_Ctrl | ImGuiKey_C // Accepted by functions taking ImGuiKeyChord arguments) - // only ImGuiMod_XXX values are legal to combine with an ImGuiKey. You CANNOT combine two ImGuiKey values. - // - The general idea is that several callers may register interest in a shortcut, and only one owner gets it. - // Parent -> call Shortcut(Ctrl+S) // When Parent is focused, Parent gets the shortcut. - // Child1 -> call Shortcut(Ctrl+S) // When Child1 is focused, Child1 gets the shortcut (Child1 overrides Parent shortcuts) - // Child2 -> no call // When Child2 is focused, Parent gets the shortcut. - // The whole system is order independent, so if Child1 makes its calls before Parent, results will be identical. - // This is an important property as it facilitate working with foreign code or larger codebase. - // - To understand the difference: - // - IsKeyChordPressed() compares mods and call IsKeyPressed() -> function has no side-effect. - // - Shortcut() submits a route, routes are resolved, if it currently can be routed it calls IsKeyChordPressed() -> function has (desirable) side-effects as it can prevents another call from getting the route. - // - Visualize registered routes in 'Metrics/Debugger->Inputs'. - IMGUI_API bool Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags = 0); - IMGUI_API void SetNextItemShortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags = 0); +// Inputs Utilities: Shortcut Testing & Routing [BETA] +// - ImGuiKeyChord = a ImGuiKey + optional ImGuiMod_Alt/ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Super. +// ImGuiKey_C // Accepted by functions taking ImGuiKey or ImGuiKeyChord arguments) +// ImGuiMod_Ctrl | ImGuiKey_C // Accepted by functions taking ImGuiKeyChord arguments) +// only ImGuiMod_XXX values are legal to combine with an ImGuiKey. You CANNOT combine two ImGuiKey values. +// - The general idea is that several callers may register interest in a shortcut, and only one owner gets it. +// Parent -> call Shortcut(Ctrl+S) // When Parent is focused, Parent gets the shortcut. +// Child1 -> call Shortcut(Ctrl+S) // When Child1 is focused, Child1 gets the shortcut (Child1 overrides +// Parent shortcuts) Child2 -> no call // When Child2 is focused, Parent gets the shortcut. +// The whole system is order independent, so if Child1 makes its calls before Parent, results will be identical. +// This is an important property as it facilitate working with foreign code or larger codebase. +// - To understand the difference: +// - IsKeyChordPressed() compares mods and call IsKeyPressed() -> function has no side-effect. +// - Shortcut() submits a route, routes are resolved, if it currently can be routed it calls IsKeyChordPressed() -> +// function has (desirable) side-effects as it can prevents another call from getting the route. +// - Visualize registered routes in 'Metrics/Debugger->Inputs'. +IMGUI_API bool Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags = 0); +IMGUI_API void SetNextItemShortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags = 0); - // Inputs Utilities: Key/Input Ownership [BETA] - // - One common use case would be to allow your items to disable standard inputs behaviors such - // as Tab or Alt key handling, Mouse Wheel scrolling, etc. - // e.g. Button(...); SetItemKeyOwner(ImGuiKey_MouseWheelY); to make hovering/activating a button disable wheel for scrolling. - // - Reminder ImGuiKey enum include access to mouse buttons and gamepad, so key ownership can apply to them. - // - Many related features are still in imgui_internal.h. For instance, most IsKeyXXX()/IsMouseXXX() functions have an owner-id-aware version. - IMGUI_API void SetItemKeyOwner(ImGuiKey key); // Set key owner to last item ID if it is hovered or active. Equivalent to 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(key, GetItemID());'. +// Inputs Utilities: Key/Input Ownership [BETA] +// - One common use case would be to allow your items to disable standard inputs behaviors such +// as Tab or Alt key handling, Mouse Wheel scrolling, etc. +// e.g. Button(...); SetItemKeyOwner(ImGuiKey_MouseWheelY); to make hovering/activating a button disable wheel for +// scrolling. +// - Reminder ImGuiKey enum include access to mouse buttons and gamepad, so key ownership can apply to them. +// - Many related features are still in imgui_internal.h. For instance, most IsKeyXXX()/IsMouseXXX() functions have an +// owner-id-aware version. +IMGUI_API void SetItemKeyOwner( + ImGuiKey key); // Set key owner to last item ID if it is hovered or active. Equivalent to 'if (IsItemHovered() || + // IsItemActive()) { SetKeyOwner(key, GetItemID());'. - // Inputs Utilities: Mouse - // - To refer to a mouse button, you may use named enums in your code e.g. ImGuiMouseButton_Left, ImGuiMouseButton_Right. - // - You can also use regular integer: it is forever guaranteed that 0=Left, 1=Right, 2=Middle. - // - Dragging operations are only reported after mouse has moved a certain distance away from the initial clicking position (see 'lock_threshold' and 'io.MouseDraggingThreshold') - IMGUI_API bool IsMouseDown(ImGuiMouseButton button); // is mouse button held? - IMGUI_API bool IsMouseClicked(ImGuiMouseButton button, bool repeat = false); // did mouse button clicked? (went from !Down to Down). Same as GetMouseClickedCount() == 1. - IMGUI_API bool IsMouseReleased(ImGuiMouseButton button); // did mouse button released? (went from Down to !Down) - IMGUI_API bool IsMouseDoubleClicked(ImGuiMouseButton button); // did mouse button double-clicked? Same as GetMouseClickedCount() == 2. (note that a double-click will also report IsMouseClicked() == true) - IMGUI_API bool IsMouseReleasedWithDelay(ImGuiMouseButton button, float delay); // delayed mouse release (use very sparingly!). Generally used with 'delay >= io.MouseDoubleClickTime' + combined with a 'io.MouseClickedLastCount==1' test. This is a very rarely used UI idiom, but some apps use this: e.g. MS Explorer single click on an icon to rename. - IMGUI_API int GetMouseClickedCount(ImGuiMouseButton button); // return the number of successive mouse-clicks at the time where a click happen (otherwise 0). - IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true);// is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block. - IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); // by convention we use (-FLT_MAX,-FLT_MAX) to denote that there is no mouse available - IMGUI_API bool IsAnyMouseDown(); // [WILL OBSOLETE] is any mouse button held? This was designed for backends, but prefer having backend maintain a mask of held mouse buttons, because upcoming input queue system will make this invalid. - IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls - IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve mouse position at the time of opening popup we have BeginPopup() into (helper to avoid user backing that value themselves) - IMGUI_API bool IsMouseDragging(ImGuiMouseButton button, float lock_threshold = -1.0f); // is mouse dragging? (uses io.MouseDraggingThreshold if lock_threshold < 0.0f) - IMGUI_API ImVec2 GetMouseDragDelta(ImGuiMouseButton button = 0, float lock_threshold = -1.0f); // return the delta from the initial clicking position while the mouse button is pressed or was just released. This is locked and return 0.0f until the mouse moves past a distance threshold at least once (uses io.MouseDraggingThreshold if lock_threshold < 0.0f) - IMGUI_API void ResetMouseDragDelta(ImGuiMouseButton button = 0); // - IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired mouse cursor shape. Important: reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you - IMGUI_API void SetMouseCursor(ImGuiMouseCursor cursor_type); // set desired mouse cursor shape - IMGUI_API void SetNextFrameWantCaptureMouse(bool want_capture_mouse); // Override io.WantCaptureMouse flag next frame (said flag is left for your application to handle, typical when true it instructs your app to ignore inputs). This is equivalent to setting "io.WantCaptureMouse = want_capture_mouse;" after the next NewFrame() call. +// Inputs Utilities: Mouse +// - To refer to a mouse button, you may use named enums in your code e.g. ImGuiMouseButton_Left, +// ImGuiMouseButton_Right. +// - You can also use regular integer: it is forever guaranteed that 0=Left, 1=Right, 2=Middle. +// - Dragging operations are only reported after mouse has moved a certain distance away from the initial clicking +// position (see 'lock_threshold' and 'io.MouseDraggingThreshold') +IMGUI_API bool IsMouseDown(ImGuiMouseButton button); // is mouse button held? +IMGUI_API bool IsMouseClicked( + ImGuiMouseButton button, + bool repeat = false); // did mouse button clicked? (went from !Down to Down). Same as GetMouseClickedCount() == 1. +IMGUI_API bool IsMouseReleased(ImGuiMouseButton button); // did mouse button released? (went from Down to !Down) +IMGUI_API bool IsMouseDoubleClicked( + ImGuiMouseButton button); // did mouse button double-clicked? Same as GetMouseClickedCount() == 2. (note that a + // double-click will also report IsMouseClicked() == true) +IMGUI_API bool IsMouseReleasedWithDelay( + ImGuiMouseButton button, + float delay); // delayed mouse release (use very sparingly!). Generally used with 'delay >= io.MouseDoubleClickTime' + // + combined with a 'io.MouseClickedLastCount==1' test. This is a very rarely used UI idiom, but some + // apps use this: e.g. MS Explorer single click on an icon to rename. +IMGUI_API int GetMouseClickedCount(ImGuiMouseButton button); // return the number of successive mouse-clicks at the time + // where a click happen (otherwise 0). +IMGUI_API bool IsMouseHoveringRect( + const ImVec2 &r_min, const ImVec2 &r_max, + bool clip = true); // is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, + // but disregarding of other consideration of focus/window ordering/popup-block. +IMGUI_API bool IsMousePosValid(const ImVec2 *mouse_pos = NULL); // by convention we use (-FLT_MAX,-FLT_MAX) to denote + // that there is no mouse available +IMGUI_API bool IsAnyMouseDown(); // [WILL OBSOLETE] is any mouse button held? This was designed for backends, but prefer + // having backend maintain a mask of held mouse buttons, because upcoming input queue + // system will make this invalid. +IMGUI_API ImVec2 +GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls +IMGUI_API ImVec2 +GetMousePosOnOpeningCurrentPopup(); // retrieve mouse position at the time of opening popup we have BeginPopup() into + // (helper to avoid user backing that value themselves) +IMGUI_API bool IsMouseDragging( + ImGuiMouseButton button, + float lock_threshold = -1.0f); // is mouse dragging? (uses io.MouseDraggingThreshold if lock_threshold < 0.0f) +IMGUI_API ImVec2 GetMouseDragDelta( + ImGuiMouseButton button = 0, + float lock_threshold = + -1.0f); // return the delta from the initial clicking position while the mouse button is pressed or was just + // released. This is locked and return 0.0f until the mouse moves past a distance threshold at least + // once (uses io.MouseDraggingThreshold if lock_threshold < 0.0f) +IMGUI_API void ResetMouseDragDelta(ImGuiMouseButton button = 0); // +IMGUI_API ImGuiMouseCursor +GetMouseCursor(); // get desired mouse cursor shape. Important: reset in ImGui::NewFrame(), this is updated during the + // frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui + // will render those for you +IMGUI_API void SetMouseCursor(ImGuiMouseCursor cursor_type); // set desired mouse cursor shape +IMGUI_API void SetNextFrameWantCaptureMouse( + bool want_capture_mouse); // Override io.WantCaptureMouse flag next frame (said flag is left for your application to + // handle, typical when true it instructs your app to ignore inputs). This is equivalent + // to setting "io.WantCaptureMouse = want_capture_mouse;" after the next NewFrame() call. - // Clipboard Utilities - // - Also see the LogToClipboard() function to capture GUI into clipboard, or easily output text data to the clipboard. - IMGUI_API const char* GetClipboardText(); - IMGUI_API void SetClipboardText(const char* text); +// Clipboard Utilities +// - Also see the LogToClipboard() function to capture GUI into clipboard, or easily output text data to the clipboard. +IMGUI_API const char *GetClipboardText(); +IMGUI_API void SetClipboardText(const char *text); - // Settings/.Ini Utilities - // - The disk functions are automatically called if io.IniFilename != NULL (default is "imgui.ini"). - // - Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini saving manually. - // - Important: default value "imgui.ini" is relative to current working dir! Most apps will want to lock this to an absolute path (e.g. same path as executables). - IMGUI_API void LoadIniSettingsFromDisk(const char* ini_filename); // call after CreateContext() and before the first call to NewFrame(). NewFrame() automatically calls LoadIniSettingsFromDisk(io.IniFilename). - IMGUI_API void LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size=0); // call after CreateContext() and before the first call to NewFrame() to provide .ini data from your own data source. - IMGUI_API void SaveIniSettingsToDisk(const char* ini_filename); // this is automatically called (if io.IniFilename is not empty) a few seconds after any modification that should be reflected in the .ini file (and also by DestroyContext). - 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. +// Settings/.Ini Utilities +// - The disk functions are automatically called if io.IniFilename != NULL (default is "imgui.ini"). +// - Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini +// saving manually. +// - Important: default value "imgui.ini" is relative to current working dir! Most apps will want to lock this to an +// absolute path (e.g. same path as executables). +IMGUI_API void LoadIniSettingsFromDisk( + const char *ini_filename); // call after CreateContext() and before the first call to NewFrame(). NewFrame() + // automatically calls LoadIniSettingsFromDisk(io.IniFilename). +IMGUI_API void LoadIniSettingsFromMemory( + const char *ini_data, size_t ini_size = 0); // call after CreateContext() and before the first call to NewFrame() to + // provide .ini data from your own data source. +IMGUI_API void SaveIniSettingsToDisk( + const char *ini_filename); // this is automatically called (if io.IniFilename is not empty) a few seconds after any + // modification that should be reflected in the .ini file (and also by DestroyContext). +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 - // - Your main debugging friend is the ShowMetricsWindow() function, which is also accessible from Demo->Tools->Metrics Debugger - IMGUI_API void DebugTextEncoding(const char* text); - IMGUI_API void DebugFlashStyleColor(ImGuiCol idx); - IMGUI_API void DebugStartItemPicker(); - 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. +// Debug Utilities +// - Your main debugging friend is the ShowMetricsWindow() function, which is also accessible from Demo->Tools->Metrics +// Debugger +IMGUI_API void DebugTextEncoding(const char *text); +IMGUI_API void DebugFlashStyleColor(ImGuiCol idx); +IMGUI_API void DebugStartItemPicker(); +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. #ifndef IMGUI_DISABLE_DEBUG_TOOLS - IMGUI_API void DebugLog(const char* fmt, ...) IM_FMTARGS(1); // Call via IMGUI_DEBUG_LOG() for maximum stripping in caller code! - IMGUI_API void DebugLogV(const char* fmt, va_list args) IM_FMTLIST(1); +IMGUI_API void DebugLog(const char *fmt, ...) + IM_FMTARGS(1); // Call via IMGUI_DEBUG_LOG() for maximum stripping in caller code! +IMGUI_API void DebugLogV(const char *fmt, va_list args) IM_FMTLIST(1); #endif - // Memory Allocators - // - 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); +// Memory Allocators +// - 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); } // namespace ImGui @@ -1135,72 +1723,109 @@ namespace ImGui //----------------------------------------------------------------------------- // Flags for ImGui::Begin() -// (Those are per-window flags. There are shared flags in ImGuiIO: io.ConfigWindowsResizeFromEdges and io.ConfigWindowsMoveFromTitleBarOnly) +// (Those are per-window flags. There are shared flags in ImGuiIO: io.ConfigWindowsResizeFromEdges and +// io.ConfigWindowsMoveFromTitleBarOnly) enum ImGuiWindowFlags_ { - ImGuiWindowFlags_None = 0, - ImGuiWindowFlags_NoTitleBar = 1 << 0, // Disable title-bar - ImGuiWindowFlags_NoResize = 1 << 1, // Disable user resizing with the lower-right grip - ImGuiWindowFlags_NoMove = 1 << 2, // Disable user moving the window - ImGuiWindowFlags_NoScrollbar = 1 << 3, // Disable scrollbars (window can still scroll with mouse or programmatically) - ImGuiWindowFlags_NoScrollWithMouse = 1 << 4, // Disable user vertically scrolling with mouse wheel. On child window, mouse wheel will be forwarded to the parent unless NoScrollbar is also set. - ImGuiWindowFlags_NoCollapse = 1 << 5, // Disable user collapsing window by double-clicking on it. Also referred to as Window Menu Button (e.g. within a docking node). - ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, // Resize every window to its content every frame - ImGuiWindowFlags_NoBackground = 1 << 7, // Disable drawing background color (WindowBg, etc.) and outside border. Similar as using SetNextWindowBgAlpha(0.0f). - ImGuiWindowFlags_NoSavedSettings = 1 << 8, // Never load/save settings in .ini file - ImGuiWindowFlags_NoMouseInputs = 1 << 9, // Disable catching mouse, hovering test with pass through. - ImGuiWindowFlags_MenuBar = 1 << 10, // Has a menu-bar - ImGuiWindowFlags_HorizontalScrollbar = 1 << 11, // Allow horizontal scrollbar to appear (off by default). You may use SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code in imgui_demo in the "Horizontal Scrolling" section. - ImGuiWindowFlags_NoFocusOnAppearing = 1 << 12, // Disable taking focus when transitioning from hidden to visible state - ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, // Disable bringing window to front when taking focus (e.g. clicking on it or programmatically giving it focus) - ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) - ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) - ImGuiWindowFlags_NoNavInputs = 1 << 16, // No keyboard/gamepad navigation within the window - ImGuiWindowFlags_NoNavFocus = 1 << 17, // No focusing toward this window with keyboard/gamepad navigation (e.g. skipped by CTRL+TAB) - ImGuiWindowFlags_UnsavedDocument = 1 << 18, // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. - ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, - ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, - ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, + ImGuiWindowFlags_None = 0, + ImGuiWindowFlags_NoTitleBar = 1 << 0, // Disable title-bar + ImGuiWindowFlags_NoResize = 1 << 1, // Disable user resizing with the lower-right grip + ImGuiWindowFlags_NoMove = 1 << 2, // Disable user moving the window + ImGuiWindowFlags_NoScrollbar = + 1 << 3, // Disable scrollbars (window can still scroll with mouse or programmatically) + ImGuiWindowFlags_NoScrollWithMouse = + 1 << 4, // Disable user vertically scrolling with mouse wheel. On child window, mouse wheel will be forwarded to + // the parent unless NoScrollbar is also set. + ImGuiWindowFlags_NoCollapse = 1 << 5, // Disable user collapsing window by double-clicking on it. Also referred to + // as Window Menu Button (e.g. within a docking node). + ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, // Resize every window to its content every frame + ImGuiWindowFlags_NoBackground = 1 << 7, // Disable drawing background color (WindowBg, etc.) and outside border. + // Similar as using SetNextWindowBgAlpha(0.0f). + ImGuiWindowFlags_NoSavedSettings = 1 << 8, // Never load/save settings in .ini file + ImGuiWindowFlags_NoMouseInputs = 1 << 9, // Disable catching mouse, hovering test with pass through. + ImGuiWindowFlags_MenuBar = 1 << 10, // Has a menu-bar + ImGuiWindowFlags_HorizontalScrollbar = + 1 << 11, // Allow horizontal scrollbar to appear (off by default). You may use + // SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code + // in imgui_demo in the "Horizontal Scrolling" section. + ImGuiWindowFlags_NoFocusOnAppearing = 1 + << 12, // Disable taking focus when transitioning from hidden to visible state + ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, // Disable bringing window to front when taking focus (e.g. + // clicking on it or programmatically giving it focus) + ImGuiWindowFlags_AlwaysVerticalScrollbar = 1 + << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) + ImGuiWindowFlags_AlwaysHorizontalScrollbar = + 1 << 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) + ImGuiWindowFlags_NoNavInputs = 1 << 16, // No keyboard/gamepad navigation within the window + ImGuiWindowFlags_NoNavFocus = + 1 << 17, // No focusing toward this window with keyboard/gamepad navigation (e.g. skipped by CTRL+TAB) + ImGuiWindowFlags_UnsavedDocument = + 1 << 18, // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking + // the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is + // assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. + ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, + ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, + ImGuiWindowFlags_NoInputs = + ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, // [Internal] - ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild() - ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip() - ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup() - ImGuiWindowFlags_Modal = 1 << 27, // Don't use! For internal use by BeginPopupModal() - ImGuiWindowFlags_ChildMenu = 1 << 28, // Don't use! For internal use by BeginMenu() + ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild() + ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip() + ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup() + ImGuiWindowFlags_Modal = 1 << 27, // Don't use! For internal use by BeginPopupModal() + ImGuiWindowFlags_ChildMenu = 1 << 28, // Don't use! For internal use by BeginMenu() // Obsolete names #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImGuiWindowFlags_NavFlattened = 1 << 29, // Obsoleted in 1.90.9: Use ImGuiChildFlags_NavFlattened in BeginChild() call. - ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 30, // Obsoleted in 1.90.0: Use ImGuiChildFlags_AlwaysUseWindowPadding in BeginChild() call. + ImGuiWindowFlags_NavFlattened = + 1 << 29, // Obsoleted in 1.90.9: Use ImGuiChildFlags_NavFlattened in BeginChild() call. + ImGuiWindowFlags_AlwaysUseWindowPadding = + 1 << 30, // Obsoleted in 1.90.0: Use ImGuiChildFlags_AlwaysUseWindowPadding in BeginChild() call. #endif }; // Flags for ImGui::BeginChild() -// (Legacy: bit 0 must always correspond to ImGuiChildFlags_Borders to be backward compatible with old API using 'bool border = false'. -// About using AutoResizeX/AutoResizeY flags: -// - May be combined with SetNextWindowSizeConstraints() to set a min/max size for each axis (see "Demo->Child->Auto-resize with Constraints"). -// - Size measurement for a given axis is only performed when the child window is within visible boundaries, or is just appearing. -// - This allows BeginChild() to return false when not within boundaries (e.g. when scrolling), which is more optimal. BUT it won't update its auto-size while clipped. -// While not perfect, it is a better default behavior as the always-on performance gain is more valuable than the occasional "resizing after becoming visible again" glitch. +// (Legacy: bit 0 must always correspond to ImGuiChildFlags_Borders to be backward compatible with old API using 'bool +// border = false'. About using AutoResizeX/AutoResizeY flags: +// - May be combined with SetNextWindowSizeConstraints() to set a min/max size for each axis (see +// "Demo->Child->Auto-resize with Constraints"). +// - Size measurement for a given axis is only performed when the child window is within visible boundaries, or is just +// appearing. +// - This allows BeginChild() to return false when not within boundaries (e.g. when scrolling), which is more optimal. +// BUT it won't update its auto-size while clipped. +// While not perfect, it is a better default behavior as the always-on performance gain is more valuable than the +// occasional "resizing after becoming visible again" glitch. // - You may also use ImGuiChildFlags_AlwaysAutoResize to force an update even when child window is not in view. -// HOWEVER PLEASE UNDERSTAND THAT DOING SO WILL PREVENT BeginChild() FROM EVER RETURNING FALSE, disabling benefits of coarse clipping. +// HOWEVER PLEASE UNDERSTAND THAT DOING SO WILL PREVENT BeginChild() FROM EVER RETURNING FALSE, disabling benefits +// of coarse clipping. enum ImGuiChildFlags_ { - ImGuiChildFlags_None = 0, - ImGuiChildFlags_Borders = 1 << 0, // Show an outer border and enable WindowPadding. (IMPORTANT: this is always == 1 == true for legacy reason) - ImGuiChildFlags_AlwaysUseWindowPadding = 1 << 1, // Pad with style.WindowPadding even if no border are drawn (no padding by default for non-bordered child windows because it makes more sense) - ImGuiChildFlags_ResizeX = 1 << 2, // Allow resize from right border (layout direction). Enable .ini saving (unless ImGuiWindowFlags_NoSavedSettings passed to window flags) - ImGuiChildFlags_ResizeY = 1 << 3, // Allow resize from bottom border (layout direction). " - ImGuiChildFlags_AutoResizeX = 1 << 4, // Enable auto-resizing width. Read "IMPORTANT: Size measurement" details above. - ImGuiChildFlags_AutoResizeY = 1 << 5, // Enable auto-resizing height. Read "IMPORTANT: Size measurement" details above. - ImGuiChildFlags_AlwaysAutoResize = 1 << 6, // Combined with AutoResizeX/AutoResizeY. Always measure size even when child is hidden, always return true, always disable clipping optimization! NOT RECOMMENDED. - ImGuiChildFlags_FrameStyle = 1 << 7, // Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding. - ImGuiChildFlags_NavFlattened = 1 << 8, // [BETA] Share focus scope, allow keyboard/gamepad navigation to cross over parent border to this child or between sibling child windows. + ImGuiChildFlags_None = 0, + ImGuiChildFlags_Borders = 1 << 0, // Show an outer border and enable WindowPadding. (IMPORTANT: this is always == 1 + // == true for legacy reason) + ImGuiChildFlags_AlwaysUseWindowPadding = + 1 << 1, // Pad with style.WindowPadding even if no border are drawn (no padding by default for non-bordered + // child windows because it makes more sense) + ImGuiChildFlags_ResizeX = 1 << 2, // Allow resize from right border (layout direction). Enable .ini saving (unless + // ImGuiWindowFlags_NoSavedSettings passed to window flags) + ImGuiChildFlags_ResizeY = 1 << 3, // Allow resize from bottom border (layout direction). " + ImGuiChildFlags_AutoResizeX = + 1 << 4, // Enable auto-resizing width. Read "IMPORTANT: Size measurement" details above. + ImGuiChildFlags_AutoResizeY = + 1 << 5, // Enable auto-resizing height. Read "IMPORTANT: Size measurement" details above. + ImGuiChildFlags_AlwaysAutoResize = + 1 << 6, // Combined with AutoResizeX/AutoResizeY. Always measure size even when child is hidden, always return + // true, always disable clipping optimization! NOT RECOMMENDED. + ImGuiChildFlags_FrameStyle = + 1 << 7, // Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding + // instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding. + ImGuiChildFlags_NavFlattened = 1 << 8, // [BETA] Share focus scope, allow keyboard/gamepad navigation to cross over + // parent border to this child or between sibling child windows. // Obsolete names #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImGuiChildFlags_Border = ImGuiChildFlags_Borders, // Renamed in 1.91.1 (August 2024) for consistency. + ImGuiChildFlags_Border = ImGuiChildFlags_Borders, // Renamed in 1.91.1 (August 2024) for consistency. #endif }; @@ -1208,314 +1833,453 @@ enum ImGuiChildFlags_ // (Those are shared by all items) enum ImGuiItemFlags_ { - ImGuiItemFlags_None = 0, // (Default) - ImGuiItemFlags_NoTabStop = 1 << 0, // false // Disable keyboard tabbing. This is a "lighter" version of ImGuiItemFlags_NoNav. - ImGuiItemFlags_NoNav = 1 << 1, // false // Disable any form of focusing (keyboard/gamepad directional navigation and SetKeyboardFocusHere() calls). - ImGuiItemFlags_NoNavDefaultFocus = 1 << 2, // false // Disable item being a candidate for default focus (e.g. used by title bar items). - ImGuiItemFlags_ButtonRepeat = 1 << 3, // false // Any button-like behavior will have repeat mode enabled (based on io.KeyRepeatDelay and io.KeyRepeatRate values). Note that you can also call IsItemActive() after any button to tell if it is being held. - ImGuiItemFlags_AutoClosePopups = 1 << 4, // true // MenuItem()/Selectable() automatically close their parent popup window. - ImGuiItemFlags_AllowDuplicateId = 1 << 5, // false // Allow submitting an item with the same identifier as an item already submitted this frame without triggering a warning tooltip if io.ConfigDebugHighlightIdConflicts is set. + ImGuiItemFlags_None = 0, // (Default) + ImGuiItemFlags_NoTabStop = + 1 << 0, // false // Disable keyboard tabbing. This is a "lighter" version of ImGuiItemFlags_NoNav. + ImGuiItemFlags_NoNav = 1 << 1, // false // Disable any form of focusing (keyboard/gamepad directional navigation + // and SetKeyboardFocusHere() calls). + ImGuiItemFlags_NoNavDefaultFocus = + 1 << 2, // false // Disable item being a candidate for default focus (e.g. used by title bar items). + ImGuiItemFlags_ButtonRepeat = 1 << 3, // false // Any button-like behavior will have repeat mode enabled (based + // on io.KeyRepeatDelay and io.KeyRepeatRate values). Note that you can also + // call IsItemActive() after any button to tell if it is being held. + ImGuiItemFlags_AutoClosePopups = + 1 << 4, // true // MenuItem()/Selectable() automatically close their parent popup window. + ImGuiItemFlags_AllowDuplicateId = + 1 << 5, // false // Allow submitting an item with the same identifier as an item already submitted this frame + // without triggering a warning tooltip if io.ConfigDebugHighlightIdConflicts is set. }; // Flags for ImGui::InputText() -// (Those are per-item flags. There are shared flags in ImGuiIO: io.ConfigInputTextCursorBlink and io.ConfigInputTextEnterKeepActive) +// (Those are per-item flags. There are shared flags in ImGuiIO: io.ConfigInputTextCursorBlink and +// io.ConfigInputTextEnterKeepActive) enum ImGuiInputTextFlags_ { // Basic filters (also see ImGuiInputTextFlags_CallbackCharFilter) - ImGuiInputTextFlags_None = 0, - ImGuiInputTextFlags_CharsDecimal = 1 << 0, // Allow 0123456789.+-*/ - ImGuiInputTextFlags_CharsHexadecimal = 1 << 1, // Allow 0123456789ABCDEFabcdef - ImGuiInputTextFlags_CharsScientific = 1 << 2, // Allow 0123456789.+-*/eE (Scientific notation input) - ImGuiInputTextFlags_CharsUppercase = 1 << 3, // Turn a..z into A..Z - ImGuiInputTextFlags_CharsNoBlank = 1 << 4, // Filter out spaces, tabs + ImGuiInputTextFlags_None = 0, + ImGuiInputTextFlags_CharsDecimal = 1 << 0, // Allow 0123456789.+-*/ + ImGuiInputTextFlags_CharsHexadecimal = 1 << 1, // Allow 0123456789ABCDEFabcdef + ImGuiInputTextFlags_CharsScientific = 1 << 2, // Allow 0123456789.+-*/eE (Scientific notation input) + ImGuiInputTextFlags_CharsUppercase = 1 << 3, // Turn a..z into A..Z + ImGuiInputTextFlags_CharsNoBlank = 1 << 4, // Filter out spaces, tabs // Inputs - ImGuiInputTextFlags_AllowTabInput = 1 << 5, // Pressing TAB input a '\t' character into the text field - ImGuiInputTextFlags_EnterReturnsTrue = 1 << 6, // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider using IsItemDeactivatedAfterEdit() instead! - ImGuiInputTextFlags_EscapeClearsAll = 1 << 7, // Escape key clears content if not empty, and deactivate otherwise (contrast to default behavior of Escape to revert) - ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 8, // In multi-line mode, validate with Enter, add new line with Ctrl+Enter (default is opposite: validate with Ctrl+Enter, add line with Enter). + ImGuiInputTextFlags_AllowTabInput = 1 << 5, // Pressing TAB input a '\t' character into the text field + ImGuiInputTextFlags_EnterReturnsTrue = + 1 << 6, // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider using + // IsItemDeactivatedAfterEdit() instead! + ImGuiInputTextFlags_EscapeClearsAll = 1 << 7, // Escape key clears content if not empty, and deactivate otherwise + // (contrast to default behavior of Escape to revert) + ImGuiInputTextFlags_CtrlEnterForNewLine = + 1 << 8, // In multi-line mode, validate with Enter, add new line with Ctrl+Enter (default is opposite: validate + // with Ctrl+Enter, add line with Enter). // Other options - ImGuiInputTextFlags_ReadOnly = 1 << 9, // Read-only mode - ImGuiInputTextFlags_Password = 1 << 10, // Password mode, display all characters as '*', disable copy - ImGuiInputTextFlags_AlwaysOverwrite = 1 << 11, // Overwrite mode - ImGuiInputTextFlags_AutoSelectAll = 1 << 12, // Select entire text when first taking mouse focus - ImGuiInputTextFlags_ParseEmptyRefVal = 1 << 13, // InputFloat(), InputInt(), InputScalar() etc. only: parse empty string as zero value. - ImGuiInputTextFlags_DisplayEmptyRefVal = 1 << 14, // InputFloat(), InputInt(), InputScalar() etc. only: when value is zero, do not display it. Generally used with ImGuiInputTextFlags_ParseEmptyRefVal. - ImGuiInputTextFlags_NoHorizontalScroll = 1 << 15, // Disable following the cursor horizontally - 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_ReadOnly = 1 << 9, // Read-only mode + ImGuiInputTextFlags_Password = 1 << 10, // Password mode, display all characters as '*', disable copy + ImGuiInputTextFlags_AlwaysOverwrite = 1 << 11, // Overwrite mode + ImGuiInputTextFlags_AutoSelectAll = 1 << 12, // Select entire text when first taking mouse focus + ImGuiInputTextFlags_ParseEmptyRefVal = + 1 << 13, // InputFloat(), InputInt(), InputScalar() etc. only: parse empty string as zero value. + ImGuiInputTextFlags_DisplayEmptyRefVal = + 1 << 14, // InputFloat(), InputInt(), InputScalar() etc. only: when value is zero, do not display it. Generally + // used with ImGuiInputTextFlags_ParseEmptyRefVal. + ImGuiInputTextFlags_NoHorizontalScroll = 1 << 15, // Disable following the cursor horizontally + 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(). // Elide display / Alignment - ImGuiInputTextFlags_ElideLeft = 1 << 17, // When text doesn't fit, elide left side to ensure right side stays visible. Useful for path/filenames. Single-line only! + ImGuiInputTextFlags_ElideLeft = 1 << 17, // When text doesn't fit, elide left side to ensure right side stays + // visible. Useful for path/filenames. Single-line only! // Callback features - ImGuiInputTextFlags_CallbackCompletion = 1 << 18, // Callback on pressing TAB (for completion handling) - ImGuiInputTextFlags_CallbackHistory = 1 << 19, // Callback on pressing Up/Down arrows (for history handling) - ImGuiInputTextFlags_CallbackAlways = 1 << 20, // Callback on each iteration. User code may query cursor position, modify text buffer. - ImGuiInputTextFlags_CallbackCharFilter = 1 << 21, // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. - ImGuiInputTextFlags_CallbackResize = 1 << 22, // 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 << 23, // Callback on any edit. Note that InputText() already returns true on edit + you can always use IsItemEdited(). The callback is useful to manipulate the underlying buffer while focus is active. + ImGuiInputTextFlags_CallbackCompletion = 1 << 18, // Callback on pressing TAB (for completion handling) + ImGuiInputTextFlags_CallbackHistory = 1 << 19, // Callback on pressing Up/Down arrows (for history handling) + ImGuiInputTextFlags_CallbackAlways = + 1 << 20, // Callback on each iteration. User code may query cursor position, modify text buffer. + ImGuiInputTextFlags_CallbackCharFilter = + 1 << 21, // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, + // or return 1 in callback to discard. + ImGuiInputTextFlags_CallbackResize = + 1 << 22, // 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 << 23, // Callback on any edit. Note that InputText() already returns true on edit + you can always use + // IsItemEdited(). The callback is useful to manipulate the underlying buffer while focus is active. // Obsolete names - //ImGuiInputTextFlags_AlwaysInsertMode = ImGuiInputTextFlags_AlwaysOverwrite // [renamed in 1.82] name was not matching behavior + // ImGuiInputTextFlags_AlwaysInsertMode = ImGuiInputTextFlags_AlwaysOverwrite // [renamed in 1.82] name was not + // matching behavior }; // Flags for ImGui::TreeNodeEx(), ImGui::CollapsingHeader*() enum ImGuiTreeNodeFlags_ { - ImGuiTreeNodeFlags_None = 0, - ImGuiTreeNodeFlags_Selected = 1 << 0, // Draw as selected - ImGuiTreeNodeFlags_Framed = 1 << 1, // Draw frame with background (e.g. for CollapsingHeader) - ImGuiTreeNodeFlags_AllowOverlap = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one - ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack - ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes) - ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be open - ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Open on double-click instead of simple click (default for multi-select unless any _OpenOnXXX behavior is set explicitly). Both behaviors may be combined. - ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Open when clicking on the arrow part (default for multi-select unless any _OpenOnXXX behavior is set explicitly). Both behaviors may be combined. - ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). - ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow. IMPORTANT: node can still be marked open/close if you don't set the _Leaf flag! - ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding() before the node. - ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line without using AllowOverlap mode. - ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (cover the indent area). - ImGuiTreeNodeFlags_SpanLabelWidth = 1 << 13, // Narrow hit box + narrow hovering highlight, will only cover the label text. - ImGuiTreeNodeFlags_SpanAllColumns = 1 << 14, // Frame will span all columns of its container table (label will still fit in current column) - ImGuiTreeNodeFlags_LabelSpanAllColumns = 1 << 15, // Label will span all columns of its container table - //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 16, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible - ImGuiTreeNodeFlags_NavLeftJumpsToParent = 1 << 17, // Nav: left arrow moves back to parent. This is processed in TreePop() when there's an unfullfilled Left nav request remaining. - ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog, + ImGuiTreeNodeFlags_None = 0, + ImGuiTreeNodeFlags_Selected = 1 << 0, // Draw as selected + ImGuiTreeNodeFlags_Framed = 1 << 1, // Draw frame with background (e.g. for CollapsingHeader) + ImGuiTreeNodeFlags_AllowOverlap = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one + ImGuiTreeNodeFlags_NoTreePushOnOpen = + 1 << 3, // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack + ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active + // (by default logging will automatically open tree nodes) + ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be open + ImGuiTreeNodeFlags_OpenOnDoubleClick = + 1 << 6, // Open on double-click instead of simple click (default for multi-select unless any _OpenOnXXX behavior + // is set explicitly). Both behaviors may be combined. + ImGuiTreeNodeFlags_OpenOnArrow = + 1 << 7, // Open when clicking on the arrow part (default for multi-select unless any _OpenOnXXX behavior is set + // explicitly). Both behaviors may be combined. + ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). + ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow. IMPORTANT: node can still be marked + // open/close if you don't set the _Leaf flag! + ImGuiTreeNodeFlags_FramePadding = + 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular + // widget height. Equivalent to calling AlignTextToFramePadding() before the node. + ImGuiTreeNodeFlags_SpanAvailWidth = + 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow + // adding other items on the same line without using AllowOverlap mode. + ImGuiTreeNodeFlags_SpanFullWidth = + 1 << 12, // Extend hit box to the left-most and right-most edges (cover the indent area). + ImGuiTreeNodeFlags_SpanLabelWidth = + 1 << 13, // Narrow hit box + narrow hovering highlight, will only cover the label text. + ImGuiTreeNodeFlags_SpanAllColumns = + 1 << 14, // Frame will span all columns of its container table (label will still fit in current column) + ImGuiTreeNodeFlags_LabelSpanAllColumns = 1 << 15, // Label will span all columns of its container table + // ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 16, // FIXME: TODO: Disable automatic scroll on TreePop() if node + // got just open and contents is not visible + ImGuiTreeNodeFlags_NavLeftJumpsToParent = + 1 << 17, // Nav: left arrow moves back to parent. This is processed in TreePop() when there's an unfullfilled + // Left nav request remaining. + ImGuiTreeNodeFlags_CollapsingHeader = + ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog, // [EXPERIMENTAL] Draw lines connecting TreeNode hierarchy. Discuss in GitHub issue #2920. // Default value is pulled from style.TreeLinesFlags. May be overridden in TreeNode calls. - ImGuiTreeNodeFlags_DrawLinesNone = 1 << 18, // No lines drawn - ImGuiTreeNodeFlags_DrawLinesFull = 1 << 19, // Horizontal lines to child nodes. Vertical line drawn down to TreePop() position: cover full contents. Faster (for large trees). - ImGuiTreeNodeFlags_DrawLinesToNodes = 1 << 20, // Horizontal lines to child nodes. Vertical line drawn down to bottom-most child node. Slower (for large trees). + ImGuiTreeNodeFlags_DrawLinesNone = 1 << 18, // No lines drawn + ImGuiTreeNodeFlags_DrawLinesFull = 1 << 19, // Horizontal lines to child nodes. Vertical line drawn down to + // TreePop() position: cover full contents. Faster (for large trees). + ImGuiTreeNodeFlags_DrawLinesToNodes = 1 << 20, // Horizontal lines to child nodes. Vertical line drawn down to + // bottom-most child node. Slower (for large trees). #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImGuiTreeNodeFlags_NavLeftJumpsBackHere = ImGuiTreeNodeFlags_NavLeftJumpsToParent, // Renamed in 1.92.0 - ImGuiTreeNodeFlags_SpanTextWidth = ImGuiTreeNodeFlags_SpanLabelWidth, // Renamed in 1.90.7 - ImGuiTreeNodeFlags_AllowItemOverlap = ImGuiTreeNodeFlags_AllowOverlap, // Renamed in 1.89.7 + ImGuiTreeNodeFlags_NavLeftJumpsBackHere = ImGuiTreeNodeFlags_NavLeftJumpsToParent, // Renamed in 1.92.0 + ImGuiTreeNodeFlags_SpanTextWidth = ImGuiTreeNodeFlags_SpanLabelWidth, // Renamed in 1.90.7 + ImGuiTreeNodeFlags_AllowItemOverlap = ImGuiTreeNodeFlags_AllowOverlap, // Renamed in 1.89.7 #endif }; // Flags for OpenPopup*(), BeginPopupContext*(), IsPopupOpen() functions. -// - To be backward compatible with older API which took an 'int mouse_button = 1' argument instead of 'ImGuiPopupFlags flags', -// we need to treat small flags values as a mouse button index, so we encode the mouse button in the first few bits of the flags. -// It is therefore guaranteed to be legal to pass a mouse button index in ImGuiPopupFlags. -// - For the same reason, we exceptionally default the ImGuiPopupFlags argument of BeginPopupContextXXX functions to 1 instead of 0. -// IMPORTANT: because the default parameter is 1 (==ImGuiPopupFlags_MouseButtonRight), if you rely on the default parameter -// and want to use another flag, you need to pass in the ImGuiPopupFlags_MouseButtonRight flag explicitly. +// - To be backward compatible with older API which took an 'int mouse_button = 1' argument instead of 'ImGuiPopupFlags +// flags', +// we need to treat small flags values as a mouse button index, so we encode the mouse button in the first few bits of +// the flags. It is therefore guaranteed to be legal to pass a mouse button index in ImGuiPopupFlags. +// - For the same reason, we exceptionally default the ImGuiPopupFlags argument of BeginPopupContextXXX functions to 1 +// instead of 0. +// IMPORTANT: because the default parameter is 1 (==ImGuiPopupFlags_MouseButtonRight), if you rely on the default +// parameter and want to use another flag, you need to pass in the ImGuiPopupFlags_MouseButtonRight flag explicitly. // - Multiple buttons currently cannot be combined/or-ed in those functions (we could allow it later). enum ImGuiPopupFlags_ { - ImGuiPopupFlags_None = 0, - ImGuiPopupFlags_MouseButtonLeft = 0, // For BeginPopupContext*(): open on Left Mouse release. Guaranteed to always be == 0 (same as ImGuiMouseButton_Left) - ImGuiPopupFlags_MouseButtonRight = 1, // For BeginPopupContext*(): open on Right Mouse release. Guaranteed to always be == 1 (same as ImGuiMouseButton_Right) - ImGuiPopupFlags_MouseButtonMiddle = 2, // For BeginPopupContext*(): open on Middle Mouse release. Guaranteed to always be == 2 (same as ImGuiMouseButton_Middle) - ImGuiPopupFlags_MouseButtonMask_ = 0x1F, - ImGuiPopupFlags_MouseButtonDefault_ = 1, - ImGuiPopupFlags_NoReopen = 1 << 5, // For OpenPopup*(), BeginPopupContext*(): don't reopen same popup if already open (won't reposition, won't reinitialize navigation) - //ImGuiPopupFlags_NoReopenAlwaysNavInit = 1 << 6, // For OpenPopup*(), BeginPopupContext*(): focus and initialize navigation even when not reopening. - ImGuiPopupFlags_NoOpenOverExistingPopup = 1 << 7, // For OpenPopup*(), BeginPopupContext*(): don't open if there's already a popup at the same level of the popup stack - ImGuiPopupFlags_NoOpenOverItems = 1 << 8, // For BeginPopupContextWindow(): don't return true when hovering items, only when hovering empty space - ImGuiPopupFlags_AnyPopupId = 1 << 10, // For IsPopupOpen(): ignore the ImGuiID parameter and test for any popup. - ImGuiPopupFlags_AnyPopupLevel = 1 << 11, // For IsPopupOpen(): search/test at any level of the popup stack (default test in the current level) - ImGuiPopupFlags_AnyPopup = ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel, + ImGuiPopupFlags_None = 0, + ImGuiPopupFlags_MouseButtonLeft = 0, // For BeginPopupContext*(): open on Left Mouse release. Guaranteed to always + // be == 0 (same as ImGuiMouseButton_Left) + ImGuiPopupFlags_MouseButtonRight = 1, // For BeginPopupContext*(): open on Right Mouse release. Guaranteed to always + // be == 1 (same as ImGuiMouseButton_Right) + ImGuiPopupFlags_MouseButtonMiddle = 2, // For BeginPopupContext*(): open on Middle Mouse release. Guaranteed to + // always be == 2 (same as ImGuiMouseButton_Middle) + ImGuiPopupFlags_MouseButtonMask_ = 0x1F, + ImGuiPopupFlags_MouseButtonDefault_ = 1, + ImGuiPopupFlags_NoReopen = 1 << 5, // For OpenPopup*(), BeginPopupContext*(): don't reopen same popup if already + // open (won't reposition, won't reinitialize navigation) + // ImGuiPopupFlags_NoReopenAlwaysNavInit = 1 << 6, // For OpenPopup*(), BeginPopupContext*(): focus and initialize + // navigation even when not reopening. + ImGuiPopupFlags_NoOpenOverExistingPopup = 1 << 7, // For OpenPopup*(), BeginPopupContext*(): don't open if there's + // already a popup at the same level of the popup stack + ImGuiPopupFlags_NoOpenOverItems = + 1 << 8, // For BeginPopupContextWindow(): don't return true when hovering items, only when hovering empty space + ImGuiPopupFlags_AnyPopupId = 1 << 10, // For IsPopupOpen(): ignore the ImGuiID parameter and test for any popup. + ImGuiPopupFlags_AnyPopupLevel = + 1 << 11, // For IsPopupOpen(): search/test at any level of the popup stack (default test in the current level) + ImGuiPopupFlags_AnyPopup = ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel, }; // Flags for ImGui::Selectable() enum ImGuiSelectableFlags_ { - ImGuiSelectableFlags_None = 0, - ImGuiSelectableFlags_NoAutoClosePopups = 1 << 0, // Clicking this doesn't close parent popup window (overrides ImGuiItemFlags_AutoClosePopups) - ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Frame will span all columns of its container table (text will still fit in current column) - ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too - ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text - ImGuiSelectableFlags_AllowOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one - ImGuiSelectableFlags_Highlight = 1 << 5, // Make the item be displayed as if it is hovered + ImGuiSelectableFlags_None = 0, + ImGuiSelectableFlags_NoAutoClosePopups = + 1 << 0, // Clicking this doesn't close parent popup window (overrides ImGuiItemFlags_AutoClosePopups) + ImGuiSelectableFlags_SpanAllColumns = + 1 << 1, // Frame will span all columns of its container table (text will still fit in current column) + ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too + ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text + ImGuiSelectableFlags_AllowOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one + ImGuiSelectableFlags_Highlight = 1 << 5, // Make the item be displayed as if it is hovered #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImGuiSelectableFlags_DontClosePopups = ImGuiSelectableFlags_NoAutoClosePopups, // Renamed in 1.91.0 - ImGuiSelectableFlags_AllowItemOverlap = ImGuiSelectableFlags_AllowOverlap, // Renamed in 1.89.7 + ImGuiSelectableFlags_DontClosePopups = ImGuiSelectableFlags_NoAutoClosePopups, // Renamed in 1.91.0 + ImGuiSelectableFlags_AllowItemOverlap = ImGuiSelectableFlags_AllowOverlap, // Renamed in 1.89.7 #endif }; // Flags for ImGui::BeginCombo() enum ImGuiComboFlags_ { - ImGuiComboFlags_None = 0, - ImGuiComboFlags_PopupAlignLeft = 1 << 0, // Align the popup toward the left by default - ImGuiComboFlags_HeightSmall = 1 << 1, // Max ~4 items visible. Tip: If you want your combo popup to be a specific size you can use SetNextWindowSizeConstraints() prior to calling BeginCombo() - ImGuiComboFlags_HeightRegular = 1 << 2, // Max ~8 items visible (default) - ImGuiComboFlags_HeightLarge = 1 << 3, // Max ~20 items visible - ImGuiComboFlags_HeightLargest = 1 << 4, // As many fitting items as possible - ImGuiComboFlags_NoArrowButton = 1 << 5, // Display on the preview box without the square arrow button - ImGuiComboFlags_NoPreview = 1 << 6, // Display only a square arrow button - ImGuiComboFlags_WidthFitPreview = 1 << 7, // Width dynamically calculated from preview contents - ImGuiComboFlags_HeightMask_ = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest, + ImGuiComboFlags_None = 0, + ImGuiComboFlags_PopupAlignLeft = 1 << 0, // Align the popup toward the left by default + ImGuiComboFlags_HeightSmall = + 1 << 1, // Max ~4 items visible. Tip: If you want your combo popup to be a specific size you can use + // SetNextWindowSizeConstraints() prior to calling BeginCombo() + ImGuiComboFlags_HeightRegular = 1 << 2, // Max ~8 items visible (default) + ImGuiComboFlags_HeightLarge = 1 << 3, // Max ~20 items visible + ImGuiComboFlags_HeightLargest = 1 << 4, // As many fitting items as possible + ImGuiComboFlags_NoArrowButton = 1 << 5, // Display on the preview box without the square arrow button + ImGuiComboFlags_NoPreview = 1 << 6, // Display only a square arrow button + ImGuiComboFlags_WidthFitPreview = 1 << 7, // Width dynamically calculated from preview contents + ImGuiComboFlags_HeightMask_ = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | + ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest, }; // Flags for ImGui::BeginTabBar() enum ImGuiTabBarFlags_ { - ImGuiTabBarFlags_None = 0, - ImGuiTabBarFlags_Reorderable = 1 << 0, // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list - ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, // Automatically select new tabs when they appear - ImGuiTabBarFlags_TabListPopupButton = 1 << 2, // Disable buttons to open the tab list popup - ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You may handle this behavior manually on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. - ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, // Disable scrolling buttons (apply when fitting policy is ImGuiTabBarFlags_FittingPolicyScroll) - ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab - ImGuiTabBarFlags_DrawSelectedOverline = 1 << 6, // Draw selected overline markers over selected tab - ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 7, // Resize tabs when they don't fit - ImGuiTabBarFlags_FittingPolicyScroll = 1 << 8, // Add scroll buttons when tabs don't fit - ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll, - ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown, + ImGuiTabBarFlags_None = 0, + ImGuiTabBarFlags_Reorderable = + 1 << 0, // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list + ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, // Automatically select new tabs when they appear + ImGuiTabBarFlags_TabListPopupButton = 1 << 2, // Disable buttons to open the tab list popup + ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = + 1 << 3, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. + // You may handle this behavior manually on user's side with if (IsItemHovered() && IsMouseClicked(2)) + // *p_open = false. + ImGuiTabBarFlags_NoTabListScrollingButtons = + 1 << 4, // Disable scrolling buttons (apply when fitting policy is ImGuiTabBarFlags_FittingPolicyScroll) + ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab + ImGuiTabBarFlags_DrawSelectedOverline = 1 << 6, // Draw selected overline markers over selected tab + ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 7, // Resize tabs when they don't fit + ImGuiTabBarFlags_FittingPolicyScroll = 1 << 8, // Add scroll buttons when tabs don't fit + ImGuiTabBarFlags_FittingPolicyMask_ = + ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll, + ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown, }; // Flags for ImGui::BeginTabItem() enum ImGuiTabItemFlags_ { - ImGuiTabItemFlags_None = 0, - ImGuiTabItemFlags_UnsavedDocument = 1 << 0, // Display a dot next to the title + set ImGuiTabItemFlags_NoAssumedClosure. - ImGuiTabItemFlags_SetSelected = 1 << 1, // Trigger flag to programmatically make the tab selected when calling BeginTabItem() - ImGuiTabItemFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You may handle this behavior manually on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. - ImGuiTabItemFlags_NoPushId = 1 << 3, // Don't call PushID()/PopID() on BeginTabItem()/EndTabItem() - ImGuiTabItemFlags_NoTooltip = 1 << 4, // Disable tooltip for the given tab - ImGuiTabItemFlags_NoReorder = 1 << 5, // Disable reordering this tab or having another tab cross over this tab - ImGuiTabItemFlags_Leading = 1 << 6, // Enforce the tab position to the left of the tab bar (after the tab list popup button) - ImGuiTabItemFlags_Trailing = 1 << 7, // Enforce the tab position to the right of the tab bar (before the scrolling buttons) - ImGuiTabItemFlags_NoAssumedClosure = 1 << 8, // Tab is selected when trying to close + closure is not immediately assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. + ImGuiTabItemFlags_None = 0, + ImGuiTabItemFlags_UnsavedDocument = + 1 << 0, // Display a dot next to the title + set ImGuiTabItemFlags_NoAssumedClosure. + ImGuiTabItemFlags_SetSelected = + 1 << 1, // Trigger flag to programmatically make the tab selected when calling BeginTabItem() + ImGuiTabItemFlags_NoCloseWithMiddleMouseButton = + 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. + // You may handle this behavior manually on user's side with if (IsItemHovered() && IsMouseClicked(2)) + // *p_open = false. + ImGuiTabItemFlags_NoPushId = 1 << 3, // Don't call PushID()/PopID() on BeginTabItem()/EndTabItem() + ImGuiTabItemFlags_NoTooltip = 1 << 4, // Disable tooltip for the given tab + ImGuiTabItemFlags_NoReorder = 1 << 5, // Disable reordering this tab or having another tab cross over this tab + ImGuiTabItemFlags_Leading = + 1 << 6, // Enforce the tab position to the left of the tab bar (after the tab list popup button) + ImGuiTabItemFlags_Trailing = + 1 << 7, // Enforce the tab position to the right of the tab bar (before the scrolling buttons) + ImGuiTabItemFlags_NoAssumedClosure = + 1 << 8, // Tab is selected when trying to close + closure is not immediately assumed (will wait for user to stop + // submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the + // tab may reappear at end of tab bar. }; // Flags for ImGui::IsWindowFocused() enum ImGuiFocusedFlags_ { - ImGuiFocusedFlags_None = 0, - ImGuiFocusedFlags_ChildWindows = 1 << 0, // Return true if any children of the window is focused - ImGuiFocusedFlags_RootWindow = 1 << 1, // Test from root window (top most parent of the current hierarchy) - ImGuiFocusedFlags_AnyWindow = 1 << 2, // Return true if any window is focused. Important: If you are trying to tell how to dispatch your low-level inputs, do NOT use this. Use 'io.WantCaptureMouse' instead! Please read the FAQ! - ImGuiFocusedFlags_NoPopupHierarchy = 1 << 3, // Do not consider popup hierarchy (do not treat popup emitter as parent of popup) (when used with _ChildWindows or _RootWindow) - //ImGuiFocusedFlags_DockHierarchy = 1 << 4, // Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow) - ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows, + ImGuiFocusedFlags_None = 0, + ImGuiFocusedFlags_ChildWindows = 1 << 0, // Return true if any children of the window is focused + ImGuiFocusedFlags_RootWindow = 1 << 1, // Test from root window (top most parent of the current hierarchy) + ImGuiFocusedFlags_AnyWindow = + 1 << 2, // Return true if any window is focused. Important: If you are trying to tell how to dispatch your + // low-level inputs, do NOT use this. Use 'io.WantCaptureMouse' instead! Please read the FAQ! + ImGuiFocusedFlags_NoPopupHierarchy = 1 << 3, // Do not consider popup hierarchy (do not treat popup emitter as + // parent of popup) (when used with _ChildWindows or _RootWindow) + // ImGuiFocusedFlags_DockHierarchy = 1 << 4, // Consider docking hierarchy (treat dockspace host as + // parent of docked window) (when used with _ChildWindows or _RootWindow) + ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows, }; // Flags for ImGui::IsItemHovered(), ImGui::IsWindowHovered() -// Note: if you are trying to check whether your mouse should be dispatched to Dear ImGui or to your app, you should use 'io.WantCaptureMouse' instead! Please read the FAQ! -// Note: windows with the ImGuiWindowFlags_NoInputs flag are ignored by IsWindowHovered() calls. +// Note: if you are trying to check whether your mouse should be dispatched to Dear ImGui or to your app, you should use +// 'io.WantCaptureMouse' instead! Please read the FAQ! Note: windows with the ImGuiWindowFlags_NoInputs flag are ignored +// by IsWindowHovered() calls. enum ImGuiHoveredFlags_ { - ImGuiHoveredFlags_None = 0, // Return true if directly over the item/window, not obstructed by another window, not obstructed by an active popup or modal blocking inputs under them. - ImGuiHoveredFlags_ChildWindows = 1 << 0, // IsWindowHovered() only: Return true if any children of the window is hovered - ImGuiHoveredFlags_RootWindow = 1 << 1, // IsWindowHovered() only: Test from root window (top most parent of the current hierarchy) - ImGuiHoveredFlags_AnyWindow = 1 << 2, // IsWindowHovered() only: Return true if any window is hovered - ImGuiHoveredFlags_NoPopupHierarchy = 1 << 3, // IsWindowHovered() only: Do not consider popup hierarchy (do not treat popup emitter as parent of popup) (when used with _ChildWindows or _RootWindow) - //ImGuiHoveredFlags_DockHierarchy = 1 << 4, // IsWindowHovered() only: Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow) - ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 5, // Return true even if a popup window is normally blocking access to this item/window - //ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 6, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet. - ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 7, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns. - ImGuiHoveredFlags_AllowWhenOverlappedByItem = 1 << 8, // IsItemHovered() only: Return true even if the item uses AllowOverlap mode and is overlapped by another hoverable item. - ImGuiHoveredFlags_AllowWhenOverlappedByWindow = 1 << 9, // IsItemHovered() only: Return true even if the position is obstructed or overlapped by another window. - ImGuiHoveredFlags_AllowWhenDisabled = 1 << 10, // IsItemHovered() only: Return true even if the item is disabled - ImGuiHoveredFlags_NoNavOverride = 1 << 11, // IsItemHovered() only: Disable using keyboard/gamepad navigation state when active, always query mouse - ImGuiHoveredFlags_AllowWhenOverlapped = ImGuiHoveredFlags_AllowWhenOverlappedByItem | ImGuiHoveredFlags_AllowWhenOverlappedByWindow, - ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, - ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows, + ImGuiHoveredFlags_None = 0, // Return true if directly over the item/window, not obstructed by another window, not + // obstructed by an active popup or modal blocking inputs under them. + ImGuiHoveredFlags_ChildWindows = + 1 << 0, // IsWindowHovered() only: Return true if any children of the window is hovered + ImGuiHoveredFlags_RootWindow = + 1 << 1, // IsWindowHovered() only: Test from root window (top most parent of the current hierarchy) + ImGuiHoveredFlags_AnyWindow = 1 << 2, // IsWindowHovered() only: Return true if any window is hovered + ImGuiHoveredFlags_NoPopupHierarchy = + 1 << 3, // IsWindowHovered() only: Do not consider popup hierarchy (do not treat popup emitter as parent of + // popup) (when used with _ChildWindows or _RootWindow) + // ImGuiHoveredFlags_DockHierarchy = 1 << 4, // IsWindowHovered() only: Consider docking hierarchy + // (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow) + ImGuiHoveredFlags_AllowWhenBlockedByPopup = + 1 << 5, // Return true even if a popup window is normally blocking access to this item/window + // ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 6, // Return true even if a modal popup window is normally + // blocking access to this item/window. FIXME-TODO: Unavailable yet. + ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 7, // Return true even if an active item is blocking access to + // this item/window. Useful for Drag and Drop patterns. + ImGuiHoveredFlags_AllowWhenOverlappedByItem = + 1 << 8, // IsItemHovered() only: Return true even if the item uses AllowOverlap mode and is overlapped by + // another hoverable item. + ImGuiHoveredFlags_AllowWhenOverlappedByWindow = + 1 << 9, // IsItemHovered() only: Return true even if the position is obstructed or overlapped by another window. + ImGuiHoveredFlags_AllowWhenDisabled = 1 << 10, // IsItemHovered() only: Return true even if the item is disabled + ImGuiHoveredFlags_NoNavOverride = + 1 + << 11, // IsItemHovered() only: Disable using keyboard/gamepad navigation state when active, always query mouse + ImGuiHoveredFlags_AllowWhenOverlapped = + ImGuiHoveredFlags_AllowWhenOverlappedByItem | ImGuiHoveredFlags_AllowWhenOverlappedByWindow, + ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | + ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, + ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows, // Tooltips mode // - typically used in IsItemHovered() + SetTooltip() sequence. - // - this is a shortcut to pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' where you can reconfigure desired behavior. + // - this is a shortcut to pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' + // where you can reconfigure desired behavior. // e.g. 'TooltipHoveredFlagsForMouse' defaults to 'ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort'. - // - for frequently actioned or hovered items providing a tooltip, you want may to use ImGuiHoveredFlags_ForTooltip (stationary + delay) so the tooltip doesn't show too often. - // - for items which main purpose is to be hovered, or items with low affordance, or in less consistent apps, prefer no delay or shorter delay. - ImGuiHoveredFlags_ForTooltip = 1 << 12, // Shortcut for standard flags when using IsItemHovered() + SetTooltip() sequence. + // - for frequently actioned or hovered items providing a tooltip, you want may to use ImGuiHoveredFlags_ForTooltip + // (stationary + delay) so the tooltip doesn't show too often. + // - for items which main purpose is to be hovered, or items with low affordance, or in less consistent apps, prefer + // no delay or shorter delay. + ImGuiHoveredFlags_ForTooltip = + 1 << 12, // Shortcut for standard flags when using IsItemHovered() + SetTooltip() sequence. // (Advanced) Mouse Hovering delays. // - generally you can use ImGuiHoveredFlags_ForTooltip to use application-standardized flags. // - use those if you need specific overrides. - ImGuiHoveredFlags_Stationary = 1 << 13, // Require mouse to be stationary for style.HoverStationaryDelay (~0.15 sec) _at least one time_. After this, can move on same item/window. Using the stationary test tends to reduces the need for a long delay. - ImGuiHoveredFlags_DelayNone = 1 << 14, // IsItemHovered() only: Return true immediately (default). As this is the default you generally ignore this. - ImGuiHoveredFlags_DelayShort = 1 << 15, // IsItemHovered() only: Return true after style.HoverDelayShort elapsed (~0.15 sec) (shared between items) + requires mouse to be stationary for style.HoverStationaryDelay (once per item). - ImGuiHoveredFlags_DelayNormal = 1 << 16, // IsItemHovered() only: Return true after style.HoverDelayNormal elapsed (~0.40 sec) (shared between items) + requires mouse to be stationary for style.HoverStationaryDelay (once per item). - ImGuiHoveredFlags_NoSharedDelay = 1 << 17, // IsItemHovered() only: Disable shared delay system where moving from one item to the next keeps the previous timer for a short time (standard for tooltips with long delays) + ImGuiHoveredFlags_Stationary = 1 << 13, // Require mouse to be stationary for style.HoverStationaryDelay (~0.15 sec) + // _at least one time_. After this, can move on same item/window. Using the + // stationary test tends to reduces the need for a long delay. + ImGuiHoveredFlags_DelayNone = 1 << 14, // IsItemHovered() only: Return true immediately (default). As this is the + // default you generally ignore this. + ImGuiHoveredFlags_DelayShort = + 1 << 15, // IsItemHovered() only: Return true after style.HoverDelayShort elapsed (~0.15 sec) (shared between + // items) + requires mouse to be stationary for style.HoverStationaryDelay (once per item). + ImGuiHoveredFlags_DelayNormal = + 1 << 16, // IsItemHovered() only: Return true after style.HoverDelayNormal elapsed (~0.40 sec) (shared between + // items) + requires mouse to be stationary for style.HoverStationaryDelay (once per item). + ImGuiHoveredFlags_NoSharedDelay = + 1 << 17, // IsItemHovered() only: Disable shared delay system where moving from one item to the next keeps the + // previous timer for a short time (standard for tooltips with long delays) }; // Flags for ImGui::BeginDragDropSource(), ImGui::AcceptDragDropPayload() enum ImGuiDragDropFlags_ { - ImGuiDragDropFlags_None = 0, + ImGuiDragDropFlags_None = 0, // BeginDragDropSource() flags - ImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0, // Disable preview tooltip. By default, a successful call to BeginDragDropSource opens a tooltip so you can display a preview or description of the source contents. This flag disables this behavior. - ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return false, to avoid subsequent user code submitting tooltips. This flag disables this behavior so you can still call IsItemHovered() on the source item. - ImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2, // Disable the behavior that allows to open tree nodes and collapsing header by holding over them while dragging a source item. - ImGuiDragDropFlags_SourceAllowNullID = 1 << 3, // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit. - ImGuiDragDropFlags_SourceExtern = 1 << 4, // External source (from outside of dear imgui), won't attempt to read current item/window info. Will always return true. Only one Extern source can be active simultaneously. - ImGuiDragDropFlags_PayloadAutoExpire = 1 << 5, // Automatically expire the payload if the source cease to be submitted (otherwise payloads are persisting while being dragged) - ImGuiDragDropFlags_PayloadNoCrossContext = 1 << 6, // Hint to specify that the payload may not be copied outside current dear imgui context. - ImGuiDragDropFlags_PayloadNoCrossProcess = 1 << 7, // Hint to specify that the payload may not be copied outside current process. + ImGuiDragDropFlags_SourceNoPreviewTooltip = + 1 << 0, // Disable preview tooltip. By default, a successful call to BeginDragDropSource opens a tooltip so you + // can display a preview or description of the source contents. This flag disables this behavior. + ImGuiDragDropFlags_SourceNoDisableHover = + 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return false, to avoid + // subsequent user code submitting tooltips. This flag disables this behavior so you can still call + // IsItemHovered() on the source item. + ImGuiDragDropFlags_SourceNoHoldToOpenOthers = + 1 << 2, // Disable the behavior that allows to open tree nodes and collapsing header by holding over them while + // dragging a source item. + ImGuiDragDropFlags_SourceAllowNullID = + 1 << 3, // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by + // manufacturing a temporary identifier based on their window-relative position. This is extremely + // unusual within the dear imgui ecosystem and so we made it explicit. + ImGuiDragDropFlags_SourceExtern = + 1 << 4, // External source (from outside of dear imgui), won't attempt to read current item/window info. Will + // always return true. Only one Extern source can be active simultaneously. + ImGuiDragDropFlags_PayloadAutoExpire = 1 << 5, // Automatically expire the payload if the source cease to be + // submitted (otherwise payloads are persisting while being dragged) + ImGuiDragDropFlags_PayloadNoCrossContext = + 1 << 6, // Hint to specify that the payload may not be copied outside current dear imgui context. + ImGuiDragDropFlags_PayloadNoCrossProcess = + 1 << 7, // Hint to specify that the payload may not be copied outside current process. // AcceptDragDropPayload() flags - ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, // AcceptDragDropPayload() will returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered. - ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, // Do not draw the default highlight rectangle when hovering over target. - ImGuiDragDropFlags_AcceptNoPreviewTooltip = 1 << 12, // Request hiding the BeginDragDropSource tooltip from the BeginDragDropTarget site. - ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect, // For peeking ahead and inspecting the payload before delivery. + ImGuiDragDropFlags_AcceptBeforeDelivery = + 1 << 10, // AcceptDragDropPayload() will returns true even before the mouse button is released. You can then + // call IsDelivery() to test if the payload needs to be delivered. + ImGuiDragDropFlags_AcceptNoDrawDefaultRect = + 1 << 11, // Do not draw the default highlight rectangle when hovering over target. + ImGuiDragDropFlags_AcceptNoPreviewTooltip = + 1 << 12, // Request hiding the BeginDragDropSource tooltip from the BeginDragDropTarget site. + ImGuiDragDropFlags_AcceptPeekOnly = + ImGuiDragDropFlags_AcceptBeforeDelivery | + ImGuiDragDropFlags_AcceptNoDrawDefaultRect, // For peeking ahead and inspecting the payload before delivery. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImGuiDragDropFlags_SourceAutoExpirePayload = ImGuiDragDropFlags_PayloadAutoExpire, // Renamed in 1.90.9 #endif }; -// Standard Drag and Drop payload types. You can define you own payload types using short strings. Types starting with '_' are defined by Dear ImGui. -#define IMGUI_PAYLOAD_TYPE_COLOR_3F "_COL3F" // float[3]: Standard type for colors, without alpha. User code may use this type. -#define IMGUI_PAYLOAD_TYPE_COLOR_4F "_COL4F" // float[4]: Standard type for colors. User code may use this type. +// Standard Drag and Drop payload types. You can define you own payload types using short strings. Types starting with +// '_' are defined by Dear ImGui. +#define IMGUI_PAYLOAD_TYPE_COLOR_3F \ + "_COL3F" // float[3]: Standard type for colors, without alpha. User code may use this type. +#define IMGUI_PAYLOAD_TYPE_COLOR_4F "_COL4F" // float[4]: Standard type for colors. User code may use this type. // A primary data type enum ImGuiDataType_ { - ImGuiDataType_S8, // signed char / char (with sensible compilers) - ImGuiDataType_U8, // unsigned char - ImGuiDataType_S16, // short - ImGuiDataType_U16, // unsigned short - ImGuiDataType_S32, // int - ImGuiDataType_U32, // unsigned int - ImGuiDataType_S64, // long long / __int64 - ImGuiDataType_U64, // unsigned long long / unsigned __int64 - ImGuiDataType_Float, // float - ImGuiDataType_Double, // double - ImGuiDataType_Bool, // bool (provided for user convenience, not supported by scalar widgets) - ImGuiDataType_String, // char* (provided for user convenience, not supported by scalar widgets) + ImGuiDataType_S8, // signed char / char (with sensible compilers) + ImGuiDataType_U8, // unsigned char + ImGuiDataType_S16, // short + ImGuiDataType_U16, // unsigned short + ImGuiDataType_S32, // int + ImGuiDataType_U32, // unsigned int + ImGuiDataType_S64, // long long / __int64 + ImGuiDataType_U64, // unsigned long long / unsigned __int64 + ImGuiDataType_Float, // float + ImGuiDataType_Double, // double + ImGuiDataType_Bool, // bool (provided for user convenience, not supported by scalar widgets) + ImGuiDataType_String, // char* (provided for user convenience, not supported by scalar widgets) ImGuiDataType_COUNT }; // A cardinal direction enum ImGuiDir : int { - ImGuiDir_None = -1, - ImGuiDir_Left = 0, - ImGuiDir_Right = 1, - ImGuiDir_Up = 2, - ImGuiDir_Down = 3, + ImGuiDir_None = -1, + ImGuiDir_Left = 0, + ImGuiDir_Right = 1, + ImGuiDir_Up = 2, + ImGuiDir_Down = 3, ImGuiDir_COUNT }; // A sorting direction enum ImGuiSortDirection : ImU8 { - ImGuiSortDirection_None = 0, - ImGuiSortDirection_Ascending = 1, // Ascending = 0->9, A->Z etc. - ImGuiSortDirection_Descending = 2 // Descending = 9->0, Z->A etc. + ImGuiSortDirection_None = 0, + ImGuiSortDirection_Ascending = 1, // Ascending = 0->9, A->Z etc. + ImGuiSortDirection_Descending = 2 // Descending = 9->0, Z->A etc. }; // A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value): can represent Keyboard, Mouse and Gamepad values. // All our named keys are >= 512. Keys value 0 to 511 are left unused and were legacy native/opaque key values (< 1.87). // Support for legacy keys was completely removed in 1.91.5. // Read details about the 1.87+ transition : https://github.com/ocornut/imgui/issues/4921 -// Note that "Keys" related to physical keys and are not the same concept as input "Characters", the later are submitted via io.AddInputCharacter(). -// The keyboard key enum values are named after the keys on a standard US keyboard, and on other keyboard types the keys reported may not match the keycaps. +// Note that "Keys" related to physical keys and are not the same concept as input "Characters", the later are submitted +// via io.AddInputCharacter(). The keyboard key enum values are named after the keys on a standard US keyboard, and on +// other keyboard types the keys reported may not match the keycaps. enum ImGuiKey : int { // Keyboard ImGuiKey_None = 0, - ImGuiKey_NamedKey_BEGIN = 512, // First valid key value (other than 0) + ImGuiKey_NamedKey_BEGIN = 512, // First valid key value (other than 0) - ImGuiKey_Tab = 512, // == ImGuiKey_NamedKey_BEGIN + ImGuiKey_Tab = 512, // == ImGuiKey_NamedKey_BEGIN ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_UpArrow, @@ -1530,35 +2294,101 @@ enum ImGuiKey : int ImGuiKey_Space, ImGuiKey_Enter, ImGuiKey_Escape, - ImGuiKey_LeftCtrl, ImGuiKey_LeftShift, ImGuiKey_LeftAlt, ImGuiKey_LeftSuper, - ImGuiKey_RightCtrl, ImGuiKey_RightShift, ImGuiKey_RightAlt, ImGuiKey_RightSuper, + ImGuiKey_LeftCtrl, + ImGuiKey_LeftShift, + ImGuiKey_LeftAlt, + ImGuiKey_LeftSuper, + ImGuiKey_RightCtrl, + ImGuiKey_RightShift, + ImGuiKey_RightAlt, + ImGuiKey_RightSuper, ImGuiKey_Menu, - ImGuiKey_0, ImGuiKey_1, ImGuiKey_2, ImGuiKey_3, ImGuiKey_4, ImGuiKey_5, ImGuiKey_6, ImGuiKey_7, ImGuiKey_8, ImGuiKey_9, - ImGuiKey_A, ImGuiKey_B, ImGuiKey_C, ImGuiKey_D, ImGuiKey_E, ImGuiKey_F, ImGuiKey_G, ImGuiKey_H, ImGuiKey_I, ImGuiKey_J, - ImGuiKey_K, ImGuiKey_L, ImGuiKey_M, ImGuiKey_N, ImGuiKey_O, ImGuiKey_P, ImGuiKey_Q, ImGuiKey_R, ImGuiKey_S, ImGuiKey_T, - ImGuiKey_U, ImGuiKey_V, ImGuiKey_W, ImGuiKey_X, ImGuiKey_Y, ImGuiKey_Z, - ImGuiKey_F1, ImGuiKey_F2, ImGuiKey_F3, ImGuiKey_F4, ImGuiKey_F5, ImGuiKey_F6, - ImGuiKey_F7, ImGuiKey_F8, ImGuiKey_F9, ImGuiKey_F10, ImGuiKey_F11, ImGuiKey_F12, - ImGuiKey_F13, ImGuiKey_F14, ImGuiKey_F15, ImGuiKey_F16, ImGuiKey_F17, ImGuiKey_F18, - ImGuiKey_F19, ImGuiKey_F20, ImGuiKey_F21, ImGuiKey_F22, ImGuiKey_F23, ImGuiKey_F24, - ImGuiKey_Apostrophe, // ' - ImGuiKey_Comma, // , - ImGuiKey_Minus, // - - ImGuiKey_Period, // . - ImGuiKey_Slash, // / - ImGuiKey_Semicolon, // ; - ImGuiKey_Equal, // = - ImGuiKey_LeftBracket, // [ - ImGuiKey_Backslash, // \ (this text inhibit multiline comment caused by backslash) - ImGuiKey_RightBracket, // ] - ImGuiKey_GraveAccent, // ` + ImGuiKey_0, + ImGuiKey_1, + ImGuiKey_2, + ImGuiKey_3, + ImGuiKey_4, + ImGuiKey_5, + ImGuiKey_6, + ImGuiKey_7, + ImGuiKey_8, + ImGuiKey_9, + ImGuiKey_A, + ImGuiKey_B, + ImGuiKey_C, + ImGuiKey_D, + ImGuiKey_E, + ImGuiKey_F, + ImGuiKey_G, + ImGuiKey_H, + ImGuiKey_I, + ImGuiKey_J, + ImGuiKey_K, + ImGuiKey_L, + ImGuiKey_M, + ImGuiKey_N, + ImGuiKey_O, + ImGuiKey_P, + ImGuiKey_Q, + ImGuiKey_R, + ImGuiKey_S, + ImGuiKey_T, + ImGuiKey_U, + ImGuiKey_V, + ImGuiKey_W, + ImGuiKey_X, + ImGuiKey_Y, + ImGuiKey_Z, + ImGuiKey_F1, + ImGuiKey_F2, + ImGuiKey_F3, + ImGuiKey_F4, + ImGuiKey_F5, + ImGuiKey_F6, + ImGuiKey_F7, + ImGuiKey_F8, + ImGuiKey_F9, + ImGuiKey_F10, + ImGuiKey_F11, + ImGuiKey_F12, + ImGuiKey_F13, + ImGuiKey_F14, + ImGuiKey_F15, + ImGuiKey_F16, + ImGuiKey_F17, + ImGuiKey_F18, + ImGuiKey_F19, + ImGuiKey_F20, + ImGuiKey_F21, + ImGuiKey_F22, + ImGuiKey_F23, + ImGuiKey_F24, + ImGuiKey_Apostrophe, // ' + ImGuiKey_Comma, // , + ImGuiKey_Minus, // - + ImGuiKey_Period, // . + ImGuiKey_Slash, // / + ImGuiKey_Semicolon, // ; + ImGuiKey_Equal, // = + ImGuiKey_LeftBracket, // [ + ImGuiKey_Backslash, // \ (this text inhibit multiline comment caused by backslash) + ImGuiKey_RightBracket, // ] + ImGuiKey_GraveAccent, // ` ImGuiKey_CapsLock, ImGuiKey_ScrollLock, ImGuiKey_NumLock, ImGuiKey_PrintScreen, ImGuiKey_Pause, - ImGuiKey_Keypad0, ImGuiKey_Keypad1, ImGuiKey_Keypad2, ImGuiKey_Keypad3, ImGuiKey_Keypad4, - ImGuiKey_Keypad5, ImGuiKey_Keypad6, ImGuiKey_Keypad7, ImGuiKey_Keypad8, ImGuiKey_Keypad9, + ImGuiKey_Keypad0, + ImGuiKey_Keypad1, + ImGuiKey_Keypad2, + ImGuiKey_Keypad3, + ImGuiKey_Keypad4, + ImGuiKey_Keypad5, + ImGuiKey_Keypad6, + ImGuiKey_Keypad7, + ImGuiKey_Keypad8, + ImGuiKey_Keypad9, ImGuiKey_KeypadDecimal, ImGuiKey_KeypadDivide, ImGuiKey_KeypadMultiply, @@ -1566,128 +2396,183 @@ enum ImGuiKey : int ImGuiKey_KeypadAdd, ImGuiKey_KeypadEnter, ImGuiKey_KeypadEqual, - ImGuiKey_AppBack, // Available on some keyboard/mouses. Often referred as "Browser Back" + ImGuiKey_AppBack, // Available on some keyboard/mouses. Often referred as "Browser Back" ImGuiKey_AppForward, - ImGuiKey_Oem102, // Non-US backslash. + ImGuiKey_Oem102, // Non-US backslash. // Gamepad (some of those are analog values, 0.0f to 1.0f) // NAVIGATION ACTION // (download controller mapping PNG/PSD at http://dearimgui.com/controls_sheets) - ImGuiKey_GamepadStart, // Menu (Xbox) + (Switch) Start/Options (PS) - ImGuiKey_GamepadBack, // View (Xbox) - (Switch) Share (PS) - ImGuiKey_GamepadFaceLeft, // X (Xbox) Y (Switch) Square (PS) // Tap: Toggle Menu. Hold: Windowing mode (Focus/Move/Resize windows) - ImGuiKey_GamepadFaceRight, // B (Xbox) A (Switch) Circle (PS) // Cancel / Close / Exit - ImGuiKey_GamepadFaceUp, // Y (Xbox) X (Switch) Triangle (PS) // Text Input / On-screen Keyboard - ImGuiKey_GamepadFaceDown, // A (Xbox) B (Switch) Cross (PS) // Activate / Open / Toggle / Tweak - ImGuiKey_GamepadDpadLeft, // D-pad Left // Move / Tweak / Resize Window (in Windowing mode) - ImGuiKey_GamepadDpadRight, // D-pad Right // Move / Tweak / Resize Window (in Windowing mode) - ImGuiKey_GamepadDpadUp, // D-pad Up // Move / Tweak / Resize Window (in Windowing mode) - ImGuiKey_GamepadDpadDown, // D-pad Down // Move / Tweak / Resize Window (in Windowing mode) - ImGuiKey_GamepadL1, // L Bumper (Xbox) L (Switch) L1 (PS) // Tweak Slower / Focus Previous (in Windowing mode) - ImGuiKey_GamepadR1, // R Bumper (Xbox) R (Switch) R1 (PS) // Tweak Faster / Focus Next (in Windowing mode) - ImGuiKey_GamepadL2, // L Trig. (Xbox) ZL (Switch) L2 (PS) [Analog] - ImGuiKey_GamepadR2, // R Trig. (Xbox) ZR (Switch) R2 (PS) [Analog] - ImGuiKey_GamepadL3, // L Stick (Xbox) L3 (Switch) L3 (PS) - ImGuiKey_GamepadR3, // R Stick (Xbox) R3 (Switch) R3 (PS) - ImGuiKey_GamepadLStickLeft, // [Analog] // Move Window (in Windowing mode) - ImGuiKey_GamepadLStickRight, // [Analog] // Move Window (in Windowing mode) - ImGuiKey_GamepadLStickUp, // [Analog] // Move Window (in Windowing mode) - ImGuiKey_GamepadLStickDown, // [Analog] // Move Window (in Windowing mode) - ImGuiKey_GamepadRStickLeft, // [Analog] - ImGuiKey_GamepadRStickRight, // [Analog] - ImGuiKey_GamepadRStickUp, // [Analog] - ImGuiKey_GamepadRStickDown, // [Analog] + ImGuiKey_GamepadStart, // Menu (Xbox) + (Switch) Start/Options (PS) + ImGuiKey_GamepadBack, // View (Xbox) - (Switch) Share (PS) + ImGuiKey_GamepadFaceLeft, // X (Xbox) Y (Switch) Square (PS) // Tap: Toggle Menu. Hold: Windowing + // mode (Focus/Move/Resize windows) + ImGuiKey_GamepadFaceRight, // B (Xbox) A (Switch) Circle (PS) // Cancel / Close / Exit + ImGuiKey_GamepadFaceUp, // Y (Xbox) X (Switch) Triangle (PS) // Text Input / On-screen Keyboard + ImGuiKey_GamepadFaceDown, // A (Xbox) B (Switch) Cross (PS) // Activate / Open / Toggle / Tweak + ImGuiKey_GamepadDpadLeft, // D-pad Left // Move / Tweak / Resize Window (in + // Windowing mode) + ImGuiKey_GamepadDpadRight, // D-pad Right // Move / Tweak / Resize Window (in + // Windowing mode) + ImGuiKey_GamepadDpadUp, // D-pad Up // Move / Tweak / Resize Window (in + // Windowing mode) + ImGuiKey_GamepadDpadDown, // D-pad Down // Move / Tweak / Resize Window (in + // Windowing mode) + ImGuiKey_GamepadL1, // L Bumper (Xbox) L (Switch) L1 (PS) // Tweak Slower / Focus Previous (in + // Windowing mode) + ImGuiKey_GamepadR1, // R Bumper (Xbox) R (Switch) R1 (PS) // Tweak Faster / Focus Next (in Windowing + // mode) + ImGuiKey_GamepadL2, // L Trig. (Xbox) ZL (Switch) L2 (PS) [Analog] + ImGuiKey_GamepadR2, // R Trig. (Xbox) ZR (Switch) R2 (PS) [Analog] + ImGuiKey_GamepadL3, // L Stick (Xbox) L3 (Switch) L3 (PS) + ImGuiKey_GamepadR3, // R Stick (Xbox) R3 (Switch) R3 (PS) + ImGuiKey_GamepadLStickLeft, // [Analog] // Move Window (in Windowing mode) + ImGuiKey_GamepadLStickRight, // [Analog] // Move Window (in Windowing mode) + ImGuiKey_GamepadLStickUp, // [Analog] // Move Window (in Windowing mode) + ImGuiKey_GamepadLStickDown, // [Analog] // Move Window (in Windowing mode) + ImGuiKey_GamepadRStickLeft, // [Analog] + ImGuiKey_GamepadRStickRight, // [Analog] + ImGuiKey_GamepadRStickUp, // [Analog] + ImGuiKey_GamepadRStickDown, // [Analog] // Aliases: Mouse Buttons (auto-submitted from AddMouseButtonEvent() calls) - // - This is mirroring the data also written to io.MouseDown[], io.MouseWheel, in a format allowing them to be accessed via standard key API. - ImGuiKey_MouseLeft, ImGuiKey_MouseRight, ImGuiKey_MouseMiddle, ImGuiKey_MouseX1, ImGuiKey_MouseX2, ImGuiKey_MouseWheelX, ImGuiKey_MouseWheelY, + // - This is mirroring the data also written to io.MouseDown[], io.MouseWheel, in a format allowing them to be + // accessed via standard key API. + ImGuiKey_MouseLeft, + ImGuiKey_MouseRight, + ImGuiKey_MouseMiddle, + ImGuiKey_MouseX1, + ImGuiKey_MouseX2, + ImGuiKey_MouseWheelX, + ImGuiKey_MouseWheelY, // [Internal] Reserved for mod storage - ImGuiKey_ReservedForModCtrl, ImGuiKey_ReservedForModShift, ImGuiKey_ReservedForModAlt, ImGuiKey_ReservedForModSuper, + ImGuiKey_ReservedForModCtrl, + ImGuiKey_ReservedForModShift, + ImGuiKey_ReservedForModAlt, + ImGuiKey_ReservedForModSuper, ImGuiKey_NamedKey_END, // Keyboard Modifiers (explicitly submitted by backend via AddKeyEvent() calls) - // - This is mirroring the data also written to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper, in a format allowing - // them to be accessed via standard key API, allowing calls such as IsKeyPressed(), IsKeyReleased(), querying duration etc. + // - This is mirroring the data also written to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper, in a format + // allowing + // them to be accessed via standard key API, allowing calls such as IsKeyPressed(), IsKeyReleased(), querying + // duration etc. // - Code polling every key (e.g. an interface to detect a key press for input mapping) might want to ignore those // and prefer using the real keys (e.g. ImGuiKey_LeftCtrl, ImGuiKey_RightCtrl instead of ImGuiMod_Ctrl). - // - In theory the value of keyboard modifiers should be roughly equivalent to a logical or of the equivalent left/right keys. - // In practice: it's complicated; mods are often provided from different sources. Keyboard layout, IME, sticky keys and - // backends tend to interfere and break that equivalence. The safer decision is to relay that ambiguity down to the end-user... + // - In theory the value of keyboard modifiers should be roughly equivalent to a logical or of the equivalent + // left/right keys. + // In practice: it's complicated; mods are often provided from different sources. Keyboard layout, IME, sticky + // keys and backends tend to interfere and break that equivalence. The safer decision is to relay that ambiguity + // down to the end-user... // - On macOS, we swap Cmd(Super) and Ctrl keys at the time of the io.AddKeyEvent() call. - ImGuiMod_None = 0, - ImGuiMod_Ctrl = 1 << 12, // Ctrl (non-macOS), Cmd (macOS) - ImGuiMod_Shift = 1 << 13, // Shift - ImGuiMod_Alt = 1 << 14, // Option/Menu - ImGuiMod_Super = 1 << 15, // Windows/Super (non-macOS), Ctrl (macOS) - ImGuiMod_Mask_ = 0xF000, // 4-bits + ImGuiMod_None = 0, + ImGuiMod_Ctrl = 1 << 12, // Ctrl (non-macOS), Cmd (macOS) + ImGuiMod_Shift = 1 << 13, // Shift + ImGuiMod_Alt = 1 << 14, // Option/Menu + ImGuiMod_Super = 1 << 15, // Windows/Super (non-macOS), Ctrl (macOS) + ImGuiMod_Mask_ = 0xF000, // 4-bits - // [Internal] If you need to iterate all keys (for e.g. an input mapper) you may use ImGuiKey_NamedKey_BEGIN..ImGuiKey_NamedKey_END. - ImGuiKey_NamedKey_COUNT = ImGuiKey_NamedKey_END - ImGuiKey_NamedKey_BEGIN, - //ImGuiKey_KeysData_SIZE = ImGuiKey_NamedKey_COUNT, // Size of KeysData[]: only hold named keys - //ImGuiKey_KeysData_OFFSET = ImGuiKey_NamedKey_BEGIN, // Accesses to io.KeysData[] must use (key - ImGuiKey_NamedKey_BEGIN) index. + // [Internal] If you need to iterate all keys (for e.g. an input mapper) you may use + // ImGuiKey_NamedKey_BEGIN..ImGuiKey_NamedKey_END. + ImGuiKey_NamedKey_COUNT = ImGuiKey_NamedKey_END - ImGuiKey_NamedKey_BEGIN, + // ImGuiKey_KeysData_SIZE = ImGuiKey_NamedKey_COUNT, // Size of KeysData[]: only hold named keys + // ImGuiKey_KeysData_OFFSET = ImGuiKey_NamedKey_BEGIN, // Accesses to io.KeysData[] must use (key - + // ImGuiKey_NamedKey_BEGIN) index. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImGuiKey_COUNT = ImGuiKey_NamedKey_END, // Obsoleted in 1.91.5 because it was extremely misleading (since named keys don't start at 0 anymore) - ImGuiMod_Shortcut = ImGuiMod_Ctrl, // Removed in 1.90.7, you can now simply use ImGuiMod_Ctrl - ImGuiKey_ModCtrl = ImGuiMod_Ctrl, ImGuiKey_ModShift = ImGuiMod_Shift, ImGuiKey_ModAlt = ImGuiMod_Alt, ImGuiKey_ModSuper = ImGuiMod_Super, // Renamed in 1.89 - //ImGuiKey_KeyPadEnter = ImGuiKey_KeypadEnter, // Renamed in 1.87 + ImGuiKey_COUNT = ImGuiKey_NamedKey_END, // Obsoleted in 1.91.5 because it was extremely misleading (since named keys + // don't start at 0 anymore) + ImGuiMod_Shortcut = ImGuiMod_Ctrl, // Removed in 1.90.7, you can now simply use ImGuiMod_Ctrl + ImGuiKey_ModCtrl = ImGuiMod_Ctrl, + ImGuiKey_ModShift = ImGuiMod_Shift, + ImGuiKey_ModAlt = ImGuiMod_Alt, + ImGuiKey_ModSuper = ImGuiMod_Super, // Renamed in 1.89 + // ImGuiKey_KeyPadEnter = ImGuiKey_KeypadEnter, // Renamed in 1.87 #endif }; // Flags for Shortcut(), SetNextItemShortcut(), -// (and for upcoming extended versions of IsKeyPressed(), IsMouseClicked(), Shortcut(), SetKeyOwner(), SetItemKeyOwner() that are still in imgui_internal.h) -// Don't mistake with ImGuiInputTextFlags! (which is for ImGui::InputText() function) +// (and for upcoming extended versions of IsKeyPressed(), IsMouseClicked(), Shortcut(), SetKeyOwner(), SetItemKeyOwner() +// that are still in imgui_internal.h) Don't mistake with ImGuiInputTextFlags! (which is for ImGui::InputText() +// function) enum ImGuiInputFlags_ { - ImGuiInputFlags_None = 0, - ImGuiInputFlags_Repeat = 1 << 0, // Enable repeat. Return true on successive repeats. Default for legacy IsKeyPressed(). NOT Default for legacy IsMouseClicked(). MUST BE == 1. + ImGuiInputFlags_None = 0, + ImGuiInputFlags_Repeat = 1 << 0, // Enable repeat. Return true on successive repeats. Default for legacy + // IsKeyPressed(). NOT Default for legacy IsMouseClicked(). MUST BE == 1. // Flags for Shortcut(), SetNextItemShortcut() - // - Routing policies: RouteGlobal+OverActive >> RouteActive or RouteFocused (if owner is active item) >> RouteGlobal+OverFocused >> RouteFocused (if in focused window stack) >> RouteGlobal. + // - Routing policies: RouteGlobal+OverActive >> RouteActive or RouteFocused (if owner is active item) >> + // RouteGlobal+OverFocused >> RouteFocused (if in focused window stack) >> RouteGlobal. // - Default policy is RouteFocused. Can select only 1 policy among all available. - ImGuiInputFlags_RouteActive = 1 << 10, // Route to active item only. - ImGuiInputFlags_RouteFocused = 1 << 11, // Route to windows in the focus stack (DEFAULT). Deep-most focused window takes inputs. Active item takes inputs over deep-most focused window. - ImGuiInputFlags_RouteGlobal = 1 << 12, // Global route (unless a focused window or active item registered the route). - ImGuiInputFlags_RouteAlways = 1 << 13, // Do not register route, poll keys directly. + ImGuiInputFlags_RouteActive = 1 << 10, // Route to active item only. + ImGuiInputFlags_RouteFocused = 1 << 11, // Route to windows in the focus stack (DEFAULT). Deep-most focused window + // takes inputs. Active item takes inputs over deep-most focused window. + ImGuiInputFlags_RouteGlobal = + 1 << 12, // Global route (unless a focused window or active item registered the route). + ImGuiInputFlags_RouteAlways = 1 << 13, // Do not register route, poll keys directly. // - Routing options - ImGuiInputFlags_RouteOverFocused = 1 << 14, // Option: global route: higher priority than focused route (unless active item in focused route). - ImGuiInputFlags_RouteOverActive = 1 << 15, // Option: global route: higher priority than active item. Unlikely you need to use that: will interfere with every active items, e.g. CTRL+A registered by InputText will be overridden by this. May not be fully honored as user/internal code is likely to always assume they can access keys when active. - ImGuiInputFlags_RouteUnlessBgFocused = 1 << 16, // Option: global route: will not be applied if underlying background/void is focused (== no Dear ImGui windows are focused). Useful for overlay applications. - ImGuiInputFlags_RouteFromRootWindow = 1 << 17, // Option: route evaluated from the point of view of root window rather than current window. + ImGuiInputFlags_RouteOverFocused = + 1 << 14, // Option: global route: higher priority than focused route (unless active item in focused route). + ImGuiInputFlags_RouteOverActive = + 1 + << 15, // Option: global route: higher priority than active item. Unlikely you need to use that: will interfere + // with every active items, e.g. CTRL+A registered by InputText will be overridden by this. May not be + // fully honored as user/internal code is likely to always assume they can access keys when active. + ImGuiInputFlags_RouteUnlessBgFocused = + 1 << 16, // Option: global route: will not be applied if underlying background/void is focused (== no Dear ImGui + // windows are focused). Useful for overlay applications. + ImGuiInputFlags_RouteFromRootWindow = + 1 << 17, // Option: route evaluated from the point of view of root window rather than current window. // Flags for SetNextItemShortcut() - ImGuiInputFlags_Tooltip = 1 << 18, // Automatically display a tooltip when hovering item [BETA] Unsure of right api (opt-in/opt-out) + ImGuiInputFlags_Tooltip = + 1 << 18, // Automatically display a tooltip when hovering item [BETA] Unsure of right api (opt-in/opt-out) }; // Configuration flags stored in io.ConfigFlags. Set by user/application. enum ImGuiConfigFlags_ { - ImGuiConfigFlags_None = 0, - ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. Enable full Tabbing + directional arrows + space/enter to activate. - ImGuiConfigFlags_NavEnableGamepad = 1 << 1, // Master gamepad navigation enable flag. Backend also needs to set ImGuiBackendFlags_HasGamepad. - ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct dear imgui to disable mouse inputs and interactions. - ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct backend to not alter mouse cursor shape and visibility. Use if the backend cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead. - ImGuiConfigFlags_NoKeyboard = 1 << 6, // Instruct dear imgui to disable keyboard inputs and interactions. This is done by ignoring keyboard events and clearing existing states. + ImGuiConfigFlags_None = 0, + ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. Enable full Tabbing + + // directional arrows + space/enter to activate. + ImGuiConfigFlags_NavEnableGamepad = + 1 << 1, // Master gamepad navigation enable flag. Backend also needs to set ImGuiBackendFlags_HasGamepad. + ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct dear imgui to disable mouse inputs and interactions. + ImGuiConfigFlags_NoMouseCursorChange = + 1 << 5, // Instruct backend to not alter mouse cursor shape and visibility. Use if the backend cursor changes + // are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may + // want to honor requests from imgui by reading GetMouseCursor() yourself instead. + ImGuiConfigFlags_NoKeyboard = 1 << 6, // Instruct dear imgui to disable keyboard inputs and interactions. This is + // done by ignoring keyboard events and clearing existing states. - // User storage (to allow your backend/engine to communicate to code that may be shared between multiple projects. Those flags are NOT used by core Dear ImGui) - ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware. - ImGuiConfigFlags_IsTouchScreen = 1 << 21, // Application is using a touch screen instead of a mouse. + // User storage (to allow your backend/engine to communicate to code that may be shared between multiple projects. + // Those flags are NOT used by core Dear ImGui) + ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware. + ImGuiConfigFlags_IsTouchScreen = 1 << 21, // Application is using a touch screen instead of a mouse. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // [moved/renamed in 1.91.4] -> use bool io.ConfigNavMoveSetMousePos - ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // [moved/renamed in 1.91.4] -> use bool io.ConfigNavCaptureKeyboard + ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // [moved/renamed in 1.91.4] -> use bool io.ConfigNavMoveSetMousePos + ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // [moved/renamed in 1.91.4] -> use bool io.ConfigNavCaptureKeyboard #endif }; // Backend capabilities flags stored in io.BackendFlags. Set by imgui_impl_xxx or custom backend. enum ImGuiBackendFlags_ { - ImGuiBackendFlags_None = 0, - ImGuiBackendFlags_HasGamepad = 1 << 0, // Backend Platform supports gamepad and currently has one connected. - ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Backend Platform supports honoring GetMouseCursor() value to change the OS cursor shape. - ImGuiBackendFlags_HasSetMousePos = 1 << 2, // Backend Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if io.ConfigNavMoveSetMousePos is set). - ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3, // Backend Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bit indices. - ImGuiBackendFlags_RendererHasTextures = 1 << 4, // Backend Renderer supports ImTextureData requests to create/update/destroy textures. This enables incremental texture updates and texture reloads. + ImGuiBackendFlags_None = 0, + ImGuiBackendFlags_HasGamepad = 1 << 0, // Backend Platform supports gamepad and currently has one connected. + ImGuiBackendFlags_HasMouseCursors = + 1 << 1, // Backend Platform supports honoring GetMouseCursor() value to change the OS cursor shape. + ImGuiBackendFlags_HasSetMousePos = + 1 << 2, // Backend Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used + // if io.ConfigNavMoveSetMousePos is set). + ImGuiBackendFlags_RendererHasVtxOffset = + 1 << 3, // Backend Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) + // while still using 16-bit indices. + ImGuiBackendFlags_RendererHasTextures = + 1 << 4, // Backend Renderer supports ImTextureData requests to create/update/destroy textures. This enables + // incremental texture updates and texture reloads. }; // Enumeration for PushStyleColor() / PopStyleColor() @@ -1695,45 +2580,45 @@ enum ImGuiCol_ { ImGuiCol_Text, ImGuiCol_TextDisabled, - ImGuiCol_WindowBg, // Background of normal windows - ImGuiCol_ChildBg, // Background of child windows - ImGuiCol_PopupBg, // Background of popups, menus, tooltips windows + ImGuiCol_WindowBg, // Background of normal windows + ImGuiCol_ChildBg, // Background of child windows + ImGuiCol_PopupBg, // Background of popups, menus, tooltips windows ImGuiCol_Border, ImGuiCol_BorderShadow, - ImGuiCol_FrameBg, // Background of checkbox, radio button, plot, slider, text input + ImGuiCol_FrameBg, // Background of checkbox, radio button, plot, slider, text input ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive, - ImGuiCol_TitleBg, // Title bar - ImGuiCol_TitleBgActive, // Title bar when focused - ImGuiCol_TitleBgCollapsed, // Title bar when collapsed + ImGuiCol_TitleBg, // Title bar + ImGuiCol_TitleBgActive, // Title bar when focused + ImGuiCol_TitleBgCollapsed, // Title bar when collapsed ImGuiCol_MenuBarBg, ImGuiCol_ScrollbarBg, ImGuiCol_ScrollbarGrab, ImGuiCol_ScrollbarGrabHovered, ImGuiCol_ScrollbarGrabActive, - ImGuiCol_CheckMark, // Checkbox tick and RadioButton circle + ImGuiCol_CheckMark, // Checkbox tick and RadioButton circle ImGuiCol_SliderGrab, ImGuiCol_SliderGrabActive, ImGuiCol_Button, ImGuiCol_ButtonHovered, ImGuiCol_ButtonActive, - ImGuiCol_Header, // Header* colors are used for CollapsingHeader, TreeNode, Selectable, MenuItem + ImGuiCol_Header, // Header* colors are used for CollapsingHeader, TreeNode, Selectable, MenuItem ImGuiCol_HeaderHovered, ImGuiCol_HeaderActive, ImGuiCol_Separator, ImGuiCol_SeparatorHovered, ImGuiCol_SeparatorActive, - ImGuiCol_ResizeGrip, // Resize grip in lower-right and lower-left corners of windows. + ImGuiCol_ResizeGrip, // Resize grip in lower-right and lower-left corners of windows. ImGuiCol_ResizeGripHovered, ImGuiCol_ResizeGripActive, - ImGuiCol_InputTextCursor, // InputText cursor/caret - ImGuiCol_TabHovered, // Tab background, when hovered - ImGuiCol_Tab, // Tab background, when tab-bar is focused & tab is unselected - ImGuiCol_TabSelected, // Tab background, when tab-bar is focused & tab is selected - ImGuiCol_TabSelectedOverline, // Tab horizontal overline, when tab-bar is focused & tab is selected - ImGuiCol_TabDimmed, // Tab background, when tab-bar is unfocused & tab is unselected - ImGuiCol_TabDimmedSelected, // Tab background, when tab-bar is unfocused & tab is selected - ImGuiCol_TabDimmedSelectedOverline,//..horizontal overline, when tab-bar is unfocused & tab is selected + ImGuiCol_InputTextCursor, // InputText cursor/caret + ImGuiCol_TabHovered, // Tab background, when hovered + ImGuiCol_Tab, // Tab background, when tab-bar is focused & tab is unselected + ImGuiCol_TabSelected, // Tab background, when tab-bar is focused & tab is selected + ImGuiCol_TabSelectedOverline, // Tab horizontal overline, when tab-bar is focused & tab is selected + ImGuiCol_TabDimmed, // Tab background, when tab-bar is unfocused & tab is unselected + ImGuiCol_TabDimmedSelected, // Tab background, when tab-bar is unfocused & tab is selected + ImGuiCol_TabDimmedSelectedOverline, //..horizontal overline, when tab-bar is unfocused & tab is selected ImGuiCol_PlotLines, ImGuiCol_PlotLinesHovered, ImGuiCol_PlotHistogram, @@ -1754,143 +2639,194 @@ enum ImGuiCol_ ImGuiCol_COUNT, #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImGuiCol_TabActive = ImGuiCol_TabSelected, // [renamed in 1.90.9] - ImGuiCol_TabUnfocused = ImGuiCol_TabDimmed, // [renamed in 1.90.9] - ImGuiCol_TabUnfocusedActive = ImGuiCol_TabDimmedSelected, // [renamed in 1.90.9] - ImGuiCol_NavHighlight = ImGuiCol_NavCursor, // [renamed in 1.91.4] + ImGuiCol_TabActive = ImGuiCol_TabSelected, // [renamed in 1.90.9] + ImGuiCol_TabUnfocused = ImGuiCol_TabDimmed, // [renamed in 1.90.9] + ImGuiCol_TabUnfocusedActive = ImGuiCol_TabDimmedSelected, // [renamed in 1.90.9] + ImGuiCol_NavHighlight = ImGuiCol_NavCursor, // [renamed in 1.91.4] #endif }; // Enumeration for PushStyleVar() / PopStyleVar() to temporarily modify the ImGuiStyle structure. // - The enum only refers to fields of ImGuiStyle which makes sense to be pushed/popped inside UI code. // During initialization or between frames, feel free to just poke into ImGuiStyle directly. -// - Tip: Use your programming IDE navigation facilities on the names in the _second column_ below to find the actual members and their description. -// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. -// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments. +// - Tip: Use your programming IDE navigation facilities on the names in the _second column_ below to find the actual +// members and their description. +// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 +// ("Edit.GoToImplementation") cannot. +// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside +// comments. // - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments. -// - When changing this enum, you need to update the associated internal table GStyleVarInfo[] accordingly. This is where we link enum values to members offset/type. +// - When changing this enum, you need to update the associated internal table GStyleVarInfo[] accordingly. This is +// where we link enum values to members offset/type. enum ImGuiStyleVar_ { // Enum name -------------------------- // Member in ImGuiStyle structure (see ImGuiStyle for descriptions) - ImGuiStyleVar_Alpha, // float Alpha - ImGuiStyleVar_DisabledAlpha, // float DisabledAlpha - ImGuiStyleVar_WindowPadding, // ImVec2 WindowPadding - ImGuiStyleVar_WindowRounding, // float WindowRounding - ImGuiStyleVar_WindowBorderSize, // float WindowBorderSize - ImGuiStyleVar_WindowMinSize, // ImVec2 WindowMinSize - ImGuiStyleVar_WindowTitleAlign, // ImVec2 WindowTitleAlign - ImGuiStyleVar_ChildRounding, // float ChildRounding - ImGuiStyleVar_ChildBorderSize, // float ChildBorderSize - ImGuiStyleVar_PopupRounding, // float PopupRounding - ImGuiStyleVar_PopupBorderSize, // float PopupBorderSize - ImGuiStyleVar_FramePadding, // ImVec2 FramePadding - ImGuiStyleVar_FrameRounding, // float FrameRounding - ImGuiStyleVar_FrameBorderSize, // float FrameBorderSize - ImGuiStyleVar_ItemSpacing, // ImVec2 ItemSpacing - ImGuiStyleVar_ItemInnerSpacing, // ImVec2 ItemInnerSpacing - ImGuiStyleVar_IndentSpacing, // float IndentSpacing - ImGuiStyleVar_CellPadding, // ImVec2 CellPadding - ImGuiStyleVar_ScrollbarSize, // float ScrollbarSize - ImGuiStyleVar_ScrollbarRounding, // float ScrollbarRounding - ImGuiStyleVar_GrabMinSize, // float GrabMinSize - ImGuiStyleVar_GrabRounding, // float GrabRounding - ImGuiStyleVar_ImageBorderSize, // float ImageBorderSize - ImGuiStyleVar_TabRounding, // float TabRounding - ImGuiStyleVar_TabBorderSize, // float TabBorderSize - ImGuiStyleVar_TabBarBorderSize, // float TabBarBorderSize - ImGuiStyleVar_TabBarOverlineSize, // float TabBarOverlineSize - ImGuiStyleVar_TableAngledHeadersAngle, // float TableAngledHeadersAngle - ImGuiStyleVar_TableAngledHeadersTextAlign,// ImVec2 TableAngledHeadersTextAlign - ImGuiStyleVar_TreeLinesSize, // float TreeLinesSize - ImGuiStyleVar_TreeLinesRounding, // float TreeLinesRounding - ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign - ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign - ImGuiStyleVar_SeparatorTextBorderSize, // float SeparatorTextBorderSize - ImGuiStyleVar_SeparatorTextAlign, // ImVec2 SeparatorTextAlign - ImGuiStyleVar_SeparatorTextPadding, // ImVec2 SeparatorTextPadding + ImGuiStyleVar_Alpha, // float Alpha + ImGuiStyleVar_DisabledAlpha, // float DisabledAlpha + ImGuiStyleVar_WindowPadding, // ImVec2 WindowPadding + ImGuiStyleVar_WindowRounding, // float WindowRounding + ImGuiStyleVar_WindowBorderSize, // float WindowBorderSize + ImGuiStyleVar_WindowMinSize, // ImVec2 WindowMinSize + ImGuiStyleVar_WindowTitleAlign, // ImVec2 WindowTitleAlign + ImGuiStyleVar_ChildRounding, // float ChildRounding + ImGuiStyleVar_ChildBorderSize, // float ChildBorderSize + ImGuiStyleVar_PopupRounding, // float PopupRounding + ImGuiStyleVar_PopupBorderSize, // float PopupBorderSize + ImGuiStyleVar_FramePadding, // ImVec2 FramePadding + ImGuiStyleVar_FrameRounding, // float FrameRounding + ImGuiStyleVar_FrameBorderSize, // float FrameBorderSize + ImGuiStyleVar_ItemSpacing, // ImVec2 ItemSpacing + ImGuiStyleVar_ItemInnerSpacing, // ImVec2 ItemInnerSpacing + ImGuiStyleVar_IndentSpacing, // float IndentSpacing + ImGuiStyleVar_CellPadding, // ImVec2 CellPadding + ImGuiStyleVar_ScrollbarSize, // float ScrollbarSize + ImGuiStyleVar_ScrollbarRounding, // float ScrollbarRounding + ImGuiStyleVar_GrabMinSize, // float GrabMinSize + ImGuiStyleVar_GrabRounding, // float GrabRounding + ImGuiStyleVar_ImageBorderSize, // float ImageBorderSize + ImGuiStyleVar_TabRounding, // float TabRounding + ImGuiStyleVar_TabBorderSize, // float TabBorderSize + ImGuiStyleVar_TabBarBorderSize, // float TabBarBorderSize + ImGuiStyleVar_TabBarOverlineSize, // float TabBarOverlineSize + ImGuiStyleVar_TableAngledHeadersAngle, // float TableAngledHeadersAngle + ImGuiStyleVar_TableAngledHeadersTextAlign, // ImVec2 TableAngledHeadersTextAlign + ImGuiStyleVar_TreeLinesSize, // float TreeLinesSize + ImGuiStyleVar_TreeLinesRounding, // float TreeLinesRounding + ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign + ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign + ImGuiStyleVar_SeparatorTextBorderSize, // float SeparatorTextBorderSize + ImGuiStyleVar_SeparatorTextAlign, // ImVec2 SeparatorTextAlign + ImGuiStyleVar_SeparatorTextPadding, // ImVec2 SeparatorTextPadding ImGuiStyleVar_COUNT }; // Flags for InvisibleButton() [extended in imgui_internal.h] enum ImGuiButtonFlags_ { - ImGuiButtonFlags_None = 0, - ImGuiButtonFlags_MouseButtonLeft = 1 << 0, // React on left mouse button (default) - ImGuiButtonFlags_MouseButtonRight = 1 << 1, // React on right mouse button - ImGuiButtonFlags_MouseButtonMiddle = 1 << 2, // React on center mouse button - ImGuiButtonFlags_MouseButtonMask_ = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle, // [Internal] - ImGuiButtonFlags_EnableNav = 1 << 3, // InvisibleButton(): do not disable navigation/tabbing. Otherwise disabled by default. + ImGuiButtonFlags_None = 0, + ImGuiButtonFlags_MouseButtonLeft = 1 << 0, // React on left mouse button (default) + ImGuiButtonFlags_MouseButtonRight = 1 << 1, // React on right mouse button + ImGuiButtonFlags_MouseButtonMiddle = 1 << 2, // React on center mouse button + ImGuiButtonFlags_MouseButtonMask_ = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | + ImGuiButtonFlags_MouseButtonMiddle, // [Internal] + ImGuiButtonFlags_EnableNav = + 1 << 3, // InvisibleButton(): do not disable navigation/tabbing. Otherwise disabled by default. }; // Flags for ColorEdit3() / ColorEdit4() / ColorPicker3() / ColorPicker4() / ColorButton() enum ImGuiColorEditFlags_ { - ImGuiColorEditFlags_None = 0, - ImGuiColorEditFlags_NoAlpha = 1 << 1, // // ColorEdit, ColorPicker, ColorButton: ignore Alpha component (will only read 3 components from the input pointer). - ImGuiColorEditFlags_NoPicker = 1 << 2, // // ColorEdit: disable picker when clicking on color square. - ImGuiColorEditFlags_NoOptions = 1 << 3, // // ColorEdit: disable toggling options menu when right-clicking on inputs/small preview. - ImGuiColorEditFlags_NoSmallPreview = 1 << 4, // // ColorEdit, ColorPicker: disable color square preview next to the inputs. (e.g. to show only the inputs) - ImGuiColorEditFlags_NoInputs = 1 << 5, // // ColorEdit, ColorPicker: disable inputs sliders/text widgets (e.g. to show only the small preview color square). - ImGuiColorEditFlags_NoTooltip = 1 << 6, // // ColorEdit, ColorPicker, ColorButton: disable tooltip when hovering the preview. - ImGuiColorEditFlags_NoLabel = 1 << 7, // // ColorEdit, ColorPicker: disable display of inline text label (the label is still forwarded to the tooltip and picker). - ImGuiColorEditFlags_NoSidePreview = 1 << 8, // // ColorPicker: disable bigger color preview on right side of the picker, use small color square preview instead. - ImGuiColorEditFlags_NoDragDrop = 1 << 9, // // ColorEdit: disable drag and drop target. ColorButton: disable drag and drop source. - ImGuiColorEditFlags_NoBorder = 1 << 10, // // ColorButton: disable border (which is enforced by default) + ImGuiColorEditFlags_None = 0, + ImGuiColorEditFlags_NoAlpha = 1 << 1, // // ColorEdit, ColorPicker, ColorButton: ignore Alpha component + // (will only read 3 components from the input pointer). + ImGuiColorEditFlags_NoPicker = 1 << 2, // // ColorEdit: disable picker when clicking on color square. + ImGuiColorEditFlags_NoOptions = + 1 << 3, // // ColorEdit: disable toggling options menu when right-clicking on inputs/small preview. + ImGuiColorEditFlags_NoSmallPreview = 1 << 4, // // ColorEdit, ColorPicker: disable color square preview + // next to the inputs. (e.g. to show only the inputs) + ImGuiColorEditFlags_NoInputs = 1 << 5, // // ColorEdit, ColorPicker: disable inputs sliders/text + // widgets (e.g. to show only the small preview color square). + ImGuiColorEditFlags_NoTooltip = + 1 << 6, // // ColorEdit, ColorPicker, ColorButton: disable tooltip when hovering the preview. + ImGuiColorEditFlags_NoLabel = + 1 << 7, // // ColorEdit, ColorPicker: disable display of inline text label (the label is still + // forwarded to the tooltip and picker). + ImGuiColorEditFlags_NoSidePreview = 1 + << 8, // // ColorPicker: disable bigger color preview on right side + // of the picker, use small color square preview instead. + ImGuiColorEditFlags_NoDragDrop = + 1 << 9, // // ColorEdit: disable drag and drop target. ColorButton: disable drag and drop source. + ImGuiColorEditFlags_NoBorder = + 1 << 10, // // ColorButton: disable border (which is enforced by default) // Alpha preview - // - Prior to 1.91.8 (2025/01/21): alpha was made opaque in the preview by default using old name ImGuiColorEditFlags_AlphaPreview. - // - We now display the preview as transparent by default. You can use ImGuiColorEditFlags_AlphaOpaque to use old behavior. + // - Prior to 1.91.8 (2025/01/21): alpha was made opaque in the preview by default using old name + // ImGuiColorEditFlags_AlphaPreview. + // - We now display the preview as transparent by default. You can use ImGuiColorEditFlags_AlphaOpaque to use old + // behavior. // - The new flags may be combined better and allow finer controls. - ImGuiColorEditFlags_AlphaOpaque = 1 << 11, // // ColorEdit, ColorPicker, ColorButton: disable alpha in the preview,. Contrary to _NoAlpha it may still be edited when calling ColorEdit4()/ColorPicker4(). For ColorButton() this does the same as _NoAlpha. - ImGuiColorEditFlags_AlphaNoBg = 1 << 12, // // ColorEdit, ColorPicker, ColorButton: disable rendering a checkerboard background behind transparent color. - ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 13, // // ColorEdit, ColorPicker, ColorButton: display half opaque / half transparent preview. + ImGuiColorEditFlags_AlphaOpaque = + 1 << 11, // // ColorEdit, ColorPicker, ColorButton: disable alpha in the preview,. Contrary to + // _NoAlpha it may still be edited when calling ColorEdit4()/ColorPicker4(). For + // ColorButton() this does the same as _NoAlpha. + ImGuiColorEditFlags_AlphaNoBg = 1 << 12, // // ColorEdit, ColorPicker, ColorButton: disable rendering a + // checkerboard background behind transparent color. + ImGuiColorEditFlags_AlphaPreviewHalf = + 1 << 13, // // ColorEdit, ColorPicker, ColorButton: display half opaque / half transparent preview. // User Options (right-click on widget to change some of them). - ImGuiColorEditFlags_AlphaBar = 1 << 16, // // ColorEdit, ColorPicker: show vertical alpha bar/gradient in picker. - ImGuiColorEditFlags_HDR = 1 << 19, // // (WIP) ColorEdit: Currently only disable 0.0f..1.0f limits in RGBA edition (note: you probably want to use ImGuiColorEditFlags_Float flag as well). - ImGuiColorEditFlags_DisplayRGB = 1 << 20, // [Display] // ColorEdit: override _display_ type among RGB/HSV/Hex. ColorPicker: select any combination using one or more of RGB/HSV/Hex. - ImGuiColorEditFlags_DisplayHSV = 1 << 21, // [Display] // " - ImGuiColorEditFlags_DisplayHex = 1 << 22, // [Display] // " - ImGuiColorEditFlags_Uint8 = 1 << 23, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0..255. - ImGuiColorEditFlags_Float = 1 << 24, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0.0f..1.0f floats instead of 0..255 integers. No round-trip of value via integers. - ImGuiColorEditFlags_PickerHueBar = 1 << 25, // [Picker] // ColorPicker: bar for Hue, rectangle for Sat/Value. - ImGuiColorEditFlags_PickerHueWheel = 1 << 26, // [Picker] // ColorPicker: wheel for Hue, triangle for Sat/Value. - ImGuiColorEditFlags_InputRGB = 1 << 27, // [Input] // ColorEdit, ColorPicker: input and output data in RGB format. - ImGuiColorEditFlags_InputHSV = 1 << 28, // [Input] // ColorEdit, ColorPicker: input and output data in HSV format. + ImGuiColorEditFlags_AlphaBar = + 1 << 16, // // ColorEdit, ColorPicker: show vertical alpha bar/gradient in picker. + ImGuiColorEditFlags_HDR = + 1 << 19, // // (WIP) ColorEdit: Currently only disable 0.0f..1.0f limits in RGBA edition (note: you + // probably want to use ImGuiColorEditFlags_Float flag as well). + ImGuiColorEditFlags_DisplayRGB = 1 << 20, // [Display] // ColorEdit: override _display_ type among RGB/HSV/Hex. + // ColorPicker: select any combination using one or more of RGB/HSV/Hex. + ImGuiColorEditFlags_DisplayHSV = 1 << 21, // [Display] // " + ImGuiColorEditFlags_DisplayHex = 1 << 22, // [Display] // " + ImGuiColorEditFlags_Uint8 = + 1 << 23, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0..255. + ImGuiColorEditFlags_Float = + 1 << 24, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0.0f..1.0f floats + // instead of 0..255 integers. No round-trip of value via integers. + ImGuiColorEditFlags_PickerHueBar = 1 << 25, // [Picker] // ColorPicker: bar for Hue, rectangle for Sat/Value. + ImGuiColorEditFlags_PickerHueWheel = 1 << 26, // [Picker] // ColorPicker: wheel for Hue, triangle for Sat/Value. + ImGuiColorEditFlags_InputRGB = + 1 << 27, // [Input] // ColorEdit, ColorPicker: input and output data in RGB format. + ImGuiColorEditFlags_InputHSV = + 1 << 28, // [Input] // ColorEdit, ColorPicker: input and output data in HSV format. - // Defaults Options. You can set application defaults using SetColorEditOptions(). The intent is that you probably don't want to - // override them in most of your calls. Let the user choose via the option menu and/or call SetColorEditOptions() once during startup. - ImGuiColorEditFlags_DefaultOptions_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar, + // Defaults Options. You can set application defaults using SetColorEditOptions(). The intent is that you probably + // don't want to override them in most of your calls. Let the user choose via the option menu and/or call + // SetColorEditOptions() once during startup. + ImGuiColorEditFlags_DefaultOptions_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | + ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar, // [Internal] Masks - ImGuiColorEditFlags_AlphaMask_ = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaOpaque | ImGuiColorEditFlags_AlphaNoBg | ImGuiColorEditFlags_AlphaPreviewHalf, - ImGuiColorEditFlags_DisplayMask_ = ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_DisplayHex, - ImGuiColorEditFlags_DataTypeMask_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_Float, - ImGuiColorEditFlags_PickerMask_ = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar, - ImGuiColorEditFlags_InputMask_ = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_InputHSV, + ImGuiColorEditFlags_AlphaMask_ = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaOpaque | + ImGuiColorEditFlags_AlphaNoBg | ImGuiColorEditFlags_AlphaPreviewHalf, + ImGuiColorEditFlags_DisplayMask_ = + ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_DisplayHex, + ImGuiColorEditFlags_DataTypeMask_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_Float, + ImGuiColorEditFlags_PickerMask_ = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar, + ImGuiColorEditFlags_InputMask_ = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_InputHSV, // Obsolete names #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImGuiColorEditFlags_AlphaPreview = 0, // [Removed in 1.91.8] This is the default now. Will display a checkerboard unless ImGuiColorEditFlags_AlphaNoBg is set. + ImGuiColorEditFlags_AlphaPreview = 0, // [Removed in 1.91.8] This is the default now. Will display a checkerboard + // unless ImGuiColorEditFlags_AlphaNoBg is set. #endif - //ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex // [renamed in 1.69] + // ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = + // ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex // [renamed in 1.69] }; // Flags for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc. -// We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them. -// (Those are per-item flags. There is shared behavior flag too: ImGuiIO: io.ConfigDragClickToInputText) +// We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it +// easier to swap them. (Those are per-item flags. There is shared behavior flag too: ImGuiIO: +// io.ConfigDragClickToInputText) enum ImGuiSliderFlags_ { - ImGuiSliderFlags_None = 0, - ImGuiSliderFlags_Logarithmic = 1 << 5, // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlags_NoRoundToFormat with this if using a format-string with small amount of digits. - ImGuiSliderFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits). - ImGuiSliderFlags_NoInput = 1 << 7, // Disable CTRL+Click or Enter key allowing to input text directly into the widget. - ImGuiSliderFlags_WrapAround = 1 << 8, // Enable wrapping around from max to min and from min to max. Only supported by DragXXX() functions for now. - ImGuiSliderFlags_ClampOnInput = 1 << 9, // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds. - ImGuiSliderFlags_ClampZeroRange = 1 << 10, // Clamp even if min==max==0.0f. Otherwise due to legacy reason DragXXX functions don't clamp with those values. When your clamping limits are dynamic you almost always want to use it. - ImGuiSliderFlags_NoSpeedTweaks = 1 << 11, // Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic. - ImGuiSliderFlags_AlwaysClamp = ImGuiSliderFlags_ClampOnInput | ImGuiSliderFlags_ClampZeroRange, - ImGuiSliderFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed. + ImGuiSliderFlags_None = 0, + ImGuiSliderFlags_Logarithmic = + 1 << 5, // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlags_NoRoundToFormat with + // this if using a format-string with small amount of digits. + ImGuiSliderFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display + // format string (e.g. %.3f values are rounded to those 3 digits). + ImGuiSliderFlags_NoInput = + 1 << 7, // Disable CTRL+Click or Enter key allowing to input text directly into the widget. + ImGuiSliderFlags_WrapAround = 1 << 8, // Enable wrapping around from max to min and from min to max. Only supported + // by DragXXX() functions for now. + ImGuiSliderFlags_ClampOnInput = 1 << 9, // Clamp value to min/max bounds when input manually with CTRL+Click. By + // default CTRL+Click allows going out of bounds. + ImGuiSliderFlags_ClampZeroRange = + 1 << 10, // Clamp even if min==max==0.0f. Otherwise due to legacy reason DragXXX functions don't clamp with + // those values. When your clamping limits are dynamic you almost always want to use it. + ImGuiSliderFlags_NoSpeedTweaks = 1 << 11, // Disable keyboard modifiers altering tweak speed. Useful if you want to + // alter tweak speed yourself based on your own logic. + ImGuiSliderFlags_AlwaysClamp = ImGuiSliderFlags_ClampOnInput | ImGuiSliderFlags_ClampZeroRange, + ImGuiSliderFlags_InvalidMask_ = + 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the + // previous API that has got miscast to this enum, and will trigger an assert if needed. }; // Identify a mouse button. @@ -1904,169 +2840,240 @@ enum ImGuiMouseButton_ }; // Enumeration for GetMouseCursor() -// User code may request backend to display given cursor by calling SetMouseCursor(), which is why we have some cursors that are marked unused here +// User code may request backend to display given cursor by calling SetMouseCursor(), which is why we have some cursors +// that are marked unused here enum ImGuiMouseCursor_ { ImGuiMouseCursor_None = -1, ImGuiMouseCursor_Arrow = 0, - ImGuiMouseCursor_TextInput, // When hovering over InputText, etc. - ImGuiMouseCursor_ResizeAll, // (Unused by Dear ImGui functions) - ImGuiMouseCursor_ResizeNS, // When hovering over a horizontal border - ImGuiMouseCursor_ResizeEW, // When hovering over a vertical border or a column - ImGuiMouseCursor_ResizeNESW, // When hovering over the bottom-left corner of a window - ImGuiMouseCursor_ResizeNWSE, // When hovering over the bottom-right corner of a window - ImGuiMouseCursor_Hand, // (Unused by Dear ImGui functions. Use for e.g. hyperlinks) - ImGuiMouseCursor_Wait, // When waiting for something to process/load. - ImGuiMouseCursor_Progress, // When waiting for something to process/load, but application is still interactive. - ImGuiMouseCursor_NotAllowed, // When hovering something with disallowed interaction. Usually a crossed circle. + ImGuiMouseCursor_TextInput, // When hovering over InputText, etc. + ImGuiMouseCursor_ResizeAll, // (Unused by Dear ImGui functions) + ImGuiMouseCursor_ResizeNS, // When hovering over a horizontal border + ImGuiMouseCursor_ResizeEW, // When hovering over a vertical border or a column + ImGuiMouseCursor_ResizeNESW, // When hovering over the bottom-left corner of a window + ImGuiMouseCursor_ResizeNWSE, // When hovering over the bottom-right corner of a window + ImGuiMouseCursor_Hand, // (Unused by Dear ImGui functions. Use for e.g. hyperlinks) + ImGuiMouseCursor_Wait, // When waiting for something to process/load. + ImGuiMouseCursor_Progress, // When waiting for something to process/load, but application is still interactive. + ImGuiMouseCursor_NotAllowed, // When hovering something with disallowed interaction. Usually a crossed circle. ImGuiMouseCursor_COUNT }; // Enumeration for AddMouseSourceEvent() actual source of Mouse Input data. -// Historically we use "Mouse" terminology everywhere to indicate pointer data, e.g. MousePos, IsMousePressed(), io.AddMousePosEvent() -// But that "Mouse" data can come from different source which occasionally may be useful for application to know about. -// You can submit a change of pointer type using io.AddMouseSourceEvent(). +// Historically we use "Mouse" terminology everywhere to indicate pointer data, e.g. MousePos, IsMousePressed(), +// io.AddMousePosEvent() But that "Mouse" data can come from different source which occasionally may be useful for +// application to know about. You can submit a change of pointer type using io.AddMouseSourceEvent(). enum ImGuiMouseSource : int { - ImGuiMouseSource_Mouse = 0, // Input is coming from an actual mouse. - ImGuiMouseSource_TouchScreen, // Input is coming from a touch screen (no hovering prior to initial press, less precise initial press aiming, dual-axis wheeling possible). - ImGuiMouseSource_Pen, // Input is coming from a pressure/magnetic pen (often used in conjunction with high-sampling rates). + ImGuiMouseSource_Mouse = 0, // Input is coming from an actual mouse. + ImGuiMouseSource_TouchScreen, // Input is coming from a touch screen (no hovering prior to initial press, less + // precise initial press aiming, dual-axis wheeling possible). + ImGuiMouseSource_Pen, // Input is coming from a pressure/magnetic pen (often used in conjunction with high-sampling + // rates). ImGuiMouseSource_COUNT }; // Enumeration for ImGui::SetNextWindow***(), SetWindow***(), SetNextItem***() functions // Represent a condition. -// Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above treat 0 as a shortcut to ImGuiCond_Always. +// Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above +// treat 0 as a shortcut to ImGuiCond_Always. enum ImGuiCond_ { - ImGuiCond_None = 0, // No condition (always set the variable), same as _Always - ImGuiCond_Always = 1 << 0, // No condition (always set the variable), same as _None - ImGuiCond_Once = 1 << 1, // Set the variable once per runtime session (only the first call will succeed) - ImGuiCond_FirstUseEver = 1 << 2, // Set the variable if the object/window has no persistently saved data (no entry in .ini file) - ImGuiCond_Appearing = 1 << 3, // Set the variable if the object/window is appearing after being hidden/inactive (or the first time) + ImGuiCond_None = 0, // No condition (always set the variable), same as _Always + ImGuiCond_Always = 1 << 0, // No condition (always set the variable), same as _None + ImGuiCond_Once = 1 << 1, // Set the variable once per runtime session (only the first call will succeed) + ImGuiCond_FirstUseEver = + 1 << 2, // Set the variable if the object/window has no persistently saved data (no entry in .ini file) + ImGuiCond_Appearing = + 1 << 3, // Set the variable if the object/window is appearing after being hidden/inactive (or the first time) }; //----------------------------------------------------------------------------- -// [SECTION] Tables API flags and structures (ImGuiTableFlags, ImGuiTableColumnFlags, ImGuiTableRowFlags, ImGuiTableBgTarget, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs) +// [SECTION] Tables API flags and structures (ImGuiTableFlags, ImGuiTableColumnFlags, ImGuiTableRowFlags, +// ImGuiTableBgTarget, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs) //----------------------------------------------------------------------------- // Flags for ImGui::BeginTable() // - Important! Sizing policies have complex and subtle side effects, much more so than you would expect. // Read comments/demos carefully + experiment with live demos to get acquainted with them. // - The DEFAULT sizing policies are: -// - Default to ImGuiTableFlags_SizingFixedFit if ScrollX is on, or if host window has ImGuiWindowFlags_AlwaysAutoResize. +// - Default to ImGuiTableFlags_SizingFixedFit if ScrollX is on, or if host window has +// ImGuiWindowFlags_AlwaysAutoResize. // - Default to ImGuiTableFlags_SizingStretchSame if ScrollX is off. // - When ScrollX is off: -// - Table defaults to ImGuiTableFlags_SizingStretchSame -> all Columns defaults to ImGuiTableColumnFlags_WidthStretch with same weight. +// - Table defaults to ImGuiTableFlags_SizingStretchSame -> all Columns defaults to +// ImGuiTableColumnFlags_WidthStretch with same weight. // - Columns sizing policy allowed: Stretch (default), Fixed/Auto. // - Fixed Columns (if any) will generally obtain their requested width (unless the table cannot fit them all). // - Stretch Columns will share the remaining width according to their respective weight. // - Mixed Fixed/Stretch columns is possible but has various side-effects on resizing behaviors. -// The typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns. -// (this is because the visible order of columns have subtle but necessary effects on how they react to manual resizing). +// The typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two +// TRAILING Stretch columns. (this is because the visible order of columns have subtle but necessary effects on how +// they react to manual resizing). // - When ScrollX is on: // - Table defaults to ImGuiTableFlags_SizingFixedFit -> all Columns defaults to ImGuiTableColumnFlags_WidthFixed // - Columns sizing policy allowed: Fixed/Auto mostly. // - Fixed Columns can be enlarged as needed. Table will show a horizontal scrollbar if needed. -// - When using auto-resizing (non-resizable) fixed columns, querying the content width to use item right-alignment e.g. SetNextItemWidth(-FLT_MIN) doesn't make sense, would create a feedback loop. -// - Using Stretch columns OFTEN DOES NOT MAKE SENSE if ScrollX is on, UNLESS you have specified a value for 'inner_width' in BeginTable(). -// If you specify a value for 'inner_width' then effectively the scrolling space is known and Stretch or mixed Fixed/Stretch columns become meaningful again. +// - When using auto-resizing (non-resizable) fixed columns, querying the content width to use item right-alignment +// e.g. SetNextItemWidth(-FLT_MIN) doesn't make sense, would create a feedback loop. +// - Using Stretch columns OFTEN DOES NOT MAKE SENSE if ScrollX is on, UNLESS you have specified a value for +// 'inner_width' in BeginTable(). +// If you specify a value for 'inner_width' then effectively the scrolling space is known and Stretch or mixed +// Fixed/Stretch columns become meaningful again. // - Read on documentation at the top of imgui_tables.cpp for details. enum ImGuiTableFlags_ { // Features - ImGuiTableFlags_None = 0, - ImGuiTableFlags_Resizable = 1 << 0, // Enable resizing columns. - ImGuiTableFlags_Reorderable = 1 << 1, // Enable reordering columns in header row (need calling TableSetupColumn() + TableHeadersRow() to display headers) - ImGuiTableFlags_Hideable = 1 << 2, // Enable hiding/disabling columns in context menu. - ImGuiTableFlags_Sortable = 1 << 3, // Enable sorting. Call TableGetSortSpecs() to obtain sort specs. Also see ImGuiTableFlags_SortMulti and ImGuiTableFlags_SortTristate. - ImGuiTableFlags_NoSavedSettings = 1 << 4, // Disable persisting columns order, width and sort settings in the .ini file. - ImGuiTableFlags_ContextMenuInBody = 1 << 5, // Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow(). + ImGuiTableFlags_None = 0, + ImGuiTableFlags_Resizable = 1 << 0, // Enable resizing columns. + ImGuiTableFlags_Reorderable = 1 << 1, // Enable reordering columns in header row (need calling TableSetupColumn() + + // TableHeadersRow() to display headers) + ImGuiTableFlags_Hideable = 1 << 2, // Enable hiding/disabling columns in context menu. + ImGuiTableFlags_Sortable = 1 << 3, // Enable sorting. Call TableGetSortSpecs() to obtain sort specs. Also see + // ImGuiTableFlags_SortMulti and ImGuiTableFlags_SortTristate. + ImGuiTableFlags_NoSavedSettings = + 1 << 4, // Disable persisting columns order, width and sort settings in the .ini file. + ImGuiTableFlags_ContextMenuInBody = 1 << 5, // Right-click on columns body/contents will display table context menu. + // By default it is available in TableHeadersRow(). // Decorations - ImGuiTableFlags_RowBg = 1 << 6, // Set each RowBg color with ImGuiCol_TableRowBg or ImGuiCol_TableRowBgAlt (equivalent of calling TableSetBgColor with ImGuiTableBgFlags_RowBg0 on each row manually) - ImGuiTableFlags_BordersInnerH = 1 << 7, // Draw horizontal borders between rows. - ImGuiTableFlags_BordersOuterH = 1 << 8, // Draw horizontal borders at the top and bottom. - ImGuiTableFlags_BordersInnerV = 1 << 9, // Draw vertical borders between columns. - ImGuiTableFlags_BordersOuterV = 1 << 10, // Draw vertical borders on the left and right sides. - ImGuiTableFlags_BordersH = ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_BordersOuterH, // Draw horizontal borders. - ImGuiTableFlags_BordersV = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersOuterV, // Draw vertical borders. - ImGuiTableFlags_BordersInner = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersInnerH, // Draw inner borders. - ImGuiTableFlags_BordersOuter = ImGuiTableFlags_BordersOuterV | ImGuiTableFlags_BordersOuterH, // Draw outer borders. - ImGuiTableFlags_Borders = ImGuiTableFlags_BordersInner | ImGuiTableFlags_BordersOuter, // Draw all borders. - ImGuiTableFlags_NoBordersInBody = 1 << 11, // [ALPHA] Disable vertical borders in columns Body (borders will always appear in Headers). -> May move to style - ImGuiTableFlags_NoBordersInBodyUntilResize = 1 << 12, // [ALPHA] Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers). -> May move to style + ImGuiTableFlags_RowBg = + 1 << 6, // Set each RowBg color with ImGuiCol_TableRowBg or ImGuiCol_TableRowBgAlt (equivalent of calling + // TableSetBgColor with ImGuiTableBgFlags_RowBg0 on each row manually) + ImGuiTableFlags_BordersInnerH = 1 << 7, // Draw horizontal borders between rows. + ImGuiTableFlags_BordersOuterH = 1 << 8, // Draw horizontal borders at the top and bottom. + ImGuiTableFlags_BordersInnerV = 1 << 9, // Draw vertical borders between columns. + ImGuiTableFlags_BordersOuterV = 1 << 10, // Draw vertical borders on the left and right sides. + ImGuiTableFlags_BordersH = + ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_BordersOuterH, // Draw horizontal borders. + ImGuiTableFlags_BordersV = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersOuterV, // Draw vertical borders. + ImGuiTableFlags_BordersInner = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersInnerH, // Draw inner borders. + ImGuiTableFlags_BordersOuter = ImGuiTableFlags_BordersOuterV | ImGuiTableFlags_BordersOuterH, // Draw outer borders. + ImGuiTableFlags_Borders = ImGuiTableFlags_BordersInner | ImGuiTableFlags_BordersOuter, // Draw all borders. + ImGuiTableFlags_NoBordersInBody = 1 << 11, // [ALPHA] Disable vertical borders in columns Body (borders will always + // appear in Headers). -> May move to style + ImGuiTableFlags_NoBordersInBodyUntilResize = + 1 << 12, // [ALPHA] Disable vertical borders in columns Body until hovered for resize (borders will always + // appear in Headers). -> May move to style // Sizing Policy (read above for defaults) - ImGuiTableFlags_SizingFixedFit = 1 << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching contents width. - ImGuiTableFlags_SizingFixedSame = 2 << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching the maximum contents width of all columns. Implicitly enable ImGuiTableFlags_NoKeepColumnsVisible. - ImGuiTableFlags_SizingStretchProp = 3 << 13, // Columns default to _WidthStretch with default weights proportional to each columns contents widths. - ImGuiTableFlags_SizingStretchSame = 4 << 13, // Columns default to _WidthStretch with default weights all equal, unless overridden by TableSetupColumn(). + ImGuiTableFlags_SizingFixedFit = + 1 + << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching contents width. + ImGuiTableFlags_SizingFixedSame = + 2 << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching the maximum + // contents width of all columns. Implicitly enable ImGuiTableFlags_NoKeepColumnsVisible. + ImGuiTableFlags_SizingStretchProp = + 3 << 13, // Columns default to _WidthStretch with default weights proportional to each columns contents widths. + ImGuiTableFlags_SizingStretchSame = 4 << 13, // Columns default to _WidthStretch with default weights all equal, + // unless overridden by TableSetupColumn(). // Sizing Extra Options - ImGuiTableFlags_NoHostExtendX = 1 << 16, // 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 = 1 << 17, // 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_NoKeepColumnsVisible = 1 << 18, // Disable keeping column always minimally visible when ScrollX is off and table gets too small. Not recommended if columns are resizable. - ImGuiTableFlags_PreciseWidths = 1 << 19, // Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth. + ImGuiTableFlags_NoHostExtendX = + 1 << 16, // 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 = + 1 << 17, // 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_NoKeepColumnsVisible = 1 + << 18, // Disable keeping column always minimally visible when ScrollX is off + // and table gets too small. Not recommended if columns are resizable. + ImGuiTableFlags_PreciseWidths = + 1 << 19, // Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with + // 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, + // resizing will appear to be less smooth. // Clipping - ImGuiTableFlags_NoClip = 1 << 20, // Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with TableSetupScrollFreeze(). + ImGuiTableFlags_NoClip = + 1 << 20, // Disable clipping rectangle for every individual columns (reduce draw command count, items will be + // able to overflow into other columns). Generally incompatible with TableSetupScrollFreeze(). // Padding - ImGuiTableFlags_PadOuterX = 1 << 21, // Default if BordersOuterV is on. Enable outermost padding. Generally desirable if you have headers. - ImGuiTableFlags_NoPadOuterX = 1 << 22, // Default if BordersOuterV is off. Disable outermost padding. - ImGuiTableFlags_NoPadInnerX = 1 << 23, // Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off). + ImGuiTableFlags_PadOuterX = + 1 << 21, // Default if BordersOuterV is on. Enable outermost padding. Generally desirable if you have headers. + ImGuiTableFlags_NoPadOuterX = 1 << 22, // Default if BordersOuterV is off. Disable outermost padding. + ImGuiTableFlags_NoPadInnerX = 1 << 23, // Disable inner padding between columns (double inner padding if + // BordersOuterV is on, single inner padding if BordersOuterV is off). // Scrolling - ImGuiTableFlags_ScrollX = 1 << 24, // Enable horizontal scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. Changes default sizing policy. Because this creates a child window, ScrollY is currently generally recommended when using ScrollX. - ImGuiTableFlags_ScrollY = 1 << 25, // Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. + ImGuiTableFlags_ScrollX = + 1 << 24, // Enable horizontal scrolling. Require 'outer_size' parameter of BeginTable() to specify the container + // size. Changes default sizing policy. Because this creates a child window, ScrollY is currently + // generally recommended when using ScrollX. + ImGuiTableFlags_ScrollY = 1 << 25, // Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to + // specify the container size. // Sorting - ImGuiTableFlags_SortMulti = 1 << 26, // Hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1). - ImGuiTableFlags_SortTristate = 1 << 27, // Allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0). + ImGuiTableFlags_SortMulti = 1 << 26, // Hold shift when clicking headers to sort on multiple column. + // TableGetSortSpecs() may return specs where (SpecsCount > 1). + ImGuiTableFlags_SortTristate = 1 << 27, // Allow no sorting, disable default sorting. TableGetSortSpecs() may return + // specs where (SpecsCount == 0). // Miscellaneous - ImGuiTableFlags_HighlightHoveredColumn = 1 << 28, // Highlight column headers when hovered (may evolve into a fuller highlight) + ImGuiTableFlags_HighlightHoveredColumn = + 1 << 28, // Highlight column headers when hovered (may evolve into a fuller highlight) // [Internal] Combinations and masks - ImGuiTableFlags_SizingMask_ = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_SizingFixedSame | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_SizingStretchSame, + ImGuiTableFlags_SizingMask_ = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_SizingFixedSame | + ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_SizingStretchSame, }; // Flags for ImGui::TableSetupColumn() enum ImGuiTableColumnFlags_ { // Input configuration flags - ImGuiTableColumnFlags_None = 0, - ImGuiTableColumnFlags_Disabled = 1 << 0, // Overriding/master disable flag: hide column, won't show in context menu (unlike calling TableSetColumnEnabled() which manipulates the user accessible state) - ImGuiTableColumnFlags_DefaultHide = 1 << 1, // Default as a hidden/disabled column. - ImGuiTableColumnFlags_DefaultSort = 1 << 2, // Default as a sorting column. - ImGuiTableColumnFlags_WidthStretch = 1 << 3, // Column will stretch. Preferable with horizontal scrolling disabled (default if table sizing policy is _SizingStretchSame or _SizingStretchProp). - ImGuiTableColumnFlags_WidthFixed = 1 << 4, // Column will not stretch. Preferable with horizontal scrolling enabled (default if table sizing policy is _SizingFixedFit and table is resizable). - ImGuiTableColumnFlags_NoResize = 1 << 5, // Disable manual resizing. - ImGuiTableColumnFlags_NoReorder = 1 << 6, // Disable manual reordering this column, this will also prevent other columns from crossing over this column. - ImGuiTableColumnFlags_NoHide = 1 << 7, // Disable ability to hide/disable this column. - ImGuiTableColumnFlags_NoClip = 1 << 8, // Disable clipping for this column (all NoClip columns will render in a same draw command). - ImGuiTableColumnFlags_NoSort = 1 << 9, // Disable ability to sort on this field (even if ImGuiTableFlags_Sortable is set on the table). - ImGuiTableColumnFlags_NoSortAscending = 1 << 10, // Disable ability to sort in the ascending direction. - ImGuiTableColumnFlags_NoSortDescending = 1 << 11, // Disable ability to sort in the descending direction. - ImGuiTableColumnFlags_NoHeaderLabel = 1 << 12, // TableHeadersRow() will submit an empty label for this column. Convenient for some small columns. Name will still appear in context menu or in angled headers. You may append into this cell by calling TableSetColumnIndex() right after the TableHeadersRow() call. - ImGuiTableColumnFlags_NoHeaderWidth = 1 << 13, // Disable header text width contribution to automatic column width. - ImGuiTableColumnFlags_PreferSortAscending = 1 << 14, // Make the initial sort direction Ascending when first sorting on this column (default). - ImGuiTableColumnFlags_PreferSortDescending = 1 << 15, // Make the initial sort direction Descending when first sorting on this column. - ImGuiTableColumnFlags_IndentEnable = 1 << 16, // Use current Indent value when entering cell (default for column 0). - ImGuiTableColumnFlags_IndentDisable = 1 << 17, // Ignore current Indent value when entering cell (default for columns > 0). Indentation changes _within_ the cell will still be honored. - ImGuiTableColumnFlags_AngledHeader = 1 << 18, // TableHeadersRow() will submit an angled header row for this column. Note this will add an extra row. + ImGuiTableColumnFlags_None = 0, + ImGuiTableColumnFlags_Disabled = + 1 << 0, // Overriding/master disable flag: hide column, won't show in context menu (unlike calling + // TableSetColumnEnabled() which manipulates the user accessible state) + ImGuiTableColumnFlags_DefaultHide = 1 << 1, // Default as a hidden/disabled column. + ImGuiTableColumnFlags_DefaultSort = 1 << 2, // Default as a sorting column. + ImGuiTableColumnFlags_WidthStretch = + 1 << 3, // Column will stretch. Preferable with horizontal scrolling disabled (default if table sizing policy is + // _SizingStretchSame or _SizingStretchProp). + ImGuiTableColumnFlags_WidthFixed = + 1 << 4, // Column will not stretch. Preferable with horizontal scrolling enabled (default if table sizing policy + // is _SizingFixedFit and table is resizable). + ImGuiTableColumnFlags_NoResize = 1 << 5, // Disable manual resizing. + ImGuiTableColumnFlags_NoReorder = 1 << 6, // Disable manual reordering this column, this will also prevent other + // columns from crossing over this column. + ImGuiTableColumnFlags_NoHide = 1 << 7, // Disable ability to hide/disable this column. + ImGuiTableColumnFlags_NoClip = + 1 << 8, // Disable clipping for this column (all NoClip columns will render in a same draw command). + ImGuiTableColumnFlags_NoSort = + 1 << 9, // Disable ability to sort on this field (even if ImGuiTableFlags_Sortable is set on the table). + ImGuiTableColumnFlags_NoSortAscending = 1 << 10, // Disable ability to sort in the ascending direction. + ImGuiTableColumnFlags_NoSortDescending = 1 << 11, // Disable ability to sort in the descending direction. + ImGuiTableColumnFlags_NoHeaderLabel = + 1 << 12, // TableHeadersRow() will submit an empty label for this column. Convenient for some small columns. + // Name will still appear in context menu or in angled headers. You may append into this cell by + // calling TableSetColumnIndex() right after the TableHeadersRow() call. + ImGuiTableColumnFlags_NoHeaderWidth = 1 << 13, // Disable header text width contribution to automatic column width. + ImGuiTableColumnFlags_PreferSortAscending = + 1 << 14, // Make the initial sort direction Ascending when first sorting on this column (default). + ImGuiTableColumnFlags_PreferSortDescending = + 1 << 15, // Make the initial sort direction Descending when first sorting on this column. + ImGuiTableColumnFlags_IndentEnable = 1 << 16, // Use current Indent value when entering cell (default for column 0). + ImGuiTableColumnFlags_IndentDisable = 1 + << 17, // Ignore current Indent value when entering cell (default for columns + // > 0). Indentation changes _within_ the cell will still be honored. + ImGuiTableColumnFlags_AngledHeader = + 1 << 18, // TableHeadersRow() will submit an angled header row for this column. Note this will add an extra row. // Output status flags, read-only via TableGetColumnFlags() - ImGuiTableColumnFlags_IsEnabled = 1 << 24, // Status: is enabled == not hidden by user/api (referred to as "Hide" in _DefaultHide and _NoHide) flags. - ImGuiTableColumnFlags_IsVisible = 1 << 25, // Status: is visible == is enabled AND not clipped by scrolling. - ImGuiTableColumnFlags_IsSorted = 1 << 26, // Status: is currently part of the sort specs - ImGuiTableColumnFlags_IsHovered = 1 << 27, // Status: is hovered by mouse + ImGuiTableColumnFlags_IsEnabled = 1 << 24, // Status: is enabled == not hidden by user/api (referred to as "Hide" in + // _DefaultHide and _NoHide) flags. + ImGuiTableColumnFlags_IsVisible = 1 << 25, // Status: is visible == is enabled AND not clipped by scrolling. + ImGuiTableColumnFlags_IsSorted = 1 << 26, // Status: is currently part of the sort specs + ImGuiTableColumnFlags_IsHovered = 1 << 27, // Status: is hovered by mouse // [Internal] Combinations and masks - ImGuiTableColumnFlags_WidthMask_ = ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_WidthFixed, - ImGuiTableColumnFlags_IndentMask_ = ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_IndentDisable, - ImGuiTableColumnFlags_StatusMask_ = ImGuiTableColumnFlags_IsEnabled | ImGuiTableColumnFlags_IsVisible | ImGuiTableColumnFlags_IsSorted | ImGuiTableColumnFlags_IsHovered, - ImGuiTableColumnFlags_NoDirectResize_ = 1 << 30, // [Internal] Disable user resizing this column directly (it may however we resized indirectly from its left edge) + ImGuiTableColumnFlags_WidthMask_ = ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_WidthFixed, + ImGuiTableColumnFlags_IndentMask_ = ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_IndentDisable, + ImGuiTableColumnFlags_StatusMask_ = ImGuiTableColumnFlags_IsEnabled | ImGuiTableColumnFlags_IsVisible | + ImGuiTableColumnFlags_IsSorted | ImGuiTableColumnFlags_IsHovered, + ImGuiTableColumnFlags_NoDirectResize_ = 1 << 30, // [Internal] Disable user resizing this column directly (it may + // however we resized indirectly from its left edge) }; // Flags for ImGui::TableNextRow() enum ImGuiTableRowFlags_ { - ImGuiTableRowFlags_None = 0, - ImGuiTableRowFlags_Headers = 1 << 0, // Identify header row (set default background color + width of its contents accounted differently for auto column width) + ImGuiTableRowFlags_None = 0, + ImGuiTableRowFlags_Headers = 1 << 0, // Identify header row (set default background color + width of its contents + // accounted differently for auto column width) }; // Enum for ImGui::TableSetBgColor() @@ -2074,40 +3081,51 @@ enum ImGuiTableRowFlags_ // - Layer 0: draw with RowBg0 color if set, otherwise draw with ColumnBg0 if set. // - Layer 1: draw with RowBg1 color if set, otherwise draw with ColumnBg1 if set. // - Layer 2: draw with CellBg color if set. -// The purpose of the two row/columns layers is to let you decide if a background color change should override or blend with the existing color. -// When using ImGuiTableFlags_RowBg on the table, each row has the RowBg0 color automatically set for odd/even rows. -// If you set the color of RowBg0 target, your color will override the existing RowBg0 color. -// If you set the color of RowBg1 or ColumnBg1 target, your color will blend over the RowBg0 color. +// The purpose of the two row/columns layers is to let you decide if a background color change should override or blend +// with the existing color. When using ImGuiTableFlags_RowBg on the table, each row has the RowBg0 color automatically +// set for odd/even rows. If you set the color of RowBg0 target, your color will override the existing RowBg0 color. If +// you set the color of RowBg1 or ColumnBg1 target, your color will blend over the RowBg0 color. enum ImGuiTableBgTarget_ { - ImGuiTableBgTarget_None = 0, - ImGuiTableBgTarget_RowBg0 = 1, // Set row background color 0 (generally used for background, automatically set when ImGuiTableFlags_RowBg is used) - ImGuiTableBgTarget_RowBg1 = 2, // Set row background color 1 (generally used for selection marking) - ImGuiTableBgTarget_CellBg = 3, // Set cell background color (top-most color) + ImGuiTableBgTarget_None = 0, + ImGuiTableBgTarget_RowBg0 = 1, // Set row background color 0 (generally used for background, automatically set when + // ImGuiTableFlags_RowBg is used) + ImGuiTableBgTarget_RowBg1 = 2, // Set row background color 1 (generally used for selection marking) + ImGuiTableBgTarget_CellBg = 3, // Set cell background color (top-most color) }; // Sorting specifications for a table (often handling sort specs for a single column, occasionally more) // Obtained by calling TableGetSortSpecs(). -// When 'SpecsDirty == true' you can sort your data. It will be true with sorting specs have changed since last call, or the first time. -// Make sure to set 'SpecsDirty = false' after sorting, else you may wastefully sort your data every frame! +// When 'SpecsDirty == true' you can sort your data. It will be true with sorting specs have changed since last call, or +// the first time. Make sure to set 'SpecsDirty = false' after sorting, else you may wastefully sort your data every +// frame! struct ImGuiTableSortSpecs { - const ImGuiTableColumnSortSpecs* Specs; // Pointer to sort spec array. - int SpecsCount; // Sort spec count. Most often 1. May be > 1 when ImGuiTableFlags_SortMulti is enabled. May be == 0 when ImGuiTableFlags_SortTristate is enabled. - bool SpecsDirty; // Set to true when specs have changed since last time! Use this to sort again, then clear the flag. + const ImGuiTableColumnSortSpecs *Specs; // Pointer to sort spec array. + int SpecsCount; // Sort spec count. Most often 1. May be > 1 when ImGuiTableFlags_SortMulti is enabled. May be == 0 + // when ImGuiTableFlags_SortTristate is enabled. + bool + SpecsDirty; // Set to true when specs have changed since last time! Use this to sort again, then clear the flag. - ImGuiTableSortSpecs() { memset(this, 0, sizeof(*this)); } + ImGuiTableSortSpecs() + { + memset(this, 0, sizeof(*this)); + } }; // Sorting specification for one column of a table (sizeof == 12 bytes) struct ImGuiTableColumnSortSpecs { - ImGuiID ColumnUserID; // User id of the column (if specified by a TableSetupColumn() call) - ImS16 ColumnIndex; // Index of the column - ImS16 SortOrder; // Index within parent ImGuiTableSortSpecs (always stored in order starting from 0, tables sorted on a single criteria will always have a 0 here) - ImGuiSortDirection SortDirection; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending + ImGuiID ColumnUserID; // User id of the column (if specified by a TableSetupColumn() call) + ImS16 ColumnIndex; // Index of the column + ImS16 SortOrder; // Index within parent ImGuiTableSortSpecs (always stored in order starting from 0, tables sorted + // on a single criteria will always have a 0 here) + ImGuiSortDirection SortDirection; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending - ImGuiTableColumnSortSpecs() { memset(this, 0, sizeof(*this)); } + ImGuiTableColumnSortSpecs() + { + memset(this, 0, sizeof(*this)); + } }; //----------------------------------------------------------------------------- @@ -2119,100 +3137,370 @@ struct ImGuiTableColumnSortSpecs //----------------------------------------------------------------------------- #ifndef IMGUI_DISABLE_DEBUG_TOOLS -#define IMGUI_DEBUG_LOG(...) ImGui::DebugLog(__VA_ARGS__) +#define IMGUI_DEBUG_LOG(...) ImGui::DebugLog(__VA_ARGS__) #else -#define IMGUI_DEBUG_LOG(...) ((void)0) +#define IMGUI_DEBUG_LOG(...) ((void)0) #endif //----------------------------------------------------------------------------- // IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() // We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax. -// Defining a custom placement new() with a custom parameter allows us to bypass including which on some platforms complains when user has disabled exceptions. +// Defining a custom placement new() with a custom parameter allows us to bypass including which on some platforms +// complains when user has disabled exceptions. //----------------------------------------------------------------------------- -struct ImNewWrapper {}; -inline void* operator new(size_t, ImNewWrapper, void* ptr) { return ptr; } -inline void operator delete(void*, ImNewWrapper, void*) {} // This is only required so we can use the symmetrical new() -#define IM_ALLOC(_SIZE) ImGui::MemAlloc(_SIZE) -#define IM_FREE(_PTR) ImGui::MemFree(_PTR) -#define IM_PLACEMENT_NEW(_PTR) new(ImNewWrapper(), _PTR) -#define IM_NEW(_TYPE) new(ImNewWrapper(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE -template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } } +struct ImNewWrapper +{ +}; +inline void *operator new(size_t, ImNewWrapper, void *ptr) +{ + return ptr; +} +inline void operator delete(void *, ImNewWrapper, void *) +{ +} // This is only required so we can use the symmetrical new() +#define IM_ALLOC(_SIZE) ImGui::MemAlloc(_SIZE) +#define IM_FREE(_PTR) ImGui::MemFree(_PTR) +#define IM_PLACEMENT_NEW(_PTR) new (ImNewWrapper(), _PTR) +#define IM_NEW(_TYPE) new (ImNewWrapper(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE +template void IM_DELETE(T *p) +{ + if (p) + { + p->~T(); + ImGui::MemFree(p); + } +} //----------------------------------------------------------------------------- // ImVector<> -// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). +// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug +// enabled are absurdly slow, we bypass it so our code runs fast in debug). //----------------------------------------------------------------------------- -// - You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our public structures are relying on it. +// - You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our +// public structures are relying on it. // - We use std-like naming convention here, which is a little unusual for this codebase. -// - Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs. -// - Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that, -// Do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset. +// - Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally +// recycle allocated buffers across frames and amortize our costs. +// - Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is +// intentional but be extra mindful of that, +// Do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can +// be safely initialized by a zero-memset. //----------------------------------------------------------------------------- IM_MSVC_RUNTIME_CHECKS_OFF -template -struct ImVector +template struct ImVector { - int Size; - int Capacity; - T* Data; + int Size; + int Capacity; + T *Data; // Provide standard typedefs but we don't use them ourselves. - typedef T value_type; - typedef value_type* iterator; - typedef const value_type* const_iterator; + typedef T value_type; + typedef value_type *iterator; + typedef const value_type *const_iterator; // Constructors, destructor - inline ImVector() { Size = Capacity = 0; Data = NULL; } - inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); } - inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); if (src.Data) memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; } - inline ~ImVector() { if (Data) IM_FREE(Data); } // Important: does not destruct anything + inline ImVector() + { + Size = Capacity = 0; + Data = NULL; + } + inline ImVector(const ImVector &src) + { + Size = Capacity = 0; + Data = NULL; + operator=(src); + } + inline ImVector &operator=(const ImVector &src) + { + clear(); + resize(src.Size); + if (src.Data) + memcpy(Data, src.Data, (size_t)Size * sizeof(T)); + return *this; + } + inline ~ImVector() + { + if (Data) + IM_FREE(Data); + } // Important: does not destruct anything - inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } } // Important: does not destruct anything - inline void clear_delete() { for (int n = 0; n < Size; n++) IM_DELETE(Data[n]); clear(); } // Important: never called automatically! always explicit. - inline void clear_destruct() { for (int n = 0; n < Size; n++) Data[n].~T(); clear(); } // Important: never called automatically! always explicit. + inline void clear() + { + if (Data) + { + Size = Capacity = 0; + IM_FREE(Data); + Data = NULL; + } + } // Important: does not destruct anything + inline void clear_delete() + { + for (int n = 0; n < Size; n++) + IM_DELETE(Data[n]); + clear(); + } // Important: never called automatically! always explicit. + inline void clear_destruct() + { + for (int n = 0; n < Size; n++) + Data[n].~T(); + clear(); + } // Important: never called automatically! always explicit. - inline bool empty() const { return Size == 0; } - inline int size() const { return Size; } - inline int size_in_bytes() const { return Size * (int)sizeof(T); } - inline int max_size() const { return 0x7FFFFFFF / (int)sizeof(T); } - inline int capacity() const { return Capacity; } - inline T& operator[](int i) { IM_ASSERT(i >= 0 && i < Size); return Data[i]; } - inline const T& operator[](int i) const { IM_ASSERT(i >= 0 && i < Size); return Data[i]; } + inline bool empty() const + { + return Size == 0; + } + inline int size() const + { + return Size; + } + inline int size_in_bytes() const + { + return Size * (int)sizeof(T); + } + inline int max_size() const + { + return 0x7FFFFFFF / (int)sizeof(T); + } + inline int capacity() const + { + return Capacity; + } + inline T &operator[](int i) + { + IM_ASSERT(i >= 0 && i < Size); + return Data[i]; + } + inline const T &operator[](int i) const + { + IM_ASSERT(i >= 0 && i < Size); + return Data[i]; + } - inline T* begin() { return Data; } - inline const T* begin() const { return Data; } - inline T* end() { return Data + Size; } - inline const T* end() const { return Data + Size; } - inline T& front() { IM_ASSERT(Size > 0); return Data[0]; } - inline const T& front() const { IM_ASSERT(Size > 0); return Data[0]; } - inline T& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; } - inline const T& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; } - inline void swap(ImVector& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; T* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } + inline T *begin() + { + return Data; + } + inline const T *begin() const + { + return Data; + } + inline T *end() + { + return Data + Size; + } + inline const T *end() const + { + return Data + Size; + } + inline T &front() + { + IM_ASSERT(Size > 0); + return Data[0]; + } + inline const T &front() const + { + IM_ASSERT(Size > 0); + return Data[0]; + } + inline T &back() + { + IM_ASSERT(Size > 0); + return Data[Size - 1]; + } + inline const T &back() const + { + IM_ASSERT(Size > 0); + return Data[Size - 1]; + } + inline void swap(ImVector &rhs) + { + int rhs_size = rhs.Size; + rhs.Size = Size; + Size = rhs_size; + int rhs_cap = rhs.Capacity; + rhs.Capacity = Capacity; + Capacity = rhs_cap; + T *rhs_data = rhs.Data; + rhs.Data = Data; + Data = rhs_data; + } - inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity / 2) : 8; return new_capacity > sz ? new_capacity : sz; } - inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } - inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } - inline void shrink(int new_size) { IM_ASSERT(new_size <= Size); Size = new_size; } // Resize a vector to a smaller size, guaranteed not to cause a reallocation - inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); IM_FREE(Data); } Data = new_data; Capacity = new_capacity; } - inline void reserve_discard(int new_capacity) { if (new_capacity <= Capacity) return; if (Data) IM_FREE(Data); Data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); Capacity = new_capacity; } + inline int _grow_capacity(int sz) const + { + int new_capacity = Capacity ? (Capacity + Capacity / 2) : 8; + return new_capacity > sz ? new_capacity : sz; + } + inline void resize(int new_size) + { + if (new_size > Capacity) + reserve(_grow_capacity(new_size)); + Size = new_size; + } + inline void resize(int new_size, const T &v) + { + if (new_size > Capacity) + reserve(_grow_capacity(new_size)); + if (new_size > Size) + for (int n = Size; n < new_size; n++) + memcpy(&Data[n], &v, sizeof(v)); + Size = new_size; + } + inline void shrink(int new_size) + { + IM_ASSERT(new_size <= Size); + Size = new_size; + } // Resize a vector to a smaller size, guaranteed not to cause a reallocation + inline void reserve(int new_capacity) + { + if (new_capacity <= Capacity) + return; + T *new_data = (T *)IM_ALLOC((size_t)new_capacity * sizeof(T)); + if (Data) + { + memcpy(new_data, Data, (size_t)Size * sizeof(T)); + IM_FREE(Data); + } + Data = new_data; + Capacity = new_capacity; + } + inline void reserve_discard(int new_capacity) + { + if (new_capacity <= Capacity) + return; + if (Data) + IM_FREE(Data); + Data = (T *)IM_ALLOC((size_t)new_capacity * sizeof(T)); + Capacity = new_capacity; + } - // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden. - inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; } - inline void pop_back() { IM_ASSERT(Size > 0); Size--; } - inline void push_front(const T& v) { if (Size == 0) push_back(v); else insert(Data, v); } - inline T* erase(const T* it) { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(T)); Size--; return Data + off; } - inline T* erase(const T* it, const T* it_last){ IM_ASSERT(it >= Data && it < Data + Size && it_last >= it && it_last <= Data + Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - (size_t)count) * sizeof(T)); Size -= (int)count; return Data + off; } - inline T* erase_unsorted(const T* it) { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; if (it < Data + Size - 1) memcpy(Data + off, Data + Size - 1, sizeof(T)); Size--; return Data + off; } - inline T* insert(const T* it, const T& v) { IM_ASSERT(it >= Data && it <= Data + Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(T)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; } - inline bool contains(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; } - inline T* find(const T& v) { T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; } - inline const T* find(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; } - inline int find_index(const T& v) const { const T* data_end = Data + Size; const T* it = find(v); if (it == data_end) return -1; const ptrdiff_t off = it - Data; return (int)off; } - inline bool find_erase(const T& v) { const T* it = find(v); if (it < Data + Size) { erase(it); return true; } return false; } - 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; } + // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! + // e.g. v.push_back(v[10]) is forbidden. + inline void push_back(const T &v) + { + if (Size == Capacity) + reserve(_grow_capacity(Size + 1)); + memcpy(&Data[Size], &v, sizeof(v)); + Size++; + } + inline void pop_back() + { + IM_ASSERT(Size > 0); + Size--; + } + inline void push_front(const T &v) + { + if (Size == 0) + push_back(v); + else + insert(Data, v); + } + inline T *erase(const T *it) + { + IM_ASSERT(it >= Data && it < Data + Size); + const ptrdiff_t off = it - Data; + memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(T)); + Size--; + return Data + off; + } + inline T *erase(const T *it, const T *it_last) + { + IM_ASSERT(it >= Data && it < Data + Size && it_last >= it && it_last <= Data + Size); + const ptrdiff_t count = it_last - it; + const ptrdiff_t off = it - Data; + memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - (size_t)count) * sizeof(T)); + Size -= (int)count; + return Data + off; + } + inline T *erase_unsorted(const T *it) + { + IM_ASSERT(it >= Data && it < Data + Size); + const ptrdiff_t off = it - Data; + if (it < Data + Size - 1) + memcpy(Data + off, Data + Size - 1, sizeof(T)); + Size--; + return Data + off; + } + inline T *insert(const T *it, const T &v) + { + IM_ASSERT(it >= Data && it <= Data + Size); + const ptrdiff_t off = it - Data; + if (Size == Capacity) + reserve(_grow_capacity(Size + 1)); + if (off < (int)Size) + memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(T)); + memcpy(&Data[off], &v, sizeof(v)); + Size++; + return Data + off; + } + inline bool contains(const T &v) const + { + const T *data = Data; + const T *data_end = Data + Size; + while (data < data_end) + if (*data++ == v) + return true; + return false; + } + inline T *find(const T &v) + { + T *data = Data; + const T *data_end = Data + Size; + while (data < data_end) + if (*data == v) + break; + else + ++data; + return data; + } + inline const T *find(const T &v) const + { + const T *data = Data; + const T *data_end = Data + Size; + while (data < data_end) + if (*data == v) + break; + else + ++data; + return data; + } + inline int find_index(const T &v) const + { + const T *data_end = Data + Size; + const T *it = find(v); + if (it == data_end) + return -1; + const ptrdiff_t off = it - Data; + return (int)off; + } + inline bool find_erase(const T &v) + { + const T *it = find(v); + if (it < Data + Size) + { + erase(it); + return true; + } + return false; + } + 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 @@ -2227,82 +3515,131 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE struct ImGuiStyle { // ImGui::GetFontSize() == FontSizeBase * (FontScaleMain * FontScaleDpi * other_scaling_factors) - float FontSizeBase; // Current base font size before external scaling factors are applied. Use PushFont()/PushFontSize() to modify. Use ImGui::GetFontSize() to obtain scaled value. - float FontScaleMain; // Main scale factor. May be set by application once, or exposed to end-user. - float FontScaleDpi; // Additional scale factor from viewport/monitor contents scale. When io.ConfigDpiScaleFonts is enabled, this is automatically overwritten when changing monitor DPI. + float FontSizeBase; // Current base font size before external scaling factors are applied. Use + // PushFont()/PushFontSize() to modify. Use ImGui::GetFontSize() to obtain scaled value. + float FontScaleMain; // Main scale factor. May be set by application once, or exposed to end-user. + float FontScaleDpi; // Additional scale factor from viewport/monitor contents scale. When io.ConfigDpiScaleFonts is + // enabled, this is automatically overwritten when changing monitor DPI. - float Alpha; // Global alpha applies to everything in Dear ImGui. - float DisabledAlpha; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. - ImVec2 WindowPadding; // Padding within a window. - float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended. - float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). - float WindowBorderHoverPadding; // Hit-testing extent outside/inside resizing border. Also extend determination of hovered window. Generally meaningfully larger than WindowBorderSize to make it easy to reach borders. - ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constrain individual windows, use SetNextWindowSizeConstraints(). - ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. - ImGuiDir WindowMenuButtonPosition; // Side of the collapsing/docking button in the title bar (None/Left/Right). Defaults to ImGuiDir_Left. - float ChildRounding; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows. - float ChildBorderSize; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). - float PopupRounding; // Radius of popup window corners rounding. (Note that tooltip windows use WindowRounding) - float PopupBorderSize; // Thickness of border around popup/tooltip windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). - ImVec2 FramePadding; // Padding within a framed rectangle (used by most widgets). - float FrameRounding; // Radius of frame corners rounding. Set to 0.0f to have rectangular frame (used by most widgets). - float FrameBorderSize; // Thickness of border around frames. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). - ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines. - ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label). - ImVec2 CellPadding; // Padding within a table cell. Cellpadding.x is locked for entire table. CellPadding.y may be altered between different rows. - ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! - float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). - float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). - float ScrollbarSize; // Width of the vertical scrollbar, Height of the horizontal scrollbar. - float ScrollbarRounding; // Radius of grab corners for scrollbar. - float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. - float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. - float LogSliderDeadzone; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. - float ImageBorderSize; // Thickness of border around Image() calls. - float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. - float TabBorderSize; // Thickness of border around tabs. - float TabCloseButtonMinWidthSelected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. - float TabCloseButtonMinWidthUnselected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. FLT_MAX: never show close button when unselected. - float TabBarBorderSize; // Thickness of tab-bar separator, which takes on the tab active color to denote focus. - float TabBarOverlineSize; // Thickness of tab-bar overline, which highlights the selected tab-bar. - float TableAngledHeadersAngle; // Angle of angled headers (supported values range from -50.0f degrees to +50.0f degrees). - ImVec2 TableAngledHeadersTextAlign;// Alignment of angled headers within the cell - ImGuiTreeNodeFlags TreeLinesFlags; // Default way to draw lines connecting TreeNode hierarchy. ImGuiTreeNodeFlags_DrawLinesNone or ImGuiTreeNodeFlags_DrawLinesFull or ImGuiTreeNodeFlags_DrawLinesToNodes. - float TreeLinesSize; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines. - float TreeLinesRounding; // Radius of lines connecting child nodes to the vertical line. - ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. - ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). - ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. - float SeparatorTextBorderSize; // Thickness of border in SeparatorText() - ImVec2 SeparatorTextAlign; // Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center). - ImVec2 SeparatorTextPadding; // Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y. - ImVec2 DisplayWindowPadding; // Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen. - ImVec2 DisplaySafeAreaPadding; // Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured). - float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). We apply per-monitor DPI scaling over this scale. May be removed later. - bool AntiAliasedLines; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList). - bool AntiAliasedLinesUseTex; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest 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 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. + float Alpha; // Global alpha applies to everything in Dear ImGui. + float + DisabledAlpha; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. + ImVec2 WindowPadding; // Padding within a window. + float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values + // tend to lead to variety of artifacts and are not recommended. + float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not + // well tested and more CPU/GPU costly). + float WindowBorderHoverPadding; // Hit-testing extent outside/inside resizing border. Also extend determination of + // hovered window. Generally meaningfully larger than WindowBorderSize to make it + // easy to reach borders. + ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constrain individual windows, + // use SetNextWindowSizeConstraints(). + ImVec2 + WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. + ImGuiDir WindowMenuButtonPosition; // Side of the collapsing/docking button in the title bar (None/Left/Right). + // Defaults to ImGuiDir_Left. + float ChildRounding; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows. + float ChildBorderSize; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. (Other values are + // not well tested and more CPU/GPU costly). + float PopupRounding; // Radius of popup window corners rounding. (Note that tooltip windows use WindowRounding) + float PopupBorderSize; // Thickness of border around popup/tooltip windows. Generally set to 0.0f or 1.0f. (Other + // values are not well tested and more CPU/GPU costly). + ImVec2 FramePadding; // Padding within a framed rectangle (used by most widgets). + float FrameRounding; // Radius of frame corners rounding. Set to 0.0f to have rectangular frame (used by most + // widgets). + float FrameBorderSize; // Thickness of border around frames. Generally set to 0.0f or 1.0f. (Other values are not + // well tested and more CPU/GPU costly). + ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines. + ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a + // slider and its label). + ImVec2 CellPadding; // Padding within a table cell. Cellpadding.x is locked for entire table. CellPadding.y may be + // altered between different rows. + ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not + // accurate enough. Unfortunately we don't sort widgets so priority on overlap will always + // be given to the first widget. So don't grow this too much! + float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + + // FramePadding.x*2). + float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). + float ScrollbarSize; // Width of the vertical scrollbar, Height of the horizontal scrollbar. + float ScrollbarRounding; // Radius of grab corners for scrollbar. + float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. + float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + float LogSliderDeadzone; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. + float ImageBorderSize; // Thickness of border around Image() calls. + float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. + float TabBorderSize; // Thickness of border around tabs. + float TabCloseButtonMinWidthSelected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered + // if minimum width. + float + TabCloseButtonMinWidthUnselected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered + // if minimum width. FLT_MAX: never show close button when unselected. + float TabBarBorderSize; // Thickness of tab-bar separator, which takes on the tab active color to denote focus. + float TabBarOverlineSize; // Thickness of tab-bar overline, which highlights the selected tab-bar. + float TableAngledHeadersAngle; // Angle of angled headers (supported values range from -50.0f degrees to +50.0f + // degrees). + ImVec2 TableAngledHeadersTextAlign; // Alignment of angled headers within the cell + ImGuiTreeNodeFlags + TreeLinesFlags; // Default way to draw lines connecting TreeNode hierarchy. ImGuiTreeNodeFlags_DrawLinesNone or + // ImGuiTreeNodeFlags_DrawLinesFull or ImGuiTreeNodeFlags_DrawLinesToNodes. + float TreeLinesSize; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines. + float TreeLinesRounding; // Radius of lines connecting child nodes to the vertical line. + ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to + // ImGuiDir_Right. + ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) + // (centered). + ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's + // generally important to keep this left-aligned if you want to lay multiple items on a + // same line. + float SeparatorTextBorderSize; // Thickness of border in SeparatorText() + ImVec2 + SeparatorTextAlign; // Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center). + ImVec2 SeparatorTextPadding; // Horizontal offset of text from each edge of the separator + spacing on other axis. + // Generally small values. .y is recommended to be == FramePadding.y. + ImVec2 DisplayWindowPadding; // Apply to regular windows: amount which we enforce to keep visible when moving near + // edges of your screen. + ImVec2 DisplaySafeAreaPadding; // Apply to every windows, menus, popups, tooltips: amount where we avoid displaying + // contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where + // scaling has not been configured). + float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). We apply + // per-monitor DPI scaling over this scale. May be removed later. + bool AntiAliasedLines; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. Latched at + // the beginning of the frame (copied to ImDrawList). + bool AntiAliasedLinesUseTex; // Enable anti-aliased lines/borders using textures where possible. Require backend to + // render with bilinear filtering (NOT point/nearest 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 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. // Colors - ImVec4 Colors[ImGuiCol_COUNT]; + ImVec4 Colors[ImGuiCol_COUNT]; // Behaviors - // (It is possible to modify those fields mid-frame if specific behavior need it, unlike e.g. configuration fields in ImGuiIO) - float HoverStationaryDelay; // Delay for IsItemHovered(ImGuiHoveredFlags_Stationary). Time required to consider mouse stationary. - float HoverDelayShort; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayShort). Usually used along with HoverStationaryDelay. - float HoverDelayNormal; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayNormal). " - ImGuiHoveredFlags HoverFlagsForTooltipMouse;// Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using mouse. - ImGuiHoveredFlags HoverFlagsForTooltipNav; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using keyboard/gamepad. + // (It is possible to modify those fields mid-frame if specific behavior need it, unlike e.g. configuration fields + // in ImGuiIO) + float HoverStationaryDelay; // Delay for IsItemHovered(ImGuiHoveredFlags_Stationary). Time required to consider + // mouse stationary. + float HoverDelayShort; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayShort). Usually used along with + // HoverStationaryDelay. + float HoverDelayNormal; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayNormal). " + ImGuiHoveredFlags HoverFlagsForTooltipMouse; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) + // or BeginItemTooltip()/SetItemTooltip() while using mouse. + ImGuiHoveredFlags HoverFlagsForTooltipNav; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) + // or BeginItemTooltip()/SetItemTooltip() while using keyboard/gamepad. // [Internal] - float _MainScale; // FIXME-WIP: Reference scale, as applied by ScaleAllSizes(). - float _NextFrameFontSizeBase; // FIXME: Temporary hack until we finish remaining work. + float _MainScale; // FIXME-WIP: Reference scale, as applied by ScaleAllSizes(). + float _NextFrameFontSizeBase; // FIXME: Temporary hack until we finish remaining work. // Functions - IMGUI_API ImGuiStyle(); - IMGUI_API void ScaleAllSizes(float scale_factor); // Scale all spacing/padding/thickness values. Do not scale fonts. + IMGUI_API ImGuiStyle(); + IMGUI_API void ScaleAllSizes(float scale_factor); // Scale all spacing/padding/thickness values. Do not scale fonts. // Obsolete names #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS @@ -2323,13 +3660,14 @@ struct ImGuiStyle //----------------------------------------------------------------------------- // [Internal] Storage used by IsKeyDown(), IsKeyPressed() etc functions. -// If prior to 1.87 you used io.KeysDownDuration[] (which was marked as internal), you should use GetKeyData(key)->DownDuration and *NOT* io.KeysData[key]->DownDuration. +// If prior to 1.87 you used io.KeysDownDuration[] (which was marked as internal), you should use +// GetKeyData(key)->DownDuration and *NOT* io.KeysData[key]->DownDuration. struct ImGuiKeyData { - bool Down; // True for if key is down - float DownDuration; // Duration the key has been down (<0.0f: not pressed, 0.0f: just pressed, >0.0f: time held) - float DownDurationPrev; // Last frame duration the key has been down - float AnalogValue; // 0.0f..1.0f for gamepad values + bool Down; // True for if key is down + float DownDuration; // Duration the key has been down (<0.0f: not pressed, 0.0f: just pressed, >0.0f: time held) + float DownDurationPrev; // Last frame duration the key has been down + float AnalogValue; // 0.0f..1.0f for gamepad values }; struct ImGuiIO @@ -2338,51 +3676,90 @@ struct ImGuiIO // Configuration // Default value //------------------------------------------------------------------ - ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Keyboard/Gamepad navigation options, etc. - ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by backend (imgui_impl_xxx files or custom backend) to communicate features supported by the backend. - ImVec2 DisplaySize; // // Main display size, in pixels (== GetMainViewport()->Size). May change every frame. - ImVec2 DisplayFramebufferScale; // = (1, 1) // Main display density. For retina display where window coordinates are different from framebuffer coordinates. This will affect font density + will end up in ImDrawData::FramebufferScale. - float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds. May change every frame. - float IniSavingRate; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds. - const char* IniFilename; // = "imgui.ini" // Path to .ini file (important: default "imgui.ini" is relative to current working dir!). Set NULL to disable automatic .ini loading/saving or if you want to manually call LoadIniSettingsXXX() / SaveIniSettingsXXX() functions. - const char* LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified). - void* UserData; // = NULL // Store your own data. + ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. + // Keyboard/Gamepad navigation options, etc. + ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by backend (imgui_impl_xxx + // files or custom backend) to communicate features supported by the backend. + ImVec2 DisplaySize; // // Main display size, in pixels (== GetMainViewport()->Size). May change + // every frame. + ImVec2 DisplayFramebufferScale; // = (1, 1) // Main display density. For retina display where window + // coordinates are different from framebuffer coordinates. This will affect font + // density + will end up in ImDrawData::FramebufferScale. + float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds. May change every frame. + float IniSavingRate; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds. + const char *IniFilename; // = "imgui.ini" // Path to .ini file (important: default "imgui.ini" is relative to + // current working dir!). Set NULL to disable automatic .ini loading/saving or if you want + // to manually call LoadIniSettingsXXX() / SaveIniSettingsXXX() functions. + const char *LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no + // file is specified). + void *UserData; // = NULL // Store your own data. // Font system - ImFontAtlas*Fonts; // // Font atlas: load, rasterize and pack one or more fonts into a single texture. - ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. - bool FontAllowUserScaling; // = false // [OBSOLETE] Allow user scaling text of individual window with CTRL+Wheel. + ImFontAtlas + *Fonts; // // Font atlas: load, rasterize and pack one or more fonts into a single texture. + ImFont *FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. + bool FontAllowUserScaling; // = false // [OBSOLETE] Allow user scaling text of individual window with + // CTRL+Wheel. // Keyboard/Gamepad Navigation options - bool ConfigNavSwapGamepadButtons; // = false // Swap Activate<>Cancel (A<>B) buttons, matching typical "Nintendo/Japanese style" gamepad layout. - bool ConfigNavMoveSetMousePos; // = false // Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult. Will update io.MousePos and set io.WantSetMousePos=true. - bool ConfigNavCaptureKeyboard; // = true // Sets io.WantCaptureKeyboard when io.NavActive is set. - bool ConfigNavEscapeClearFocusItem; // = true // Pressing Escape can clear focused item + navigation id/highlight. Set to false if you want to always keep highlight on. - bool ConfigNavEscapeClearFocusWindow;// = false // Pressing Escape can clear focused window as well (super set of io.ConfigNavEscapeClearFocusItem). - bool ConfigNavCursorVisibleAuto; // = true // Using directional navigation key makes the cursor visible. Mouse click hides the cursor. - bool ConfigNavCursorVisibleAlways; // = false // Navigation cursor is always visible. + bool ConfigNavSwapGamepadButtons; // = false // Swap Activate<>Cancel (A<>B) buttons, matching typical + // "Nintendo/Japanese style" gamepad layout. + bool ConfigNavMoveSetMousePos; // = false // Directional/tabbing navigation teleports the mouse cursor. May + // be useful on TV/console systems where moving a virtual mouse is difficult. Will + // update io.MousePos and set io.WantSetMousePos=true. + bool ConfigNavCaptureKeyboard; // = true // Sets io.WantCaptureKeyboard when io.NavActive is set. + bool ConfigNavEscapeClearFocusItem; // = true // Pressing Escape can clear focused item + navigation + // id/highlight. Set to false if you want to always keep highlight on. + bool ConfigNavEscapeClearFocusWindow; // = false // Pressing Escape can clear focused window as well (super + // set of io.ConfigNavEscapeClearFocusItem). + bool ConfigNavCursorVisibleAuto; // = true // Using directional navigation key makes the cursor visible. + // Mouse click hides the cursor. + bool ConfigNavCursorVisibleAlways; // = false // Navigation cursor is always visible. // Miscellaneous options // (you can visualize and interact with all options in 'Demo->Configuration') - bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations. - bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // Swap Cmd<>Ctrl keys + OS X style text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl. - bool ConfigInputTrickleEventQueue; // = true // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates. - bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting). - bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will keep item active and select contents (single-line only). - bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard. - bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) - bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar. - bool ConfigWindowsCopyContentsWithCtrlC; // = false // [EXPERIMENTAL] CTRL+C copy the contents of focused window into the clipboard. Experimental because: (1) has known issues with nested Begin/End pairs (2) text output quality varies (3) text output is in submission order rather than spatial order. - bool ConfigScrollbarScrollByPage; // = true // Enable scrolling page by page when clicking outside the scrollbar grab. When disabled, always scroll to clicked location. When enabled, Shift+Click scrolls to clicked location. - float ConfigMemoryCompactTimer; // = 60.0f // Timer (in seconds) to free transient windows/tables memory buffers when unused. Set to -1.0f to disable. + bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform + // without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is + // frequently used by backend implementations. + bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // Swap Cmd<>Ctrl keys + OS X style text editing cursor movement + // using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start + // and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of + // selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl. + bool ConfigInputTrickleEventQueue; // = true // Enable input queue trickling: some types of events + // submitted during the same frame (e.g. button down + up) will be spread over + // multiple frames, improving interactions with low framerates. + bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it + // to be distracting). + bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will keep item active and select + // contents (single-line only). + bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a + // simple mouse click-release (without moving). Not desirable on devices without a + // keyboard. + bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the + // lower-left corner. This requires ImGuiBackendFlags_HasMouseCursors for better + // mouse cursor feedback. (This used to be a per-window + // ImGuiWindowFlags_ResizeFromAnySide flag) + bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on + // their title bar. Does not apply to windows without a title bar. + bool ConfigWindowsCopyContentsWithCtrlC; // = false // [EXPERIMENTAL] CTRL+C copy the contents of focused + // window into the clipboard. Experimental because: (1) has known issues + // with nested Begin/End pairs (2) text output quality varies (3) text + // output is in submission order rather than spatial order. + bool ConfigScrollbarScrollByPage; // = true // Enable scrolling page by page when clicking outside the + // scrollbar grab. When disabled, always scroll to clicked location. When enabled, + // Shift+Click scrolls to clicked location. + float ConfigMemoryCompactTimer; // = 60.0f // Timer (in seconds) to free transient windows/tables memory + // buffers when unused. Set to -1.0f to disable. // Inputs Behaviors // (other variables, ones which are expected to be tweaked within UI code, are exposed in ImGuiStyle) - float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds. - float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels. - float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging. - float KeyRepeatDelay; // = 0.275f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). - float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. + float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds. + float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in + // pixels. + float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging. + float KeyRepeatDelay; // = 0.275f // When holding a key/button, time before it starts repeating, in seconds + // (for buttons in Repeat mode, etc.). + float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. //------------------------------------------------------------------ // Debug options @@ -2390,50 +3767,72 @@ struct ImGuiIO // Options to configure Error Handling and how we handle recoverable errors [EXPERIMENTAL] // - Error recovery is provided as a way to facilitate: - // - Recovery after a programming error (native code or scripting language - the later tends to facilitate iterating on code while running). - // - Recovery after running an exception handler or any error processing which may skip code after an error has been detected. + // - Recovery after a programming error (native code or scripting language - the later tends to facilitate + // iterating on code while running). + // - Recovery after running an exception handler or any error processing which may skip code after an error has + // been detected. // - Error recovery is not perfect nor guaranteed! It is a feature to ease development. // You not are not supposed to rely on it in the course of a normal application run. // - Functions that support error recovery are using IM_ASSERT_USER_ERROR() instead of IM_ASSERT(). // - By design, we do NOT allow error recovery to be 100% silent. One of the three options needs to be checked! - // - Always ensure that on programmers seats you have at minimum Asserts or Tooltips enabled when making direct imgui API calls! + // - Always ensure that on programmers seats you have at minimum Asserts or Tooltips enabled when making direct + // imgui API calls! // Otherwise it would severely hinder your ability to catch and correct mistakes! // Read https://github.com/ocornut/imgui/wiki/Error-Handling for details. // - Programmer seats: keep asserts (default), or disable asserts and keep error tooltips (new and nice!) - // - Non-programmer seats: maybe disable asserts, but make sure errors are resurfaced (tooltips, visible log entries, use callback etc.) - // - Recovery after error/exception: record stack sizes with ErrorRecoveryStoreState(), disable assert, set log callback (to e.g. trigger high-level breakpoint), recover with ErrorRecoveryTryToRecoverState(), restore settings. - bool ConfigErrorRecovery; // = true // Enable error recovery support. Some errors won't be detected and lead to direct crashes if recovery is disabled. - bool ConfigErrorRecoveryEnableAssert; // = true // Enable asserts on recoverable error. By default call IM_ASSERT() when returning from a failing IM_ASSERT_USER_ERROR() - bool ConfigErrorRecoveryEnableDebugLog; // = true // Enable debug log output on recoverable errors. - bool ConfigErrorRecoveryEnableTooltip; // = true // Enable tooltip on recoverable errors. The tooltip include a way to enable asserts if they were disabled. + // - Non-programmer seats: maybe disable asserts, but make sure errors are resurfaced (tooltips, visible log + // entries, use callback etc.) + // - Recovery after error/exception: record stack sizes with ErrorRecoveryStoreState(), disable assert, set log + // callback (to e.g. trigger high-level breakpoint), recover with ErrorRecoveryTryToRecoverState(), restore + // settings. + bool ConfigErrorRecovery; // = true // Enable error recovery support. Some errors won't be detected and lead + // to direct crashes if recovery is disabled. + bool ConfigErrorRecoveryEnableAssert; // = true // Enable asserts on recoverable error. By default call + // IM_ASSERT() when returning from a failing IM_ASSERT_USER_ERROR() + bool ConfigErrorRecoveryEnableDebugLog; // = true // Enable debug log output on recoverable errors. + bool ConfigErrorRecoveryEnableTooltip; // = true // Enable tooltip on recoverable errors. The tooltip include + // a way to enable asserts if they were disabled. // Option to enable various debug tools showing buttons that will call the IM_DEBUG_BREAK() macro. - // - The Item Picker tool will be available regardless of this being enabled, in order to maximize its discoverability. + // - The Item Picker tool will be available regardless of this being enabled, in order to maximize its + // discoverability. // - Requires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application. - // e.g. io.ConfigDebugIsDebuggerPresent = ::IsDebuggerPresent() on Win32, or refer to ImOsIsDebuggerPresent() imgui_test_engine/imgui_te_utils.cpp for a Unix compatible version). - bool ConfigDebugIsDebuggerPresent; // = false // Enable various tools calling IM_DEBUG_BREAK(). + // e.g. io.ConfigDebugIsDebuggerPresent = ::IsDebuggerPresent() on Win32, or refer to ImOsIsDebuggerPresent() + // imgui_test_engine/imgui_te_utils.cpp for a Unix compatible version). + bool ConfigDebugIsDebuggerPresent; // = false // Enable various tools calling IM_DEBUG_BREAK(). // Tools to detect code submitting items with conflicting/duplicate IDs // - Code should use PushID()/PopID() in loops, or append "##xx" to same-label identifiers. // - Empty label e.g. Button("") == same ID as parent widget/node. Use Button("##xx") instead! // - See FAQ https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-about-the-id-stack-system - bool ConfigDebugHighlightIdConflicts;// = true // Highlight and show an error message popup when multiple items have conflicting identifiers. - bool ConfigDebugHighlightIdConflictsShowItemPicker;//=true // Show "Item Picker" button in aforementioned popup. + bool ConfigDebugHighlightIdConflicts; // = true // Highlight and show an error message popup when multiple + // items have conflicting identifiers. + bool ConfigDebugHighlightIdConflictsShowItemPicker; //=true // Show "Item Picker" button in aforementioned popup. // Tools to test correct Begin/End and BeginChild/EndChild behaviors. - // - Presently Begin()/End() and BeginChild()/EndChild() needs to ALWAYS be called in tandem, regardless of return value of BeginXXX() + // - Presently Begin()/End() and BeginChild()/EndChild() needs to ALWAYS be called in tandem, regardless of return + // value of BeginXXX() // - This is inconsistent with other BeginXXX functions and create confusion for many users. - // - We expect to update the API eventually. In the meanwhile we provide tools to facilitate checking user-code behavior. - bool ConfigDebugBeginReturnValueOnce;// = false // First-time calls to Begin()/BeginChild() will return false. NEEDS TO BE SET AT APPLICATION BOOT TIME if you don't want to miss windows. - bool ConfigDebugBeginReturnValueLoop;// = false // Some calls to Begin()/BeginChild() will return false. Will cycle through window depths then repeat. Suggested use: add "io.ConfigDebugBeginReturnValue = io.KeyShift" in your main loop then occasionally press SHIFT. Windows should be flickering while running. + // - We expect to update the API eventually. In the meanwhile we provide tools to facilitate checking user-code + // behavior. + bool ConfigDebugBeginReturnValueOnce; // = false // First-time calls to Begin()/BeginChild() will return + // false. NEEDS TO BE SET AT APPLICATION BOOT TIME if you don't want to miss + // windows. + bool ConfigDebugBeginReturnValueLoop; // = false // Some calls to Begin()/BeginChild() will return false. + // Will cycle through window depths then repeat. Suggested use: add + // "io.ConfigDebugBeginReturnValue = io.KeyShift" in your main loop then + // occasionally press SHIFT. Windows should be flickering while running. // Option to deactivate io.AddFocusEvent(false) handling. // - May facilitate interactions with a debugger when focus loss leads to clearing inputs data. - // - Backends may have other side-effects on focus loss, so this will reduce side-effects but not necessary remove all of them. - bool ConfigDebugIgnoreFocusLoss; // = false // Ignore io.AddFocusEvent(false), consequently not calling io.ClearInputKeys()/io.ClearInputMouse() in input processing. + // - Backends may have other side-effects on focus loss, so this will reduce side-effects but not necessary remove + // all of them. + bool ConfigDebugIgnoreFocusLoss; // = false // Ignore io.AddFocusEvent(false), consequently not calling + // io.ClearInputKeys()/io.ClearInputMouse() in input processing. // Option to audit .ini data - bool ConfigDebugIniSettings; // = false // Save .ini data with extra comments (particularly helpful for Docking, but makes saving slower) + bool ConfigDebugIniSettings; // = false // Save .ini data with extra comments (particularly helpful for + // Docking, but makes saving slower) //------------------------------------------------------------------ // Platform Identifiers @@ -2441,36 +3840,54 @@ struct ImGuiIO //------------------------------------------------------------------ // Nowadays those would be stored in ImGuiPlatformIO but we are leaving them here for legacy reasons. - // Optional: Platform/Renderer backend name (informational only! will be displayed in About Window) + User data for backend/wrappers to store their own stuff. - const char* BackendPlatformName; // = NULL - const char* BackendRendererName; // = NULL - void* BackendPlatformUserData; // = NULL // User data for platform backend - void* BackendRendererUserData; // = NULL // User data for renderer backend - void* BackendLanguageUserData; // = NULL // User data for non C++ programming language backend + // Optional: Platform/Renderer backend name (informational only! will be displayed in About Window) + User data for + // backend/wrappers to store their own stuff. + const char *BackendPlatformName; // = NULL + const char *BackendRendererName; // = NULL + void *BackendPlatformUserData; // = NULL // User data for platform backend + void *BackendRendererUserData; // = NULL // User data for renderer backend + void *BackendLanguageUserData; // = NULL // User data for non C++ programming language backend //------------------------------------------------------------------ // Input - Call before calling NewFrame() //------------------------------------------------------------------ // Input Functions - IMGUI_API void AddKeyEvent(ImGuiKey key, bool down); // Queue a new key down/up event. Key should be "translated" (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character) - IMGUI_API void AddKeyAnalogEvent(ImGuiKey key, bool down, float v); // Queue a new key down/up event for analog values (e.g. ImGuiKey_Gamepad_ values). Dead-zones should be handled by the backend. - IMGUI_API void AddMousePosEvent(float x, float y); // Queue a mouse position update. Use -FLT_MAX,-FLT_MAX to signify no mouse (e.g. app not focused and not hovered) - IMGUI_API void AddMouseButtonEvent(int button, bool down); // Queue a mouse button change - IMGUI_API void AddMouseWheelEvent(float wheel_x, float wheel_y); // Queue a mouse wheel update. wheel_y<0: scroll down, wheel_y>0: scroll up, wheel_x<0: scroll right, wheel_x>0: scroll left. - IMGUI_API void AddMouseSourceEvent(ImGuiMouseSource source); // Queue a mouse source change (Mouse/TouchScreen/Pen) - IMGUI_API void AddFocusEvent(bool focused); // Queue a gain/loss of focus for the application (generally based on OS/platform focus of your window) - IMGUI_API void AddInputCharacter(unsigned int c); // Queue a new character input - IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue a new character input from a UTF-16 character, it can be a surrogate - IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue a new characters input from a UTF-8 string + IMGUI_API void AddKeyEvent( + ImGuiKey key, bool down); // Queue a new key down/up event. Key should be "translated" (as in, generally + // ImGuiKey_A matches the key end-user would use to emit an 'A' character) + IMGUI_API void AddKeyAnalogEvent( + ImGuiKey key, bool down, float v); // Queue a new key down/up event for analog values (e.g. ImGuiKey_Gamepad_ + // values). Dead-zones should be handled by the backend. + IMGUI_API void AddMousePosEvent(float x, float y); // Queue a mouse position update. Use -FLT_MAX,-FLT_MAX to + // signify no mouse (e.g. app not focused and not hovered) + IMGUI_API void AddMouseButtonEvent(int button, bool down); // Queue a mouse button change + IMGUI_API void AddMouseWheelEvent(float wheel_x, + float wheel_y); // Queue a mouse wheel update. wheel_y<0: scroll down, wheel_y>0: + // scroll up, wheel_x<0: scroll right, wheel_x>0: scroll left. + IMGUI_API void AddMouseSourceEvent(ImGuiMouseSource source); // Queue a mouse source change (Mouse/TouchScreen/Pen) + IMGUI_API void AddFocusEvent(bool focused); // Queue a gain/loss of focus for the application (generally based on + // OS/platform focus of your window) + IMGUI_API void AddInputCharacter(unsigned int c); // Queue a new character input + IMGUI_API void AddInputCharacterUTF16( + ImWchar16 c); // Queue a new character input from a UTF-16 character, it can be a surrogate + IMGUI_API void AddInputCharactersUTF8(const char *str); // Queue a new characters input from a UTF-8 string - IMGUI_API void SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index = -1); // [Optional] Specify index for legacy <1.87 IsKeyXXX() functions with native indices + specify native keycode, scancode. - IMGUI_API void SetAppAcceptingEvents(bool accepting_events); // Set master flag for accepting key/mouse/text events (default to true). Useful if you have native dialog boxes that are interrupting your application loop/refresh, and you want to disable events being queued while your app is frozen. - IMGUI_API void ClearEventsQueue(); // Clear all incoming events. - IMGUI_API void ClearInputKeys(); // Clear current keyboard/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons. - IMGUI_API void ClearInputMouse(); // Clear current mouse state. + IMGUI_API void SetKeyEventNativeData( + ImGuiKey key, int native_keycode, int native_scancode, + int native_legacy_index = -1); // [Optional] Specify index for legacy <1.87 IsKeyXXX() functions with native + // indices + specify native keycode, scancode. + IMGUI_API void SetAppAcceptingEvents( + bool accepting_events); // Set master flag for accepting key/mouse/text events (default to true). Useful if you + // have native dialog boxes that are interrupting your application loop/refresh, and you + // want to disable events being queued while your app is frozen. + IMGUI_API void ClearEventsQueue(); // Clear all incoming events. + IMGUI_API void ClearInputKeys(); // Clear current keyboard/gamepad state + current frame text input buffer. + // Equivalent to releasing all keys/buttons. + IMGUI_API void ClearInputMouse(); // Clear current mouse state. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - IMGUI_API void ClearInputCharacters(); // [Obsoleted in 1.89.8] Clear the current frame text input buffer. Now included within ClearInputKeys(). + IMGUI_API void ClearInputCharacters(); // [Obsoleted in 1.89.8] Clear the current frame text input buffer. Now + // included within ClearInputKeys(). #endif //------------------------------------------------------------------ @@ -2479,296 +3896,476 @@ struct ImGuiIO // generally easier and more correct to use their state BEFORE calling NewFrame(). See FAQ for details!) //------------------------------------------------------------------ - bool WantCaptureMouse; // Set when Dear ImGui will use mouse inputs, in this case do not dispatch them to your main game/application (either way, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.). - bool WantCaptureKeyboard; // Set when Dear ImGui will use keyboard inputs, in this case do not dispatch them to your main game/application (either way, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.). - bool WantTextInput; // Mobile/console: when set, you may display an on-screen keyboard. This is set by Dear ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active). - bool WantSetMousePos; // MousePos has been altered, backend should reposition mouse on next frame. Rarely used! Set only when io.ConfigNavMoveSetMousePos is enabled. - 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 highlight is visible and allowed (will handle ImGuiKey_NavXXX events). - float Framerate; // Estimate of application framerate (rolling average over 60 frames, based on io.DeltaTime), in frame per second. Solely for convenience. Slow applications may not want to use a moving average or may want to reset underlying buffers occasionally. - 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 - int MetricsActiveWindows; // Number of active windows - ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta. + bool WantCaptureMouse; // Set when Dear ImGui will use mouse inputs, in this case do not dispatch them to your main + // game/application (either way, always pass on mouse inputs to imgui). (e.g. unclicked mouse + // is hovering over an imgui window, widget is active, mouse was clicked over an imgui + // window, etc.). + bool WantCaptureKeyboard; // Set when Dear ImGui will use keyboard inputs, in this case do not dispatch them to your + // main game/application (either way, always pass keyboard inputs to imgui). (e.g. + // InputText active, or an imgui window is focused and navigation is enabled, etc.). + bool WantTextInput; // Mobile/console: when set, you may display an on-screen keyboard. This is set by Dear ImGui + // when it wants textual keyboard input to happen (e.g. when a InputText widget is active). + bool WantSetMousePos; // MousePos has been altered, backend should reposition mouse on next frame. Rarely used! Set + // only when io.ConfigNavMoveSetMousePos is enabled. + 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 highlight is visible and allowed (will handle ImGuiKey_NavXXX + // events). + float Framerate; // Estimate of application framerate (rolling average over 60 frames, based on io.DeltaTime), in + // frame per second. Solely for convenience. Slow applications may not want to use a moving average + // or may want to reset underlying buffers occasionally. + 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 + int MetricsActiveWindows; // Number of active windows + ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid + // (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta. //------------------------------------------------------------------ // [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed! //------------------------------------------------------------------ - ImGuiContext* Ctx; // Parent UI context (needs to be set explicitly by parent). + ImGuiContext *Ctx; // Parent UI context (needs to be set explicitly by parent). // Main Input State - // (this block used to be written by backend, since 1.87 it is best to NOT write to those directly, call the AddXXX functions above instead) - // (reading from those variables is fair game, as they are extremely unlikely to be moving anywhere) - ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX, -FLT_MAX) if mouse is unavailable (on another screen, etc.) - bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui mostly uses left and right buttons. Other buttons allow us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API. - float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. >0 scrolls Up, <0 scrolls Down. Hold SHIFT to turn vertical scroll into horizontal scroll. - float MouseWheelH; // Mouse wheel Horizontal. >0 scrolls Left, <0 scrolls Right. Most users don't have a mouse with a horizontal wheel, may not be filled by all backends. - ImGuiMouseSource MouseSource; // Mouse actual input peripheral (Mouse/TouchScreen/Pen). - bool KeyCtrl; // Keyboard modifier down: Control - bool KeyShift; // Keyboard modifier down: Shift - bool KeyAlt; // Keyboard modifier down: Alt - bool KeySuper; // Keyboard modifier down: Cmd/Super/Windows + // (this block used to be written by backend, since 1.87 it is best to NOT write to those directly, call the AddXXX + // functions above instead) (reading from those variables is fair game, as they are extremely unlikely to be moving + // anywhere) + ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX, -FLT_MAX) if mouse is unavailable (on another + // screen, etc.) + bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui + // mostly uses left and right buttons. Other buttons allow us to track if the mouse is being used + // by your application + available to user as a convenience via IsMouse** API. + float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. >0 scrolls Up, <0 scrolls Down. Hold + // SHIFT to turn vertical scroll into horizontal scroll. + float MouseWheelH; // Mouse wheel Horizontal. >0 scrolls Left, <0 scrolls Right. Most users don't have a mouse with + // a horizontal wheel, may not be filled by all backends. + ImGuiMouseSource MouseSource; // Mouse actual input peripheral (Mouse/TouchScreen/Pen). + bool KeyCtrl; // Keyboard modifier down: Control + bool KeyShift; // Keyboard modifier down: Shift + bool KeyAlt; // Keyboard modifier down: Alt + bool KeySuper; // Keyboard modifier down: Cmd/Super/Windows // Other state maintained from data above + IO function calls - ImGuiKeyChord KeyMods; // Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags. Read-only, updated by NewFrame() - ImGuiKeyData KeysData[ImGuiKey_NamedKey_COUNT];// Key state for all known keys. Use IsKeyXXX() functions to access this. - bool WantCaptureMouseUnlessPopupClose; // Alternative to WantCaptureMouse: (WantCaptureMouse == true && WantCaptureMouseUnlessPopupClose == false) when a click over void is expected to close a popup. - ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) - ImVec2 MouseClickedPos[5]; // Position at time of clicking - double MouseClickedTime[5]; // Time of last click (used to figure out double-click) - bool MouseClicked[5]; // Mouse button went from !Down to Down (same as MouseClickedCount[x] != 0) - bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? (same as MouseClickedCount[x] == 2) - ImU16 MouseClickedCount[5]; // == 0 (not clicked), == 1 (same as MouseClicked[]), == 2 (double-clicked), == 3 (triple-clicked) etc. when going from !Down to Down - ImU16 MouseClickedLastCount[5]; // Count successive number of clicks. Stays valid after mouse release. Reset after another click is done. - bool MouseReleased[5]; // Mouse button went from Down to !Down - double MouseReleasedTime[5]; // Time of last released (rarely used! but useful to handle delayed single-click when trying to disambiguate them from double-click). - bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds. - bool MouseDownOwnedUnlessPopupClose[5]; // Track if button was clicked inside a dear imgui window. - bool MouseWheelRequestAxisSwap; // On a non-Mac system, holding SHIFT requests WheelY to perform the equivalent of a WheelX event. On a Mac system this is already enforced by the system. - bool MouseCtrlLeftAsRightClick; // (OSX) Set to true when the current click was a Ctrl+click that spawned a simulated right click - float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) - float MouseDownDurationPrev[5]; // Previous time the mouse button has been down - float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point (used for moving thresholds) - float PenPressure; // Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper storage currently unused by Dear ImGui. - bool AppFocusLost; // Only modify via AddFocusEvent() - bool AppAcceptingEvents; // Only modify via SetAppAcceptingEvents() - ImWchar16 InputQueueSurrogate; // For AddInputCharacterUTF16() - ImVector InputQueueCharacters; // Queue of _characters_ input (obtained by platform backend). Fill using AddInputCharacter() helper. + ImGuiKeyChord + KeyMods; // Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as + // io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags. Read-only, updated by NewFrame() + ImGuiKeyData + KeysData[ImGuiKey_NamedKey_COUNT]; // Key state for all known keys. Use IsKeyXXX() functions to access this. + bool WantCaptureMouseUnlessPopupClose; // Alternative to WantCaptureMouse: (WantCaptureMouse == true && + // WantCaptureMouseUnlessPopupClose == false) when a click over void is + // expected to close a popup. + ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in + // case either position is invalid) + ImVec2 MouseClickedPos[5]; // Position at time of clicking + double MouseClickedTime[5]; // Time of last click (used to figure out double-click) + bool MouseClicked[5]; // Mouse button went from !Down to Down (same as MouseClickedCount[x] != 0) + bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? (same as MouseClickedCount[x] == 2) + ImU16 MouseClickedCount[5]; // == 0 (not clicked), == 1 (same as MouseClicked[]), == 2 (double-clicked), == 3 + // (triple-clicked) etc. when going from !Down to Down + ImU16 MouseClickedLastCount[5]; // Count successive number of clicks. Stays valid after mouse release. Reset after + // another click is done. + bool MouseReleased[5]; // Mouse button went from Down to !Down + double MouseReleasedTime[5]; // Time of last released (rarely used! but useful to handle delayed single-click when + // trying to disambiguate them from double-click). + bool + MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We + // don't request mouse capture from the application if click started outside ImGui bounds. + bool MouseDownOwnedUnlessPopupClose[5]; // Track if button was clicked inside a dear imgui window. + bool MouseWheelRequestAxisSwap; // On a non-Mac system, holding SHIFT requests WheelY to perform the equivalent of a + // WheelX event. On a Mac system this is already enforced by the system. + bool MouseCtrlLeftAsRightClick; // (OSX) Set to true when the current click was a Ctrl+click that spawned a + // simulated right click + float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) + float MouseDownDurationPrev[5]; // Previous time the mouse button has been down + float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point + // (used for moving thresholds) + float PenPressure; // Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper + // storage currently unused by Dear ImGui. + bool AppFocusLost; // Only modify via AddFocusEvent() + bool AppAcceptingEvents; // Only modify via SetAppAcceptingEvents() + ImWchar16 InputQueueSurrogate; // For AddInputCharacterUTF16() + ImVector InputQueueCharacters; // Queue of _characters_ input (obtained by platform backend). Fill using + // AddInputCharacter() helper. - // Legacy: before 1.87, we required backend to fill io.KeyMap[] (imgui->native map) during initialization and io.KeysDown[] (native indices) every frame. - // This is still temporarily supported as a legacy feature. However the new preferred scheme is for backend to call io.AddKeyEvent(). - // Old (<1.87): ImGui::IsKeyPressed(ImGui::GetIO().KeyMap[ImGuiKey_Space]) --> New (1.87+) ImGui::IsKeyPressed(ImGuiKey_Space) - // Old (<1.87): ImGui::IsKeyPressed(MYPLATFORM_KEY_SPACE) --> New (1.87+) ImGui::IsKeyPressed(ImGuiKey_Space) + // Legacy: before 1.87, we required backend to fill io.KeyMap[] (imgui->native map) during initialization and + // io.KeysDown[] (native indices) every frame. This is still temporarily supported as a legacy feature. However the + // new preferred scheme is for backend to call io.AddKeyEvent(). + // Old (<1.87): ImGui::IsKeyPressed(ImGui::GetIO().KeyMap[ImGuiKey_Space]) --> New (1.87+) + // ImGui::IsKeyPressed(ImGuiKey_Space) Old (<1.87): ImGui::IsKeyPressed(MYPLATFORM_KEY_SPACE) --> New (1.87+) + // ImGui::IsKeyPressed(ImGuiKey_Space) // Read https://github.com/ocornut/imgui/issues/4921 for details. - //int KeyMap[ImGuiKey_COUNT]; // [LEGACY] Input: map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. The first 512 are now unused and should be kept zero. Legacy backend will write into KeyMap[] using ImGuiKey_ indices which are always >512. - //bool KeysDown[ImGuiKey_COUNT]; // [LEGACY] Input: Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). This used to be [512] sized. It is now ImGuiKey_COUNT to allow legacy io.KeysDown[GetKeyIndex(...)] to work without an overflow. - //float NavInputs[ImGuiNavInput_COUNT]; // [LEGACY] Since 1.88, NavInputs[] was removed. Backends from 1.60 to 1.86 won't build. Feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums. - //void* ImeWindowHandle; // [Obsoleted in 1.87] Set ImGuiViewport::PlatformHandleRaw instead. Set this to your HWND to get automatic IME cursor positioning. + // int KeyMap[ImGuiKey_COUNT]; // [LEGACY] Input: map of indices into the KeysDown[512] entries + // array which represent your "native" keyboard state. The first 512 are now unused and should be kept zero. Legacy + // backend will write into KeyMap[] using ImGuiKey_ indices which are always >512. bool KeysDown[ImGuiKey_COUNT]; // + // [LEGACY] Input: Keyboard keys that are pressed (ideally left in the "native" order your engine has access to + // keyboard keys, so you can use your own defines/enums for keys). This used to be [512] sized. It is now + // ImGuiKey_COUNT to allow legacy io.KeysDown[GetKeyIndex(...)] to work without an overflow. float + // NavInputs[ImGuiNavInput_COUNT]; // [LEGACY] Since 1.88, NavInputs[] was removed. Backends from 1.60 to 1.86 + // won't build. Feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums. void* ImeWindowHandle; + // // [Obsoleted in 1.87] Set ImGuiViewport::PlatformHandleRaw instead. Set this to your HWND to get automatic IME + // cursor positioning. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - float FontGlobalScale; // Moved io.FontGlobalScale to style.FontScaleMain in 1.92 (June 2025) + float FontGlobalScale; // Moved io.FontGlobalScale to style.FontScaleMain in 1.92 (June 2025) // Legacy: before 1.91.1, clipboard functions were stored in ImGuiIO instead of ImGuiPlatformIO. - // As this is will affect all users of custom engines/backends, we are providing proper legacy redirection (will obsolete). - const char* (*GetClipboardTextFn)(void* user_data); - void (*SetClipboardTextFn)(void* user_data, const char* text); - void* ClipboardUserData; + // As this is will affect all users of custom engines/backends, we are providing proper legacy redirection (will + // obsolete). + const char *(*GetClipboardTextFn)(void *user_data); + void (*SetClipboardTextFn)(void *user_data, const char *text); + void *ClipboardUserData; #endif - IMGUI_API ImGuiIO(); + IMGUI_API ImGuiIO(); }; //----------------------------------------------------------------------------- // [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload) //----------------------------------------------------------------------------- -// Shared state of InputText(), passed as an argument to your callback when a ImGuiInputTextFlags_Callback* flag is used. -// The callback function should return 0 by default. -// Callbacks (follow a flag name and see comments in ImGuiInputTextFlags_ declarations for more details) -// - ImGuiInputTextFlags_CallbackEdit: Callback on buffer edit. Note that InputText() already returns true on edit + you can always use IsItemEdited(). The callback is useful to manipulate the underlying buffer while focus is active. +// Shared state of InputText(), passed as an argument to your callback when a ImGuiInputTextFlags_Callback* flag is +// used. The callback function should return 0 by default. Callbacks (follow a flag name and see comments in +// ImGuiInputTextFlags_ declarations for more details) +// - ImGuiInputTextFlags_CallbackEdit: Callback on buffer edit. Note that InputText() already returns true on +// edit + you can always use IsItemEdited(). The callback is useful to manipulate the underlying buffer while focus is +// active. // - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration // - ImGuiInputTextFlags_CallbackCompletion: Callback on pressing TAB // - ImGuiInputTextFlags_CallbackHistory: Callback on pressing Up/Down arrows -// - ImGuiInputTextFlags_CallbackCharFilter: Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. -// - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. +// - ImGuiInputTextFlags_CallbackCharFilter: Callback on character inputs to replace or discard them. Modify +// 'EventChar' to replace or discard, or return 1 in callback to discard. +// - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter +// value), allowing the string to grow. struct ImGuiInputTextCallbackData { - ImGuiContext* Ctx; // Parent UI context - ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only - ImGuiInputTextFlags Flags; // What user passed to InputText() // Read-only - void* UserData; // What user passed to InputText() // Read-only + ImGuiContext *Ctx; // Parent UI context + ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only + ImGuiInputTextFlags Flags; // What user passed to InputText() // Read-only + void *UserData; // What user passed to InputText() // Read-only // Arguments for the different callback events // - During Resize callback, Buf will be same as your input buffer. - // - However, during Completion/History/Always callback, Buf always points to our own internal data (it is not the same as your buffer)! Changes to it will be reflected into your own buffer shortly after the callback. - // - To modify the text buffer in a callback, prefer using the InsertChars() / DeleteChars() function. InsertChars() will take care of calling the resize callback if necessary. - // - If you know your edits are not going to resize the underlying buffer allocation, you may modify the contents of 'Buf[]' directly. You need to update 'BufTextLen' accordingly (0 <= BufTextLen < BufSize) and set 'BufDirty'' to true so InputText can update its internal state. - ImWchar EventChar; // Character input // Read-write // [CharFilter] Replace character with another one, or set to zero to drop. return 1 is equivalent to setting EventChar=0; - ImGuiKey EventKey; // Key pressed (Up/Down/TAB) // Read-only // [Completion,History] - char* Buf; // Text buffer // Read-write // [Resize] Can replace pointer / [Completion,History,Always] Only write to pointed data, don't replace the actual pointer! - int BufTextLen; // Text length (in bytes) // Read-write // [Resize,Completion,History,Always] Exclude zero-terminator storage. In C land: == strlen(some_text), in C++ land: string.length() - int BufSize; // Buffer size (in bytes) = capacity+1 // Read-only // [Resize,Completion,History,Always] Include zero-terminator storage. In C land == ARRAYSIZE(my_char_array), in C++ land: string.capacity()+1 - bool BufDirty; // Set if you modify Buf/BufTextLen! // Write // [Completion,History,Always] - int CursorPos; // // Read-write // [Completion,History,Always] - int SelectionStart; // // Read-write // [Completion,History,Always] == to SelectionEnd when no selection) - int SelectionEnd; // // Read-write // [Completion,History,Always] + // - However, during Completion/History/Always callback, Buf always points to our own internal data (it is not the + // same as your buffer)! Changes to it will be reflected into your own buffer shortly after the callback. + // - To modify the text buffer in a callback, prefer using the InsertChars() / DeleteChars() function. InsertChars() + // will take care of calling the resize callback if necessary. + // - If you know your edits are not going to resize the underlying buffer allocation, you may modify the contents of + // 'Buf[]' directly. You need to update 'BufTextLen' accordingly (0 <= BufTextLen < BufSize) and set 'BufDirty'' to + // true so InputText can update its internal state. + ImWchar EventChar; // Character input // Read-write // [CharFilter] Replace character with + // another one, or set to zero to drop. return 1 is equivalent to setting EventChar=0; + ImGuiKey EventKey; // Key pressed (Up/Down/TAB) // Read-only // [Completion,History] + char *Buf; // Text buffer // Read-write // [Resize] Can replace pointer / + // [Completion,History,Always] Only write to pointed data, don't replace the actual pointer! + int BufTextLen; // Text length (in bytes) // Read-write // [Resize,Completion,History,Always] + // Exclude zero-terminator storage. In C land: == strlen(some_text), in C++ land: string.length() + int BufSize; // Buffer size (in bytes) = capacity+1 // Read-only // [Resize,Completion,History,Always] Include + // zero-terminator storage. In C land == ARRAYSIZE(my_char_array), in C++ land: string.capacity()+1 + bool BufDirty; // Set if you modify Buf/BufTextLen! // Write // [Completion,History,Always] + int CursorPos; // // Read-write // [Completion,History,Always] + int SelectionStart; // // Read-write // [Completion,History,Always] == to + // SelectionEnd when no selection) + int SelectionEnd; // // Read-write // [Completion,History,Always] // Helper functions for text manipulation. // Use those function to benefit from the CallbackResize behaviors. Calling those function reset the selection. IMGUI_API ImGuiInputTextCallbackData(); - IMGUI_API void DeleteChars(int pos, int bytes_count); - IMGUI_API void InsertChars(int pos, const char* text, const char* text_end = NULL); - void SelectAll() { SelectionStart = 0; SelectionEnd = BufTextLen; } - void ClearSelection() { SelectionStart = SelectionEnd = BufTextLen; } - bool HasSelection() const { return SelectionStart != SelectionEnd; } + IMGUI_API void DeleteChars(int pos, int bytes_count); + IMGUI_API void InsertChars(int pos, const char *text, const char *text_end = NULL); + void SelectAll() + { + SelectionStart = 0; + SelectionEnd = BufTextLen; + } + void ClearSelection() + { + SelectionStart = SelectionEnd = BufTextLen; + } + bool HasSelection() const + { + return SelectionStart != SelectionEnd; + } }; -// Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraints(). Callback is called during the next Begin(). -// NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraints() parameters are enough. +// Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraints(). Callback is called +// during the next Begin(). NB: For basic min/max size constraint on each axis you don't need to use the callback! The +// SetNextWindowSizeConstraints() parameters are enough. struct ImGuiSizeCallbackData { - void* UserData; // Read-only. What user passed to SetNextWindowSizeConstraints(). Generally store an integer or float in here (need reinterpret_cast<>). - ImVec2 Pos; // Read-only. Window position, for reference. - ImVec2 CurrentSize; // Read-only. Current window size. - ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing. + void *UserData; // Read-only. What user passed to SetNextWindowSizeConstraints(). Generally store an integer or + // float in here (need reinterpret_cast<>). + ImVec2 Pos; // Read-only. Window position, for reference. + ImVec2 CurrentSize; // Read-only. Current window size. + ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain + // resizing. }; // Data payload for Drag and Drop operations: AcceptDragDropPayload(), GetDragDropPayload() struct ImGuiPayload { // Members - void* Data; // Data (copied and owned by dear imgui) - int DataSize; // Data size + void *Data; // Data (copied and owned by dear imgui) + int DataSize; // Data size // [Internal] - ImGuiID SourceId; // Source item id - ImGuiID SourceParentId; // Source parent id (if available) - int DataFrameCount; // Data timestamp - char DataType[32 + 1]; // Data type tag (short user-supplied string, 32 characters max) - bool Preview; // Set when AcceptDragDropPayload() was called and mouse has been hovering the target item (nb: handle overlapping drag targets) - bool Delivery; // Set when AcceptDragDropPayload() was called and mouse button is released over the target item. + ImGuiID SourceId; // Source item id + ImGuiID SourceParentId; // Source parent id (if available) + int DataFrameCount; // Data timestamp + char DataType[32 + 1]; // Data type tag (short user-supplied string, 32 characters max) + bool Preview; // Set when AcceptDragDropPayload() was called and mouse has been hovering the target item (nb: handle + // overlapping drag targets) + bool Delivery; // Set when AcceptDragDropPayload() was called and mouse button is released over the target item. - ImGuiPayload() { Clear(); } - void Clear() { SourceId = SourceParentId = 0; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Preview = Delivery = false; } - bool IsDataType(const char* type) const { return DataFrameCount != -1 && strcmp(type, DataType) == 0; } - bool IsPreview() const { return Preview; } - bool IsDelivery() const { return Delivery; } + ImGuiPayload() + { + Clear(); + } + void Clear() + { + SourceId = SourceParentId = 0; + Data = NULL; + DataSize = 0; + memset(DataType, 0, sizeof(DataType)); + DataFrameCount = -1; + Preview = Delivery = false; + } + bool IsDataType(const char *type) const + { + return DataFrameCount != -1 && strcmp(type, DataType) == 0; + } + bool IsPreview() const + { + return Preview; + } + bool IsDelivery() const + { + return Delivery; + } }; //----------------------------------------------------------------------------- -// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor) +// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math +// Operators, ImColor) //----------------------------------------------------------------------------- // Helper: Unicode defines -#define IM_UNICODE_CODEPOINT_INVALID 0xFFFD // Invalid Unicode code point (standard value). +#define IM_UNICODE_CODEPOINT_INVALID 0xFFFD // Invalid Unicode code point (standard value). #ifdef IMGUI_USE_WCHAR32 -#define IM_UNICODE_CODEPOINT_MAX 0x10FFFF // Maximum Unicode code point supported by this build. +#define IM_UNICODE_CODEPOINT_MAX 0x10FFFF // Maximum Unicode code point supported by this build. #else -#define IM_UNICODE_CODEPOINT_MAX 0xFFFF // Maximum Unicode code point supported by this build. +#define IM_UNICODE_CODEPOINT_MAX 0xFFFF // Maximum Unicode code point supported by this build. #endif -// Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create a UI within deep-nested code that runs multiple times every frame. -// Usage: static ImGuiOnceUponAFrame oaf; if (oaf) ImGui::Text("This will be called only once per frame"); +// Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create a UI within +// deep-nested code that runs multiple times every frame. Usage: static ImGuiOnceUponAFrame oaf; if (oaf) +// ImGui::Text("This will be called only once per frame"); struct ImGuiOnceUponAFrame { - ImGuiOnceUponAFrame() { RefFrame = -1; } + ImGuiOnceUponAFrame() + { + RefFrame = -1; + } mutable int RefFrame; - operator bool() const { int current_frame = ImGui::GetFrameCount(); if (RefFrame == current_frame) return false; RefFrame = current_frame; return true; } + operator bool() const + { + int current_frame = ImGui::GetFrameCount(); + if (RefFrame == current_frame) + return false; + RefFrame = current_frame; + return true; + } }; // Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" struct ImGuiTextFilter { - IMGUI_API ImGuiTextFilter(const char* default_filter = ""); - IMGUI_API bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build - IMGUI_API bool PassFilter(const char* text, const char* text_end = NULL) const; - IMGUI_API void Build(); - void Clear() { InputBuf[0] = 0; Build(); } - bool IsActive() const { return !Filters.empty(); } + IMGUI_API ImGuiTextFilter(const char *default_filter = ""); + IMGUI_API bool Draw(const char *label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build + IMGUI_API bool PassFilter(const char *text, const char *text_end = NULL) const; + IMGUI_API void Build(); + void Clear() + { + InputBuf[0] = 0; + Build(); + } + bool IsActive() const + { + return !Filters.empty(); + } // [Internal] struct ImGuiTextRange { - const char* b; - const char* e; + const char *b; + const char *e; - ImGuiTextRange() { b = e = NULL; } - ImGuiTextRange(const char* _b, const char* _e) { b = _b; e = _e; } - bool empty() const { return b == e; } - IMGUI_API void split(char separator, ImVector* out) const; + ImGuiTextRange() + { + b = e = NULL; + } + ImGuiTextRange(const char *_b, const char *_e) + { + b = _b; + e = _e; + } + bool empty() const + { + return b == e; + } + IMGUI_API void split(char separator, ImVector *out) const; }; - char InputBuf[256]; - ImVectorFilters; - int CountGrep; + char InputBuf[256]; + ImVector Filters; + int CountGrep; }; // Helper: Growable text buffer for logging/accumulating text // (this could be called 'ImGuiTextBuilder' / 'ImGuiStringBuilder') struct ImGuiTextBuffer { - ImVector Buf; + ImVector Buf; IMGUI_API static char EmptyString[1]; - ImGuiTextBuffer() { } - inline char operator[](int i) const { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; } - const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; } - const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator - int size() const { return Buf.Size ? Buf.Size - 1 : 0; } - bool empty() const { return Buf.Size <= 1; } - void clear() { Buf.clear(); } - void resize(int size) { if (Buf.Size > size) Buf.Data[size] = 0; Buf.resize(size ? size + 1 : 0, 0); } // Similar to resize(0) on ImVector: empty string but don't free buffer. - void reserve(int capacity) { Buf.reserve(capacity); } - const char* c_str() const { return Buf.Data ? Buf.Data : EmptyString; } - IMGUI_API void append(const char* str, const char* str_end = NULL); - IMGUI_API void appendf(const char* fmt, ...) IM_FMTARGS(2); - IMGUI_API void appendfv(const char* fmt, va_list args) IM_FMTLIST(2); + ImGuiTextBuffer() + { + } + inline char operator[](int i) const + { + IM_ASSERT(Buf.Data != NULL); + return Buf.Data[i]; + } + const char *begin() const + { + return Buf.Data ? &Buf.front() : EmptyString; + } + const char *end() const + { + return Buf.Data ? &Buf.back() : EmptyString; + } // Buf is zero-terminated, so end() will point on the zero-terminator + int size() const + { + return Buf.Size ? Buf.Size - 1 : 0; + } + bool empty() const + { + return Buf.Size <= 1; + } + void clear() + { + Buf.clear(); + } + void resize(int size) + { + if (Buf.Size > size) + Buf.Data[size] = 0; + Buf.resize(size ? size + 1 : 0, 0); + } // Similar to resize(0) on ImVector: empty string but don't free buffer. + void reserve(int capacity) + { + Buf.reserve(capacity); + } + const char *c_str() const + { + return Buf.Data ? Buf.Data : EmptyString; + } + IMGUI_API void append(const char *str, const char *str_end = NULL); + IMGUI_API void appendf(const char *fmt, ...) IM_FMTARGS(2); + IMGUI_API void appendfv(const char *fmt, va_list args) IM_FMTLIST(2); }; // [Internal] Key+Value for ImGuiStorage struct ImGuiStoragePair { - ImGuiID key; - union { int val_i; float val_f; void* val_p; }; - ImGuiStoragePair(ImGuiID _key, int _val) { key = _key; val_i = _val; } - ImGuiStoragePair(ImGuiID _key, float _val) { key = _key; val_f = _val; } - ImGuiStoragePair(ImGuiID _key, void* _val) { key = _key; val_p = _val; } + ImGuiID key; + union { + int val_i; + float val_f; + void *val_p; + }; + ImGuiStoragePair(ImGuiID _key, int _val) + { + key = _key; + val_i = _val; + } + ImGuiStoragePair(ImGuiID _key, float _val) + { + key = _key; + val_f = _val; + } + ImGuiStoragePair(ImGuiID _key, void *_val) + { + key = _key; + val_p = _val; + } }; // Helper: Key->Value storage // Typically you don't have to worry about this since a storage is held within each Window. // We use it to e.g. store collapse state for a tree (Int 0/1) -// This is optimized for efficient lookup (dichotomy into a contiguous buffer) and rare insertion (typically tied to user interactions aka max once a frame) -// You can use it as custom user storage for temporary values. Declare your own storage if, for example: -// - You want to manipulate the open/close state of a particular sub-tree in your interface (tree node uses Int 0/1 to store their state). -// - You want to store custom debug data easily without adding or editing structures in your code (probably not efficient, but convenient) -// Types are NOT stored, so it is up to you to make sure your Key don't collide with different types. +// This is optimized for efficient lookup (dichotomy into a contiguous buffer) and rare insertion (typically tied to +// user interactions aka max once a frame) You can use it as custom user storage for temporary values. Declare your own +// storage if, for example: +// - You want to manipulate the open/close state of a particular sub-tree in your interface (tree node uses Int 0/1 to +// store their state). +// - You want to store custom debug data easily without adding or editing structures in your code (probably not +// efficient, but convenient) Types are NOT stored, so it is up to you to make sure your Key don't collide with +// different types. struct ImGuiStorage { // [Internal] - ImVector Data; + ImVector Data; // - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N) // - Set***() functions find pair, insertion on demand if missing. // - Sorted insertion is costly, paid once. A typical frame shouldn't need to insert any new pair. - void Clear() { Data.clear(); } - IMGUI_API int GetInt(ImGuiID key, int default_val = 0) const; - IMGUI_API void SetInt(ImGuiID key, int val); - IMGUI_API bool GetBool(ImGuiID key, bool default_val = false) const; - IMGUI_API void SetBool(ImGuiID key, bool val); - IMGUI_API float GetFloat(ImGuiID key, float default_val = 0.0f) const; - IMGUI_API void SetFloat(ImGuiID key, float val); - IMGUI_API void* GetVoidPtr(ImGuiID key) const; // default_val is NULL - IMGUI_API void SetVoidPtr(ImGuiID key, void* val); + void Clear() + { + Data.clear(); + } + IMGUI_API int GetInt(ImGuiID key, int default_val = 0) const; + IMGUI_API void SetInt(ImGuiID key, int val); + IMGUI_API bool GetBool(ImGuiID key, bool default_val = false) const; + IMGUI_API void SetBool(ImGuiID key, bool val); + IMGUI_API float GetFloat(ImGuiID key, float default_val = 0.0f) const; + IMGUI_API void SetFloat(ImGuiID key, float val); + IMGUI_API void *GetVoidPtr(ImGuiID key) const; // default_val is NULL + IMGUI_API void SetVoidPtr(ImGuiID key, void *val); - // - Get***Ref() functions finds pair, insert on demand if missing, return pointer. Useful if you intend to do Get+Set. - // - References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer. - // - A typical use case where this is convenient for quick hacking (e.g. add storage during a live Edit&Continue session if you can't modify existing struct) + // - Get***Ref() functions finds pair, insert on demand if missing, return pointer. Useful if you intend to do + // Get+Set. + // - References are only valid until a new value is added to the storage. Calling a Set***() function or a + // Get***Ref() function invalidates the pointer. + // - A typical use case where this is convenient for quick hacking (e.g. add storage during a live Edit&Continue + // session if you can't modify existing struct) // float* pvar = ImGui::GetFloatRef(key); ImGui::SliderFloat("var", pvar, 0, 100.0f); some_var += *pvar; - IMGUI_API int* GetIntRef(ImGuiID key, int default_val = 0); - IMGUI_API bool* GetBoolRef(ImGuiID key, bool default_val = false); - IMGUI_API float* GetFloatRef(ImGuiID key, float default_val = 0.0f); - IMGUI_API void** GetVoidPtrRef(ImGuiID key, void* default_val = NULL); + IMGUI_API int *GetIntRef(ImGuiID key, int default_val = 0); + IMGUI_API bool *GetBoolRef(ImGuiID key, bool default_val = false); + IMGUI_API float *GetFloatRef(ImGuiID key, float default_val = 0.0f); + IMGUI_API void **GetVoidPtrRef(ImGuiID key, void *default_val = NULL); - // Advanced: for quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once. - IMGUI_API void BuildSortByKey(); + // Advanced: for quicker full rebuild of a storage (instead of an incremental one), you may add all your contents + // and then sort once. + IMGUI_API void BuildSortByKey(); // Obsolete: use on your own storage if you know only integer are being stored (open/close all tree nodes) - IMGUI_API void SetAllInt(int val); + IMGUI_API void SetAllInt(int val); #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - //typedef ::ImGuiStoragePair ImGuiStoragePair; // 1.90.8: moved type outside struct + // typedef ::ImGuiStoragePair ImGuiStoragePair; // 1.90.8: moved type outside struct #endif }; // Helper: Manually clip large list of items. // If you have lots evenly spaced items and you have random access to the list, you can perform coarse // clipping based on visibility to only submit items that are in view. -// The clipper calculates the range of visible items and advance the cursor to compensate for the non-visible items we have skipped. -// (Dear ImGui already clip items based on their bounds but: it needs to first layout the item to do so, and generally -// fetching/submitting your own data incurs additional cost. Coarse clipping using ImGuiListClipper allows you to easily -// scale using lists with tens of thousands of items without a problem) +// The clipper calculates the range of visible items and advance the cursor to compensate for the non-visible items we +// have skipped. (Dear ImGui already clip items based on their bounds but: it needs to first layout the item to do so, +// and generally +// fetching/submitting your own data incurs additional cost. Coarse clipping using ImGuiListClipper allows you to +// easily scale using lists with tens of thousands of items without a problem) // Usage: // ImGuiListClipper clipper; // clipper.Begin(1000); // We have 1000 elements, evenly spaced. @@ -2776,131 +4373,270 @@ struct ImGuiStorage // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) // ImGui::Text("line number %d", i); // Generally what happens is: -// - Clipper lets you process the first element (DisplayStart = 0, DisplayEnd = 1) regardless of it being visible or not. +// - Clipper lets you process the first element (DisplayStart = 0, DisplayEnd = 1) regardless of it being visible or +// not. // - User code submit that one element. // - Clipper can measure the height of the first element -// - Clipper calculate the actual range of elements to display based on the current clipping rectangle, position the cursor before the first visible element. +// - Clipper calculate the actual range of elements to display based on the current clipping rectangle, position the +// cursor before the first visible element. // - User code submit visible elements. // - The clipper also handles various subtleties related to keyboard/gamepad navigation, wrapping etc. struct ImGuiListClipper { - ImGuiContext* Ctx; // Parent UI context - int DisplayStart; // First item to display, updated by each call to Step() - int DisplayEnd; // End of items to display (exclusive) - int ItemsCount; // [Internal] Number of items - float ItemsHeight; // [Internal] Height of item after a first step and item submission can calculate it - double StartPosY; // [Internal] Cursor position at the time of Begin() or after table frozen rows are all processed - double StartSeekOffsetY; // [Internal] Account for frozen rows in a table and initial loss of precision in very large windows. - void* TempData; // [Internal] Internal data + ImGuiContext *Ctx; // Parent UI context + int DisplayStart; // First item to display, updated by each call to Step() + int DisplayEnd; // End of items to display (exclusive) + int ItemsCount; // [Internal] Number of items + float ItemsHeight; // [Internal] Height of item after a first step and item submission can calculate it + double StartPosY; // [Internal] Cursor position at the time of Begin() or after table frozen rows are all processed + double StartSeekOffsetY; // [Internal] Account for frozen rows in a table and initial loss of precision in very + // large windows. + void *TempData; // [Internal] Internal data - // items_count: Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step, and you can call SeekCursorForItem() manually if you need) - // items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetFrameHeightWithSpacing(). + // items_count: Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in + // the final step, and you can call SeekCursorForItem() manually if you need) items_height: Use -1.0f to be + // calculated automatically on first step. Otherwise pass in the distance between your items, typically + // GetTextLineHeightWithSpacing() or GetFrameHeightWithSpacing(). IMGUI_API ImGuiListClipper(); IMGUI_API ~ImGuiListClipper(); - IMGUI_API void Begin(int items_count, float items_height = -1.0f); - IMGUI_API void End(); // Automatically called on the last call of Step() that returns false. - IMGUI_API bool Step(); // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can process/draw those items. + IMGUI_API void Begin(int items_count, float items_height = -1.0f); + IMGUI_API void End(); // Automatically called on the last call of Step() that returns false. + IMGUI_API bool Step(); // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can + // process/draw those items. - // Call IncludeItemByIndex() or IncludeItemsByIndex() *BEFORE* first call to Step() if you need a range of items to not be clipped, regardless of their visibility. - // (Due to alignment / padding of certain items it is possible that an extra item may be included on either end of the display range). - inline void IncludeItemByIndex(int item_index) { IncludeItemsByIndex(item_index, item_index + 1); } - IMGUI_API void IncludeItemsByIndex(int item_begin, int item_end); // item_end is exclusive e.g. use (42, 42+1) to make item 42 never clipped. + // Call IncludeItemByIndex() or IncludeItemsByIndex() *BEFORE* first call to Step() if you need a range of items to + // not be clipped, regardless of their visibility. (Due to alignment / padding of certain items it is possible that + // an extra item may be included on either end of the display range). + inline void IncludeItemByIndex(int item_index) + { + IncludeItemsByIndex(item_index, item_index + 1); + } + IMGUI_API void IncludeItemsByIndex( + int item_begin, int item_end); // item_end is exclusive e.g. use (42, 42+1) to make item 42 never clipped. // Seek cursor toward given item. This is automatically called while stepping. - // - The only reason to call this is: you can use ImGuiListClipper::Begin(INT_MAX) if you don't know item count ahead of time. + // - The only reason to call this is: you can use ImGuiListClipper::Begin(INT_MAX) if you don't know item count + // ahead of time. // - In this case, after all steps are done, you'll want to call SeekCursorForItem(item_count). - IMGUI_API void SeekCursorForItem(int item_index); + IMGUI_API void SeekCursorForItem(int item_index); #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - inline void IncludeRangeByIndices(int item_begin, int item_end) { IncludeItemsByIndex(item_begin, item_end); } // [renamed in 1.89.9] - //inline void ForceDisplayRangeByIndices(int item_begin, int item_end) { IncludeItemsByIndex(item_begin, item_end); } // [renamed in 1.89.6] - //inline ImGuiListClipper(int items_count, float items_height = -1.0f) { memset(this, 0, sizeof(*this)); ItemsCount = -1; Begin(items_count, items_height); } // [removed in 1.79] + inline void IncludeRangeByIndices(int item_begin, int item_end) + { + IncludeItemsByIndex(item_begin, item_end); + } // [renamed in 1.89.9] + // inline void ForceDisplayRangeByIndices(int item_begin, int item_end) { IncludeItemsByIndex(item_begin, item_end); + // } // [renamed in 1.89.6] inline ImGuiListClipper(int items_count, float items_height = -1.0f) { memset(this, 0, + // sizeof(*this)); ItemsCount = -1; Begin(items_count, items_height); } // [removed in 1.79] #endif }; // Helpers: ImVec2/ImVec4 operators // - It is important that we are keeping those disabled by default so they don't leak in user space. -// - This is in order to allow user enabling implicit cast operators between ImVec2/ImVec4 and their own types (using IM_VEC2_CLASS_EXTRA in imconfig.h) -// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths operators for ImVec2 and ImVec4. -// - We intentionally provide ImVec2*float but not float*ImVec2: this is rare enough and we want to reduce the surface for possible user mistake. +// - This is in order to allow user enabling implicit cast operators between ImVec2/ImVec4 and their own types (using +// IM_VEC2_CLASS_EXTRA in imconfig.h) +// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths +// operators for ImVec2 and ImVec4. +// - We intentionally provide ImVec2*float but not float*ImVec2: this is rare enough and we want to reduce the surface +// for possible user mistake. #ifdef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED IM_MSVC_RUNTIME_CHECKS_OFF // ImVec2 operators -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); } -static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } -static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } -static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } -static inline ImVec2 operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); } -static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } -static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } -static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } -static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } -static inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; } -static inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; } -static inline bool operator==(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } -static inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y; } +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); +} +static inline ImVec2 operator-(const ImVec2 &lhs, const ImVec2 &rhs) +{ + return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); +} +static inline ImVec2 operator*(const ImVec2 &lhs, const ImVec2 &rhs) +{ + return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); +} +static inline ImVec2 operator/(const ImVec2 &lhs, const ImVec2 &rhs) +{ + return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); +} +static inline ImVec2 operator-(const ImVec2 &lhs) +{ + return ImVec2(-lhs.x, -lhs.y); +} +static inline ImVec2 &operator*=(ImVec2 &lhs, const float rhs) +{ + lhs.x *= rhs; + lhs.y *= rhs; + return lhs; +} +static inline ImVec2 &operator/=(ImVec2 &lhs, const float rhs) +{ + lhs.x /= rhs; + lhs.y /= rhs; + return lhs; +} +static inline ImVec2 &operator+=(ImVec2 &lhs, const ImVec2 &rhs) +{ + lhs.x += rhs.x; + lhs.y += rhs.y; + return lhs; +} +static inline ImVec2 &operator-=(ImVec2 &lhs, const ImVec2 &rhs) +{ + lhs.x -= rhs.x; + lhs.y -= rhs.y; + return lhs; +} +static inline ImVec2 &operator*=(ImVec2 &lhs, const ImVec2 &rhs) +{ + lhs.x *= rhs.x; + lhs.y *= rhs.y; + return lhs; +} +static inline ImVec2 &operator/=(ImVec2 &lhs, const ImVec2 &rhs) +{ + lhs.x /= rhs.x; + lhs.y /= rhs.y; + return lhs; +} +static inline bool operator==(const ImVec2 &lhs, const ImVec2 &rhs) +{ + return lhs.x == rhs.x && lhs.y == rhs.y; +} +static inline bool operator!=(const ImVec2 &lhs, const ImVec2 &rhs) +{ + return lhs.x != rhs.x || lhs.y != rhs.y; +} // ImVec4 operators -static inline ImVec4 operator*(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs); } -static inline ImVec4 operator/(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / 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); } -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) { return ImVec4(-lhs.x, -lhs.y, -lhs.z, -lhs.w); } -static inline bool operator==(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w; } -static inline bool operator!=(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z || lhs.w != rhs.w; } +static inline ImVec4 operator*(const ImVec4 &lhs, const float rhs) +{ + return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs); +} +static inline ImVec4 operator/(const ImVec4 &lhs, const float rhs) +{ + return ImVec4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / 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); +} +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) +{ + return ImVec4(-lhs.x, -lhs.y, -lhs.z, -lhs.w); +} +static inline bool operator==(const ImVec4 &lhs, const ImVec4 &rhs) +{ + return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w; +} +static inline bool operator!=(const ImVec4 &lhs, const ImVec4 &rhs) +{ + return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z || lhs.w != rhs.w; +} IM_MSVC_RUNTIME_CHECKS_RESTORE #endif // Helpers macros to generate 32-bit encoded colors // - User can declare their own format by #defining the 5 _SHIFT/_MASK macros in their imconfig file. -// - Any setting other than the default will need custom backend support. The only standard backend that supports anything else than the default is DirectX9. +// - Any setting other than the default will need custom backend support. The only standard backend that supports +// anything else than the default is DirectX9. #ifndef IM_COL32_R_SHIFT #ifdef IMGUI_USE_BGRA_PACKED_COLOR -#define IM_COL32_R_SHIFT 16 -#define IM_COL32_G_SHIFT 8 -#define IM_COL32_B_SHIFT 0 -#define IM_COL32_A_SHIFT 24 -#define IM_COL32_A_MASK 0xFF000000 +#define IM_COL32_R_SHIFT 16 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 0 +#define IM_COL32_A_SHIFT 24 +#define IM_COL32_A_MASK 0xFF000000 #else -#define IM_COL32_R_SHIFT 0 -#define IM_COL32_G_SHIFT 8 -#define IM_COL32_B_SHIFT 16 -#define IM_COL32_A_SHIFT 24 -#define IM_COL32_A_MASK 0xFF000000 +#define IM_COL32_R_SHIFT 0 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 16 +#define IM_COL32_A_SHIFT 24 +#define IM_COL32_A_MASK 0xFF000000 #endif #endif -#define IM_COL32(R,G,B,A) (((ImU32)(A)<> IM_COL32_R_SHIFT) & 0xFF) * (1.0f / 255.0f), (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * (1.0f / 255.0f), (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * (1.0f / 255.0f), (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * (1.0f / 255.0f)) {} - inline operator ImU32() const { return ImGui::ColorConvertFloat4ToU32(Value); } - inline operator ImVec4() const { return Value; } + constexpr ImColor() + { + } + constexpr ImColor(float r, float g, float b, float a = 1.0f) : Value(r, g, b, a) + { + } + constexpr ImColor(const ImVec4 &col) : Value(col) + { + } + constexpr ImColor(int r, int g, int b, int a = 255) + : Value((float)r * (1.0f / 255.0f), (float)g * (1.0f / 255.0f), (float)b * (1.0f / 255.0f), + (float)a * (1.0f / 255.0f)) + { + } + constexpr ImColor(ImU32 rgba) + : Value((float)((rgba >> IM_COL32_R_SHIFT) & 0xFF) * (1.0f / 255.0f), + (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * (1.0f / 255.0f), + (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * (1.0f / 255.0f), + (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * (1.0f / 255.0f)) + { + } + inline operator ImU32() const + { + return ImGui::ColorConvertFloat4ToU32(Value); + } + inline operator ImVec4() const + { + return Value; + } // FIXME-OBSOLETE: May need to obsolete/cleanup those helpers. - inline void SetHSV(float h, float s, float v, float a = 1.0f){ ImGui::ColorConvertHSVtoRGB(h, s, v, Value.x, Value.y, Value.z); Value.w = a; } - static ImColor HSV(float h, float s, float v, float a = 1.0f) { float r, g, b; ImGui::ColorConvertHSVtoRGB(h, s, v, r, g, b); return ImColor(r, g, b, a); } + inline void SetHSV(float h, float s, float v, float a = 1.0f) + { + ImGui::ColorConvertHSVtoRGB(h, s, v, Value.x, Value.y, Value.z); + Value.w = a; + } + static ImColor HSV(float h, float s, float v, float a = 1.0f) + { + float r, g, b; + ImGui::ColorConvertHSVtoRGB(h, s, v, r, g, b); + return ImColor(r, g, b, a); + } }; //----------------------------------------------------------------------------- -// [SECTION] Multi-Select API flags and structures (ImGuiMultiSelectFlags, ImGuiSelectionRequestType, ImGuiSelectionRequest, ImGuiMultiSelectIO, ImGuiSelectionBasicStorage) +// [SECTION] Multi-Select API flags and structures (ImGuiMultiSelectFlags, ImGuiSelectionRequestType, +// ImGuiSelectionRequest, ImGuiMultiSelectIO, ImGuiSelectionBasicStorage) //----------------------------------------------------------------------------- // Multi-selection system @@ -2909,29 +4645,37 @@ struct ImColor // - This system implements standard multi-selection idioms (CTRL+Mouse/Keyboard, SHIFT+Mouse/Keyboard, etc) // with support for clipper (skipping non-visible items), box-select and many other details. // - Selectable(), Checkbox() are supported but custom widgets may use it as well. -// - TreeNode() is technically supported but... using this correctly is more complicated: you need some sort of linear/random access to your tree, -// which is suited to advanced trees setups also implementing filters and clipper. We will work toward simplifying and demoing it. +// - TreeNode() is technically supported but... using this correctly is more complicated: you need some sort of +// linear/random access to your tree, +// which is suited to advanced trees setups also implementing filters and clipper. We will work toward simplifying and +// demoing it. // - In the spirit of Dear ImGui design, your code owns actual selection data. // This is designed to allow all kinds of selection storage you may use in your application e.g. set/map/hash. // About ImGuiSelectionBasicStorage: // - This is an optional helper to store a selection state and apply selection requests. // - It is used by our demos and provided as a convenience to quickly implement multi-selection. // Usage: -// - Identify submitted items with SetNextItemSelectionUserData(), most likely using an index into your current data-set. +// - Identify submitted items with SetNextItemSelectionUserData(), most likely using an index into your current +// data-set. // - Store and maintain actual selection data using persistent object identifiers. // - Usage flow: // BEGIN - (1) Call BeginMultiSelect() and retrieve the ImGuiMultiSelectIO* result. // - (2) Honor request list (SetAll/SetRange requests) by updating your selection data. Same code as Step 6. -// - (3) [If using clipper] You need to make sure RangeSrcItem is always submitted. Calculate its index and pass to clipper.IncludeItemByIndex(). If storing indices in ImGuiSelectionUserData, a simple clipper.IncludeItemByIndex(ms_io->RangeSrcItem) call will work. +// - (3) [If using clipper] You need to make sure RangeSrcItem is always submitted. Calculate its index and +// pass to clipper.IncludeItemByIndex(). If storing indices in ImGuiSelectionUserData, a simple +// clipper.IncludeItemByIndex(ms_io->RangeSrcItem) call will work. // LOOP - (4) Submit your items with SetNextItemSelectionUserData() + Selectable()/TreeNode() calls. // END - (5) Call EndMultiSelect() and retrieve the ImGuiMultiSelectIO* result. // - (6) Honor request list (SetAll/SetRange requests) by updating your selection data. Same code as Step 2. -// If you submit all items (no clipper), Step 2 and 3 are optional and will be handled by each item themselves. It is fine to always honor those steps. +// If you submit all items (no clipper), Step 2 and 3 are optional and will be handled by each item themselves. It +// is fine to always honor those steps. // About ImGuiSelectionUserData: -// - This can store an application-defined identifier (e.g. index or pointer) submitted via SetNextItemSelectionUserData(). +// - This can store an application-defined identifier (e.g. index or pointer) submitted via +// SetNextItemSelectionUserData(). // - In return we store them into RangeSrcItem/RangeFirstItem/RangeLastItem and other fields in ImGuiMultiSelectIO. // - Most applications will store an object INDEX, hence the chosen name and type. Storing an index is natural, because -// SetRange requests will give you two end-points and you will need to iterate/interpolate between them to update your selection. +// SetRange requests will give you two end-points and you will need to iterate/interpolate between them to update your +// selection. // - However it is perfectly possible to store a POINTER or another IDENTIFIER inside ImGuiSelectionUserData. // Our system never assume that you identify items by indices, it never attempts to interpolate between two values. // - If you enable ImGuiMultiSelectFlags_NoRangeSelect then it is guaranteed that you will never have to interpolate @@ -2942,59 +4686,105 @@ struct ImColor // Flags for BeginMultiSelect() enum ImGuiMultiSelectFlags_ { - ImGuiMultiSelectFlags_None = 0, - ImGuiMultiSelectFlags_SingleSelect = 1 << 0, // Disable selecting more than one item. This is available to allow single-selection code to share same code/logic if desired. It essentially disables the main purpose of BeginMultiSelect() tho! - ImGuiMultiSelectFlags_NoSelectAll = 1 << 1, // Disable CTRL+A shortcut to select all. - ImGuiMultiSelectFlags_NoRangeSelect = 1 << 2, // Disable Shift+selection mouse/keyboard support (useful for unordered 2D selection). With BoxSelect is also ensure contiguous SetRange requests are not combined into one. This allows not handling interpolation in SetRange requests. - ImGuiMultiSelectFlags_NoAutoSelect = 1 << 3, // Disable selecting items when navigating (useful for e.g. supporting range-select in a list of checkboxes). - ImGuiMultiSelectFlags_NoAutoClear = 1 << 4, // Disable clearing selection when navigating or selecting another one (generally used with ImGuiMultiSelectFlags_NoAutoSelect. useful for e.g. supporting range-select in a list of checkboxes). - ImGuiMultiSelectFlags_NoAutoClearOnReselect = 1 << 5, // Disable clearing selection when clicking/selecting an already selected item. - ImGuiMultiSelectFlags_BoxSelect1d = 1 << 6, // Enable box-selection with same width and same x pos items (e.g. full row Selectable()). Box-selection works better with little bit of spacing between items hit-box in order to be able to aim at empty space. - ImGuiMultiSelectFlags_BoxSelect2d = 1 << 7, // Enable box-selection with varying width or varying x pos items support (e.g. different width labels, or 2D layout/grid). This is slower: alters clipping logic so that e.g. horizontal movements will update selection of normally clipped items. - ImGuiMultiSelectFlags_BoxSelectNoScroll = 1 << 8, // Disable scrolling when box-selecting near edges of scope. - ImGuiMultiSelectFlags_ClearOnEscape = 1 << 9, // Clear selection when pressing Escape while scope is focused. - ImGuiMultiSelectFlags_ClearOnClickVoid = 1 << 10, // Clear selection when clicking on empty location within scope. - ImGuiMultiSelectFlags_ScopeWindow = 1 << 11, // Scope for _BoxSelect and _ClearOnClickVoid is whole window (Default). Use if BeginMultiSelect() covers a whole window or used a single time in same window. - ImGuiMultiSelectFlags_ScopeRect = 1 << 12, // Scope for _BoxSelect and _ClearOnClickVoid is rectangle encompassing BeginMultiSelect()/EndMultiSelect(). Use if BeginMultiSelect() is called multiple times in same window. - ImGuiMultiSelectFlags_SelectOnClick = 1 << 13, // Apply selection on mouse down when clicking on unselected item. (Default) - ImGuiMultiSelectFlags_SelectOnClickRelease = 1 << 14, // Apply selection on mouse release when clicking an unselected item. Allow dragging an unselected item without altering selection. - //ImGuiMultiSelectFlags_RangeSelect2d = 1 << 15, // Shift+Selection uses 2d geometry instead of linear sequence, so possible to use Shift+up/down to select vertically in grid. Analogous to what BoxSelect does. - ImGuiMultiSelectFlags_NavWrapX = 1 << 16, // [Temporary] Enable navigation wrapping on X axis. Provided as a convenience because we don't have a design for the general Nav API for this yet. When the more general feature be public we may obsolete this flag in favor of new one. + ImGuiMultiSelectFlags_None = 0, + ImGuiMultiSelectFlags_SingleSelect = + 1 << 0, // Disable selecting more than one item. This is available to allow single-selection code to share same + // code/logic if desired. It essentially disables the main purpose of BeginMultiSelect() tho! + ImGuiMultiSelectFlags_NoSelectAll = 1 << 1, // Disable CTRL+A shortcut to select all. + ImGuiMultiSelectFlags_NoRangeSelect = + 1 << 2, // Disable Shift+selection mouse/keyboard support (useful for unordered 2D selection). With BoxSelect is + // also ensure contiguous SetRange requests are not combined into one. This allows not handling + // interpolation in SetRange requests. + ImGuiMultiSelectFlags_NoAutoSelect = 1 << 3, // Disable selecting items when navigating (useful for e.g. supporting + // range-select in a list of checkboxes). + ImGuiMultiSelectFlags_NoAutoClear = + 1 << 4, // Disable clearing selection when navigating or selecting another one (generally used with + // ImGuiMultiSelectFlags_NoAutoSelect. useful for e.g. supporting range-select in a list of checkboxes). + ImGuiMultiSelectFlags_NoAutoClearOnReselect = + 1 << 5, // Disable clearing selection when clicking/selecting an already selected item. + ImGuiMultiSelectFlags_BoxSelect1d = + 1 << 6, // Enable box-selection with same width and same x pos items (e.g. full row Selectable()). Box-selection + // works better with little bit of spacing between items hit-box in order to be able to aim at empty + // space. + ImGuiMultiSelectFlags_BoxSelect2d = + 1 << 7, // Enable box-selection with varying width or varying x pos items support (e.g. different width labels, + // or 2D layout/grid). This is slower: alters clipping logic so that e.g. horizontal movements will + // update selection of normally clipped items. + ImGuiMultiSelectFlags_BoxSelectNoScroll = 1 << 8, // Disable scrolling when box-selecting near edges of scope. + ImGuiMultiSelectFlags_ClearOnEscape = 1 << 9, // Clear selection when pressing Escape while scope is focused. + ImGuiMultiSelectFlags_ClearOnClickVoid = 1 << 10, // Clear selection when clicking on empty location within scope. + ImGuiMultiSelectFlags_ScopeWindow = + 1 << 11, // Scope for _BoxSelect and _ClearOnClickVoid is whole window (Default). Use if BeginMultiSelect() + // covers a whole window or used a single time in same window. + ImGuiMultiSelectFlags_ScopeRect = 1 << 12, // Scope for _BoxSelect and _ClearOnClickVoid is rectangle encompassing + // BeginMultiSelect()/EndMultiSelect(). Use if BeginMultiSelect() is + // called multiple times in same window. + ImGuiMultiSelectFlags_SelectOnClick = + 1 << 13, // Apply selection on mouse down when clicking on unselected item. (Default) + ImGuiMultiSelectFlags_SelectOnClickRelease = + 1 << 14, // Apply selection on mouse release when clicking an unselected item. Allow dragging an unselected item + // without altering selection. + // ImGuiMultiSelectFlags_RangeSelect2d = 1 << 15, // Shift+Selection uses 2d geometry instead of linear + // sequence, so possible to use Shift+up/down to select vertically in grid. Analogous to what BoxSelect does. + ImGuiMultiSelectFlags_NavWrapX = + 1 << 16, // [Temporary] Enable navigation wrapping on X axis. Provided as a convenience because we don't have a + // design for the general Nav API for this yet. When the more general feature be public we may obsolete + // this flag in favor of new one. }; // Main IO structure returned by BeginMultiSelect()/EndMultiSelect(). // This mainly contains a list of selection requests. // - Use 'Demo->Tools->Debug Log->Selection' to see requests as they happen. -// - Some fields are only useful if your list is dynamic and allows deletion (getting post-deletion focus/state right is shown in the demo) +// - Some fields are only useful if your list is dynamic and allows deletion (getting post-deletion focus/state right is +// shown in the demo) // - Below: who reads/writes each fields? 'r'=read, 'w'=write, 'ms'=multi-select code, 'app'=application/user code. struct ImGuiMultiSelectIO { //------------------------------------------// BeginMultiSelect / EndMultiSelect - ImVector Requests; // ms:w, app:r / ms:w app:r // Requests to apply to your selection data. - ImGuiSelectionUserData RangeSrcItem; // ms:w app:r / // (If using clipper) Begin: Source item (often the first selected item) must never be clipped: use clipper.IncludeItemByIndex() to ensure it is submitted. - ImGuiSelectionUserData NavIdItem; // ms:w, app:r / // (If using deletion) Last known SetNextItemSelectionUserData() value for NavId (if part of submitted items). - bool NavIdSelected; // ms:w, app:r / app:r // (If using deletion) Last known selection state for NavId (if part of submitted items). - bool RangeSrcReset; // app:w / ms:r // (If using deletion) Set before EndMultiSelect() to reset ResetSrcItem (e.g. if deleted selection). - int ItemsCount; // ms:w, app:r / app:r // 'int items_count' parameter to BeginMultiSelect() is copied here for convenience, allowing simpler calls to your ApplyRequests handler. Not used internally. + ImVector + Requests; // ms:w, app:r / ms:w app:r // Requests to apply to your selection data. + ImGuiSelectionUserData RangeSrcItem; // ms:w app:r / // (If using clipper) Begin: Source item + // (often the first selected item) must never be clipped: use + // clipper.IncludeItemByIndex() to ensure it is submitted. + ImGuiSelectionUserData NavIdItem; // ms:w, app:r / // (If using deletion) Last known + // SetNextItemSelectionUserData() value for NavId (if part of submitted items). + bool NavIdSelected; // ms:w, app:r / app:r // (If using deletion) Last known selection state for NavId + // (if part of submitted items). + bool RangeSrcReset; // app:w / ms:r // (If using deletion) Set before EndMultiSelect() to reset + // ResetSrcItem (e.g. if deleted selection). + int ItemsCount; // ms:w, app:r / app:r // 'int items_count' parameter to BeginMultiSelect() is copied + // here for convenience, allowing simpler calls to your ApplyRequests handler. Not used internally. }; // Selection request type enum ImGuiSelectionRequestType { ImGuiSelectionRequestType_None = 0, - ImGuiSelectionRequestType_SetAll, // Request app to clear selection (if Selected==false) or select all items (if Selected==true). We cannot set RangeFirstItem/RangeLastItem as its contents is entirely up to user (not necessarily an index) - ImGuiSelectionRequestType_SetRange, // Request app to select/unselect [RangeFirstItem..RangeLastItem] items (inclusive) based on value of Selected. Only EndMultiSelect() request this, app code can read after BeginMultiSelect() and it will always be false. + ImGuiSelectionRequestType_SetAll, // Request app to clear selection (if Selected==false) or select all items (if + // Selected==true). We cannot set RangeFirstItem/RangeLastItem as its contents is + // entirely up to user (not necessarily an index) + ImGuiSelectionRequestType_SetRange, // Request app to select/unselect [RangeFirstItem..RangeLastItem] items + // (inclusive) based on value of Selected. Only EndMultiSelect() request this, + // app code can read after BeginMultiSelect() and it will always be false. }; // Selection request item struct ImGuiSelectionRequest { //------------------------------------------// BeginMultiSelect / EndMultiSelect - ImGuiSelectionRequestType Type; // ms:w, app:r / ms:w, app:r // Request type. You'll most often receive 1 Clear + 1 SetRange with a single-item range. - bool Selected; // ms:w, app:r / ms:w, app:r // Parameter for SetAll/SetRange requests (true = select, false = unselect) - ImS8 RangeDirection; // / ms:w app:r // Parameter for SetRange request: +1 when RangeFirstItem comes before RangeLastItem, -1 otherwise. Useful if you want to preserve selection order on a backward Shift+Click. - ImGuiSelectionUserData RangeFirstItem; // / ms:w, app:r // Parameter for SetRange request (this is generally == RangeSrcItem when shift selecting from top to bottom). - ImGuiSelectionUserData RangeLastItem; // / ms:w, app:r // Parameter for SetRange request (this is generally == RangeSrcItem when shift selecting from bottom to top). Inclusive! + ImGuiSelectionRequestType Type; // ms:w, app:r / ms:w, app:r // Request type. You'll most often receive 1 + // Clear + 1 SetRange with a single-item range. + bool Selected; // ms:w, app:r / ms:w, app:r // Parameter for SetAll/SetRange requests (true = select, false + // = unselect) + ImS8 RangeDirection; // / ms:w app:r // Parameter for SetRange request: +1 when RangeFirstItem + // comes before RangeLastItem, -1 otherwise. Useful if you want to preserve + // selection order on a backward Shift+Click. + ImGuiSelectionUserData + RangeFirstItem; // / ms:w, app:r // Parameter for SetRange request (this is generally == + // RangeSrcItem when shift selecting from top to bottom). + ImGuiSelectionUserData + RangeLastItem; // / ms:w, app:r // Parameter for SetRange request (this is generally == + // RangeSrcItem when shift selecting from bottom to top). Inclusive! }; // Optional helper to store multi-selection state + apply multi-selection requests. @@ -3004,64 +4794,89 @@ struct ImGuiSelectionRequest // - USING THIS IS NOT MANDATORY. This is only a helper and not a required API. // To store a multi-selection, in your application you could: // - Use this helper as a convenience. We use our simple key->value ImGuiStorage as a std::set replacement. -// - Use your own external storage: e.g. std::set, std::vector, interval trees, intrusively stored selection etc. -// In ImGuiSelectionBasicStorage we: -// - always use indices in the multi-selection API (passed to SetNextItemSelectionUserData(), retrieved in ImGuiMultiSelectIO) -// - use the AdapterIndexToStorageId() indirection layer to abstract how persistent selection data is derived from an index. +// - Use your own external storage: e.g. std::set, std::vector, interval trees, intrusively +// stored selection etc. In ImGuiSelectionBasicStorage we: +// - always use indices in the multi-selection API (passed to SetNextItemSelectionUserData(), retrieved in +// ImGuiMultiSelectIO) +// - use the AdapterIndexToStorageId() indirection layer to abstract how persistent selection data is derived from an +// index. // - use decently optimized logic to allow queries and insertion of very large selection sets. // - do not preserve selection order. -// Many combinations are possible depending on how you prefer to store your items and how you prefer to store your selection. -// Large applications are likely to eventually want to get rid of this indirection layer and do their own thing. -// See https://github.com/ocornut/imgui/wiki/Multi-Select for details and pseudo-code using this helper. +// Many combinations are possible depending on how you prefer to store your items and how you prefer to store your +// selection. Large applications are likely to eventually want to get rid of this indirection layer and do their own +// thing. See https://github.com/ocornut/imgui/wiki/Multi-Select for details and pseudo-code using this helper. struct ImGuiSelectionBasicStorage { // Members - int Size; // // Number of selected items, maintained by this helper. - bool PreserveOrder; // = false // GetNextSelectedItem() will return ordered selection (currently implemented by two additional sorts of selection. Could be improved) - void* UserData; // = NULL // User data for use by adapter function // e.g. selection.UserData = (void*)my_items; - ImGuiID (*AdapterIndexToStorageId)(ImGuiSelectionBasicStorage* self, int idx); // e.g. selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { return ((MyItems**)self->UserData)[idx]->ID; }; - int _SelectionOrder;// [Internal] Increasing counter to store selection order - ImGuiStorage _Storage; // [Internal] Selection set. Think of this as similar to e.g. std::set. Prefer not accessing directly: iterate with GetNextSelectedItem(). + int Size; // // Number of selected items, maintained by this helper. + bool PreserveOrder; // = false // GetNextSelectedItem() will return ordered selection (currently implemented by two + // additional sorts of selection. Could be improved) + void *UserData; // = NULL // User data for use by adapter function // e.g. selection.UserData = + // (void*)my_items; + ImGuiID (*AdapterIndexToStorageId)( + ImGuiSelectionBasicStorage *self, + int idx); // e.g. selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { return + // ((MyItems**)self->UserData)[idx]->ID; }; + int _SelectionOrder; // [Internal] Increasing counter to store selection order + ImGuiStorage _Storage; // [Internal] Selection set. Think of this as similar to e.g. std::set. Prefer not + // accessing directly: iterate with GetNextSelectedItem(). // Methods IMGUI_API ImGuiSelectionBasicStorage(); - IMGUI_API void ApplyRequests(ImGuiMultiSelectIO* ms_io); // Apply selection requests coming from BeginMultiSelect() and EndMultiSelect() functions. It uses 'items_count' passed to BeginMultiSelect() - IMGUI_API bool Contains(ImGuiID id) const; // Query if an item id is in selection. - IMGUI_API void Clear(); // Clear selection - IMGUI_API void Swap(ImGuiSelectionBasicStorage& r); // Swap two selections - IMGUI_API void SetItemSelected(ImGuiID id, bool selected); // Add/remove an item from selection (generally done by ApplyRequests() function) - IMGUI_API bool GetNextSelectedItem(void** opaque_it, ImGuiID* out_id); // Iterate selection with 'void* it = NULL; ImGuiID id; while (selection.GetNextSelectedItem(&it, &id)) { ... }' - inline ImGuiID GetStorageIdFromIndex(int idx) { return AdapterIndexToStorageId(this, idx); } // Convert index to item id based on provided adapter. + IMGUI_API void ApplyRequests( + ImGuiMultiSelectIO *ms_io); // Apply selection requests coming from BeginMultiSelect() and EndMultiSelect() + // functions. It uses 'items_count' passed to BeginMultiSelect() + IMGUI_API bool Contains(ImGuiID id) const; // Query if an item id is in selection. + IMGUI_API void Clear(); // Clear selection + IMGUI_API void Swap(ImGuiSelectionBasicStorage &r); // Swap two selections + IMGUI_API void SetItemSelected( + ImGuiID id, bool selected); // Add/remove an item from selection (generally done by ApplyRequests() function) + IMGUI_API bool GetNextSelectedItem(void **opaque_it, + ImGuiID *out_id); // Iterate selection with 'void* it = NULL; ImGuiID id; while + // (selection.GetNextSelectedItem(&it, &id)) { ... }' + inline ImGuiID GetStorageIdFromIndex(int idx) + { + return AdapterIndexToStorageId(this, idx); + } // Convert index to item id based on provided adapter. }; // Optional helper to apply multi-selection requests to existing randomly accessible storage. -// Convenient if you want to quickly wire multi-select API on e.g. an array of bool or items storing their own selection state. +// Convenient if you want to quickly wire multi-select API on e.g. an array of bool or items storing their own selection +// state. struct ImGuiSelectionExternalStorage { // Members - void* UserData; // User data for use by adapter function // e.g. selection.UserData = (void*)my_items; - void (*AdapterSetItemSelected)(ImGuiSelectionExternalStorage* self, int idx, bool selected); // e.g. AdapterSetItemSelected = [](ImGuiSelectionExternalStorage* self, int idx, bool selected) { ((MyItems**)self->UserData)[idx]->Selected = selected; } + void *UserData; // User data for use by adapter function // e.g. selection.UserData = + // (void*)my_items; + void (*AdapterSetItemSelected)( + ImGuiSelectionExternalStorage *self, int idx, + bool selected); // e.g. AdapterSetItemSelected = [](ImGuiSelectionExternalStorage* self, int idx, bool selected) + // { ((MyItems**)self->UserData)[idx]->Selected = selected; } // Methods IMGUI_API ImGuiSelectionExternalStorage(); - IMGUI_API void ApplyRequests(ImGuiMultiSelectIO* ms_io); // Apply selection requests by using AdapterSetItemSelected() calls + IMGUI_API void ApplyRequests( + ImGuiMultiSelectIO *ms_io); // Apply selection requests by using AdapterSetItemSelected() calls }; //----------------------------------------------------------------------------- -// [SECTION] Drawing API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData) -// Hold a series of drawing commands. The user provides a renderer for ImDrawData which essentially contains an array of ImDrawList. +// [SECTION] Drawing API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, +// ImDrawList, ImDrawData) Hold a series of drawing commands. The user provides a renderer for ImDrawData which +// essentially contains an array of ImDrawList. //----------------------------------------------------------------------------- -// The maximum line width to bake anti-aliased textures for. Build atlas with ImFontAtlasFlags_NoBakedLines to disable baking. +// The maximum line width to bake anti-aliased textures for. Build atlas with ImFontAtlasFlags_NoBakedLines to disable +// baking. #ifndef IM_DRAWLIST_TEX_LINES_WIDTH_MAX -#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (32) +#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (32) #endif // ImDrawIdx: vertex index. [Compile-time configurable type] -// - To use 16-bit indices + allow large meshes: backend need to set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset (recommended). +// - To use 16-bit indices + allow large meshes: backend need to set 'io.BackendFlags |= +// ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset (recommended). // - To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in your imconfig.h file. #ifndef ImDrawIdx -typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibility with renderer backends) +typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibility with renderer backends) #endif // ImDrawCallback: Draw callbacks for advanced uses [configurable type: override in imconfig.h] @@ -3069,17 +4884,19 @@ typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibilit // you can poke into the draw list for that! Draw callback may be useful for example to: // A) Change your GPU render state, // B) render a complex 3D scene inside a UI element without an intermediate texture/render target, etc. -// The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) { cmd.UserCallback(parent_list, cmd); } else { RenderTriangles() }' -// If you want to override the signature of ImDrawCallback, you can simply use e.g. '#define ImDrawCallback MyDrawCallback' (in imconfig.h) + update rendering backend accordingly. +// The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) { cmd.UserCallback(parent_list, +// cmd); } else { RenderTriangles() }' If you want to override the signature of ImDrawCallback, you can simply use e.g. +// '#define ImDrawCallback MyDrawCallback' (in imconfig.h) + update rendering backend accordingly. #ifndef ImDrawCallback -typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd); +typedef void (*ImDrawCallback)(const ImDrawList *parent_list, const ImDrawCmd *cmd); #endif // Special Draw callback value to request renderer backend to reset the graphics/render state. -// The renderer backend needs to handle this special value, otherwise it will crash trying to call a function at this address. -// This is useful, for example, if you submitted callbacks which you know have altered the render state and you want it to be restored. -// Render state is not reset by default because they are many perfectly useful way of altering render state (e.g. changing shader/blending settings before an Image call). -#define ImDrawCallback_ResetRenderState (ImDrawCallback)(-8) +// The renderer backend needs to handle this special value, otherwise it will crash trying to call a function at this +// address. This is useful, for example, if you submitted callbacks which you know have altered the render state and you +// want it to be restored. Render state is not reset by default because they are many perfectly useful way of altering +// render state (e.g. changing shader/blending settings before an Image call). +#define ImDrawCallback_ResetRenderState (ImDrawCallback)(-8) // Typically, 1 command = 1 GPU draw call (unless command is a callback) // - VtxOffset: When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' is enabled, @@ -3088,100 +4905,143 @@ typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* c // - The ClipRect/TexRef/VtxOffset fields must be contiguous as we memcmp() them together (this is asserted for). struct ImDrawCmd { - ImVec4 ClipRect; // 4*4 // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates - ImTextureRef TexRef; // 16 // Reference to a font/texture atlas (where backend called ImTextureData::SetTexID()) or to a user-provided texture ID (via e.g. ImGui::Image() calls). Both will lead to a ImTextureID value. - unsigned int VtxOffset; // 4 // Start offset in vertex buffer. ImGuiBackendFlags_RendererHasVtxOffset: always 0, otherwise may be >0 to support meshes larger than 64K vertices with 16-bit indices. - unsigned int IdxOffset; // 4 // Start offset in index buffer. - unsigned int ElemCount; // 4 // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. - ImDrawCallback UserCallback; // 4-8 // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally. - void* UserCallbackData; // 4-8 // Callback user data (when UserCallback != NULL). If called AddCallback() with size == 0, this is a copy of the AddCallback() argument. If called AddCallback() with size > 0, this is pointing to a buffer where data is stored. - int UserCallbackDataSize; // 4 // Size of callback user data when using storage, otherwise 0. - int UserCallbackDataOffset;// 4 // [Internal] Offset of callback user data when using storage, otherwise -1. + ImVec4 ClipRect; // 4*4 // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping + // rectangle in "viewport" coordinates + ImTextureRef + TexRef; // 16 // Reference to a font/texture atlas (where backend called ImTextureData::SetTexID()) or to a + // user-provided texture ID (via e.g. ImGui::Image() calls). Both will lead to a ImTextureID value. + unsigned int VtxOffset; // 4 // Start offset in vertex buffer. ImGuiBackendFlags_RendererHasVtxOffset: always 0, + // otherwise may be >0 to support meshes larger than 64K vertices with 16-bit indices. + unsigned int IdxOffset; // 4 // Start offset in index buffer. + unsigned int ElemCount; // 4 // Number of indices (multiple of 3) to be rendered as triangles. Vertices are + // stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. + ImDrawCallback UserCallback; // 4-8 // If != NULL, call the function instead of rendering the vertices. clip_rect + // and texture_id will be set normally. + void *UserCallbackData; // 4-8 // Callback user data (when UserCallback != NULL). If called AddCallback() with size + // == 0, this is a copy of the AddCallback() argument. If called AddCallback() with size > + // 0, this is pointing to a buffer where data is stored. + int UserCallbackDataSize; // 4 // Size of callback user data when using storage, otherwise 0. + int UserCallbackDataOffset; // 4 // [Internal] Offset of callback user data when using storage, otherwise -1. - ImDrawCmd() { memset(this, 0, sizeof(*this)); } // Also ensure our padding fields are zeroed + 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) - // Since 1.92: removed ImDrawCmd::TextureId field, the getter function must be used! - inline ImTextureID GetTexID() const; // == (TexRef._TexData ? TexRef._TexData->TexID : TexRef._TexID + // 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) Since 1.92: removed ImDrawCmd::TextureId + // field, the getter function must be used! + inline ImTextureID GetTexID() const; // == (TexRef._TexData ? TexRef._TexData->TexID : TexRef._TexID }; // Vertex layout #ifndef IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { - ImVec2 pos; - ImVec2 uv; - ImU32 col; + ImVec2 pos; + ImVec2 uv; + ImU32 col; }; #else // You can override the vertex format layout by defining IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT in imconfig.h -// The code expect ImVec2 pos (8 bytes), ImVec2 uv (8 bytes), ImU32 col (4 bytes), but you can re-order them or add other fields as needed to simplify integration in your engine. -// The type has to be described within the macro (you can either declare the struct or use a typedef). This is because ImVec2/ImU32 are likely not declared at the time you'd want to set your type up. -// NOTE: IMGUI DOESN'T CLEAR THE STRUCTURE AND DOESN'T CALL A CONSTRUCTOR SO ANY CUSTOM FIELD WILL BE UNINITIALIZED. IF YOU ADD EXTRA FIELDS (SUCH AS A 'Z' COORDINATES) YOU WILL NEED TO CLEAR THEM DURING RENDER OR TO IGNORE THEM. +// The code expect ImVec2 pos (8 bytes), ImVec2 uv (8 bytes), ImU32 col (4 bytes), but you can re-order them or add +// other fields as needed to simplify integration in your engine. The type has to be described within the macro (you can +// either declare the struct or use a typedef). This is because ImVec2/ImU32 are likely not declared at the time you'd +// want to set your type up. NOTE: IMGUI DOESN'T CLEAR THE STRUCTURE AND DOESN'T CALL A CONSTRUCTOR SO ANY CUSTOM FIELD +// WILL BE UNINITIALIZED. IF YOU ADD EXTRA FIELDS (SUCH AS A 'Z' COORDINATES) YOU WILL NEED TO CLEAR THEM DURING RENDER +// OR TO IGNORE THEM. IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT; #endif // [Internal] For use by ImDrawList struct ImDrawCmdHeader { - ImVec4 ClipRect; - ImTextureRef TexRef; - unsigned int VtxOffset; + ImVec4 ClipRect; + ImTextureRef TexRef; + unsigned int VtxOffset; }; // [Internal] For use by ImDrawListSplitter struct ImDrawChannel { - ImVector _CmdBuffer; - ImVector _IdxBuffer; + ImVector _CmdBuffer; + ImVector _IdxBuffer; }; // Split/Merge functions are used to split the draw list into different layers which can be drawn into out of order. // This is used by the Columns/Tables API, so items of each column can be batched together in a same draw call. struct ImDrawListSplitter { - int _Current; // Current channel number (0) - int _Count; // Number of active channels (1+) - ImVector _Channels; // Draw channels (not resized down so _Count might be < Channels.Size) + int _Current; // Current channel number (0) + int _Count; // Number of active channels (1+) + ImVector _Channels; // Draw channels (not resized down so _Count might be < Channels.Size) - inline ImDrawListSplitter() { memset(this, 0, sizeof(*this)); } - inline ~ImDrawListSplitter() { ClearFreeMemory(); } - inline void Clear() { _Current = 0; _Count = 1; } // Do not clear Channels[] so our allocations are reused next frame - IMGUI_API void ClearFreeMemory(); - IMGUI_API void Split(ImDrawList* draw_list, int count); - IMGUI_API void Merge(ImDrawList* draw_list); - IMGUI_API void SetCurrentChannel(ImDrawList* draw_list, int channel_idx); + inline ImDrawListSplitter() + { + memset(this, 0, sizeof(*this)); + } + inline ~ImDrawListSplitter() + { + ClearFreeMemory(); + } + inline void Clear() + { + _Current = 0; + _Count = 1; + } // Do not clear Channels[] so our allocations are reused next frame + IMGUI_API void ClearFreeMemory(); + IMGUI_API void Split(ImDrawList *draw_list, int count); + IMGUI_API void Merge(ImDrawList *draw_list); + IMGUI_API void SetCurrentChannel(ImDrawList *draw_list, int channel_idx); }; // 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) +// (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_ { - 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, + 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 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. +// 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_ { - ImDrawListFlags_None = 0, - ImDrawListFlags_AntiAliasedLines = 1 << 0, // Enable anti-aliased lines/borders (*2 the number of triangles for 1.0f wide line or lines thin enough to be drawn using textures, otherwise *3 the number of triangles) - ImDrawListFlags_AntiAliasedLinesUseTex = 1 << 1, // Enable anti-aliased lines/borders using textures when possible. Require backend to render with bilinear filtering (NOT point/nearest filtering). - ImDrawListFlags_AntiAliasedFill = 1 << 2, // Enable anti-aliased edge around filled shapes (rounded rectangles, circles). - ImDrawListFlags_AllowVtxOffset = 1 << 3, // Can emit 'VtxOffset > 0' to allow large meshes. Set when 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled. + ImDrawListFlags_None = 0, + ImDrawListFlags_AntiAliasedLines = + 1 << 0, // Enable anti-aliased lines/borders (*2 the number of triangles for 1.0f wide line or lines thin enough + // to be drawn using textures, otherwise *3 the number of triangles) + ImDrawListFlags_AntiAliasedLinesUseTex = + 1 << 1, // Enable anti-aliased lines/borders using textures when possible. Require backend to render with + // bilinear filtering (NOT point/nearest filtering). + ImDrawListFlags_AntiAliasedFill = + 1 << 2, // Enable anti-aliased edge around filled shapes (rounded rectangles, circles). + ImDrawListFlags_AllowVtxOffset = 1 << 3, // Can emit 'VtxOffset > 0' to allow large meshes. Set when + // 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled. }; // Draw command list @@ -3190,265 +5050,459 @@ enum ImDrawListFlags_ // Each dear imgui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to // access the current window draw list and draw custom primitives. // You can interleave normal ImGui:: calls and adding primitives to the current draw list. -// In single viewport mode, top-left is == GetMainViewport()->Pos (generally 0,0), bottom-right is == GetMainViewport()->Pos+Size (generally io.DisplaySize). -// You are totally free to apply whatever transformation matrix you want to the data (depending on the use of the transformation you may want to apply it to ClipRect as well!) -// Important: Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: functions), if you use this API a lot consider coarse culling your drawn objects. +// In single viewport mode, top-left is == GetMainViewport()->Pos (generally 0,0), bottom-right is == +// GetMainViewport()->Pos+Size (generally io.DisplaySize). You are totally free to apply whatever transformation matrix +// you want to the data (depending on the use of the transformation you may want to apply it to ClipRect as well!) +// Important: Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: +// functions), if you use this API a lot consider coarse culling your drawn objects. struct ImDrawList { // This is what you have to render - ImVector CmdBuffer; // Draw commands. Typically 1 command = 1 GPU draw call, unless the command is a callback. - ImVector IdxBuffer; // Index buffer. Each command consume ImDrawCmd::ElemCount of those - ImVector VtxBuffer; // Vertex buffer. - ImDrawListFlags Flags; // Flags, you may poke into these to adjust anti-aliasing settings per-primitive. + ImVector + CmdBuffer; // Draw commands. Typically 1 command = 1 GPU draw call, unless the command is a callback. + ImVector IdxBuffer; // Index buffer. Each command consume ImDrawCmd::ElemCount of those + ImVector VtxBuffer; // Vertex buffer. + ImDrawListFlags Flags; // Flags, you may poke into these to adjust anti-aliasing settings per-primitive. // [Internal, used while building lists] - unsigned int _VtxCurrentIdx; // [Internal] generally == VtxBuffer.Size unless we are past 64K vertices, in which case this gets reset to 0. - ImDrawListSharedData* _Data; // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context) - ImDrawVert* _VtxWritePtr; // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) - ImDrawIdx* _IdxWritePtr; // [Internal] point within IdxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) - ImVector _Path; // [Internal] current path building - ImDrawCmdHeader _CmdHeader; // [Internal] template of active commands. Fields should match those of CmdBuffer.back(). - ImDrawListSplitter _Splitter; // [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!) - ImVector _ClipRectStack; // [Internal] - ImVector _TextureStack; // [Internal] - ImVector _CallbacksDataBuf; // [Internal] - float _FringeScale; // [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while zooming at vertex buffer content - const char* _OwnerName; // Pointer to owner window's name for debugging + unsigned int _VtxCurrentIdx; // [Internal] generally == VtxBuffer.Size unless we are past 64K vertices, in which + // case this gets reset to 0. + ImDrawListSharedData *_Data; // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the + // one from current ImGui context) + ImDrawVert *_VtxWritePtr; // [Internal] point within VtxBuffer.Data after each add command (to avoid using the + // ImVector<> operators too much) + ImDrawIdx *_IdxWritePtr; // [Internal] point within IdxBuffer.Data after each add command (to avoid using the + // ImVector<> operators too much) + ImVector _Path; // [Internal] current path building + ImDrawCmdHeader + _CmdHeader; // [Internal] template of active commands. Fields should match those of CmdBuffer.back(). + ImDrawListSplitter _Splitter; // [Internal] for channels api (note: prefer using your own persistent instance of + // ImDrawListSplitter!) + ImVector _ClipRectStack; // [Internal] + ImVector _TextureStack; // [Internal] + ImVector _CallbacksDataBuf; // [Internal] + float _FringeScale; // [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while + // zooming at vertex buffer content + const char *_OwnerName; // Pointer to owner window's name for debugging // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData(). - // (advanced: you may create and use your own ImDrawListSharedData so you can use ImDrawList without ImGui, but that's more involved) - IMGUI_API ImDrawList(ImDrawListSharedData* shared_data); + // (advanced: you may create and use your own ImDrawListSharedData so you can use ImDrawList without ImGui, but + // that's more involved) + IMGUI_API ImDrawList(ImDrawListSharedData *shared_data); IMGUI_API ~ImDrawList(); - IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect = false); // 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) - IMGUI_API void PushClipRectFullScreen(); - IMGUI_API void PopClipRect(); - IMGUI_API void PushTexture(ImTextureRef tex_ref); - IMGUI_API void PopTexture(); - inline ImVec2 GetClipRectMin() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.x, cr.y); } - inline ImVec2 GetClipRectMax() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.z, cr.w); } + IMGUI_API void PushClipRect(const ImVec2 &clip_rect_min, const ImVec2 &clip_rect_max, + bool intersect_with_current_clip_rect = + false); // 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) + IMGUI_API void PushClipRectFullScreen(); + IMGUI_API void PopClipRect(); + IMGUI_API void PushTexture(ImTextureRef tex_ref); + IMGUI_API void PopTexture(); + inline ImVec2 GetClipRectMin() const + { + const ImVec4 &cr = _ClipRectStack.back(); + return ImVec2(cr.x, cr.y); + } + inline ImVec2 GetClipRectMax() const + { + const ImVec4 &cr = _ClipRectStack.back(); + return ImVec2(cr.z, cr.w); + } // Primitives - // - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing. + // - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. + // Counter-clockwise shapes will have "inward" anti-aliasing. // - For rectangular primitives, "p_min" and "p_max" represent the upper-left and lower-right corners. // - For circle primitives, use "num_segments == 0" to automatically calculate tessellation (preferred). // In older versions (until Dear ImGui 1.77) the AddCircle functions defaulted to num_segments == 12. // In future versions we will use textures to provide cheaper and higher-quality circles. // Use AddNgon() and AddNgonFilled() functions if you need to guarantee 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, 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); - IMGUI_API void AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness = 1.0f); - IMGUI_API void AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col); - IMGUI_API void AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments = 0, float thickness = 1.0f); - IMGUI_API void AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments = 0); - IMGUI_API void AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness = 1.0f); - IMGUI_API void AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments); - IMGUI_API void AddEllipse(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot = 0.0f, int num_segments = 0, float thickness = 1.0f); - IMGUI_API void AddEllipseFilled(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot = 0.0f, int num_segments = 0); - IMGUI_API void AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL); - IMGUI_API void AddText(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 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) + 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, + 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); + IMGUI_API void AddTriangle(const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddTriangleFilled(const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, ImU32 col); + IMGUI_API void AddCircle(const ImVec2 ¢er, float radius, ImU32 col, int num_segments = 0, + float thickness = 1.0f); + IMGUI_API void AddCircleFilled(const ImVec2 ¢er, float radius, ImU32 col, int num_segments = 0); + IMGUI_API void AddNgon(const ImVec2 ¢er, float radius, ImU32 col, int num_segments, float thickness = 1.0f); + IMGUI_API void AddNgonFilled(const ImVec2 ¢er, float radius, ImU32 col, int num_segments); + IMGUI_API void AddEllipse(const ImVec2 ¢er, const ImVec2 &radius, ImU32 col, float rot = 0.0f, + int num_segments = 0, float thickness = 1.0f); + IMGUI_API void AddEllipseFilled(const ImVec2 ¢er, const ImVec2 &radius, ImU32 col, float rot = 0.0f, + int num_segments = 0); + IMGUI_API void AddText(const ImVec2 &pos, ImU32 col, const char *text_begin, const char *text_end = NULL); + IMGUI_API void AddText(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 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) // General polygon // - Only simple polygons are supported by filling functions (no self-intersections, no holes). - // - Concave polygon fill is more expensive than convex one: it has O(N^2) complexity. Provided as a convenience for the user but not used by the main library. - 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); - IMGUI_API void AddConcavePolyFilled(const ImVec2* points, int num_points, ImU32 col); + // - Concave polygon fill is more expensive than convex one: it has O(N^2) complexity. Provided as a convenience for + // the user but not used by the main library. + 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); + IMGUI_API void AddConcavePolyFilled(const ImVec2 *points, int num_points, ImU32 col); // Image primitives // - Read FAQ to understand what ImTextureID/ImTextureRef are. // - "p_min" and "p_max" represent the upper-left and lower-right corners of the rectangle. - // - "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(ImTextureRef tex_ref, 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(ImTextureRef tex_ref, 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(ImTextureRef tex_ref, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags = 0); + // - "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(ImTextureRef tex_ref, 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(ImTextureRef tex_ref, 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(ImTextureRef tex_ref, 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() - // - Important: filled shapes must always use clockwise winding order! The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing. - // so e.g. 'PathArcTo(center, radius, PI * -0.5f, PI)' is ok, whereas 'PathArcTo(center, radius, PI, PI * -0.5f)' won't have correct anti-aliasing when followed by PathFillConvex(). - 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; } - inline void PathFillConcave(ImU32 col) { AddConcavePolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; } - 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 PathEllipticalArcTo(const ImVec2& center, const ImVec2& radius, float rot, float a_min, float a_max, int num_segments = 0); // Ellipse - 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, ImDrawFlags flags = 0); + // - Important: filled shapes must always use clockwise winding order! The anti-aliasing fringe depends on it. + // Counter-clockwise shapes will have "inward" anti-aliasing. + // so e.g. 'PathArcTo(center, radius, PI * -0.5f, PI)' is ok, whereas 'PathArcTo(center, radius, PI, PI * -0.5f)' + // won't have correct anti-aliasing when followed by PathFillConvex(). + 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; + } + inline void PathFillConcave(ImU32 col) + { + AddConcavePolyFilled(_Path.Data, _Path.Size, col); + _Path.Size = 0; + } + 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 ¢er, float radius, float a_min, float a_max, int num_segments = 0); + IMGUI_API void PathArcToFast(const ImVec2 ¢er, float radius, int a_min_of_12, + int a_max_of_12); // Use precomputed angles for a 12 steps circle + IMGUI_API void PathEllipticalArcTo(const ImVec2 ¢er, const ImVec2 &radius, float rot, float a_min, float a_max, + int num_segments = 0); // Ellipse + 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, + ImDrawFlags flags = 0); // Advanced: Draw Callbacks - // - May be used to alter render state (change sampler, blending, current shader). May be used to emit custom rendering commands (difficult to do correctly, but possible). - // - Use special ImDrawCallback_ResetRenderState callback to instruct backend to reset its render state to the default. - // - Your rendering loop must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles. All standard backends are honoring this. - // - For some backends, the callback may access selected render-states exposed by the backend in a ImGui_ImplXXXX_RenderState structure pointed to by platform_io.Renderer_RenderState. - // - IMPORTANT: please be mindful of the different level of indirection between using size==0 (copying argument) and using size>0 (copying pointed data into a buffer). - // - If userdata_size == 0: we copy/store the 'userdata' argument as-is. It will be available unmodified in ImDrawCmd::UserCallbackData during render. - // - If userdata_size > 0, we copy/store 'userdata_size' bytes pointed to by 'userdata'. We store them in a buffer stored inside the drawlist. ImDrawCmd::UserCallbackData will point inside that buffer so you have to retrieve data from there. Your callback may need to use ImDrawCmd::UserCallbackDataSize if you expect dynamically-sized data. - // - Support for userdata_size > 0 was added in v1.91.4, October 2024. So earlier code always only allowed to copy/store a simple void*. - IMGUI_API void AddCallback(ImDrawCallback callback, void* userdata, size_t userdata_size = 0); + // - May be used to alter render state (change sampler, blending, current shader). May be used to emit custom + // rendering commands (difficult to do correctly, but possible). + // - Use special ImDrawCallback_ResetRenderState callback to instruct backend to reset its render state to the + // default. + // - Your rendering loop must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering + // triangles. All standard backends are honoring this. + // - For some backends, the callback may access selected render-states exposed by the backend in a + // ImGui_ImplXXXX_RenderState structure pointed to by platform_io.Renderer_RenderState. + // - IMPORTANT: please be mindful of the different level of indirection between using size==0 (copying argument) and + // using size>0 (copying pointed data into a buffer). + // - If userdata_size == 0: we copy/store the 'userdata' argument as-is. It will be available unmodified in + // ImDrawCmd::UserCallbackData during render. + // - If userdata_size > 0, we copy/store 'userdata_size' bytes pointed to by 'userdata'. We store them in a + // buffer stored inside the drawlist. ImDrawCmd::UserCallbackData will point inside that buffer so you have to + // retrieve data from there. Your callback may need to use ImDrawCmd::UserCallbackDataSize if you expect + // dynamically-sized data. + // - Support for userdata_size > 0 was added in v1.91.4, October 2024. So earlier code always only allowed to + // copy/store a simple void*. + IMGUI_API void AddCallback(ImDrawCallback callback, void *userdata, size_t userdata_size = 0); // Advanced: Miscellaneous - IMGUI_API void AddDrawCmd(); // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible - IMGUI_API ImDrawList* CloneOutput() const; // Create a clone of the CmdBuffer/IdxBuffer/VtxBuffer. + IMGUI_API void AddDrawCmd(); // This is useful if you need to forcefully create a new draw call (to allow for + // dependent rendering / blending). Otherwise primitives are merged into the same + // draw-call as much as possible + IMGUI_API ImDrawList *CloneOutput() const; // Create a clone of the CmdBuffer/IdxBuffer/VtxBuffer. // Advanced: Channels - // - Use to split render into layers. By switching channels to can render out-of-order (e.g. submit FG primitives before BG primitives) - // - Use to minimize draw calls (e.g. if going back-and-forth between multiple clipping rectangles, prefer to append into separate channels then merge at the end) + // - Use to split render into layers. By switching channels to can render out-of-order (e.g. submit FG primitives + // before BG primitives) + // - Use to minimize draw calls (e.g. if going back-and-forth between multiple clipping rectangles, prefer to append + // into separate channels then merge at the end) // - This API shouldn't have been in ImDrawList in the first place! // Prefer using your own persistent instance of ImDrawListSplitter as you can stack them. // Using the ImDrawList::ChannelsXXXX you cannot stack a split over another. - inline void ChannelsSplit(int count) { _Splitter.Split(this, count); } - inline void ChannelsMerge() { _Splitter.Merge(this); } - inline void ChannelsSetCurrent(int n) { _Splitter.SetCurrentChannel(this, n); } + inline void ChannelsSplit(int count) + { + _Splitter.Split(this, count); + } + inline void ChannelsMerge() + { + _Splitter.Merge(this); + } + inline void ChannelsSetCurrent(int n) + { + _Splitter.SetCurrentChannel(this, n); + } // Advanced: Primitives allocations // - We render triangles (three vertices) // - All primitives needs to be reserved via PrimReserve() beforehand. - IMGUI_API void PrimReserve(int idx_count, int vtx_count); - IMGUI_API void PrimUnreserve(int idx_count, int vtx_count); - IMGUI_API void PrimRect(const ImVec2& a, const ImVec2& b, ImU32 col); // Axis aligned rectangle (composed of two triangles) - IMGUI_API void PrimRectUV(const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col); - IMGUI_API void PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col); - inline void PrimWriteVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { _VtxWritePtr->pos = pos; _VtxWritePtr->uv = uv; _VtxWritePtr->col = col; _VtxWritePtr++; _VtxCurrentIdx++; } - inline void PrimWriteIdx(ImDrawIdx idx) { *_IdxWritePtr = idx; _IdxWritePtr++; } - inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } // Write vertex with unique index + IMGUI_API void PrimReserve(int idx_count, int vtx_count); + IMGUI_API void PrimUnreserve(int idx_count, int vtx_count); + IMGUI_API void PrimRect(const ImVec2 &a, const ImVec2 &b, + ImU32 col); // Axis aligned rectangle (composed of two triangles) + IMGUI_API void PrimRectUV(const ImVec2 &a, const ImVec2 &b, const ImVec2 &uv_a, const ImVec2 &uv_b, ImU32 col); + IMGUI_API void PrimQuadUV(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &d, const ImVec2 &uv_a, + const ImVec2 &uv_b, const ImVec2 &uv_c, const ImVec2 &uv_d, ImU32 col); + inline void PrimWriteVtx(const ImVec2 &pos, const ImVec2 &uv, ImU32 col) + { + _VtxWritePtr->pos = pos; + _VtxWritePtr->uv = uv; + _VtxWritePtr->col = col; + _VtxWritePtr++; + _VtxCurrentIdx++; + } + inline void PrimWriteIdx(ImDrawIdx idx) + { + *_IdxWritePtr = idx; + _IdxWritePtr++; + } + inline void PrimVtx(const ImVec2 &pos, const ImVec2 &uv, ImU32 col) + { + PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); + PrimWriteVtx(pos, uv, col); + } // Write vertex with unique index // Obsolete names #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - IMGUI_API void PushTextureID(ImTextureRef tex_ref) { PushTexture(tex_ref); } // RENAMED in 1.92.x - IMGUI_API void PopTextureID() { PopTexture(); } // RENAMED in 1.92.x + IMGUI_API void PushTextureID(ImTextureRef tex_ref) + { + PushTexture(tex_ref); + } // RENAMED in 1.92.x + IMGUI_API void PopTextureID() + { + PopTexture(); + } // RENAMED in 1.92.x #endif - //inline void AddEllipse(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0, float thickness = 1.0f) { AddEllipse(center, ImVec2(radius_x, radius_y), col, rot, num_segments, thickness); } // OBSOLETED in 1.90.5 (Mar 2024) - //inline void AddEllipseFilled(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0) { AddEllipseFilled(center, ImVec2(radius_x, radius_y), col, rot, num_segments); } // OBSOLETED in 1.90.5 (Mar 2024) - //inline void PathEllipticalArcTo(const ImVec2& center, float radius_x, float radius_y, float rot, float a_min, float a_max, int num_segments = 0) { PathEllipticalArcTo(center, ImVec2(radius_x, radius_y), rot, a_min, a_max, num_segments); } // OBSOLETED in 1.90.5 (Mar 2024) - //inline void AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0) { AddBezierCubic(p1, p2, p3, p4, col, thickness, num_segments); } // OBSOLETED in 1.80 (Jan 2021) - //inline void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); } // OBSOLETED in 1.80 (Jan 2021) + // inline void AddEllipse(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int + // num_segments = 0, float thickness = 1.0f) { AddEllipse(center, ImVec2(radius_x, radius_y), col, rot, + // num_segments, thickness); } // OBSOLETED in 1.90.5 (Mar 2024) inline void AddEllipseFilled(const ImVec2& + // center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0) { + // AddEllipseFilled(center, ImVec2(radius_x, radius_y), col, rot, num_segments); } // + // OBSOLETED in 1.90.5 (Mar 2024) inline void PathEllipticalArcTo(const ImVec2& center, float radius_x, float + // radius_y, float rot, float a_min, float a_max, int num_segments = 0) { PathEllipticalArcTo(center, + // ImVec2(radius_x, radius_y), rot, a_min, a_max, num_segments); } // OBSOLETED in 1.90.5 (Mar 2024) inline void + // AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float + // thickness, int num_segments = 0) { AddBezierCubic(p1, p2, p3, p4, col, thickness, num_segments); } // OBSOLETED + // in 1.80 (Jan 2021) inline void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int + // num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); } // OBSOLETED in 1.80 (Jan 2021) // [Internal helpers] - IMGUI_API void _SetDrawListSharedData(ImDrawListSharedData* data); - IMGUI_API void _ResetForNewFrame(); - IMGUI_API void _ClearFreeMemory(); - IMGUI_API void _PopUnusedDrawCmd(); - IMGUI_API void _TryMergeDrawCmds(); - IMGUI_API void _OnChangedClipRect(); - IMGUI_API void _OnChangedTexture(); - IMGUI_API void _OnChangedVtxOffset(); - IMGUI_API void _SetTexture(ImTextureRef tex_ref); - 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); + IMGUI_API void _SetDrawListSharedData(ImDrawListSharedData *data); + IMGUI_API void _ResetForNewFrame(); + IMGUI_API void _ClearFreeMemory(); + IMGUI_API void _PopUnusedDrawCmd(); + IMGUI_API void _TryMergeDrawCmds(); + IMGUI_API void _OnChangedClipRect(); + IMGUI_API void _OnChangedTexture(); + IMGUI_API void _OnChangedVtxOffset(); + IMGUI_API void _SetTexture(ImTextureRef tex_ref); + IMGUI_API int _CalcCircleAutoSegmentCount(float radius) const; + IMGUI_API void _PathArcToFastEx(const ImVec2 ¢er, float radius, int a_min_sample, int a_max_sample, int a_step); + IMGUI_API void _PathArcToN(const ImVec2 ¢er, float radius, float a_min, float a_max, int num_segments); }; // All draw data to render a Dear ImGui frame -// (NB: the style and the naming convention here is a little inconsistent, we currently preserve them for backward compatibility purpose, -// as this is one of the oldest structure exposed by the library! Basically, ImDrawList == CmdList) +// (NB: the style and the naming convention here is a little inconsistent, we currently preserve them for backward +// compatibility purpose, as this is one of the oldest structure exposed by the library! Basically, ImDrawList == +// CmdList) struct ImDrawData { - bool Valid; // Only valid after Render() is called and before the next NewFrame() is called. - int CmdListsCount; // Number of ImDrawList* to render. (== CmdLists.Size). Exists for legacy reason. - int TotalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size - int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size - ImVector CmdLists; // Array of ImDrawList* to render. The ImDrawLists are owned by ImGuiContext and only pointed to from here. - ImVec2 DisplayPos; // Top-left position of the viewport to render (== top-left of the orthogonal projection matrix to use) (== GetMainViewport()->Pos for the main viewport, == (0.0) in most single-viewport applications) - ImVec2 DisplaySize; // Size of the viewport to render (== GetMainViewport()->Size for the main viewport, == io.DisplaySize in most single-viewport applications) - ImVec2 FramebufferScale; // Amount of pixels for each unit of DisplaySize. Copied from viewport->FramebufferScale (== io.DisplayFramebufferScale for main viewport). Generally (1,1) on normal display, (2,2) on OSX with Retina display. - ImGuiViewport* OwnerViewport; // Viewport carrying the ImDrawData instance, might be of use to the renderer (generally not). - ImVector* Textures; // List of textures to update. Most of the times the list is shared by all ImDrawData, has only 1 texture and it doesn't need any update. This almost always points to ImGui::GetPlatformIO().Textures[]. May be overriden or set to NULL if you want to manually update textures. + bool Valid; // Only valid after Render() is called and before the next NewFrame() is called. + int CmdListsCount; // Number of ImDrawList* to render. (== CmdLists.Size). Exists for legacy reason. + int TotalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size + int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size + ImVector CmdLists; // Array of ImDrawList* to render. The ImDrawLists are owned by ImGuiContext and + // only pointed to from here. + ImVec2 DisplayPos; // Top-left position of the viewport to render (== top-left of the orthogonal projection matrix + // to use) (== GetMainViewport()->Pos for the main viewport, == (0.0) in most single-viewport + // applications) + ImVec2 DisplaySize; // Size of the viewport to render (== GetMainViewport()->Size for the main viewport, == + // io.DisplaySize in most single-viewport applications) + ImVec2 FramebufferScale; // Amount of pixels for each unit of DisplaySize. Copied from viewport->FramebufferScale + // (== io.DisplayFramebufferScale for main viewport). Generally (1,1) on normal display, + // (2,2) on OSX with Retina display. + ImGuiViewport + *OwnerViewport; // Viewport carrying the ImDrawData instance, might be of use to the renderer (generally not). + ImVector *Textures; // List of textures to update. Most of the times the list is shared by all + // ImDrawData, has only 1 texture and it doesn't need any update. This almost + // always points to ImGui::GetPlatformIO().Textures[]. May be overriden or set + // to NULL if you want to manually update textures. // Functions - ImDrawData() { Clear(); } - IMGUI_API void Clear(); - IMGUI_API void AddDrawList(ImDrawList* draw_list); // Helper to add an external draw list into an existing ImDrawData. - IMGUI_API void DeIndexAllBuffers(); // Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! - IMGUI_API void ScaleClipRects(const ImVec2& fb_scale); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than Dear ImGui expects, or if there is a difference between your window resolution and framebuffer resolution. + ImDrawData() + { + Clear(); + } + IMGUI_API void Clear(); + IMGUI_API void AddDrawList( + ImDrawList *draw_list); // Helper to add an external draw list into an existing ImDrawData. + IMGUI_API void DeIndexAllBuffers(); // Helper to convert all buffers from indexed to non-indexed, in case you cannot + // render indexed. Note: this is slow and most likely a waste of resources. + // Always prefer indexed rendering! + IMGUI_API void ScaleClipRects( + const ImVec2 &fb_scale); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output + // buffer is at a different scale than Dear ImGui expects, or if there is a difference + // between your window resolution and framebuffer resolution. }; //----------------------------------------------------------------------------- // [SECTION] Texture API (ImTextureFormat, ImTextureStatus, ImTextureRect, ImTextureData) //----------------------------------------------------------------------------- // In principle, the only data types that user/application code should care about are 'ImTextureRef' and 'ImTextureID'. -// They are defined above in this header file. Read their description to the difference between ImTextureRef and ImTextureID. -// FOR ALL OTHER ImTextureXXXX TYPES: ONLY CORE LIBRARY AND RENDERER BACKENDS NEED TO KNOW AND CARE ABOUT THEM. +// They are defined above in this header file. Read their description to the difference between ImTextureRef and +// ImTextureID. FOR ALL OTHER ImTextureXXXX TYPES: ONLY CORE LIBRARY AND RENDERER BACKENDS NEED TO KNOW AND CARE ABOUT +// THEM. //----------------------------------------------------------------------------- // We intentionally support a limited amount of texture formats to limit burden on CPU-side code and extension. // Most standard backends only support RGBA32 but we provide a single channel option for low-resource/embedded systems. enum ImTextureFormat { - ImTextureFormat_RGBA32, // 4 components per pixel, each is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 - ImTextureFormat_Alpha8, // 1 component per pixel, each is unsigned 8-bit. Total size = TexWidth * TexHeight + ImTextureFormat_RGBA32, // 4 components per pixel, each is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 + ImTextureFormat_Alpha8, // 1 component per pixel, each is unsigned 8-bit. Total size = TexWidth * TexHeight }; // Status of a texture to communicate with Renderer Backend. enum ImTextureStatus { ImTextureStatus_OK, - ImTextureStatus_Destroyed, // Backend destroyed the texture. - ImTextureStatus_WantCreate, // Requesting backend to create the texture. Set status OK when done. - ImTextureStatus_WantUpdates, // Requesting backend to update specific blocks of pixels (write to texture portions which have never been used before). Set status OK when done. - ImTextureStatus_WantDestroy, // Requesting backend to destroy the texture. Set status to Destroyed when done. + ImTextureStatus_Destroyed, // Backend destroyed the texture. + ImTextureStatus_WantCreate, // Requesting backend to create the texture. Set status OK when done. + ImTextureStatus_WantUpdates, // Requesting backend to update specific blocks of pixels (write to texture portions + // which have never been used before). Set status OK when done. + ImTextureStatus_WantDestroy, // Requesting backend to destroy the texture. Set status to Destroyed when done. }; // Coordinates of a rectangle within a texture. -// When a texture is in ImTextureStatus_WantUpdates state, we provide a list of individual rectangles to copy to the graphics system. -// You may use ImTextureData::Updates[] for the list, or ImTextureData::UpdateBox for a single bounding box. +// When a texture is in ImTextureStatus_WantUpdates state, we provide a list of individual rectangles to copy to the +// graphics system. You may use ImTextureData::Updates[] for the list, or ImTextureData::UpdateBox for a single bounding +// box. struct ImTextureRect { - unsigned short x, y; // Upper-left coordinates of rectangle to update - unsigned short w, h; // Size of rectangle to update (in pixels) + unsigned short x, y; // Upper-left coordinates of rectangle to update + unsigned short w, h; // Size of rectangle to update (in pixels) }; // Specs and pixel storage for a texture used by Dear ImGui. // This is only useful for (1) core library and (2) backends. End-user/applications do not need to care about this. // Renderer Backends will create a GPU-side version of this. // Why does we store two identifiers: TexID and BackendUserData? -// - ImTextureID TexID = lower-level identifier stored in ImDrawCmd. ImDrawCmd can refer to textures not created by the backend, and for which there's no ImTextureData. -// - void* BackendUserData = higher-level opaque storage for backend own book-keeping. Some backends may have enough with TexID and not need both. - // In columns below: who reads/writes each fields? 'r'=read, 'w'=write, 'core'=main library, 'backend'=renderer backend +// - ImTextureID TexID = lower-level identifier stored in ImDrawCmd. ImDrawCmd can refer to textures not +// created by the backend, and for which there's no ImTextureData. +// - void* BackendUserData = higher-level opaque storage for backend own book-keeping. Some backends may have +// enough with TexID and not need both. In columns below: who reads/writes each fields? 'r'=read, 'w'=write, 'core'=main +// library, 'backend'=renderer backend struct ImTextureData { //------------------------------------------ core / backend --------------------------------------- - int UniqueID; // w - // Sequential index to facilitate identifying a texture when debugging/printing. Unique per atlas. - ImTextureStatus Status; // rw rw // ImTextureStatus_OK/_WantCreate/_WantUpdates/_WantDestroy. Always use SetStatus() to modify! - void* BackendUserData; // - rw // Convenience storage for backend. Some backends may have enough with TexID. - ImTextureID TexID; // r w // Backend-specific texture identifier. Always use SetTexID() to modify! The identifier will stored in ImDrawCmd::GetTexID() and passed to backend's RenderDrawData function. - ImTextureFormat Format; // w r // ImTextureFormat_RGBA32 (default) or ImTextureFormat_Alpha8 - int Width; // w r // Texture width - int Height; // w r // Texture height - int BytesPerPixel; // w r // 4 or 1 - unsigned char* Pixels; // w r // Pointer to buffer holding 'Width*Height' pixels and 'Width*Height*BytesPerPixels' bytes. - ImTextureRect UsedRect; // w r // Bounding box encompassing all past and queued Updates[]. - ImTextureRect UpdateRect; // w r // Bounding box encompassing all queued Updates[]. - ImVector Updates; // w r // Array of individual updates. - int UnusedFrames; // w r // In order to facilitate handling Status==WantDestroy in some backend: this is a count successive frames where the texture was not used. Always >0 when Status==WantDestroy. - unsigned short RefCount; // w r // Number of contexts using this texture. Used during backend shutdown. - bool UseColors; // w r // Tell whether our texture data is known to use colors (rather than just white + alpha). - bool WantDestroyNextFrame; // rw - // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still be used in the current frame. + int UniqueID; // w - // Sequential index to facilitate identifying a texture when debugging/printing. Unique + // per atlas. + ImTextureStatus Status; // rw rw // ImTextureStatus_OK/_WantCreate/_WantUpdates/_WantDestroy. Always use + // SetStatus() to modify! + void *BackendUserData; // - rw // Convenience storage for backend. Some backends may have enough with TexID. + ImTextureID + TexID; // r w // Backend-specific texture identifier. Always use SetTexID() to modify! The identifier will + // stored in ImDrawCmd::GetTexID() and passed to backend's RenderDrawData function. + ImTextureFormat Format; // w r // ImTextureFormat_RGBA32 (default) or ImTextureFormat_Alpha8 + int Width; // w r // Texture width + int Height; // w r // Texture height + int BytesPerPixel; // w r // 4 or 1 + unsigned char + *Pixels; // w r // Pointer to buffer holding 'Width*Height' pixels and 'Width*Height*BytesPerPixels' bytes. + ImTextureRect UsedRect; // w r // Bounding box encompassing all past and queued Updates[]. + ImTextureRect UpdateRect; // w r // Bounding box encompassing all queued Updates[]. + ImVector Updates; // w r // Array of individual updates. + int UnusedFrames; // w r // In order to facilitate handling Status==WantDestroy in some backend: this is a + // count successive frames where the texture was not used. Always >0 when Status==WantDestroy. + unsigned short RefCount; // w r // Number of contexts using this texture. Used during backend shutdown. + bool + UseColors; // w r // Tell whether our texture data is known to use colors (rather than just white + alpha). + bool WantDestroyNextFrame; // rw - // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still + // be used in the current frame. // Functions - ImTextureData() { memset(this, 0, sizeof(*this)); } - ~ImTextureData() { DestroyPixels(); } - IMGUI_API void Create(ImTextureFormat format, int w, int h); - IMGUI_API void DestroyPixels(); - unsigned char* GetPixels() { IM_ASSERT(Pixels != NULL); return Pixels; } - unsigned char* GetPixelsAt(int x, int y) { IM_ASSERT(Pixels != NULL); return Pixels + (x + y * Width) * BytesPerPixel; } - int GetSizeInBytes() const { return Width * Height * BytesPerPixel; } - int GetPitch() const { return Width * BytesPerPixel; } - ImTextureRef GetTexRef() { ImTextureRef tex_ref; tex_ref._TexData = this; tex_ref._TexID = ImTextureID_Invalid; return tex_ref; } - ImTextureID GetTexID() const { return TexID; } + ImTextureData() + { + memset(this, 0, sizeof(*this)); + } + ~ImTextureData() + { + DestroyPixels(); + } + IMGUI_API void Create(ImTextureFormat format, int w, int h); + IMGUI_API void DestroyPixels(); + unsigned char *GetPixels() + { + IM_ASSERT(Pixels != NULL); + return Pixels; + } + unsigned char *GetPixelsAt(int x, int y) + { + IM_ASSERT(Pixels != NULL); + return Pixels + (x + y * Width) * BytesPerPixel; + } + int GetSizeInBytes() const + { + return Width * Height * BytesPerPixel; + } + int GetPitch() const + { + return Width * BytesPerPixel; + } + ImTextureRef GetTexRef() + { + ImTextureRef tex_ref; + tex_ref._TexData = this; + tex_ref._TexID = ImTextureID_Invalid; + return tex_ref; + } + ImTextureID GetTexID() const + { + return TexID; + } // Called by Renderer backend - void SetTexID(ImTextureID tex_id) { TexID = tex_id; } // Call after creating or destroying the texture. Never modify TexID directly! - void SetStatus(ImTextureStatus status) { Status = status; } // Call after honoring a request. Never modify Status directly! + void SetTexID(ImTextureID tex_id) + { + TexID = tex_id; + } // Call after creating or destroying the texture. Never modify TexID directly! + void SetStatus(ImTextureStatus status) + { + Status = status; + } // Call after honoring a request. Never modify Status directly! }; //----------------------------------------------------------------------------- @@ -3459,71 +5513,132 @@ struct ImTextureData struct ImFontConfig { // Data Source - char Name[40]; // // Name (strictly to ease debugging, hence limited size buffer) - void* FontData; // // TTF/OTF data - int FontDataSize; // // TTF/OTF data size - bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself). + char Name[40]; // // Name (strictly to ease debugging, hence limited size buffer) + void *FontData; // // TTF/OTF data + int FontDataSize; // // TTF/OTF data size + bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete + // memory itself). // Options - bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. - bool PixelSnapH; // false // Align every glyph AdvanceX to pixel boundaries. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. - bool PixelSnapV; // true // Align Scaled GlyphOffset.y to pixel boundaries. - ImS8 FontNo; // 0 // Index of font within TTF/OTF file - ImS8 OversampleH; // 0 (2) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1 or 2 depending on size. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. - ImS8 OversampleV; // 0 (1) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not really useful as we don't use sub-pixel positions on the Y axis. - float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). - const ImWchar* GlyphRanges; // NULL // *LEGACY* THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). - const ImWchar* GlyphExcludeRanges; // NULL // Pointer to a VERY SHORT user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). This is very close to GlyphRanges[] but designed to exclude ranges from a font source, when merging fonts with overlapping glyphs. Use "Input Glyphs Overlap Detection Tool" to find about your overlapping ranges. - //ImVec2 GlyphExtraSpacing; // 0, 0 // (REMOVED AT IT SEEMS LARGELY OBSOLETE. PLEASE REPORT IF YOU WERE USING THIS). Extra spacing (in pixels) between glyphs when rendered: essentially add to glyph->AdvanceX. Only X axis is supported for now. - ImVec2 GlyphOffset; // 0, 0 // Offset (in pixels) all glyphs from this font input. Absolute value for default size, other sizes will scale this value. - float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font. Absolute value for default size, other sizes will scale this value. - float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs - float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this. // FIXME-NEWATLAS: Intentionally unscaled - unsigned int FontLoaderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. - //unsigned int FontBuilderFlags; // -- // [Renamed in 1.92] Ue FontLoaderFlags. - float RasterizerMultiply; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future. - float RasterizerDensity; // 1.0f // [LEGACY: this only makes sense when ImGuiBackendFlags_RendererHasTextures is not supported] DPI scale multiplier for rasterization. Not altering other font metrics: makes it easy to swap between e.g. a 100% and a 400% fonts for a zooming display, or handle Retina screen. IMPORTANT: If you change this it is expected that you increase/decrease font scale roughly to the inverse of this, otherwise quality may look lowered. - ImWchar EllipsisChar; // 0 // Explicitly specify Unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. + bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont + // (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of + // different heights. + bool PixelSnapH; // false // Align every glyph AdvanceX to pixel boundaries. Useful e.g. if you are merging a + // non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. + bool PixelSnapV; // true // Align Scaled GlyphOffset.y to pixel boundaries. + ImS8 FontNo; // 0 // Index of font within TTF/OTF file + ImS8 OversampleH; // 0 (2) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1 or 2 + // depending on size. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for + // large glyphs save memory. Read + // https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. + ImS8 OversampleV; // 0 (1) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not + // really useful as we don't use sub-pixel positions on the Y axis. + float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). + const ImWchar *GlyphRanges; // NULL // *LEGACY* THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. + // Pointer to a user-provided list of Unicode range (2 value per range, values are + // inclusive, zero-terminated list). + const ImWchar + *GlyphExcludeRanges; // NULL // Pointer to a VERY SHORT user-provided list of Unicode range (2 value per + // range, values are inclusive, zero-terminated list). This is very close to GlyphRanges[] + // but designed to exclude ranges from a font source, when merging fonts with overlapping + // glyphs. Use "Input Glyphs Overlap Detection Tool" to find about your overlapping ranges. + // ImVec2 GlyphExtraSpacing; // 0, 0 // (REMOVED AT IT SEEMS LARGELY OBSOLETE. PLEASE REPORT IF YOU + // WERE USING THIS). Extra spacing (in pixels) between glyphs when rendered: essentially add to glyph->AdvanceX. + // Only X axis is supported for now. + ImVec2 GlyphOffset; // 0, 0 // Offset (in pixels) all glyphs from this font input. Absolute value for default + // size, other sizes will scale this value. + float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to + // enforce mono-space font. Absolute value for default size, other sizes will scale this + // value. + float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs + float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are + // using this. // FIXME-NEWATLAS: Intentionally unscaled + unsigned int FontLoaderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION + // DEPENDENT. Leave as zero if unsure. + // unsigned int FontBuilderFlags; // -- // [Renamed in 1.92] Ue FontLoaderFlags. + float RasterizerMultiply; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small + // fonts may be a good workaround to make them more readable. This is a silly thing we may + // remove in the future. + float RasterizerDensity; // 1.0f // [LEGACY: this only makes sense when ImGuiBackendFlags_RendererHasTextures is + // not supported] DPI scale multiplier for rasterization. Not altering other font metrics: + // makes it easy to swap between e.g. a 100% and a 400% fonts for a zooming display, or + // handle Retina screen. IMPORTANT: If you change this it is expected that you + // increase/decrease font scale roughly to the inverse of this, otherwise quality may look + // lowered. + ImWchar EllipsisChar; // 0 // Explicitly specify Unicode codepoint of ellipsis character. When fonts are + // being merged first specified ellipsis will be used. // [Internal] - ImFontFlags Flags; // Font flags (don't use just yet, will be exposed in upcoming 1.92.X updates) - ImFont* DstFont; // Target font (as we merging fonts, multiple ImFontConfig may target the same font) - const ImFontLoader* FontLoader; // Custom font backend for this source (other use one stored in ImFontAtlas) - void* FontLoaderData; // Font loader opaque storage (per font config) + ImFontFlags Flags; // Font flags (don't use just yet, will be exposed in upcoming 1.92.X updates) + ImFont *DstFont; // Target font (as we merging fonts, multiple ImFontConfig may target the same font) + const ImFontLoader *FontLoader; // Custom font backend for this source (other use one stored in ImFontAtlas) + void *FontLoaderData; // Font loader opaque storage (per font config) IMGUI_API ImFontConfig(); }; // Hold rendering data for one glyph. -// (Note: some language parsers may fail to convert the bitfield members, in this case maybe drop store a single u32 or we can rework this) +// (Note: some language parsers may fail to convert the bitfield members, in this case maybe drop store a single u32 or +// we can rework this) struct ImFontGlyph { - unsigned int Colored : 1; // Flag to indicate glyph is colored and should generally ignore tinting (make it usable with no shift on little-endian as this is used in loops) - unsigned int Visible : 1; // Flag to indicate glyph has no visible pixels (e.g. space). Allow early out when rendering. - unsigned int SourceIdx : 4; // Index of source in parent font - unsigned int Codepoint : 26; // 0x0000..0x10FFFF - float AdvanceX; // Horizontal distance to advance cursor/layout position. - float X0, Y0, X1, Y1; // Glyph corners. Offsets from current cursor/layout position. - float U0, V0, U1, V1; // Texture coordinates for the current value of ImFontAtlas->TexRef. Cached equivalent of calling GetCustomRect() with PackId. - int PackId; // [Internal] ImFontAtlasRectId value (FIXME: Cold data, could be moved elsewhere?) + unsigned int Colored : 1; // Flag to indicate glyph is colored and should generally ignore tinting (make it usable + // with no shift on little-endian as this is used in loops) + unsigned int Visible + : 1; // Flag to indicate glyph has no visible pixels (e.g. space). Allow early out when rendering. + unsigned int SourceIdx : 4; // Index of source in parent font + unsigned int Codepoint : 26; // 0x0000..0x10FFFF + float AdvanceX; // Horizontal distance to advance cursor/layout position. + float X0, Y0, X1, Y1; // Glyph corners. Offsets from current cursor/layout position. + float U0, V0, U1, V1; // Texture coordinates for the current value of ImFontAtlas->TexRef. Cached equivalent of + // calling GetCustomRect() with PackId. + int PackId; // [Internal] ImFontAtlasRectId value (FIXME: Cold data, could be moved elsewhere?) - ImFontGlyph() { memset(this, 0, sizeof(*this)); PackId = -1; } + ImFontGlyph() + { + memset(this, 0, sizeof(*this)); + PackId = -1; + } }; -// Helper to build glyph ranges from text/string data. Feed your application strings/characters to it then call BuildRanges(). -// This is essentially a tightly packed of vector of 64k booleans = 8KB storage. +// Helper to build glyph ranges from text/string data. Feed your application strings/characters to it then call +// BuildRanges(). This is essentially a tightly packed of vector of 64k booleans = 8KB storage. struct ImFontGlyphRangesBuilder { - ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) + ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) - ImFontGlyphRangesBuilder() { Clear(); } - inline void Clear() { int size_in_bytes = (IM_UNICODE_CODEPOINT_MAX + 1) / 8; UsedChars.resize(size_in_bytes / (int)sizeof(ImU32)); memset(UsedChars.Data, 0, (size_t)size_in_bytes); } - inline bool GetBit(size_t n) const { int off = (int)(n >> 5); ImU32 mask = 1u << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array - inline void SetBit(size_t n) { int off = (int)(n >> 5); ImU32 mask = 1u << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array - inline void AddChar(ImWchar c) { SetBit(c); } // Add character - IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added) - IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext - IMGUI_API void BuildRanges(ImVector* out_ranges); // Output new ranges + ImFontGlyphRangesBuilder() + { + Clear(); + } + inline void Clear() + { + int size_in_bytes = (IM_UNICODE_CODEPOINT_MAX + 1) / 8; + UsedChars.resize(size_in_bytes / (int)sizeof(ImU32)); + memset(UsedChars.Data, 0, (size_t)size_in_bytes); + } + inline bool GetBit(size_t n) const + { + int off = (int)(n >> 5); + ImU32 mask = 1u << (n & 31); + return (UsedChars[off] & mask) != 0; + } // Get bit n in the array + inline void SetBit(size_t n) + { + int off = (int)(n >> 5); + ImU32 mask = 1u << (n & 31); + UsedChars[off] |= mask; + } // Set bit n in the array + inline void AddChar(ImWchar c) + { + SetBit(c); + } // Add character + IMGUI_API void AddText(const char *text, + const char *text_end = NULL); // Add string (each character of the UTF-8 string are added) + IMGUI_API void AddRanges( + const ImWchar *ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add + // all of ASCII/Latin+Ext + IMGUI_API void BuildRanges(ImVector *out_ranges); // Output new ranges }; // An opaque identifier to a rectangle in the atlas. -1 when invalid. @@ -3536,97 +5651,149 @@ typedef int ImFontAtlasRectId; // (this is in theory derived from ImTextureRect but we use separate structures for reasons) struct ImFontAtlasRect { - unsigned short x, y; // Position (in current texture) - unsigned short w, h; // Size - ImVec2 uv0, uv1; // UV coordinates (in current texture) + unsigned short x, y; // Position (in current texture) + unsigned short w, h; // Size + ImVec2 uv0, uv1; // UV coordinates (in current texture) - ImFontAtlasRect() { memset(this, 0, sizeof(*this)); } + ImFontAtlasRect() + { + memset(this, 0, sizeof(*this)); + } }; // Flags for ImFontAtlas build enum ImFontAtlasFlags_ { - ImFontAtlasFlags_None = 0, - ImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0, // Don't round the height to next power of two - ImFontAtlasFlags_NoMouseCursors = 1 << 1, // Don't build software mouse cursors into the atlas (save a little texture memory) - ImFontAtlasFlags_NoBakedLines = 1 << 2, // Don't build thick line textures into the atlas (save a little texture memory, allow support for point/nearest filtering). The AntiAliasedLinesUseTex features uses them, otherwise they will be rendered using polygons (more expensive for CPU/GPU). + ImFontAtlasFlags_None = 0, + ImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0, // Don't round the height to next power of two + ImFontAtlasFlags_NoMouseCursors = + 1 << 1, // Don't build software mouse cursors into the atlas (save a little texture memory) + ImFontAtlasFlags_NoBakedLines = + 1 << 2, // Don't build thick line textures into the atlas (save a little texture memory, allow support for + // point/nearest filtering). The AntiAliasedLinesUseTex features uses them, otherwise they will be + // rendered using polygons (more expensive for CPU/GPU). }; // Load and rasterize multiple TTF/OTF fonts into a same texture. The font atlas will build a single texture holding: // - One or more fonts. // - Custom graphics data needed to render the shapes needed by Dear ImGui. -// - Mouse cursor shapes for software cursor rendering (unless setting 'Flags |= ImFontAtlasFlags_NoMouseCursors' in the font atlas). +// - Mouse cursor shapes for software cursor rendering (unless setting 'Flags |= ImFontAtlasFlags_NoMouseCursors' in +// the font atlas). // - If you don't call any AddFont*** functions, the default font embedded in the code will be loaded for you. // It is the rendering backend responsibility to upload texture into your graphics API: -// - ImGui_ImplXXXX_RenderDrawData() functions generally iterate platform_io->Textures[] to create/update/destroy each ImTextureData instance. +// - ImGui_ImplXXXX_RenderDrawData() functions generally iterate platform_io->Textures[] to create/update/destroy each +// ImTextureData instance. // - Backend then set ImTextureData's TexID and BackendUserData. -// - Texture id are passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID/ImTextureRef for more details. +// - Texture id are passed back to you during rendering to identify the texture. Read FAQ entry about +// ImTextureID/ImTextureRef for more details. // Legacy path: // - Call Build() + GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data. -// - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API. +// - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics +// API. // Common pitfalls: -// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the +// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until +// the // atlas is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data. -// - Important: By default, AddFontFromMemoryTTF() takes ownership of the data. Even though we are not writing to it, we will free the pointer on destruction. +// - Important: By default, AddFontFromMemoryTTF() takes ownership of the data. Even though we are not writing to it, we +// will free the pointer on destruction. // You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed, // - Even though many functions are suffixed with "TTF", OTF data is supported just as well. -// - This is an old API and it is currently awkward for those and various other reasons! We will address them in the future! +// - This is an old API and it is currently awkward for those and various other reasons! We will address them in the +// future! struct ImFontAtlas { IMGUI_API ImFontAtlas(); IMGUI_API ~ImFontAtlas(); - IMGUI_API ImFont* AddFont(const ImFontConfig* font_cfg); - IMGUI_API ImFont* AddFontDefault(const ImFontConfig* font_cfg = NULL); - IMGUI_API ImFont* AddFontFromFileTTF(const char* filename, float size_pixels = 0.0f, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); - IMGUI_API ImFont* AddFontFromMemoryTTF(void* font_data, int font_data_size, float size_pixels = 0.0f, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted after destruction of the atlas. Set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed. - IMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_data_size, float size_pixels = 0.0f, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp. - IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels = 0.0f, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter. - IMGUI_API void RemoveFont(ImFont* font); + IMGUI_API ImFont *AddFont(const ImFontConfig *font_cfg); + IMGUI_API ImFont *AddFontDefault(const ImFontConfig *font_cfg = NULL); + IMGUI_API ImFont *AddFontFromFileTTF(const char *filename, float size_pixels = 0.0f, + const ImFontConfig *font_cfg = NULL, const ImWchar *glyph_ranges = NULL); + IMGUI_API ImFont *AddFontFromMemoryTTF( + void *font_data, int font_data_size, float size_pixels = 0.0f, const ImFontConfig *font_cfg = NULL, + const ImWchar *glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted + // after destruction of the atlas. Set font_cfg->FontDataOwnedByAtlas=false + // to keep ownership of your data and it won't be freed. + IMGUI_API ImFont *AddFontFromMemoryCompressedTTF( + const void *compressed_font_data, int compressed_font_data_size, float size_pixels = 0.0f, + const ImFontConfig *font_cfg = NULL, + const ImWchar *glyph_ranges = + NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp. + IMGUI_API ImFont *AddFontFromMemoryCompressedBase85TTF( + const char *compressed_font_data_base85, float size_pixels = 0.0f, const ImFontConfig *font_cfg = NULL, + const ImWchar *glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with + // binary_to_compressed_c.cpp with -base85 parameter. + IMGUI_API void RemoveFont(ImFont *font); - IMGUI_API void Clear(); // Clear everything (input fonts, output glyphs/textures) - IMGUI_API void CompactCache(); // Compact cached glyphs and texture. + IMGUI_API void Clear(); // Clear everything (input fonts, output glyphs/textures) + IMGUI_API void CompactCache(); // Compact cached glyphs and texture. // As we are transitioning toward a new font system, we expect to obsolete those soon: - IMGUI_API void ClearInputData(); // [OBSOLETE] Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. - IMGUI_API void ClearFonts(); // [OBSOLETE] Clear input+output font data (same as ClearInputData() + glyphs storage, UV coordinates). - IMGUI_API void ClearTexData(); // [OBSOLETE] Clear CPU-side copy of the texture data. Saves RAM once the texture has been copied to graphics memory. + IMGUI_API void ClearInputData(); // [OBSOLETE] Clear input data (all ImFontConfig structures including sizes, TTF + // data, glyph ranges, etc.) = all the data used to build the texture and fonts. + IMGUI_API void ClearFonts(); // [OBSOLETE] Clear input+output font data (same as ClearInputData() + glyphs storage, + // UV coordinates). + IMGUI_API void ClearTexData(); // [OBSOLETE] Clear CPU-side copy of the texture data. Saves RAM once the texture has + // been copied to graphics memory. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Legacy path for build atlas + retrieving pixel data. - // - User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). + // - User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then + // store your texture handle with SetTexID(). // - The pitch is always = Width * BytesPerPixels (1 or 4) - // - Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into - // the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste. + // - Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually + // manipulate or copy color data into + // the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% + // of memory/bandwidth waste. // - From 1.92 with backends supporting ImGuiBackendFlags_RendererHasTextures: // - Calling Build(), GetTexDataAsAlpha8(), GetTexDataAsRGBA32() is not needed. - // - In backend: replace calls to ImFontAtlas::SetTexID() with calls to ImTextureData::SetTexID() after honoring texture creation. - IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. - IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel - IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel - void SetTexID(ImTextureID id) { IM_ASSERT(TexRef._TexID == ImTextureID_Invalid); TexRef._TexData->TexID = id; } // Called by legacy backends. May be called before texture creation. - void SetTexID(ImTextureRef id) { IM_ASSERT(TexRef._TexID == ImTextureID_Invalid && id._TexData == NULL); TexRef._TexData->TexID = id._TexID; } // Called by legacy backends. - bool IsBuilt() const { return Fonts.Size > 0 && TexIsBuilt; } // Bit ambiguous: used to detect when user didn't build texture but effectively we should check TexID != 0 except that would be backend dependent.. + // - In backend: replace calls to ImFontAtlas::SetTexID() with calls to ImTextureData::SetTexID() after honoring + // texture creation. + IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. + IMGUI_API void GetTexDataAsAlpha8(unsigned char **out_pixels, int *out_width, int *out_height, + int *out_bytes_per_pixel = NULL); // 1 byte per-pixel + IMGUI_API void GetTexDataAsRGBA32(unsigned char **out_pixels, int *out_width, int *out_height, + int *out_bytes_per_pixel = NULL); // 4 bytes-per-pixel + void SetTexID(ImTextureID id) + { + IM_ASSERT(TexRef._TexID == ImTextureID_Invalid); + TexRef._TexData->TexID = id; + } // Called by legacy backends. May be called before texture creation. + void SetTexID(ImTextureRef id) + { + IM_ASSERT(TexRef._TexID == ImTextureID_Invalid && id._TexData == NULL); + TexRef._TexData->TexID = id._TexID; + } // Called by legacy backends. + bool IsBuilt() const + { + return Fonts.Size > 0 && TexIsBuilt; + } // Bit ambiguous: used to detect when user didn't build texture but effectively we should check TexID != 0 except + // that would be backend dependent.. #endif //------------------------------------------- // Glyph Ranges //------------------------------------------- - // Since 1.92: specifying glyph ranges is only useful/necessary if your backend doesn't support ImGuiBackendFlags_RendererHasTextures! - IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin + // Since 1.92: specifying glyph ranges is only useful/necessary if your backend doesn't support + // ImGuiBackendFlags_RendererHasTextures! + IMGUI_API const ImWchar *GetGlyphRangesDefault(); // Basic Latin, Extended Latin #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list) // NB: Make sure that your string are UTF-8 and NOT in your local code page. // Read https://github.com/ocornut/imgui/blob/master/docs/FONTS.md/#about-utf-8-encoding for details. // NB: Consider using ImFontGlyphRangesBuilder to build glyph ranges from textual data. - IMGUI_API const ImWchar* GetGlyphRangesGreek(); // Default + Greek and Coptic - IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters - IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 2999 Ideographs - IMGUI_API const ImWchar* GetGlyphRangesChineseFull(); // Default + Half-Width + Japanese Hiragana/Katakana + full set of about 21000 CJK Unified Ideographs - IMGUI_API const ImWchar* GetGlyphRangesChineseSimplifiedCommon();// Default + Half-Width + Japanese Hiragana/Katakana + set of 2500 CJK Unified Ideographs for common simplified Chinese - IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters - IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters - IMGUI_API const ImWchar* GetGlyphRangesVietnamese(); // Default + Vietnamese characters + IMGUI_API const ImWchar *GetGlyphRangesGreek(); // Default + Greek and Coptic + IMGUI_API const ImWchar *GetGlyphRangesKorean(); // Default + Korean characters + IMGUI_API const ImWchar *GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 2999 + // Ideographs + IMGUI_API const ImWchar *GetGlyphRangesChineseFull(); // Default + Half-Width + Japanese Hiragana/Katakana + full + // set of about 21000 CJK Unified Ideographs + IMGUI_API const ImWchar *GetGlyphRangesChineseSimplifiedCommon(); // Default + Half-Width + Japanese + // Hiragana/Katakana + set of 2500 CJK Unified + // Ideographs for common simplified Chinese + IMGUI_API const ImWchar *GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters + IMGUI_API const ImWchar *GetGlyphRangesThai(); // Default + Thai characters + IMGUI_API const ImWchar *GetGlyphRangesVietnamese(); // Default + Vietnamese characters #endif //------------------------------------------- @@ -3635,86 +5802,127 @@ struct ImFontAtlas // Register and retrieve custom rectangles // - You can request arbitrary rectangles to be packed into the atlas, for your own purpose. - // - Since 1.92.X, packing is done immediately in the function call (previously packing was done during the Build call) + // - Since 1.92.X, packing is done immediately in the function call (previously packing was done during the Build + // call) // - You can render your pixels into the texture right after calling the AddCustomRect() functions. // - VERY IMPORTANT: // - Texture may be created/resized at any time when calling ImGui or ImFontAtlas functions. // - IT WILL INVALIDATE RECTANGLE DATA SUCH AS UV COORDINATES. Always use latest values from GetCustomRect(). - // - UV coordinates are associated to the current texture identifier aka 'atlas->TexRef'. Both TexRef and UV coordinates are typically changed at the same time. - // - If you render colored output into your custom rectangles: set 'atlas->TexPixelsUseColors = true' as this may help some backends decide of preferred texture format. + // - UV coordinates are associated to the current texture identifier aka 'atlas->TexRef'. Both TexRef and UV + // coordinates are typically changed at the same time. + // - If you render colored output into your custom rectangles: set 'atlas->TexPixelsUseColors = true' as this may + // help some backends decide of preferred texture format. // - Read docs/FONTS.md for more details about using colorful icons. - // - Note: this API may be reworked further in order to facilitate supporting e.g. multi-monitor, varying DPI settings. + // - Note: this API may be reworked further in order to facilitate supporting e.g. multi-monitor, varying DPI + // settings. // - (Pre-1.92 names) ------------> (1.92 names) // - GetCustomRectByIndex() --> Use GetCustomRect() // - CalcCustomRectUV() --> Use GetCustomRect() and read uv0, uv1 fields. // - AddCustomRectRegular() --> Renamed to AddCustomRect() // - AddCustomRectFontGlyph() --> Prefer using custom ImFontLoader inside ImFontConfig // - ImFontAtlasCustomRect --> Renamed to ImFontAtlasRect - IMGUI_API ImFontAtlasRectId AddCustomRect(int width, int height, ImFontAtlasRect* out_r = NULL);// Register a rectangle. Return -1 (ImFontAtlasRectId_Invalid) on error. - IMGUI_API void RemoveCustomRect(ImFontAtlasRectId id); // Unregister a rectangle. Existing pixels will stay in texture until resized / garbage collected. - IMGUI_API bool GetCustomRect(ImFontAtlasRectId id, ImFontAtlasRect* out_r) const; // Get rectangle coordinates for current texture. Valid immediately, never store this (read above)! + IMGUI_API ImFontAtlasRectId AddCustomRect( + int width, int height, + ImFontAtlasRect *out_r = NULL); // Register a rectangle. Return -1 (ImFontAtlasRectId_Invalid) on error. + IMGUI_API void RemoveCustomRect(ImFontAtlasRectId id); // Unregister a rectangle. Existing pixels will stay in + // texture until resized / garbage collected. + IMGUI_API bool GetCustomRect(ImFontAtlasRectId id, ImFontAtlasRect *out_r) + const; // Get rectangle coordinates for current texture. Valid immediately, never store this (read above)! //------------------------------------------- // Members //------------------------------------------- // Input - ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) - ImTextureFormat TexDesiredFormat; // Desired texture format (default to ImTextureFormat_RGBA32 but may be changed to ImTextureFormat_Alpha8). - int TexGlyphPadding; // FIXME: Should be called "TexPackPadding". 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 (will also need to set AntiAliasedLinesUseTex = false). - int TexMinWidth; // Minimum desired texture width. Must be a power of two. Default to 512. - int TexMinHeight; // Minimum desired texture height. Must be a power of two. Default to 128. - int TexMaxWidth; // Maximum desired texture width. Must be a power of two. Default to 8192. - int TexMaxHeight; // Maximum desired texture height. Must be a power of two. Default to 8192. - void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas). + ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) + ImTextureFormat TexDesiredFormat; // Desired texture format (default to ImTextureFormat_RGBA32 but may be changed to + // ImTextureFormat_Alpha8). + int TexGlyphPadding; // FIXME: Should be called "TexPackPadding". 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 (will also need to set AntiAliasedLinesUseTex = false). + int TexMinWidth; // Minimum desired texture width. Must be a power of two. Default to 512. + int TexMinHeight; // Minimum desired texture height. Must be a power of two. Default to 128. + int TexMaxWidth; // Maximum desired texture width. Must be a power of two. Default to 8192. + int TexMaxHeight; // Maximum desired texture height. Must be a power of two. Default to 8192. + void *UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas). // Output - // - Because textures are dynamically created/resized, the current texture identifier may changed at *ANY TIME* during the frame. - // - This should not affect you as you can always use the latest value. But note that any precomputed UV coordinates are only valid for the current TexRef. + // - Because textures are dynamically created/resized, the current texture identifier may changed at *ANY TIME* + // during the frame. + // - This should not affect you as you can always use the latest value. But note that any precomputed UV coordinates + // are only valid for the current TexRef. #ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImTextureRef TexRef; // Latest texture identifier == TexData->GetTexRef(). + ImTextureRef TexRef; // Latest texture identifier == TexData->GetTexRef(). #else - union { ImTextureRef TexRef; ImTextureRef TexID; }; // Latest texture identifier == TexData->GetTexRef(). // RENAMED TexID to TexRef in 1.92.x + union { + ImTextureRef TexRef; + ImTextureRef TexID; + }; // Latest texture identifier == TexData->GetTexRef(). // RENAMED TexID to TexRef in 1.92.x #endif - ImTextureData* TexData; // Latest texture. + ImTextureData *TexData; // Latest texture. // [Internal] - ImVector TexList; // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). DO NOT USE DIRECTLY, USE GetDrawData().Textures[]/GetPlatformIO().Textures[] instead! - bool Locked; // Marked as locked during ImGui::NewFrame()..EndFrame() scope if TexUpdates are not supported. Any attempt to modify the atlas will assert. - bool RendererHasTextures;// Copy of (BackendFlags & ImGuiBackendFlags_RendererHasTextures) from supporting context. - bool TexIsBuilt; // Set when texture was built matching current font input. Mostly useful for legacy IsBuilt() call. - 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 or conversion process. - ImVec2 TexUvScale; // = (1.0f/TexData->TexWidth, 1.0f/TexData->TexHeight). May change as new texture gets created. - ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel. May change as new texture gets created. - ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. - ImVector Sources; // Source/configuration data - ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines - int TexNextUniqueID; // Next value to be stored in TexData->UniqueID - int FontNextUniqueID; // Next value to be stored in ImFont->FontID - ImVector DrawListSharedDatas; // List of users for this atlas. Typically one per Dear ImGui context. - ImFontAtlasBuilder* Builder; // Opaque interface to our data that doesn't need to be public and may be discarded when rebuilding. - const ImFontLoader* FontLoader; // Font loader opaque interface (default to stb_truetype, can be changed to use FreeType by defining IMGUI_ENABLE_FREETYPE). Don't set directly! - const char* FontLoaderName; // Font loader name (for display e.g. in About box) == FontLoader->Name - void* FontLoaderData; // Font backend opaque storage - unsigned int FontLoaderFlags; // Shared flags (for all fonts) for font loader. THIS IS BUILD IMPLEMENTATION DEPENDENT (e.g. Per-font override is also available in ImFontConfig). - int RefCount; // Number of contexts using this atlas - ImGuiContext* OwnerContext; // Context which own the atlas will be in charge of updating and destroying it. + ImVector + TexList; // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). DO NOT USE + // DIRECTLY, USE GetDrawData().Textures[]/GetPlatformIO().Textures[] instead! + bool Locked; // Marked as locked during ImGui::NewFrame()..EndFrame() scope if TexUpdates are not supported. Any + // attempt to modify the atlas will assert. + bool RendererHasTextures; // Copy of (BackendFlags & ImGuiBackendFlags_RendererHasTextures) from supporting context. + bool TexIsBuilt; // Set when texture was built matching current font input. Mostly useful for legacy IsBuilt() call. + 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 or conversion process. + ImVec2 TexUvScale; // = (1.0f/TexData->TexWidth, 1.0f/TexData->TexHeight). May change as new texture gets created. + ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel. May change as new texture gets created. + ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling + // ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. + ImVector Sources; // Source/configuration data + ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines + int TexNextUniqueID; // Next value to be stored in TexData->UniqueID + int FontNextUniqueID; // Next value to be stored in ImFont->FontID + ImVector + DrawListSharedDatas; // List of users for this atlas. Typically one per Dear ImGui context. + ImFontAtlasBuilder + *Builder; // Opaque interface to our data that doesn't need to be public and may be discarded when rebuilding. + const ImFontLoader *FontLoader; // Font loader opaque interface (default to stb_truetype, can be changed to use + // FreeType by defining IMGUI_ENABLE_FREETYPE). Don't set directly! + const char *FontLoaderName; // Font loader name (for display e.g. in About box) == FontLoader->Name + void *FontLoaderData; // Font backend opaque storage + unsigned int FontLoaderFlags; // Shared flags (for all fonts) for font loader. THIS IS BUILD IMPLEMENTATION + // DEPENDENT (e.g. Per-font override is also available in ImFontConfig). + int RefCount; // Number of contexts using this atlas + ImGuiContext *OwnerContext; // Context which own the atlas will be in charge of updating and destroying it. // [Obsolete] #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - // Legacy: You can 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. --> Prefer using a custom ImFontLoader. - ImFontAtlasRect TempRect; // For old GetCustomRectByIndex() API - inline ImFontAtlasRectId AddCustomRectRegular(int w, int h) { return AddCustomRect(w, h); } // RENAMED in 1.92.X - inline const ImFontAtlasRect* GetCustomRectByIndex(ImFontAtlasRectId id) { return GetCustomRect(id, &TempRect) ? &TempRect : NULL; } // OBSOLETED in 1.92.X - inline void CalcCustomRectUV(const ImFontAtlasRect* r, ImVec2* out_uv_min, ImVec2* out_uv_max) const { *out_uv_min = r->uv0; *out_uv_max = r->uv1; } // OBSOLETED in 1.92.X - IMGUI_API ImFontAtlasRectId AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int w, int h, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // OBSOLETED in 1.92.X: Use custom ImFontLoader in ImFontConfig - IMGUI_API ImFontAtlasRectId AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int w, int h, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // ADDED AND OBSOLETED in 1.92.X + // Legacy: You can 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. --> Prefer using a custom ImFontLoader. + ImFontAtlasRect TempRect; // For old GetCustomRectByIndex() API + inline ImFontAtlasRectId AddCustomRectRegular(int w, int h) + { + return AddCustomRect(w, h); + } // RENAMED in 1.92.X + inline const ImFontAtlasRect *GetCustomRectByIndex(ImFontAtlasRectId id) + { + return GetCustomRect(id, &TempRect) ? &TempRect : NULL; + } // OBSOLETED in 1.92.X + inline void CalcCustomRectUV(const ImFontAtlasRect *r, ImVec2 *out_uv_min, ImVec2 *out_uv_max) const + { + *out_uv_min = r->uv0; + *out_uv_max = r->uv1; + } // OBSOLETED in 1.92.X + IMGUI_API ImFontAtlasRectId AddCustomRectFontGlyph( + ImFont *font, ImWchar codepoint, int w, int h, float advance_x, + const ImVec2 &offset = ImVec2(0, 0)); // OBSOLETED in 1.92.X: Use custom ImFontLoader in ImFontConfig + IMGUI_API ImFontAtlasRectId + AddCustomRectFontGlyphForSize(ImFont *font, float font_size, ImWchar codepoint, int w, int h, float advance_x, + const ImVec2 &offset = ImVec2(0, 0)); // ADDED AND OBSOLETED in 1.92.X #endif - //unsigned int FontBuilderFlags; // OBSOLETED in 1.92.X: Renamed to FontLoaderFlags. - //int TexDesiredWidth; // OBSOLETED in 1.92.X: Force texture width before calling 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) - //typedef ImFontAtlasRect ImFontAtlasCustomRect; // OBSOLETED in 1.92.X - //typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ - //typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ + // unsigned int FontBuilderFlags; // OBSOLETED in 1.92.X: Renamed to FontLoaderFlags. + // int TexDesiredWidth; // OBSOLETED in 1.92.X: Force texture width before + // calling 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) typedef ImFontAtlasRect ImFontAtlasCustomRect; + // // OBSOLETED in 1.92.X typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ typedef + // ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ }; // Font runtime data for a given size @@ -3722,96 +5930,129 @@ struct ImFontAtlas struct ImFontBaked { // [Internal] Members: Hot ~20/24 bytes (for CalcTextSize) - ImVector IndexAdvanceX; // 12-16 // out // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this info, and are often bottleneck in large UI). - float FallbackAdvanceX; // 4 // out // FindGlyph(FallbackChar)->AdvanceX - float Size; // 4 // in // Height of characters/line, set during loading (doesn't change after loading) - float RasterizerDensity; // 4 // in // Density this is baked at + ImVector + IndexAdvanceX; // 12-16 // out // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for + // CalcTextSize functions which only this info, and are often bottleneck in large UI). + float FallbackAdvanceX; // 4 // out // FindGlyph(FallbackChar)->AdvanceX + float Size; // 4 // in // Height of characters/line, set during loading (doesn't change after loading) + float RasterizerDensity; // 4 // in // Density this is baked at // [Internal] Members: Hot ~28/36 bytes (for RenderText loop) - ImVector IndexLookup; // 12-16 // out // Sparse. Index glyphs by Unicode code-point. - ImVector Glyphs; // 12-16 // out // All glyphs. - int FallbackGlyphIndex; // 4 // out // Index of FontFallbackChar + ImVector IndexLookup; // 12-16 // out // Sparse. Index glyphs by Unicode code-point. + ImVector Glyphs; // 12-16 // out // All glyphs. + int FallbackGlyphIndex; // 4 // out // Index of FontFallbackChar // [Internal] Members: Cold - float Ascent, Descent; // 4+4 // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled) - unsigned int MetricsTotalSurface:26;// 3 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) - unsigned int WantDestroy:1; // 0 // // Queued for destroy - unsigned int LockLoadingFallback:1; // 0 // // - int LastUsedFrame; // 4 // // Record of that time this was bounds - ImGuiID BakedId; // 4 // - ImFont* ContainerFont; // 4-8 // in // Parent font - void* FontLoaderDatas; // 4-8 // // Font loader opaque storage (per baked font * sources): single contiguous buffer allocated by imgui, passed to loader. + float Ascent, Descent; // 4+4 // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled) + unsigned int MetricsTotalSurface + : 26; // 3 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, + // we approximate the cost of padding between glyphs) + unsigned int WantDestroy : 1; // 0 // // Queued for destroy + unsigned int LockLoadingFallback : 1; // 0 // // + int LastUsedFrame; // 4 // // Record of that time this was bounds + ImGuiID BakedId; // 4 // + ImFont *ContainerFont; // 4-8 // in // Parent font + void *FontLoaderDatas; // 4-8 // // Font loader opaque storage (per baked font * sources): single contiguous + // buffer allocated by imgui, passed to loader. // Functions IMGUI_API ImFontBaked(); - IMGUI_API void ClearOutputData(); - IMGUI_API ImFontGlyph* FindGlyph(ImWchar c); // Return U+FFFD glyph if requested glyph doesn't exists. - IMGUI_API ImFontGlyph* FindGlyphNoFallback(ImWchar c); // Return NULL if glyph doesn't exist - IMGUI_API float GetCharAdvance(ImWchar c); - IMGUI_API bool IsGlyphLoaded(ImWchar c); + IMGUI_API void ClearOutputData(); + IMGUI_API ImFontGlyph *FindGlyph(ImWchar c); // Return U+FFFD glyph if requested glyph doesn't exists. + IMGUI_API ImFontGlyph *FindGlyphNoFallback(ImWchar c); // Return NULL if glyph doesn't exist + IMGUI_API float GetCharAdvance(ImWchar c); + IMGUI_API bool IsGlyphLoaded(ImWchar c); }; // Font flags -// (in future versions as we redesign font loading API, this will become more important and better documented. for now please consider this as internal/advanced use) +// (in future versions as we redesign font loading API, this will become more important and better documented. for now +// please consider this as internal/advanced use) enum ImFontFlags_ { - ImFontFlags_None = 0, - ImFontFlags_DefaultToLegacySize = 1 << 0, // Legacy compatibility: make PushFont() calls without explicit size use font->LegacySize instead of current font size. - ImFontFlags_NoLoadError = 1 << 1, // Disable throwing an error/assert when calling AddFontXXX() with missing file/data. Calling code is expected to check AddFontXXX() return value. - ImFontFlags_NoLoadGlyphs = 1 << 2, // [Internal] Disable loading new glyphs. - ImFontFlags_LockBakedSizes = 1 << 3, // [Internal] Disable loading new baked sizes, disable garbage collecting current ones. e.g. if you want to lock a font to a single size. Important: if you use this to preload given sizes, consider the possibility of multiple font density used on Retina display. + ImFontFlags_None = 0, + ImFontFlags_DefaultToLegacySize = 1 << 0, // Legacy compatibility: make PushFont() calls without explicit size use + // font->LegacySize instead of current font size. + ImFontFlags_NoLoadError = 1 << 1, // Disable throwing an error/assert when calling AddFontXXX() with missing + // file/data. Calling code is expected to check AddFontXXX() return value. + ImFontFlags_NoLoadGlyphs = 1 << 2, // [Internal] Disable loading new glyphs. + ImFontFlags_LockBakedSizes = + 1 << 3, // [Internal] Disable loading new baked sizes, disable garbage collecting current ones. e.g. if you want + // to lock a font to a single size. Important: if you use this to preload given sizes, consider the + // possibility of multiple font density used on Retina display. }; // Font runtime data and rendering // - ImFontAtlas automatically loads a default embedded font for you if you didn't load one manually. // - Since 1.92.X a font may be rendered as any size! Therefore a font doesn't have one specific size. // - Use 'font->GetFontBaked(size)' to retrieve the ImFontBaked* corresponding to a given size. -// - If you used g.Font + g.FontSize (which is frequent from the ImGui layer), you can use g.FontBaked as a shortcut, as g.FontBaked == g.Font->GetFontBaked(g.FontSize). +// - If you used g.Font + g.FontSize (which is frequent from the ImGui layer), you can use g.FontBaked as a shortcut, as +// g.FontBaked == g.Font->GetFontBaked(g.FontSize). struct ImFont { // [Internal] Members: Hot ~12-20 bytes - ImFontBaked* LastBaked; // 4-8 // Cache last bound baked. NEVER USE DIRECTLY. Use GetFontBaked(). - ImFontAtlas* ContainerAtlas; // 4-8 // What we have been loaded into. - ImFontFlags Flags; // 4 // Font flags. - float CurrentRasterizerDensity; // Current rasterizer density. This is a varying state of the font. + ImFontBaked *LastBaked; // 4-8 // Cache last bound baked. NEVER USE DIRECTLY. Use GetFontBaked(). + ImFontAtlas *ContainerAtlas; // 4-8 // What we have been loaded into. + ImFontFlags Flags; // 4 // Font flags. + float CurrentRasterizerDensity; // Current rasterizer density. This is a varying state of the font. // [Internal] Members: Cold ~24-52 bytes // Conceptually Sources[] is the list of font sources merged to create this font. - ImGuiID FontId; // Unique identifier for the font - float LegacySize; // 4 // in // Font size passed to AddFont(). Use for old code calling PushFont() expecting to use that size. (use ImGui::GetFontBaked() to get font baked at current bound size). - ImVector Sources; // 16 // in // List of sources. Pointers within ContainerAtlas->Sources[] - ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...'). - ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') - ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. - bool EllipsisAutoBake; // 1 // // Mark when the "..." glyph needs to be generated. - ImGuiStorage RemapPairs; // 16 // // Remapping pairs when using AddRemapChar(), otherwise empty. + ImGuiID FontId; // Unique identifier for the font + float LegacySize; // 4 // in // Font size passed to AddFont(). Use for old code calling PushFont() expecting to + // use that size. (use ImGui::GetFontBaked() to get font baked at current bound size). + ImVector Sources; // 16 // in // List of sources. Pointers within ContainerAtlas->Sources[] + ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...'). + ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') + ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX + 1) / 8192 / + 8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block + // of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations + // across all used codepoints. + bool EllipsisAutoBake; // 1 // // Mark when the "..." glyph needs to be generated. + ImGuiStorage RemapPairs; // 16 // // Remapping pairs when using AddRemapChar(), otherwise empty. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - float Scale; // 4 // in // Legacy base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() + float Scale; // 4 // in // Legacy base font scale (~1.0f), multiplied by the per-window font scale which you + // can adjust with SetWindowFontScale() #endif // Methods IMGUI_API ImFont(); IMGUI_API ~ImFont(); - IMGUI_API bool IsGlyphInFont(ImWchar c); - bool IsLoaded() const { return ContainerAtlas != NULL; } - const char* GetDebugName() const { return Sources.Size ? Sources[0]->Name : ""; } // Fill ImFontConfig::Name. + IMGUI_API bool IsGlyphInFont(ImWchar c); + bool IsLoaded() const + { + return ContainerAtlas != NULL; + } + const char *GetDebugName() const + { + return Sources.Size ? Sources[0]->Name : ""; + } // Fill ImFontConfig::Name. // [Internal] Don't use! // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. - IMGUI_API ImFontBaked* GetFontBaked(float font_size, float density = -1.0f); // Get or create baked data for given size - IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL); // utf8 - IMGUI_API const char* CalcWordWrapPosition(float size, const char* text, const char* text_end, float wrap_width); - IMGUI_API void RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c, const ImVec4* cpu_fine_clip = NULL); - IMGUI_API void RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false); + IMGUI_API ImFontBaked *GetFontBaked(float font_size, + float density = -1.0f); // Get or create baked data for given size + IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char *text_begin, + const char *text_end = NULL, const char **remaining = NULL); // utf8 + IMGUI_API const char *CalcWordWrapPosition(float size, const char *text, const char *text_end, float wrap_width); + IMGUI_API void RenderChar(ImDrawList *draw_list, float size, const ImVec2 &pos, ImU32 col, ImWchar c, + const ImVec4 *cpu_fine_clip = NULL); + IMGUI_API void RenderText(ImDrawList *draw_list, float size, const ImVec2 &pos, ImU32 col, const ImVec4 &clip_rect, + const char *text_begin, const char *text_end, float wrap_width = 0.0f, + bool cpu_fine_clip = false); #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - inline const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) { return CalcWordWrapPosition(LegacySize * scale, text, text_end, wrap_width); } + inline const char *CalcWordWrapPositionA(float scale, const char *text, const char *text_end, float wrap_width) + { + return CalcWordWrapPosition(LegacySize * scale, text, text_end, wrap_width); + } #endif // [Internal] Don't use! - IMGUI_API void ClearOutputData(); - IMGUI_API void AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint); // Makes 'from_codepoint' character points to 'to_codepoint' glyph. - IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); + IMGUI_API void ClearOutputData(); + IMGUI_API void AddRemapChar( + ImWchar from_codepoint, + ImWchar to_codepoint); // Makes 'from_codepoint' character points to 'to_codepoint' glyph. + IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); }; // This is provided for consistency (but we don't actually use this) @@ -3821,14 +6062,17 @@ inline ImTextureID ImTextureRef::GetTexID() const return _TexData ? _TexData->TexID : _TexID; } -// Using an indirection to avoid patching ImDrawCmd after a SetTexID() call (but this could be an alternative solution too) +// Using an indirection to avoid patching ImDrawCmd after a SetTexID() call (but this could be an alternative solution +// too) inline ImTextureID ImDrawCmd::GetTexID() const { // If you are getting this assert: A renderer backend with support for ImGuiBackendFlags_RendererHasTextures (1.92) // must iterate and handle ImTextureData requests stored in ImDrawData::Textures[]. ImTextureID tex_id = TexRef._TexData ? TexRef._TexData->TexID : TexRef._TexID; // == TexRef.GetTexID() above. if (TexRef._TexData != NULL) - IM_ASSERT(tex_id != ImTextureID_Invalid && "ImDrawCmd is referring to ImTextureData that wasn't uploaded to graphics system. Backend must call ImTextureData::SetTexID() after handling ImTextureStatus_WantCreate request!"); + IM_ASSERT(tex_id != ImTextureID_Invalid && + "ImDrawCmd is referring to ImTextureData that wasn't uploaded to graphics system. Backend must call " + "ImTextureData::SetTexID() after handling ImTextureStatus_WantCreate request!"); return tex_id; } @@ -3839,38 +6083,53 @@ inline ImTextureID ImDrawCmd::GetTexID() const // Flags stored in ImGuiViewport::Flags, giving indications to the platform backends. enum ImGuiViewportFlags_ { - ImGuiViewportFlags_None = 0, - ImGuiViewportFlags_IsPlatformWindow = 1 << 0, // Represent a Platform Window - ImGuiViewportFlags_IsPlatformMonitor = 1 << 1, // Represent a Platform Monitor (unused yet) - ImGuiViewportFlags_OwnedByApp = 1 << 2, // Platform Window: Is created/managed by the application (rather than a dear imgui backend) + ImGuiViewportFlags_None = 0, + ImGuiViewportFlags_IsPlatformWindow = 1 << 0, // Represent a Platform Window + ImGuiViewportFlags_IsPlatformMonitor = 1 << 1, // Represent a Platform Monitor (unused yet) + ImGuiViewportFlags_OwnedByApp = + 1 << 2, // Platform Window: Is created/managed by the application (rather than a dear imgui backend) }; // - 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. +// - In the future we will extend this concept further to also represent Platform Monitor and support a "no main +// platform window" operation mode. // - About Main Area vs Work Area: // - Main Area = entire viewport. -// - Work Area = entire viewport minus sections used by main menu bars (for platform windows), or by task bar (for platform monitor). +// - Work Area = entire viewport minus sections used by main menu bars (for platform windows), or by task bar (for +// platform monitor). // - Windows are generally trying to stay within the Work Area of their host viewport. struct ImGuiViewport { - ImGuiID ID; // Unique identifier for the viewport - ImGuiViewportFlags Flags; // See ImGuiViewportFlags_ - 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 FramebufferScale; // Density of the viewport for Retina display (always 1,1 on Windows, may be 2,2 etc on macOS/iOS). This will affect font rasterizer density. - 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) + ImGuiID ID; // Unique identifier for the viewport + ImGuiViewportFlags Flags; // See ImGuiViewportFlags_ + 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 FramebufferScale; // Density of the viewport for Retina display (always 1,1 on Windows, may be 2,2 etc on + // macOS/iOS). This will affect font rasterizer density. + 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) // Platform/Backend Dependent Data - void* PlatformHandle; // void* to hold higher-level, platform window handle (e.g. HWND, GLFWWindow*, SDL_Window*) - void* PlatformHandleRaw; // void* to hold lower-level, platform-native window handle (under Win32 this is expected to be a HWND, unused for other platforms) + void *PlatformHandle; // void* to hold higher-level, platform window handle (e.g. HWND, GLFWWindow*, SDL_Window*) + void *PlatformHandleRaw; // void* to hold lower-level, platform-native window handle (under Win32 this is expected + // to be a HWND, unused for other platforms) - ImGuiViewport() { memset(this, 0, sizeof(*this)); } + ImGuiViewport() + { + memset(this, 0, sizeof(*this)); + } // Helpers - ImVec2 GetCenter() const { return ImVec2(Pos.x + Size.x * 0.5f, Pos.y + Size.y * 0.5f); } - ImVec2 GetWorkCenter() const { return ImVec2(WorkPos.x + WorkSize.x * 0.5f, WorkPos.y + WorkSize.y * 0.5f); } + ImVec2 GetCenter() const + { + return ImVec2(Pos.x + Size.x * 0.5f, Pos.y + Size.y * 0.5f); + } + ImVec2 GetWorkCenter() const + { + return ImVec2(WorkPos.x + WorkSize.x * 0.5f, WorkPos.y + WorkSize.y * 0.5f); + } }; //----------------------------------------------------------------------------- @@ -3887,199 +6146,307 @@ struct ImGuiPlatformIO //------------------------------------------------------------------ // Optional: Access OS clipboard - // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures) - const char* (*Platform_GetClipboardTextFn)(ImGuiContext* ctx); - void (*Platform_SetClipboardTextFn)(ImGuiContext* ctx, const char* text); - void* Platform_ClipboardUserData; + // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS + // clipboard on other architectures) + const char *(*Platform_GetClipboardTextFn)(ImGuiContext *ctx); + void (*Platform_SetClipboardTextFn)(ImGuiContext *ctx, const char *text); + void *Platform_ClipboardUserData; // Optional: Open link/folder/file in OS Shell // (default to use ShellExecuteW() on Windows, system() on Linux/Mac) - bool (*Platform_OpenInShellFn)(ImGuiContext* ctx, const char* path); - void* Platform_OpenInShellUserData; + bool (*Platform_OpenInShellFn)(ImGuiContext *ctx, const char *path); + void *Platform_OpenInShellUserData; - // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows) - // (default to use native imm32 api on Windows) - void (*Platform_SetImeDataFn)(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); - void* Platform_ImeUserData; - //void (*SetPlatformImeDataFn)(ImGuiViewport* viewport, ImGuiPlatformImeData* data); // [Renamed to platform_io.PlatformSetImeDataFn in 1.91.1] + // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when + // using Japanese/Chinese IME on Windows) (default to use native imm32 api on Windows) + void (*Platform_SetImeDataFn)(ImGuiContext *ctx, ImGuiViewport *viewport, ImGuiPlatformImeData *data); + void *Platform_ImeUserData; + // void (*SetPlatformImeDataFn)(ImGuiViewport* viewport, ImGuiPlatformImeData* data); // [Renamed to + // platform_io.PlatformSetImeDataFn in 1.91.1] // Optional: Platform locale - // [Experimental] Configure decimal point e.g. '.' or ',' useful for some languages (e.g. German), generally pulled from *localeconv()->decimal_point - ImWchar Platform_LocaleDecimalPoint; // '.' + // [Experimental] Configure decimal point e.g. '.' or ',' useful for some languages (e.g. German), generally pulled + // from *localeconv()->decimal_point + ImWchar Platform_LocaleDecimalPoint; // '.' //------------------------------------------------------------------ // Input - Interface with Renderer Backend //------------------------------------------------------------------ // Optional: Maximum texture size supported by renderer (used to adjust how we size textures). 0 if not known. - int Renderer_TextureMaxWidth; - int Renderer_TextureMaxHeight; + int Renderer_TextureMaxWidth; + int Renderer_TextureMaxHeight; - // Written by some backends during ImGui_ImplXXXX_RenderDrawData() call to point backend_specific ImGui_ImplXXXX_RenderState* structure. - void* Renderer_RenderState; + // Written by some backends during ImGui_ImplXXXX_RenderDrawData() call to point backend_specific + // ImGui_ImplXXXX_RenderState* structure. + void *Renderer_RenderState; //------------------------------------------------------------------ // Output //------------------------------------------------------------------ // Textures list (the list is updated by calling ImGui::EndFrame or ImGui::Render) - // The ImGui_ImplXXXX_RenderDrawData() function of each backend generally access this via ImDrawData::Textures which points to this. The array is available here mostly because backends will want to destroy textures on shutdown. - ImVector Textures; // List of textures used by Dear ImGui (most often 1) + contents of external texture list is automatically appended into this. + // The ImGui_ImplXXXX_RenderDrawData() function of each backend generally access this via ImDrawData::Textures which + // points to this. The array is available here mostly because backends will want to destroy textures on shutdown. + ImVector Textures; // List of textures used by Dear ImGui (most often 1) + contents of external + // texture list is automatically appended into this. }; -// (Optional) Support for IME (Input Method Editor) via the platform_io.Platform_SetImeDataFn() function. Handler is called during EndFrame(). +// (Optional) Support for IME (Input Method Editor) via the platform_io.Platform_SetImeDataFn() function. Handler is +// called during EndFrame(). struct ImGuiPlatformImeData { - bool WantVisible; // A widget wants the IME to be visible. - bool WantTextInput; // A widget wants text input, not necessarily IME to be visible. This is automatically set to the upcoming value of io.WantTextInput. - ImVec2 InputPos; // Position of input cursor (for IME). - float InputLineHeight; // Line height (for IME). - ImGuiID ViewportId; // ID of platform window/viewport. + bool WantVisible; // A widget wants the IME to be visible. + bool WantTextInput; // A widget wants text input, not necessarily IME to be visible. This is automatically set to + // the upcoming value of io.WantTextInput. + ImVec2 InputPos; // Position of input cursor (for IME). + float InputLineHeight; // Line height (for IME). + ImGuiID ViewportId; // ID of platform window/viewport. - ImGuiPlatformImeData() { memset(this, 0, sizeof(*this)); } + ImGuiPlatformImeData() + { + memset(this, 0, sizeof(*this)); + } }; //----------------------------------------------------------------------------- // [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. +// 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.92.0 (from June 2025) - IMGUI_API void SetWindowFontScale(float scale); // Set font scale factor for current window. Prefer using PushFontSize(style.FontSizeBase * factor) or use style.FontScaleMain to scale all windows. - // OBSOLETED in 1.91.9 (from February 2025) - IMGUI_API void Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col); // <-- 'border_col' was removed in favor of ImGuiCol_ImageBorder. If you use 'tint_col', use ImageWithBg() instead. - // OBSOLETED in 1.91.0 (from July 2024) - static inline void PushButtonRepeat(bool repeat) { PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); } - static inline void PopButtonRepeat() { PopItemFlag(); } - static inline void PushTabStop(bool tab_stop) { PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); } - static inline void PopTabStop() { PopItemFlag(); } - IMGUI_API ImVec2 GetContentRegionMax(); // Content boundaries max (e.g. window boundaries including scrolling, or current column boundaries). You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()! - IMGUI_API ImVec2 GetWindowContentRegionMin(); // Content boundaries min for the window (roughly (0,0)-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()! - IMGUI_API ImVec2 GetWindowContentRegionMax(); // Content boundaries max for the window (roughly (0,0)+Size-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()! - // OBSOLETED in 1.90.0 (from September 2023) - static inline bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags window_flags = 0) { return BeginChild(id, size, ImGuiChildFlags_FrameStyle, window_flags); } - static inline void EndChildFrame() { EndChild(); } - //static inline bool BeginChild(const char* str_id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags){ return BeginChild(str_id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders - //static inline bool BeginChild(ImGuiID id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags) { return BeginChild(id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders - static inline void ShowStackToolWindow(bool* p_open = NULL) { ShowIDStackToolWindow(p_open); } - IMGUI_API bool Combo(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int popup_max_height_in_items = -1); - IMGUI_API bool ListBox(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int height_in_items = -1); - // OBSOLETED in 1.89.7 (from June 2023) - IMGUI_API void SetItemAllowOverlap(); // Use SetNextItemAllowOverlap() before item. - - // Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE) - //-- OBSOLETED in 1.89.4 (from March 2023) - //static inline void PushAllowKeyboardFocus(bool tab_stop) { PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); } - //static inline void PopAllowKeyboardFocus() { PopItemFlag(); } - //-- OBSOLETED in 1.89 (from August 2022) - //IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); // --> Use new ImageButton() signature (explicit item id, regular FramePadding). Refer to code in 1.91 if you want to grab a copy of this version. - //-- OBSOLETED in 1.88 (from May 2022) - //static inline void CaptureKeyboardFromApp(bool want_capture_keyboard = true) { SetNextFrameWantCaptureKeyboard(want_capture_keyboard); } // Renamed as name was misleading + removed default value. - //static inline void CaptureMouseFromApp(bool want_capture_mouse = true) { SetNextFrameWantCaptureMouse(want_capture_mouse); } // Renamed as name was misleading + removed default value. - //-- OBSOLETED in 1.87 (from February 2022, more formally obsoleted April 2024) - //IMGUI_API ImGuiKey GetKeyIndex(ImGuiKey key); { IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END); const ImGuiKeyData* key_data = GetKeyData(key); return (ImGuiKey)(key_data - g.IO.KeysData); } // Map ImGuiKey_* values into legacy native key index. == io.KeyMap[key]. When using a 1.87+ backend using io.AddKeyEvent(), calling GetKeyIndex() with ANY ImGuiKey_XXXX values will return the same value! - //static inline ImGuiKey GetKeyIndex(ImGuiKey key) { IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END); return key; } - //-- OBSOLETED in 1.86 (from November 2021) - //IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // Code removed, see 1.90 for last version of the code. Calculate range of visible items for large list of evenly sized items. Prefer using ImGuiListClipper. - //-- OBSOLETED in 1.85 (from August 2021) - //static inline float GetWindowContentRegionWidth() { return GetWindowContentRegionMax().x - GetWindowContentRegionMin().x; } - //-- OBSOLETED in 1.81 (from February 2021) - //static inline bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)) { return BeginListBox(label, size); } - //static inline bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1) { float height = GetTextLineHeightWithSpacing() * ((height_in_items < 0 ? ImMin(items_count, 7) : height_in_items) + 0.25f) + GetStyle().FramePadding.y * 2.0f; return BeginListBox(label, ImVec2(0.0f, height)); } // Helper to calculate size from items_count and height_in_items - //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.0f' argument instead of ImGuiSliderFlags_Logarithmic. See github.com/ocornut/imgui/issues/3361 for details. - //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 = 1.0f) // OBSOLETED in 1.78 (from June 2020) - //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 = 1.0f); // OBSOLETED in 1.78 (from June 2020) - //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 = 1.0f); // OBSOLETED in 1.78 (from June 2020) - //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 = 1.0f); // OBSOLETED in 1.78 (from June 2020) - //static inline bool DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power = 1.0f) { return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) - //static inline bool DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power = 1.0f) { return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) - //static inline bool DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power = 1.0f) { return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) - //static inline bool DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power = 1.0f) { return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) - //static inline bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power = 1.0f) { return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) - //static inline bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power = 1.0f) { return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) - //static inline bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power = 1.0f) { return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) - //static inline bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power = 1.0f) { return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) - //-- OBSOLETED in 1.77 and before - //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.77 (from June 2020) - //static inline void TreeAdvanceToLabelPos() { SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()); } // OBSOLETED in 1.72 (from July 2019) - //static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); } // OBSOLETED in 1.71 (from June 2019) - //static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; } // OBSOLETED in 1.70 (from May 2019) - //static inline ImDrawList* GetOverlayDrawList() { return GetForegroundDrawList(); } // OBSOLETED in 1.69 (from Mar 2019) - //static inline void SetScrollHere(float ratio = 0.5f) { SetScrollHereY(ratio); } // OBSOLETED in 1.66 (from Nov 2018) - //static inline bool IsItemDeactivatedAfterChange() { return IsItemDeactivatedAfterEdit(); } // OBSOLETED in 1.63 (from Aug 2018) - //-- OBSOLETED in 1.60 and before - //static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } // OBSOLETED in 1.60 (from Apr 2018) - //static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018) - //static inline void ShowTestWindow() { return ShowDemoWindow(); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) - //static inline bool IsRootWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootWindow); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) - //static inline bool IsRootWindowOrAnyChildFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) - //static inline void SetNextWindowContentWidth(float w) { SetNextWindowContentSize(ImVec2(w, 0.0f)); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) - //static inline float GetItemsLineHeightWithSpacing() { return GetFrameHeightWithSpacing(); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) - //IMGUI_API bool Begin(char* name, bool* p_open, ImVec2 size_first_use, float bg_alpha = -1.0f, ImGuiWindowFlags flags=0); // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017): Equivalent of using SetNextWindowSize(size, ImGuiCond_FirstUseEver) and SetNextWindowBgAlpha(). - //static inline bool IsRootWindowOrAnyChildHovered() { return IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); } // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017) - //static inline void AlignFirstTextHeightToWidgets() { AlignTextToFramePadding(); } // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017) - //static inline void SetNextWindowPosCenter(ImGuiCond c=0) { SetNextWindowPos(GetMainViewport()->GetCenter(), c, ImVec2(0.5f,0.5f)); } // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017) - //static inline bool IsItemHoveredRect() { return IsItemHovered(ImGuiHoveredFlags_RectOnly); } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017) - //static inline bool IsPosHoveringAnyWindow(const ImVec2&) { IM_ASSERT(0); return false; } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017): This was misleading and partly broken. You probably want to use the io.WantCaptureMouse flag instead. - //static inline bool IsMouseHoveringAnyWindow() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017) - //static inline bool IsMouseHoveringWindow() { return IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017) - //-- OBSOLETED in 1.50 and before - //static inline bool CollapsingHeader(char* label, const char* str_id, bool framed = true, bool default_open = false) { return CollapsingHeader(label, (default_open ? (1 << 5) : 0)); } // OBSOLETED in 1.49 - //static inline ImFont*GetWindowFont() { return GetFont(); } // OBSOLETED in 1.48 - //static inline float GetWindowFontSize() { return GetFontSize(); } // OBSOLETED in 1.48 - //static inline void SetScrollPosHere() { SetScrollHere(); } // OBSOLETED in 1.42 +// OBSOLETED in 1.92.0 (from June 2025) +IMGUI_API void SetWindowFontScale( + float scale); // Set font scale factor for current window. Prefer using PushFontSize(style.FontSizeBase * factor) or + // use style.FontScaleMain to scale all windows. +// OBSOLETED in 1.91.9 (from February 2025) +IMGUI_API void Image(ImTextureRef tex_ref, const ImVec2 &image_size, const ImVec2 &uv0, const ImVec2 &uv1, + const ImVec4 &tint_col, + const ImVec4 &border_col); // <-- 'border_col' was removed in favor of ImGuiCol_ImageBorder. If you + // use 'tint_col', use ImageWithBg() instead. +// OBSOLETED in 1.91.0 (from July 2024) +static inline void PushButtonRepeat(bool repeat) +{ + PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); } +static inline void PopButtonRepeat() +{ + PopItemFlag(); +} +static inline void PushTabStop(bool tab_stop) +{ + PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); +} +static inline void PopTabStop() +{ + PopItemFlag(); +} +IMGUI_API ImVec2 GetContentRegionMax(); // Content boundaries max (e.g. window boundaries including scrolling, or + // current column boundaries). You should never need this. Always use + // GetCursorScreenPos() and GetContentRegionAvail()! +IMGUI_API ImVec2 GetWindowContentRegionMin(); // Content boundaries min for the window (roughly (0,0)-Scroll), in + // window-local coordinates. You should never need this. Always use + // GetCursorScreenPos() and GetContentRegionAvail()! +IMGUI_API ImVec2 GetWindowContentRegionMax(); // Content boundaries max for the window (roughly (0,0)+Size-Scroll), in + // window-local coordinates. You should never need this. Always use + // GetCursorScreenPos() and GetContentRegionAvail()! +// OBSOLETED in 1.90.0 (from September 2023) +static inline bool BeginChildFrame(ImGuiID id, const ImVec2 &size, ImGuiWindowFlags window_flags = 0) +{ + return BeginChild(id, size, ImGuiChildFlags_FrameStyle, window_flags); +} +static inline void EndChildFrame() +{ + EndChild(); +} +// static inline bool BeginChild(const char* str_id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags +// window_flags){ return BeginChild(str_id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, +// window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders static inline bool BeginChild(ImGuiID id, const +// ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags) { return BeginChild(id, size_arg, borders ? +// ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == +// ImGuiChildFlags_Borders +static inline void ShowStackToolWindow(bool *p_open = NULL) +{ + ShowIDStackToolWindow(p_open); +} +IMGUI_API bool Combo(const char *label, int *current_item, + bool (*old_callback)(void *user_data, int idx, const char **out_text), void *user_data, + int items_count, int popup_max_height_in_items = -1); +IMGUI_API bool ListBox(const char *label, int *current_item, + bool (*old_callback)(void *user_data, int idx, const char **out_text), void *user_data, + int items_count, int height_in_items = -1); +// OBSOLETED in 1.89.7 (from June 2023) +IMGUI_API void SetItemAllowOverlap(); // Use SetNextItemAllowOverlap() before item. + +// Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE) +//-- OBSOLETED in 1.89.4 (from March 2023) +// static inline void PushAllowKeyboardFocus(bool tab_stop) { +// PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); } static inline void PopAllowKeyboardFocus() { PopItemFlag(); } +//-- OBSOLETED in 1.89 (from August 2022) +// IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), +// const ImVec2& uv1 = ImVec2(1, 1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& +// tint_col = ImVec4(1, 1, 1, 1)); // --> Use new ImageButton() signature (explicit item id, regular FramePadding). +// Refer to code in 1.91 if you want to grab a copy of this version. +//-- OBSOLETED in 1.88 (from May 2022) +// static inline void CaptureKeyboardFromApp(bool want_capture_keyboard = true) { +// SetNextFrameWantCaptureKeyboard(want_capture_keyboard); } // Renamed as name was misleading + removed default value. +// static inline void CaptureMouseFromApp(bool want_capture_mouse = true) { +// SetNextFrameWantCaptureMouse(want_capture_mouse); } // Renamed as name was misleading + removed default value. +//-- OBSOLETED in 1.87 (from February 2022, more formally obsoleted April 2024) +// IMGUI_API ImGuiKey GetKeyIndex(ImGuiKey key); { IM_ASSERT(key >= +// ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END); const ImGuiKeyData* key_data = GetKeyData(key); return +// (ImGuiKey)(key_data - g.IO.KeysData); } // Map ImGuiKey_* values into legacy native key index. == io.KeyMap[key]. +// When using a 1.87+ backend using io.AddKeyEvent(), calling GetKeyIndex() with ANY ImGuiKey_XXXX values will return +// the same value! static inline ImGuiKey GetKeyIndex(ImGuiKey key) { +// IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END); return key; } +//-- OBSOLETED in 1.86 (from November 2021) +// IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* +// out_items_display_end); // Code removed, see 1.90 for last version of the code. Calculate range of visible items for +// large list of evenly sized items. Prefer using ImGuiListClipper. +//-- OBSOLETED in 1.85 (from August 2021) +// static inline float GetWindowContentRegionWidth() { return +// GetWindowContentRegionMax().x - GetWindowContentRegionMin().x; } +//-- OBSOLETED in 1.81 (from February 2021) +// static inline bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)) { return +// BeginListBox(label, size); } static inline bool ListBoxHeader(const char* label, int items_count, int +// height_in_items = -1) { float height = GetTextLineHeightWithSpacing() * ((height_in_items < 0 ? ImMin(items_count, 7) +// : height_in_items) + 0.25f) + GetStyle().FramePadding.y * 2.0f; return BeginListBox(label, ImVec2(0.0f, height)); } +// // Helper to calculate size from items_count and height_in_items 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.0f' argument instead of +//ImGuiSliderFlags_Logarithmic. See github.com/ocornut/imgui/issues/3361 for details. 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 = 1.0f) // OBSOLETED in 1.78 (from +// June 2020) 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 = 1.0f); // OBSOLETED in 1.78 +// (from June 2020) 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 = 1.0f); // OBSOLETED in 1.78 (from June 2020) +// 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 = 1.0f); // OBSOLETED in 1.78 (from June 2020) static +// inline bool DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, +// float power = 1.0f) { return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); } +// // OBSOLETED in 1.78 (from June 2020) static inline bool DragFloat2(const char* label, float v[2], float v_speed, +// float v_min, float v_max, const char* format, float power = 1.0f) { return DragScalarN(label, ImGuiDataType_Float, v, +// 2, v_speed, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) static inline bool +// DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power +// = 1.0f) { return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); } // +// OBSOLETED in 1.78 (from June 2020) static inline bool DragFloat4(const char* label, float v[4], float v_speed, float +// v_min, float v_max, const char* format, float power = 1.0f) { return DragScalarN(label, ImGuiDataType_Float, v, 4, +// v_speed, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) static inline bool SliderFloat(const +// char* label, float* v, float v_min, float v_max, const char* format, float power = 1.0f) { return +// SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from +// June 2020) static inline bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* +// format, float power = 1.0f) { return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, +// format, power); } // OBSOLETED in 1.78 (from June 2020) static inline bool SliderFloat3(const char* label, +// float v[3], float v_min, float v_max, const char* format, float power = 1.0f) { return +// SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from +// June 2020) static inline bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* +// format, float power = 1.0f) { return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, +// format, power); } // OBSOLETED in 1.78 (from June 2020) +//-- OBSOLETED in 1.77 and before +// 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.77 +// (from June 2020) static inline void TreeAdvanceToLabelPos() { SetCursorPosX(GetCursorPosX() + +// GetTreeNodeToLabelSpacing()); } // OBSOLETED in 1.72 (from July 2019) static inline void SetNextTreeNodeOpen(bool +// open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); } // OBSOLETED in 1.71 (from June +// 2019) static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; } // OBSOLETED +// in 1.70 (from May 2019) static inline ImDrawList* GetOverlayDrawList() { return GetForegroundDrawList(); } +// // OBSOLETED in 1.69 (from Mar 2019) static inline void SetScrollHere(float ratio = 0.5f) { +// SetScrollHereY(ratio); } // OBSOLETED in 1.66 (from Nov 2018) static inline +// bool IsItemDeactivatedAfterChange() { return IsItemDeactivatedAfterEdit(); } // +// OBSOLETED in 1.63 (from Aug 2018) +//-- OBSOLETED in 1.60 and before +// static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } // +// OBSOLETED in 1.60 (from Apr 2018) static inline bool IsAnyWindowHovered() { return +// IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018) +// static inline void ShowTestWindow() { return ShowDemoWindow(); } // OBSOLETED in 1.53 (between +// Oct 2017 and Dec 2017) static inline bool IsRootWindowFocused() { return +// IsWindowFocused(ImGuiFocusedFlags_RootWindow); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) +// static inline bool IsRootWindowOrAnyChildFocused() { return +// IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) +// static inline void SetNextWindowContentWidth(float w) { SetNextWindowContentSize(ImVec2(w, 0.0f)); } // OBSOLETED +// in 1.53 (between Oct 2017 and Dec 2017) static inline float GetItemsLineHeightWithSpacing() { return +// GetFrameHeightWithSpacing(); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) +// IMGUI_API bool Begin(char* name, bool* p_open, ImVec2 size_first_use, float bg_alpha = -1.0f, ImGuiWindowFlags +// flags=0); // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017): Equivalent of using SetNextWindowSize(size, +// ImGuiCond_FirstUseEver) and SetNextWindowBgAlpha(). static inline bool IsRootWindowOrAnyChildHovered() { +// return IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); } // OBSOLETED in 1.52 (between Aug 2017 and Oct +// 2017) static inline void AlignFirstTextHeightToWidgets() { AlignTextToFramePadding(); } // OBSOLETED in 1.52 +// (between Aug 2017 and Oct 2017) static inline void SetNextWindowPosCenter(ImGuiCond c=0) { +// SetNextWindowPos(GetMainViewport()->GetCenter(), c, ImVec2(0.5f,0.5f)); } // OBSOLETED in 1.52 (between Aug 2017 and +// Oct 2017) static inline bool IsItemHoveredRect() { return +// IsItemHovered(ImGuiHoveredFlags_RectOnly); } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017) +// static inline bool IsPosHoveringAnyWindow(const ImVec2&) { IM_ASSERT(0); return false; } // OBSOLETED in 1.51 +// (between Jun 2017 and Aug 2017): This was misleading and partly broken. You probably want to use the +// io.WantCaptureMouse flag instead. static inline bool IsMouseHoveringAnyWindow() { return +// IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017) +// static inline bool IsMouseHoveringWindow() { return +// IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); } // +// OBSOLETED in 1.51 (between Jun 2017 and Aug 2017) +//-- OBSOLETED in 1.50 and before +// static inline bool CollapsingHeader(char* label, const char* str_id, bool framed = true, bool default_open = false) +// { return CollapsingHeader(label, (default_open ? (1 << 5) : 0)); } // OBSOLETED in 1.49 static inline +// ImFont*GetWindowFont() { return GetFont(); } // +// OBSOLETED in 1.48 static inline float GetWindowFontSize() { return GetFontSize(); } // OBSOLETED +// in 1.48 static inline void SetScrollPosHere() { SetScrollHere(); } // OBSOLETED in 1.42 +} // namespace ImGui //-- OBSOLETED in 1.92.x: ImFontAtlasCustomRect becomes ImTextureRect // - ImFontAtlasCustomRect::X,Y --> ImTextureRect::x,y // - ImFontAtlasCustomRect::Width,Height --> ImTextureRect::w,h -// - ImFontAtlasCustomRect::GlyphColored --> if you need to write to this, instead you can write to 'font->Glyphs.back()->Colored' after calling AddCustomRectFontGlyph() -// We could make ImTextureRect an union to use old names, but 1) this would be confusing 2) the fix is easy 3) ImFontAtlasCustomRect was always a rather esoteric api. +// - ImFontAtlasCustomRect::GlyphColored --> if you need to write to this, instead you can write to +// 'font->Glyphs.back()->Colored' after calling AddCustomRectFontGlyph() We could make ImTextureRect an union to use old +// names, but 1) this would be confusing 2) the fix is easy 3) ImFontAtlasCustomRect was always a rather esoteric api. typedef ImFontAtlasRect ImFontAtlasCustomRect; /*struct ImFontAtlasCustomRect { unsigned short X, Y; // Output // Packed position in Atlas unsigned short Width, Height; // Input // [Internal] Desired rectangle dimension unsigned int GlyphID:31; // Input // [Internal] For custom font glyphs only (ID < 0x110000) - unsigned int GlyphColored:1; // Input // [Internal] For custom font glyphs only: glyph is colored, removed tinting. - float GlyphAdvanceX; // Input // [Internal] For custom font glyphs only: glyph xadvance - ImVec2 GlyphOffset; // Input // [Internal] For custom font glyphs only: glyph display offset - ImFont* Font; // Input // [Internal] For custom font glyphs only: target font - ImFontAtlasCustomRect() { X = Y = 0xFFFF; Width = Height = 0; GlyphID = 0; GlyphColored = 0; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; } - bool IsPacked() const { return X != 0xFFFF; } + unsigned int GlyphColored:1; // Input // [Internal] For custom font glyphs only: glyph is colored, removed +tinting. float GlyphAdvanceX; // Input // [Internal] For custom font glyphs only: glyph xadvance ImVec2 +GlyphOffset; // Input // [Internal] For custom font glyphs only: glyph display offset ImFont* Font; // +Input // [Internal] For custom font glyphs only: target font ImFontAtlasCustomRect() { X = Y = 0xFFFF; Width += Height = 0; GlyphID = 0; GlyphColored = 0; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; } bool +IsPacked() const { return X != 0xFFFF; } };*/ //-- OBSOLETED in 1.82 (from Mars 2021): flags for AddRect(), AddRectFilled(), AddImageRounded(), PathRect() -//typedef ImDrawFlags ImDrawCornerFlags; -//enum ImDrawCornerFlags_ +// 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_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, //}; // RENAMED and MERGED both ImGuiKey_ModXXX and ImGuiModFlags_XXX into ImGuiMod_XXX (from September 2022) -// RENAMED ImGuiKeyModFlags -> ImGuiModFlags in 1.88 (from April 2022). Exceptionally commented out ahead of obscolescence schedule to reduce confusion and because they were not meant to be used in the first place. -//typedef ImGuiKeyChord ImGuiModFlags; // == int. We generally use ImGuiKeyChord to mean "a ImGuiKey or-ed with any number of ImGuiMod_XXX value", so you may store mods in there. -//enum ImGuiModFlags_ { ImGuiModFlags_None = 0, ImGuiModFlags_Ctrl = ImGuiMod_Ctrl, ImGuiModFlags_Shift = ImGuiMod_Shift, ImGuiModFlags_Alt = ImGuiMod_Alt, ImGuiModFlags_Super = ImGuiMod_Super }; -//typedef ImGuiKeyChord ImGuiKeyModFlags; // == int -//enum ImGuiKeyModFlags_ { ImGuiKeyModFlags_None = 0, ImGuiKeyModFlags_Ctrl = ImGuiMod_Ctrl, ImGuiKeyModFlags_Shift = ImGuiMod_Shift, ImGuiKeyModFlags_Alt = ImGuiMod_Alt, ImGuiKeyModFlags_Super = ImGuiMod_Super }; +// RENAMED ImGuiKeyModFlags -> ImGuiModFlags in 1.88 (from April 2022). Exceptionally commented out ahead of +// obscolescence schedule to reduce confusion and because they were not meant to be used in the first place. +// typedef ImGuiKeyChord ImGuiModFlags; // == int. We generally use ImGuiKeyChord to mean "a ImGuiKey or-ed with +// any number of ImGuiMod_XXX value", so you may store mods in there. enum ImGuiModFlags_ { ImGuiModFlags_None = 0, +// ImGuiModFlags_Ctrl = ImGuiMod_Ctrl, ImGuiModFlags_Shift = ImGuiMod_Shift, ImGuiModFlags_Alt = ImGuiMod_Alt, +// ImGuiModFlags_Super = ImGuiMod_Super }; typedef ImGuiKeyChord ImGuiKeyModFlags; // == int enum ImGuiKeyModFlags_ { +// ImGuiKeyModFlags_None = 0, ImGuiKeyModFlags_Ctrl = ImGuiMod_Ctrl, ImGuiKeyModFlags_Shift = ImGuiMod_Shift, +// ImGuiKeyModFlags_Alt = ImGuiMod_Alt, ImGuiKeyModFlags_Super = ImGuiMod_Super }; -#define IM_OFFSETOF(_TYPE,_MEMBER) offsetof(_TYPE, _MEMBER) // OBSOLETED IN 1.90 (now using C++11 standard version) +#define IM_OFFSETOF(_TYPE, _MEMBER) offsetof(_TYPE, _MEMBER) // OBSOLETED IN 1.90 (now using C++11 standard version) #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS @@ -4097,7 +6464,7 @@ typedef ImFontAtlasRect ImFontAtlasCustomRect; #endif #ifdef _MSC_VER -#pragma warning (pop) +#pragma warning(pop) #endif // Include imgui_user.h at the end of imgui.h diff --git a/firmware/components/insa/CMakeLists.txt b/firmware/components/insa/CMakeLists.txt index 76ad02c..d062ef1 100644 --- a/firmware/components/insa/CMakeLists.txt +++ b/firmware/components/insa/CMakeLists.txt @@ -1,15 +1,11 @@ idf_component_register(SRCS - src/common/ColorSettingsMenu.cpp src/common/InactivityTracker.cpp src/common/Menu.cpp src/common/ScrollBar.cpp src/common/Widget.cpp src/data/MenuItem.cpp - src/ui/DayColorSettingsMenu.cpp src/ui/LightMenu.cpp - src/ui/LightSettingsMenu.cpp src/ui/MainMenu.cpp - src/ui/NightColorSettingsMenu.cpp src/ui/ClockScreenSaver.cpp src/ui/ScreenSaver.cpp src/ui/SettingsMenu.cpp @@ -19,4 +15,5 @@ idf_component_register(SRCS u8g2 led-manager persistence-manager + simulator ) diff --git a/firmware/components/insa/include/common/ColorSettingsMenu.h b/firmware/components/insa/include/common/ColorSettingsMenu.h deleted file mode 100644 index dfe5fa0..0000000 --- a/firmware/components/insa/include/common/ColorSettingsMenu.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "common/Menu.h" - -namespace ColorSettingsMenuOptions -{ -constexpr auto RED = "red_"; -constexpr auto GREEN = "green_"; -constexpr auto BLUE = "blue_"; -} // namespace ColorSettingsMenuOptions - -class ColorSettingsMenu : public Menu -{ - public: - /** - * @brief Constructs a ColorSettingsMenu with the specified options - * @param options Pointer to menu configuration options structure - * @details Initializes the menu with color settings options - */ - explicit ColorSettingsMenu(menu_options_t *options, std::string prefix); - - void onButtonPressed(const MenuItem &menuItem, const ButtonType button) override; - - void onExit() override; - - private: - std::string m_suffix; - menu_options_t *m_options; -}; diff --git a/firmware/components/insa/include/common/Menu.h b/firmware/components/insa/include/common/Menu.h index 354e6a2..a9b992a 100644 --- a/firmware/components/insa/include/common/Menu.h +++ b/firmware/components/insa/include/common/Menu.h @@ -194,9 +194,9 @@ class Menu : public Widget private: MenuItem replaceItem(int index, const MenuItem &item); - void render() override; + void Render() override; - void onButtonClicked(ButtonType button) override; + void OnButtonClicked(ButtonType button) override; void onPressedDown(); diff --git a/firmware/components/insa/include/common/ScrollBar.h b/firmware/components/insa/include/common/ScrollBar.h index bd7b833..8607b0c 100644 --- a/firmware/components/insa/include/common/ScrollBar.h +++ b/firmware/components/insa/include/common/ScrollBar.h @@ -22,20 +22,20 @@ * that indicates the current position within a scrollable range. The thumb * size is proportional to the visible area relative to the total content, * and its position reflects the current scroll offset. - * + * * The scrollbar automatically calculates thumb dimensions and position based on * the provided scroll values (current, minimum, maximum). It is designed to be * used alongside scrollable content like menus or lists to provide visual * feedback about scroll state. - * + * * @note This class is marked as final and cannot be inherited from. - * + * * @see Widget * @see menu_options_t */ class ScrollBar final : public Widget { -public: + public: /** * @brief Constructs a ScrollBar with specified position and dimensions * @param options Pointer to menu options configuration structure @@ -43,12 +43,12 @@ public: * @param y Y coordinate position of the scrollbar on screen * @param width Width of the scrollbar in pixels * @param height Height of the scrollbar in pixels - * + * * @pre options must not be nullptr and must remain valid for the scrollbar's lifetime * @pre width and height must be greater than 0 * @pre x and y must be valid screen coordinates * @post ScrollBar is initialized with the specified geometry and ready for use - * + * * @note The scrollbar does not take ownership of the options structure and * assumes it remains valid throughout the scrollbar's lifetime. */ @@ -59,48 +59,48 @@ public: * @details Overrides the base Widget render method to draw the scrollbar track * and thumb. The appearance is determined by the current scroll state * and the menu options configuration. - * + * * @pre u8g2 display context must be initialized and ready for drawing * @post Scrollbar's visual representation is drawn to the display buffer - * + * * @note This method is called during each frame's render cycle. The scrollbar * track and thumb are drawn based on the current scroll values set by refresh(). */ - void render() override; + void Render() override; /** * @brief Updates the scrollbar state with new scroll values * @param value Current scroll position value (must be between min and max) * @param max Maximum scroll value (total content size) * @param min Minimum scroll value (default: 0, typically the start of content) - * + * * @pre value must be between min and max (inclusive) * @pre max must be greater than or equal to min * @post Scrollbar thumb position and size are recalculated based on new values - * + * * @details This method recalculates the thumb's height and vertical position * based on the provided scroll range and current position. The thumb * height represents the proportion of visible content to total content, * while its position represents the current scroll offset within the range. - * + * * @note Call this method whenever the scroll state changes to keep the * scrollbar visualization synchronized with the actual content position. */ void refresh(size_t value, size_t max, size_t min = 0); -private: + private: // Position and dimensions - size_t m_x; ///< X coordinate of the scrollbar's left edge - size_t m_y; ///< Y coordinate of the scrollbar's top edge - size_t m_width; ///< Width of the scrollbar track in pixels - size_t m_height; ///< Height of the scrollbar track in pixels + size_t m_x; ///< X coordinate of the scrollbar's left edge + size_t m_y; ///< Y coordinate of the scrollbar's top edge + size_t m_width; ///< Width of the scrollbar track in pixels + size_t m_height; ///< Height of the scrollbar track in pixels // Scroll state values - size_t m_value; ///< Current scroll position within the range [m_min, m_max] - size_t m_max; ///< Maximum scroll value representing the end of content - size_t m_min; ///< Minimum scroll value representing the start of content + size_t m_value; ///< Current scroll position within the range [m_min, m_max] + size_t m_max; ///< Maximum scroll value representing the end of content + size_t m_min; ///< Minimum scroll value representing the start of content // Calculated thumb properties (updated by refresh()) - size_t m_thumbHeight; ///< Calculated height of the scroll thumb in pixels - size_t m_thumbY; ///< Calculated Y position of the scroll thumb relative to track + size_t m_thumbHeight; ///< Calculated height of the scroll thumb in pixels + size_t m_thumbY; ///< Calculated Y position of the scroll thumb relative to track }; \ No newline at end of file diff --git a/firmware/components/insa/include/common/Widget.h b/firmware/components/insa/include/common/Widget.h index f222778..6cca341 100644 --- a/firmware/components/insa/include/common/Widget.h +++ b/firmware/components/insa/include/common/Widget.h @@ -117,7 +117,7 @@ class Widget * @note Override this method in derived classes to implement time-based behavior * such as animations, blinking effects, or timeout handling. */ - virtual void update(uint64_t dt); + virtual void Update(uint64_t dt); /** * @brief Renders the widget to the display @@ -133,7 +133,7 @@ class Widget * Derived classes should use the u8g2 member variable to perform * drawing operations. */ - virtual void render(); + virtual void Render(); /** * @brief Handles button press events @@ -148,7 +148,7 @@ class Widget * * @see ButtonType for available button types */ - virtual void onButtonClicked(ButtonType button); + virtual void OnButtonClicked(ButtonType button); protected: /** diff --git a/firmware/components/insa/include/ui/ClockScreenSaver.h b/firmware/components/insa/include/ui/ClockScreenSaver.h index 99fe60e..1dbc0b1 100644 --- a/firmware/components/insa/include/ui/ClockScreenSaver.h +++ b/firmware/components/insa/include/ui/ClockScreenSaver.h @@ -21,9 +21,9 @@ class ClockScreenSaver final : public Widget { public: explicit ClockScreenSaver(menu_options_t *options); - void update(uint64_t dt) override; - void render() override; - void onButtonClicked(ButtonType button) override; + void Update(uint64_t dt) override; + void Render() override; + void OnButtonClicked(ButtonType button) override; private: static constexpr int MOVE_INTERVAL = 50; // milliseconds between movements diff --git a/firmware/components/insa/include/ui/DayColorSettingsMenu.h b/firmware/components/insa/include/ui/DayColorSettingsMenu.h deleted file mode 100644 index 0b6b234..0000000 --- a/firmware/components/insa/include/ui/DayColorSettingsMenu.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "common/ColorSettingsMenu.h" - -class DayColorSettingsMenu final : public ColorSettingsMenu -{ - public: - /** - * @brief Constructs a DayColorSettingsMenu with the specified options - * @param options Pointer to menu configuration options structure - * @details Initializes the menu with day color settings options - */ - explicit DayColorSettingsMenu(menu_options_t *options); -}; diff --git a/firmware/components/insa/include/ui/LightSettingsMenu.h b/firmware/components/insa/include/ui/LightSettingsMenu.h deleted file mode 100644 index 82abe5f..0000000 --- a/firmware/components/insa/include/ui/LightSettingsMenu.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "common/Menu.h" - -/** - * @class LightSettingsMenu - * @brief Menu for configuring light system settings including sections and LED parameters - * @details This menu extends the base Menu class to provide specialized functionality - * for managing light system configurations. It handles dynamic section management - * and provides persistence for user settings. - */ -class LightSettingsMenu final : public Menu -{ -public: - /** - * @brief Constructs a LightSettingsMenu with the specified options - * @param options Pointer to menu configuration options structure - * @details Initializes the menu with section counter and default section settings - */ - explicit LightSettingsMenu(menu_options_t *options); - -private: - /** - * @brief Handles button press events for light settings menu items - * @param menuItem The menu item that received the button press - * @param button The type of button that was pressed - * @details Manages value switching, dynamic section list updates, and - * persistence of section values when settings are modified - */ - void onButtonPressed(const MenuItem& menuItem, ButtonType button) override; - - static std::string CreateKey(int index); - - menu_options_t *m_options; ///< Pointer to menu configuration options -}; \ No newline at end of file diff --git a/firmware/components/insa/include/ui/NightColorSettingsMenu.h b/firmware/components/insa/include/ui/NightColorSettingsMenu.h deleted file mode 100644 index e825768..0000000 --- a/firmware/components/insa/include/ui/NightColorSettingsMenu.h +++ /dev/null @@ -1,15 +0,0 @@ - -#pragma once - -#include "common/ColorSettingsMenu.h" - -class NightColorSettingsMenu final : public ColorSettingsMenu -{ - public: - /** - * @brief Constructs a NightColorSettingsMenu with the specified options - * @param options Pointer to menu configuration options structure - * @details Initializes the menu with night color settings options - */ - explicit NightColorSettingsMenu(menu_options_t *options); -}; diff --git a/firmware/components/insa/include/ui/ScreenSaver.h b/firmware/components/insa/include/ui/ScreenSaver.h index 57ac697..7386d5b 100644 --- a/firmware/components/insa/include/ui/ScreenSaver.h +++ b/firmware/components/insa/include/ui/ScreenSaver.h @@ -23,9 +23,9 @@ class ScreenSaver final : public Widget { public: explicit ScreenSaver(menu_options_t *options); - void update(uint64_t dt) override; - void render() override; - void onButtonClicked(ButtonType button) override; + void Update(uint64_t dt) override; + void Render() override; + void OnButtonClicked(ButtonType button) override; private: /** diff --git a/firmware/components/insa/include/ui/SplashScreen.h b/firmware/components/insa/include/ui/SplashScreen.h index 034d2b4..5ffeb4e 100644 --- a/firmware/components/insa/include/ui/SplashScreen.h +++ b/firmware/components/insa/include/ui/SplashScreen.h @@ -21,71 +21,71 @@ * displayed when the application starts. It serves multiple purposes including * brand presentation, system initialization feedback, and smooth transition * preparation to the main application interface. - * + * * The SplashScreen class provides: * - Brand identity display (logos, company information, product name) * - System initialization progress indication * - Smooth animations and visual effects for professional appearance * - Automatic transition timing to main menu after initialization * - Error indication if initialization fails - * + * * Key features include: * - Time-based automatic progression to main menu * - Animated elements (fade-in effects, progress indicators) * - Version information display * - Loading status messages * - Graceful handling of initialization delays - * + * * The splash screen typically displays for a minimum duration to ensure users * can read branding information, even if system initialization completes quickly. * It automatically transitions to the main menu once both the minimum display * time and system initialization are complete. - * + * * @note This class is marked as final and cannot be inherited from. * @note The splash screen does not handle user input - it operates on timing * and system state rather than user interaction. - * + * * @see Widget for base widget functionality * @see menu_options_t for configuration structure * @see MainMenu for the target transition screen */ class SplashScreen final : public Widget { -public: + public: /** * @brief Constructs the splash screen with specified configuration * @param options Pointer to menu options configuration structure - * + * * @pre options must not be nullptr and must remain valid for the splash screen's lifetime * @pre options->u8g2 must be initialized and ready for graphics operations * @pre Screen transition callbacks in options must be properly configured * @post SplashScreen is initialized and ready to display startup sequence - * + * * @details The constructor initializes the splash screen by: * - Setting up the initial display state and animations * - Preparing branding elements (logos, text, version info) * - Initializing timing controls for minimum display duration * - Configuring transition parameters for smooth progression * - Loading any required graphics resources or assets - * + * * The splash screen prepares all visual elements during construction to * ensure smooth rendering performance during the critical startup phase. * It also establishes the timing framework for controlling display duration * and transition timing. - * + * * @note The splash screen does not take ownership of the options structure * and assumes it remains valid throughout the screen's lifetime. * @note Graphics resources are loaded during construction, so any required * assets must be available at initialization time. - * + * * @see Widget::Widget for base class construction details */ explicit SplashScreen(menu_options_t *options); - + /** * @brief Updates the splash screen state, animations, and timing logic * @param dt Delta time in milliseconds since the last update call - * + * * @details Overrides the base Widget update method to handle splash screen-specific * logic including: * - Animation progression (fade effects, transitions, progress indicators) @@ -93,31 +93,31 @@ public: * - System initialization status monitoring * - Automatic transition preparation to main menu * - Loading progress updates and status message changes - * + * * The update method manages the splash screen's lifecycle by tracking * elapsed time and system readiness state. It ensures the splash screen * remains visible for a minimum duration while also monitoring system * initialization completion. Once both conditions are met, it initiates * the transition to the main application interface. - * + * * Animation updates include: * - Fade-in effects for branding elements * - Progress bar or spinner animations * - Text transitions for status messages * - Smooth preparation for screen transition - * + * * @note This method is called every frame during the splash screen display * and must be efficient to maintain smooth visual presentation. * @note The method automatically handles transition to the main menu when * appropriate, using the callback functions provided in m_options. - * + * * @see Widget::update for the base update interface */ - void update(uint64_t dt) override; - + void Update(uint64_t dt) override; + /** * @brief Renders the splash screen visual elements to the display - * + * * @details Overrides the base Widget render method to draw all splash screen * elements including branding, status information, and visual effects. * The rendering includes: @@ -126,50 +126,50 @@ public: * - Loading progress indicators (progress bars, spinners, etc.) * - Status messages indicating initialization progress * - Background graphics and visual effects - * + * * The render method creates a professional, polished appearance that * reinforces brand identity while providing useful feedback about the * application startup process. All elements are positioned and styled * to create a cohesive, attractive presentation. - * + * * Rendering features include: * - Centered layout with balanced visual hierarchy * - Smooth animations and transitions * - Consistent typography and color scheme * - Progress feedback elements * - Error indication if initialization problems occur - * + * * @pre u8g2 display context must be initialized and ready for drawing * @post All splash screen visual elements are drawn to the display buffer - * + * * @note This method is called every frame and must be efficient to maintain * smooth visual presentation during the startup sequence. * @note The visual design should be consistent with the overall application * theme and branding guidelines. - * + * * @see Widget::render for the base render interface */ - void render() override; + void Render() override; -private: + private: /** * @brief Pointer to menu options configuration structure * @details Stores a reference to the menu configuration passed during construction. * This provides access to the display context for rendering operations * and screen transition callbacks for automatic progression to the main menu. - * + * * The configuration enables: * - Display context (u8g2) for graphics rendering operations * - Screen transition callbacks for automatic progression to main menu * - System integration for initialization status monitoring - * + * * The splash screen uses the setScreen callback to automatically transition * to the main menu once the startup sequence is complete. This ensures a * seamless user experience from application launch to main interface. - * + * * @note This pointer is not owned by the SplashScreen and must remain valid * throughout the screen's lifetime. It is managed by the application framework. - * + * * @warning Must not be modified after construction as it contains critical * system callbacks required for proper application flow. */ diff --git a/firmware/components/insa/src/common/ColorSettingsMenu.cpp b/firmware/components/insa/src/common/ColorSettingsMenu.cpp deleted file mode 100644 index 3fec3fc..0000000 --- a/firmware/components/insa/src/common/ColorSettingsMenu.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include "common/ColorSettingsMenu.h" - -#include "led_manager.h" - -namespace ColorSettingsMenuItem -{ -constexpr auto RED = 0; -constexpr auto GREEN = 1; -constexpr auto BLUE = 2; -} // namespace ColorSettingsMenuItem - -ColorSettingsMenu::ColorSettingsMenu(menu_options_t *options, std::string suffix) - : Menu(options), m_suffix(std::move(suffix)), m_options(options) -{ - - std::vector values; - for (size_t i = 0; i <= 254; i++) - { - values.emplace_back(std::to_string(i)); - } - - int red_value = 0; - if (m_options && m_options->persistenceManager) - { - std::string key = ColorSettingsMenuOptions::RED + m_suffix; - red_value = m_options->persistenceManager->GetValue(key, red_value); - } - addSelection(ColorSettingsMenuItem::RED, "Rot", values, red_value); - - int green_value = 0; - if (m_options && m_options->persistenceManager) - { - std::string key = ColorSettingsMenuOptions::GREEN + m_suffix; - green_value = m_options->persistenceManager->GetValue(key, green_value); - } - addSelection(ColorSettingsMenuItem::GREEN, "Gruen", values, green_value); - - int blue_value = 0; - if (m_options && m_options->persistenceManager) - { - std::string key = ColorSettingsMenuOptions::BLUE + m_suffix; - blue_value = m_options->persistenceManager->GetValue(key, blue_value); - } - addSelection(ColorSettingsMenuItem::BLUE, "Blau", values, blue_value); -} - -void ColorSettingsMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType button) -{ - switch (menuItem.getId()) - { - case ColorSettingsMenuItem::RED: - if (button == ButtonType::LEFT || button == ButtonType::RIGHT) - { - const auto item = switchValue(menuItem, button); - const auto value = getItem(item.getId()).getIndex(); - if (m_options && m_options->persistenceManager) - { - std::string key = ColorSettingsMenuOptions::RED + m_suffix; - m_options->persistenceManager->SetValue(key, value); - } - } - break; - - case ColorSettingsMenuItem::GREEN: - if (button == ButtonType::LEFT || button == ButtonType::RIGHT) - { - const auto item = switchValue(menuItem, button); - const auto value = getItem(item.getId()).getIndex(); - if (m_options && m_options->persistenceManager) - { - std::string key = ColorSettingsMenuOptions::GREEN + m_suffix; - m_options->persistenceManager->SetValue(key, value); - } - } - break; - - case ColorSettingsMenuItem::BLUE: - if (button == ButtonType::LEFT || button == ButtonType::RIGHT) - { - const auto item = switchValue(menuItem, button); - const auto value = getItem(item.getId()).getIndex(); - if (m_options && m_options->persistenceManager) - { - std::string key = ColorSettingsMenuOptions::BLUE + m_suffix; - m_options->persistenceManager->SetValue(key, value); - } - } - break; - } -} - -void ColorSettingsMenu::onExit() -{ - if (m_options && m_options->persistenceManager) - { - m_options->persistenceManager->Save(); - - led_event_data_t payload = {.value = 42}; - send_event(EVENT_LED_REFRESH, &payload); - } -} diff --git a/firmware/components/insa/src/common/Menu.cpp b/firmware/components/insa/src/common/Menu.cpp index 67703c5..3f5742a 100644 --- a/firmware/components/insa/src/common/Menu.cpp +++ b/firmware/components/insa/src/common/Menu.cpp @@ -29,7 +29,7 @@ constexpr int BOTTOM_OFFSET = 10; Menu::Menu(menu_options_t *options) : Widget(options->u8g2), m_options(options) { // Set up button callback using lambda to forward to member function - m_options->onButtonClicked = [this](const ButtonType button) { onButtonClicked(button); }; + m_options->onButtonClicked = [this](const ButtonType button) { OnButtonClicked(button); }; } Menu::~Menu() @@ -126,7 +126,7 @@ MenuItem Menu::replaceItem(const int index, const MenuItem &item) return item; } -void Menu::render() +void Menu::Render() { // Initialize selection if not set if (m_selected_item >= m_items.size() && !m_items.empty()) @@ -232,7 +232,7 @@ void Menu::renderWidget(const MenuItem *item, const uint8_t *font, const int x, } } -void Menu::onButtonClicked(const ButtonType button) +void Menu::OnButtonClicked(const ButtonType button) { // Map button input to navigation functions switch (button) @@ -362,7 +362,7 @@ void Menu::drawScrollBar() const // Create scrollbar instance ScrollBar scrollBar(m_options, u8g2->width - UIConstants::SCROLLBAR_WIDTH, 3, 1, u8g2->height - 6); scrollBar.refresh(m_selected_item, m_items.size()); - scrollBar.render(); + scrollBar.Render(); } void Menu::drawSelectionBox() const diff --git a/firmware/components/insa/src/common/ScrollBar.cpp b/firmware/components/insa/src/common/ScrollBar.cpp index 5881eba..20da5c8 100644 --- a/firmware/components/insa/src/common/ScrollBar.cpp +++ b/firmware/components/insa/src/common/ScrollBar.cpp @@ -7,7 +7,7 @@ ScrollBar::ScrollBar(const menu_options_t *options, const size_t x, const size_t { } -void ScrollBar::render() +void ScrollBar::Render() { if (m_max <= 1) { diff --git a/firmware/components/insa/src/common/Widget.cpp b/firmware/components/insa/src/common/Widget.cpp index a5da811..64750e6 100644 --- a/firmware/components/insa/src/common/Widget.cpp +++ b/firmware/components/insa/src/common/Widget.cpp @@ -20,14 +20,14 @@ void Widget::onExit() { } -void Widget::update(uint64_t dt) +void Widget::Update(uint64_t dt) { } -void Widget::render() +void Widget::Render() { } -void Widget::onButtonClicked(ButtonType button) +void Widget::OnButtonClicked(ButtonType button) { } diff --git a/firmware/components/insa/src/ui/ClockScreenSaver.cpp b/firmware/components/insa/src/ui/ClockScreenSaver.cpp index c25a307..fa63b0a 100644 --- a/firmware/components/insa/src/ui/ClockScreenSaver.cpp +++ b/firmware/components/insa/src/ui/ClockScreenSaver.cpp @@ -1,4 +1,5 @@ #include "ui/ClockScreenSaver.h" +#include "simulator.h" #include #include @@ -36,17 +37,25 @@ void ClockScreenSaver::updateTextDimensions() void ClockScreenSaver::getCurrentTimeString(char *buffer, size_t bufferSize) const { - time_t rawtime; - struct tm *timeinfo; + char *simulated_time = get_time(); + if (simulated_time != nullptr) + { + strncpy(buffer, simulated_time, bufferSize); + } + else + { + time_t rawtime; + struct tm *timeinfo; - time(&rawtime); - timeinfo = localtime(&rawtime); + time(&rawtime); + timeinfo = localtime(&rawtime); - // Format time as HH:MM:SS - strftime(buffer, bufferSize, "%H:%M:%S", timeinfo); + // Format time as HH:MM:SS + strftime(buffer, bufferSize, "%H:%M:%S", timeinfo); + } } -void ClockScreenSaver::update(const uint64_t dt) +void ClockScreenSaver::Update(const uint64_t dt) { m_moveTimer += dt; @@ -94,7 +103,7 @@ void ClockScreenSaver::checkBoundaryCollision() } } -void ClockScreenSaver::render() +void ClockScreenSaver::Render() { // Clear screen with a black background u8g2_SetDrawColor(u8g2, 0); @@ -112,7 +121,7 @@ void ClockScreenSaver::render() u8g2_DrawStr(u8g2, m_posX, m_posY, timeBuffer); } -void ClockScreenSaver::onButtonClicked(ButtonType button) +void ClockScreenSaver::OnButtonClicked(ButtonType button) { // Exit screensaver on any button press if (m_options && m_options->popScreen) diff --git a/firmware/components/insa/src/ui/DayColorSettingsMenu.cpp b/firmware/components/insa/src/ui/DayColorSettingsMenu.cpp deleted file mode 100644 index e5f02e0..0000000 --- a/firmware/components/insa/src/ui/DayColorSettingsMenu.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "ui/DayColorSettingsMenu.h" - -DayColorSettingsMenu::DayColorSettingsMenu(menu_options_t *options) : ColorSettingsMenu(options, "day") -{ -} diff --git a/firmware/components/insa/src/ui/LightMenu.cpp b/firmware/components/insa/src/ui/LightMenu.cpp index 3ec9c5b..f3c0eef 100644 --- a/firmware/components/insa/src/ui/LightMenu.cpp +++ b/firmware/components/insa/src/ui/LightMenu.cpp @@ -1,7 +1,6 @@ #include "ui/LightMenu.h" -#include "led_manager.h" -#include "ui/LightSettingsMenu.h" +#include "led_strip_ws2812.h" /** * @namespace LightMenuItem @@ -9,9 +8,8 @@ */ namespace LightMenuItem { -constexpr auto ACTIVATE = 0; ///< ID for the light activation toggle -constexpr auto MODE = 1; ///< ID for the light mode selection -constexpr auto LED_SETTINGS = 2; ///< ID for the LED settings menu item +constexpr auto ACTIVATE = 0; ///< ID for the light activation toggle +constexpr auto MODE = 1; ///< ID for the light mode selection } // namespace LightMenuItem namespace LightMenuOptions @@ -30,19 +28,17 @@ LightMenu::LightMenu(menu_options_t *options) : Menu(options), m_options(options } addToggle(LightMenuItem::ACTIVATE, "Einschalten", active); - // Create mode selection options (Day/Night modes) - std::vector values; - values.emplace_back("Tag"); // Day mode - values.emplace_back("Nacht"); // Night mode + // Create mode selection options (Simulation/Day/Night modes) + std::vector items; + items.emplace_back("Simulation"); // Simulation mode + items.emplace_back("Tag"); // Day mode + items.emplace_back("Nacht"); // Night mode int mode_value = 0; if (m_options && m_options->persistenceManager) { mode_value = m_options->persistenceManager->GetValue(LightMenuOptions::LIGHT_MODE, mode_value); } - addSelection(LightMenuItem::MODE, "Modus", values, mode_value); - - // Add menu item for accessing LED settings submenu - addText(LightMenuItem::LED_SETTINGS, "Einstellungen"); + addSelection(LightMenuItem::MODE, "Modus", items, mode_value); } void LightMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType button) @@ -58,14 +54,13 @@ void LightMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType butto { toggle(menuItem); const auto value = getItem(menuItem.getId()).getValue() == "1"; - led_event_data_t payload = {.value = 42}; if (value) { - send_event(EVENT_LED_ON, &payload); + led_strip_update(LED_STATE_DAY, rgb_t{}); } else { - send_event(EVENT_LED_OFF, &payload); + led_strip_update(LED_STATE_OFF, rgb_t{}); } if (m_options && m_options->persistenceManager) @@ -88,17 +83,7 @@ void LightMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType butto m_options->persistenceManager->Save(); } - led_event_data_t payload = {.value = value}; - send_event(EVENT_LED_DAY + value, &payload); - } - break; - } - - case LightMenuItem::LED_SETTINGS: { - // Open the LED settings submenu when SELECT is pressed - if (button == ButtonType::SELECT) - { - widget = std::make_shared(m_options); + led_strip_update(value == 0 ? LED_STATE_DAY : LED_STATE_NIGHT, rgb_t{}); } break; } @@ -113,4 +98,4 @@ void LightMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType butto { m_options->pushScreen(widget); } -} \ No newline at end of file +} diff --git a/firmware/components/insa/src/ui/LightSettingsMenu.cpp b/firmware/components/insa/src/ui/LightSettingsMenu.cpp deleted file mode 100644 index b8440e1..0000000 --- a/firmware/components/insa/src/ui/LightSettingsMenu.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include "ui/LightSettingsMenu.h" - -#include "common/Common.h" -#include "ui/DayColorSettingsMenu.h" -#include "ui/NightColorSettingsMenu.h" - -/** - * @namespace LightSettingsMenuItem - * @brief Constants for light settings menu item identifiers - */ -namespace LightSettingsMenuItem -{ -constexpr uint8_t RGB_SETTING_DAY = 0; -constexpr uint8_t RGB_SETTING_NIGHT = 1; -constexpr uint8_t SECTION_COUNTER = 2; -} // namespace LightSettingsMenuItem - -std::string LightSettingsMenu::CreateKey(const int index) -{ - constexpr int key_length = 20; - char key[key_length] = ""; - snprintf(key, key_length, "section_%d", index); - return key; -} - -LightSettingsMenu::LightSettingsMenu(menu_options_t *options) : Menu(options), m_options(options) -{ - addText(LightSettingsMenuItem::RGB_SETTING_DAY, "Tag (Farbe)"); - addText(LightSettingsMenuItem::RGB_SETTING_NIGHT, "Nacht (Farbe)"); - - /* - // Create values vector for section counts (1-99) - std::vector values; - for (size_t i = 1; i <= 99; i++) - { - values.emplace_back(std::to_string(i)); - } - - // Add section counter selection (allows choosing number of sections) - auto value = 7; - if (m_options && m_options->persistenceManager) - { - value = m_options->persistenceManager->GetValue(CreateKey(0), value); - } - addSelection(LightSettingsMenuItem::SECTION_COUNTER, "Sektionen", values, value); - - setItemSize(std::stoull(getItem(LightSettingsMenuItem::SECTION_COUNTER).getValue()), - LightSettingsMenuItem::SECTION_COUNTER); - */ -} - -void LightSettingsMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType button) -{ - std::shared_ptr widget; - - switch (button) - { - case ButtonType::SELECT: - switch (menuItem.getId()) - { - case LightSettingsMenuItem::RGB_SETTING_DAY: - widget = std::make_shared(m_options); - break; - - case LightSettingsMenuItem::RGB_SETTING_NIGHT: - widget = std::make_shared(m_options); - break; - - default: - break; - } - - if (m_options && m_options->pushScreen) - { - m_options->pushScreen(widget); - } - break; - - case ButtonType::RIGHT: - case ButtonType::LEFT: - // Handle value switching for the current menu item - switchValue(menuItem, button); - - // Update the section list size based on the section counter value - if (menuItem.getId() == LightSettingsMenuItem::SECTION_COUNTER) - { - setItemSize(std::stoull(getItem(LightSettingsMenuItem::SECTION_COUNTER).getValue()), - LightSettingsMenuItem::SECTION_COUNTER); - } - - // Persist the changed section values if persistence is available - if (m_options && m_options->persistenceManager) - { - const auto value = getItem(menuItem.getId()).getIndex(); - m_options->persistenceManager->SetValue(CreateKey(menuItem.getId()), value); - } - break; - - default: - break; - } -} diff --git a/firmware/components/insa/src/ui/NightColorSettingsMenu.cpp b/firmware/components/insa/src/ui/NightColorSettingsMenu.cpp deleted file mode 100644 index 1a42968..0000000 --- a/firmware/components/insa/src/ui/NightColorSettingsMenu.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "ui/NightColorSettingsMenu.h" - -NightColorSettingsMenu::NightColorSettingsMenu(menu_options_t *options) : ColorSettingsMenu(options, "night") -{ -} \ No newline at end of file diff --git a/firmware/components/insa/src/ui/ScreenSaver.cpp b/firmware/components/insa/src/ui/ScreenSaver.cpp index 67a1500..16c384e 100644 --- a/firmware/components/insa/src/ui/ScreenSaver.cpp +++ b/firmware/components/insa/src/ui/ScreenSaver.cpp @@ -20,7 +20,7 @@ void ScreenSaver::initVehicles() } } -void ScreenSaver::update(const uint64_t dt) +void ScreenSaver::Update(const uint64_t dt) { m_animationCounter += dt; m_lastSpawnTime += dt; @@ -214,7 +214,7 @@ ScreenSaver::Direction ScreenSaver::getRandomDirection() return (random() % 2 == 0) ? Direction::LEFT : Direction::RIGHT; } -void ScreenSaver::render() +void ScreenSaver::Render() { // Clear screen with a black background u8g2_SetDrawColor(u8g2, 0); @@ -320,7 +320,7 @@ const unsigned char *ScreenSaver::getVehicleBitmap(const VehicleType type, const } } -void ScreenSaver::onButtonClicked(ButtonType button) +void ScreenSaver::OnButtonClicked(ButtonType button) { if (m_options && m_options->popScreen) { diff --git a/firmware/components/insa/src/ui/SplashScreen.cpp b/firmware/components/insa/src/ui/SplashScreen.cpp index a380f48..b1e3392 100644 --- a/firmware/components/insa/src/ui/SplashScreen.cpp +++ b/firmware/components/insa/src/ui/SplashScreen.cpp @@ -8,7 +8,7 @@ SplashScreen::SplashScreen(menu_options_t *options) : Widget(options->u8g2), m_o { } -void SplashScreen::update(const uint64_t dt) +void SplashScreen::Update(const uint64_t dt) { splashTime += dt; if (splashTime > 100) @@ -20,7 +20,7 @@ void SplashScreen::update(const uint64_t dt) } } -void SplashScreen::render() +void SplashScreen::Render() { u8g2_SetFont(u8g2, u8g2_font_DigitalDisco_tr); u8g2_DrawStr(u8g2, 28, u8g2->height / 2 - 10, "HO Anlage"); diff --git a/firmware/components/led-manager/CMakeLists.txt b/firmware/components/led-manager/CMakeLists.txt index 6a6cdd5..0ee439c 100644 --- a/firmware/components/led-manager/CMakeLists.txt +++ b/firmware/components/led-manager/CMakeLists.txt @@ -1,6 +1,6 @@ idf_component_register(SRCS - src/led_manager.cpp src/led_status.c + src/led_strip_ws2812.c INCLUDE_DIRS "include" PRIV_REQUIRES insa @@ -8,4 +8,5 @@ idf_component_register(SRCS esp_event esp_timer persistence-manager + simulator ) diff --git a/firmware/components/led-manager/Kconfig b/firmware/components/led-manager/Kconfig index 65ca2c4..e70be74 100644 --- a/firmware/components/led-manager/Kconfig +++ b/firmware/components/led-manager/Kconfig @@ -10,4 +10,10 @@ menu "Led Manager Configuration" default 2 help The number of the status WLED pin. + + config LED_STRIP_MAX_LEDS + int "Maximum number of LEDs" + default 500 + help + The maximum number of LEDs that can be controlled. endmenu diff --git a/firmware/components/led-manager/include/color.h b/firmware/components/led-manager/include/color.h new file mode 100644 index 0000000..dae761d --- /dev/null +++ b/firmware/components/led-manager/include/color.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +typedef struct +{ + uint8_t red; + uint8_t green; + uint8_t blue; +} rgb_t; + +void interpolate_color(const rgb_t start_color, const rgb_t end_color, float fraction, rgb_t *out_color); diff --git a/firmware/components/led-manager/include/led_manager.h b/firmware/components/led-manager/include/led_manager.h deleted file mode 100644 index 4fd25a2..0000000 --- a/firmware/components/led-manager/include/led_manager.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include - -enum -{ - EVENT_LED_ON, - EVENT_LED_OFF, - EVENT_LED_DAY, - EVENT_LED_NIGHT, - EVENT_LED_REFRESH -}; - -typedef struct -{ - int value; -} led_event_data_t; - -uint64_t wled_init(); - -uint64_t register_handler(); - -uint64_t send_event(uint32_t event, led_event_data_t *payload); diff --git a/firmware/components/led-manager/include/led_status.h b/firmware/components/led-manager/include/led_status.h index f3dfeda..1e312d2 100644 --- a/firmware/components/led-manager/include/led_status.h +++ b/firmware/components/led-manager/include/led_status.h @@ -1,5 +1,6 @@ #pragma once +#include "color.h" #include "esp_check.h" #include @@ -14,14 +15,6 @@ typedef enum LED_MODE_BLINK } led_mode_t; -// Structure for an RGB color -typedef struct -{ - uint8_t r; - uint8_t g; - uint8_t b; -} rgb_t; - // This is the structure you pass from the outside to define a behavior typedef struct { @@ -31,28 +24,23 @@ typedef struct uint32_t off_time_ms; // Only relevant for BLINK } led_behavior_t; -#ifdef __cplusplus -extern "C" -{ -#endif - /** - * @brief Initializes the status manager and the LED strip. - * - * @param gpio_num GPIO where the data line of the LEDs is connected. - * @return esp_err_t ESP_OK on success. - */ - esp_err_t led_status_init(int gpio_num); +__BEGIN_DECLS +/** + * @brief Initializes the status manager and the LED strip. + * + * @param gpio_num GPIO where the data line of the LEDs is connected. + * @return esp_err_t ESP_OK on success. + */ +esp_err_t led_status_init(int gpio_num); - /** - * @brief Sets the lighting behavior for a single LED. - * - * This function is thread-safe. - * - * @param index Index of the LED (0 to STATUS_LED_COUNT - 1). - * @param behavior The structure with the desired behavior. - * @return esp_err_t ESP_OK on success, ESP_ERR_INVALID_ARG on invalid index. - */ - esp_err_t led_status_set_behavior(uint8_t index, led_behavior_t behavior); -#ifdef __cplusplus -} -#endif +/** + * @brief Sets the lighting behavior for a single LED. + * + * This function is thread-safe. + * + * @param index Index of the LED (0 to STATUS_LED_COUNT - 1). + * @param behavior The structure with the desired behavior. + * @return esp_err_t ESP_OK on success, ESP_ERR_INVALID_ARG on invalid index. + */ +esp_err_t led_status_set_behavior(uint8_t index, led_behavior_t behavior); +__END_DECLS diff --git a/firmware/components/led-manager/include/led_strip_ws2812.h b/firmware/components/led-manager/include/led_strip_ws2812.h new file mode 100644 index 0000000..88e80fd --- /dev/null +++ b/firmware/components/led-manager/include/led_strip_ws2812.h @@ -0,0 +1,18 @@ +#pragma once + +#include "color.h" +#include +#include + +typedef enum +{ + LED_STATE_OFF, + LED_STATE_DAY, + LED_STATE_NIGHT, + LED_STATE_SIMULATION, +} led_state_t; + +__BEGIN_DECLS +esp_err_t led_strip_init(void); +esp_err_t led_strip_update(led_state_t state, rgb_t color); +__END_DECLS diff --git a/firmware/components/led-manager/src/color.c b/firmware/components/led-manager/src/color.c new file mode 100644 index 0000000..6bbaecb --- /dev/null +++ b/firmware/components/led-manager/src/color.c @@ -0,0 +1,8 @@ +#include "color.h" + +void interpolate_color(const rgb_t start_color, const rgb_t end_color, float fraction, rgb_t *out_color) +{ + out_color->r = start_color.r + (end_color.r - start_color.r) * fraction; + out_color->g = start_color.g + (end_color.g - start_color.g) * fraction; + out_color->b = start_color.b + (end_color.b - start_color.b) * fraction; +} \ No newline at end of file diff --git a/firmware/components/led-manager/src/led_manager.cpp b/firmware/components/led-manager/src/led_manager.cpp deleted file mode 100644 index 56e022e..0000000 --- a/firmware/components/led-manager/src/led_manager.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "led_manager.h" - -#include "common/ColorSettingsMenu.h" -#include "esp_event.h" -#include "esp_log.h" -#include "hal_esp32/PersistenceManager.h" -#include "led_status.h" -#include "led_strip.h" -#include "sdkconfig.h" - -led_strip_handle_t led_strip; - -static const int value = 125; -static const uint32_t max_leds = 500; - -ESP_EVENT_DECLARE_BASE(LED_EVENTS_BASE); -ESP_EVENT_DEFINE_BASE(LED_EVENTS_BASE); - -esp_event_loop_handle_t loop_handle; - -const char *TAG = "led_manager"; - -uint64_t wled_init(void) -{ - led_strip_config_t strip_config = { - .strip_gpio_num = CONFIG_WLED_DIN_PIN, - .max_leds = max_leds, - .led_model = LED_MODEL_WS2812, - .color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB, - .flags = - { - .invert_out = false, - }, - }; - - led_strip_rmt_config_t rmt_config = { - .clk_src = RMT_CLK_SRC_DEFAULT, - .resolution_hz = 0, - .mem_block_symbols = 0, - .flags = - { - .with_dma = true, - }, - }; - - ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip)); - - return ESP_OK; -} - -void event_handler(void *arg, esp_event_base_t base, int32_t id, void *event_data) -{ - uint8_t red = 0; - uint8_t green = 0; - uint8_t blue = 0; - - if (id != EVENT_LED_OFF) - { - auto persistenceManager = PersistenceManager(); - persistenceManager.Load(); - - auto mode = persistenceManager.GetValue("light_mode", 0); - auto light_mode = (mode == 0) ? "day" : "night"; - red = persistenceManager.GetValue(std::string(ColorSettingsMenuOptions::RED) + light_mode, value); - green = persistenceManager.GetValue(std::string(ColorSettingsMenuOptions::GREEN) + light_mode, value); - blue = persistenceManager.GetValue(std::string(ColorSettingsMenuOptions::BLUE) + light_mode, value); - } - - for (uint32_t i = 0; i < max_leds; i++) - { - led_strip_set_pixel(led_strip, i, red, green, blue); - } - led_strip_refresh(led_strip); - - led_behavior_t led2_behavior = { - .mode = LED_MODE_SOLID, .color = {.r = red, .g = green, .b = blue}, .on_time_ms = 0, .off_time_ms = 0}; - led_status_set_behavior(2, led2_behavior); -} - -uint64_t register_handler(void) -{ - esp_event_loop_args_t loop_args = { - .queue_size = 2, .task_name = "led_manager", .task_priority = 5, .task_stack_size = 4096, .task_core_id = 1}; - esp_event_loop_create(&loop_args, &loop_handle); - - esp_event_handler_register_with(loop_handle, LED_EVENTS_BASE, ESP_EVENT_ANY_ID, event_handler, NULL); - return ESP_OK; -} - -uint64_t send_event(uint32_t event, led_event_data_t *payload) -{ - if (payload == nullptr) - { - return ESP_ERR_INVALID_ARG; - } - - esp_err_t err = esp_event_post_to(loop_handle, // Event loop handle - LED_EVENTS_BASE, // Event base - event, // Event ID (EVENT_LED_ON, EVENT_LED_OFF, etc.) - payload, // Data pointer - sizeof(led_event_data_t), // Data size - portMAX_DELAY // Wait time - ); - - if (err != ESP_OK) - { - ESP_LOGE("LED", "Failed to post event: %s", esp_err_to_name(err)); - return err; - } - - return ESP_OK; -} diff --git a/firmware/components/led-manager/src/led_status.c b/firmware/components/led-manager/src/led_status.c index ec1db87..f2b54d4 100644 --- a/firmware/components/led-manager/src/led_status.c +++ b/firmware/components/led-manager/src/led_status.c @@ -46,8 +46,8 @@ static void led_status_task(void *pvParameters) break; case LED_MODE_SOLID: - led_strip_set_pixel(led_strip, i, control->behavior.color.r, control->behavior.color.g, - control->behavior.color.b); + led_strip_set_pixel(led_strip, i, control->behavior.color.red, control->behavior.color.green, + control->behavior.color.blue); break; case LED_MODE_BLINK: { @@ -61,8 +61,8 @@ static void led_status_task(void *pvParameters) if (control->is_on_in_blink) { - led_strip_set_pixel(led_strip, i, control->behavior.color.r, control->behavior.color.g, - control->behavior.color.b); + led_strip_set_pixel(led_strip, i, control->behavior.color.red, control->behavior.color.green, + control->behavior.color.blue); } else { @@ -119,7 +119,7 @@ esp_err_t led_status_init(int gpio_num) } // Start task - xTaskCreate(led_status_task, "led_status_task", 2048, NULL, 5, NULL); + xTaskCreate(led_status_task, "led_status_task", 2048, NULL, tskIDLE_PRIORITY + 1, NULL); return ESP_OK; } diff --git a/firmware/components/led-manager/src/led_strip_ws2812.c b/firmware/components/led-manager/src/led_strip_ws2812.c new file mode 100644 index 0000000..76eb48e --- /dev/null +++ b/firmware/components/led-manager/src/led_strip_ws2812.c @@ -0,0 +1,111 @@ +#include "led_strip_ws2812.h" +#include "color.h" +#include "led_status.h" +#include +#include +#include +#include +#include +#include + +static const char *TAG = "led_strip"; + +static led_strip_handle_t led_strip; +static QueueHandle_t led_command_queue; + +static const uint32_t MAX_LEDS = CONFIG_LED_STRIP_MAX_LEDS; + +typedef struct +{ + led_state_t state; + rgb_t color; +} led_command_t; + +static void set_all_pixels(const rgb_t color) +{ + for (uint32_t i = 0; i < MAX_LEDS; i++) + { + led_strip_set_pixel(led_strip, i, color.red, color.green, color.blue); + } + led_strip_refresh(led_strip); + + led_behavior_t led2_behavior = {.mode = LED_MODE_SOLID, + .color = {.red = color.red, .green = color.green, .blue = color.blue}}; + led_status_set_behavior(2, led2_behavior); +} + +void led_strip_task(void *pvParameters) +{ + led_state_t current_state = LED_STATE_OFF; + led_command_t cmd; + + for (;;) + { + TickType_t wait_ticks = (current_state == LED_STATE_SIMULATION) ? pdMS_TO_TICKS(50) : portMAX_DELAY; + if (xQueueReceive(led_command_queue, &cmd, wait_ticks) == pdPASS) + { + current_state = cmd.state; + } + + rgb_t color; + switch (current_state) + { + case LED_STATE_OFF: + color = (rgb_t){.red = 0, .green = 0, .blue = 0}; + break; + default: + color = cmd.color; + break; + } + + set_all_pixels(color); + } +}; + +esp_err_t led_strip_init(void) +{ + led_strip_config_t strip_config = { + .strip_gpio_num = CONFIG_WLED_DIN_PIN, + .max_leds = MAX_LEDS, + .led_model = LED_MODEL_WS2812, + .color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB, + .flags = {.invert_out = false}, + }; + + led_strip_rmt_config_t rmt_config = { + .clk_src = RMT_CLK_SRC_DEFAULT, + .resolution_hz = 0, + .mem_block_symbols = 0, + .flags = {.with_dma = true}, + }; + + ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip)); + + led_command_queue = xQueueCreate(5, sizeof(led_command_t)); + if (led_command_queue == NULL) + { + ESP_LOGE(TAG, "Failed to create command queue"); + return ESP_FAIL; + } + + xTaskCreate(led_strip_task, "led_strip_task", 4096, NULL, tskIDLE_PRIORITY + 1, NULL); + + ESP_LOGI(TAG, "LED strip initialized"); + + return ESP_OK; +} + +esp_err_t led_strip_update(led_state_t state, rgb_t color) +{ + led_command_t cmd = { + .state = state, + .color = color, + }; + + if (xQueueSend(led_command_queue, &cmd, pdMS_TO_TICKS(100)) != pdPASS) + { + ESP_LOGE(TAG, "Failed to send command to LED manager queue"); + return ESP_FAIL; + } + return ESP_OK; +} diff --git a/firmware/components/simulator/CMakeLists.txt b/firmware/components/simulator/CMakeLists.txt index 796658f..1a87221 100644 --- a/firmware/components/simulator/CMakeLists.txt +++ b/firmware/components/simulator/CMakeLists.txt @@ -1,6 +1,6 @@ idf_component_register(SRCS - "simulator.c" - "storage.c" + "src/simulator.c" + "src/storage.c" INCLUDE_DIRS "include" PRIV_REQUIRES led-manager diff --git a/firmware/components/simulator/include/simulator.h b/firmware/components/simulator/include/simulator.h index b6ea299..05585d6 100644 --- a/firmware/components/simulator/include/simulator.h +++ b/firmware/components/simulator/include/simulator.h @@ -3,15 +3,18 @@ #include "esp_check.h" #include -esp_err_t add_light_item(const char time[5], uint8_t red, uint8_t green, uint8_t blue); - -void cleanup_light_items(void); - -#ifdef __cplusplus -extern "C" +// Configuration structure for the simulation +typedef struct { -#endif - void simulate(void *args); -#ifdef __cplusplus -} -#endif + int cycle_duration_minutes; +} simulation_config_t; + +__BEGIN_DECLS +char *get_time(void); + +esp_err_t add_light_item(const char time[5], uint8_t red, uint8_t green, uint8_t blue); +void cleanup_light_items(void); +void start_simulate_day(void); +void start_simulate_night(void); +void start_simulation_task(void); +__END_DECLS diff --git a/firmware/components/simulator/simulator.c b/firmware/components/simulator/simulator.c deleted file mode 100644 index 96d32ec..0000000 --- a/firmware/components/simulator/simulator.c +++ /dev/null @@ -1,120 +0,0 @@ -#include "simulator.h" - -#include "esp_heap_caps.h" -#include "esp_log.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "led_status.h" -#include "storage.h" -#include -#include -#include - -static const char *TAG = "simulator"; - -// The struct is extended with a 'next' pointer to form a linked list. -typedef struct light_item_node_t -{ - char time[5]; - uint8_t red; - uint8_t green; - uint8_t blue; - struct light_item_node_t *next; -} light_item_node_t; - -// Global pointers for the head and tail of the list. -static light_item_node_t *head = NULL; -static light_item_node_t *tail = NULL; - -esp_err_t add_light_item(const char time[5], uint8_t red, uint8_t green, uint8_t blue) -{ - // Allocate memory for a new node in PSRAM. - light_item_node_t *new_node = (light_item_node_t *)heap_caps_malloc(sizeof(light_item_node_t), MALLOC_CAP_SPIRAM); - if (new_node == NULL) - { - ESP_LOGE(TAG, "Failed to allocate memory in PSRAM for new light_item_node_t."); - return ESP_FAIL; - } - - // Initialize the data of the new node. - memcpy(new_node->time, time, sizeof(new_node->time)); - new_node->red = red; - new_node->green = green; - new_node->blue = blue; - new_node->next = NULL; - - // Append the new node to the end of the list. - if (head == NULL) - { - // If the list is empty, the new node becomes both head and tail. - head = new_node; - tail = new_node; - } - else - { - // Otherwise, append the new node to the end and update tail. - tail->next = new_node; - tail = new_node; - } - - return ESP_OK; -} - -void cleanup_light_items(void) -{ - light_item_node_t *current = head; - light_item_node_t *next_node; - - while (current != NULL) - { - next_node = current->next; - heap_caps_free(current); - current = next_node; - } - - head = NULL; - tail = NULL; - ESP_LOGI(TAG, "Cleaned up all light items."); -} - -void simulate(void *args) -{ - ESP_LOGI(TAG, "Simulation task started with args: %p", args); - - initialize_storage(); - load_file("/spiffs/schema_02.csv"); - - if (head == NULL) - { - ESP_LOGW(TAG, "Light schedule is empty. Simulation will not run."); - vTaskDelete(NULL); - return; - } - - ESP_LOGI(TAG, "Starting simulation loop."); - light_item_node_t *current_item = head; - - while (1) - { - if (current_item == NULL) - { - current_item = head; - ESP_LOGI(TAG, "Reached end of schedule, restarting from head."); - } - - ESP_LOGI(TAG, "Simulating time: %s -> R:%d, G:%d, B:%d", current_item->time, current_item->red, - current_item->green, current_item->blue); - led_behavior_t led1_behavior = { - .mode = LED_MODE_SOLID, - .color = {.r = current_item->red, .g = current_item->green, .b = current_item->blue}, - .on_time_ms = 0, - .off_time_ms = 0}; - led_status_set_behavior(1, led1_behavior); - - current_item = current_item->next; - - vTaskDelay(pdMS_TO_TICKS(1000)); - } - - cleanup_light_items(); -} diff --git a/firmware/components/simulator/src/simulator.c b/firmware/components/simulator/src/simulator.c new file mode 100644 index 0000000..68ee606 --- /dev/null +++ b/firmware/components/simulator/src/simulator.c @@ -0,0 +1,245 @@ +#include "simulator.h" + +#include "color.h" +#include "led_strip_ws2812.h" +#include "storage.h" +#include +#include +#include +#include +#include +#include +#include + +static const char *TAG = "simulator"; +static char *time; + +static char *time_to_string(int hhmm) +{ + static char buffer[20]; + snprintf(buffer, sizeof(buffer), "%02d:%02d Uhr", hhmm / 100, hhmm % 100); + return buffer; +} + +static TaskHandle_t simulation_task_handle = NULL; + +// The struct is extended with a 'next' pointer to form a linked list. +typedef struct light_item_node_t +{ + char time[5]; + uint8_t red; + uint8_t green; + uint8_t blue; + struct light_item_node_t *next; +} light_item_node_t; + +// Global pointers for the head and tail of the list. +static light_item_node_t *head = NULL; +static light_item_node_t *tail = NULL; + +char *get_time(void) +{ + return time; +} + +esp_err_t add_light_item(const char time[5], uint8_t red, uint8_t green, uint8_t blue) +{ + // Allocate memory for a new node in PSRAM. + light_item_node_t *new_node = (light_item_node_t *)heap_caps_malloc(sizeof(light_item_node_t), MALLOC_CAP_SPIRAM); + if (new_node == NULL) + { + ESP_LOGE(TAG, "Failed to allocate memory in PSRAM for new light_item_node_t."); + return ESP_FAIL; + } + + // Initialize the data of the new node. + memcpy(new_node->time, time, sizeof(new_node->time)); + new_node->red = red; + new_node->green = green; + new_node->blue = blue; + new_node->next = NULL; + + // Append the new node to the end of the list. + if (head == NULL) + { + // If the list is empty, the new node becomes both head and tail. + head = new_node; + tail = new_node; + } + else + { + // Otherwise, append the new node to the end and update tail. + tail->next = new_node; + tail = new_node; + } + + return ESP_OK; +} + +void cleanup_light_items(void) +{ + light_item_node_t *current = head; + light_item_node_t *next_node; + + while (current != NULL) + { + next_node = current->next; + heap_caps_free(current); + current = next_node; + } + + head = NULL; + tail = NULL; + ESP_LOGI(TAG, "Cleaned up all light items."); +} + +static void initialize_light_items(void) +{ + if (head != NULL) + { + ESP_LOGI(TAG, "Light schedule already initialized."); + return; + } + + initialize_storage(); + load_file("/spiffs/schema_02.csv"); + + if (head == NULL) + { + ESP_LOGW(TAG, "Light schedule is empty. Simulation will not run."); + vTaskDelete(NULL); + return; + } +} + +static light_item_node_t *find_best_light_item_for_time(int hhmm) +{ + light_item_node_t *best_item = NULL; + light_item_node_t *current = head; + int best_time = -1; + + while (current != NULL) + { + int current_time = atoi(current->time); + if (current_time <= hhmm && current_time > best_time) + { + best_time = current_time; + best_item = current; + } + current = current->next; + } + + if (best_item == NULL) + { + ESP_LOGW(TAG, "No suitable light item found for time up to %04d", hhmm); + } + else + { + ESP_LOGD(TAG, "Best light item for time %04d is %s", hhmm, best_item->time); + } + + return best_item; +} + +void start_simulate_day(void) +{ + initialize_light_items(); + + light_item_node_t *current_item = find_best_light_item_for_time(1200); + if (current_item != NULL) + { + led_strip_update(LED_STATE_DAY, + (rgb_t){.red = current_item->red, .green = current_item->green, .blue = current_item->blue}); + } +} + +void start_simulate_night(void) +{ + initialize_light_items(); + + light_item_node_t *current_item = find_best_light_item_for_time(0); + if (current_item != NULL) + { + led_strip_update(LED_STATE_NIGHT, + (rgb_t){.red = current_item->red, .green = current_item->green, .blue = current_item->blue}); + } +} + +void simulate_cycle(void *args) +{ + simulation_config_t *config = (simulation_config_t *)args; + int cycle_duration_minutes = config->cycle_duration_minutes; + heap_caps_free(config); + + if (cycle_duration_minutes <= 0) + { + ESP_LOGE(TAG, "Invalid cycle duration: %d minutes. Must be positive.", cycle_duration_minutes); + vTaskDelete(NULL); + return; + } + + initialize_light_items(); + + const int total_minutes_in_day = 24 * 60; + long delay_ms = (long)cycle_duration_minutes * 60 * 1000 / total_minutes_in_day; + ESP_LOGI(TAG, "Starting simulation of a 24h cycle over %d minutes. Each simulated minute will take %ld ms.", + cycle_duration_minutes, delay_ms); + + int current_minute_of_day = 0; + light_item_node_t *last_item = NULL; + + while (1) + { + int hours = current_minute_of_day / 60; + int minutes = current_minute_of_day % 60; + int hhmm = hours * 100 + minutes; + time = time_to_string(hhmm); + + light_item_node_t *current_item = find_best_light_item_for_time(hhmm); + + if (current_item != NULL && current_item != last_item) + { + ESP_LOGI(TAG, "Simulating time: %02d:%02d -> Closest schedule is %s. R:%d, G:%d, B:%d", hours, minutes, + current_item->time, current_item->red, current_item->green, current_item->blue); + led_strip_update( + LED_STATE_SIMULATION, + (rgb_t){.red = current_item->red, .green = current_item->green, .blue = current_item->blue}); + last_item = current_item; + } + + vTaskDelay(pdMS_TO_TICKS(delay_ms)); + + current_minute_of_day++; + if (current_minute_of_day >= total_minutes_in_day) + { + current_minute_of_day = 0; + ESP_LOGI(TAG, "Simulation cycle restarting."); + } + } +} + +void start_simulation_task(void) +{ + if (simulation_task_handle != NULL) + { + vTaskDelete(simulation_task_handle); + simulation_task_handle = NULL; + } + + simulation_config_t *config = + (simulation_config_t *)heap_caps_malloc(sizeof(simulation_config_t), MALLOC_CAP_SPIRAM); + if (config == NULL) + { + ESP_LOGE(TAG, "Failed to allocate memory for simulation config."); + return; + } + + config->cycle_duration_minutes = 15; + + if (xTaskCreate(simulate_cycle, "simulate_cycle", 4096, (void *)config, tskIDLE_PRIORITY + 1, + &simulation_task_handle) != pdPASS) + { + ESP_LOGE(TAG, "Failed to create simulation task."); + heap_caps_free(config); + } +} diff --git a/firmware/components/simulator/storage.c b/firmware/components/simulator/src/storage.c similarity index 100% rename from firmware/components/simulator/storage.c rename to firmware/components/simulator/src/storage.c diff --git a/firmware/main/app_task.cpp b/firmware/main/app_task.cpp index ff02fad..3be5300 100644 --- a/firmware/main/app_task.cpp +++ b/firmware/main/app_task.cpp @@ -113,7 +113,7 @@ static void init_ui(void) }); u8g2_ClearBuffer(&u8g2); - m_widget->render(); + m_widget->Render(); u8g2_SendBuffer(&u8g2); } @@ -126,27 +126,27 @@ static void handle_button(uint8_t button) switch (button) { case 1: - m_widget->onButtonClicked(ButtonType::UP); + m_widget->OnButtonClicked(ButtonType::UP); break; case 3: - m_widget->onButtonClicked(ButtonType::LEFT); + m_widget->OnButtonClicked(ButtonType::LEFT); break; case 5: - m_widget->onButtonClicked(ButtonType::RIGHT); + m_widget->OnButtonClicked(ButtonType::RIGHT); break; case 6: - m_widget->onButtonClicked(ButtonType::DOWN); + m_widget->OnButtonClicked(ButtonType::DOWN); break; case 16: - m_widget->onButtonClicked(ButtonType::BACK); + m_widget->OnButtonClicked(ButtonType::BACK); break; case 18: - m_widget->onButtonClicked(ButtonType::SELECT); + m_widget->OnButtonClicked(ButtonType::SELECT); break; default: @@ -160,8 +160,10 @@ void app_task(void *args) { if (i2c_bus_scan_and_check() != ESP_OK) { - led_behavior_t led0_behavior = { - .mode = LED_MODE_BLINK, .color = {.r = 50, .g = 0, .b = 0}, .on_time_ms = 1000, .off_time_ms = 500}; + led_behavior_t led0_behavior = {.mode = LED_MODE_BLINK, + .color = {.red = 50, .green = 0, .blue = 0}, + .on_time_ms = 1000, + .off_time_ms = 500}; led_status_set_behavior(0, led0_behavior); ESP_LOGE(TAG, "Display not found on I2C bus"); @@ -192,8 +194,8 @@ void app_task(void *args) uint64_t deltaMs = delta / 1000; - m_widget->update(deltaMs); - m_widget->render(); + m_widget->Update(deltaMs); + m_widget->Render(); m_inactivityTracker->update(deltaMs); } diff --git a/firmware/main/button_handling.h b/firmware/main/button_handling.h index 620048a..f774ad3 100644 --- a/firmware/main/button_handling.h +++ b/firmware/main/button_handling.h @@ -1,11 +1,8 @@ #pragma once -#ifdef __cplusplus -extern "C" -{ -#endif - void setup_buttons(void); - void cleanup_buttons(void); -#ifdef __cplusplus -} -#endif \ No newline at end of file +#include + +__BEGIN_DECLS +void setup_buttons(void); +void cleanup_buttons(void); +__END_DECLS diff --git a/firmware/main/hal/u8g2_esp32_hal.h b/firmware/main/hal/u8g2_esp32_hal.h index 9cf20d4..814a14c 100644 --- a/firmware/main/hal/u8g2_esp32_hal.h +++ b/firmware/main/hal/u8g2_esp32_hal.h @@ -70,23 +70,18 @@ typedef struct .reset = U8G2_ESP32_HAL_UNDEFINED, \ .dc = U8G2_ESP32_HAL_UNDEFINED} -#ifdef __cplusplus -extern "C" -{ -#endif - /** - * Initialize the HAL with the given configuration. - * - * @see u8g2_esp32_hal_t - * @see U8G2_ESP32_HAL_DEFAULT - */ - void u8g2_esp32_hal_init(u8g2_esp32_hal_t u8g2_esp32_hal_param); - uint8_t u8g2_esp32_spi_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr); - uint8_t u8g2_esp32_i2c_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr); - uint8_t u8g2_esp32_gpio_and_delay_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr); -#ifdef __cplusplus -} -#endif +__BEGIN_DECLS +/** + * Initialize the HAL with the given configuration. + * + * @see u8g2_esp32_hal_t + * @see U8G2_ESP32_HAL_DEFAULT + */ +void u8g2_esp32_hal_init(u8g2_esp32_hal_t u8g2_esp32_hal_param); +uint8_t u8g2_esp32_spi_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr); +uint8_t u8g2_esp32_i2c_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr); +uint8_t u8g2_esp32_gpio_and_delay_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr); +__END_DECLS #endif /* U8G2_ESP32_HAL_H_ */ -#endif \ No newline at end of file +#endif diff --git a/firmware/main/i2c_checker.h b/firmware/main/i2c_checker.h index 270faa3..4f498fa 100644 --- a/firmware/main/i2c_checker.h +++ b/firmware/main/i2c_checker.h @@ -8,11 +8,6 @@ #define I2C_MASTER_SDA_PIN ((gpio_num_t)CONFIG_DISPLAY_SDA_PIN) #define I2C_MASTER_SCL_PIN ((gpio_num_t)CONFIG_DISPLAY_SCL_PIN) -#ifdef __cplusplus -extern "C" -{ -#endif - esp_err_t i2c_bus_scan_and_check(void); -#ifdef __cplusplus -} -#endif +__BEGIN_DECLS +esp_err_t i2c_bus_scan_and_check(void); +__END_DECLS diff --git a/firmware/main/main.cpp b/firmware/main/main.cpp index 119eda9..9e8d407 100644 --- a/firmware/main/main.cpp +++ b/firmware/main/main.cpp @@ -1,52 +1,45 @@ #include "app_task.h" -#include "ble_manager.h" -#include "esp_event.h" -#include "esp_insights.h" -#include "esp_log.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" +#include "color.h" #include "hal_esp32/PersistenceManager.h" -#include "led_manager.h" #include "led_status.h" -#include "nvs_flash.h" -#include "sdkconfig.h" +#include "led_strip_ws2812.h" #include "simulator.h" #include "wifi_manager.h" +#include +#include +#include +#include +#include +#include +#include +#include -#ifdef __cplusplus -extern "C" +__BEGIN_DECLS +void app_main(void) { -#endif - void app_main(void) + // Initialize NVS + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { - // Initialize NVS - esp_err_t err = nvs_flash_init(); - if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) - { - ESP_ERROR_CHECK(nvs_flash_erase()); - ESP_ERROR_CHECK(nvs_flash_init()); - } - - led_status_init(CONFIG_STATUS_WLED_PIN); - - wled_init(); - - register_handler(); - - xTaskCreatePinnedToCore(app_task, "app_task", 4096, NULL, tskIDLE_PRIORITY + 1, NULL, portNUM_PROCESSORS - 1); - xTaskCreatePinnedToCore(simulate, "simulate", 4096, NULL, tskIDLE_PRIORITY + 1, NULL, portNUM_PROCESSORS - 1); - // xTaskCreatePinnedToCore(ble_manager_task, "ble_manager", 4096, NULL, tskIDLE_PRIORITY + 1, NULL, - // portNUM_PROCESSORS - 1); - - auto persistence = PersistenceManager(); - persistence.Load(); - - if (persistence.GetValue("light_active", false)) - { - led_event_data_t payload = {.value = 42}; - send_event(EVENT_LED_ON, &payload); - } + ESP_ERROR_CHECK(nvs_flash_erase()); + ESP_ERROR_CHECK(nvs_flash_init()); + } + + auto persistence = PersistenceManager(); + persistence.Load(); + + led_status_init(CONFIG_STATUS_WLED_PIN); + + led_strip_init(); + start_simulation_task(); + + xTaskCreatePinnedToCore(app_task, "app_task", 4096, NULL, tskIDLE_PRIORITY + 1, NULL, portNUM_PROCESSORS - 1); + // xTaskCreatePinnedToCore(ble_manager_task, "ble_manager", 4096, NULL, tskIDLE_PRIORITY + 1, NULL, + // portNUM_PROCESSORS - 1); + + if (persistence.GetValue("light_active", false)) + { + led_strip_update(LED_STATE_DAY, rgb_t{}); } -#ifdef __cplusplus } -#endif +__END_DECLS diff --git a/firmware/src/ui/Device.cpp b/firmware/src/ui/Device.cpp index f479c4a..747b29a 100644 --- a/firmware/src/ui/Device.cpp +++ b/firmware/src/ui/Device.cpp @@ -206,8 +206,8 @@ void Device::DrawScreen(const uint64_t dt) const if (m_widget != nullptr) { - m_widget->update(dt); - m_widget->render(); + m_widget->Update(dt); + m_widget->Render(); } RenderU8G2(); @@ -257,7 +257,7 @@ void Device::OnButtonClicked(const ButtonType button) const if (m_widget != nullptr) { - m_widget->onButtonClicked(button); + m_widget->OnButtonClicked(button); } }