diff --git a/3rdparty/ocornut-imgui/imconfig.h b/3rdparty/ocornut-imgui/imconfig.h index b544f550d..ec57f2132 100644 --- a/3rdparty/ocornut-imgui/imconfig.h +++ b/3rdparty/ocornut-imgui/imconfig.h @@ -24,13 +24,16 @@ #define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION #define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION +//---- Don't implement help and test window functionality (ShowUserGuide()/ShowStyleEditor()/ShowTestWindow() methods will be empty) +//#define IMGUI_DISABLE_TEST_WINDOWS + //---- Include imgui_user.inl at the end of imgui.cpp so you can include code that extends ImGui using its private data/functions. //#define IMGUI_INCLUDE_IMGUI_USER_INL //---- Include imgui_user.h at the end of imgui.h //#define IMGUI_INCLUDE_IMGUI_USER_H -//---- Define implicit cast operators to convert back<>forth from your math types and ImVec2/ImVec4. +//---- Define constructor and implicit cast operators to convert back<>forth from your math types and ImVec2/ImVec4. /* #define IM_VEC2_CLASS_EXTRA \ ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ diff --git a/3rdparty/ocornut-imgui/imgui.cpp b/3rdparty/ocornut-imgui/imgui.cpp index 13019bdef..bea55adf1 100644 --- a/3rdparty/ocornut-imgui/imgui.cpp +++ b/3rdparty/ocornut-imgui/imgui.cpp @@ -1,8 +1,8 @@ -// ImGui library v1.35 +// ImGui library v1.38 WIP // See ImGui::ShowTestWindow() for sample code. // Read 'Programmer guide' below for notes on how to setup ImGui in your codebase. // Get latest version at https://github.com/ocornut/imgui -// Developed by Omar Cornut and contributors. +// Developed by Omar Cornut and ImGui contributors. /* @@ -11,13 +11,18 @@ - END-USER GUIDE - PROGRAMMER GUIDE (read me!) - API BREAKING CHANGES (read me when you update!) - - FREQUENTLY ASKED QUESTIONS (FAQ) & TROUBLESHOOTING (read me!) + - FREQUENTLY ASKED QUESTIONS (FAQ), TIPS + - Can I have multiple widgets with the same label? (Yes) + - Why is my text output blurry? + - How can I load a different font than the default? + - How can I load multiple fonts? + - How can I display and input Chinese, Japanese, Korean characters? - ISSUES & TODO-LIST - CODE - SAMPLE CODE - FONT DATA - + MISSION STATEMENT ================= @@ -34,7 +39,7 @@ Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes: - doesn't look fancy, doesn't animate - limited layout features, intricate layouts are typically crafted in code - - occasionally uses statically sized buffers for string manipulations - won't crash, but some long text may be clipped. functions like ImGui::TextUnformatted() don't have such restriction. + - occasionally uses statically sized buffers for string manipulations - won't crash, but some very long pieces of text may be clipped. functions like ImGui::TextUnformatted() don't have such restriction. END-USER GUIDE @@ -66,16 +71,17 @@ - read the FAQ below this section! - your code creates the UI, if your code doesn't run the UI is gone! == very dynamic UI, no construction/destructions steps, less data retention on your side, no state duplication, less sync, less bugs. - call and read ImGui::ShowTestWindow() for sample code demonstrating most features. - - see examples/ folder for standalone sample applications. - - customization: use the style editor or PushStyleColor/PushStyleVar to tweak the look of the interface (e.g. if you want a more compact UI or a different color scheme). + - see examples/ folder for standalone sample applications. e.g. examples/opengl_example/ + - customization: PushStyleColor()/PushStyleVar() or the style editor to tweak the look of the interface (e.g. if you want a more compact UI or a different color scheme). - getting started: - - initialisation: call ImGui::GetIO() and fill the 'Settings' data. - - every frame: + - initialisation: call ImGui::GetIO() to retrieve the ImGuiIO structure and fill the 'Settings' data. + - every frame: 1/ in your mainloop or right after you got your keyboard/mouse info, call ImGui::GetIO() and fill the 'Input' data, then call ImGui::NewFrame(). 2/ use any ImGui function you want between NewFrame() and Render() 3/ ImGui::Render() to render all the accumulated command-lists. it will call your RenderDrawListFn handler that you set in the IO structure. - - all rendering information are stored into command-lists until ImGui::Render() is called. + - all rendering information are stored into command-lists until ImGui::Render() is called. + - ImGui never touches or know about your GPU state. the only function that knows about GPU is the RenderDrawListFn handler that you must provide. - effectively it means you can create widgets at any time in your code, regardless of "update" vs "render" considerations. - refer to the examples applications in the examples/ folder for instruction on how to setup your code. - a typical application skeleton may be: @@ -92,7 +98,7 @@ unsigned char* pixels; int width, height, bytes_per_pixels; io.Fonts->GetTexDataAsRGBA32(pixels, &width, &height, &bytes_per_pixels); - // TODO: copy texture to graphics memory. + // TODO: copy texture to graphics memory. // TODO: store your texture pointer/identifier in 'io.Fonts->TexID' // Application main loop @@ -100,7 +106,7 @@ { // 1) get low-level input // e.g. on Win32, GetKeyboardState(), or poll your events, etc. - + // 2) TODO: fill all fields of IO structure and call NewFrame ImGuiIO& io = ImGui::GetIO(); io.MousePos = mouse_pos; @@ -120,7 +126,7 @@ // swap video buffer, etc. } - - after calling ImGui::NewFrame() you can read back 'io.WantCaptureMouse' and 'io.WantCaptureKeyboard' to tell if ImGui + - after calling ImGui::NewFrame() you can read back 'io.WantCaptureMouse' and 'io.WantCaptureKeyboard' to tell if ImGui wants to use your inputs. if it does you can discard/hide the inputs from the rest of your application. API BREAKING CHANGES @@ -128,9 +134,16 @@ Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix. Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. - + + - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function (will obsolete). + - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API + - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive. + - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead. + - 2015/03/17 (1.36) - renamed GetItemRectMin()/GetItemRectMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function (will obsolete). + - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing + - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function (will obsolete). - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth - - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond), kept inline redirection function. + - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function (will obsolete). - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once. - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now. - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior @@ -168,22 +181,29 @@ - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes - FREQUENTLY ASKED QUESTIONS (FAQ) & TROUBLESHOOTING - ================================================== + FREQUENTLY ASKED QUESTIONS (FAQ), TIPS + ====================================== - If text or lines are blurry when integrating ImGui in your engine: - - - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) - - A primer on the meaning and use of ID in ImGui: - - - widgets require state to be carried over multiple frames (most typically ImGui often needs to remember what is the "active" widget). + Q: Can I have multiple widgets with the same label? + A: Yes. A primer on the use of labels/IDs in ImGui.. + + - Interactive widgets require state to be carried over multiple frames (most typically ImGui often needs to remember what is the "active" widget). to do so they need an unique ID. unique ID are typically derived from a string label, an integer index or a pointer. - + Button("OK"); // Label = "OK", ID = hash of "OK" Button("Cancel"); // Label = "Cancel", ID = hash of "Cancel" - - ID are uniquely scoped within Windows so no conflict can happen if you have two buttons called "OK" in two different Windows. + - Elements that are not clickable, such as Text() items don't need an ID. + + - ID are uniquely scoped within windows, tree nodes, etc. so no conflict can happen if you have two buttons called "OK" in two different windows + or in two different locations of a tree. + + - if you have a same ID twice in the same location, you'll have a conflict: + + Button("OK"); + Button("OK"); // ID collision! Both buttons will be treated as the same. + + Fear not! this is easy to solve and there are many ways to solve it! - when passing a label you can optionally specify extra unique ID information within string itself. This helps solving the simpler collision cases. use "##" to pass a complement to the ID that won't be visible to the end-user: @@ -191,48 +211,85 @@ Button("Play##0"); // Label = "Play", ID = hash of "Play##0" Button("Play##1"); // Label = "Play", ID = hash of "Play##1" (different from above) - use "###" to pass a label that isn't part of ID. You can use that to change labels while preserving a constant ID. + - occasionally (rarely) you might want change a label while preserving a constant ID. This allows you to animate labels. + use "###" to pass a label that isn't part of ID: Button("Hello###ID"; // Label = "Hello", ID = hash of "ID" Button("World###ID"; // Label = "World", ID = hash of "ID" (same as above) - - use PushID() / PopID() to create scopes and avoid ID conflicts within the same Window: + - use PushID() / PopID() to create scopes and avoid ID conflicts within the same Window. + this is the most convenient way of distinguish ID if you are iterating and creating many UI elements. + you can push a pointer, a string or an integer value. remember that ID are formed from the addition of everything in the ID stack! + + for (int i = 0; i < 100; i++) + { + PushID(i); + Button("Click"); // Label = "Click", ID = hash of integer + "label" (unique) + PopID(); + } + + for (int i = 0; i < 100; i++) + { + MyObject* obj = Objects[i]; + PushID(obj); + Button("Click"); // Label = "Click", ID = hash of pointer + "label" (unique) + PopID(); + } + + for (int i = 0; i < 100; i++) + { + MyObject* obj = Objects[i]; + PushID(obj->Name); + Button("Click"); // Label = "Click", ID = hash of string + "label" (unique) + PopID(); + } + + - more example showing that you can stack multiple prefixes into the ID stack: Button("Click"); // Label = "Click", ID = hash of "Click" PushID("node"); - Button("Click"); // Label = "Click", ID = hash of "node" and "Click" - for (int i = 0; i < 100; i++) + Button("Click"); // Label = "Click", ID = hash of "node" + "Click" + PushID(my_ptr); + Button("Click"); // Label = "Click", ID = hash of "node" + ptr + "Click" + PopID(); + PopID(); + + - tree nodes implicitly creates a scope for you by calling PushID(). + + Button("Click"); // Label = "Click", ID = hash of "Click" + if (TreeNode("node")) { - PushID(i); - Button("Click"); // Label = "Click", ID = hash of "node" and i and "label" - PopID(); + Button("Click"); // Label = "Click", ID = hash of "node" + "Click" + TreePop(); } - PopID(); - PushID(my_ptr); - Button("Click"); // Label = "Click", ID = hash of ptr and "Click" - PopID(); - so if you have a loop creating multiple items, you can use PushID() / PopID() with the index of each item, or their pointer, etc. - some functions like TreeNode() implicitly creates a scope for you by calling PushID(). - - - when working with trees, ID are used to preserve the opened/closed state of tree nodes. - depending on your use cases you may want to use strings, indices or pointers as ID. + - when working with trees, ID are used to preserve the opened/closed state of each tree node. + depending on your use cases you may want to use strings, indices or pointers as ID. e.g. when displaying a single object that may change over time (1-1 relationship), using a static string as ID will preserve your node open/closed state when the targeted object change. e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differently. experiment and see what makes more sense! - If you want to load a different font than the default (ProggyClean.ttf, size 13) + Q: Why is my text output blurry? + A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) + + Q: How can I load a different font than the default? (default is an embedded version of ProggyClean.ttf, rendered at size 13) + A: Use the font atlas to load the TTF file you want: io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() - If you want to load multiple fonts, use the font atlas to pack them into a single texture! + Q: How can I load multiple fonts? + A: Use the font atlas to pack them into a single texture: ImFont* font0 = io.Fonts->AddFontDefault(); ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels); io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() + // the first loaded font gets used by default + // use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime - If you want to display Chinese, Japanese, Korean characters, pass custom Unicode ranges when loading a font: + Q: How can I render and input Chinese, Japanese, Korean characters? + A: When loading a font, pass custom Unicode ranges to specify the glyphs to load. ImGui will support UTF-8 encoding across the board. + Character input depends on you passing the right character code to io.AddInputCharacter(). The example applications do that. io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, io.Fonts->GetGlyphRangesJapanese()); // Load Japanese characters io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() @@ -248,39 +305,38 @@ ISSUES & TODO-LIST ================== - - misc: merge or clarify ImVec4 / ImGuiAabb, they are essentially duplicate containers + - misc: merge or clarify ImVec4 vs ImRect? - window: add horizontal scroll - window: fix resize grip rendering scaling along with Rounding style setting - window: autofit feedback loop when user relies on any dynamic layout (window width multiplier, column). maybe just clearly drop manual autofit? - - window: add a way for very transient windows (non-saved, temporary overlay over hundreds of objects) to "clean" up from the global window list. + - window: add a way for very transient windows (non-saved, temporary overlay over hundreds of objects) to "clean" up from the global window list. - window: allow resizing of child windows (possibly given min/max for each axis?) - window: background options for child windows, border option (disable rounding) - window: resizing from any sides? + mouse cursor directives for app. - - widgets: clicking on widget b while widget a should activate widget b (doesn't anymore because of hover capture) - widgets: display mode: widget-label, label-widget (aligned on column or using fixed size), label-newline-tab-widget etc. - - widgets: clip text? hover clipped text shows it in a tooltip or in-place overlay + - widgets: clean up widgets internal toward exposing everything. - main: considering adding EndFrame()/Init(). some constructs are awkward in the implementation because of the lack of them. - - main: IsItemHovered() returns true even if mouse is active on another widget (e.g. dragging outside of sliders). Maybe not a sensible default? Add parameter or alternate function? - main: IsItemHovered() make it more consistent for various type of widgets, widgets with multiple components, etc. also effectively IsHovered() region sometimes differs from hot region, e.g tree nodes - main: IsItemHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode? -!- input number: very large int not reliably supported because of int<>float conversions. +!- input number: large int not reliably supported because of int<>float conversions. - input number: optional range min/max for Input*() functions - input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled) - input number: use mouse wheel to step up/down - input number: non-decimal input. + - text: proper alignment options - layout: horizontal layout helper (github issue #97) - layout: more generic alignment state (left/right/centered) for single items? - layout: clean up the InputFloatN/SliderFloatN/ColorEdit4 layout code. item width should include frame padding. - - columns: separator function or parameter that works within the column (currently Separator() bypass all columns) - - columns: declare column set (each column: fixed size, %, fill, distribute default size among fills) - - columns: columns header to act as button (~sort op) and allow resize/reorder - - columns: user specify columns size - - columns: tree node example, removing the last NextColumn() makes a padding difference (it should not) + - columns: separator function or parameter that works within the column (currently Separator() bypass all columns) (github issue #125) + - columns: declare column set (each column: fixed size, %, fill, distribute default size among fills) (github issue #125) + - columns: columns header to act as button (~sort op) and allow resize/reorder (github issue #125) + - columns: user specify columns size (github issue #125) + - popup: border options. richer api like BeginChild() perhaps? (github issue #197) - combo: turn child handling code into pop up helper - combo: contents should extends to fit label if combo widget is small - listbox: multiple selection - listbox: user may want to initial scroll to focus on the one selected value? - ! menubar, menus + ! menubar, menus (github issue #126) - tabs - gauge: various forms of gauge/loading bars widgets - color: better color editor. @@ -289,22 +345,24 @@ - plot: add a helper e.g. Plot(char* label, float value, float time_span=2.0f) that stores values and Plot them for you - probably another function name. and/or automatically allow to plot ANY displayed value (more reliance on stable ID) - file selection widget -> build the tool in our codebase to improve model-dialog idioms - slider: allow using the [-]/[+] buttons used by InputFloat()/InputInt() - - slider: initial absolute click is imprecise. change to relative movement slider? hide mouse cursor, allow more precise input using less screen-space. same as scrollbar. + - slider: initial absolute click is imprecise. change to relative movement slider (same as scrollbar). + - slider: add dragging-based widgets to edit values with mouse (on 2 axises), saving screen real-estate. - text edit: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now. - text edit: centered text for slider as input text so it matches typical positioning. - - text edit: flag to disable live update of the user buffer. + - text edit: flag to disable live update of the user buffer. - text edit: field resize behavior - field could stretch when being edited? hover tooltip shows more text? - text edit: add multi-line text edit - tree: add treenode/treepush int variants? because (void*) cast from int warns on some platforms/settings - settings: write more decent code to allow saving/loading new fields - - settings: api for per-tool simple persistent data (bool,int,float) in .ini file + - settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file ! style: store rounded corners in texture to use 1 quad per corner (filled and wireframe). so rounding have minor cost. - - style: checkbox: padding for "active" color should be a multiplier of the + - style: checkbox: padding for "active" color should be a multiplier of the - style: colorbox not always square? - text: simple markup language for color change? - log: LogButtons() options for specifying depth and/or hiding depth slider - log: have more control over the log scope (e.g. stop logging when leaving current tree node scope) - - log: be able to right-click and log a window or tree-node into tty/file/clipboard / generalized context menu? + - log: be able to log anything (e.g. right-click on a window/tree-node, shows context menu? log into tty/file/clipboard) + - log: let user copy any window content to clipboard easily (CTRL+C on windows? while moving it? context menu?). code is commented because it fails with multiple Begin/End pairs. - filters: set a current filter that tree node can automatically query to hide themselves - filters: handle wildcards (with implicit leading/trailing *), regexps - shortcuts: add a shortcut api, e.g. parse "&Save" and/or "Save (CTRL+S)", pass in to widgets or provide simple ways to use (button=activate, input=focus) @@ -319,11 +377,10 @@ - misc: double-clicking on title bar to minimize isn't consistent, perhaps move to single-click on left-most collapse icon? - style editor: have a more global HSV setter (e.g. alter hue on all elements). consider replacing active/hovered by offset in HSV space? - style editor: color child window height expressed in multiple of line height. - - optimization/render: use indexed rendering to reduce vertex data cost (for remote/networked imgui) + - optimization/render: use indexed rendering to reduce vertex data cost (e.g. for remote/networked imgui) - optimization/render: merge command-lists with same clip-rect into one even if they aren't sequential? (as long as in-between clip rectangle don't overlap)? - optimization: turn some the various stack vectors into statically-sized arrays - optimization: better clipping for multi-component widgets - - optimization: specialize for height based clipping first (assume widgets never go up + height tests before width tests?) */ #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) @@ -331,14 +388,13 @@ #endif #include "imgui.h" -#include // toupper -#include // sqrtf +#include // toupper, isprint +#include // sqrtf, fabsf, fmodf, powf, cosf, sinf, floorf, ceilf #include // intptr_t -#include // vsnprintf +#include // vsnprintf, sscanf #include // new (ptr) #ifdef _MSC_VER -#pragma warning (disable: 4100) // unreferenced formal parameter #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 #endif @@ -350,13 +406,11 @@ #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 "-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 "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it. -#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // -#pragma clang diagnostic ignored "-Wunused-parameter" // warning: unused parameter ‘xxxx’ -#elif defined(__GNUC__) +#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // +#pragma clang diagnostic ignored "-Wmissing-noreturn" // warning : function xx could be declared with attribute 'noreturn' warning // GetDefaultFontData() asserts which some implementation makes it never return. +#endif +#ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used -#pragma GCC diagnostic ignored "-Wunused-parameter" // warning: unused parameter ‘xxxx’ -#pragma GCC diagnostic ignored "-Wtype-limits" // warning: comparison is always true due to limited range of data type -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // warning: ‘xxxx’ may be used uninitialized in this function #endif //------------------------------------------------------------------------- @@ -398,6 +452,8 @@ namespace IMGUI_STB_NAMESPACE #endif #include "stb_truetype.h" +#undef STB_TEXTEDIT_STRING +#undef STB_TEXTEDIT_CHARTYPE #define STB_TEXTEDIT_STRING ImGuiTextEditState #define STB_TEXTEDIT_CHARTYPE ImWchar #include "stb_textedit.h" @@ -415,16 +471,16 @@ using namespace IMGUI_STB_NAMESPACE; // Forward Declarations //------------------------------------------------------------------------- +struct ImRect; struct ImGuiColMod; struct ImGuiStyleMod; -struct ImGuiAabb; struct ImGuiDrawContext; struct ImGuiTextEditState; struct ImGuiIniData; struct ImGuiState; struct ImGuiWindow; -static bool ButtonBehaviour(const ImGuiAabb& bb, const ImGuiID& id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, bool repeat = false, bool pressed_on_click = false); +static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, bool repeat = false, bool pressed_on_click = false); static void LogText(const ImVec2& ref_pos, const char* text, const char* text_end = NULL); static void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); @@ -434,13 +490,13 @@ static void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool static void RenderCollapseTriangle(ImVec2 p_min, bool opened, float scale = 1.0f, bool shadow = false); static void SetFont(ImFont* font); -static bool ItemAdd(const ImGuiAabb& bb, const ImGuiID* id); -static void ItemSize(ImVec2 size, ImVec2* adjust_start_offset = NULL); -static void ItemSize(const ImGuiAabb& bb, ImVec2* adjust_start_offset = NULL); +static bool ItemAdd(const ImRect& bb, const ImGuiID* id); +static void ItemSize(ImVec2 size, float text_offset_y = 0.0f); +static void ItemSize(const ImRect& bb, float text_offset_y = 0.0f); static void PushColumnClipRect(int column_index = -1); -static bool IsClipped(const ImGuiAabb& bb); +static bool IsClippedEx(const ImRect& bb, bool clip_even_when_logged); -static bool IsMouseHoveringBox(const ImGuiAabb& bb); +static bool IsMouseHoveringRect(const ImRect& bb); static bool IsKeyPressedMap(ImGuiKey key, bool repeat = true); static void Scrollbar(ImGuiWindow* window); @@ -479,17 +535,6 @@ static const char* GetClipboardTextFn_DefaultImpl(); static void SetClipboardTextFn_DefaultImpl(const char* text); static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); -//----------------------------------------------------------------------------- -// Texture Atlas data -//----------------------------------------------------------------------------- - -// Technically we should use the rect pack API for that, but it's just simpler to hard-core the positions for now. -// As we start using more of the texture atlas (for rounded corners) we can change that. -static const ImVec2 TEX_ATLAS_SIZE(32, 32); -static const ImVec2 TEX_ATLAS_POS_MOUSE_CURSOR_BLACK(1, 3); -static const ImVec2 TEX_ATLAS_POS_MOUSE_CURSOR_WHITE(14, 3); -static const ImVec2 TEX_ATLAS_SIZE_MOUSE_CURSOR(12, 19); - //----------------------------------------------------------------------------- // User facing structures //----------------------------------------------------------------------------- @@ -505,20 +550,23 @@ ImGuiStyle::ImGuiStyle() FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets). ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) - TouchExtraPadding = ImVec2(0,0); // Expand bounding box for touch-based system where touch position is not accurate enough (unnecessary for mouse inputs). Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget running. So dont grow this too much! + TouchExtraPadding = ImVec2(0,0); // 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! AutoFitPadding = ImVec2(8,8); // Extra space after auto-fit (double-clicking on resize grip) WindowFillAlphaDefault = 0.70f; // Default alpha of window background, if not specified in ImGui::Begin() - TreeNodeSpacing = 22.0f; // Horizontal spacing when entering a tree node + IndentSpacing = 22.0f; // Horizontal spacing when e.g. entering a tree node ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns ScrollbarWidth = 16.0f; // Width of the vertical scrollbar GrabMinSize = 10.0f; // Minimum width/height of a slider or scrollbar grab + DisplaySafeAreaPadding = ImVec2(22,22); // Window positions are clamped to be visible within the display area. If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding Colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); Colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); Colors[ImGuiCol_ChildWindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - Colors[ImGuiCol_Border] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + Colors[ImGuiCol_Border] = ImVec4(0.70f, 0.70f, 0.70f, 1.00f); Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.60f); Colors[ImGuiCol_FrameBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.30f); // Background of checkbox, radio button, plot, slider, text input + Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.90f, 0.80f, 0.80f, 0.40f); + Colors[ImGuiCol_FrameBgActive] = ImVec4(0.90f, 0.65f, 0.65f, 0.45f); Colors[ImGuiCol_TitleBg] = ImVec4(0.50f, 0.50f, 1.00f, 0.45f); Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f); Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.40f, 0.40f, 0.80f, 0.15f); @@ -526,8 +574,6 @@ ImGuiStyle::ImGuiStyle() Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f); Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.80f, 0.50f, 0.50f, 0.40f); Colors[ImGuiCol_ComboBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.99f); - Colors[ImGuiCol_CheckHovered] = ImVec4(0.60f, 0.40f, 0.40f, 0.45f); - Colors[ImGuiCol_CheckActive] = ImVec4(0.65f, 0.50f, 0.50f, 0.55f); 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.80f, 0.50f, 0.50f, 1.00f); @@ -537,9 +583,9 @@ ImGuiStyle::ImGuiStyle() 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_Column] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); - Colors[ImGuiCol_ColumnHovered] = ImVec4(0.60f, 0.40f, 0.40f, 1.00f); - Colors[ImGuiCol_ColumnActive] = ImVec4(0.80f, 0.50f, 0.50f, 1.00f); + Colors[ImGuiCol_Column] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); + Colors[ImGuiCol_ColumnHovered] = ImVec4(0.70f, 0.60f, 0.60f, 1.00f); + Colors[ImGuiCol_ColumnActive] = ImVec4(0.90f, 0.70f, 0.70f, 1.00f); Colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); Colors[ImGuiCol_ResizeGripHovered] = ImVec4(1.00f, 1.00f, 1.00f, 0.60f); Colors[ImGuiCol_ResizeGripActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.90f); @@ -574,6 +620,7 @@ ImGuiIO::ImGuiIO() MousePosPrev = ImVec2(-1,-1); MouseDoubleClickTime = 0.30f; MouseDoubleClickMaxDist = 6.0f; + MouseDragThreshold = 6.0f; UserData = NULL; // User functions @@ -608,9 +655,11 @@ void ImGuiIO::AddInputCharacter(ImWchar c) const float PI = 3.14159265358979323846f; #ifdef INT_MAX -#define IM_INT_MAX INT_MAX +#define IM_INT_MIN INT_MIN +#define IM_INT_MAX INT_MAX #else -#define IM_INT_MAX 2147483647 +#define IM_INT_MIN (-2147483647-1) +#define IM_INT_MAX (2147483647) #endif // Play it nice with Windows users. Notepad in 2015 still doesn't display text data with Unix-style \n. @@ -700,30 +749,30 @@ static const char* ImStristr(const char* haystack, const char* needle, const cha // Pass data_size==0 for zero-terminated string // Try to replace with FNV1a hash? -static ImU32 ImHash(const void* data, size_t data_size, ImU32 seed = 0) -{ +static ImU32 ImHash(const void* data, size_t data_size, ImU32 seed = 0) +{ static ImU32 crc32_lut[256] = { 0 }; if (!crc32_lut[1]) { const ImU32 polynomial = 0xEDB88320; - for (ImU32 i = 0; i < 256; i++) - { - ImU32 crc = i; - for (ImU32 j = 0; j < 8; j++) - crc = (crc >> 1) ^ (ImU32(-int(crc & 1)) & polynomial); - crc32_lut[i] = crc; + for (ImU32 i = 0; i < 256; i++) + { + ImU32 crc = i; + for (ImU32 j = 0; j < 8; j++) + crc = (crc >> 1) ^ (ImU32(-int(crc & 1)) & polynomial); + crc32_lut[i] = crc; } } seed = ~seed; - ImU32 crc = seed; + ImU32 crc = seed; const unsigned char* current = (const unsigned char*)data; if (data_size > 0) { // Known size - while (data_size--) - crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *current++]; + while (data_size--) + crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *current++]; } else { @@ -732,7 +781,7 @@ static ImU32 ImHash(const void* data, size_t data_size, ImU32 seed = 0) { // We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed. // Because this syntax is rarely used we are optimizing for the common case. - // - If we reach ### in the string we discard the hash so far and reset to the seed. + // - If we reach ### in the string we discard the hash so far and reset to the seed. // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller. if (c == '#' && current[0] == '#' && current[1] == '#') crc = seed; @@ -740,8 +789,8 @@ static ImU32 ImHash(const void* data, size_t data_size, ImU32 seed = 0) crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; } } - return ~crc; -} + return ~crc; +} static size_t ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) { @@ -794,7 +843,7 @@ void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& // Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593 // also http://en.wikipedia.org/wiki/HSL_and_HSV void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b) -{ +{ if (s == 0.0f) { // gray @@ -825,7 +874,6 @@ void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& static bool ImLoadFileToMemory(const char* filename, const char* file_open_mode, void** out_file_data, size_t* out_file_size, size_t padding_bytes) { IM_ASSERT(filename && file_open_mode && out_file_data && out_file_size); - IM_ASSERT(padding_bytes >= 0); *out_file_data = NULL; *out_file_size = 0; @@ -877,31 +925,53 @@ struct ImGuiStyleMod // Style modifier, backup of modified data so we can res ImVec2 PreviousValue; }; -struct ImGuiAabb // 2D axis aligned bounding-box +struct ImRect // 2D axis aligned bounding-box { ImVec2 Min; ImVec2 Max; - ImGuiAabb() { Min = ImVec2(FLT_MAX,FLT_MAX); Max = ImVec2(-FLT_MAX,-FLT_MAX); } - ImGuiAabb(const ImVec2& min, const ImVec2& max) { Min = min; Max = max; } - ImGuiAabb(const ImVec4& v) { Min.x = v.x; Min.y = v.y; Max.x = v.z; Max.y = v.w; } - ImGuiAabb(float x1, float y1, float x2, float y2) { Min.x = x1; Min.y = y1; Max.x = x2; Max.y = y2; } + ImRect() { Min = ImVec2(FLT_MAX,FLT_MAX); Max = ImVec2(-FLT_MAX,-FLT_MAX); } + ImRect(const ImVec2& min, const ImVec2& max) { Min = min; Max = max; } + ImRect(const ImVec4& v) { Min.x = v.x; Min.y = v.y; Max.x = v.z; Max.y = v.w; } + ImRect(float x1, float y1, float x2, float y2) { Min.x = x1; Min.y = y1; Max.x = x2; Max.y = y2; } - ImVec2 GetCenter() const { return Min + (Max-Min)*0.5f; } - ImVec2 GetSize() const { return Max-Min; } - float GetWidth() const { return (Max-Min).x; } - float GetHeight() const { return (Max-Min).y; } - ImVec2 GetTL() const { return Min; } - ImVec2 GetTR() const { return ImVec2(Max.x,Min.y); } - ImVec2 GetBL() const { return ImVec2(Min.x,Max.y); } - ImVec2 GetBR() const { return Max; } - bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x <= Max.x && p.y <= Max.y; } - bool Contains(const ImGuiAabb& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x <= Max.x && r.Max.y <= Max.y; } - bool Overlaps(const ImGuiAabb& r) const { return r.Min.y <= Max.y && r.Max.y >= Min.y && r.Min.x <= Max.x && r.Max.x >= Min.x; } - void Add(const ImVec2& rhs) { Min.x = ImMin(Min.x, rhs.x); Min.y = ImMin(Min.y, rhs.y); Max.x = ImMax(Max.x, rhs.x); Max.y = ImMax(Max.x, rhs.x); } - void Add(const ImGuiAabb& rhs) { Min.x = ImMin(Min.x, rhs.Min.x); Min.y = ImMin(Min.y, rhs.Min.y); Max.x = ImMax(Max.x, rhs.Max.x); Max.y = ImMax(Max.y, rhs.Max.y); } - void Expand(const ImVec2& sz) { Min -= sz; Max += sz; } - void Clip(const ImGuiAabb& clip) { Min.x = ImMax(Min.x, clip.Min.x); Min.y = ImMax(Min.y, clip.Min.y); Max.x = ImMin(Max.x, clip.Max.x); Max.y = ImMin(Max.y, clip.Max.y); } + ImVec2 GetCenter() const { return Min + (Max-Min)*0.5f; } + ImVec2 GetSize() const { return Max-Min; } + float GetWidth() const { return (Max-Min).x; } + float GetHeight() const { return (Max-Min).y; } + ImVec2 GetTL() const { return Min; } + ImVec2 GetTR() const { return ImVec2(Max.x,Min.y); } + ImVec2 GetBL() const { return ImVec2(Min.x,Max.y); } + ImVec2 GetBR() const { return Max; } + bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; } + bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x < Max.x && r.Max.y < Max.y; } + bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; } + void Add(const ImVec2& rhs) { Min.x = ImMin(Min.x, rhs.x); Min.y = ImMin(Min.y, rhs.y); Max.x = ImMax(Max.x, rhs.x); Max.y = ImMax(Max.x, rhs.x); } + void Add(const ImRect& rhs) { Min.x = ImMin(Min.x, rhs.Min.x); Min.y = ImMin(Min.y, rhs.Min.y); Max.x = ImMax(Max.x, rhs.Max.x); Max.y = ImMax(Max.y, rhs.Max.y); } + void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; } + void Expand(const ImVec2& amount) { Min -= amount; Max += amount; } + void Clip(const ImRect& clip) { Min.x = ImMax(Min.x, clip.Min.x); Min.y = ImMax(Min.y, clip.Min.y); Max.x = ImMin(Max.x, clip.Max.x); Max.y = ImMin(Max.y, clip.Max.y); } + ImVec2 GetClosestPoint(ImVec2 p, bool on_edge) const + { + if (!on_edge && Contains(p)) + return p; + if (p.x > Max.x) p.x = Max.x; + else if (p.x < Min.x) p.x = Min.x; + if (p.y > Max.y) p.y = Max.y; + else if (p.y < Min.y) p.y = Min.y; + return p; + } +}; +typedef ImRect ImGuiAabb; // FIXME-OBSOLETE + +struct ImGuiGroupData +{ + ImVec2 BackupCursorPos; + ImVec2 BackupCursorMaxPos; + float BackupColumnsStartX; + float BackupCurrentLineHeight; + float BackupCurrentLineTextBaseOffset; + float BackupLogLinePosY; }; // Temporary per-window data, reset at the beginning of the frame @@ -910,21 +980,26 @@ struct ImGuiDrawContext ImVec2 CursorPos; ImVec2 CursorPosPrevLine; ImVec2 CursorStartPos; + ImVec2 CursorMaxPos; // Implicitly calculate the size of our contents, always extending. Saved into window->SizeContents at the end of the frame float CurrentLineHeight; + float CurrentLineTextBaseOffset; float PrevLineHeight; - float LogLineHeight; + float PrevLineTextBaseOffset; + float LogLinePosY; int TreeDepth; ImGuiID LastItemID; - ImGuiAabb LastItemAabb; - bool LastItemHovered; + ImRect LastItemRect; + bool LastItemHoveredAndUsable; + bool LastItemHoveredRect; ImVector ChildWindows; ImVector AllowKeyboardFocus; ImVector ItemWidth; // 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window ImVector TextWrapPos; + ImVector GroupStack; ImGuiColorEditMode ColorEditMode; ImGuiStorage* StateStorage; - float ColumnsStartX; // Start position from left of window (increased by TreePush/TreePop, etc.) + float ColumnsStartX; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) float ColumnsOffsetX; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. int ColumnsCurrent; int ColumnsCount; @@ -937,13 +1012,15 @@ struct ImGuiDrawContext ImGuiDrawContext() { - CursorPos = CursorPosPrevLine = CursorStartPos = ImVec2(0.0f, 0.0f); + CursorPos = CursorPosPrevLine = CursorStartPos = CursorMaxPos = ImVec2(0.0f, 0.0f); CurrentLineHeight = PrevLineHeight = 0.0f; - LogLineHeight = -1.0f; + CurrentLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f; + LogLinePosY = -1.0f; TreeDepth = 0; LastItemID = 0; - LastItemAabb = ImGuiAabb(0.0f,0.0f,0.0f,0.0f); - LastItemHovered = false; + LastItemRect = ImRect(0.0f,0.0f,0.0f,0.0f); + LastItemHoveredAndUsable = LastItemHoveredRect = false; + ColorEditMode = ImGuiColorEditMode_RGB; StateStorage = NULL; ColumnsStartX = 0.0f; @@ -962,8 +1039,8 @@ struct ImGuiTextEditState { ImGuiID Id; // widget id owning the text state ImWchar Text[1024]; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. - char InitialText[1024*4+1]; // backup of end-user buffer at the time of focus (in UTF-8, unaltered) - int CurLenA, CurLenW; // we need to maintain our buffer length in both UTF-8 and wchar format. + char InitialText[1024*3+1]; // backup of end-user buffer at the time of focus (in UTF-8, unaltered) + size_t CurLenA, CurLenW; // we need to maintain our buffer length in both UTF-8 and wchar format. size_t BufSizeA; // end-user buffer size, <= 1024 (or increase above) float Width; // widget width float ScrollX; @@ -1004,6 +1081,15 @@ struct ImGuiIniData ~ImGuiIniData() { if (Name) { ImGui::MemFree(Name); Name = NULL; } } }; +struct ImGuiMouseCursorData +{ + ImGuiMouseCursor Type; + ImVec2 Offset; + ImVec2 Size; + ImVec2 TexUvMin[2]; + ImVec2 TexUvMax[2]; +}; + // Main state for ImGui struct ImGuiState { @@ -1011,26 +1097,30 @@ struct ImGuiState ImGuiIO IO; ImGuiStyle Style; ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back() - float FontSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Size of characters. + float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize() + float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Size of characters. ImVec2 FontTexUvWhitePixel; // (Shortcut) == Font->TexUvForWhite float Time; int FrameCount; int FrameCountRendered; ImVector Windows; + ImVector WindowsSortBuffer; ImGuiWindow* CurrentWindow; // Being drawn into ImVector CurrentWindowStack; ImGuiWindow* FocusedWindow; // Will catch keyboard inputs ImGuiWindow* HoveredWindow; // Will catch mouse inputs ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only) - ImGuiID HoveredId; - ImGuiID ActiveId; + ImGuiID HoveredId; // Hovered widget + ImGuiID ActiveId; // Active widget ImGuiID ActiveIdPreviousFrame; bool ActiveIdIsAlive; + bool ActiveIdIsJustActivated; // Set when bool ActiveIdIsFocusedOnly; // Set only by active widget. Denote focus but no active interaction. ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window. Only valid if ActiveID is the "#MOVE" identifier of a window. float SettingsDirtyTimer; ImVector Settings; + int DisableHideTextAfterDoubleHash; ImVector ColorModifiers; ImVector StyleModifiers; ImVector FontStack; @@ -1046,14 +1136,22 @@ struct ImGuiState ImGuiSetCond SetNextTreeNodeOpenedCond; // Render - ImVector RenderDrawLists; - ImVector RenderSortedWindows; + ImVector RenderDrawLists[3]; + + // Mouse cursor + ImGuiMouseCursor MouseCursor; + ImDrawList MouseCursorDrawList; // Optional software render of mouse cursors, if io.MouseDrawCursor is set + ImGuiMouseCursorData MouseCursorData[ImGuiMouseCursor_Count_]; // Widget state ImGuiTextEditState InputTextState; - ImGuiID SliderAsInputTextId; + ImGuiID ScalarAsInputTextId; // Temporary text input when CTRL+clicking on a slider, etc. ImGuiStorage ColorEditModeStorage; // for user selection ImGuiID ActiveComboID; + float DragCurrentValue; // current dragged value, always float, not rounded by end-user precision settings + ImVec2 DragLastMouseDelta; + float DragSpeedScaleSlow; + float DragSpeedScaleFast; float ScrollbarClickDeltaToGrabCenter; // distance between mouse and center of grab box, normalized in parent space char Tooltip[1024]; char* PrivateClipboard; // if no custom clipboard handler is defined @@ -1069,12 +1167,13 @@ struct ImGuiState float FramerateSecPerFrame[120]; // calculate estimate of framerate for user int FramerateSecPerFrameIdx; float FramerateSecPerFrameAccum; + char TempBuffer[1024*3+1]; // temporary text buffer - void Clear() + ImGuiState() { Initialized = false; Font = NULL; - FontSize = 0.0f; + FontBaseSize = FontSize = 0.0f; FontTexUvWhitePixel = ImVec2(0.0f, 0.0f); Time = 0.0f; @@ -1088,9 +1187,11 @@ struct ImGuiState ActiveId = 0; ActiveIdPreviousFrame = 0; ActiveIdIsAlive = false; + ActiveIdIsJustActivated = false; ActiveIdIsFocusedOnly = false; MovedWindow = NULL; SettingsDirtyTimer = 0.0f; + DisableHideTextAfterDoubleHash = 0; SetNextWindowPosVal = ImVec2(0.0f, 0.0f); SetNextWindowPosCond = 0; @@ -1102,12 +1203,18 @@ struct ImGuiState SetNextTreeNodeOpenedVal = false; SetNextTreeNodeOpenedCond = 0; - SliderAsInputTextId = 0; + ScalarAsInputTextId = 0; ActiveComboID = 0; + DragCurrentValue = 0.0f; + DragLastMouseDelta = ImVec2(0.0f, 0.0f); + DragSpeedScaleSlow = 0.01f; + DragSpeedScaleFast = 10.0f; ScrollbarClickDeltaToGrabCenter = 0.0f; memset(Tooltip, 0, sizeof(Tooltip)); PrivateClipboard = NULL; + MouseCursor = ImGuiMouseCursor_Arrow; + LogEnabled = false; LogFile = NULL; LogClipboard = NULL; @@ -1117,26 +1224,6 @@ struct ImGuiState memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame)); FramerateSecPerFrameIdx = 0; FramerateSecPerFrameAccum = 0.0f; - - Windows.clear(); - RenderSortedWindows.clear(); - CurrentWindowStack.clear(); - Settings.clear(); - ColorEditModeStorage.Clear(); - ColorModifiers.clear(); - StyleModifiers.clear(); - FontStack.clear(); - RenderDrawLists.clear(); - } - - ImGuiState() - { - Clear(); - } - - ~ImGuiState() - { - Clear(); } }; @@ -1153,24 +1240,25 @@ struct ImGuiWindow ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) ImVec2 SizeFull; // Size when non collapsed ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame - ImVec2 SizeContentsCurrent; // Size of contents, currently extending + ImGuiID MoveID; // == window->GetID("#MOVE") float ScrollY; float NextScrollY; bool ScrollbarY; bool Visible; // Set to true on Begin() + bool WasVisible; bool Accessed; // Set to true when any widget access the current window bool Collapsed; // Set when collapsing window to become only title-bar bool SkipItems; // == Visible && !Collapsed int AutoFitFrames; bool AutoFitOnlyGrows; - int SetWindowPosAllowFlags; // bit ImGuiSetCond_*** specify if SetWindowPos() call is allowed with this particular flag. - int SetWindowSizeAllowFlags; // bit ImGuiSetCond_*** specify if SetWindowSize() call is allowed with this particular flag. - int SetWindowCollapsedAllowFlags; // bit ImGuiSetCond_*** specify if SetWindowCollapsed() call is allowed with this particular flag. + int SetWindowPosAllowFlags; // bit ImGuiSetCond_*** specify if SetWindowPos() call will succeed with this particular flag. + int SetWindowSizeAllowFlags; // bit ImGuiSetCond_*** specify if SetWindowSize() call will succeed with this particular flag. + int SetWindowCollapsedAllowFlags; // bit ImGuiSetCond_*** specify if SetWindowCollapsed() call will succeed with this particular flag. - ImGuiDrawContext DC; - ImVector IDStack; + ImGuiDrawContext DC; // Temporary per-window data, reset at the beginning of the frame + ImVector IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack ImVector ClipRectStack; // Scissoring / clipping rectangle. x1, y1, x2, y2. - ImGuiAabb ClippedAabb; // = ClipRectStack.front() after setup in Begin() + ImRect ClippedRect; // = ClipRectStack.front() after setup in Begin() int LastFrameDrawn; float ItemWidthDefault; ImGuiStorage StateStorage; @@ -1190,32 +1278,37 @@ public: ImGuiWindow(const char* name); ~ImGuiWindow(); - ImGuiID GetID(const char* str); + ImGuiID GetID(const char* str, const char* str_end = NULL); ImGuiID GetID(const void* ptr); - void AddToRenderList(); bool FocusItemRegister(bool is_active, bool tab_stop = true); // Return true if focus is requested void FocusItemUnregister(); - ImGuiAabb Aabb() const { return ImGuiAabb(Pos, Pos+Size); } - ImFont* Font() const { return GImGui->Font; } - float FontSize() const { return GImGui->FontSize * FontWindowScale; } - ImVec2 CursorPos() const { return DC.CursorPos; } - float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0 : FontSize() + GImGui->Style.FramePadding.y * 2.0f; } - ImGuiAabb TitleBarAabb() const { return ImGuiAabb(Pos, Pos + ImVec2(SizeFull.x, TitleBarHeight())); } - ImVec2 WindowPadding() const { return ((Flags & ImGuiWindowFlags_ChildWindow) && !(Flags & ImGuiWindowFlags_ShowBorders)) ? ImVec2(0,0) : GImGui->Style.WindowPadding; } + ImRect Rect() const { return ImRect(Pos, Pos+Size); } + float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; } + float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0 : CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f; } + ImRect TitleBarRect() const { return ImRect(Pos, Pos + ImVec2(SizeFull.x, TitleBarHeight())); } + ImVec2 WindowPadding() const { return ((Flags & ImGuiWindowFlags_ChildWindow) && !(Flags & ImGuiWindowFlags_ShowBorders) && !(Flags & ImGuiWindowFlags_ComboBox)) ? ImVec2(0,0) : GImGui->Style.WindowPadding; } ImU32 Color(ImGuiCol idx, float a=1.f) const { ImVec4 c = GImGui->Style.Colors[idx]; c.w *= GImGui->Style.Alpha * a; return ImGui::ColorConvertFloat4ToU32(c); } ImU32 Color(const ImVec4& col) const { ImVec4 c = col; c.w *= GImGui->Style.Alpha; return ImGui::ColorConvertFloat4ToU32(c); } }; static inline ImGuiWindow* GetCurrentWindow() { + // If this ever crash it probably means that ImGui::NewFrame() hasn't been called. We should always have a CurrentWindow in the stack (there is an implicit "Debug" window) ImGuiState& g = *GImGui; - IM_ASSERT(g.CurrentWindow != NULL); // ImGui::NewFrame() hasn't been called yet? g.CurrentWindow->Accessed = true; return g.CurrentWindow; } +static inline void SetCurrentWindow(ImGuiWindow* window) +{ + ImGuiState& g = *GImGui; + g.CurrentWindow = window; + if (window) + g.FontSize = window->CalcFontSize(); +} + static inline ImGuiWindow* GetParentWindow() { ImGuiState& g = *GImGui; @@ -1223,14 +1316,15 @@ static inline ImGuiWindow* GetParentWindow() return g.CurrentWindowStack[g.CurrentWindowStack.size() - 2]; } -static void SetActiveId(ImGuiID id) +static void SetActiveId(ImGuiID id) { ImGuiState& g = *GImGui; - g.ActiveId = id; + g.ActiveId = id; g.ActiveIdIsFocusedOnly = false; + g.ActiveIdIsJustActivated = true; } -static void RegisterAliveId(const ImGuiID& id) +static void RegisterAliveId(ImGuiID id) { ImGuiState& g = *GImGui; if (g.ActiveId == id) @@ -1448,7 +1542,7 @@ bool ImGuiTextFilter::PassFilter(const char* val) const //----------------------------------------------------------------------------- -// On some platform vsnprintf() takes va_list by reference and modifies it. +// On some platform vsnprintf() takes va_list by reference and modifies it. // va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it. #ifndef va_copy #define va_copy(dest, src) (dest = src) @@ -1489,17 +1583,18 @@ void ImGuiTextBuffer::append(const char* fmt, ...) ImGuiWindow::ImGuiWindow(const char* name) { Name = ImStrdup(name); - ID = ImHash(name, 0); + ID = ImHash(name, 0); IDStack.push_back(ID); + MoveID = GetID("#MOVE"); Flags = 0; PosFloat = Pos = ImVec2(0.0f, 0.0f); Size = SizeFull = ImVec2(0.0f, 0.0f); - SizeContents = SizeContentsCurrent = ImVec2(0.0f, 0.0f); + SizeContents = ImVec2(0.0f, 0.0f); ScrollY = 0.0f; NextScrollY = 0.0f; ScrollbarY = false; - Visible = false; + Visible = WasVisible = false; Accessed = false; Collapsed = false; SkipItems = false; @@ -1511,12 +1606,6 @@ ImGuiWindow::ImGuiWindow(const char* name) ItemWidthDefault = 0.0f; FontWindowScale = 1.0f; - if (ImLengthSqr(Size) < 0.00001f) - { - AutoFitFrames = 2; - AutoFitOnlyGrows = true; - } - DrawList = (ImDrawList*)ImGui::MemAlloc(sizeof(ImDrawList)); new(DrawList) ImDrawList(); RootWindow = NULL; @@ -1535,10 +1624,10 @@ ImGuiWindow::~ImGuiWindow() Name = NULL; } -ImGuiID ImGuiWindow::GetID(const char* str) +ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end) { ImGuiID seed = IDStack.back(); - const ImGuiID id = ImHash(str, 0, seed); + const ImGuiID id = ImHash(str, str_end ? str_end - str : 0, seed); RegisterAliveId(id); return id; } @@ -1585,21 +1674,25 @@ void ImGuiWindow::FocusItemUnregister() FocusIdxTabCounter--; } -void ImGuiWindow::AddToRenderList() +static inline void AddDrawListToRenderList(ImVector& out_render_list, ImDrawList* draw_list) { - ImGuiState& g = *GImGui; - - if (!DrawList->commands.empty() && !DrawList->vtx_buffer.empty()) + if (!draw_list->commands.empty() && !draw_list->vtx_buffer.empty()) { - if (DrawList->commands.back().vtx_count == 0) - DrawList->commands.pop_back(); - g.RenderDrawLists.push_back(DrawList); + if (draw_list->commands.back().vtx_count == 0) + draw_list->commands.pop_back(); + out_render_list.push_back(draw_list); + GImGui->IO.MetricsRenderVertices += (int)draw_list->vtx_buffer.size(); } - for (size_t i = 0; i < DC.ChildWindows.size(); i++) +} + +static void AddWindowToRenderList(ImVector& out_render_list, ImGuiWindow* window) +{ + AddDrawListToRenderList(out_render_list, window->DrawList); + for (size_t i = 0; i < window->DC.ChildWindows.size(); i++) { - ImGuiWindow* child = DC.ChildWindows[i]; + ImGuiWindow* child = window->DC.ChildWindows[i]; if (child->Visible) // clipped children may have been marked not Visible - child->AddToRenderList(); + AddWindowToRenderList(out_render_list, child); } } @@ -1614,7 +1707,7 @@ void ImGui::MemFree(void* ptr) { return GImGui->IO.MemFreeFn(ptr); } - + static ImGuiIniData* FindWindowSettings(const char* name) { ImGuiState& g = *GImGui; @@ -1662,7 +1755,7 @@ static void LoadSettings() const char* line_end = line_start; while (line_end < buf_end && *line_end != '\n' && *line_end != '\r') line_end++; - + if (line_start[0] == '[' && line_end > line_start && line_end[-1] == ']') { char name[64]; @@ -1739,6 +1832,11 @@ static void MarkSettingsDirty() g.SettingsDirtyTimer = g.IO.IniSavingRate; } +const char* ImGui::GetVersion() +{ + return IMGUI_VERSION; +} + // Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself // Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module void* ImGui::GetInternalState() @@ -1755,7 +1853,7 @@ void ImGui::SetInternalState(void* state, bool construct) { if (construct) new (state) ImGuiState(); - + GImGui = (ImGuiState*)state; } @@ -1821,8 +1919,13 @@ void ImGui::NewFrame() else { g.IO.MouseClickedTime[i] = g.Time; - g.IO.MouseClickedPos[i] = g.IO.MousePos; } + g.IO.MouseClickedPos[i] = g.IO.MousePos; + g.IO.MouseDragMaxDistanceSqr[i] = 0.0f; + } + else if (g.IO.MouseDown[i]) + { + g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(g.IO.MousePos - g.IO.MouseClickedPos[i])); } } for (size_t i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++) @@ -1840,6 +1943,7 @@ void ImGui::NewFrame() SetActiveId(0); g.ActiveIdPreviousFrame = g.ActiveId; g.ActiveIdIsAlive = false; + g.ActiveIdIsJustActivated = false; if (!g.ActiveId) g.MovedWindow = NULL; @@ -1872,6 +1976,7 @@ void ImGui::NewFrame() bool mouse_owned_by_application = mouse_earliest_button_down != -1 && !g.IO.MouseDownOwned[mouse_earliest_button_down]; g.IO.WantCaptureMouse = (!mouse_owned_by_application && g.HoveredWindow != NULL) || (g.ActiveId != 0); g.IO.WantCaptureKeyboard = (g.ActiveId != 0); + g.MouseCursor = ImGuiMouseCursor_Arrow; // If mouse was first clicked outside of ImGui bounds we also cancel out hovering. if (mouse_owned_by_application) @@ -1903,7 +2008,7 @@ void ImGui::NewFrame() if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse)) { const int scroll_lines = (window->Flags & ImGuiWindowFlags_ComboBox) ? 3 : 5; - window->NextScrollY -= g.IO.MouseWheel * window->FontSize() * scroll_lines; + window->NextScrollY -= g.IO.MouseWheel * window->CalcFontSize() * scroll_lines; } } } @@ -1919,6 +2024,7 @@ void ImGui::NewFrame() for (size_t i = 0; i != g.Windows.size(); i++) { ImGuiWindow* window = g.Windows[i]; + window->WasVisible = window->Visible; window->Visible = false; window->Accessed = false; } @@ -1928,10 +2034,11 @@ void ImGui::NewFrame() g.CurrentWindowStack.resize(0); // Create implicit window - we will only render it if the user has added something to it. - ImGui::Begin("Debug", NULL, ImVec2(400,400)); + ImGui::SetNextWindowSize(ImVec2(400,400), ImGuiSetCond_FirstUseEver); + ImGui::Begin("Debug"); } -// NB: behaviour of ImGui after Shutdown() is not tested/guaranteed at the moment. This function is merely here to free heap allocations. +// NB: behavior of ImGui after Shutdown() is not tested/guaranteed at the moment. This function is merely here to free heap allocations. void ImGui::Shutdown() { ImGuiState& g = *GImGui; @@ -1946,9 +2053,8 @@ void ImGui::Shutdown() ImGui::MemFree(g.Windows[i]); } g.Windows.clear(); - g.RenderSortedWindows.clear(); + g.WindowsSortBuffer.clear(); g.CurrentWindowStack.clear(); - g.RenderDrawLists.clear(); g.FocusedWindow = NULL; g.HoveredWindow = NULL; g.HoveredRootWindow = NULL; @@ -1961,27 +2067,28 @@ void ImGui::Shutdown() g.ColorModifiers.clear(); g.StyleModifiers.clear(); g.FontStack.clear(); + for (size_t i = 0; i < IM_ARRAYSIZE(g.RenderDrawLists); i++) + g.RenderDrawLists[i].clear(); + g.MouseCursorDrawList.ClearFreeMemory(); g.ColorEditModeStorage.Clear(); - if (g.LogFile && g.LogFile != stdout) - { - fclose(g.LogFile); - g.LogFile = NULL; - } - g.IO.Fonts->Clear(); - if (g.PrivateClipboard) { ImGui::MemFree(g.PrivateClipboard); g.PrivateClipboard = NULL; } + if (g.LogFile && g.LogFile != stdout) + { + fclose(g.LogFile); + g.LogFile = NULL; + } if (g.LogClipboard) { g.LogClipboard->~ImGuiTextBuffer(); ImGui::MemFree(g.LogClipboard); } - GDefaultFontAtlas.Clear(); + g.IO.Fonts->Clear(); g.Initialized = false; } @@ -1991,6 +2098,8 @@ static int ChildWindowComparer(const void* lhs, const void* rhs) { const ImGuiWindow* a = *(const ImGuiWindow**)lhs; const ImGuiWindow* b = *(const ImGuiWindow**)rhs; + if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup)) + return d; if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip)) return d; if (int d = (a->Flags & ImGuiWindowFlags_ComboBox) - (b->Flags & ImGuiWindowFlags_ComboBox)) @@ -1998,9 +2107,9 @@ static int ChildWindowComparer(const void* lhs, const void* rhs) return 0; } -static void AddWindowToSortedBuffer(ImGuiWindow* window, ImVector& sorted_windows) +static void AddWindowToSortedBuffer(ImVector& out_sorted_windows, ImGuiWindow* window) { - sorted_windows.push_back(window); + out_sorted_windows.push_back(window); if (window->Visible) { const size_t count = window->DC.ChildWindows.size(); @@ -2010,7 +2119,7 @@ static void AddWindowToSortedBuffer(ImGuiWindow* window, ImVector& { ImGuiWindow* child = window->DC.ChildWindows[i]; if (child->Visible) - AddWindowToSortedBuffer(child, sorted_windows); + AddWindowToSortedBuffer(out_sorted_windows, child); } } } @@ -2026,7 +2135,10 @@ static void PushClipRect(const ImVec4& clip_rect, bool clipped = true) const ImVec4 cur_cr = window->ClipRectStack.back(); cr = ImVec4(ImMax(cr.x, cur_cr.x), ImMax(cr.y, cur_cr.y), ImMin(cr.z, cur_cr.z), ImMin(cr.w, cur_cr.w)); } + cr.z = ImMax(cr.x, cr.z); + cr.w = ImMax(cr.y, cr.w); + IM_ASSERT(cr.x <= cr.z && cr.y <= cr.w); window->ClipRectStack.push_back(cr); window->DrawList->PushClipRect(cr); } @@ -2045,37 +2157,45 @@ void ImGui::Render() const bool first_render_of_the_frame = (g.FrameCountRendered != g.FrameCount); g.FrameCountRendered = g.FrameCount; - + if (first_render_of_the_frame) { // Hide implicit window if it hasn't been used - IM_ASSERT(g.CurrentWindowStack.size() == 1); // Mismatched Begin/End + IM_ASSERT(g.CurrentWindowStack.size() == 1); // Mismatched Begin/End if (g.CurrentWindow && !g.CurrentWindow->Accessed) g.CurrentWindow->Visible = false; ImGui::End(); - // Select window for move/focus when we're done with all our widgets (we use the root window ID here) - if (g.ActiveId == 0 && g.HoveredId == 0 && g.HoveredRootWindow != NULL && g.IO.MouseClicked[0]) + if (g.ActiveId == 0 && g.HoveredId == 0 && g.IO.MouseClicked[0]) { - IM_ASSERT(g.MovedWindow == NULL); - g.MovedWindow = g.HoveredWindow; - SetActiveId(g.HoveredRootWindow->GetID("#MOVE")); + if (g.HoveredRootWindow != NULL) + { + // Select window for move/focus when we're done with all our widgets (we use the root window ID here) + IM_ASSERT(g.MovedWindow == NULL); + g.MovedWindow = g.HoveredWindow; + SetActiveId(g.HoveredRootWindow->MoveID); + } + else if (g.FocusedWindow != NULL) + { + // Clicking on void disable focus + FocusWindow(NULL); + } } // Sort the window list so that all child windows are after their parent // We cannot do that on FocusWindow() because childs may not exist yet - g.RenderSortedWindows.resize(0); - g.RenderSortedWindows.reserve(g.Windows.size()); + g.WindowsSortBuffer.resize(0); + g.WindowsSortBuffer.reserve(g.Windows.size()); for (size_t i = 0; i != g.Windows.size(); i++) { ImGuiWindow* window = g.Windows[i]; if (window->Flags & ImGuiWindowFlags_ChildWindow) // if a child is visible its parent will add it if (window->Visible) continue; - AddWindowToSortedBuffer(window, g.RenderSortedWindows); + AddWindowToSortedBuffer(g.WindowsSortBuffer, window); } - IM_ASSERT(g.Windows.size() == g.RenderSortedWindows.size()); // we done something wrong - g.Windows.swap(g.RenderSortedWindows); + IM_ASSERT(g.Windows.size() == g.WindowsSortBuffer.size()); // we done something wrong + g.Windows.swap(g.WindowsSortBuffer); // Clear data for next frame g.IO.MouseWheel = 0.0f; @@ -2096,39 +2216,59 @@ void ImGui::Render() } // Gather windows to render - g.RenderDrawLists.resize(0); + g.IO.MetricsRenderVertices = 0; + for (size_t i = 0; i < IM_ARRAYSIZE(g.RenderDrawLists); i++) + g.RenderDrawLists[i].resize(0); for (size_t i = 0; i != g.Windows.size(); i++) { ImGuiWindow* window = g.Windows[i]; - if (window->Visible && (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0) - window->AddToRenderList(); + if (window->Visible && (window->Flags & (ImGuiWindowFlags_ChildWindow)) == 0) + { + // FIXME: Generalize this with a proper layering system so we can stack. + if (window->Flags & ImGuiWindowFlags_Popup) + AddWindowToRenderList(g.RenderDrawLists[1], window); + else if (window->Flags & ImGuiWindowFlags_Tooltip) + AddWindowToRenderList(g.RenderDrawLists[2], window); + else + AddWindowToRenderList(g.RenderDrawLists[0], window); + } } - for (size_t i = 0; i != g.Windows.size(); i++) + + // Flatten layers + size_t n = g.RenderDrawLists[0].size(); + size_t flattened_size = n; + for (size_t i = 1; i < IM_ARRAYSIZE(g.RenderDrawLists); i++) + flattened_size += g.RenderDrawLists[i].size(); + g.RenderDrawLists[0].resize(flattened_size); + for (size_t i = 1; i < IM_ARRAYSIZE(g.RenderDrawLists); i++) { - ImGuiWindow* window = g.Windows[i]; - if (window->Visible && (window->Flags & ImGuiWindowFlags_Tooltip)) - window->AddToRenderList(); + ImVector& layer = g.RenderDrawLists[i]; + if (!layer.empty()) + { + memcpy(&g.RenderDrawLists[0][n], &layer[0], layer.size() * sizeof(ImDrawList*)); + n += layer.size(); + } } if (g.IO.MouseDrawCursor) { - const ImVec2 pos = g.IO.MousePos; - const ImVec2 size = TEX_ATLAS_SIZE_MOUSE_CURSOR; + const ImGuiMouseCursorData& cursor_data = g.MouseCursorData[g.MouseCursor]; + const ImVec2 pos = g.IO.MousePos - cursor_data.Offset; + const ImVec2 size = cursor_data.Size; const ImTextureID tex_id = g.IO.Fonts->TexID; - const ImVec2 tex_uv_scale(1.0f/g.IO.Fonts->TexWidth, 1.0f/g.IO.Fonts->TexHeight); - static ImDrawList draw_list; - draw_list.Clear(); - draw_list.AddImage(tex_id, pos+ImVec2(1,0), pos+ImVec2(1,0) + size, TEX_ATLAS_POS_MOUSE_CURSOR_BLACK * tex_uv_scale, (TEX_ATLAS_POS_MOUSE_CURSOR_BLACK + size) * tex_uv_scale, 0x30000000); // Shadow - draw_list.AddImage(tex_id, pos+ImVec2(2,0), pos+ImVec2(2,0) + size, TEX_ATLAS_POS_MOUSE_CURSOR_BLACK * tex_uv_scale, (TEX_ATLAS_POS_MOUSE_CURSOR_BLACK + size) * tex_uv_scale, 0x30000000); // Shadow - draw_list.AddImage(tex_id, pos, pos + size, TEX_ATLAS_POS_MOUSE_CURSOR_BLACK * tex_uv_scale, (TEX_ATLAS_POS_MOUSE_CURSOR_BLACK + size) * tex_uv_scale, 0xFF000000); // Black border - draw_list.AddImage(tex_id, pos, pos + size, TEX_ATLAS_POS_MOUSE_CURSOR_WHITE * tex_uv_scale, (TEX_ATLAS_POS_MOUSE_CURSOR_WHITE + size) * tex_uv_scale, 0xFFFFFFFF); // White fill - g.RenderDrawLists.push_back(&draw_list); + g.MouseCursorDrawList.Clear(); + g.MouseCursorDrawList.PushTextureID(tex_id); + g.MouseCursorDrawList.AddImage(tex_id, pos+ImVec2(1,0), pos+ImVec2(1,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0x30000000); // Shadow + g.MouseCursorDrawList.AddImage(tex_id, pos+ImVec2(2,0), pos+ImVec2(2,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0x30000000); // Shadow + g.MouseCursorDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0xFF000000); // Black border + g.MouseCursorDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[0], cursor_data.TexUvMax[0], 0xFFFFFFFF); // White fill + g.MouseCursorDrawList.PopTextureID(); + AddDrawListToRenderList(g.RenderDrawLists[0], &g.MouseCursorDrawList); } // Render - if (!g.RenderDrawLists.empty()) - g.IO.RenderDrawListsFn(&g.RenderDrawLists[0], (int)g.RenderDrawLists.size()); - g.RenderDrawLists.resize(0); + if (!g.RenderDrawLists[0].empty()) + g.IO.RenderDrawListsFn(&g.RenderDrawLists[0][0], (int)g.RenderDrawLists[0].size()); } } @@ -2138,8 +2278,18 @@ static const char* FindTextDisplayEnd(const char* text, const char* text_end = const char* text_display_end = text; if (!text_end) text_end = (const char*)-1; - while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#')) - text_display_end++; + + ImGuiState& g = *GImGui; + if (g.DisableHideTextAfterDoubleHash > 0) + { + while (text_display_end < text_end && *text_display_end != '\0') + text_display_end++; + } + else + { + while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#')) + text_display_end++; + } return text_display_end; } @@ -2173,8 +2323,8 @@ static void LogText(const ImVec2& ref_pos, const char* text, const char* text_en if (!text_end) text_end = FindTextDisplayEnd(text, text_end); - const bool log_new_line = ref_pos.y > window->DC.LogLineHeight+1; - window->DC.LogLineHeight = ref_pos.y; + const bool log_new_line = ref_pos.y > window->DC.LogLinePosY+1; + window->DC.LogLinePosY = ref_pos.y; const char* text_remaining = text; if (g.LogStartDepth > window->DC.TreeDepth) // Re-adjust padding if we have popped out of our starting depth @@ -2224,7 +2374,7 @@ static float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) wrap_pos_x = ImGui::GetContentRegionMax().x; if (wrap_pos_x > 0.0f) wrap_pos_x += window->Pos.x; // wrap_pos_x is provided is window local space - + const float wrap_width = wrap_pos_x > 0.0f ? ImMax(wrap_pos_x - pos.x, 0.00001f) : 0.0f; return wrap_width; } @@ -2253,7 +2403,7 @@ static void RenderText(ImVec2 pos, const char* text, const char* text_end, bool if (text_len > 0) { // Render - window->DrawList->AddText(window->Font(), window->FontSize(), pos, window->Color(ImGuiCol_Text), text, text_display_end); + window->DrawList->AddText(g.Font, g.FontSize, pos, window->Color(ImGuiCol_Text), text, text_display_end); // Log as text if (g.LogEnabled) @@ -2273,7 +2423,7 @@ static void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end if (text_len > 0) { // Render - window->DrawList->AddText(window->Font(), window->FontSize(), pos, window->Color(ImGuiCol_Text), text, text_end, wrap_width); + window->DrawList->AddText(g.Font, g.FontSize, pos, window->Color(ImGuiCol_Text), text, text_end, wrap_width); // Log as text if (g.LogEnabled) @@ -2297,7 +2447,7 @@ static void RenderTextClipped(ImVec2 pos, const char* text, const char* text_end const bool need_clipping = (pos.x + text_size.x >= clip_max.x) || (pos.y + text_size.y >= clip_max.y); // Render - window->DrawList->AddText(window->Font(), window->FontSize(), pos, window->Color(ImGuiCol_Text), text, text_display_end, 0.0f, need_clipping ? &clip_max : NULL); + window->DrawList->AddText(g.Font, g.FontSize, pos, window->Color(ImGuiCol_Text), text, text_display_end, 0.0f, need_clipping ? &clip_max : NULL); // Log as text if (g.LogEnabled) @@ -2322,9 +2472,10 @@ static void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, // Render a triangle to denote expanded/collapsed state static void RenderCollapseTriangle(ImVec2 p_min, bool opened, float scale, bool shadow) { + ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - const float h = window->FontSize() * 1.00f; + const float h = g.FontSize * 1.00f; const float r = h * 0.40f * scale; ImVec2 center = p_min + ImVec2(h*0.50f, h*0.50f*scale); @@ -2342,7 +2493,7 @@ static void RenderCollapseTriangle(ImVec2 p_min, bool opened, float scale, bool b = center + ImVec2(-0.500f,0.866f)*r; c = center + ImVec2(-0.500f,-0.866f)*r; } - + if (shadow && (window->Flags & ImGuiWindowFlags_ShowBorders) != 0) window->DrawList->AddTriangleFilled(a+ImVec2(2,2), b+ImVec2(2,2), c+ImVec2(2,2), window->Color(ImGuiCol_BorderShadow)); window->DrawList->AddTriangleFilled(a, b, c, window->Color(ImGuiCol_Text)); @@ -2352,7 +2503,7 @@ static void RenderCollapseTriangle(ImVec2 p_min, bool opened, float scale, bool // CalcTextSize("") should return ImVec2(0.0f, GImGui->FontSize) ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiState& g = *GImGui; const char* text_display_end; if (hide_text_after_double_hash) @@ -2360,12 +2511,12 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex else text_display_end = text_end; - ImFont* font = window->Font(); - const float font_size = window->FontSize(); + ImFont* font = g.Font; + const float font_size = g.FontSize; ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL); // Cancel out character spacing for the last character of a line (it is baked into glyph->XAdvance field) - const float font_scale = font_size / font->FontSize; + const float font_scale = font_size / font->FontSize; const float character_spacing_x = 1.0f * font_scale; if (text_size.x > 0.0f) text_size.x -= character_spacing_x; @@ -2373,7 +2524,7 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex return text_size; } -// Helper to calculate coarse clipping of large list of evenly sized items. +// Helper to calculate coarse clipping of large list of evenly sized items. // If you are displaying thousands of items and you have a random access to the list, you can perform clipping yourself to save on CPU. // { // float item_height = ImGui::GetTextLineHeightWithSpacing(); @@ -2424,37 +2575,37 @@ static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs) continue; // Using the clipped AABB so a child window will typically be clipped by its parent. - ImGuiAabb bb(window->ClippedAabb.Min - g.Style.TouchExtraPadding, window->ClippedAabb.Max + g.Style.TouchExtraPadding); + ImRect bb(window->ClippedRect.Min - g.Style.TouchExtraPadding, window->ClippedRect.Max + g.Style.TouchExtraPadding); if (bb.Contains(pos)) return window; } return NULL; } -// Test if mouse cursor is hovering given aabb -// NB- Box is clipped by our current clip setting -// NB- Expand the aabb to be generous on imprecise inputs systems (g.Style.TouchExtraPadding) -static bool IsMouseHoveringBox(const ImGuiAabb& bb) +// Test if mouse cursor is hovering given rectangle +// NB- Rectangle is clipped by our current clip setting +// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding) +static bool IsMouseHoveringRect(const ImRect& rect) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); // Clip - ImGuiAabb box_clipped = bb; + ImRect rect_clipped = rect; if (!window->ClipRectStack.empty()) { const ImVec4 clip_rect = window->ClipRectStack.back(); - box_clipped.Clip(ImGuiAabb(ImVec2(clip_rect.x, clip_rect.y), ImVec2(clip_rect.z, clip_rect.w))); + rect_clipped.Clip(ImRect(ImVec2(clip_rect.x, clip_rect.y), ImVec2(clip_rect.z, clip_rect.w))); } // Expand for touch input - const ImGuiAabb box_for_touch(box_clipped.Min - g.Style.TouchExtraPadding, box_clipped.Max + g.Style.TouchExtraPadding); - return box_for_touch.Contains(g.IO.MousePos); + const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding); + return rect_for_touch.Contains(g.IO.MousePos); } -bool ImGui::IsMouseHoveringBox(const ImVec2& box_min, const ImVec2& box_max) +bool ImGui::IsMouseHoveringRect(const ImVec2& rect_min, const ImVec2& rect_max) { - return IsMouseHoveringBox(ImGuiAabb(box_min, box_max)); + return IsMouseHoveringRect(ImRect(rect_min, rect_max)); } bool ImGui::IsMouseHoveringWindow() @@ -2525,15 +2676,60 @@ bool ImGui::IsMouseDoubleClicked(int button) return g.IO.MouseDoubleClicked[button]; } +bool ImGui::IsMouseDragging(int button, float lock_threshold) +{ + ImGuiState& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (lock_threshold < 0.0f) + lock_threshold = g.IO.MouseDragThreshold; + return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold; +} + ImVec2 ImGui::GetMousePos() { return GImGui->IO.MousePos; } +ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold) +{ + ImGuiState& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (lock_threshold < 0.0f) + lock_threshold = g.IO.MouseDragThreshold; + if (g.IO.MouseDown[button]) + if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold) + return g.IO.MousePos - g.IO.MouseClickedPos[button]; // Assume we can only get active with left-mouse button (at the moment). + return ImVec2(0.0f, 0.0f); +} + +void ImGui::ResetMouseDragDelta(int button) +{ + ImGuiState& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr + g.IO.MouseClickedPos[button] = g.IO.MousePos; +} + +ImGuiMouseCursor ImGui::GetMouseCursor() +{ + return GImGui->MouseCursor; +} + +void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) +{ + GImGui->MouseCursor = cursor_type; +} + bool ImGui::IsItemHovered() { ImGuiWindow* window = GetCurrentWindow(); - return window->DC.LastItemHovered; + return window->DC.LastItemHoveredAndUsable; +} + +bool ImGui::IsItemHoveredRect() +{ + ImGuiWindow* window = GetCurrentWindow(); + return window->DC.LastItemHoveredRect; } bool ImGui::IsItemActive() @@ -2553,16 +2749,37 @@ bool ImGui::IsAnyItemActive() return g.ActiveId != 0; } -ImVec2 ImGui::GetItemBoxMin() +bool ImGui::IsItemVisible() { ImGuiWindow* window = GetCurrentWindow(); - return window->DC.LastItemAabb.Min; + ImRect r(window->ClipRectStack.back()); + return r.Overlaps(window->DC.LastItemRect); } -ImVec2 ImGui::GetItemBoxMax() +ImVec2 ImGui::GetItemRectMin() { ImGuiWindow* window = GetCurrentWindow(); - return window->DC.LastItemAabb.Max; + return window->DC.LastItemRect.Min; +} + +ImVec2 ImGui::GetItemRectMax() +{ + ImGuiWindow* window = GetCurrentWindow(); + return window->DC.LastItemRect.Max; +} + +ImVec2 ImGui::GetItemRectSize() +{ + ImGuiWindow* window = GetCurrentWindow(); + return window->DC.LastItemRect.GetSize(); +} + +ImVec2 ImGui::CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge, float outward) +{ + ImGuiWindow* window = GetCurrentWindow(); + ImRect rect = window->DC.LastItemRect; + rect.Expand(outward); + return rect.GetClosestPoint(pos, on_edge); } // Tooltip is stored and turned into a BeginTooltip()/EndTooltip() sequence at the end of the frame. Each call override previous value. @@ -2593,8 +2810,8 @@ int ImGui::GetFrameCount() void ImGui::BeginTooltip() { ImGuiState& g = *GImGui; - ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_Tooltip; - ImGui::Begin("##Tooltip", NULL, ImVec2(0,0), g.Style.Colors[ImGuiCol_TooltipBg].w, window_flags); + ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; + ImGui::Begin("##Tooltip", NULL, ImVec2(0,0), g.Style.Colors[ImGuiCol_TooltipBg].w, flags); } void ImGui::EndTooltip() @@ -2603,6 +2820,22 @@ void ImGui::EndTooltip() ImGui::End(); } +void ImGui::BeginPopup(bool* p_opened) +{ + IM_ASSERT(p_opened != NULL); // Must provide a bool at the moment + + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGuiWindowFlags flags = ImGuiWindowFlags_Popup|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; + ImGui::Begin("##Popup", p_opened, flags); +} + +void ImGui::EndPopup() +{ + IM_ASSERT(GetCurrentWindow()->Flags & ImGuiWindowFlags_Popup); + ImGui::End(); + ImGui::PopStyleVar(); +} + bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) { ImGuiState& g = *GImGui; @@ -2660,17 +2893,18 @@ void ImGui::EndChild() } else { - // When using auto-filling child window, we don't provide the width/height to ItemSize so that it doesn't feed back into automatic size-fitting. + // When using auto-filling child window, we don't provide full width/height to ItemSize so that it doesn't feed back into automatic size-fitting. + ImGuiState& g = *GImGui; ImVec2 sz = ImGui::GetWindowSize(); if (window->Flags & ImGuiWindowFlags_ChildWindowAutoFitX) - sz.x = 0; + sz.x = ImMax(g.Style.WindowMinSize.x, sz.x - g.Style.AutoFitPadding.x); if (window->Flags & ImGuiWindowFlags_ChildWindowAutoFitY) - sz.y = 0; - + sz.y = ImMax(g.Style.WindowMinSize.y, sz.y - g.Style.AutoFitPadding.y); + ImGui::End(); window = GetCurrentWindow(); - ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + sz); + ImRect bb(window->DC.CursorPos, window->DC.CursorPos + sz); ItemSize(sz); ItemAdd(bb, NULL); } @@ -2748,20 +2982,37 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl size = settings->Size; window->Size = window->SizeFull = size; } + + if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) + { + window->AutoFitFrames = 2; + window->AutoFitOnlyGrows = false; + } + else if (ImLengthSqr(window->Size) < 0.00001f) + { + window->AutoFitFrames = 2; + window->AutoFitOnlyGrows = true; + } + g.Windows.push_back(window); return window; } -// Push a new ImGui window to add widgets to. +// Push a new ImGui window to add widgets to. // - 'size' for a regular window denote the initial size for first-time creation (no saved data) and isn't that useful. Use SetNextWindowSize() prior to calling Begin() for more flexible window manipulation. // - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair. // - Begin/End can be called multiple times during the frame with the same window name to append content. -// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file). +// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file). // You can use the "##" or "###" markers to use the same label with different id, or same id with different label. See documentation at the top of this file. // - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned. // - Passing 'bool* p_opened' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed. // - Passing non-zero 'size' is roughly equivalent to calling SetNextWindowSize(size, ImGuiSetCond_FirstUseEver) prior to calling Begin(). -bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg_alpha, ImGuiWindowFlags flags) +bool ImGui::Begin(const char* name, bool* p_opened, ImGuiWindowFlags flags) +{ + return ImGui::Begin(name, p_opened, ImVec2(0.f, 0.f), -1.0f, flags); +} + +bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_use, float bg_alpha, ImGuiWindowFlags flags) { ImGuiState& g = *GImGui; const ImGuiStyle& style = g.Style; @@ -2769,20 +3020,24 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg IM_ASSERT(name != NULL); // Must pass a name // Find or create + bool window_is_new = false; ImGuiWindow* window = FindWindowByName(name); if (!window) - window = CreateNewWindow(name, size, flags); + { + window = CreateNewWindow(name, size_on_first_use, flags); + window_is_new = true; + } window->Flags = (ImGuiWindowFlags)flags; // Add to stack g.CurrentWindowStack.push_back(window); - g.CurrentWindow = window; + SetCurrentWindow(window); // Process SetNextWindow***() calls bool window_pos_set_by_api = false; if (g.SetNextWindowPosCond) { - const ImVec2 backup_cursor_pos = window->DC.CursorPos; + const ImVec2 backup_cursor_pos = window->DC.CursorPos; // FIXME: not sure of the exact reason of this anymore :( need to look into that. ImGui::SetWindowPos(g.SetNextWindowPosVal, g.SetNextWindowPosCond); window->DC.CursorPos = backup_cursor_pos; window_pos_set_by_api = true; @@ -2830,21 +3085,33 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->Visible = true; // New windows appears in front - if (window->LastFrameDrawn < current_frame - 1) - FocusWindow(window); + if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) + { + if (window->LastFrameDrawn < current_frame - 1) + { + FocusWindow(window); + + // Popup position themselves when they first appear + if (flags & ImGuiWindowFlags_Popup) + { + if (!window_pos_set_by_api) + window->PosFloat = g.IO.MousePos; + } + } + } window->LastFrameDrawn = current_frame; window->ClipRectStack.resize(0); // Reset contents size for auto-fitting - window->SizeContents = window->SizeContentsCurrent; - window->SizeContentsCurrent = ImVec2(0.0f, 0.0f); + window->SizeContents = window_is_new ? ImVec2(0.0f, 0.0f) : window->DC.CursorMaxPos - window->Pos; + window->SizeContents.y += window->ScrollY; if (flags & ImGuiWindowFlags_ChildWindow) { parent_window->DC.ChildWindows.push_back(window); window->Pos = window->PosFloat = parent_window->DC.CursorPos; - window->SizeFull = size; + window->SizeFull = size_on_first_use; } } @@ -2866,9 +3133,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->IDStack.resize(1); // Move window (at the beginning of the frame to avoid input lag or sheering). Only valid for root windows. - const ImGuiID move_id = window->GetID("#MOVE"); - RegisterAliveId(move_id); - if (g.ActiveId == move_id) + RegisterAliveId(window->MoveID); + if (g.ActiveId == window->MoveID) { if (g.IO.MouseDown[0]) { @@ -2897,12 +3163,10 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg // Clamp into view if (!(window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Tooltip)) { - // FIXME: Parameterize padding. - const ImVec2 pad = ImVec2(window->FontSize()*2.0f, window->FontSize()*2.0f); // FIXME: Parametrize of clarify this behavior. - if (g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. + if (window->AutoFitFrames <= 0 && g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. { - ImVec2 clip_min = pad; - ImVec2 clip_max = g.IO.DisplaySize - pad; + ImVec2 clip_min = style.DisplaySafeAreaPadding; + ImVec2 clip_max = g.IO.DisplaySize - style.DisplaySafeAreaPadding; window->PosFloat = ImMax(window->PosFloat + window->Size, clip_min) - window->Size; window->PosFloat = ImMin(window->PosFloat, clip_max); } @@ -2928,7 +3192,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->FocusIdxAllCounter = window->FocusIdxTabCounter = -1; window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = IM_INT_MAX; - ImGuiAabb title_bar_aabb = window->TitleBarAabb(); + ImRect title_bar_rect = window->TitleBarRect(); // Apply and ImClamp scrolling window->ScrollY = window->NextScrollY; @@ -2941,7 +3205,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg // Collapse window by double-clicking on title bar if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) { - if (!(window->Flags & ImGuiWindowFlags_NoCollapse) && g.HoveredWindow == window && IsMouseHoveringBox(title_bar_aabb) && g.IO.MouseDoubleClicked[0]) + if (!(window->Flags & ImGuiWindowFlags_NoCollapse) && g.HoveredWindow == window && IsMouseHoveringRect(title_bar_rect) && g.IO.MouseDoubleClicked[0]) { window->Collapsed = !window->Collapsed; if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) @@ -2954,32 +3218,49 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->Collapsed = false; } + // Calculate auto-fit size + ImVec2 size_auto_fit; + if ((window->Flags & ImGuiWindowFlags_Tooltip) != 0) + { + // Tooltip always resize. We keep the spacing symmetric on both axises for aesthetic purpose. + size_auto_fit = window->SizeContents + style.WindowPadding - ImVec2(0.0f, style.ItemSpacing.y); + } + else + { + size_auto_fit = ImClamp(window->SizeContents + style.AutoFitPadding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - style.AutoFitPadding)); + if (size_auto_fit.y < window->SizeContents.y + style.AutoFitPadding.y) + size_auto_fit.x += style.ScrollbarWidth; + } + const float window_rounding = (window->Flags & ImGuiWindowFlags_ChildWindow) ? style.ChildWindowRounding : style.WindowRounding; if (window->Collapsed) { + // We still process initial auto-fit on collapsed windows to get a window width + // But otherwise we don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. + if (window->AutoFitFrames > 0) + { + window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit; + title_bar_rect = window->TitleBarRect(); + } + // Draw title bar only - window->Size = title_bar_aabb.GetSize(); - window->DrawList->AddRectFilled(title_bar_aabb.GetTL(), title_bar_aabb.GetBR(), window->Color(ImGuiCol_TitleBgCollapsed), window_rounding); + window->Size = title_bar_rect.GetSize(); + window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), window->Color(ImGuiCol_TitleBgCollapsed), window_rounding); if (window->Flags & ImGuiWindowFlags_ShowBorders) { - window->DrawList->AddRect(title_bar_aabb.GetTL()+ImVec2(1,1), title_bar_aabb.GetBR()+ImVec2(1,1), window->Color(ImGuiCol_BorderShadow), window_rounding); - window->DrawList->AddRect(title_bar_aabb.GetTL(), title_bar_aabb.GetBR(), window->Color(ImGuiCol_Border), window_rounding); + window->DrawList->AddRect(title_bar_rect.GetTL()+ImVec2(1,1), title_bar_rect.GetBR()+ImVec2(1,1), window->Color(ImGuiCol_BorderShadow), window_rounding); + window->DrawList->AddRect(title_bar_rect.GetTL(), title_bar_rect.GetBR(), window->Color(ImGuiCol_Border), window_rounding); } } else { - window->Size = window->SizeFull; - ImU32 resize_col = 0; if ((window->Flags & ImGuiWindowFlags_Tooltip) != 0) { - // Tooltip always resize. We keep the spacing symmetric on both axises for aesthetic purpose. - const ImVec2 size_auto_fit = window->SizeContents + style.WindowPadding - ImVec2(0.0f, style.ItemSpacing.y); - window->SizeFull = size_auto_fit; + window->Size = window->SizeFull = size_auto_fit; } else { - const ImVec2 size_auto_fit = ImClamp(window->SizeContents + style.AutoFitPadding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - style.AutoFitPadding)); if ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) { // Don't continuously mark settings as dirty, the size of the window doesn't need to be stored. @@ -2988,42 +3269,42 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg else if (window->AutoFitFrames > 0) { // Auto-fit only grows during the first few frames - if (window->AutoFitOnlyGrows) - window->SizeFull = ImMax(window->SizeFull, size_auto_fit); - else - window->SizeFull = size_auto_fit; + window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit; if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); } else if (!(window->Flags & ImGuiWindowFlags_NoResize)) { // Manual resize grip - const ImGuiAabb resize_aabb(window->Aabb().GetBR()-ImVec2(18,18), window->Aabb().GetBR()); + const ImRect resize_rect(window->Rect().GetBR()-ImVec2(14,14), window->Rect().GetBR()); const ImGuiID resize_id = window->GetID("#RESIZE"); bool hovered, held; - ButtonBehaviour(resize_aabb, resize_id, &hovered, &held, true); + ButtonBehavior(resize_rect, resize_id, &hovered, &held, true); resize_col = window->Color(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); + if (hovered || held) + g.MouseCursor = ImGuiMouseCursor_ResizeNWSE; + if (g.HoveredWindow == window && held && g.IO.MouseDoubleClicked[0]) { // Manual auto-fit when double-clicking window->SizeFull = size_auto_fit; - window->Size = window->SizeFull; if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); + SetActiveId(0); } else if (held) { // Resize window->SizeFull = ImMax(window->SizeFull + g.IO.MouseDelta, style.WindowMinSize); - window->Size = window->SizeFull; if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); } } - // Update aabb immediately so that rendering right below us isn't one frame late - title_bar_aabb = window->TitleBarAabb(); + // Update rectangle immediately so that rendering right below us isn't one frame late + window->Size = window->SizeFull; + title_bar_rect = window->TitleBarRect(); } // Scrollbar @@ -3044,7 +3325,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg // Title bar if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) - window->DrawList->AddRectFilled(title_bar_aabb.GetTL(), title_bar_aabb.GetBR(), window->Color(ImGuiCol_TitleBg), window_rounding, 1|2); + window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), window->Color(ImGuiCol_TitleBg), window_rounding, 1|2); // Borders if (window->Flags & ImGuiWindowFlags_ShowBorders) @@ -3052,7 +3333,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->DrawList->AddRect(window->Pos+ImVec2(1,1), window->Pos+window->Size+ImVec2(1,1), window->Color(ImGuiCol_BorderShadow), window_rounding); window->DrawList->AddRect(window->Pos, window->Pos+window->Size, window->Color(ImGuiCol_Border), window_rounding); if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) - window->DrawList->AddLine(title_bar_aabb.GetBL(), title_bar_aabb.GetBR(), window->Color(ImGuiCol_Border)); + window->DrawList->AddLine(title_bar_rect.GetBL(), title_bar_rect.GetBR(), window->Color(ImGuiCol_Border)); } // Scrollbar @@ -3064,7 +3345,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg if (!(window->Flags & ImGuiWindowFlags_NoResize)) { const float r = window_rounding; - const ImVec2 br = window->Aabb().GetBR(); + const ImVec2 br = window->Rect().GetBR(); if (r == 0.0f) { window->DrawList->AddTriangleFilled(br, br-ImVec2(0,14), br-ImVec2(14,0), resize_col); @@ -3072,7 +3353,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg else { // FIXME: We should draw 4 triangles and decide on a size that's not dependent on the rounding size (previously used 18) - window->DrawList->AddArc(br - ImVec2(r,r), r, resize_col, 6, 9, true); + window->DrawList->AddArcFast(br - ImVec2(r,r), r, resize_col, 6, 9, true); window->DrawList->AddTriangleFilled(br+ImVec2(0,-2*r),br+ImVec2(0,-r),br+ImVec2(-r,-r), resize_col); window->DrawList->AddTriangleFilled(br+ImVec2(-r,-r), br+ImVec2(-r,0),br+ImVec2(-2*r,0), resize_col); } @@ -3085,10 +3366,12 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.ColumnsStartX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->WindowPadding().y) - ImVec2(0.0f, window->ScrollY); window->DC.CursorPos = window->DC.CursorStartPos; window->DC.CursorPosPrevLine = window->DC.CursorPos; + window->DC.CursorMaxPos = window->DC.CursorStartPos; window->DC.CurrentLineHeight = window->DC.PrevLineHeight = 0.0f; - window->DC.LogLineHeight = window->DC.CursorPos.y - 9999.0f; + window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; + window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; window->DC.ChildWindows.resize(0); - window->DC.ItemWidth.resize(0); + window->DC.ItemWidth.resize(0); window->DC.ItemWidth.push_back(window->ItemWidthDefault); window->DC.AllowKeyboardFocus.resize(0); window->DC.AllowKeyboardFocus.push_back(true); @@ -3101,6 +3384,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY = window->DC.ColumnsStartPos.y; window->DC.TreeDepth = 0; window->DC.StateStorage = &window->StateStorage; + window->DC.GroupStack.resize(0); if (window->AutoFitFrames > 0) window->AutoFitFrames--; @@ -3115,23 +3399,45 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg if (!(window->Flags & ImGuiWindowFlags_NoCollapse)) { RenderCollapseTriangle(window->Pos + style.FramePadding, !window->Collapsed, 1.0f, true); - text_min.x += window->FontSize() + style.ItemInnerSpacing.x; + text_min.x += g.FontSize + style.ItemInnerSpacing.x; } const ImVec2 text_size = CalcTextSize(name, NULL, true); - const ImVec2 text_max = window->Pos + ImVec2(window->Size.x - (p_opened ? (title_bar_aabb.GetHeight()-3) : style.FramePadding.x), style.FramePadding.y*2 + text_size.y); + const ImVec2 text_max = window->Pos + ImVec2(window->Size.x - (p_opened ? (title_bar_rect.GetHeight()-3) : style.FramePadding.x), style.FramePadding.y*2 + text_size.y); RenderTextClipped(text_min, name, NULL, &text_size, text_max); } + if (window->Flags & ImGuiWindowFlags_Popup) + { + if (p_opened) + { + if (g.IO.MouseClicked[0] && (!g.HoveredWindow || g.HoveredWindow->RootWindow != window)) + *p_opened = false; + else if (!g.FocusedWindow) + *p_opened = false; + else if (g.FocusedWindow->RootWindow != window)// && !(g.FocusedWindow->RootWindow->Flags & ImGuiWindowFlags_Tooltip)) + *p_opened = false; + } + } // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() - window->ClippedAabb = window->Aabb(); - window->ClippedAabb.Clip(window->ClipRectStack.front()); + window->ClippedRect = window->Rect(); + window->ClippedRect.Clip(window->ClipRectStack.front()); + + // Pressing CTRL+C while holding on a window copy its content to the clipboard + // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope. + // Maybe we can support CTRL+C on every element? + /* + if (g.ActiveId == move_id) + if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C)) + ImGui::LogToClipboard(); + */ } // Inner clipping rectangle // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame - const ImGuiAabb title_bar_aabb = window->TitleBarAabb(); - ImVec4 clip_rect(title_bar_aabb.Min.x+0.5f+window->WindowPadding().x*0.5f, title_bar_aabb.Max.y+0.5f, window->Aabb().Max.x+0.5f-window->WindowPadding().x*0.5f, window->Aabb().Max.y-1.5f); + // Note that if our window is collapsed we will end up with a null clipping rectangle which is the correct behavior. + const ImRect title_bar_rect = window->TitleBarRect(); + ImVec4 clip_rect(title_bar_rect.Min.x+0.5f+window->WindowPadding().x*0.5f, title_bar_rect.Max.y+0.5f, window->Rect().Max.x+0.5f-window->WindowPadding().x*0.5f, window->Rect().Max.y-1.5f); if (window->ScrollbarY) clip_rect.z -= style.ScrollbarWidth; PushClipRect(clip_rect); @@ -3159,7 +3465,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->Visible = false; // Return false if we don't intend to display anything to allow user to perform an early out optimization - window->SkipItems = window->Collapsed || (!window->Visible && window->AutoFitFrames == 0); + window->SkipItems = (window->Collapsed || !window->Visible) && window->AutoFitFrames <= 0; return !window->SkipItems; } @@ -3180,7 +3486,7 @@ void ImGui::End() // Pop // NB: we don't clear 'window->RootWindow'. The pointer is allowed to live until the next call to Begin(). g.CurrentWindowStack.pop_back(); - g.CurrentWindow = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back(); + SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back()); } // Vertical scrollbar @@ -3194,21 +3500,21 @@ static void Scrollbar(ImGuiWindow* window) const ImGuiID id = window->GetID("#SCROLLY"); // Render background - ImGuiAabb bb(window->Aabb().Max.x - style.ScrollbarWidth, window->Pos.y + window->TitleBarHeight()+1, window->Aabb().Max.x, window->Aabb().Max.y-1); + ImRect bb(window->Rect().Max.x - style.ScrollbarWidth, window->Pos.y + window->TitleBarHeight()+1, window->Rect().Max.x, window->Rect().Max.y-1); window->DrawList->AddRectFilled(bb.Min, bb.Max, window->Color(ImGuiCol_ScrollbarBg)); - bb.Expand(ImVec2(-3,-3)); + bb.Expand(-3.0f); const float scrollbar_height = bb.GetHeight(); // The grabable box size 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. - const float grab_h_pixels = ImMax(style.GrabMinSize, scrollbar_height * ImSaturate(window->Size.y / ImMax(window->SizeContents.y, window->Size.y))); + const float grab_h_pixels = ImMin(ImMax(scrollbar_height * ImSaturate(window->Size.y / ImMax(window->SizeContents.y, window->Size.y)), style.GrabMinSize), scrollbar_height); const float grab_h_norm = grab_h_pixels / scrollbar_height; // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar(). bool held = false; bool hovered = false; const bool previously_held = (g.ActiveId == id); - ButtonBehaviour(bb, id, &hovered, &held, true); + ButtonBehavior(bb, id, &hovered, &held, true); const float scroll_max = ImMax(1.0f, window->SizeContents.y - window->Size.y); float scroll_ratio = ImSaturate(window->ScrollY / scroll_max); @@ -3260,7 +3566,11 @@ static void FocusWindow(ImGuiWindow* window) // Always mark the window we passed as focused. This is used for keyboard interactions such as tabbing. g.FocusedWindow = window; - // And move its root window to the top of the pile + // Passing NULL allow to disable keyboard focus + if (!window) + return; + + // And move its root window to the top of the pile if (window->RootWindow) window = window->RootWindow; @@ -3311,7 +3621,8 @@ static void SetFont(ImFont* font) IM_ASSERT(font && font->IsLoaded()); IM_ASSERT(font->Scale > 0.0f); g.Font = font; - g.FontSize = g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale; + g.FontBaseSize = g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale; + g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; g.FontTexUvWhitePixel = g.Font->ContainerAtlas->TexUvWhitePixel; } @@ -3393,7 +3704,8 @@ static float* GetStyleVarFloatAddr(ImGuiStyleVar idx) case ImGuiStyleVar_WindowRounding: return &g.Style.WindowRounding; case ImGuiStyleVar_ChildWindowRounding: return &g.Style.ChildWindowRounding; case ImGuiStyleVar_FrameRounding: return &g.Style.FrameRounding; - case ImGuiStyleVar_TreeNodeSpacing: return &g.Style.TreeNodeSpacing; + case ImGuiStyleVar_IndentSpacing: return &g.Style.IndentSpacing; + case ImGuiStyleVar_GrabMinSize: return &g.Style.GrabMinSize; } return NULL; } @@ -3465,6 +3777,8 @@ const char* ImGui::GetStyleColName(ImGuiCol idx) case ImGuiCol_Border: return "Border"; case ImGuiCol_BorderShadow: return "BorderShadow"; case ImGuiCol_FrameBg: return "FrameBg"; + case ImGuiCol_FrameBgHovered: return "FrameBgHovered"; + case ImGuiCol_FrameBgActive: return "FrameBgActive"; case ImGuiCol_TitleBg: return "TitleBg"; case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed"; case ImGuiCol_ScrollbarBg: return "ScrollbarBg"; @@ -3472,8 +3786,6 @@ const char* ImGui::GetStyleColName(ImGuiCol idx) case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered"; case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive"; case ImGuiCol_ComboBg: return "ComboBg"; - case ImGuiCol_CheckHovered: return "CheckHovered"; - case ImGuiCol_CheckActive: return "CheckActive"; case ImGuiCol_CheckMark: return "CheckMark"; case ImGuiCol_SliderGrab: return "SliderGrab"; case ImGuiCol_SliderGrabActive: return "SliderGrabActive"; @@ -3503,13 +3815,27 @@ const char* ImGui::GetStyleColName(ImGuiCol idx) return "Unknown"; } -bool ImGui::GetWindowIsFocused() +bool ImGui::IsWindowFocused() { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); return g.FocusedWindow == window; } +bool ImGui::IsRootWindowFocused() +{ + ImGuiState& g = *GImGui; + ImGuiWindow* root_window = GetCurrentWindow()->RootWindow; + return g.FocusedWindow == root_window; +} + +bool ImGui::IsRootWindowOrAnyChildFocused() +{ + ImGuiState& g = *GImGui; + ImGuiWindow* root_window = GetCurrentWindow()->RootWindow; + return g.FocusedWindow && g.FocusedWindow->RootWindow == root_window; +} + float ImGui::GetWindowWidth() { ImGuiWindow* window = GetCurrentWindow(); @@ -3533,7 +3859,8 @@ static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiSetCond co const ImVec2 old_pos = window->Pos; window->PosFloat = pos; window->Pos = ImVec2((float)(int)window->PosFloat.x, (float)(int)window->PosFloat.y); - window->DC.CursorPos += (window->Pos - old_pos); // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor + window->DC.CursorPos += (window->Pos - old_pos); // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor + window->DC.CursorMaxPos += (window->Pos - old_pos); // And more importantly we need to adjust this so size calculation doesn't get affected. } void ImGui::SetWindowPos(const ImVec2& pos, ImGuiSetCond cond) @@ -3627,9 +3954,16 @@ void ImGui::SetWindowFocus() void ImGui::SetWindowFocus(const char* name) { - ImGuiWindow* window = FindWindowByName(name); - if (window) - FocusWindow(window); + if (name) + { + ImGuiWindow* window = FindWindowByName(name); + if (window) + FocusWindow(window); + } + else + { + FocusWindow(NULL); + } } void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiSetCond cond) @@ -3694,15 +4028,14 @@ ImVec2 ImGui::GetWindowContentRegionMax() float ImGui::GetTextLineHeight() { - ImGuiWindow* window = GetCurrentWindow(); - return window->FontSize(); + ImGuiState& g = *GImGui; + return g.FontSize; } float ImGui::GetTextLineHeightWithSpacing() { ImGuiState& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); - return window->FontSize() + g.Style.ItemSpacing.y; + return g.FontSize + g.Style.ItemSpacing.y; } ImDrawList* ImGui::GetWindowDrawList() @@ -3713,20 +4046,22 @@ ImDrawList* ImGui::GetWindowDrawList() ImFont* ImGui::GetWindowFont() { - ImGuiWindow* window = GetCurrentWindow(); - return window->Font(); + ImGuiState& g = *GImGui; + return g.Font; } float ImGui::GetWindowFontSize() { - ImGuiWindow* window = GetCurrentWindow(); - return window->FontSize(); + ImGuiState& g = *GImGui; + return g.FontSize; } void ImGui::SetWindowFontScale(float scale) { + ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); window->FontWindowScale = scale; + g.FontSize = window->CalcFontSize(); } // NB: internally we store CursorPos in absolute screen coordinates because it is more convenient. @@ -3751,21 +4086,21 @@ void ImGui::SetCursorPos(const ImVec2& pos) { ImGuiWindow* window = GetCurrentWindow(); window->DC.CursorPos = window->Pos + pos; - window->SizeContentsCurrent = ImMax(window->SizeContentsCurrent, pos + ImVec2(0.0f, window->ScrollY)); + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); } void ImGui::SetCursorPosX(float x) { ImGuiWindow* window = GetCurrentWindow(); window->DC.CursorPos.x = window->Pos.x + x; - window->SizeContentsCurrent.x = ImMax(window->SizeContentsCurrent.x, x); + window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x); } void ImGui::SetCursorPosY(float y) { ImGuiWindow* window = GetCurrentWindow(); window->DC.CursorPos.y = window->Pos.y + y; - window->SizeContentsCurrent.y = ImMax(window->SizeContentsCurrent.y, y + window->ScrollY); + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y); } ImVec2 ImGui::GetCursorScreenPos() @@ -3819,13 +4154,13 @@ ImGuiStorage* ImGui::GetStateStorage() void ImGui::TextV(const char* fmt, va_list args) { + ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return; - static char buf[1024]; - const char* text_end = buf + ImFormatStringV(buf, IM_ARRAYSIZE(buf), fmt, args); - TextUnformatted(buf, text_end); + const char* text_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + TextUnformatted(g.TempBuffer, text_end); } void ImGui::Text(const char* fmt, ...) @@ -3884,22 +4219,22 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) { // 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. + // 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. const char* line = text; const float line_height = ImGui::GetTextLineHeight(); - const ImVec2 start_pos = window->DC.CursorPos; + const ImVec2 text_pos = window->DC.CursorPos + ImVec2(0.0f, window->DC.CurrentLineTextBaseOffset); const ImVec4 clip_rect = window->ClipRectStack.back(); ImVec2 text_size(0,0); - if (start_pos.y <= clip_rect.w) + if (text_pos.y <= clip_rect.w) { - ImVec2 pos = start_pos; + ImVec2 pos = text_pos; // Lines to skip (can't skip when logging text) if (!g.LogEnabled) { - int lines_skippable = (int)((clip_rect.y - start_pos.y) / line_height) - 1; + int lines_skippable = (int)((clip_rect.y - text_pos.y) / line_height) - 1; if (lines_skippable > 0) { int lines_skipped = 0; @@ -3916,11 +4251,11 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) // Lines to render if (line < text_end) { - ImGuiAabb line_box(pos, pos + ImVec2(ImGui::GetWindowWidth(), line_height)); + ImRect line_rect(pos, pos + ImVec2(ImGui::GetWindowWidth(), line_height)); while (line < text_end) { const char* line_end = strchr(line, '\n'); - if (IsClipped(line_box)) + if (IsClippedEx(line_rect, false)) break; const ImVec2 line_size = CalcTextSize(line, line_end, false); @@ -3929,8 +4264,8 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) if (!line_end) line_end = text_end; line = line_end + 1; - line_box.Min.y += line_height; - line_box.Max.y += line_height; + line_rect.Min.y += line_height; + line_rect.Max.y += line_height; pos.y += line_height; } @@ -3947,9 +4282,10 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) pos.y += lines_skipped * line_height; } - text_size.y += (pos - start_pos).y; + text_size.y += (pos - text_pos).y; } - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + text_size); + + ImRect bb(text_pos, text_pos + text_size); ItemSize(bb); ItemAdd(bb, NULL); } @@ -3957,8 +4293,13 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) { const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f; const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width); - ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + text_size); - ItemSize(bb.GetSize(), &bb.Min); + + // Account of baseline offset + ImVec2 text_pos = window->DC.CursorPos; + text_pos.y += window->DC.CurrentLineTextBaseOffset; + + ImRect bb(text_pos, text_pos + text_size); + ItemSize(bb.GetSize()); if (!ItemAdd(bb, NULL)) return; @@ -3975,7 +4316,7 @@ void ImGui::AlignFirstTextHeightToWidgets() return; // Declare a dummy item size to that upcoming items that are smaller will center-align on the newly expanded line height. - ItemSize(ImVec2(0, window->FontSize() + g.Style.FramePadding.y*2)); + ItemSize(ImVec2(0, g.FontSize + g.Style.FramePadding.y*2), g.Style.FramePadding.y); ImGui::SameLine(0, 0); } @@ -3986,23 +4327,23 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return; + const ImGuiStyle& style = g.Style; const float w = ImGui::CalcItemWidth(); - static char buf[1024]; - const char* value_text_begin = &buf[0]; - const char* value_text_end = value_text_begin + ImFormatStringV(buf, IM_ARRAYSIZE(buf), fmt, args); + const char* value_text_begin = &g.TempBuffer[0]; + const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImGuiAabb value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + style.FramePadding.x*2, label_size.y)); - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + style.FramePadding.x*2 + (label_size.x > 0.0f ? style.ItemInnerSpacing.x : 0.0f), 0.0f) + label_size); - ItemSize(bb); - if (!ItemAdd(value_bb, NULL)) + const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + style.FramePadding.x*2, label_size.y + style.FramePadding.y*2)); + const ImRect total_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + style.FramePadding.x*2 + (label_size.x > 0.0f ? style.ItemInnerSpacing.x : 0.0f), style.FramePadding.y*2) + label_size); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, NULL)) return; // Render - RenderTextClipped(value_bb.Min, value_text_begin, value_text_end, NULL, value_bb.Max); - RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y), label); + RenderTextClipped(ImVec2(value_bb.Min.x, value_bb.Min.y + style.FramePadding.y), value_text_begin, value_text_end, NULL, value_bb.Max); + RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label); } void ImGui::LabelText(const char* label, const char* fmt, ...) @@ -4013,22 +4354,34 @@ void ImGui::LabelText(const char* label, const char* fmt, ...) va_end(args); } -static bool IsHovered(const ImGuiAabb& bb, const ImGuiID& id) +static inline bool IsWindowContentHoverable(ImGuiWindow* window) +{ + ImGuiState& g = *GImGui; + + // An active popup disable hovering on other windows (apart from its own children) + if (ImGuiWindow* focused_window = g.FocusedWindow) + if (ImGuiWindow* focused_root_window = focused_window->RootWindow) + if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) != 0 && focused_root_window->WasVisible && focused_root_window != window->RootWindow) + return false; + + return true; +} + +static bool IsHovered(const ImRect& bb, ImGuiID id) { ImGuiState& g = *GImGui; if (g.HoveredId == 0) { ImGuiWindow* window = GetCurrentWindow(); if (g.HoveredRootWindow == window->RootWindow) - { - bool hovered = (g.ActiveId == 0 || g.ActiveId == id || g.ActiveIdIsFocusedOnly) && IsMouseHoveringBox(bb); - return hovered; - } + if ((g.ActiveId == 0 || g.ActiveId == id || g.ActiveIdIsFocusedOnly) && IsMouseHoveringRect(bb)) + if (IsWindowContentHoverable(g.HoveredRootWindow)) + return true; } return false; } -static bool ButtonBehaviour(const ImGuiAabb& bb, const ImGuiID& id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, bool repeat, bool pressed_on_click) +static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, bool repeat, bool pressed_on_click) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -4038,7 +4391,7 @@ static bool ButtonBehaviour(const ImGuiAabb& bb, const ImGuiID& id, bool* out_ho if (hovered) { g.HoveredId = id; - if (allow_key_modifiers || (!g.IO.KeyCtrl && !g.IO.KeyShift)) + if (allow_key_modifiers || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt)) { if (g.IO.MouseClicked[0]) { @@ -4092,21 +4445,21 @@ bool ImGui::Button(const char* label, const ImVec2& size_arg, bool repeat_when_h const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y); - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + size + style.FramePadding*2.0f); - ItemSize(bb); + const ImVec2 size(size_arg.x != 0.0f ? size_arg.x : (label_size.x + style.FramePadding.x*2), size_arg.y != 0.0f ? size_arg.y : (label_size.y + style.FramePadding.y*2)); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + ItemSize(bb, style.FramePadding.y); if (!ItemAdd(bb, &id)) return false; bool hovered, held; - bool pressed = ButtonBehaviour(bb, id, &hovered, &held, true, repeat_when_held); + bool pressed = ButtonBehavior(bb, id, &hovered, &held, true, repeat_when_held); // Render const ImU32 col = window->Color((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); const ImVec2 off = ImVec2(ImMax(0.0f, size.x - label_size.x) * 0.5f, ImMax(0.0f, size.y - label_size.y) * 0.5f); // Center (only applies if we explicitly gave a size bigger than the text size, which isn't the common path) - RenderTextClipped(bb.Min + style.FramePadding + off, label, NULL, &label_size, bb.Max); // Render clip (only applies if we explicitly gave a size smaller than the text size, which isn't the commmon path) + RenderTextClipped(bb.Min + off, label, NULL, &label_size, bb.Max); // Render clip (only applies if we explicitly gave a size smaller than the text size, which isn't the commmon path) return pressed; } @@ -4123,13 +4476,15 @@ bool ImGui::SmallButton(const char* label) const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + label_size + ImVec2(style.FramePadding.x*2,0)); + ImVec2 text_pos = window->DC.CursorPos; + text_pos.y += window->DC.CurrentLineTextBaseOffset; + ImRect bb(text_pos, text_pos + label_size + ImVec2(style.FramePadding.x*2,0)); ItemSize(bb); if (!ItemAdd(bb, &id)) return false; bool hovered, held; - bool pressed = ButtonBehaviour(bb, id, &hovered, &held, true); + bool pressed = ButtonBehavior(bb, id, &hovered, &held, true); // Render const ImU32 col = window->Color((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); @@ -4148,13 +4503,13 @@ bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size) return false; const ImGuiID id = window->GetID(str_id); - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + size); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); ItemSize(bb); if (!ItemAdd(bb, &id)) return false; bool hovered, held; - bool pressed = ButtonBehaviour(bb, id, &hovered, &held, true); + bool pressed = ButtonBehavior(bb, id, &hovered, &held, true); return pressed; } @@ -4166,10 +4521,10 @@ static bool CloseWindowButton(bool* p_opened) const ImGuiID id = window->GetID("#CLOSE"); const float size = window->TitleBarHeight() - 4.0f; - const ImGuiAabb bb(window->Aabb().GetTR() + ImVec2(-3.0f-size,2.0f), window->Aabb().GetTR() + ImVec2(-3.0f,2.0f+size)); + const ImRect bb(window->Rect().GetTR() + ImVec2(-3.0f-size,2.0f), window->Rect().GetTR() + ImVec2(-3.0f,2.0f+size)); bool hovered, held; - bool pressed = ButtonBehaviour(bb, id, &hovered, &held, true); + bool pressed = ButtonBehavior(bb, id, &hovered, &held, true); // Render const ImU32 col = window->Color((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_CloseButtonHovered : ImGuiCol_CloseButton); @@ -4195,7 +4550,7 @@ void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& if (window->SkipItems) return; - ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + size); + ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); if (border_col.w > 0.0f) bb.Max += ImVec2(2,2); ItemSize(bb); @@ -4233,14 +4588,14 @@ bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const I ImGui::PopID(); const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : style.FramePadding; - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + size + padding*2); - const ImGuiAabb image_bb(window->DC.CursorPos + padding, window->DC.CursorPos + padding + size); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding*2); + const ImRect image_bb(window->DC.CursorPos + padding, window->DC.CursorPos + padding + size); ItemSize(bb); if (!ItemAdd(bb, &id)) return false; bool hovered, held; - bool pressed = ButtonBehaviour(bb, id, &hovered, &held, true); + bool pressed = ButtonBehavior(bb, id, &hovered, &held, true); // Render const ImU32 col = window->Color((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); @@ -4276,7 +4631,11 @@ void ImGui::LogToFile(int max_depth, const char* filename) if (g.LogEnabled) return; if (!filename) + { filename = g.IO.LogFilename; + if (!filename) + return; + } g.LogFile = fopen(filename, "ab"); if (!g.LogFile) @@ -4336,7 +4695,7 @@ void ImGui::LogButtons() ImGui::PushID("LogButtons"); const bool log_to_tty = ImGui::Button("Log To TTY"); - ImGui::SameLine(); + ImGui::SameLine(); const bool log_to_file = ImGui::Button("Log To File"); ImGui::SameLine(); const bool log_to_clipboard = ImGui::Button("Log To Clipboard"); @@ -4410,7 +4769,7 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 pos_min = window->DC.CursorPos; const ImVec2 pos_max = window->Pos + GetContentRegionMax(); - ImGuiAabb bb = ImGuiAabb(pos_min, ImVec2(pos_max.x, pos_min.y + label_size.y)); + ImRect bb = ImRect(pos_min, ImVec2(pos_max.x, pos_min.y + label_size.y)); if (display_frame) { bb.Min.x -= window_padding.x*0.5f - 1; @@ -4418,10 +4777,11 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display bb.Max.y += style.FramePadding.y * 2; } - const ImGuiAabb text_bb(bb.Min, bb.Min + ImVec2(window->FontSize() + style.FramePadding.x*2*2,0) + label_size); - ItemSize(ImVec2(text_bb.GetSize().x, bb.GetSize().y)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit + // FIXME: we don't provide our width so that it doesn't get feed back into AutoFit. Should manage that better so we can still hover without extending ContentsSize + const ImRect text_bb(bb.Min, bb.Min + ImVec2(g.FontSize + style.FramePadding.x*2*2,0) + label_size); + ItemSize(ImVec2(text_bb.GetSize().x, bb.GetSize().y), display_frame ? style.FramePadding.y : 0.0f); - // When logging is enabled, if automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behaviour). + // When logging is enabled, if 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 && !display_frame && window->DC.TreeDepth < g.LogAutoExpandMaxDepth) opened = true; @@ -4430,7 +4790,7 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display return opened; bool hovered, held; - bool pressed = ButtonBehaviour(display_frame ? bb : text_bb, id, &hovered, &held, false); + bool pressed = ButtonBehavior(display_frame ? bb : text_bb, id, &hovered, &held, false); if (pressed) { opened = !opened; @@ -4450,7 +4810,7 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display const char log_prefix[] = "\n##"; LogText(bb.Min + style.FramePadding, log_prefix, log_prefix+3); } - RenderText(bb.Min + style.FramePadding + ImVec2(window->FontSize() + style.FramePadding.x*2,0), label); + RenderText(bb.Min + style.FramePadding + ImVec2(g.FontSize + style.FramePadding.x*2,0), label); if (g.LogEnabled) { const char log_suffix[] = "##"; @@ -4462,10 +4822,10 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display // Unframed typed for tree nodes if ((held && hovered) || hovered) RenderFrame(bb.Min, bb.Max, col, false); - RenderCollapseTriangle(bb.Min + ImVec2(style.FramePadding.x, window->FontSize()*0.15f), opened, 0.70f, false); + RenderCollapseTriangle(bb.Min + ImVec2(style.FramePadding.x, g.FontSize*0.15f), opened, 0.70f, false); if (g.LogEnabled) LogText(bb.Min, ">"); - RenderText(bb.Min + ImVec2(window->FontSize() + style.FramePadding.x*2,0), label); + RenderText(bb.Min + ImVec2(g.FontSize + style.FramePadding.x*2,0), label); } return opened; @@ -4479,8 +4839,8 @@ void ImGui::Bullet() return; const ImGuiStyle& style = g.Style; - const float line_height = window->FontSize(); - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(line_height, line_height)); + const float line_height = g.FontSize; + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(line_height, line_height)); ItemSize(bb); if (!ItemAdd(bb, NULL)) return; @@ -4500,15 +4860,14 @@ void ImGui::BulletTextV(const char* fmt, va_list args) ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return; - - static char buf[1024]; - const char* text_begin = buf; - const char* text_end = text_begin + ImFormatStringV(buf, IM_ARRAYSIZE(buf), fmt, args); + + const char* text_begin = g.TempBuffer; + const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); const ImGuiStyle& style = g.Style; - const float line_height = window->FontSize(); + const float line_height = g.FontSize; const ImVec2 label_size = CalcTextSize(text_begin, text_end, true); - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(line_height + (label_size.x > 0.0f ? (style.FramePadding.x*2) : 0.0f),0) + label_size); // Empty text doesn't add padding + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(line_height + (label_size.x > 0.0f ? (style.FramePadding.x*2) : 0.0f),0) + label_size); // Empty text doesn't add padding ItemSize(bb); if (!ItemAdd(bb, NULL)) return; @@ -4516,7 +4875,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args) // Render const float bullet_size = line_height*0.15f; window->DrawList->AddCircleFilled(bb.Min + ImVec2(style.FramePadding.x + line_height*0.5f, line_height*0.5f), bullet_size, window->Color(ImGuiCol_Text)); - RenderText(bb.Min+ImVec2(window->FontSize() + style.FramePadding.x*2,0), text_begin, text_end); + RenderText(bb.Min+ImVec2(g.FontSize + style.FramePadding.x*2,0), text_begin, text_end); } void ImGui::BulletText(const char* fmt, ...) @@ -4530,14 +4889,18 @@ void ImGui::BulletText(const char* fmt, ...) // If returning 'true' the node is open and the user is responsible for calling TreePop bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args) { - static char buf[1024]; - ImFormatStringV(buf, IM_ARRAYSIZE(buf), fmt, args); + ImGuiState& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); if (!str_id || !str_id[0]) str_id = fmt; ImGui::PushID(str_id); - const bool opened = ImGui::CollapsingHeader(buf, "", false); // do not add to the ID so that TreeNodeSetOpen can access + const bool opened = ImGui::CollapsingHeader(g.TempBuffer, "", false); ImGui::PopID(); if (opened) @@ -4558,14 +4921,18 @@ bool ImGui::TreeNode(const char* str_id, const char* fmt, ...) // If returning 'true' the node is open and the user is responsible for calling TreePop bool ImGui::TreeNodeV(const void* ptr_id, const char* fmt, va_list args) { - static char buf[1024]; - ImFormatStringV(buf, IM_ARRAYSIZE(buf), fmt, args); + ImGuiState& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); if (!ptr_id) ptr_id = fmt; ImGui::PushID(ptr_id); - const bool opened = ImGui::CollapsingHeader(buf, "", false); + const bool opened = ImGui::CollapsingHeader(g.TempBuffer, "", false); ImGui::PopID(); if (opened) @@ -4601,6 +4968,12 @@ void ImGui::PushID(const char* str_id) window->IDStack.push_back(window->GetID(str_id)); } +void ImGui::PushID(const char* str_id_begin, const char* str_id_end) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->IDStack.push_back(window->GetID(str_id_begin, str_id_end)); +} + void ImGui::PushID(const void* ptr_id) { ImGuiWindow* window = GetCurrentWindow(); @@ -4626,6 +4999,12 @@ ImGuiID ImGui::GetID(const char* str_id) return window->GetID(str_id); } +ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end) +{ + ImGuiWindow* window = GetCurrentWindow(); + return window->GetID(str_id_begin, str_id_end); +} + ImGuiID ImGui::GetID(const void* ptr_id) { ImGuiWindow* window = GetCurrentWindow(); @@ -4678,146 +5057,127 @@ static void ApplyNumericalTextInput(const char* buf, float *v) *v = op_v; } -// Use power!=1.0 for logarithmic sliders. -// Adjust display_format to decorate the value with a prefix or a suffix. -bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* display_format, float power) +// Create text input in place of a slider (when CTRL+Clicking on slider) +static bool SliderFloatAsInputText(const char* label, float* v, ImGuiID id, int decimal_precision) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - if (window->SkipItems) - return false; - const ImGuiStyle& style = g.Style; - const ImGuiID id = window->GetID(label); - const float w = ImGui::CalcItemWidth(); + char text_buf[64]; + ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%.*f", decimal_precision, *v); - if (!display_format) - display_format = "%.3f"; + SetActiveId(g.ScalarAsInputTextId); + g.HoveredId = 0; - // Parse display precision back from the display format string - int decimal_precision = 3; - if (const char* p = strchr(display_format, '%')) + // Our replacement widget will override the focus ID (registered previously to allow for a TAB focus to happen) + window->FocusItemUnregister(); + + bool value_changed = ImGui::InputText(label, text_buf, IM_ARRAYSIZE(text_buf), ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_AutoSelectAll); + if (g.ScalarAsInputTextId == 0) { - p++; - while (*p >= '0' && *p <= '9') - p++; - if (*p == '.') + // First frame + IM_ASSERT(g.ActiveId == id); // InputText ID expected to match the Slider ID (else we'd need to store them both, which is also possible) + g.ScalarAsInputTextId = g.ActiveId; + g.HoveredId = id; + } + else if (g.ActiveId != g.ScalarAsInputTextId) + { + // Release + g.ScalarAsInputTextId = 0; + } + if (value_changed) + { + ApplyNumericalTextInput(text_buf, v); + } + return value_changed; +} + +// Parse display precision back from the display format string +static inline void ParseFormat(const char* fmt, int& decimal_precision) +{ + while ((fmt = strchr(fmt, '%')) != NULL) + { + fmt++; + if (fmt[0] == '%') { fmt++; continue; } // Ignore "%%" + while (*fmt >= '0' && *fmt <= '9') + fmt++; + if (*fmt == '.') { - decimal_precision = atoi(p+1); + decimal_precision = atoi(fmt + 1); if (decimal_precision < 0 || decimal_precision > 10) decimal_precision = 3; } + break; } +} - const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImGuiAabb frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); - const ImGuiAabb slider_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); - const ImGuiAabb bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); - - // NB- we don't call ItemSize() yet becausae we may turn into a text edit box later in the function - if (!ItemAdd(slider_bb, &id)) - { - ItemSize(bb); - return false; - } - - const bool tab_focus_requested = window->FocusItemRegister(g.ActiveId == id); - - const bool is_unbound = v_min == -FLT_MAX || v_min == FLT_MAX || v_max == -FLT_MAX || v_max == FLT_MAX; - - const float grab_size_in_units = 1.0f; // In 'v' units. Probably needs to be parametrized, based on a 'v_step' value? decimal precision? - float grab_size_in_pixels; - if (decimal_precision > 0 || is_unbound) - grab_size_in_pixels = style.GrabMinSize; +static inline float RoundScalar(float value, int decimal_precision) +{ + // Round past decimal precision + // 0: 1, 1: 0.1, 2: 0.01, etc. + // So when our value is 1.99999 with a precision of 0.001 we'll end up rounding to 2.0 + // FIXME: Investigate better rounding methods + const float min_step = 1.0f / powf(10.0f, (float)decimal_precision); + const float remainder = fmodf(value, min_step); + if (remainder <= min_step*0.5f) + value -= remainder; else - grab_size_in_pixels = ImMax(grab_size_in_units * (w / (v_max-v_min+1.0f)), style.GrabMinSize); // Integer sliders - const float slider_effective_w = slider_bb.GetWidth() - grab_size_in_pixels; - const float slider_effective_x1 = slider_bb.Min.x + grab_size_in_pixels*0.5f; - const float slider_effective_x2 = slider_bb.Max.x - grab_size_in_pixels*0.5f; + value += (min_step - remainder); + return value; +} + +static bool SliderBehavior(const ImRect& frame_bb, const ImRect& slider_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, bool horizontal) +{ + ImGuiState& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + const ImGuiStyle& style = g.Style; + + // Draw frame + RenderFrame(frame_bb.Min, frame_bb.Max, window->Color(ImGuiCol_FrameBg), true, style.FrameRounding); + + const bool is_non_linear = fabsf(power - 1.0f) > 0.0001f; + + const float slider_sz = horizontal ? slider_bb.GetWidth() : slider_bb.GetHeight(); + float grab_sz; + if (decimal_precision > 0) + grab_sz = ImMin(style.GrabMinSize, slider_sz); + else + grab_sz = ImMin(ImMax(1.0f * (slider_sz / (v_max-v_min+1.0f)), style.GrabMinSize), slider_sz); // Integer sliders, if possible have the grab size represent 1 unit + const float slider_usable_sz = slider_sz - grab_sz; + const float slider_usable_pos_min = (horizontal ? slider_bb.Min.x : slider_bb.Min.y) + grab_sz*0.5f; + const float slider_usable_pos_max = (horizontal ? slider_bb.Max.x : slider_bb.Max.y) - grab_sz*0.5f; + + bool value_changed = false; // For logarithmic sliders that cross over sign boundary we want the exponential increase to be symmetric around 0.0f float linear_zero_pos = 0.0f; // 0.0->1.0f - if (!is_unbound) + if (v_min * v_max < 0.0f) { - if (v_min * v_max < 0.0f) - { - // Different sign - const float linear_dist_min_to_0 = powf(fabsf(0.0f - v_min), 1.0f/power); - const float linear_dist_max_to_0 = powf(fabsf(v_max - 0.0f), 1.0f/power); - linear_zero_pos = linear_dist_min_to_0 / (linear_dist_min_to_0+linear_dist_max_to_0); - } - else - { - // Same sign - linear_zero_pos = v_min < 0.0f ? 1.0f : 0.0f; - } + // Different sign + const float linear_dist_min_to_0 = powf(fabsf(0.0f - v_min), 1.0f/power); + const float linear_dist_max_to_0 = powf(fabsf(v_max - 0.0f), 1.0f/power); + linear_zero_pos = linear_dist_min_to_0 / (linear_dist_min_to_0+linear_dist_max_to_0); } - - const bool hovered = IsHovered(slider_bb, id); - if (hovered) - g.HoveredId = id; - - bool start_text_input = false; - if (tab_focus_requested || (hovered && g.IO.MouseClicked[0])) + else { - SetActiveId(id); - FocusWindow(window); - - const bool is_ctrl_down = g.IO.KeyCtrl; - if (tab_focus_requested || is_ctrl_down || is_unbound) - { - start_text_input = true; - g.SliderAsInputTextId = 0; - } + // Same sign + linear_zero_pos = v_min < 0.0f ? 1.0f : 0.0f; } - // Tabbing or CTRL-clicking through slider turns into an input box - bool value_changed = false; - if (start_text_input || (g.ActiveId == id && id == g.SliderAsInputTextId)) - { - char text_buf[64]; - ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%.*f", decimal_precision, *v); - - SetActiveId(g.SliderAsInputTextId); - g.HoveredId = 0; - window->FocusItemUnregister(); // Our replacement slider will override the focus ID (registered previously to allow for a TAB focus to happen) - value_changed = ImGui::InputText(label, text_buf, IM_ARRAYSIZE(text_buf), ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_AutoSelectAll); - if (g.SliderAsInputTextId == 0) - { - // First frame - IM_ASSERT(g.ActiveId == id); // InputText ID expected to match the Slider ID (else we'd need to store them both, which is also possible) - g.SliderAsInputTextId = g.ActiveId; - g.HoveredId = id; - } - else if (g.ActiveId != g.SliderAsInputTextId) - { - // Release - g.SliderAsInputTextId = 0; - } - if (value_changed) - { - ApplyNumericalTextInput(text_buf, v); - } - return value_changed; - } - - ItemSize(bb); - RenderFrame(frame_bb.Min, frame_bb.Max, window->Color(ImGuiCol_FrameBg), true, style.FrameRounding); - // Process clicking on the slider if (g.ActiveId == id) { if (g.IO.MouseDown[0]) { - if (!is_unbound) + const float mouse_abs_pos = horizontal ? g.IO.MousePos.x : g.IO.MousePos.y; + float normalized_pos = ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f); + if (!horizontal) + normalized_pos = 1.0f - normalized_pos; + + float new_value; + if (is_non_linear) { - const float normalized_pos = ImClamp((g.IO.MousePos.x - slider_effective_x1) / slider_effective_w, 0.0f, 1.0f); - - // Linear slider - //float new_value = ImLerp(v_min, v_max, normalized_pos); - // Account for logarithmic scale on both sides of the zero - float new_value; if (normalized_pos < linear_zero_pos) { // Negative: rescale to the negative range before powering @@ -4836,22 +5196,20 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c a = powf(a, power); new_value = ImLerp(ImMax(v_min,0.0f), v_max, a); } + } + else + { + // Linear slider + new_value = ImLerp(v_min, v_max, normalized_pos); + } - // Round past decimal precision - // 0->1, 1->0.1, 2->0.01, etc. - // So when our value is 1.99999 with a precision of 0.001 we'll end up rounding to 2.0 - const float min_step = 1.0f / powf(10.0f, (float)decimal_precision); - const float remainder = fmodf(new_value, min_step); - if (remainder <= min_step*0.5f) - new_value -= remainder; - else - new_value += (min_step - remainder); + // Round past decimal precision + new_value = RoundScalar(new_value, decimal_precision); - if (*v != new_value) - { - *v = new_value; - value_changed = true; - } + if (*v != new_value) + { + *v = new_value; + value_changed = true; } } else @@ -4860,13 +5218,10 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c } } - if (!is_unbound) + // Calculate slider grab positioning + float grab_t; + if (is_non_linear) { - // Linear slider - // const float grab_t = (ImClamp(*v, v_min, v_max) - v_min) / (v_max - v_min); - - // Calculate slider grab positioning - float grab_t; float v_clamped = ImClamp(*v, v_min, v_max); if (v_clamped < 0.0f) { @@ -4878,29 +5233,154 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c const float f = (v_clamped - ImMax(0.0f,v_min)) / (v_max - ImMax(0.0f,v_min)); grab_t = linear_zero_pos + powf(f, 1.0f/power) * (1.0f - linear_zero_pos); } - - // Draw - const float grab_x = ImLerp(slider_effective_x1, slider_effective_x2, grab_t); - const ImGuiAabb grab_bb(ImVec2(grab_x-grab_size_in_pixels*0.5f,frame_bb.Min.y+2.0f), ImVec2(grab_x+grab_size_in_pixels*0.5f,frame_bb.Max.y-2.0f)); - window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, window->Color(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab)); + } + else + { + // Linear slider + grab_t = (ImClamp(*v, v_min, v_max) - v_min) / (v_max - v_min); } - // Draw value using user-provided display format so user can add prefix/suffix/decorations to the value. - char value_buf[64]; - char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v); - const ImVec2 value_text_size = CalcTextSize(value_buf, value_buf_end, true); - RenderTextClipped(ImVec2(ImMax(frame_bb.Min.x + style.FramePadding.x, slider_bb.GetCenter().x - value_text_size.x*0.5f), frame_bb.Min.y + style.FramePadding.y), value_buf, value_buf_end, &value_text_size, frame_bb.Max); - - RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, slider_bb.Min.y), label); + // Draw + if (!horizontal) + grab_t = 1.0f - grab_t; + const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); + ImRect grab_bb; + if (horizontal) + grab_bb = ImRect(ImVec2(grab_pos - grab_sz*0.5f, frame_bb.Min.y + 2.0f), ImVec2(grab_pos + grab_sz*0.5f, frame_bb.Max.y - 2.0f)); + else + grab_bb = ImRect(ImVec2(frame_bb.Min.x + 2.0f, grab_pos - grab_sz*0.5f), ImVec2(frame_bb.Max.x - 2.0f, grab_pos + grab_sz*0.5f)); + window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, window->Color(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab)); return value_changed; } -bool ImGui::SliderAngle(const char* label, float* v, float v_degrees_min, float v_degrees_max) +// Use power!=1.0 for logarithmic sliders. +// Adjust display_format to decorate the value with a prefix or a suffix. +// "%.3f" 1.234 +// "%5.2f secs" 01.23 secs +// "Gold: %.0f" Gold: 1 +bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* display_format, float power) { - float v_deg = *v * 360.0f / (2*PI); + ImGuiState& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const float w = ImGui::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*2.0f); + 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.0f)); + + // NB- we don't call ItemSize() yet because we may turn into a text edit box below + if (!ItemAdd(total_bb, &id)) + { + ItemSize(total_bb, style.FramePadding.y); + return false; + } + + const bool hovered = IsHovered(frame_bb, id); + if (hovered) + g.HoveredId = id; + + if (!display_format) + display_format = "%.3f"; + int decimal_precision = 3; + ParseFormat(display_format, decimal_precision); + + // Tabbing or CTRL-clicking on Slider turns it into an input box + bool start_text_input = false; + const bool tab_focus_requested = window->FocusItemRegister(g.ActiveId == id); + if (tab_focus_requested || (hovered && g.IO.MouseClicked[0])) + { + SetActiveId(id); + FocusWindow(window); + + const bool is_ctrl_down = g.IO.KeyCtrl; + if (tab_focus_requested || is_ctrl_down) + { + start_text_input = true; + g.ScalarAsInputTextId = 0; + } + } + if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id)) + return SliderFloatAsInputText(label, v, id, decimal_precision); + + ItemSize(total_bb, style.FramePadding.y); + + // Actual slider behavior + render grab + const bool value_changed = SliderBehavior(frame_bb, inner_bb, id, v, v_min, v_max, power, decimal_precision, true); + + // 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 + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v); + const ImVec2 value_text_size = CalcTextSize(value_buf, value_buf_end, true); + RenderTextClipped(ImVec2(ImMax(frame_bb.Min.x + style.FramePadding.x, inner_bb.GetCenter().x - value_text_size.x*0.5f), frame_bb.Min.y + style.FramePadding.y), value_buf, value_buf_end, &value_text_size, frame_bb.Max); + + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); + + return value_changed; +} + +bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* display_format, float power) +{ + ImGuiState& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + 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 slider_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); + 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)) + return false; + + const bool hovered = IsHovered(frame_bb, id); + if (hovered) + g.HoveredId = id; + + if (!display_format) + display_format = "%.3f"; + int decimal_precision = 3; + ParseFormat(display_format, decimal_precision); + + if (hovered && g.IO.MouseClicked[0]) + { + SetActiveId(id); + FocusWindow(window); + } + + // Actual slider behavior + render grab + bool value_changed = SliderBehavior(frame_bb, slider_bb, id, v, v_min, v_max, power, decimal_precision, false); + + // 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]; + char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v); + const ImVec2 value_text_size = CalcTextSize(value_buf, value_buf_end, true); + RenderTextClipped(ImVec2(ImMax(frame_bb.Min.x, slider_bb.GetCenter().x - value_text_size.x*0.5f), frame_bb.Min.y + style.FramePadding.y), value_buf, value_buf_end, &value_text_size, frame_bb.Max); + + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, slider_bb.Min.y), label); + + return value_changed; +} + +bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max) +{ + float v_deg = (*v_rad) * 360.0f / (2*PI); bool value_changed = ImGui::SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, "%.0f deg", 1.0f); - *v = v_deg * (2*PI) / 360.0f; + *v_rad = v_deg * (2*PI) / 360.0f; return value_changed; } @@ -4914,6 +5394,16 @@ bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const cha return value_changed; } +bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* display_format) +{ + if (!display_format) + display_format = "%.0f"; + float v_f = (float)*v; + bool value_changed = ImGui::VSliderFloat(label, size, &v_f, (float)v_min, (float)v_max, display_format, 1.0f); + *v = (int)v_f; + return value_changed; +} + // Add multiple sliders on 1 line for compact edition of multiple components static bool SliderFloatN(const char* label, float v[3], int components, float v_min, float v_max, const char* display_format, float power) { @@ -4928,6 +5418,7 @@ static bool SliderFloatN(const char* label, float v[3], int components, float v_ const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.FramePadding.x*2.0f + style.ItemInnerSpacing.x)*(components-1))); bool value_changed = false; + ImGui::BeginGroup(); ImGui::PushID(label); ImGui::PushItemWidth(w_item_one); for (int i = 0; i < components; i++) @@ -4946,6 +5437,7 @@ static bool SliderFloatN(const char* label, float v[3], int components, float v_ ImGui::PopID(); ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::EndGroup(); return value_changed; } @@ -4978,6 +5470,7 @@ static bool SliderIntN(const char* label, int v[3], int components, int v_min, i const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.FramePadding.x*2.0f + style.ItemInnerSpacing.x)*(components-1))); bool value_changed = false; + ImGui::BeginGroup(); ImGui::PushID(label); ImGui::PushItemWidth(w_item_one); for (int i = 0; i < components; i++) @@ -4996,6 +5489,7 @@ static bool SliderIntN(const char* label, int v[3], int components, int v_min, i ImGui::PopID(); ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::EndGroup(); return value_changed; } @@ -5015,6 +5509,158 @@ bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const return SliderIntN(label, v, 4, v_min, v_max, display_format); } +// FIXME-WIP: Work in progress. May change API / behavior. +static bool DragScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_speed, float v_min, float v_max, int decimal_precision, float power) +{ + ImGuiState& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + const ImGuiStyle& style = g.Style; + + // Draw frame + const ImU32 frame_col = window->Color(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding); + + bool value_changed = false; + + // Process clicking on the slider + if (g.ActiveId == id) + { + if (g.IO.MouseDown[0]) + { + if (g.ActiveIdIsJustActivated) + { + // Lock current value on click + g.DragCurrentValue = *v; + g.DragLastMouseDelta = ImVec2(0.f, 0.f); + } + + const ImVec2 mouse_drag_delta = ImGui::GetMouseDragDelta(0, 1.0f); + if (fabsf(mouse_drag_delta.x - g.DragLastMouseDelta.x) > 0.0f) + { + float speed = v_speed; + if (g.IO.KeyShift && g.DragSpeedScaleFast >= 0.0f) + speed = v_speed * g.DragSpeedScaleFast; + if (g.IO.KeyAlt && g.DragSpeedScaleSlow >= 0.0f) + speed = v_speed * g.DragSpeedScaleSlow; + + float v_cur = g.DragCurrentValue; + float delta = (mouse_drag_delta.x - g.DragLastMouseDelta.x) * speed; + if (fabsf(power - 1.0f) > 0.001f) + { + // Logarithmic curve on both side of 0.0 + float v0_abs = v_cur >= 0.0f ? v_cur : -v_cur; + float v0_sign = v_cur >= 0.0f ? 1.0f : -1.0f; + float v1 = powf(v0_abs, 1.0f / power) + (delta * v0_sign); + float v1_abs = v1 >= 0.0f ? v1 : -v1; + float v1_sign = v1 >= 0.0f ? 1.0f : -1.0f; // Crossed sign line + v_cur = powf(v1_abs, power) * v0_sign * v1_sign; // Reapply sign + } + else + { + v_cur += delta; + } + g.DragLastMouseDelta.x = mouse_drag_delta.x; + + // Clamp + if (v_min < v_max) + v_cur = ImClamp(v_cur, v_min, v_max); + g.DragCurrentValue = v_cur; + + // Round to user desired precision, then apply + v_cur = RoundScalar(v_cur, decimal_precision); + if (*v != v_cur) + { + *v = v_cur; + value_changed = true; + } + } + } + else + { + SetActiveId(0); + } + } + + return value_changed; +} + +bool ImGui::DragFloat(const char* label, float *v, float v_speed, float v_min, float v_max, const char* display_format, float power) +{ + ImGuiState& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const float w = ImGui::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*2.0f); + 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.0f)); + + // NB- we don't call ItemSize() yet because we may turn into a text edit box below + if (!ItemAdd(total_bb, &id)) + { + ItemSize(total_bb, style.FramePadding.y); + return false; + } + + const bool hovered = IsHovered(frame_bb, id); + if (hovered) + g.HoveredId = id; + + if (!display_format) + display_format = "%.3f"; + int decimal_precision = 3; + ParseFormat(display_format, decimal_precision); + + // Tabbing or CTRL-clicking on Drag turns it into an input box + bool start_text_input = false; + const bool tab_focus_requested = window->FocusItemRegister(g.ActiveId == id); + if (tab_focus_requested || (hovered && (g.IO.MouseClicked[0] | g.IO.MouseDoubleClicked[0]))) + { + SetActiveId(id); + FocusWindow(window); + + if (tab_focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0]) + { + start_text_input = true; + g.ScalarAsInputTextId = 0; + } + } + if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id)) + return SliderFloatAsInputText(label, v, id, decimal_precision); + + ItemSize(total_bb, style.FramePadding.y); + + // Actual drag behavior + const bool value_changed = DragScalarBehavior(frame_bb, id, v, v_speed, v_min, v_max, decimal_precision, power); + + // 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 + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v); + const ImVec2 value_text_size = CalcTextSize(value_buf, value_buf_end, true); + RenderTextClipped(ImVec2(ImMax(frame_bb.Min.x + style.FramePadding.x, inner_bb.GetCenter().x - value_text_size.x*0.5f), frame_bb.Min.y + style.FramePadding.y), value_buf, value_buf_end, &value_text_size, frame_bb.Max); + + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); + + return value_changed; +} + +// 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* display_format) +{ + if (!display_format) + display_format = "%.0f"; + float v_f = (float)*v; + bool value_changed = ImGui::DragFloat(label, &v_f, v_speed, (float)v_min, (float)v_max, display_format); + *v = (int)v_f; + return value_changed; +} + enum ImGuiPlotType { ImGuiPlotType_Lines, @@ -5032,15 +5678,15 @@ static void Plot(ImGuiPlotType plot_type, const char* label, float (*values_gett const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); if (graph_size.x == 0.0f) - graph_size.x = ImGui::CalcItemWidth(); + graph_size.x = ImGui::CalcItemWidth() + (style.FramePadding.x * 2); if (graph_size.y == 0.0f) - graph_size.y = label_size.y; + graph_size.y = label_size.y + (style.FramePadding.y * 2); - const ImGuiAabb frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(graph_size.x, graph_size.y) + style.FramePadding*2.0f); - const ImGuiAabb graph_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); - const ImGuiAabb bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0)); - ItemSize(bb); - if (!ItemAdd(bb, NULL)) + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(graph_size.x, graph_size.y)); + 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)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, NULL)) return; // Determine scale from values if not specified @@ -5068,12 +5714,12 @@ static void Plot(ImGuiPlotType plot_type, const char* label, float (*values_gett // Tooltip on hover int v_hovered = -1; - if (IsMouseHoveringBox(graph_bb)) + if (IsMouseHoveringRect(inner_bb)) { - const float t = ImClamp((g.IO.MousePos.x - graph_bb.Min.x) / (graph_bb.Max.x - graph_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 * (values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0))); IM_ASSERT(v_idx >= 0 && v_idx < values_count); - + const float v0 = values_getter(data, (v_idx + values_offset) % values_count); const float v1 = values_getter(data, (v_idx + 1 + values_offset) % values_count); if (plot_type == ImGuiPlotType_Lines) @@ -5102,9 +5748,9 @@ static void Plot(ImGuiPlotType plot_type, const char* label, float (*values_gett // NB- Draw calls are merged together by the DrawList system. if (plot_type == ImGuiPlotType_Lines) - window->DrawList->AddLine(ImLerp(graph_bb.Min, graph_bb.Max, p0), ImLerp(graph_bb.Min, graph_bb.Max, p1), v_hovered == v_idx ? col_hovered : col_base); + window->DrawList->AddLine(ImLerp(inner_bb.Min, inner_bb.Max, p0), ImLerp(inner_bb.Min, inner_bb.Max, p1), v_hovered == v_idx ? col_hovered : col_base); else if (plot_type == ImGuiPlotType_Histogram) - window->DrawList->AddRectFilled(ImLerp(graph_bb.Min, graph_bb.Max, p0), ImLerp(graph_bb.Min, graph_bb.Max, ImVec2(p1.x, 1.0f))+ImVec2(-1,0), v_hovered == v_idx ? col_hovered : col_base); + window->DrawList->AddRectFilled(ImLerp(inner_bb.Min, inner_bb.Max, p0), ImLerp(inner_bb.Min, inner_bb.Max, ImVec2(p1.x, 1.0f))+ImVec2(-1,0), v_hovered == v_idx ? col_hovered : col_base); t0 = t1; p0 = p1; @@ -5112,9 +5758,9 @@ static void Plot(ImGuiPlotType plot_type, const char* label, float (*values_gett // Text overlay if (overlay_text) - RenderText(ImVec2(graph_bb.GetCenter().x - ImGui::CalcTextSize(overlay_text, NULL, true).x*0.5f, frame_bb.Min.y + style.FramePadding.y), overlay_text); + RenderText(ImVec2(inner_bb.GetCenter().x - ImGui::CalcTextSize(overlay_text, NULL, true).x*0.5f, frame_bb.Min.y + style.FramePadding.y), overlay_text); - RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, graph_bb.Min.y), label); + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); } struct ImGuiPlotArrayGetterData @@ -5165,28 +5811,28 @@ bool ImGui::Checkbox(const char* label, bool* v) const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImGuiAabb check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y*2, label_size.y + style.FramePadding.y*2)); - ItemSize(check_bb); + const ImRect check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y*2, label_size.y + style.FramePadding.y*2)); + ItemSize(check_bb, style.FramePadding.y); - ImGuiAabb total_bb = check_bb; + ImRect total_bb = check_bb; if (label_size.x > 0) SameLine(0, (int)style.ItemInnerSpacing.x); - const ImGuiAabb text_bb(window->DC.CursorPos + ImVec2(0,style.FramePadding.y), window->DC.CursorPos + ImVec2(0,style.FramePadding.y) + label_size); + const ImRect text_bb(window->DC.CursorPos + ImVec2(0,style.FramePadding.y), window->DC.CursorPos + ImVec2(0,style.FramePadding.y) + label_size); if (label_size.x > 0) { - ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight())); - total_bb = ImGuiAabb(ImMin(check_bb.Min, text_bb.Min), ImMax(check_bb.Max, text_bb.Max)); + ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y); + total_bb = ImRect(ImMin(check_bb.Min, text_bb.Min), ImMax(check_bb.Max, text_bb.Max)); } if (!ItemAdd(total_bb, &id)) return false; bool hovered, held; - bool pressed = ButtonBehaviour(total_bb, id, &hovered, &held, true); + bool pressed = ButtonBehavior(total_bb, id, &hovered, &held, true); if (pressed) *v = !(*v); - RenderFrame(check_bb.Min, check_bb.Max, window->Color((held && hovered) ? ImGuiCol_CheckActive : hovered ? ImGuiCol_CheckHovered : ImGuiCol_FrameBg), true, style.FrameRounding); + RenderFrame(check_bb.Min, check_bb.Max, window->Color((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); if (*v) { const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight()); @@ -5223,16 +5869,16 @@ bool ImGui::RadioButton(const char* label, bool active) const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImGuiAabb check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y*2-1, label_size.y + style.FramePadding.y*2-1)); - ItemSize(check_bb); + const ImRect check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y*2-1, label_size.y + style.FramePadding.y*2-1)); + ItemSize(check_bb, style.FramePadding.y); - ImGuiAabb total_bb = check_bb; + ImRect total_bb = check_bb; if (label_size.x > 0) SameLine(0, (int)style.ItemInnerSpacing.x); - const ImGuiAabb text_bb(window->DC.CursorPos + ImVec2(0, style.FramePadding.y), window->DC.CursorPos + ImVec2(0, style.FramePadding.y) + label_size); + const ImRect text_bb(window->DC.CursorPos + ImVec2(0, style.FramePadding.y), window->DC.CursorPos + ImVec2(0, style.FramePadding.y) + label_size); if (label_size.x > 0) { - ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight())); + ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y); total_bb.Add(text_bb); } @@ -5245,9 +5891,9 @@ bool ImGui::RadioButton(const char* label, bool active) const float radius = check_bb.GetHeight() * 0.5f; bool hovered, held; - bool pressed = ButtonBehaviour(total_bb, id, &hovered, &held, true); + bool pressed = ButtonBehavior(total_bb, id, &hovered, &held, true); - window->DrawList->AddCircleFilled(center, radius, window->Color((held && hovered) ? ImGuiCol_CheckActive : hovered ? ImGuiCol_CheckHovered : ImGuiCol_FrameBg), 16); + window->DrawList->AddCircleFilled(center, radius, window->Color((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16); if (active) { const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight()); @@ -5307,9 +5953,9 @@ static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n) obj->CurLenW -= n; // Offset remaining text - const ImWchar* src = obj->Text + pos + n; + const ImWchar* src = obj->Text + pos + n; while (ImWchar c = *src++) - *dst++ = c; + *dst++ = c; *dst = '\0'; } @@ -5334,24 +5980,22 @@ static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const Im return true; } -enum -{ - STB_TEXTEDIT_K_LEFT = 1 << 16, // keyboard input to move cursor left - STB_TEXTEDIT_K_RIGHT, // keyboard input to move cursor right - STB_TEXTEDIT_K_UP, // keyboard input to move cursor up - STB_TEXTEDIT_K_DOWN, // keyboard input to move cursor down - STB_TEXTEDIT_K_LINESTART, // keyboard input to move cursor to start of line - STB_TEXTEDIT_K_LINEEND, // keyboard input to move cursor to end of line - STB_TEXTEDIT_K_TEXTSTART, // keyboard input to move cursor to start of text - STB_TEXTEDIT_K_TEXTEND, // keyboard input to move cursor to end of text - STB_TEXTEDIT_K_DELETE, // keyboard input to delete selection or character under cursor - STB_TEXTEDIT_K_BACKSPACE, // keyboard input to delete selection or character left of cursor - STB_TEXTEDIT_K_UNDO, // keyboard input to perform undo - STB_TEXTEDIT_K_REDO, // keyboard input to perform redo - STB_TEXTEDIT_K_WORDLEFT, // keyboard input to move cursor left one word - STB_TEXTEDIT_K_WORDRIGHT, // keyboard input to move cursor right one word - STB_TEXTEDIT_K_SHIFT = 1 << 17 -}; +// 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 0x10000 // keyboard input to move cursor left +#define STB_TEXTEDIT_K_RIGHT 0x10001 // keyboard input to move cursor right +#define STB_TEXTEDIT_K_UP 0x10002 // keyboard input to move cursor up +#define STB_TEXTEDIT_K_DOWN 0x10003 // keyboard input to move cursor down +#define STB_TEXTEDIT_K_LINESTART 0x10004 // keyboard input to move cursor to start of line +#define STB_TEXTEDIT_K_LINEEND 0x10005 // keyboard input to move cursor to end of line +#define STB_TEXTEDIT_K_TEXTSTART 0x10006 // keyboard input to move cursor to start of text +#define STB_TEXTEDIT_K_TEXTEND 0x10007 // keyboard input to move cursor to end of text +#define STB_TEXTEDIT_K_DELETE 0x10008 // keyboard input to delete selection or character under cursor +#define STB_TEXTEDIT_K_BACKSPACE 0x10009 // keyboard input to delete selection or character left of cursor +#define STB_TEXTEDIT_K_UNDO 0x1000A // keyboard input to perform undo +#define STB_TEXTEDIT_K_REDO 0x1000B // keyboard input to perform redo +#define STB_TEXTEDIT_K_WORDLEFT 0x1000C // keyboard input to move cursor left one word +#define STB_TEXTEDIT_K_WORDRIGHT 0x1000D // keyboard input to move cursor right one word +#define STB_TEXTEDIT_K_SHIFT 0x20000 #ifdef IMGUI_STB_NAMESPACE namespace IMGUI_STB_NAMESPACE @@ -5364,9 +6008,9 @@ namespace IMGUI_STB_NAMESPACE #endif void ImGuiTextEditState::OnKeyPressed(int key) -{ - stb_textedit_key(this, &StbState, key); - CursorAnimReset(); +{ + stb_textedit_key(this, &StbState, key); + CursorAnimReset(); } void ImGuiTextEditState::UpdateScrollOffset() @@ -5374,9 +6018,21 @@ void ImGuiTextEditState::UpdateScrollOffset() // Scroll in chunks of quarter width const float scroll_x_increment = Width * 0.25f; const float cursor_offset_x = Font->CalcTextSizeW(FontSize, FLT_MAX, Text, Text+StbState.cursor, NULL).x; - if (ScrollX > cursor_offset_x) - ScrollX = ImMax(0.0f, cursor_offset_x - scroll_x_increment); - else if (ScrollX < cursor_offset_x - Width) + + // If widget became bigger than text (because of a resize), reset horizontal scrolling + if (ScrollX > 0.0f) + { + const float text_width = cursor_offset_x + Font->CalcTextSizeW(FontSize, FLT_MAX, Text+StbState.cursor, NULL, NULL).x; + if (text_width < Width) + { + ScrollX = 0.0f; + return; + } + } + + if (cursor_offset_x < ScrollX) + ScrollX = ImMax(0.0f, cursor_offset_x - scroll_x_increment); + else if (cursor_offset_x - Width >= ScrollX) ScrollX = cursor_offset_x - Width + scroll_x_increment; } @@ -5386,7 +6042,7 @@ ImVec2 ImGuiTextEditState::CalcDisplayOffsetFromCharIdx(int i) const const ImWchar* text_end = (Text+i >= text_start) ? Text+i : text_start; // Clip if requested character is outside of display IM_ASSERT(text_end >= text_start); - const ImVec2 offset = Font->CalcTextSizeW(FontSize, Width, text_start, text_end, NULL); + const ImVec2 offset = Font->CalcTextSizeW(FontSize, Width+1, text_start, text_end, NULL); return offset; } @@ -5419,30 +6075,19 @@ const ImWchar* ImGuiTextEditState::GetTextPointerClippedW(ImFont* font, float fo // [Static] void ImGuiTextEditState::RenderTextScrolledClipped(ImFont* font, float font_size, const char* buf, ImVec2 pos, float width, float scroll_x) { - // NB- We start drawing at character boundary - ImVec2 text_size; - const char* text_start = GetTextPointerClippedA(font, font_size, buf, scroll_x, NULL); - const char* text_end = GetTextPointerClippedA(font, font_size, text_start, width, &text_size); + ImGuiWindow* window = GetCurrentWindow(); + const ImU32 font_color = window->Color(ImGuiCol_Text); + //window->DrawList->AddLine(pos, pos+ImVec2(width,0), 0xFF00FFFF); - // We need to test for the possibility of malformed UTF-8 (instead of just text_end[0] != 0) - unsigned int text_end_char = 0; - ImTextCharFromUtf8(&text_end_char, text_end, NULL); + // Determine start and end of visible string + // FIXME-OPT: This is pretty slow for what it does. + const char* text_start = scroll_x <= 0.0f ? buf : GetTextPointerClippedA(font, font_size, buf, scroll_x, NULL); + const char* text_end = GetTextPointerClippedA(font, font_size, text_start, width + 1, NULL); // +1 to allow character spacing to fit outside the allowed width + window->DrawList->AddText(font, font_size, pos, font_color, text_start, text_end); - // Draw a little clip symbol if we've got text on either left or right of the box - const char symbol_c = '~'; - const float symbol_w = font_size*0.40f; // FIXME: compute correct width - const float clip_begin = (text_start > buf && text_start < text_end) ? symbol_w : 0.0f; - const float clip_end = (text_end_char != 0 && text_end > text_start) ? symbol_w : 0.0f; - - // Draw text - RenderText(pos+ImVec2(clip_begin,0), text_start+(clip_begin>0.0f?1:0), text_end-(clip_end>0.0f?1:0), false); - - // Draw the clip symbol - const char s[2] = {symbol_c,'\0'}; - if (clip_begin > 0.0f) - RenderText(pos, s); - if (clip_end > 0.0f) - RenderText(pos+ImVec2(width-clip_end,0.0f), s); + // Log as text + if (GImGui->LogEnabled) + LogText(pos, buf, NULL); } bool ImGui::InputFloat(const char* label, float *v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags extra_flags) @@ -5455,12 +6100,13 @@ bool ImGui::InputFloat(const char* label, float *v, float step, float step_fast, const ImGuiStyle& style = g.Style; const float w = ImGui::CalcItemWidth(); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImGuiAabb frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); + ImGui::BeginGroup(); ImGui::PushID(label); - const float button_sz = window->FontSize(); + const ImVec2 button_sz = ImVec2(g.FontSize, g.FontSize) + style.FramePadding * 2; if (step > 0.0f) - ImGui::PushItemWidth(ImMax(1.0f, w - (button_sz + style.FramePadding.x*2.0f + style.ItemInnerSpacing.x)*2)); + ImGui::PushItemWidth(ImMax(1.0f, w - (button_sz.x + style.ItemInnerSpacing.x)*2)); char buf[64]; if (decimal_precision < 0) @@ -5480,13 +6126,13 @@ bool ImGui::InputFloat(const char* label, float *v, float step, float step_fast, { ImGui::PopItemWidth(); ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); - if (ImGui::Button("-", ImVec2(button_sz,button_sz), true)) + if (ImGui::Button("-", button_sz, true)) { *v -= g.IO.KeyCtrl && step_fast > 0.0f ? step_fast : step; value_changed = true; } ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); - if (ImGui::Button("+", ImVec2(button_sz,button_sz), true)) + if (ImGui::Button("+", button_sz, true)) { *v += g.IO.KeyCtrl && step_fast > 0.0f ? step_fast : step; value_changed = true; @@ -5498,10 +6144,12 @@ bool ImGui::InputFloat(const char* label, float *v, float step, float step_fast, if (label_size.x > 0) { ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); - ItemSize(label_size); - RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + RenderText(ImVec2(window->DC.CursorPos.x, window->DC.CursorPos.y + style.FramePadding.y), label); + ItemSize(label_size, style.FramePadding.y); } + ImGui::EndGroup(); + return value_changed; } @@ -5588,8 +6236,8 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f { ImGuiTextEditCallbackData callback_data; memset(&callback_data, 0, sizeof(ImGuiTextEditCallbackData)); - callback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter; - callback_data.EventChar = ImWchar(c); + callback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter; + callback_data.EventChar = (ImWchar)c; callback_data.Flags = flags; callback_data.UserData = user_data; if (callback(&callback_data) != 0) @@ -5617,10 +6265,10 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT const float w = ImGui::CalcItemWidth(); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImGuiAabb frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); - const ImGuiAabb 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); - if (!ItemAdd(frame_bb, &id)) + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*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)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, &id)) return false; // NB: we are only allowed to access 'edit_state' if we are the active widget. @@ -5634,7 +6282,10 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT const bool hovered = IsHovered(frame_bb, id); if (hovered) + { g.HoveredId = id; + g.MouseCursor = ImGuiMouseCursor_TextInput; + } const bool user_clicked = hovered && io.MouseClicked[0]; bool select_all = (g.ActiveId != id) && (flags & ImGuiInputTextFlags_AutoSelectAll) != 0; @@ -5647,9 +6298,9 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT // From the moment we focused we are ignoring the content of 'buf' ImFormatString(edit_state.InitialText, IM_ARRAYSIZE(edit_state.InitialText), "%s", buf); const char* buf_end = NULL; - edit_state.CurLenW = (int)ImTextStrFromUtf8(edit_state.Text, IM_ARRAYSIZE(edit_state.Text), buf, NULL, &buf_end); - edit_state.CurLenA = (int)(buf_end - buf); // We can't get the result from ImFormatString() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8. - edit_state.Width = w; + edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text, IM_ARRAYSIZE(edit_state.Text), buf, NULL, &buf_end); + edit_state.CurLenA = buf_end - buf; // We can't get the result from ImFormatString() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8. + edit_state.Width = w + style.FramePadding.x; edit_state.InputCursorScreenPos = ImVec2(-1.f,-1.f); edit_state.CursorAnimReset(); @@ -5657,7 +6308,7 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT { edit_state.Id = id; edit_state.ScrollX = 0.0f; - stb_textedit_initialize_state(&edit_state.StbState, true); + stb_textedit_initialize_state(&edit_state.StbState, true); if (focus_requested_by_code) select_all = true; } @@ -5665,9 +6316,9 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT { // 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. - edit_state.StbState.cursor = ImMin(edit_state.StbState.cursor, edit_state.CurLenW); - edit_state.StbState.select_start = ImMin(edit_state.StbState.select_start, edit_state.CurLenW); - edit_state.StbState.select_end = ImMin(edit_state.StbState.select_end, edit_state.CurLenW); + edit_state.StbState.cursor = ImMin(edit_state.StbState.cursor, (int)edit_state.CurLenW); + edit_state.StbState.select_start = ImMin(edit_state.StbState.select_start, (int)edit_state.CurLenW); + edit_state.StbState.select_end = ImMin(edit_state.StbState.select_end, (int)edit_state.CurLenW); } if (focus_requested_by_tab || (user_clicked && is_ctrl_down)) select_all = true; @@ -5692,18 +6343,22 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT bool value_changed = false; bool cancel_edit = false; bool enter_pressed = false; - static char text_tmp_utf8[IM_ARRAYSIZE(edit_state.InitialText)]; + if (g.ActiveId == id) + //if (edit_state.Id == id) // Works, but double-click to select-all sets cursors to end which in turn tends to scroll toward the right when shrinking widget. + { + // Update some data if we are active or last active + edit_state.Width = w + style.FramePadding.x; + edit_state.BufSizeA = buf_size; + edit_state.Font = g.Font; + edit_state.FontSize = g.FontSize; + edit_state.UpdateScrollOffset(); + } if (g.ActiveId == id) { // Edit in progress - edit_state.BufSizeA = buf_size; - edit_state.Font = window->Font(); - edit_state.FontSize = window->FontSize(); - const float mx = g.IO.MousePos.x - frame_bb.Min.x - style.FramePadding.x; - const float my = window->FontSize()*0.5f; // Flatten mouse because we are doing a single-line edit + const float my = g.FontSize*0.5f; // Flatten mouse because we are doing a single-line edit - edit_state.UpdateScrollOffset(); if (select_all || (hovered && io.MouseDoubleClicked[0])) { edit_state.SelectAll(); @@ -5713,7 +6368,6 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT { stb_textedit_click(&edit_state, &edit_state.StbState, mx + edit_state.ScrollX, my); edit_state.CursorAnimReset(); - } else if (io.MouseDown[0] && !edit_state.SelectedAllMouseLock) { @@ -5721,7 +6375,7 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT edit_state.CursorAnimReset(); } if (edit_state.SelectedAllMouseLock && !io.MouseDown[0]) - edit_state.SelectedAllMouseLock = false; + edit_state.SelectedAllMouseLock = false; if (g.IO.InputCharacters[0]) { @@ -5764,9 +6418,9 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT if (g.IO.SetClipboardTextFn) { const int ib = edit_state.HasSelection() ? ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end) : 0; - const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : edit_state.CurLenW; - ImTextStrToUtf8(text_tmp_utf8, IM_ARRAYSIZE(text_tmp_utf8), edit_state.Text+ib, edit_state.Text+ie); - g.IO.SetClipboardTextFn(text_tmp_utf8); + const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : (int)edit_state.CurLenW; + ImTextStrToUtf8(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), edit_state.Text+ib, edit_state.Text+ie); + g.IO.SetClipboardTextFn(g.TempBuffer); } if (cut) @@ -5818,7 +6472,7 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT // Note that as soon as we can focus into the input box, the in-widget value gets priority over any underlying modification of the input buffer // FIXME: We actually always render 'buf' in RenderTextScrolledClipped // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks - ImTextStrToUtf8(text_tmp_utf8, IM_ARRAYSIZE(text_tmp_utf8), edit_state.Text, NULL); + ImTextStrToUtf8(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), edit_state.Text, NULL); // User callback if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackAlways)) != 0) @@ -5847,9 +6501,9 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT if (event_key != ImGuiKey_COUNT || (flags & ImGuiInputTextFlags_CallbackAlways) != 0) { ImGuiTextEditCallbackData callback_data; - callback_data.EventFlag = event_flag; + callback_data.EventFlag = event_flag; callback_data.EventKey = event_key; - callback_data.Buf = text_tmp_utf8; + callback_data.Buf = g.TempBuffer; callback_data.BufSize = edit_state.BufSizeA; callback_data.BufDirty = false; callback_data.Flags = flags; @@ -5864,7 +6518,7 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT callback(&callback_data); // Read back what user may have modified - IM_ASSERT(callback_data.Buf == text_tmp_utf8); // Invalid to modify those fields + IM_ASSERT(callback_data.Buf == g.TempBuffer); // Invalid to modify those fields IM_ASSERT(callback_data.BufSize == edit_state.BufSizeA); IM_ASSERT(callback_data.Flags == flags); if (callback_data.CursorPos != utf8_cursor_pos) edit_state.StbState.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); @@ -5872,24 +6526,24 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT if (callback_data.SelectionEnd != utf8_selection_end) edit_state.StbState.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); if (callback_data.BufDirty) { - ImTextStrFromUtf8(edit_state.Text, IM_ARRAYSIZE(edit_state.Text), text_tmp_utf8, NULL); + ImTextStrFromUtf8(edit_state.Text, IM_ARRAYSIZE(edit_state.Text), g.TempBuffer, NULL); edit_state.CursorAnimReset(); } } } - if (strcmp(text_tmp_utf8, buf) != 0) + if (strcmp(g.TempBuffer, buf) != 0) { - ImFormatString(buf, buf_size, "%s", text_tmp_utf8); + ImFormatString(buf, buf_size, "%s", g.TempBuffer); value_changed = true; } } } - + RenderFrame(frame_bb.Min, frame_bb.Max, window->Color(ImGuiCol_FrameBg), true, style.FrameRounding); - const ImVec2 font_off_up = ImVec2(0.0f,window->FontSize()+1.0f); // FIXME: those offsets are part of the style or font API - const ImVec2 font_off_dn = ImVec2(0.0f,2.0f); + const ImVec2 font_off_up = ImVec2(0.0f, g.FontSize+1.0f); // FIXME: those offsets are part of the style or font API + const ImVec2 font_off_dn = ImVec2(0.0f, 2.0f); if (g.ActiveId == id) { @@ -5904,7 +6558,9 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT } } - ImGuiTextEditState::RenderTextScrolledClipped(window->Font(), window->FontSize(), buf, frame_bb.Min + style.FramePadding, w, (g.ActiveId == id) ? edit_state.ScrollX : 0.0f); + //const float render_scroll_x = (g.ActiveId == id) ? edit_state.ScrollX : 0.0f; + const float render_scroll_x = (edit_state.Id == id) ? edit_state.ScrollX : 0.0f; + ImGuiTextEditState::RenderTextScrolledClipped(g.Font, g.FontSize, buf, frame_bb.Min + style.FramePadding, w + style.FramePadding.x, render_scroll_x); if (g.ActiveId == id) { @@ -5913,10 +6569,10 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT // Draw blinking cursor if (g.InputTextState.CursorIsVisible()) window->DrawList->AddRect(cursor_pos - font_off_up + ImVec2(0,2), cursor_pos + font_off_dn - ImVec2(0,3), window->Color(ImGuiCol_Text)); - + // Notify OS of text input position for advanced IME if (io.ImeSetInputScreenPosFn && ImLengthSqr(edit_state.InputCursorScreenPos - cursor_pos) > 0.0001f) - io.ImeSetInputScreenPosFn((int)cursor_pos.x - 1, (int)(cursor_pos.y - window->FontSize())); // -1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety. + io.ImeSetInputScreenPosFn((int)cursor_pos.x - 1, (int)(cursor_pos.y - g.FontSize)); // -1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety. edit_state.InputCursorScreenPos = cursor_pos; } @@ -5943,6 +6599,7 @@ static bool InputFloatN(const char* label, float* v, int components, int decimal const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.FramePadding.x*2.0f + style.ItemInnerSpacing.x) * (components-1))); bool value_changed = false; + ImGui::BeginGroup(); ImGui::PushID(label); ImGui::PushItemWidth(w_item_one); for (int i = 0; i < components; i++) @@ -5960,7 +6617,9 @@ static bool InputFloatN(const char* label, float* v, int components, int decimal ImGui::PopItemWidth(); ImGui::PopID(); + window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.CurrentLineTextBaseOffset, style.FramePadding.y); ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::EndGroup(); return value_changed; } @@ -5980,6 +6639,59 @@ bool ImGui::InputFloat4(const char* label, float v[4], int decimal_precision) return InputFloatN(label, v, 4, decimal_precision); } +static bool InputIntN(const char* label, int* v, int components) +{ + ImGuiState& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const ImGuiStyle& style = g.Style; + const float w_full = ImGui::CalcItemWidth(); + const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f + style.ItemInnerSpacing.x) * (components-1)) / (float)components)); + const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.FramePadding.x*2.0f + style.ItemInnerSpacing.x) * (components-1))); + + bool value_changed = false; + ImGui::BeginGroup(); + ImGui::PushID(label); + ImGui::PushItemWidth(w_item_one); + for (int i = 0; i < components; i++) + { + ImGui::PushID(i); + if (i + 1 == components) + { + ImGui::PopItemWidth(); + ImGui::PushItemWidth(w_item_last); + } + value_changed |= ImGui::InputInt("##v", &v[i], 0, 0); + ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); + ImGui::PopID(); + } + ImGui::PopItemWidth(); + ImGui::PopID(); + + window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.CurrentLineTextBaseOffset, style.FramePadding.y); + ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::EndGroup(); + + return value_changed; +} + +bool ImGui::InputInt2(const char* label, int v[2]) +{ + return InputIntN(label, v, 2); +} + +bool ImGui::InputInt3(const char* label, int v[3]) +{ + return InputIntN(label, v, 3); +} + +bool ImGui::InputInt4(const char* label, int v[4]) +{ + return InputIntN(label, v, 4); +} + static bool Items_ArrayGetter(void* data, int idx, const char** out_text) { const char** items = (const char**)data; @@ -6042,17 +6754,17 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi const float w = ImGui::CalcItemWidth(); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImGuiAabb frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); - const ImGuiAabb bb(frame_bb.Min, frame_bb.Max + ImVec2(style.ItemInnerSpacing.x + label_size.x,0)); - ItemSize(bb); - if (!ItemAdd(frame_bb, &id)) + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(style.ItemInnerSpacing.x + label_size.x,0)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, &id)) return false; - const float arrow_size = (window->FontSize() + style.FramePadding.x * 2.0f); + const float arrow_size = (g.FontSize + style.FramePadding.x * 2.0f); const bool hovered = IsHovered(frame_bb, id); bool value_changed = false; - const ImGuiAabb value_bb(frame_bb.Min, frame_bb.Max - ImVec2(arrow_size, 0.0f)); + const ImRect value_bb(frame_bb.Min, frame_bb.Max - ImVec2(arrow_size, 0.0f)); RenderFrame(frame_bb.Min, frame_bb.Max, window->Color(ImGuiCol_FrameBg), true, style.FrameRounding); RenderFrame(ImVec2(frame_bb.Max.x-arrow_size, frame_bb.Min.y), frame_bb.Max, window->Color(hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button), true, style.FrameRounding); // FIXME-ROUNDING RenderCollapseTriangle(ImVec2(frame_bb.Max.x-arrow_size, frame_bb.Min.y) + style.FramePadding, true); @@ -6066,7 +6778,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); - + ImGui::PushID((int)id); bool menu_toggled = false; if (hovered) @@ -6080,7 +6792,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi FocusWindow(window); } } - + if (g.ActiveComboID == id) { // Size default to hold ~7 items @@ -6089,12 +6801,13 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi const ImVec2 backup_pos = ImGui::GetCursorPos(); const float popup_off_x = 0.0f;//style.ItemInnerSpacing.x; - const float popup_height = (label_size.y + style.ItemSpacing.y) * ImMin(items_count, height_in_items) + style.WindowPadding.y; - const ImGuiAabb popup_aabb(ImVec2(frame_bb.Min.x+popup_off_x, frame_bb.Max.y), ImVec2(frame_bb.Max.x+popup_off_x, frame_bb.Max.y + popup_height)); - ImGui::SetCursorPos(popup_aabb.Min - window->Pos); + const float popup_height = (label_size.y + style.ItemSpacing.y) * ImMin(items_count, height_in_items) + (style.FramePadding.y * 3); + const ImRect popup_rect(ImVec2(frame_bb.Min.x+popup_off_x, frame_bb.Max.y), ImVec2(frame_bb.Max.x+popup_off_x, frame_bb.Max.y + popup_height)); + ImGui::SetCursorPos(popup_rect.Min - window->Pos); const ImGuiWindowFlags flags = ImGuiWindowFlags_ComboBox | ((window->Flags & ImGuiWindowFlags_ShowBorders) ? ImGuiWindowFlags_ShowBorders : 0); - ImGui::BeginChild("#ComboBox", popup_aabb.GetSize(), false, flags); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); + ImGui::BeginChild("#ComboBox", popup_rect.GetSize(), false, flags); ImGui::Spacing(); bool combo_item_active = false; @@ -6121,8 +6834,9 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi ImGui::PopID(); } ImGui::EndChild(); + ImGui::PopStyleVar(); ImGui::SetCursorPos(backup_pos); - + if (!combo_item_active && g.ActiveId != 0) g.ActiveComboID = 0; } @@ -6144,14 +6858,15 @@ bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg) const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - - const float w = window->Pos.x + ImGui::GetContentRegionMax().x - window->DC.CursorPos.x; + + const float w = ImMax(label_size.x, window->Pos.x + ImGui::GetContentRegionMax().x - style.AutoFitPadding.x - window->DC.CursorPos.x); const ImVec2 size(size_arg.x != 0.0f ? size_arg.x : w, size_arg.y != 0.0f ? size_arg.y : label_size.y); - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + size); + ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); ItemSize(bb); + bb.Max.x += style.AutoFitPadding.x; // Selectables are meant to be tightly packed together. So for both rendering and collision we extend to compensate for spacing. - ImGuiAabb bb_with_spacing = bb; + ImRect bb_with_spacing = bb; const float spacing_L = (float)(int)(style.ItemSpacing.x * 0.5f); const float spacing_U = (float)(int)(style.ItemSpacing.y * 0.5f); const float spacing_R = style.ItemSpacing.x - spacing_L; @@ -6164,7 +6879,7 @@ bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg) return false; bool hovered, held; - bool pressed = ButtonBehaviour(bb_with_spacing, id, &hovered, &held, true, false, false); + bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, true, false, false); // Render if (hovered || selected) @@ -6201,13 +6916,14 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. ImVec2 size; - size.x = (size_arg.x != 0.0f) ? size_arg.x : ImGui::CalcItemWidth() + style.FramePadding.x * 2.0f; - size.y = (size_arg.y != 0.0f) ? size_arg.y : ImGui::GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y; + size.x = (size_arg.x != 0.0f) ? (size_arg.x) : ImGui::CalcItemWidth() + style.FramePadding.x * 2.0f; + size.y = (size_arg.y != 0.0f) ? (size_arg.y) : ImGui::GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y; const ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); - const ImGuiAabb frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); - const ImGuiAabb bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); - window->DC.LastItemAabb = bb; + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_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)); + window->DC.LastItemRect = bb; + ImGui::BeginGroup(); if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); @@ -6234,12 +6950,17 @@ bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_item void ImGui::ListBoxFooter() { ImGuiWindow* parent_window = GetParentWindow(); - const ImGuiAabb bb = parent_window->DC.LastItemAabb; - + const ImRect bb = parent_window->DC.LastItemRect; + const ImGuiStyle& style = ImGui::GetStyle(); + ImGui::EndChildFrame(); + // Redeclare item size so that it includes the label (we have stored the full size in LastItemRect) + // We call SameLine() to restore DC.CurrentLine* data + ImGui::SameLine(); parent_window->DC.CursorPos = bb.Min; - ItemSize(bb, NULL); + ItemSize(bb, style.FramePadding.y); + ImGui::EndGroup(); } bool ImGui::ListBox(const char* label, int* current_item, const char** items, int items_count, int height_items) @@ -6288,14 +7009,14 @@ bool ImGui::ColorButton(const ImVec4& col, bool small_height, bool outline_borde const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID("#colorbutton"); - const float square_size = window->FontSize(); - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(square_size + style.FramePadding.x*2, square_size + (small_height ? 0 : style.FramePadding.y*2))); - ItemSize(bb); + const float square_size = g.FontSize; + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(square_size + style.FramePadding.x*2, square_size + (small_height ? 0 : style.FramePadding.y*2))); + ItemSize(bb, small_height ? 0.0f : style.FramePadding.y); if (!ItemAdd(bb, &id)) return false; bool hovered, held; - bool pressed = ButtonBehaviour(bb, id, &hovered, &held, true); + bool pressed = ButtonBehavior(bb, id, &hovered, &held, true); RenderFrame(bb.Min, bb.Max, window->Color(col), outline_border, style.FrameRounding); if (hovered) @@ -6336,59 +7057,54 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); const float w_full = ImGui::CalcItemWidth(); - const float square_sz = (window->FontSize() + style.FramePadding.x * 2.0f); + const float square_sz = (g.FontSize + style.FramePadding.x * 2.0f); ImGuiColorEditMode edit_mode = window->DC.ColorEditMode; if (edit_mode == ImGuiColorEditMode_UserSelect || edit_mode == ImGuiColorEditMode_UserSelectShowButton) edit_mode = g.ColorEditModeStorage.GetInt(id, 0) % 3; - float fx = col[0]; - float fy = col[1]; - float fz = col[2]; - float fw = col[3]; - const ImVec4 col_display(fx, fy, fz, 1.0f); + float f[4] = { col[0], col[1], col[2], col[3] }; if (edit_mode == ImGuiColorEditMode_HSV) - ImGui::ColorConvertRGBtoHSV(fx, fy, fz, fx, fy, fz); + ImGui::ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); - int ix = (int)(fx * 255.0f + 0.5f); - int iy = (int)(fy * 255.0f + 0.5f); - int iz = (int)(fz * 255.0f + 0.5f); - int iw = (int)(fw * 255.0f + 0.5f); + int i[4] = { (int)(f[0] * 255.0f + 0.5f), (int)(f[1] * 255.0f + 0.5f), (int)(f[2] * 255.0f + 0.5f), (int)(f[3] * 255.0f + 0.5f) }; int components = alpha ? 4 : 3; bool value_changed = false; + ImGui::BeginGroup(); ImGui::PushID(label); - bool hsv = (edit_mode == 1); + const bool hsv = (edit_mode == 1); switch (edit_mode) { case ImGuiColorEditMode_RGB: case ImGuiColorEditMode_HSV: { - // 0: RGB 0..255 Sliders - // 1: HSV 0..255 Sliders + // RGB/HSV 0..255 Sliders const float w_items_all = w_full - (square_sz + style.ItemInnerSpacing.x); const float w_item_one = ImMax(1.0f, (float)(int)((w_items_all - (style.FramePadding.x*2.0f + style.ItemInnerSpacing.x) * (components-1)) / (float)components)); const float w_item_last = ImMax(1.0f, (float)(int)(w_items_all - (w_item_one + style.FramePadding.x*2.0f + style.ItemInnerSpacing.x) * (components-1))); + const bool hide_prefix = (w_item_one <= CalcTextSize("M:999").x); + const char* ids[4] = { "##X", "##Y", "##Z", "##W" }; + const char* fmt_table[3][4] = + { + { "%3.0f", "%3.0f", "%3.0f", "%3.0f" }, + { "R:%3.0f", "G:%3.0f", "B:%3.0f", "A:%3.0f" }, + { "H:%3.0f", "S:%3.0f", "V:%3.0f", "A:%3.0f" } + }; + const char** fmt = hide_prefix ? fmt_table[0] : hsv ? fmt_table[2] : fmt_table[1]; + ImGui::PushItemWidth(w_item_one); - value_changed |= ImGui::SliderInt("##X", &ix, 0, 255, hsv ? "H:%3.0f" : "R:%3.0f"); - ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); - value_changed |= ImGui::SliderInt("##Y", &iy, 0, 255, hsv ? "S:%3.0f" : "G:%3.0f"); - ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); - if (alpha) + for (int n = 0; n < components; n++) { - value_changed |= ImGui::SliderInt("##Z", &iz, 0, 255, hsv ? "V:%3.0f" : "B:%3.0f"); - ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); - ImGui::PushItemWidth(w_item_last); - value_changed |= ImGui::SliderInt("##W", &iw, 0, 255, "A:%3.0f"); - } - else - { - ImGui::PushItemWidth(w_item_last); - value_changed |= ImGui::SliderInt("##Z", &iz, 0, 255, hsv ? "V:%3.0f" : "B:%3.0f"); + if (n > 0) + ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); + if (n + 1 == components) + ImGui::PushItemWidth(w_item_last); + value_changed |= ImGui::DragInt(ids[n], &i[n], 1.0f, 0, 255, fmt[n]); } ImGui::PopItemWidth(); ImGui::PopItemWidth(); @@ -6396,46 +7112,42 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) break; case ImGuiColorEditMode_HEX: { - // 2: RGB Hexadecimal + // RGB Hexadecimal Input const float w_slider_all = w_full - square_sz; char buf[64]; if (alpha) - sprintf(buf, "#%02X%02X%02X%02X", ix, iy, iz, iw); + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", i[0], i[1], i[2], i[3]); else - sprintf(buf, "#%02X%02X%02X", ix, iy, iz); + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", i[0], i[1], i[2]); ImGui::PushItemWidth(w_slider_all - style.ItemInnerSpacing.x); - value_changed |= ImGui::InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal); + value_changed |= ImGui::InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); ImGui::PopItemWidth(); char* p = buf; - while (*p == '#' || ImCharIsSpace(*p)) + while (*p == '#' || ImCharIsSpace(*p)) p++; // Treat at unsigned (%X is unsigned) - ix = iy = iz = iw = 0; + i[0] = i[1] = i[2] = i[3] = 0; if (alpha) - sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&ix, (unsigned int*)&iy, (unsigned int*)&iz, (unsigned int*)&iw); + sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); else - sscanf(p, "%02X%02X%02X", (unsigned int*)&ix, (unsigned int*)&iy, (unsigned int*)&iz); + sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]); } break; } ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); + + const ImVec4 col_display(col[0], col[1], col[2], 1.0f); if (ImGui::ColorButton(col_display)) - { - // Don't set local copy of 'edit_mode' right away! - g.ColorEditModeStorage.SetInt(id, (edit_mode + 1) % 3); - } + g.ColorEditModeStorage.SetInt(id, (edit_mode + 1) % 3); // Don't set local copy of 'edit_mode' right away! if (window->DC.ColorEditMode == ImGuiColorEditMode_UserSelectShowButton) { ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); const char* button_titles[3] = { "RGB", "HSV", "HEX" }; if (ImGui::Button(button_titles[edit_mode])) - { - // Don't set local copy of 'edit_mode' right away! - g.ColorEditModeStorage.SetInt(id, (edit_mode + 1) % 3); - } + g.ColorEditModeStorage.SetInt(id, (edit_mode + 1) % 3); // Don't set local copy of 'edit_mode' right away! ImGui::SameLine(); } else @@ -6446,23 +7158,22 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); // Convert back - fx = ix / 255.0f; - fy = iy / 255.0f; - fz = iz / 255.0f; - fw = iw / 255.0f; + for (int n = 0; n < 4; n++) + f[n] = i[n] / 255.0f; if (edit_mode == 1) - ImGui::ColorConvertHSVtoRGB(fx, fy, fz, fx, fy, fz); + ImGui::ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); if (value_changed) { - col[0] = fx; - col[1] = fy; - col[2] = fz; + col[0] = f[0]; + col[1] = f[1]; + col[2] = f[2]; if (alpha) - col[3] = fw; + col[3] = f[3]; } ImGui::PopID(); + ImGui::EndGroup(); return value_changed; } @@ -6483,7 +7194,7 @@ void ImGui::Separator() if (window->DC.ColumnsCount > 1) PopClipRect(); - const ImGuiAabb bb(ImVec2(window->Pos.x, window->DC.CursorPos.y), ImVec2(window->Pos.x + window->Size.x, window->DC.CursorPos.y)); + const ImRect bb(ImVec2(window->Pos.x, window->DC.CursorPos.y), ImVec2(window->Pos.x + window->Size.x, window->DC.CursorPos.y)); ItemSize(ImVec2(0.0f, bb.GetSize().y)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit if (!ItemAdd(bb, NULL)) { @@ -6494,6 +7205,10 @@ void ImGui::Separator() window->DrawList->AddLine(bb.Min, bb.Max, window->Color(ImGuiCol_Border)); + ImGuiState& g = *GImGui; + if (g.LogEnabled) + ImGui::LogText(STR_NEWLINE "--------------------------------"); + if (window->DC.ColumnsCount > 1) { PushColumnClipRect(); @@ -6512,66 +7227,134 @@ void ImGui::Spacing() } // Advance cursor given item size. -static void ItemSize(ImVec2 size, ImVec2* adjust_vertical_offset) +static void ItemSize(ImVec2 size, float text_offset_y) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return; - const float line_height = ImMax(window->DC.CurrentLineHeight, size.y); - if (adjust_vertical_offset) - adjust_vertical_offset->y = adjust_vertical_offset->y + (line_height - size.y) * 0.5f; - // Always align ourselves on pixel boundaries + const float line_height = ImMax(window->DC.CurrentLineHeight, size.y); + const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y); window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y); window->DC.CursorPos = ImVec2((float)(int)(window->Pos.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX), (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y)); + window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y); - window->SizeContentsCurrent = ImMax(window->SizeContentsCurrent, ImVec2(window->DC.CursorPosPrevLine.x - window->Pos.x, window->DC.CursorPos.y + window->ScrollY - window->Pos.y)); + //window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, 0xFF0000FF, 4); // Debug window->DC.PrevLineHeight = line_height; - window->DC.CurrentLineHeight = 0.0f; + window->DC.PrevLineTextBaseOffset = text_base_offset; + window->DC.CurrentLineHeight = window->DC.CurrentLineTextBaseOffset = 0.0f; } -static void ItemSize(const ImGuiAabb& bb, ImVec2* adjust_start_offset) -{ - ItemSize(bb.GetSize(), adjust_start_offset); +static inline void ItemSize(const ImRect& bb, float text_offset_y) +{ + ItemSize(bb.GetSize(), text_offset_y); } -static bool IsClipped(const ImGuiAabb& bb) +static bool IsClippedEx(const ImRect& bb, bool clip_even_when_logged) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - if (!bb.Overlaps(ImGuiAabb(window->ClipRectStack.back())) && !g.LogEnabled) - return true; + if (!bb.Overlaps(ImRect(window->ClipRectStack.back()))) + { + if (clip_even_when_logged || !g.LogEnabled) + return true; + } return false; } -bool ImGui::IsClipped(const ImVec2& item_size) +bool ImGui::IsRectClipped(const ImVec2& size) { ImGuiWindow* window = GetCurrentWindow(); - return IsClipped(ImGuiAabb(window->DC.CursorPos, window->DC.CursorPos + item_size)); + return IsClippedEx(ImRect(window->DC.CursorPos, window->DC.CursorPos + size), true); } -static bool ItemAdd(const ImGuiAabb& bb, const ImGuiID* id) +static bool ItemAdd(const ImRect& bb, const ImGuiID* id) { ImGuiWindow* window = GetCurrentWindow(); window->DC.LastItemID = id ? *id : 0; - window->DC.LastItemAabb = bb; - if (IsClipped(bb)) + window->DC.LastItemRect = bb; + if (IsClippedEx(bb, false)) { - window->DC.LastItemHovered = false; - return false; + if (!id || *id != GImGui->ActiveId) + { + window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRect = false; + return false; + } } // This is a sensible default, but widgets are free to override it after calling ItemAdd() - const bool hovered = IsMouseHoveringBox(bb); - //const bool hovered = (g.ActiveId == 0 || (id && g.ActiveId == *id) || g.ActiveIdIsFocusedOnly) && IsMouseHoveringBox(bb); // matching the behaviour of IsHovered(), not always what the user wants? - window->DC.LastItemHovered = hovered; + ImGuiState& g = *GImGui; + if (IsMouseHoveringRect(bb)) + { + // Matching the behavior of IsHovered() but ignore if ActiveId==window->MoveID (we clicked on the window background) + // So that clicking on items with no active id such as Text() still returns true with IsItemHovered() + window->DC.LastItemHoveredRect = true; + window->DC.LastItemHoveredAndUsable = false; + if (g.HoveredRootWindow == window->RootWindow) + if (g.ActiveId == 0 || (id && g.ActiveId == *id) || g.ActiveIdIsFocusedOnly || (g.ActiveId == window->MoveID)) + if (IsWindowContentHoverable(window)) + window->DC.LastItemHoveredAndUsable = true; + } + else + { + window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRect = false; + } + return true; } +void ImGui::BeginGroup() +{ + ImGuiWindow* window = GetCurrentWindow(); + + window->DC.GroupStack.resize(window->DC.GroupStack.size() + 1); + ImGuiGroupData& group_data = window->DC.GroupStack.back(); + group_data.BackupCursorPos = window->DC.CursorPos; + group_data.BackupCursorMaxPos = window->DC.CursorMaxPos; + group_data.BackupColumnsStartX = window->DC.ColumnsStartX; + group_data.BackupCurrentLineHeight = window->DC.CurrentLineHeight; + group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset; + group_data.BackupLogLinePosY = window->DC.LogLinePosY; + + window->DC.ColumnsStartX = window->DC.CursorPos.x - window->Pos.x; + window->DC.CursorMaxPos = window->DC.CursorPos; + window->DC.CurrentLineHeight = 0.0f; + window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; +} + +void ImGui::EndGroup() +{ + ImGuiWindow* window = GetCurrentWindow(); + ImGuiStyle& style = ImGui::GetStyle(); + + IM_ASSERT(!window->DC.GroupStack.empty()); + + ImGuiGroupData& group_data = window->DC.GroupStack.back(); + + ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos); + group_bb.Max.y -= style.ItemSpacing.y; // Cancel out last vertical spacing because we are adding one ourselves. + group_bb.Max = ImMax(group_bb.Min, group_bb.Max); + + window->DC.CursorPos = group_data.BackupCursorPos; + window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); + window->DC.CurrentLineHeight = group_data.BackupCurrentLineHeight; + window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset; // FIXME: Ideally we'll grab the base offset from the first line of the group. + window->DC.ColumnsStartX = group_data.BackupColumnsStartX; + window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; + + ItemSize(group_bb.GetSize(), group_data.BackupCurrentLineTextBaseOffset); + ItemAdd(group_bb, NULL); + + window->DC.GroupStack.pop_back(); + + //window->DrawList->AddRect(group_bb.Min, group_bb.Max, 0xFFFF00FF); // Debug +} + // Gets back to previous line and continue with horizontal layout // column_x == 0 : follow on previous item // columm_x != 0 : align to specified column @@ -6583,7 +7366,7 @@ void ImGui::SameLine(int column_x, int spacing_w) ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return; - + float x, y; if (column_x != 0) { @@ -6598,6 +7381,7 @@ void ImGui::SameLine(int column_x, int spacing_w) y = window->DC.CursorPosPrevLine.y; } window->DC.CurrentLineHeight = window->DC.PrevLineHeight; + window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; window->DC.CursorPos = ImVec2(x, y); } @@ -6627,6 +7411,7 @@ void ImGui::NextColumn() window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX); window->DC.CursorPos.y = window->DC.ColumnsCellMinY; window->DC.CurrentLineHeight = 0.0f; + window->DC.CurrentLineTextBaseOffset = 0.0f; PushColumnClipRect(); ImGui::PushItemWidth(ImGui::GetColumnWidth() * 0.65f); @@ -6724,15 +7509,17 @@ void ImGui::Columns(int columns_count, const char* id, bool border) for (int i = 1; i < window->DC.ColumnsCount; i++) { float x = window->Pos.x + GetColumnOffset(i); - + const ImGuiID column_id = window->DC.ColumnsSetID + ImGuiID(i); - const ImGuiAabb column_aabb(ImVec2(x-4,y1),ImVec2(x+4,y2)); + const ImRect column_rect(ImVec2(x-4,y1),ImVec2(x+4,y2)); - if (IsClipped(column_aabb)) + if (IsClippedEx(column_rect, false)) continue; bool hovered, held; - ButtonBehaviour(column_aabb, column_id, &hovered, &held, true); + ButtonBehavior(column_rect, column_id, &hovered, &held, true); + if (hovered || held) + g.MouseCursor = ImGuiMouseCursor_ResizeEW; // Draw before resize so our items positioning are in sync with the line being drawn const ImU32 col = window->Color(held ? ImGuiCol_ColumnActive : hovered ? ImGuiCol_ColumnHovered : ImGuiCol_Column); @@ -6783,32 +7570,43 @@ void ImGui::Columns(int columns_count, const char* id, bool border) } } -void ImGui::TreePush(const char* str_id) + +inline void ImGui::Indent() { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - window->DC.ColumnsStartX += g.Style.TreeNodeSpacing; + window->DC.ColumnsStartX += g.Style.IndentSpacing; window->DC.CursorPos.x = window->Pos.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX; +} + +inline void ImGui::Unindent() +{ + ImGuiState& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + window->DC.ColumnsStartX -= g.Style.IndentSpacing; + window->DC.CursorPos.x = window->Pos.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX; +} + +void ImGui::TreePush(const char* str_id) +{ + ImGuiWindow* window = GetCurrentWindow(); + ImGui::Indent(); window->DC.TreeDepth++; PushID(str_id ? str_id : "#TreePush"); } void ImGui::TreePush(const void* ptr_id) { - ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - window->DC.ColumnsStartX += g.Style.TreeNodeSpacing; - window->DC.CursorPos.x = window->Pos.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX; + ImGui::Indent(); window->DC.TreeDepth++; PushID(ptr_id ? ptr_id : (const void*)"#TreePush"); } void ImGui::TreePop() { - ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - window->DC.ColumnsStartX -= g.Style.TreeNodeSpacing; - window->DC.CursorPos.x = window->Pos.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX; + ImGui::Unindent(); window->DC.TreeDepth--; PopID(); } @@ -6833,7 +7631,7 @@ void ImGui::Value(const char* prefix, float v, const char* float_format) if (float_format) { char fmt[64]; - sprintf(fmt, "%%s: %s", float_format); + ImFormatString(fmt, IM_ARRAYSIZE(fmt), "%%s: %s", float_format); ImGui::Text(fmt, prefix, v); } else @@ -6877,6 +7675,15 @@ void ImDrawList::Clear() texture_id_stack.resize(0); } +void ImDrawList::ClearFreeMemory() +{ + commands.clear(); + vtx_buffer.clear(); + vtx_write = NULL; + clip_rect_stack.clear(); + texture_id_stack.clear(); +} + void ImDrawList::AddDrawCmd() { ImDrawCmd draw_cmd; @@ -6885,6 +7692,8 @@ void ImDrawList::AddDrawCmd() draw_cmd.texture_id = texture_id_stack.empty() ? NULL : texture_id_stack.back(); draw_cmd.user_callback = NULL; draw_cmd.user_callback_data = NULL; + + IM_ASSERT(draw_cmd.clip_rect.x <= draw_cmd.clip_rect.z && draw_cmd.clip_rect.y <= draw_cmd.clip_rect.w); commands.push_back(draw_cmd); } @@ -6924,6 +7733,18 @@ void ImDrawList::PushClipRect(const ImVec4& clip_rect) UpdateClipRect(); } +void ImDrawList::PushClipRectFullScreen() +{ + PushClipRect(GNullClipRect); + + // This would be more correct but we're not supposed to access ImGuiState from here? + //ImGuiState& g = *GImGui; + //if (g.IO.DisplayVisibleMin.x != g.IO.DisplayVisibleMax.x && g.IO.DisplayVisibleMin.y != g.IO.DisplayVisibleMax.y) + // PushClipRect(ImVec4(g.IO.DisplayVisibleMin.x, g.IO.DisplayVisibleMin.y, g.IO.DisplayVisibleMax.x, g.IO.DisplayVisibleMax.y)); + //else + // PushClipRect(ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y)); +} + void ImDrawList::PopClipRect() { IM_ASSERT(clip_rect_stack.size() > 0); @@ -6958,92 +7779,128 @@ void ImDrawList::PopTextureID() UpdateTextureID(); } -void ImDrawList::ReserveVertices(unsigned int vtx_count) +void ImDrawList::PrimReserve(unsigned int vtx_count) { - if (vtx_count > 0) - { - ImDrawCmd& draw_cmd = commands.back(); - draw_cmd.vtx_count += vtx_count; - vtx_buffer.resize(vtx_buffer.size() + vtx_count); - vtx_write = &vtx_buffer[vtx_buffer.size() - vtx_count]; - } + ImDrawCmd& draw_cmd = commands.back(); + draw_cmd.vtx_count += vtx_count; + + size_t vtx_buffer_size = vtx_buffer.size(); + vtx_buffer.resize(vtx_buffer_size + vtx_count); + vtx_write = &vtx_buffer[vtx_buffer_size]; } -void ImDrawList::AddVtx(const ImVec2& pos, ImU32 col) +void ImDrawList::PrimTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col) { - vtx_write->pos = pos; - vtx_write->col = col; - vtx_write->uv = GImGui->FontTexUvWhitePixel; - vtx_write++; + const ImVec2 uv = GImGui->FontTexUvWhitePixel; + vtx_write[0].pos = a; vtx_write[0].uv = uv; vtx_write[0].col = col; + vtx_write[1].pos = b; vtx_write[1].uv = uv; vtx_write[1].col = col; + vtx_write[2].pos = c; vtx_write[2].uv = uv; vtx_write[2].col = col; + vtx_write += 3; } -void ImDrawList::AddVtxUV(const ImVec2& pos, ImU32 col, const ImVec2& uv) +void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col) { - vtx_write->pos = pos; - vtx_write->col = col; - vtx_write->uv = uv; - vtx_write++; + const ImVec2 uv = GImGui->FontTexUvWhitePixel; + const ImVec2 b(c.x, a.y); + const ImVec2 d(a.x, c.y); + vtx_write[0].pos = a; vtx_write[0].uv = uv; vtx_write[0].col = col; + vtx_write[1].pos = b; vtx_write[1].uv = uv; vtx_write[1].col = col; + vtx_write[2].pos = c; vtx_write[2].uv = uv; vtx_write[2].col = col; + vtx_write[3].pos = a; vtx_write[3].uv = uv; vtx_write[3].col = col; + vtx_write[4].pos = c; vtx_write[4].uv = uv; vtx_write[4].col = col; + vtx_write[5].pos = d; vtx_write[5].uv = uv; vtx_write[5].col = col; + vtx_write += 6; } -// NB: memory should be reserved for 6 vertices by the caller. -void ImDrawList::AddVtxLine(const ImVec2& a, const ImVec2& b, ImU32 col) +void ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a, const ImVec2& uv_c, ImU32 col) { - const float length = sqrtf(ImLengthSqr(b - a)); - const ImVec2 hn = (b - a) * (0.50f / length); // half normal - const ImVec2 hp0 = ImVec2(+hn.y, -hn.x); // half perpendiculars + user offset - const ImVec2 hp1 = ImVec2(-hn.y, +hn.x); - - // Two triangles makes up one line. Using triangles allows us to reduce amount of draw calls. - AddVtx(a + hp0, col); - AddVtx(b + hp0, col); - AddVtx(a + hp1, col); - AddVtx(b + hp0, col); - AddVtx(b + hp1, col); - AddVtx(a + hp1, col); + const ImVec2 b(c.x, a.y); + const ImVec2 d(a.x, c.y); + const ImVec2 uv_b(uv_c.x, uv_a.y); + const ImVec2 uv_d(uv_a.x, uv_c.y); + vtx_write[0].pos = a; vtx_write[0].uv = uv_a; vtx_write[0].col = col; + vtx_write[1].pos = b; vtx_write[1].uv = uv_b; vtx_write[1].col = col; + vtx_write[2].pos = c; vtx_write[2].uv = uv_c; vtx_write[2].col = col; + vtx_write[3].pos = a; vtx_write[3].uv = uv_a; vtx_write[3].col = col; + vtx_write[4].pos = c; vtx_write[4].uv = uv_c; vtx_write[4].col = col; + vtx_write[5].pos = d; vtx_write[5].uv = uv_d; vtx_write[5].col = col; + vtx_write += 6; } -void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col) +void ImDrawList::PrimQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col) +{ + const ImVec2 uv = GImGui->FontTexUvWhitePixel; + vtx_write[0].pos = a; vtx_write[0].uv = uv; vtx_write[0].col = col; + vtx_write[1].pos = b; vtx_write[1].uv = uv; vtx_write[1].col = col; + vtx_write[2].pos = c; vtx_write[2].uv = uv; vtx_write[2].col = col; + vtx_write[3].pos = a; vtx_write[3].uv = uv; vtx_write[3].col = col; + vtx_write[4].pos = c; vtx_write[4].uv = uv; vtx_write[4].col = col; + vtx_write[5].pos = d; vtx_write[5].uv = uv; vtx_write[5].col = col; + vtx_write += 6; +} + +// FIXME-OPT: In many instances the caller could provide a normal. +void ImDrawList::PrimLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness) +{ + const float inv_length = 1.0f / sqrtf(ImLengthSqr(b - a)); + const float dx = (b.x - a.x) * (thickness * 0.5f * inv_length); // line direction, halved + const float dy = (b.y - a.y) * (thickness * 0.5f * inv_length); // line direction, halved + + const ImVec2 pa(a.x + dy, a.y - dx); + const ImVec2 pb(b.x + dy, b.y - dx); + const ImVec2 pc(b.x - dy, b.y + dx); + const ImVec2 pd(a.x - dy, a.y + dx); + PrimQuad(pa, pb, pc, pd, col); +} + +void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness) { if ((col >> 24) == 0) return; - ReserveVertices(6); - AddVtxLine(a, b, col); + PrimReserve(6); + PrimLine(a, b, col, thickness); } -void ImDrawList::AddArc(const ImVec2& center, float rad, ImU32 col, int a_min, int a_max, bool tris, const ImVec2& third_point_offset) +void ImDrawList::AddArcFast(const ImVec2& center, float radius, ImU32 col, int a_min, int a_max, bool filled, const ImVec2& third_point_offset) { if ((col >> 24) == 0) return; - static ImVec2 circle_vtx[12]; + const int SAMPLES = 12; + static ImVec2 circle_vtx[SAMPLES]; static bool circle_vtx_builds = false; if (!circle_vtx_builds) { - for (int i = 0; i < IM_ARRAYSIZE(circle_vtx); i++) + for (int i = 0; i < SAMPLES; i++) { - const float a = ((float)i / (float)IM_ARRAYSIZE(circle_vtx)) * 2*PI; + const float a = ((float)i / (float)SAMPLES) * 2*PI; circle_vtx[i].x = cosf(a + PI); circle_vtx[i].y = sinf(a + PI); } circle_vtx_builds = true; } - - if (tris) + + const ImVec2 uv = GImGui->FontTexUvWhitePixel; + if (filled) { - ReserveVertices((unsigned int)(a_max-a_min) * 3); - for (int a = a_min; a < a_max; a++) + PrimReserve((unsigned int)(a_max-a_min) * 3); + for (int a0 = a_min; a0 < a_max; a0++) { - AddVtx(center + circle_vtx[a % IM_ARRAYSIZE(circle_vtx)] * rad, col); - AddVtx(center + circle_vtx[(a+1) % IM_ARRAYSIZE(circle_vtx)] * rad, col); - AddVtx(center + third_point_offset, col); + int a1 = (a0 + 1 == SAMPLES) ? 0 : a0 + 1; + PrimVtx(center + circle_vtx[a0] * radius, uv, col); + PrimVtx(center + circle_vtx[a1] * radius, uv, col); + PrimVtx(center + third_point_offset, uv, col); } } else { - ReserveVertices((unsigned int)(a_max-a_min) * 6); - for (int a = a_min; a < a_max; a++) - AddVtxLine(center + circle_vtx[a % IM_ARRAYSIZE(circle_vtx)] * rad, center + circle_vtx[(a+1) % IM_ARRAYSIZE(circle_vtx)] * rad, col); + PrimReserve((unsigned int)(a_max-a_min) * 6); + for (int a0 = a_min; a0 < a_max; a0++) + { + int a1 = (a0 + 1 == SAMPLES) ? 0 : a0 + 1; + PrimLine(center + circle_vtx[a0] * radius, center + circle_vtx[a1] * radius, col); + } } } @@ -7058,24 +7915,24 @@ void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float roun if (r == 0.0f || rounding_corners == 0) { - ReserveVertices(4*6); - AddVtxLine(ImVec2(a.x,a.y), ImVec2(b.x,a.y), col); - AddVtxLine(ImVec2(b.x,a.y), ImVec2(b.x,b.y), col); - AddVtxLine(ImVec2(b.x,b.y), ImVec2(a.x,b.y), col); - AddVtxLine(ImVec2(a.x,b.y), ImVec2(a.x,a.y), col); + PrimReserve(4*6); + PrimLine(ImVec2(a.x,a.y), ImVec2(b.x,a.y), col); + PrimLine(ImVec2(b.x,a.y), ImVec2(b.x,b.y), col); + PrimLine(ImVec2(b.x,b.y), ImVec2(a.x,b.y), col); + PrimLine(ImVec2(a.x,b.y), ImVec2(a.x,a.y), col); } else { - ReserveVertices(4*6); - AddVtxLine(ImVec2(a.x + ((rounding_corners & 1)?r:0), a.y), ImVec2(b.x - ((rounding_corners & 2)?r:0), a.y), col); - AddVtxLine(ImVec2(b.x, a.y + ((rounding_corners & 2)?r:0)), ImVec2(b.x, b.y - ((rounding_corners & 4)?r:0)), col); - AddVtxLine(ImVec2(b.x - ((rounding_corners & 4)?r:0), b.y), ImVec2(a.x + ((rounding_corners & 8)?r:0), b.y), col); - AddVtxLine(ImVec2(a.x, b.y - ((rounding_corners & 8)?r:0)), ImVec2(a.x, a.y + ((rounding_corners & 1)?r:0)), col); + PrimReserve(4*6); + PrimLine(ImVec2(a.x + ((rounding_corners & 1)?r:0), a.y), ImVec2(b.x - ((rounding_corners & 2)?r:0), a.y), col); + PrimLine(ImVec2(b.x, a.y + ((rounding_corners & 2)?r:0)), ImVec2(b.x, b.y - ((rounding_corners & 4)?r:0)), col); + PrimLine(ImVec2(b.x - ((rounding_corners & 4)?r:0), b.y), ImVec2(a.x + ((rounding_corners & 8)?r:0), b.y), col); + PrimLine(ImVec2(a.x, b.y - ((rounding_corners & 8)?r:0)), ImVec2(a.x, a.y + ((rounding_corners & 1)?r:0)), col); - if (rounding_corners & 1) AddArc(ImVec2(a.x+r,a.y+r), r, col, 0, 3); - if (rounding_corners & 2) AddArc(ImVec2(b.x-r,a.y+r), r, col, 3, 6); - if (rounding_corners & 4) AddArc(ImVec2(b.x-r,b.y-r), r, col, 6, 9); - if (rounding_corners & 8) AddArc(ImVec2(a.x+r,b.y-r), r, col, 9, 12); + if (rounding_corners & 1) AddArcFast(ImVec2(a.x+r,a.y+r), r, col, 0, 3); + if (rounding_corners & 2) AddArcFast(ImVec2(b.x-r,a.y+r), r, col, 3, 6); + if (rounding_corners & 4) AddArcFast(ImVec2(b.x-r,b.y-r), r, col, 6, 9); + if (rounding_corners & 8) AddArcFast(ImVec2(a.x+r,b.y-r), r, col, 9, 12); } } @@ -7091,46 +7948,26 @@ void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, floa if (r == 0.0f || rounding_corners == 0) { // Use triangle so we can merge more draw calls together (at the cost of extra vertices) - ReserveVertices(6); - AddVtx(ImVec2(a.x,a.y), col); - AddVtx(ImVec2(b.x,a.y), col); - AddVtx(ImVec2(b.x,b.y), col); - AddVtx(ImVec2(a.x,a.y), col); - AddVtx(ImVec2(b.x,b.y), col); - AddVtx(ImVec2(a.x,b.y), col); + PrimReserve(6); + PrimRect(a, b, col); } else { - ReserveVertices(6+6*2); - AddVtx(ImVec2(a.x+r,a.y), col); - AddVtx(ImVec2(b.x-r,a.y), col); - AddVtx(ImVec2(b.x-r,b.y), col); - AddVtx(ImVec2(a.x+r,a.y), col); - AddVtx(ImVec2(b.x-r,b.y), col); - AddVtx(ImVec2(a.x+r,b.y), col); - + PrimReserve(6+6*2); + PrimRect(ImVec2(a.x+r,a.y), ImVec2(b.x-r,b.y), col); + float top_y = (rounding_corners & 1) ? a.y+r : a.y; float bot_y = (rounding_corners & 8) ? b.y-r : b.y; - AddVtx(ImVec2(a.x,top_y), col); - AddVtx(ImVec2(a.x+r,top_y), col); - AddVtx(ImVec2(a.x+r,bot_y), col); - AddVtx(ImVec2(a.x,top_y), col); - AddVtx(ImVec2(a.x+r,bot_y), col); - AddVtx(ImVec2(a.x,bot_y), col); + PrimRect(ImVec2(a.x,top_y), ImVec2(a.x+r,bot_y), col); top_y = (rounding_corners & 2) ? a.y+r : a.y; bot_y = (rounding_corners & 4) ? b.y-r : b.y; - AddVtx(ImVec2(b.x-r,top_y), col); - AddVtx(ImVec2(b.x,top_y), col); - AddVtx(ImVec2(b.x,bot_y), col); - AddVtx(ImVec2(b.x-r,top_y), col); - AddVtx(ImVec2(b.x,bot_y), col); - AddVtx(ImVec2(b.x-r,bot_y), col); + PrimRect(ImVec2(b.x-r,top_y), ImVec2(b.x,bot_y), col); - if (rounding_corners & 1) AddArc(ImVec2(a.x+r,a.y+r), r, col, 0, 3, true); - if (rounding_corners & 2) AddArc(ImVec2(b.x-r,a.y+r), r, col, 3, 6, true); - if (rounding_corners & 4) AddArc(ImVec2(b.x-r,b.y-r), r, col, 6, 9, true); - if (rounding_corners & 8) AddArc(ImVec2(a.x+r,b.y-r), r, col, 9, 12,true); + if (rounding_corners & 1) AddArcFast(ImVec2(a.x+r,a.y+r), r, col, 0, 3, true); + if (rounding_corners & 2) AddArcFast(ImVec2(b.x-r,a.y+r), r, col, 3, 6, true); + if (rounding_corners & 4) AddArcFast(ImVec2(b.x-r,b.y-r), r, col, 6, 9, true); + if (rounding_corners & 8) AddArcFast(ImVec2(a.x+r,b.y-r), r, col, 9, 12, true); } } @@ -7139,10 +7976,8 @@ void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec if ((col >> 24) == 0) return; - ReserveVertices(3); - AddVtx(a, col); - AddVtx(b, col); - AddVtx(c, col); + PrimReserve(3); + PrimTriangle(a, b, c, col); } void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments) @@ -7150,13 +7985,13 @@ void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int nu if ((col >> 24) == 0) return; - ReserveVertices((unsigned int)num_segments*6); + PrimReserve((unsigned int)num_segments*6); const float a_step = 2*PI/(float)num_segments; float a0 = 0.0f; for (int i = 0; i < num_segments; i++) { const float a1 = (i + 1) == num_segments ? 0.0f : a0 + a_step; - AddVtxLine(centre + ImVec2(cosf(a0), sinf(a0))*radius, centre + ImVec2(cosf(a1), sinf(a1))*radius, col); + PrimLine(centre + ImVec2(cosf(a0), sinf(a0))*radius, centre + ImVec2(cosf(a1), sinf(a1))*radius, col); a0 = a1; } } @@ -7166,26 +8001,29 @@ void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, if ((col >> 24) == 0) return; - ReserveVertices((unsigned int)num_segments*3); + const ImVec2 uv = GImGui->FontTexUvWhitePixel; + PrimReserve((unsigned int)num_segments*3); const float a_step = 2*PI/(float)num_segments; float a0 = 0.0f; for (int i = 0; i < num_segments; i++) { const float a1 = (i + 1) == num_segments ? 0.0f : a0 + a_step; - AddVtx(centre + ImVec2(cosf(a0), sinf(a0))*radius, col); - AddVtx(centre + ImVec2(cosf(a1), sinf(a1))*radius, col); - AddVtx(centre, col); + PrimVtx(centre + ImVec2(cosf(a0), sinf(a0))*radius, uv, col); + PrimVtx(centre + ImVec2(cosf(a1), sinf(a1))*radius, uv, col); + PrimVtx(centre, uv, col); a0 = a1; } } -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 ImVec2* cpu_clip_max) +void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec2* cpu_clip_max) { if ((col >> 24) == 0) return; if (text_end == NULL) text_end = text_begin + strlen(text_begin); + if (text_begin == text_end) + return; IM_ASSERT(font->ContainerAtlas->TexID == texture_id_stack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. @@ -7193,9 +8031,9 @@ void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 const unsigned int char_count = (unsigned int)(text_end - text_begin); const unsigned int vtx_count_max = char_count * 6; const size_t vtx_begin = vtx_buffer.size(); - ReserveVertices(vtx_count_max); + PrimReserve(vtx_count_max); - font->RenderText(font_size, pos, col, clip_rect_stack.back(), text_begin, text_end, vtx_write, wrap_width, cpu_clip_max); + font->RenderText(font_size, pos, col, clip_rect_stack.back(), text_begin, text_end, this, wrap_width, cpu_clip_max); // give back unused vertices vtx_buffer.resize((size_t)(vtx_write - &vtx_buffer.front())); @@ -7209,17 +8047,13 @@ void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& a, const Im if ((col >> 24) == 0) return; + // FIXME-OPT: This is wasting draw calls. const bool push_texture_id = texture_id_stack.empty() || user_texture_id != texture_id_stack.back(); if (push_texture_id) PushTextureID(user_texture_id); - ReserveVertices(6); - AddVtxUV(ImVec2(a.x,a.y), col, uv0); - AddVtxUV(ImVec2(b.x,a.y), col, ImVec2(uv1.x,uv0.y)); - AddVtxUV(ImVec2(b.x,b.y), col, uv1); - AddVtxUV(ImVec2(a.x,a.y), col, ImVec2(uv0.x,uv0.y)); - AddVtxUV(ImVec2(b.x,b.y), col, uv1); - AddVtxUV(ImVec2(a.x,b.y), col, ImVec2(uv0.x,uv1.y)); + PrimReserve(6); + PrimRectUV(a, b, uv0, uv1, col); if (push_texture_id) PopTextureID(); @@ -7252,7 +8086,7 @@ ImFontAtlas::ImFontAtlas() TexPixelsAlpha8 = NULL; TexPixelsRGBA32 = NULL; TexWidth = TexHeight = 0; - TexExtraDataPos = TexUvWhitePixel = ImVec2(0, 0); + TexUvWhitePixel = ImVec2(0, 0); } ImFontAtlas::~ImFontAtlas() @@ -7283,7 +8117,7 @@ void ImFontAtlas::ClearTexData() void ImFontAtlas::Clear() { - ClearInputData(); + ClearInputData(); ClearTexData(); for (size_t i = 0; i < Fonts.size(); i++) { @@ -7348,18 +8182,10 @@ static unsigned int stb_decompress(unsigned char *output, unsigned char *i, unsi // Load embedded ProggyClean.ttf at size 13 ImFont* ImFontAtlas::AddFontDefault() { - // Get compressed data unsigned int ttf_compressed_size; const void* ttf_compressed; GetDefaultCompressedFontDataTTF(&ttf_compressed, &ttf_compressed_size); - - // Decompress - const size_t buf_decompressed_size = stb_decompress_length((unsigned char*)ttf_compressed); - unsigned char* buf_decompressed = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size); - stb_decompress(buf_decompressed, (unsigned char*)ttf_compressed, ttf_compressed_size); - - // Add - ImFont* font = AddFontFromMemoryTTF(buf_decompressed, buf_decompressed_size, 13.0f, GetGlyphRangesDefault(), 0); + ImFont* font = AddFontFromMemoryCompressedTTF(ttf_compressed, ttf_compressed_size, 13.0f, GetGlyphRangesDefault(), 0); font->DisplayOffset.y += 1; return font; } @@ -7374,13 +8200,12 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, return NULL; } - // Add ImFont* font = AddFontFromMemoryTTF(data, data_size, size_pixels, glyph_ranges, font_no); return font; } // NB: ownership of 'data' is given to ImFontAtlas which will clear it. -ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* in_ttf_data, size_t in_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges, int font_no) +ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* in_ttf_data, unsigned int in_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges, int font_no) { // Create new font ImFont* font = (ImFont*)ImGui::MemAlloc(sizeof(ImFont)); @@ -7404,13 +8229,25 @@ ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* in_ttf_data, size_t in_ttf_data_ return font; } +ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* in_compressed_ttf_data, unsigned int in_compressed_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges, int font_no) +{ + // Decompress + const size_t buf_decompressed_size = stb_decompress_length((unsigned char*)in_compressed_ttf_data); + unsigned char* buf_decompressed = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size); + stb_decompress(buf_decompressed, (unsigned char*)in_compressed_ttf_data, in_compressed_ttf_data_size); + + // Add + ImFont* font = AddFontFromMemoryTTF(buf_decompressed, buf_decompressed_size, size_pixels, glyph_ranges, font_no); + return font; +} + bool ImFontAtlas::Build() { IM_ASSERT(InputData.size() > 0); TexID = NULL; TexWidth = TexHeight = 0; - TexExtraDataPos = TexUvWhitePixel = ImVec2(0, 0); + TexUvWhitePixel = ImVec2(0, 0); ClearTexData(); // Initialize font information early (so we can error without any cleanup) + count glyphs @@ -7422,7 +8259,7 @@ bool ImFontAtlas::Build() IM_ASSERT(data.OutFont && !data.OutFont->IsLoaded()); const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)data.TTFData, data.FontNo); IM_ASSERT(font_offset >= 0); - if (!stbtt_InitFont(&data.FontInfo, (unsigned char*)data.TTFData, font_offset)) + if (!stbtt_InitFont(&data.FontInfo, (unsigned char*)data.TTFData, font_offset)) return false; if (!data.GlyphRanges) @@ -7443,12 +8280,13 @@ bool ImFontAtlas::Build() IM_ASSERT(ret); stbtt_PackSetOversampling(&spc, 1, 1); - // Pack our extra data rectangle first, so it will be on the upper-left corner of our texture (UV will have small values). - stbrp_rect extra_rect; - extra_rect.w = (stbrp_coord)TEX_ATLAS_SIZE.x; - extra_rect.h = (stbrp_coord)TEX_ATLAS_SIZE.y; - stbrp_pack_rects((stbrp_context*)spc.pack_info, &extra_rect, 1); - TexExtraDataPos = ImVec2(extra_rect.x, extra_rect.y); + // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). + ImVector extra_rects; + RenderCustomTexData(0, &extra_rects); + stbrp_pack_rects((stbrp_context*)spc.pack_info, &extra_rects[0], (int)extra_rects.size()); + for (size_t i = 0; i < extra_rects.size(); i++) + if (extra_rects[i].was_packed) + TexHeight = ImMax(TexHeight, extra_rects[i].y + extra_rects[i].h); // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0) int buf_packedchars_n = 0, buf_rects_n = 0, buf_ranges_n = 0; @@ -7456,11 +8294,10 @@ bool ImFontAtlas::Build() stbrp_rect* buf_rects = (stbrp_rect*)ImGui::MemAlloc(total_glyph_count * sizeof(stbrp_rect)); stbtt_pack_range* buf_ranges = (stbtt_pack_range*)ImGui::MemAlloc(total_glyph_range_count * sizeof(stbtt_pack_range)); memset(buf_packedchars, 0, total_glyph_count * sizeof(stbtt_packedchar)); - memset(buf_rects, 0, total_glyph_count * sizeof(stbrp_rect)); // Unnessary but let's clear this for the sake of sanity. + memset(buf_rects, 0, total_glyph_count * sizeof(stbrp_rect)); // Unnecessary but let's clear this for the sake of sanity. memset(buf_ranges, 0, total_glyph_range_count * sizeof(stbtt_pack_range)); - // First pass: pack all glyphs (no rendering at this point, we are working with glyph sizes only) - int tex_height = extra_rect.y + extra_rect.h; + // First font pass: pack all glyphs (no rendering at this point, we are working with glyph sizes only) for (size_t input_i = 0; input_i < InputData.size(); input_i++) { ImFontAtlasData& data = *InputData[input_i]; @@ -7496,14 +8333,14 @@ bool ImFontAtlas::Build() // Extend texture height for (int i = 0; i < n; i++) if (data.Rects[i].was_packed) - tex_height = ImMax(tex_height, data.Rects[i].y + data.Rects[i].h); + TexHeight = ImMax(TexHeight, data.Rects[i].y + data.Rects[i].h); } IM_ASSERT(buf_rects_n == total_glyph_count); IM_ASSERT(buf_packedchars_n == total_glyph_count); IM_ASSERT(buf_ranges_n == total_glyph_range_count); // Create texture - TexHeight = ImUpperPowerOfTwo(tex_height); + TexHeight = ImUpperPowerOfTwo(TexHeight); TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(TexWidth * TexHeight); memset(TexPixelsAlpha8, 0, TexWidth * TexHeight); spc.pixels = TexPixelsAlpha8; @@ -7572,50 +8409,97 @@ bool ImFontAtlas::Build() ClearInputData(); // Render into our custom data block - RenderCustomTexData(); + RenderCustomTexData(1, &extra_rects); return true; } -void ImFontAtlas::RenderCustomTexData() +void ImFontAtlas::RenderCustomTexData(int pass, void* p_rects) { - IM_ASSERT(TexExtraDataPos.x == 0.0f && TexExtraDataPos.y == 0.0f); - - // Draw white pixel into texture and make UV points to it - TexPixelsAlpha8[0] = TexPixelsAlpha8[1] = TexPixelsAlpha8[TexWidth+0] = TexPixelsAlpha8[TexWidth+1] = 0xFF; - TexUvWhitePixel = ImVec2((TexExtraDataPos.x + 0.5f) / TexWidth, (TexExtraDataPos.y + 0.5f) / TexHeight); - - // Draw a mouse cursor into texture - // Because our font uses a single color channel, we have to spread the cursor in 2 layers (black/white) which will be rendered separately. - const char cursor_pixels[] = + // . = white layer, X = black layer, others are blank + const int TEX_DATA_W = 90; + const int TEX_DATA_H = 27; + const char texture_data[TEX_DATA_W*TEX_DATA_H+1] = { - "X " - "XX " - "X.X " - "X..X " - "X...X " - "X....X " - "X.....X " - "X......X " - "X.......X " - "X........X " - "X.........X " - "X..........X" - "X......XXXXX" - "X...X..X " - "X..X X..X " - "X.X X..X " - "XX X..X " - " X..X " - " XX " + "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX" + "..- -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" + "XX - 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..X - X.X - X.X - X.X -XX X.X - X.X XX" + "X...X - X.X - X.X - 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 - X.X - X..X X.X X..X - X.X - X.X " + "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-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...XXXXXX.XXXXXX...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......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X " + "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX " + "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------" + "X.X X..X - -X.......X- X.......X - XX XX - " + "XX 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 - " + "------------ - X - X -X.....................X- " + " ----------------------------------- X...XXXXXXXXXXXXX...X - " + " - X..X X..X - " + " - X.X X.X - " + " - XX XX - " }; - IM_ASSERT(sizeof(cursor_pixels)-1 == (int)TEX_ATLAS_SIZE_MOUSE_CURSOR.x * (int)TEX_ATLAS_SIZE_MOUSE_CURSOR.y); - for (int y = 0, n = 0; y < 19; y++) - for (int x = 0; x < 12; x++, n++) + + ImVector& rects = *(ImVector*)p_rects; + if (pass == 0) + { + stbrp_rect r = { 0 }; + r.w = (TEX_DATA_W*2)+1; + r.h = TEX_DATA_H+1; + rects.push_back(r); + } + else if (pass == 1) + { + // Copy pixels + const stbrp_rect& r = rects[0]; + for (int y = 0, n = 0; y < TEX_DATA_H; y++) + for (int x = 0; x < TEX_DATA_W; x++, n++) + { + const int offset0 = (int)(r.x + x) + (int)(r.y + y) * TexWidth; + const int offset1 = offset0 + 1 + TEX_DATA_W; + TexPixelsAlpha8[offset0] = texture_data[n] == '.' ? 0xFF : 0x00; + TexPixelsAlpha8[offset1] = texture_data[n] == 'X' ? 0xFF : 0x00; + } + const ImVec2 tex_uv_scale(1.0f / TexWidth, 1.0f / TexHeight); + TexUvWhitePixel = ImVec2(r.x + 0.5f, r.y + 0.5f) * tex_uv_scale; + + const ImVec2 cursor_datas[ImGuiMouseCursor_Count_][3] = { - TexPixelsAlpha8[((int)TEX_ATLAS_POS_MOUSE_CURSOR_BLACK.x + x) + ((int)TEX_ATLAS_POS_MOUSE_CURSOR_BLACK.y + y) * TexWidth] = (cursor_pixels[n] == 'X') ? 0xFF : 0x00; - TexPixelsAlpha8[((int)TEX_ATLAS_POS_MOUSE_CURSOR_WHITE.x + x) + ((int)TEX_ATLAS_POS_MOUSE_CURSOR_WHITE.y + y) * TexWidth] = (cursor_pixels[n] == '.') ? 0xFF : 0x00; + // Pos ........ Size ......... Offset ...... + { ImVec2(0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow + { ImVec2(13,0), ImVec2(7,16), ImVec2( 4, 8) }, // ImGuiMouseCursor_TextInput + { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_Move + { ImVec2(21,0), ImVec2( 9,23), ImVec2( 5,11) }, // ImGuiMouseCursor_ResizeNS + { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 5) }, // ImGuiMouseCursor_ResizeEW + { ImVec2(73,0), ImVec2(17,17), ImVec2( 9, 9) }, // ImGuiMouseCursor_ResizeNESW + { ImVec2(55,0), ImVec2(17,17), ImVec2( 9, 9) }, // ImGuiMouseCursor_ResizeNWSE + }; + + for (int type = 0; type < ImGuiMouseCursor_Count_; type++) + { + ImGuiMouseCursorData& cursor_data = GImGui->MouseCursorData[type]; + ImVec2 pos = cursor_datas[type][0] + ImVec2((float)r.x, (float)r.y); + const ImVec2 size = cursor_datas[type][1]; + cursor_data.Type = type; + cursor_data.Size = size; + cursor_data.Offset = cursor_datas[type][2]; + cursor_data.TexUvMin[0] = (pos) * tex_uv_scale; + cursor_data.TexUvMax[0] = (pos + size) * tex_uv_scale; + pos.x += TEX_DATA_W+1; + cursor_data.TexUvMin[1] = (pos) * tex_uv_scale; + cursor_data.TexUvMax[1] = (pos + size) * tex_uv_scale; } + } } //----------------------------------------------------------------------------- @@ -7629,6 +8513,16 @@ ImFont::ImFont() Clear(); } +ImFont::~ImFont() +{ + // Invalidate active font so that the user gets a clear crash instead of a dangling pointer. + // If you want to delete fonts you need to do it between Render() and NewFrame(). + ImGuiState& g = *GImGui; + if (g.Font == this) + g.Font = NULL; + Clear(); +} + void ImFont::Clear() { FontSize = 0.0f; @@ -7670,7 +8564,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese() { // Store the 1946 ideograms code points as successive offsets from the initial unicode codepoint 0x4E00. Each offset has an implicit +1. // This encoding helps us reduce the source code size. - static const short offsets_from_0x4E00[] = + static const short offsets_from_0x4E00[] = { -1,0,1,3,0,0,0,0,1,0,5,1,1,0,7,4,6,10,0,1,9,9,7,1,3,19,1,10,7,1,0,1,0,5,1,0,6,4,2,6,0,0,12,6,8,0,3,5,0,1,0,9,0,0,8,1,1,3,4,5,13,0,0,8,2,17, 4,3,1,1,9,6,0,0,0,2,1,3,2,22,1,9,11,1,13,1,3,12,0,5,9,2,0,6,12,5,3,12,4,1,2,16,1,1,4,6,5,3,0,6,13,15,5,12,8,14,0,0,6,15,3,6,0,18,8,1,6,14,1, @@ -7800,10 +8694,10 @@ static int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const *out_char = c; return 1; } - if ((*str & 0xe0) == 0xc0) + if ((*str & 0xe0) == 0xc0) { *out_char = 0; - if (in_text_end && in_text_end - (const char*)str < 2) return 0; + if (in_text_end && in_text_end - (const char*)str < 2) return 0; if (*str < 0xc2) return 0; c = (unsigned int)((*str++ & 0x1f) << 6); if ((*str & 0xc0) != 0x80) return 0; @@ -7811,7 +8705,7 @@ static int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const *out_char = c; return 2; } - if ((*str & 0xf0) == 0xe0) + if ((*str & 0xf0) == 0xe0) { *out_char = 0; if (in_text_end && in_text_end - (const char*)str < 3) return 0; @@ -7825,7 +8719,7 @@ static int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const *out_char = c; return 3; } - if ((*str & 0xf8) == 0xf0) + if ((*str & 0xf8) == 0xf0) { *out_char = 0; if (in_text_end && in_text_end - (const char*)str < 4) return 0; @@ -7889,13 +8783,13 @@ static int ImTextCharToUtf8(char* buf, size_t buf_size, unsigned int c) { size_t i = 0; size_t n = buf_size; - if (c < 0x80) + if (c < 0x80) { if (i+1 > n) return 0; buf[i++] = (char)c; return 1; - } - else if (c < 0x800) + } + else if (c < 0x800) { if (i+2 > n) return 0; buf[i++] = (char)(0xc0 + (c >> 6)); @@ -7905,8 +8799,8 @@ static int ImTextCharToUtf8(char* buf, size_t buf_size, unsigned int c) else if (c >= 0xdc00 && c < 0xe000) { return 0; - } - else if (c >= 0xd800 && c < 0xdc00) + } + else if (c >= 0xd800 && c < 0xdc00) { if (i+4 > n) return 0; buf[i++] = (char)(0xf0 + (c >> 18)); @@ -8087,6 +8981,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons } // Decode and advance source (handle unlikely UTF-8 decoding failure by skipping to the next byte) + const char* prev_s = s; unsigned int c = (unsigned int)*s; if (c < 0x80) { @@ -8098,7 +8993,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons if (c == 0) break; } - + if (c == '\n') { text_size.x = ImMax(text_size.x, line_width); @@ -8106,10 +9001,13 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons line_width = 0.0f; continue; } - + const float char_width = ((size_t)c < IndexXAdvance.size()) ? IndexXAdvance[(size_t)c] * scale : FallbackXAdvance; if (line_width + char_width >= max_width) + { + s = prev_s; break; + } line_width += char_width; } @@ -8150,10 +9048,13 @@ ImVec2 ImFont::CalcTextSizeW(float size, float max_width, const ImWchar* text_be line_width = 0.0f; continue; } - + const float char_width = ((size_t)c < IndexXAdvance.size()) ? IndexXAdvance[(size_t)c] * scale : FallbackXAdvance; if (line_width + char_width >= max_width) + { + s--; break; + } line_width += char_width; } @@ -8171,7 +9072,7 @@ ImVec2 ImFont::CalcTextSizeW(float size, float max_width, const ImWchar* text_be return text_size; } -void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect_ref, const char* text_begin, const char* text_end, ImDrawVert*& out_vertices, float wrap_width, const ImVec2* cpu_clip_max) const +void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect_ref, const char* text_begin, const char* text_end, ImDrawList* draw_list, float wrap_width, const ImVec2* cpu_clip_max) const { if (!text_end) text_end = text_begin + strlen(text_begin); @@ -8195,6 +9096,8 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re float x = pos.x; float y = pos.y; + ImDrawVert* out_vertices = draw_list->vtx_write; + const char* s = text_begin; while (s < text_end) { @@ -8282,6 +9185,7 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re } } + // NB: we are not calling PrimRectUV() here because non-inlined causes too much overhead in a debug build. out_vertices[0].pos = ImVec2(x1, y1); out_vertices[0].uv = ImVec2(u1, v1); out_vertices[0].col = col; @@ -8309,6 +9213,8 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re x += char_width; } + + draw_list->vtx_write = out_vertices; } //----------------------------------------------------------------------------- @@ -8331,9 +9237,9 @@ static const char* GetClipboardTextFn_DefaultImpl() ImGui::MemFree(buf_local); buf_local = NULL; } - if (!OpenClipboard(NULL)) + if (!OpenClipboard(NULL)) return NULL; - HANDLE wbuf_handle = GetClipboardData(CF_UNICODETEXT); + HANDLE wbuf_handle = GetClipboardData(CF_UNICODETEXT); if (wbuf_handle == NULL) return NULL; if (ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle)) @@ -8342,8 +9248,8 @@ static const char* GetClipboardTextFn_DefaultImpl() buf_local = (char*)ImGui::MemAlloc(buf_len * sizeof(char)); ImTextStrToUtf8(buf_local, buf_len, wbuf_global, NULL); } - GlobalUnlock(wbuf_handle); - CloseClipboard(); + GlobalUnlock(wbuf_handle); + CloseClipboard(); return buf_local; } @@ -8354,12 +9260,12 @@ static void SetClipboardTextFn_DefaultImpl(const char* text) return; const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1; - HGLOBAL wbuf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar)); + HGLOBAL wbuf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar)); if (wbuf_handle == NULL) return; - ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle); + ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle); ImTextStrFromUtf8(wbuf_global, wbuf_length, text, NULL); - GlobalUnlock(wbuf_handle); + GlobalUnlock(wbuf_handle); EmptyClipboard(); SetClipboardData(CF_UNICODETEXT, wbuf_handle); CloseClipboard(); @@ -8415,12 +9321,21 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y) #else -static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y) +static void ImeSetInputScreenPosFn_DefaultImpl(int, int) { } #endif +#ifdef IMGUI_DISABLE_TEST_WINDOWS + +void ImGui::ShowUserGuide() {} +void ImGui::ShowStyleEditor(ImGuiStyle*) {} +void ImGui::ShowTestWindow(bool*) {} +void ImGui::ShowMetricsWindow(bool*) {} + +#else + //----------------------------------------------------------------------------- // HELP //----------------------------------------------------------------------------- @@ -8478,7 +9393,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); - ImGui::SliderFloat("TreeNodeSpacing", &style.TreeNodeSpacing, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat("ScrollBarWidth", &style.ScrollbarWidth, 1.0f, 20.0f, "%.0f"); ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); ImGui::TreePop(); @@ -8558,12 +9473,15 @@ static void ShowExampleAppCustomRendering(bool* opened); void ImGui::ShowTestWindow(bool* opened) { // Examples apps + static bool show_app_metrics = false; static bool show_app_console = false; static bool show_app_long_text = false; static bool show_app_auto_resize = false; static bool show_app_fixed_overlay = false; static bool show_app_custom_rendering = false; static bool show_app_manipulating_window_title = false; + if (show_app_metrics) + ImGui::ShowMetricsWindow(&show_app_metrics); if (show_app_console) ShowExampleAppConsole(&show_app_console); if (show_app_long_text) @@ -8599,13 +9517,14 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::End(); return; } - - ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f); // 2/3 of the space for widget and 1/3 for labels - //ImGui::PushItemWidth(-140); // Right align, keep 140 pixels for labels + + //ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f); // 2/3 of the space for widget and 1/3 for labels + ImGui::PushItemWidth(-140); // Right align, keep 140 pixels for labels ImGui::Text("ImGui says hello."); //ImGui::Text("MousePos (%g, %g)", ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y); //ImGui::Text("MouseWheel %d", ImGui::GetIO().MouseWheel); + //ImGui::Text("KeyMods %s%s%s", ImGui::GetIO().KeyCtrl ? "CTRL" : "", ImGui::GetIO().KeyShift ? "SHIFT" : "", ImGui::GetIO().KeyAlt? "ALT" : ""); //ImGui::Text("WantCaptureMouse: %d", ImGui::GetIO().WantCaptureMouse); //ImGui::Text("WantCaptureKeyboard: %d", ImGui::GetIO().WantCaptureKeyboard); @@ -8620,7 +9539,7 @@ void ImGui::ShowTestWindow(bool* opened) { ImGui::Checkbox("no titlebar", &no_titlebar); ImGui::SameLine(150); ImGui::Checkbox("no border", &no_border); ImGui::SameLine(300); - ImGui::Checkbox("no resize", &no_resize); + ImGui::Checkbox("no resize", &no_resize); ImGui::Checkbox("no move", &no_move); ImGui::SameLine(150); ImGui::Checkbox("no scrollbar", &no_scrollbar); ImGui::SameLine(300); ImGui::Checkbox("no collapse", &no_collapse); @@ -8671,7 +9590,7 @@ void ImGui::ShowTestWindow(bool* opened) if (ImGui::Button("Button")) { printf("Clicked\n"); a ^= 1; } if (a) { - ImGui::SameLine(); + ImGui::SameLine(); ImGui::Text("Thanks for clicking me!"); } @@ -8722,14 +9641,14 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::GetWindowDrawList()->AddRectFilled(ImGui::GetCursorScreenPos() + ImVec2(wrap_width, 0.0f), ImGui::GetCursorScreenPos() + ImVec2(wrap_width+10, ImGui::GetTextLineHeight()), 0xFFFF00FF); ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); ImGui::Text("lazy dog. This paragraph is made to fit within %.0f pixels. The quick brown fox jumps over the lazy dog.", wrap_width); - ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemBoxMin(), ImGui::GetItemBoxMax(), 0xFF00FFFF); + ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), 0xFF00FFFF); ImGui::PopTextWrapPos(); ImGui::Text("Test paragraph 2:"); ImGui::GetWindowDrawList()->AddRectFilled(ImGui::GetCursorScreenPos() + ImVec2(wrap_width, 0.0f), ImGui::GetCursorScreenPos() + ImVec2(wrap_width+10, ImGui::GetTextLineHeight()), 0xFFFF00FF); ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); ImGui::Text("aaaaaaaa bbbbbbbb, cccccccc,dddddddd. eeeeeeee ffffffff. gggggggg!hhhhhhhh"); - ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemBoxMin(), ImGui::GetItemBoxMax(), 0xFF00FFFF); + ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), 0xFF00FFFF); ImGui::PopTextWrapPos(); ImGui::TreePop(); @@ -8805,7 +9724,7 @@ void ImGui::ShowTestWindow(bool* opened) static bool selected[3] = { false, true, false }; ImGui::Selectable("1. I am selectable", &selected[0]); ImGui::Selectable("2. I am selectable", &selected[1]); - ImGui::Text("3. I am normal text"); + ImGui::Text("3. I am not selectable"); ImGui::Selectable("4. I am selectable", &selected[2]); ImGui::TreePop(); } @@ -8839,6 +9758,33 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::TreePop(); } + if (ImGui::TreeNode("Popup")) + { + static bool popup_open = false; + static int selected_fish = -1; + const char* fishes[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" }; + if (ImGui::Button("Select..")) + popup_open = true; + ImGui::SameLine(); + ImGui::Text(selected_fish == -1 ? "" : fishes[selected_fish]); + if (popup_open) + { + ImGui::BeginPopup(&popup_open); + ImGui::Text("Aquarium"); + ImGui::Separator(); + for (int i = 0; i < IM_ARRAYSIZE(fishes); i++) + { + if (ImGui::Selectable(fishes[i], false)) + { + selected_fish = i; + popup_open = false; + } + } + ImGui::EndPopup(); + } + ImGui::TreePop(); + } + if (ImGui::TreeNode("Filtered Text Input")) { static char buf1[64] = ""; ImGui::InputText("default", buf1, 64); @@ -8898,6 +9844,8 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::Separator(); + ImGui::LabelText("label", "Value"); + static int item = 1; ImGui::Combo("combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); @@ -8905,43 +9853,45 @@ void ImGui::ShowTestWindow(bool* opened) static int item2 = -1; ImGui::Combo("combo scroll", &item2, items, IM_ARRAYSIZE(items)); - static char str0[128] = "Hello, world!"; - static int i0=123; - static float f0=0.001f; - ImGui::InputText("string", str0, IM_ARRAYSIZE(str0)); - ImGui::InputInt("input int", &i0); - ImGui::InputFloat("input float", &f0, 0.01f, 1.0f); + { + static char str0[128] = "Hello, world!"; + static int i0=123; + static float f0=0.001f; + ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0)); + ImGui::InputInt("input int", &i0); + ImGui::InputFloat("input float", &f0, 0.01f, 1.0f); - static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; - //ImGui::InputFloat2("input float2", vec4a); - ImGui::InputFloat3("input float3", vec4a); - //ImGui::InputFloat4("input float4", vec4a); + static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; + ImGui::InputFloat3("input float3", vec4a); + } - static int i1=0; - static int i2=42; - ImGui::SliderInt("int 0..3", &i1, 0, 3); - ImGui::SliderInt("int -100..100", &i2, -100, 100); + /* + { + static int i1=50; + static int i2=42; + ImGui::DragInt("drag int", &i1, 1); + ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100); - static float f1=1.123f; - static float f2=0; - static float f3=0; - static float f4=123456789.0f; - ImGui::SliderFloat("float", &f1, 0.0f, 2.0f); - ImGui::SliderFloat("log float", &f2, 0.0f, 10.0f, "%.4f", 2.0f); - ImGui::SliderFloat("signed log float", &f3, -10.0f, 10.0f, "%.4f", 3.0f); - ImGui::SliderFloat("unbound float", &f4, -FLT_MAX, FLT_MAX, "%.4f"); - static float angle = 0.0f; - ImGui::SliderAngle("angle", &angle); + static float f1=1.00f; + static float f2=0.0067f; + ImGui::DragFloat("drag float", &f1, 1.0f); + ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f"); + } + */ - static float vec4b[4] = { 0.10f, 0.20f, 0.30f, 0.40f }; - //ImGui::SliderFloat2("slider float2", vec4b, 0.0f, 1.0f); - ImGui::SliderFloat3("slider float3", vec4b, 0.0f, 1.0f); - //ImGui::SliderFloat4("slider float4", vec4b, 0.0f, 1.0f); + { + static int i1=0; + static int i2=42; + ImGui::SliderInt("slider int 0..3", &i1, 0, 3); + ImGui::SliderInt("slider int -100..100", &i2, -100, 100); - //static int vec4i[4] = { 1, 5, 100, 255 }; - //ImGui::SliderInt2("slider int2", vec4i, 0, 255); - //ImGui::SliderInt3("slider int3", vec4i, 0, 255); - //ImGui::SliderInt4("slider int4", vec4i, 0, 255); + static float f1=1.123f; + static float f2=0; + ImGui::SliderFloat("slider float", &f1, 0.0f, 2.0f); + ImGui::SliderFloat("slider log float", &f2, -10.0f, 10.0f, "%.4f", 3.0f); + static float angle = 0.0f; + ImGui::SliderAngle("slider angle", &angle); + } static float col1[3] = { 1.0f,0.0f,0.2f }; static float col2[4] = { 0.4f,0.7f,0.0f,0.5f }; @@ -8956,6 +9906,120 @@ void ImGui::ShowTestWindow(bool* opened) //ImGui::PushItemWidth(-1); //ImGui::ListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4); //ImGui::PopItemWidth(); + + if (ImGui::TreeNode("Multi-component Widgets")) + { + ImGui::Unindent(); + + static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; + static int vec4i[4] = { 1, 5, 100, 255 }; + + ImGui::InputFloat2("input float2", vec4f); + ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); + ImGui::InputInt2("input int2", vec4i); + ImGui::SliderInt2("slider int2", vec4i, 0, 255); + + ImGui::InputFloat3("input float3", vec4f); + ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); + ImGui::InputInt3("input int3", vec4i); + ImGui::SliderInt3("slider int3", vec4i, 0, 255); + + ImGui::InputFloat4("input float4", vec4f); + ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); + ImGui::InputInt4("input int4", vec4i); + ImGui::SliderInt4("slider int4", vec4i, 0, 255); + + ImGui::Indent(); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Vertical Sliders")) + { + ImGui::Unindent(); + const float spacing = 4; + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)); + + static int int_value = 0; + 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 }; + ImGui::PushID("set1"); + for (int i = 0; i < 7; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::PushID(i); + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImColor::HSV(i/7.0f, 0.5f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImColor::HSV(i/7.0f, 0.6f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImColor::HSV(i/7.0f, 0.7f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImColor::HSV(i/7.0f, 0.9f, 0.9f)); + ImGui::VSliderFloat("##v", ImVec2(18,160), &values[i], 0.0f, 1.0f, ""); + if (ImGui::IsItemActive() || ImGui::IsItemHovered()) + ImGui::SetTooltip("%.3f", values[i]); + ImGui::PopStyleColor(4); + ImGui::PopID(); + } + ImGui::PopID(); + + ImGui::SameLine(); + ImGui::PushID("set2"); + static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f }; + const int rows = 3; + const ImVec2 small_slider_size(18, (160.0f-(rows-1)*spacing)/rows); + for (int nx = 0; nx < 4; nx++) + { + if (nx > 0) ImGui::SameLine(); + ImGui::BeginGroup(); + for (int ny = 0; ny < rows; ny++) + { + ImGui::PushID(nx*rows+ny); + ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, ""); + if (ImGui::IsItemActive() || ImGui::IsItemHovered()) + ImGui::SetTooltip("%.3f", values2[nx]); + ImGui::PopID(); + } + ImGui::EndGroup(); + } + ImGui::PopID(); + + ImGui::SameLine(); + ImGui::PushID("set3"); + for (int i = 0; i < 4; i++) + { + 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"); + ImGui::PopStyleVar(); + ImGui::PopID(); + } + ImGui::PopID(); + + ImGui::Indent(); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Dragging")) + { + // You can use ImGui::GetItemActiveDragDelta() to query for the dragged amount on any widget. + static ImVec2 value_raw(0.0f, 0.0f); + static ImVec2 value_with_lock_threshold(0.0f, 0.0f); + ImGui::Button("Drag Me"); + if (ImGui::IsItemActive()) + { + value_raw = ImGui::GetMouseDragDelta(0, 0.0f); + value_with_lock_threshold = ImGui::GetMouseDragDelta(0); + //ImGui::SetTooltip("Delta: %.1f, %.1f", value.x, value.y); + + // Draw a line between the button and the mouse cursor + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + draw_list->PushClipRectFullScreen(); + draw_list->AddLine(ImGui::CalcItemRectClosestPoint(ImGui::GetIO().MousePos, true, -2.0f), ImGui::GetIO().MousePos, ImColor(ImGui::GetStyle().Colors[ImGuiCol_Button]), 4.0f); + draw_list->PopClipRect(); + } + ImGui::SameLine(); ImGui::Text("Raw (%.1f, %.1f), WithLockThresold (%.1f, %.1f)", value_raw.x, value_raw.y, value_with_lock_threshold.x, value_with_lock_threshold.y); + ImGui::TreePop(); + } } if (ImGui::CollapsingHeader("Graphs widgets")) @@ -8964,84 +10028,198 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); static bool pause; - static ImVector values; if (values.empty()) { values.resize(100); memset(&values.front(), 0, values.size()*sizeof(float)); } - static size_t values_offset = 0; - if (!pause) - { + static ImVector values; if (values.empty()) { values.resize(90); memset(&values.front(), 0, values.size()*sizeof(float)); } + static size_t values_offset = 0; + if (!pause) + { // create dummy data at fixed 60 hz rate static float refresh_time = -1.0f; if (ImGui::GetTime() > refresh_time + 1.0f/60.0f) { refresh_time = ImGui::GetTime(); static float phase = 0.0f; - values[values_offset] = cosf(phase); - values_offset = (values_offset+1)%values.size(); - phase += 0.10f*values_offset; + values[values_offset] = cosf(phase); + values_offset = (values_offset+1)%values.size(); + phase += 0.10f*values_offset; } } - ImGui::PlotLines("Frame Times", &values.front(), (int)values.size(), (int)values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0,70)); - - ImGui::SameLine(); ImGui::Checkbox("pause", &pause); - ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0,70)); + ImGui::PlotLines("##Graph", &values.front(), (int)values.size(), (int)values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0,80)); + ImGui::SameLine(0, (int)ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::BeginGroup(); + ImGui::Text("Graph"); + ImGui::Checkbox("pause", &pause); + ImGui::EndGroup(); + ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0,80)); } - if (ImGui::CollapsingHeader("Horizontal Layout")) + if (ImGui::CollapsingHeader("Layout")) { - // Text - ImGui::Text("Hello"); - ImGui::SameLine(); - ImGui::Text("World"); - - // Button - if (ImGui::Button("Banana")) printf("Pressed!\n"); - 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("can fit within a text block."); - - // Checkbox - 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("Rich", &c4); - - // Various - static float f0=1.0f, f1=2.0f, f2=3.0f; - ImGui::PushItemWidth(80); - 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::SliderFloat("Z", &f2, 0.0f,5.0f); - ImGui::PopItemWidth(); - - ImGui::PushItemWidth(80); - ImGui::Text("Lists:"); - static int selection[4] = { 0, 1, 2, 3 }; - for (int i = 0; i < 4; i++) + if (ImGui::TreeNode("Widgets Alignment")) { - if (i > 0) ImGui::SameLine(); - ImGui::PushID(i); - ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items)); - ImGui::PopID(); - //if (ImGui::IsItemHovered()) ImGui::SetTooltip("ListBox %d hovered", i); + static float f = 0.0f; + ImGui::Text("Fixed: 100 pixels"); + ImGui::PushItemWidth(100); + ImGui::InputFloat("float##1", &f); + ImGui::PopItemWidth(); + + ImGui::Text("Proportional: 50%% of window width"); + ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f); + ImGui::InputFloat("float##2", &f); + ImGui::PopItemWidth(); + + ImGui::Text("Right-aligned: Leave 100 pixels for label"); + ImGui::PushItemWidth(-100); + ImGui::InputFloat("float##3", &f); + ImGui::PopItemWidth(); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Basic Horizontal Layout")) + { + ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceeding item)"); + + // Text + ImGui::Text("Two items: Hello"); + ImGui::SameLine(); + ImGui::TextColored(ImVec4(1,1,0,1), "World"); + + // Adjust spacing + ImGui::Text("More spacing: Hello"); + ImGui::SameLine(0, 20); + ImGui::TextColored(ImVec4(1,1,0,1), "World"); + + // Button + ImGui::AlignFirstTextHeightToWidgets(); + 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("can fit within a text block."); + + // Aligned to arbitrary position. Easy/cheap column. + ImGui::Text("Aligned"); + 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"); + + // Checkbox + 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("Rich", &c4); + + // Various + static float f0=1.0f, f1=2.0f, f2=3.0f; + ImGui::PushItemWidth(80); + 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::SliderFloat("Z", &f2, 0.0f,5.0f); + ImGui::PopItemWidth(); + + ImGui::PushItemWidth(80); + ImGui::Text("Lists:"); + static int selection[4] = { 0, 1, 2, 3 }; + for (int i = 0; i < 4; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::PushID(i); + ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items)); + ImGui::PopID(); + //if (ImGui::IsItemHovered()) ImGui::SetTooltip("ListBox %d hovered", i); + } + ImGui::PopItemWidth(); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Groups")) + { + ImGui::TextWrapped("(Using ImGui::BeginGroup()/EndGroup() to layout items)"); + + ImVec2 size; + ImGui::BeginGroup(); + { + ImGui::BeginGroup(); + ImGui::Button("AAA"); + ImGui::SameLine(); + ImGui::Button("BBB"); + ImGui::SameLine(); + ImGui::BeginGroup(); + ImGui::Button("CCC"); + ImGui::Button("DDD"); + ImGui::EndGroup(); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Group hovered"); + ImGui::SameLine(); + ImGui::Button("EEE"); + ImGui::EndGroup(); + + // Capture the group size and create widgets using the same size + size = ImGui::GetItemRectSize(); + 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)); + ImGui::SameLine(); + ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f,size.y)); + ImGui::EndGroup(); + ImGui::SameLine(); + + ImGui::Button("LEVERAGE\nBUZZWORD", size); + ImGui::SameLine(); + + ImGui::ListBoxHeader("List", size); + ImGui::Selectable("Selected", true); + ImGui::Selectable("Not Selected", false); + ImGui::ListBoxFooter(); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Text Baseline Alignment")) + { + ImGui::TextWrapped("(This is testing the vertical alignment that occurs on text to keep it at the same baseline as widgets. Lines only composed of text or \"small\" widgets fit in less vertical spaces than lines with normal widgets)"); + + 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("One\nTwo\nThree"); + + ImGui::Button("HOP"); ImGui::SameLine(); + ImGui::Text("Banana"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("Banana"); + + ImGui::Button("HOP"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("Banana"); + + ImGui::Button("TEST"); ImGui::SameLine(); + ImGui::Text("TEST"); ImGui::SameLine(); + ImGui::SmallButton("TEST"); + + ImGui::AlignFirstTextHeightToWidgets(); // If your line starts with text, call this to align it to upcoming widgets. + ImGui::Text("Text aligned to Widget"); ImGui::SameLine(); + ImGui::Button("Widget"); ImGui::SameLine(); + ImGui::Text("Widget"); ImGui::SameLine(); + ImGui::SmallButton("Widget"); + + ImGui::TreePop(); } - ImGui::PopItemWidth(); } if (ImGui::CollapsingHeader("Child regions")) @@ -9049,7 +10227,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::Text("Without border"); static int line = 50; bool goto_line = ImGui::Button("Goto"); - ImGui::SameLine(); + ImGui::SameLine(); ImGui::PushItemWidth(100); goto_line |= ImGui::InputInt("##Line", &line, 0, 0, ImGuiInputTextFlags_EnterReturnsTrue); ImGui::PopItemWidth(); @@ -9087,6 +10265,7 @@ void ImGui::ShowTestWindow(bool* opened) // Basic columns ImGui::Text("Basic:"); ImGui::Columns(4, "mycolumns"); + ImGui::Separator(); ImGui::Text("ID"); ImGui::NextColumn(); ImGui::Text("Name"); ImGui::NextColumn(); ImGui::Text("Path"); ImGui::NextColumn(); @@ -9098,7 +10277,7 @@ void ImGui::ShowTestWindow(bool* opened) { ImGui::Text("%04d", i); ImGui::NextColumn(); ImGui::Text(names[i]); ImGui::NextColumn(); - ImGui::Text(paths[i]); ImGui::NextColumn(); + ImGui::Text(paths[i]); ImGui::NextColumn(); ImGui::Text("...."); ImGui::NextColumn(); } ImGui::Columns(1); @@ -9107,7 +10286,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::Spacing(); // Scrolling columns - /* + /* ImGui::Text("Scrolling:"); ImGui::BeginChild("##header", ImVec2(0, ImGui::GetTextLineHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y)); ImGui::Columns(3); @@ -9130,7 +10309,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::Separator(); ImGui::Spacing(); - */ + */ // Create multiple items in a same cell before switching to next column ImGui::Text("Mixed items:"); @@ -9138,24 +10317,24 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::Separator(); static int e = 0; - ImGui::Text("Hello"); + ImGui::Text("Hello"); ImGui::Button("Banana"); - ImGui::RadioButton("radio a", &e, 0); + ImGui::RadioButton("radio a", &e, 0); ImGui::NextColumn(); - ImGui::Text("ImGui"); + ImGui::Text("ImGui"); ImGui::Button("Apple"); ImGui::RadioButton("radio b", &e, 1); static float foo = 1.0f; - ImGui::InputFloat("red", &foo, 0.05f, 0, 3); + ImGui::InputFloat("red", &foo, 0.05f, 0, 3); ImGui::Text("An extra line here."); ImGui::NextColumn(); - + ImGui::Text("World!"); ImGui::Button("Corniflower"); ImGui::RadioButton("radio c", &e, 2); static float bar = 1.0f; - ImGui::InputFloat("blue", &bar, 0.05f, 0, 3); + ImGui::InputFloat("blue", &bar, 0.05f, 0, 3); ImGui::NextColumn(); if (ImGui::CollapsingHeader("Category A")) ImGui::Text("Blah blah blah"); ImGui::NextColumn(); @@ -9234,7 +10413,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::BulletText("%s", lines[i]); } - if (ImGui::CollapsingHeader("Keyboard & Focus")) + if (ImGui::CollapsingHeader("Keyboard, Mouse & Focus")) { if (ImGui::TreeNode("Tabbing")) { @@ -9258,11 +10437,11 @@ void ImGui::ShowTestWindow(bool* opened) 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(); ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); if (ImGui::IsItemActive()) has_focus = 1; - + if (focus_2) ImGui::SetKeyboardFocusHere(); ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); if (ImGui::IsItemActive()) has_focus = 2; @@ -9274,15 +10453,32 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::PopAllowKeyboardFocus(); if (has_focus) ImGui::Text("Item with focus: %d", has_focus); - else + else ImGui::Text("Item with focus: "); ImGui::TextWrapped("Cursor & selection are preserved when refocusing last used item in code."); ImGui::TreePop(); } + + if (ImGui::TreeNode("Mouse cursors")) + { + ImGui::TextWrapped("(Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. You can also set io.MouseDrawCursor to ask ImGui to render the cursor for you in software)"); + ImGui::Checkbox("io.MouseDrawCursor", &ImGui::GetIO().MouseDrawCursor); + ImGui::Text("Hover to see mouse cursors:"); + for (int i = 0; i < ImGuiMouseCursor_Count_; i++) + { + char label[32]; + sprintf(label, "Mouse cursor %d", i); + ImGui::Bullet(); ImGui::Selectable(label, false); + if (ImGui::IsItemHovered()) + ImGui::SetMouseCursor(i); + } + ImGui::TreePop(); + } } if (ImGui::CollapsingHeader("App Examples")) { + ImGui::Checkbox("Metrics", &show_app_metrics); ImGui::Checkbox("Console", &show_app_console); ImGui::Checkbox("Long text display", &show_app_long_text); ImGui::Checkbox("Auto-resizing window", &show_app_auto_resize); @@ -9294,9 +10490,72 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::End(); } +void ImGui::ShowMetricsWindow(bool* opened) +{ + if (ImGui::Begin("ImGui Metrics", opened)) + { + ImGui::Text("ImGui %s", ImGui::GetVersion()); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::Text("%d vertices", ImGui::GetIO().MetricsRenderVertices); + ImGui::Separator(); + + struct Funcs + { + static void NodeDrawList(ImDrawList* draw_list, const char* label) + { + bool opened = ImGui::TreeNode(draw_list, "%s: %d vtx, %d cmds", label, draw_list->vtx_buffer.size(), draw_list->commands.size()); + if (draw_list == ImGui::GetWindowDrawList()) + { + ImGui::SameLine(); + ImGui::TextColored(ImColor(255,100,100), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered) + } + if (!opened) + return; + for (const ImDrawCmd* pcmd = draw_list->commands.begin(); pcmd < draw_list->commands.end(); pcmd++) + if (pcmd->user_callback) + ImGui::BulletText("Callback %p, user_data %p", pcmd->user_callback, pcmd->user_callback_data); + else + ImGui::BulletText("Draw %d vtx, tex = %p", pcmd->vtx_count, pcmd->texture_id); + ImGui::TreePop(); + } + + static void NodeWindows(ImVector& windows, const char* label) + { + if (!ImGui::TreeNode(label, "%s (%d)", label, (int)windows.size())) + return; + for (int i = 0; i < (int)windows.size(); i++) + Funcs::NodeWindow(windows[i], "Window"); + ImGui::TreePop(); + } + + static void NodeWindow(ImGuiWindow* window, const char* label) + { + if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Visible, window)) + return; + NodeDrawList(window->DrawList, "DrawList"); + if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow"); + if (window->DC.ChildWindows.size() > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows"); + ImGui::TreePop(); + } + }; + + ImGuiState& g = *GImGui; // Access private state + g.DisableHideTextAfterDoubleHash++; // Not exposed (yet). Disable processing that hides text after '##' markers. + Funcs::NodeWindows(g.Windows, "Windows"); + if (ImGui::TreeNode("DrawList", "Active DrawLists (%d)", (int)g.RenderDrawLists[0].size())) + { + for (int i = 0; i < (int)g.RenderDrawLists[0].size(); i++) + Funcs::NodeDrawList(g.RenderDrawLists[0][i], "DrawList"); + ImGui::TreePop(); + } + g.DisableHideTextAfterDoubleHash--; + } + ImGui::End(); +} + static void ShowExampleAppAutoResize(bool* opened) { - if (!ImGui::Begin("Example: Auto-Resizing Window", opened, ImVec2(0,0), -1.0f, ImGuiWindowFlags_AlwaysAutoResize)) + if (!ImGui::Begin("Example: Auto-Resizing Window", opened, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::End(); return; @@ -9313,22 +10572,24 @@ static void ShowExampleAppAutoResize(bool* opened) static void ShowExampleAppFixedOverlay(bool* opened) { + ImGui::SetNextWindowPos(ImVec2(10,10)); if (!ImGui::Begin("Example: Fixed Overlay", opened, ImVec2(0,0), 0.3f, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings)) { ImGui::End(); return; } - ImGui::SetWindowPos(ImVec2(10,10)); ImGui::Text("Simple overlay\non the top-left side of the screen."); ImGui::Separator(); - ImGui::Text("Mouse Position: (%.1f,%.1f)", ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y); + ImGui::Text("Mouse Position: (%.1f,%.1f)", ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y); ImGui::End(); } -static void ShowExampleAppManipulatingWindowTitle(bool* /*opened*/) +static void ShowExampleAppManipulatingWindowTitle(bool* opened) { + (void)opened; + // By default, Windows are uniquely identified by their title. // You can use the "##" and "###" markers to manipulate the display/ID. Read FAQ at the top of this file! @@ -9343,9 +10604,9 @@ static void ShowExampleAppManipulatingWindowTitle(bool* /*opened*/) ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique."); ImGui::End(); - // Using "###" to display a changing title but keep a static identifier "MyWindow" + // Using "###" to display a changing title but keep a static identifier "AnimatedTitle" char buf[128]; - ImFormatString(buf, IM_ARRAYSIZE(buf), "Animated title %c %d###MyWindow", "|/-\\"[(int)(ImGui::GetTime()/0.25f)&3], rand()); + ImFormatString(buf, IM_ARRAYSIZE(buf), "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime()/0.25f)&3], rand()); ImGui::SetNextWindowPos(ImVec2(100,300), ImGuiSetCond_FirstUseEver); ImGui::Begin(buf); ImGui::Text("This window has a changing title."); @@ -9435,14 +10696,14 @@ struct ExampleAppConsole ~ExampleAppConsole() { ClearLog(); - for (size_t i = 0; i < Items.size(); i++) - ImGui::MemFree(History[i]); + for (size_t i = 0; i < Items.size(); i++) + ImGui::MemFree(History[i]); } void ClearLog() { - for (size_t i = 0; i < Items.size(); i++) - ImGui::MemFree(Items[i]); + for (size_t i = 0; i < Items.size(); i++) + ImGui::MemFree(Items[i]); Items.clear(); ScrollToBottom = true; } @@ -9460,7 +10721,8 @@ struct ExampleAppConsole void Run(const char* title, bool* opened) { - if (!ImGui::Begin(title, opened, ImVec2(520,600))) + ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiSetCond_FirstUseEver); + if (!ImGui::Begin(title, opened)) { ImGui::End(); return; @@ -9472,8 +10734,8 @@ struct ExampleAppConsole // TODO: display from bottom // TODO: clip manually - if (ImGui::SmallButton("Add Dummy Text")) { AddLog("%d some text", Items.size()); AddLog("some more text"); AddLog("display very important message here!"); } ImGui::SameLine(); - if (ImGui::SmallButton("Add Dummy Error")) AddLog("[error] something went wrong"); ImGui::SameLine(); + if (ImGui::SmallButton("Add Dummy Text")) { AddLog("%d some text", Items.size()); AddLog("some more text"); AddLog("display very important message here!"); } ImGui::SameLine(); + if (ImGui::SmallButton("Add Dummy Error")) AddLog("[error] something went wrong"); ImGui::SameLine(); if (ImGui::SmallButton("Clear")) ClearLog(); //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); } @@ -9482,7 +10744,7 @@ struct ExampleAppConsole ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0)); static ImGuiTextFilter filter; filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180); - if (ImGui::IsItemHovered()) ImGui::SetKeyboardFocusHere(-1); // Auto focus on hover + //if (ImGui::IsItemHovered()) ImGui::SetKeyboardFocusHere(-1); // Auto focus on hover ImGui::PopStyleVar(); ImGui::Separator(); @@ -9520,7 +10782,9 @@ struct ExampleAppConsole strcpy(InputBuf, ""); } - if (ImGui::IsItemHovered()) ImGui::SetKeyboardFocusHere(-1); // Auto focus on hover + // Demonstrate keeping auto focus on the input box + if (ImGui::IsItemHovered() || (ImGui::IsRootWindowOrAnyChildFocused() && !ImGui::IsAnyItemActive() && !ImGui::IsMouseClicked(0))) + ImGui::SetKeyboardFocusHere(-1); // Auto focus ImGui::End(); } @@ -9677,7 +10941,8 @@ static void ShowExampleAppConsole(bool* opened) static void ShowExampleAppLongText(bool* opened) { - if (!ImGui::Begin("Example: Long text display", opened, ImVec2(520,600))) + ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiSetCond_FirstUseEver); + if (!ImGui::Begin("Example: Long text display", opened)) { ImGui::End(); return; @@ -9687,7 +10952,7 @@ static void ShowExampleAppLongText(bool* opened) static ImGuiTextBuffer log; static int lines = 0; ImGui::Text("Printing unusually long amount of text."); - ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped manually\0Multiple calls to Text(), not clipped"); + ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped manually\0Multiple calls to Text(), not clipped"); ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size()); if (ImGui::Button("Clear")) { log.clear(); lines = 0; } ImGui::SameLine(); @@ -9728,20 +10993,14 @@ static void ShowExampleAppLongText(bool* opened) } // End of Sample code +#endif //----------------------------------------------------------------------------- // FONT DATA //----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// ProggyClean.ttf -// Copyright (c) 2004, 2005 Tristan Grimmer -// MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip) -// Download and more information at http://upperbounds.net -//----------------------------------------------------------------------------- // Compressed with stb_compress() then converted to a C array. -// Decompressor from stb.h (public domain) by Sean Barrett -// https://github.com/nothings/stb/blob/master/stb.h +// Use the program in extra_fonts/binary_to_compressed_c.cpp to create the array from a TTF file. +// Decompressor from stb.h (public domain) by Sean Barrett https://github.com/nothings/stb/blob/master/stb.h //----------------------------------------------------------------------------- static unsigned int stb_decompress_length(unsigned char *input) @@ -9750,12 +11009,11 @@ static unsigned int stb_decompress_length(unsigned char *input) } static unsigned char *stb__barrier, *stb__barrier2, *stb__barrier3, *stb__barrier4; - static unsigned char *stb__dout; static void stb__match(unsigned char *data, unsigned int length) { // INVERSE of memmove... write each byte before copying the next... - assert (stb__dout + length <= stb__barrier); + IM_ASSERT (stb__dout + length <= stb__barrier); if (stb__dout + length > stb__barrier) { stb__dout += length; return; } if (data < stb__barrier4) { stb__dout = stb__barrier+1; return; } while (length--) *stb__dout++ = *data++; @@ -9763,7 +11021,7 @@ static void stb__match(unsigned char *data, unsigned int length) static void stb__lit(unsigned char *data, unsigned int length) { - assert (stb__dout + length <= stb__barrier); + IM_ASSERT (stb__dout + length <= stb__barrier); if (stb__dout + length > stb__barrier) { stb__dout += length; return; } if (data < stb__barrier2) { stb__dout = stb__barrier+1; return; } memcpy(stb__dout, data, length); @@ -9840,225 +11098,231 @@ static unsigned int stb_decompress(unsigned char *output, unsigned char *i, unsi i = stb_decompress_token(i); if (i == old_i) { if (*i == 0x05 && i[1] == 0xfa) { - assert(stb__dout == output + olen); + IM_ASSERT(stb__dout == output + olen); if (stb__dout != output + olen) return 0; if (stb_adler32(1, output, olen) != (unsigned int) stb__in4(2)) return 0; return olen; } else { - assert(0); /* NOTREACHED */ + IM_ASSERT(0); /* NOTREACHED */ return 0; } } - assert(stb__dout <= output + olen); + IM_ASSERT(stb__dout <= output + olen); if (stb__dout > output + olen) return 0; } } +//----------------------------------------------------------------------------- +// ProggyClean.ttf +// Copyright (c) 2004, 2005 Tristan Grimmer +// MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip) +// Download and more information at http://upperbounds.net +//----------------------------------------------------------------------------- static const unsigned int proggy_clean_ttf_compressed_size = 9583; static const unsigned int proggy_clean_ttf_compressed_data[9584/4] = { - 0x0000bc57, 0x00000000, 0xf8a00000, 0x00000400, 0x00010037, 0x000c0000, 0x00030080, 0x2f534f40, 0x74eb8832, 0x01000090, 0x2c158248, 0x616d634e, - 0x23120270, 0x03000075, 0x241382a0, 0x74766352, 0x82178220, 0xfc042102, 0x02380482, 0x66796c67, 0x5689af12, 0x04070000, 0x80920000, 0x64616568, - 0xd36691d7, 0xcc201b82, 0x36210382, 0x27108268, 0xc3014208, 0x04010000, 0x243b0f82, 0x78746d68, 0x807e008a, 0x98010000, 0x06020000, 0x61636f6c, - 0xd8b0738c, 0x82050000, 0x0402291e, 0x7078616d, 0xda00ae01, 0x28201f82, 0x202c1082, 0x656d616e, 0x96bb5925, 0x84990000, 0x9e2c1382, 0x74736f70, - 0xef83aca6, 0x249b0000, 0xd22c3382, 0x70657270, 0x12010269, 0xf4040000, 0x08202f82, 0x012ecb84, 0x553c0000, 0x0f5fd5e9, 0x0300f53c, 0x00830008, - 0x7767b722, 0x002b3f82, 0xa692bd00, 0xfe0000d7, 0x83800380, 0x21f1826f, 0x00850002, 0x41820120, 0x40fec026, 0x80030000, 0x05821083, 0x07830120, - 0x0221038a, 0x24118200, 0x90000101, 0x82798200, 0x00022617, 0x00400008, 0x2009820a, 0x82098276, 0x82002006, 0x9001213b, 0x0223c883, 0x828a02bc, - 0x858f2010, 0xc5012507, 0x00023200, 0x04210083, 0x91058309, 0x6c412b03, 0x40007374, 0xac200000, 0x00830008, 0x01000523, 0x834d8380, 0x80032103, - 0x012101bf, 0x23b88280, 0x00800000, 0x0b830382, 0x07820120, 0x83800021, 0x88012001, 0x84002009, 0x2005870f, 0x870d8301, 0x2023901b, 0x83199501, - 0x82002015, 0x84802000, 0x84238267, 0x88002027, 0x8561882d, 0x21058211, 0x13880000, 0x01800022, 0x05850d85, 0x0f828020, 0x03208384, 0x03200582, - 0x47901b84, 0x1b850020, 0x1f821d82, 0x3f831d88, 0x3f410383, 0x84058405, 0x210982cd, 0x09830000, 0x03207789, 0xf38a1384, 0x01203782, 0x13872384, - 0x0b88c983, 0x0d898f84, 0x00202982, 0x23900383, 0x87008021, 0x83df8301, 0x86118d03, 0x863f880d, 0x8f35880f, 0x2160820f, 0x04830300, 0x1c220382, - 0x05820100, 0x4c000022, 0x09831182, 0x04001c24, 0x11823000, 0x0800082e, 0x00000200, 0xff007f00, 0xffffac20, 0x00220982, 0x09848100, 0xdf216682, - 0x843586d5, 0x06012116, 0x04400684, 0xa58120d7, 0x00b127d8, 0x01b88d01, 0x2d8685ff, 0xc100c621, 0xf4be0801, 0x9e011c01, 0x88021402, 0x1403fc02, - 0x9c035803, 0x1404de03, 0x50043204, 0xa2046204, 0x66051605, 0x1206bc05, 0xd6067406, 0x7e073807, 0x4e08ec07, 0x96086c08, 0x1009d008, 0x88094a09, - 0x800a160a, 0x560b040b, 0x2e0cc80b, 0xea0c820c, 0xa40d5e0d, 0x500eea0d, 0x280f960e, 0x1210b00f, 0xe0107410, 0xb6115211, 0x6e120412, 0x4c13c412, - 0xf613ac13, 0xae145814, 0x4015ea14, 0xa6158015, 0x1216b815, 0xc6167e16, 0x8e173417, 0x5618e017, 0xee18ba18, 0x96193619, 0x481ad419, 0xf01a9c1a, - 0xc81b5c1b, 0x4c1c041c, 0xea1c961c, 0x921d2a1d, 0x401ed21d, 0xe01e8e1e, 0x761f241f, 0xa61fa61f, 0x01821020, 0x8a202e34, 0xc820b220, 0x74211421, - 0xee219821, 0x86226222, 0x01820c23, 0x83238021, 0x23983c01, 0x24d823b0, 0x244a2400, 0x24902468, 0x250625ae, 0x25822560, 0x26f825f8, 0x82aa2658, - 0xd8be0801, 0x9a274027, 0x68280a28, 0x0e29a828, 0xb8292029, 0x362af829, 0x602a602a, 0x2a2b022b, 0xac2b5e2b, 0x202ce62b, 0x9a2c342c, 0x5c2d282d, - 0xaa2d782d, 0x262ee82d, 0x262fa62e, 0xf42fb62f, 0xc8305e30, 0xb4313e31, 0x9e321e32, 0x82331e33, 0x5c34ee33, 0x3a35ce34, 0xd4358635, 0x72362636, - 0x7637e636, 0x3a38d837, 0x1239a638, 0xae397439, 0x9a3a2e3a, 0x7c3b063b, 0x3a3ce83b, 0x223d963c, 0xec3d863d, 0xc63e563e, 0x9a3f2a3f, 0x6a401240, - 0x3641d040, 0x0842a241, 0x7a424042, 0xf042b842, 0xcc436243, 0x8a442a44, 0x5845ee44, 0xe245b645, 0xb4465446, 0x7a471447, 0x5448da47, 0x4049c648, - 0x15462400, 0x034d0808, 0x0b000700, 0x13000f00, 0x1b001700, 0x23001f00, 0x2b002700, 0x33002f00, 0x3b003700, 0x43003f00, 0x4b004700, 0x53004f00, - 0x5b005700, 0x63005f00, 0x6b006700, 0x73006f00, 0x7b007700, 0x83007f00, 0x8b008700, 0x00008f00, 0x15333511, 0x20039631, 0x20178205, 0xd3038221, - 0x20739707, 0x25008580, 0x028080fc, 0x05be8080, 0x04204a85, 0x05ce0685, 0x0107002a, 0x02000080, 0x00000400, 0x250d8b41, 0x33350100, 0x03920715, - 0x13820320, 0x858d0120, 0x0e8d0320, 0xff260d83, 0x00808000, 0x54820106, 0x04800223, 0x845b8c80, 0x41332059, 0x078b068f, 0x82000121, 0x82fe2039, - 0x84802003, 0x83042004, 0x23598a0e, 0x00180000, 0x03210082, 0x42ab9080, 0x73942137, 0x2013bb41, 0x8f978205, 0x2027a39b, 0x20b68801, 0x84b286fd, - 0x91c88407, 0x41032011, 0x11a51130, 0x15000027, 0x80ff8000, 0x11af4103, 0x841b0341, 0x8bd983fd, 0x9be99bc9, 0x8343831b, 0x21f1821f, 0xb58300ff, - 0x0f84e889, 0xf78a0484, 0x8000ff22, 0x0020eeb3, 0x14200082, 0x2130ef41, 0xeb431300, 0x4133200a, 0xd7410ecb, 0x9a07200b, 0x2027871b, 0x21238221, - 0xe7828080, 0xe784fd20, 0xe8848020, 0xfe808022, 0x08880d85, 0xba41fd20, 0x82248205, 0x85eab02a, 0x008022e7, 0x2cd74200, 0x44010021, 0xd34406eb, - 0x44312013, 0xcf8b0eef, 0x0d422f8b, 0x82332007, 0x0001212f, 0x8023cf82, 0x83000180, 0x820583de, 0x830682d4, 0x820020d4, 0x82dc850a, 0x20e282e9, - 0xb2ff85fe, 0x010327e9, 0x02000380, 0x0f440400, 0x0c634407, 0x68825982, 0x85048021, 0x260a825d, 0x010b0000, 0x4400ff00, 0x2746103f, 0x08d74209, - 0x4d440720, 0x0eaf4406, 0xc3441d20, 0x23078406, 0xff800002, 0x04845b83, 0x8d05b241, 0x1781436f, 0x6b8c87a5, 0x1521878e, 0x06474505, 0x01210783, - 0x84688c00, 0x8904828e, 0x441e8cf7, 0x0b270cff, 0x80008000, 0x45030003, 0xfb430fab, 0x080f4107, 0x410bf942, 0xd34307e5, 0x070d4207, 0x80800123, - 0x205d85fe, 0x849183fe, 0x20128404, 0x82809702, 0x00002217, 0x41839a09, 0x6b4408cf, 0x0733440f, 0x3b460720, 0x82798707, 0x97802052, 0x0000296f, - 0xff800004, 0x01800100, 0x0021ef89, 0x0a914625, 0x410a4d41, 0x00250ed4, 0x00050000, 0x056d4280, 0x210a7b46, 0x21481300, 0x46ed8512, 0x00210bd1, - 0x89718202, 0x21738877, 0x2b850001, 0x00220582, 0x87450a00, 0x0ddb4606, 0x41079b42, 0x9d420c09, 0x0b09420b, 0x8d820720, 0x9742fc84, 0x42098909, - 0x00241e0f, 0x00800014, 0x0b47da82, 0x0833442a, 0x49078d41, 0x2f450f13, 0x42278f17, 0x01200751, 0x22063742, 0x44808001, 0x20450519, 0x88068906, - 0x83fe2019, 0x4203202a, 0x1a941a58, 0x00820020, 0xe7a40e20, 0x420ce146, 0x854307e9, 0x0fcb4713, 0xff20a182, 0xfe209b82, 0x0c867f8b, 0x0021aea4, - 0x219fa40f, 0x7d41003b, 0x07194214, 0xbf440520, 0x071d4206, 0x6941a590, 0x80802309, 0x028900ff, 0xa9a4b685, 0xc5808021, 0x449b82ab, 0x152007eb, - 0x42134d46, 0x61440a15, 0x051e4208, 0x222b0442, 0x47001100, 0xfd412913, 0x17194714, 0x410f5b41, 0x02220773, 0x09428080, 0x21a98208, 0xd4420001, - 0x481c840d, 0x00232bc9, 0x42120000, 0xe74c261b, 0x149d4405, 0x07209d87, 0x410db944, 0x14421c81, 0x42fd2005, 0x80410bd2, 0x203d8531, 0x06874100, - 0x48256f4a, 0xcb420c95, 0x13934113, 0x44075d44, 0x044c0855, 0x00ff2105, 0xfe228185, 0x45448000, 0x22c5b508, 0x410c0000, 0x7b412087, 0x1bb74514, - 0x32429c85, 0x0a574805, 0x21208943, 0x8ba01300, 0x440dfb4e, 0x77431437, 0x245b4113, 0x200fb145, 0x41108ffe, 0x80203562, 0x00200082, 0x46362b42, - 0x1742178d, 0x4527830f, 0x0f830b2f, 0x4a138146, 0x802409a1, 0xfe8000ff, 0x94419982, 0x09294320, 0x04000022, 0x49050f4f, 0xcb470a63, 0x48032008, - 0x2b48067b, 0x85022008, 0x82638338, 0x00002209, 0x05af4806, 0x900e9f49, 0x84c5873f, 0x214285bd, 0x064900ff, 0x0c894607, 0x00000023, 0x4903820a, - 0x714319f3, 0x0749410c, 0x8a07a145, 0x02152507, 0xfe808000, 0x74490386, 0x8080211b, 0x0c276f82, 0x00018000, 0x48028003, 0x2b2315db, 0x43002f00, - 0x6f82142f, 0x44011521, 0x93510da7, 0x20e68508, 0x06494d80, 0x8e838020, 0x06821286, 0x124bff20, 0x25f3830c, 0x03800080, 0xe74a0380, 0x207b8715, - 0x876b861d, 0x4a152007, 0x07870775, 0xf6876086, 0x8417674a, 0x0a0021f2, 0x431c9743, 0x8d421485, 0x200b830b, 0x06474d03, 0x71828020, 0x04510120, - 0x42da8606, 0x1f831882, 0x001a0022, 0xff4d0082, 0x0b0f532c, 0x0d449b94, 0x4e312007, 0x074f12e7, 0x0bf3490b, 0xbb412120, 0x413f820a, 0xef490857, - 0x80002313, 0xe2830001, 0x6441fc20, 0x8b802006, 0x00012108, 0xfd201582, 0x492c9b48, 0x802014ff, 0x51084347, 0x0f4327f3, 0x17bf4a14, 0x201b7944, - 0x06964201, 0x134ffe20, 0x20d6830b, 0x25d78280, 0xfd800002, 0x05888000, 0x9318dc41, 0x21d282d4, 0xdb481800, 0x0dff542a, 0x45107743, 0xe14813f5, - 0x0f034113, 0x83135d45, 0x47b28437, 0xe4510e73, 0x21f58e06, 0x2b8400fd, 0x1041fcac, 0x08db4b0b, 0x421fdb41, 0xdf4b18df, 0x011d210a, 0x420af350, - 0x6e8308af, 0xac85cb86, 0x1e461082, 0x82b7a407, 0x411420a3, 0xa34130ab, 0x178f4124, 0x41139741, 0x86410d93, 0x82118511, 0x057243d8, 0x8941d9a4, - 0x3093480c, 0x4a13474f, 0xfb5016a9, 0x07ad4108, 0x4a0f9d42, 0xfe200fad, 0x4708aa41, 0x83482dba, 0x288f4d06, 0xb398c3bb, 0x44267b41, 0xb34439d7, - 0x0755410f, 0x200ebb45, 0x0f5f4215, 0x20191343, 0x06df5301, 0xf04c0220, 0x2ba64d07, 0x82050841, 0x430020ce, 0xa78f3627, 0x5213ff42, 0x2f970bc1, - 0x4305ab55, 0xa084111b, 0x450bac45, 0x5f4238b8, 0x010c2106, 0x0220ed82, 0x441bb344, 0x875010af, 0x0737480f, 0x490c5747, 0x0c840c03, 0x4c204b42, - 0x8ba905d7, 0x8b948793, 0x510c0c51, 0xfb4b24b9, 0x1b174107, 0x5709d74c, 0xd1410ca5, 0x079d480f, 0x201ff541, 0x06804780, 0x7d520120, 0x80002205, - 0x20a983fe, 0x47bb83fe, 0x1b8409b4, 0x81580220, 0x4e00202c, 0x4f41282f, 0x0eab4f17, 0x57471520, 0x0e0f4808, 0x8221e041, 0x3e1b4a8b, 0x4407175d, - 0x1b4b071f, 0x4a0f8b07, 0x174a0703, 0x0ba5411b, 0x430fb141, 0x0120057b, 0xfc20dd82, 0x4a056047, 0xf4850c0c, 0x01221982, 0x02828000, 0x1a5d088b, - 0x20094108, 0x8c0e3941, 0x4900200e, 0x7744434f, 0x200b870b, 0x0e4b5a33, 0x2b41f78b, 0x8b138307, 0x0b9f450b, 0x2406f741, 0xfd808001, 0x09475a00, - 0x84000121, 0x5980200e, 0x85450e5d, 0x832c8206, 0x4106831e, 0x00213814, 0x28b34810, 0x410c2f4b, 0x5f4a13d7, 0x0b2b4113, 0x6e43a883, 0x11174b05, - 0x4b066a45, 0xcc470541, 0x5000202b, 0xcb472f4b, 0x44b59f0f, 0xc5430b5b, 0x0d654907, 0x21065544, 0xd6828080, 0xfe201982, 0x8230ec4a, 0x120025c2, - 0x80ff8000, 0x4128d74d, 0x3320408b, 0x410a9f50, 0xdb822793, 0x822bd454, 0x61134b2e, 0x410b214a, 0xad4117c9, 0x0001211f, 0x4206854f, 0x4b430596, - 0x06bb5530, 0x2025cf46, 0x0ddd5747, 0x500ea349, 0x0f840fa7, 0x5213c153, 0x634e08d1, 0x0bbe4809, 0x59316e4d, 0x5b50053f, 0x203f6323, 0x5117eb46, - 0x94450a63, 0x246e410a, 0x63410020, 0x0bdb5f2f, 0x4233ab44, 0x39480757, 0x112d4a07, 0x7241118f, 0x000e2132, 0x9f286f41, 0x0f8762c3, 0x33350723, - 0x094e6415, 0x2010925f, 0x067252fe, 0xd0438020, 0x63a68225, 0x11203a4f, 0x480e6360, 0x5748131f, 0x079b521f, 0x200e2f43, 0x864b8315, 0x113348e7, - 0x85084e48, 0x06855008, 0x5880fd21, 0x7c420925, 0x0c414824, 0x37470c86, 0x1b8b422b, 0x5b0a8755, 0x23410c21, 0x0b83420b, 0x5a082047, 0xf482067f, - 0xa80b4c47, 0x0c0021cf, 0x20207b42, 0x0fb74100, 0x420b8744, 0xeb43076f, 0x0f6f420b, 0x4261fe20, 0x439aa00c, 0x215034e3, 0x0ff9570f, 0x4b1f2d5d, - 0x2d5d0c6f, 0x09634d0b, 0x1f51b8a0, 0x620f200c, 0xaf681e87, 0x24f94d07, 0x4e0f4945, 0xfe200c05, 0x22139742, 0x57048080, 0x23950c20, 0x97601585, - 0x4813201f, 0xad620523, 0x200f8f0f, 0x9e638f15, 0x00002181, 0x41342341, 0x0f930f0b, 0x210b4b62, 0x978f0001, 0xfe200f84, 0x8425c863, 0x2704822b, - 0x80000a00, 0x00038001, 0x610e9768, 0x834514bb, 0x0bc3430f, 0x2107e357, 0x80848080, 0x4400fe21, 0x2e410983, 0x00002a1a, 0x00000700, 0x800380ff, - 0x0fdf5800, 0x59150021, 0xd142163d, 0x0c02410c, 0x01020025, 0x65800300, 0x00240853, 0x1d333501, 0x15220382, 0x35420001, 0x44002008, 0x376406d7, - 0x096f6b19, 0x480bc142, 0x8f4908a7, 0x211f8b1f, 0x9e830001, 0x0584fe20, 0x4180fd21, 0x11850910, 0x8d198259, 0x000021d4, 0x5a08275d, 0x275d1983, - 0x06d9420e, 0x9f08b36a, 0x0f7d47b5, 0x8d8a2f8b, 0x4c0e0b57, 0xe7410e17, 0x42d18c1a, 0xb351087a, 0x1ac36505, 0x4b4a2f20, 0x0b9f450d, 0x430beb53, - 0xa7881015, 0xa5826a83, 0x80200f82, 0x86185a65, 0x4100208e, 0x176c3367, 0x0fe7650b, 0x4a17ad4b, 0x0f4217ed, 0x112e4206, 0x41113a42, 0xf7423169, - 0x0cb34737, 0x560f8b46, 0xa75407e5, 0x5f01200f, 0x31590c48, 0x80802106, 0x42268841, 0x0020091e, 0x4207ef64, 0x69461df7, 0x138d4114, 0x820f5145, - 0x53802090, 0xff200529, 0xb944b183, 0x417e8505, 0x00202561, 0x15210082, 0x42378200, 0x9b431cc3, 0x004f220d, 0x0dd54253, 0x4213f149, 0x7d41133b, - 0x42c9870b, 0x802010f9, 0x420b2c42, 0x8f441138, 0x267c4408, 0x600cb743, 0x8f4109d3, 0x05ab701d, 0x83440020, 0x3521223f, 0x0b794733, 0xfb62fe20, - 0x4afd2010, 0xaf410ae7, 0x25ce8525, 0x01080000, 0x7b6b0000, 0x0973710b, 0x82010021, 0x49038375, 0x33420767, 0x052c4212, 0x58464b85, 0x41fe2005, - 0x50440c27, 0x000c2209, 0x1cb36b80, 0x9b06df44, 0x0f93566f, 0x52830220, 0xfe216e8d, 0x200f8200, 0x0fb86704, 0xb057238d, 0x050b5305, 0x7217eb47, - 0xbd410b6b, 0x0f214610, 0x871f9956, 0x1e91567e, 0x2029b741, 0x20008200, 0x18b7410a, 0x27002322, 0x41095543, 0x0f8f0fb3, 0x41000121, 0x889d111c, - 0x14207b82, 0x00200382, 0x73188761, 0x475013a7, 0x6e33200c, 0x234e0ea3, 0x9b138313, 0x08e54d17, 0x9711094e, 0x2ee74311, 0x4908875e, 0xd75d1f1f, - 0x19ab5238, 0xa2084d48, 0x63a7a9b3, 0x55450b83, 0x0fd74213, 0x440d814c, 0x4f481673, 0x05714323, 0x13000022, 0x412e1f46, 0xdf493459, 0x21c7550f, - 0x8408215f, 0x201d49cb, 0xb1103043, 0x0f0d65d7, 0x452b8d41, 0x594b0f8d, 0x0b004605, 0xb215eb46, 0x000a24d7, 0x47000080, 0x002118cf, 0x06436413, - 0x420bd750, 0x2b500743, 0x076a470c, 0x4105c050, 0xd942053f, 0x0d00211a, 0x5f44779c, 0x0ce94805, 0x51558186, 0x14a54c0b, 0x49082b41, 0x0a4b0888, - 0x8080261f, 0x0d000000, 0x20048201, 0x1deb6a03, 0x420cb372, 0x07201783, 0x4306854d, 0x8b830c59, 0x59093c74, 0x0020250f, 0x67070f4a, 0x2341160b, - 0x00372105, 0x431c515d, 0x554e17ef, 0x0e5d6b05, 0x41115442, 0xb74a1ac1, 0x2243420a, 0x5b4f878f, 0x7507200f, 0x384b086f, 0x09d45409, 0x0020869a, - 0x12200082, 0xab460382, 0x10075329, 0x54138346, 0xaf540fbf, 0x1ea75413, 0x9a0c9e54, 0x0f6b44c1, 0x41000021, 0x47412a4f, 0x07374907, 0x5310bf76, - 0xff2009b4, 0x9a09a64c, 0x8200208d, 0x34c34500, 0x970fe141, 0x1fd74b0f, 0x440a3850, 0x206411f0, 0x27934609, 0x470c5d41, 0x555c2947, 0x1787540f, - 0x6e0f234e, 0x7d540a1b, 0x1d736b08, 0x0026a088, 0x80000e00, 0x9b5200ff, 0x08ef4318, 0x450bff77, 0x1d4d0b83, 0x081f7006, 0xcb691b86, 0x4b022008, - 0xc34b0b33, 0x1d0d4a0c, 0x8025a188, 0x0b000000, 0x52a38201, 0xbf7d0873, 0x0c234511, 0x8f0f894a, 0x4101200f, 0x0c880c9d, 0x2b418ea1, 0x06c74128, - 0x66181341, 0x7b4c0bb9, 0x0c06630b, 0xfe200c87, 0x9ba10882, 0x27091765, 0x01000008, 0x02800380, 0x48113f4e, 0x29430cf5, 0x09a75a0b, 0x31618020, - 0x6d802009, 0x61840e33, 0x8208bf51, 0x0c637d61, 0x7f092379, 0x4f470f4b, 0x1797510c, 0x46076157, 0xf5500fdf, 0x0f616910, 0x1171fe20, 0x82802006, - 0x08696908, 0x41127a4c, 0x3f4a15f3, 0x01042607, 0x0200ff00, 0x1cf77700, 0xff204185, 0x00235b8d, 0x43100000, 0x3b22243f, 0x3b4d3f00, 0x0b937709, - 0xad42f18f, 0x0b1f420f, 0x51084b43, 0x8020104a, 0xb557ff83, 0x052b7f2a, 0x0280ff22, 0x250beb78, 0x00170013, 0xbf6d2500, 0x07db760e, 0x410e2b7f, - 0x00230e4f, 0x49030000, 0x0582055b, 0x07000326, 0x00000b00, 0x580bcd46, 0x00200cdd, 0x57078749, 0x8749160f, 0x0f994f0a, 0x41134761, 0x01200b31, - 0xeb796883, 0x0b41500b, 0x0e90b38e, 0x202e7b51, 0x05d95801, 0x41080570, 0x1d530fc9, 0x0b937a0f, 0xaf8eb387, 0xf743b98f, 0x07c74227, 0x80000523, - 0x0fcb4503, 0x430ca37b, 0x7782077f, 0x8d0a9947, 0x08af4666, 0xeb798020, 0x6459881e, 0xc3740bbf, 0x0feb6f0b, 0x20072748, 0x052b6102, 0x435e0584, - 0x7d088308, 0x03200afd, 0x92109e41, 0x28aa8210, 0x80001500, 0x80030000, 0x0fdb5805, 0x209f4018, 0xa7418d87, 0x0aa3440f, 0x20314961, 0x073a52ff, - 0x6108505d, 0x43181051, 0x00223457, 0xe7820500, 0x50028021, 0x81410d33, 0x063d7108, 0xdb41af84, 0x4d888205, 0x00201198, 0x463d835f, 0x152106d7, - 0x0a355a33, 0x6917614e, 0x75411f4d, 0x184b8b07, 0x1809c344, 0x21091640, 0x0b828000, 0x42808021, 0x26790519, 0x86058605, 0x2428422d, 0x22123b42, - 0x42000080, 0xf587513b, 0x7813677b, 0xaf4d139f, 0x00ff210c, 0x5e0a1d57, 0x3b421546, 0x01032736, 0x02000380, 0x41180480, 0x2f420f07, 0x0c624807, - 0x00000025, 0x18000103, 0x83153741, 0x430120c3, 0x042106b2, 0x088d4d00, 0x2f830620, 0x1810434a, 0x18140345, 0x8507fb41, 0x5ee582ea, 0x0023116c, - 0x8d000600, 0x053b56af, 0xa6554fa2, 0x0d704608, 0x40180d20, 0x47181a43, 0xd37b07ff, 0x0b79500c, 0x420fd745, 0x47450bd9, 0x8471830a, 0x095a777e, - 0x84137542, 0x82002013, 0x2f401800, 0x0007213b, 0x4405e349, 0x0d550ff3, 0x16254c0c, 0x820ffe4a, 0x0400218a, 0x89066f41, 0x106b414f, 0xc84d0120, - 0x80802206, 0x0c9a4b03, 0x00100025, 0x68000200, 0x9d8c2473, 0x44134344, 0xf36a0f33, 0x4678860f, 0x1b440a25, 0x41988c0a, 0x80201879, 0x43079b5e, - 0x4a18080b, 0x0341190b, 0x1259530c, 0x43251552, 0x908205c8, 0x0cac4018, 0x86000421, 0x0e504aa2, 0x0020b891, 0xfb450082, 0x51132014, 0x8f5205f3, - 0x35052108, 0x8505cb59, 0x0f6d4f70, 0x82150021, 0x29af5047, 0x4f004b24, 0x75795300, 0x1b595709, 0x460b6742, 0xbf4b0f0d, 0x5743870b, 0xcb6d1461, - 0x08f64505, 0x4e05ab6c, 0x334126c3, 0x0bcb6b0d, 0x1811034d, 0x4111ef4b, 0x814f1ce5, 0x20af8227, 0x07fd7b80, 0x41188e84, 0xef410f33, 0x80802429, - 0x410d0000, 0xa34205ab, 0x76b7881c, 0xff500b89, 0x0741430f, 0x20086f4a, 0x209d8200, 0x234c18fd, 0x05d4670a, 0x4509af51, 0x9642078d, 0x189e831d, - 0x7c1cc74b, 0xcd4c07b9, 0x0e7c440f, 0x8b7b0320, 0x21108210, 0xc76c8080, 0x03002106, 0x6b23bf41, 0xc549060b, 0x7946180b, 0x0ff7530f, 0x17ad4618, - 0x200ecd45, 0x208c83fd, 0x5e0488fe, 0x032009c6, 0x420d044e, 0x0d8f0d7f, 0x00820020, 0x18001021, 0x6d273b45, 0xfd4c0c93, 0xcf451813, 0x0fe5450f, - 0x5a47c382, 0x820a8b0a, 0x282b4998, 0x410a8b5b, 0x4b232583, 0x54004f00, 0x978f0ce3, 0x500f1944, 0xa95f1709, 0x0280220b, 0x05ba7080, 0xa1530682, - 0x06324c13, 0x91412582, 0x05536e2c, 0x63431020, 0x0f434706, 0x8c11374c, 0x176143d7, 0x4d0f454c, 0xd3680bed, 0x0bee4d17, 0x212b9a41, 0x0f530a00, - 0x140d531c, 0x43139143, 0x95610e8d, 0x0f094415, 0x4205fb56, 0x1b4205cf, 0x17015225, 0x5e0c477f, 0xaf6e0aeb, 0x0ff36218, 0x04849a84, 0x0a454218, - 0x9c430420, 0x23c6822b, 0x04000102, 0x45091b4b, 0xf05f0955, 0x82802007, 0x421c2023, 0x5218282b, 0x7b53173f, 0x0fe7480c, 0x74173b7f, 0x47751317, - 0x634d1807, 0x0f6f430f, 0x24086547, 0xfc808002, 0x0b3c7f80, 0x10840120, 0x188d1282, 0x20096b43, 0x0fc24403, 0x00260faf, 0x0180000b, 0x3f500280, - 0x18002019, 0x450b4941, 0xf3530fb9, 0x18002010, 0x8208a551, 0x06234d56, 0xcb58a39b, 0xc3421805, 0x1313461e, 0x0f855018, 0xd34b0120, 0x6cfe2008, - 0x574f0885, 0x09204114, 0x07000029, 0x00008000, 0x44028002, 0x01420f57, 0x10c95c10, 0x11184c18, 0x80221185, 0x7f421e00, 0x00732240, 0x09cd4977, - 0x6d0b2b42, 0x4f180f8f, 0x8f5a0bcb, 0x9b0f830f, 0x0fb9411f, 0x230b5756, 0x00fd8080, 0x82060745, 0x000121d5, 0x8e0fb277, 0x4a8d4211, 0x24061c53, - 0x04000007, 0x12275280, 0x430c954c, 0x80201545, 0x200f764f, 0x20008200, 0x20ce8308, 0x09534f02, 0x660edf64, 0x73731771, 0xe7411807, 0x20a2820c, - 0x13b64404, 0x8f5d6682, 0x1d6b4508, 0x0cff4d18, 0x3348c58f, 0x0fc34c07, 0x31558b84, 0x8398820f, 0x17514712, 0x240b0e46, 0x80000a00, 0x093b4502, - 0x420f9759, 0xa54c0bf1, 0x0f2b470c, 0x410d314b, 0x2584170c, 0x73b30020, 0xb55fe782, 0x204d8410, 0x08e043fe, 0x4f147e41, 0x022008ab, 0x4b055159, - 0x2950068f, 0x00022208, 0x48511880, 0x82002009, 0x00112300, 0x634dff00, 0x24415f27, 0x180f6d43, 0x4d0b5d45, 0x4d5f05ef, 0x01802317, 0x56188000, - 0xa7840807, 0xc6450220, 0x21ca8229, 0x4b781a00, 0x3359182c, 0x0cf3470f, 0x180bef46, 0x420b0354, 0xff470b07, 0x4515200a, 0x9758239b, 0x4a80200c, - 0xd2410a26, 0x05fb4a08, 0x4b05e241, 0x03200dc9, 0x92290941, 0x00002829, 0x00010900, 0x5b020001, 0x23201363, 0x460d776a, 0xef530fdb, 0x209a890c, - 0x13fc4302, 0x00008024, 0xc4820104, 0x08820220, 0x20086b5b, 0x18518700, 0x8408d349, 0x0da449a1, 0x00080024, 0x7b690280, 0x4c438b1a, 0x01220f63, - 0x4c878000, 0x5c149c53, 0xfb430868, 0x2f56181e, 0x0ccf7b1b, 0x0f075618, 0x2008e347, 0x14144104, 0x00207f83, 0x00207b82, 0x201adf47, 0x16c35a13, - 0x540fdf47, 0x802006c8, 0x5418f185, 0x29430995, 0x00002419, 0x58001600, 0x5720316f, 0x4d051542, 0x4b7b1b03, 0x138f4707, 0xb747b787, 0x4aab8213, - 0x058305fc, 0x20115759, 0x82128401, 0x0a0b44e8, 0x46800121, 0xe64210d0, 0x82129312, 0x4bffdffe, 0x3b41171b, 0x9b27870f, 0x808022ff, 0x085c68fe, - 0x41800021, 0x01410b20, 0x001a213a, 0x47480082, 0x11374e12, 0x56130b4c, 0xdf4b0c65, 0x0b0f590b, 0x0f574c18, 0x830feb4b, 0x075f480f, 0x480b4755, - 0x40490b73, 0x80012206, 0x09d74280, 0x80fe8022, 0x80210e86, 0x056643ff, 0x10820020, 0x420b2646, 0x0b58391a, 0xd74c1808, 0x078b4e22, 0x2007f55f, - 0x4b491807, 0x83802017, 0x65aa82a7, 0x3152099e, 0x068b7616, 0x9b431220, 0x09bb742c, 0x500e376c, 0x8342179b, 0x0a4d5d0f, 0x8020a883, 0x180cd349, - 0x2016bb4b, 0x14476004, 0x84136c43, 0x08cf7813, 0x4f4c0520, 0x156f420f, 0x20085f42, 0x6fd3be03, 0xd4d30803, 0xa7411420, 0x004b222c, 0x0d3b614f, - 0x3f702120, 0x1393410a, 0x8f132745, 0x47421827, 0x41e08209, 0xb05e2bb9, 0x18b7410c, 0x18082647, 0x4107a748, 0xeb8826bf, 0x0ca76018, 0x733ecb41, - 0xd0410d83, 0x43ebaf2a, 0x0420067f, 0x721dab4c, 0x472005bb, 0x4105d341, 0x334844cb, 0x20dba408, 0x47d6ac00, 0x034e3aef, 0x0f8f421b, 0x930f134d, - 0x3521231f, 0xb7421533, 0x42f5ad0a, 0x1e961eaa, 0x17000022, 0x4c367b50, 0x7d491001, 0x0bf5520f, 0x4c18fda7, 0xb8460c55, 0x83fe2005, 0x00fe25b9, - 0x80000180, 0x9e751085, 0x261b5c12, 0x82110341, 0x001123fb, 0x4518fe80, 0xf38c2753, 0x6d134979, 0x295107a7, 0xaf5f180f, 0x0fe3660c, 0x180b6079, - 0x2007bd5f, 0x9aab9103, 0x2f4d1811, 0x05002109, 0x44254746, 0x1d200787, 0x450bab75, 0x4f180f57, 0x4f181361, 0x3b831795, 0xeb4b0120, 0x0b734805, - 0x84078f48, 0x2e1b47bc, 0x00203383, 0xaf065f45, 0x831520d7, 0x130f51a7, 0x1797bf97, 0x2b47d783, 0x18fe2005, 0x4a18a44f, 0xa64d086d, 0x1ab0410d, - 0x6205a258, 0xdbab069f, 0x4f06f778, 0xa963081d, 0x133b670a, 0x8323d141, 0x13195b23, 0x530f5e70, 0xe5ad0824, 0x58001421, 0x1f472b4b, 0x47bf410c, - 0x82000121, 0x83fe20cb, 0x07424404, 0x68068243, 0xd7ad0d3d, 0x00010d26, 0x80020000, 0x4a1c6f43, 0x23681081, 0x10a14f13, 0x8a070e57, 0x430a848f, - 0x7372243e, 0x4397a205, 0xb56c1021, 0x43978f0f, 0x64180505, 0x99aa0ff2, 0x0e000022, 0x20223341, 0x094b4f37, 0x074a3320, 0x2639410a, 0xfe208e84, - 0x8b0e0048, 0x508020a3, 0x9e4308fe, 0x073f4115, 0xe3480420, 0x0c9b5f1b, 0x7c137743, 0x9a95185b, 0x6122b148, 0x979b08df, 0x0fe36c18, 0x48109358, - 0x23441375, 0x0ffd5c0b, 0x180fc746, 0x2011d157, 0x07e95702, 0x58180120, 0x18770ac3, 0x51032008, 0x7d4118e3, 0x80802315, 0x3b4c1900, 0xbb5a1830, - 0x0ceb6109, 0x5b0b3d42, 0x4f181369, 0x4f180b8d, 0x4f180f75, 0x355a1b81, 0x200d820d, 0x18e483fd, 0x4528854f, 0x89420846, 0x1321411f, 0x44086b60, - 0x07421d77, 0x107d4405, 0x4113fd41, 0x5a181bf1, 0x4f180db3, 0x8021128f, 0x20f68280, 0x44a882fe, 0x334d249a, 0x052f6109, 0x1520c3a7, 0xef4eb783, - 0x4ec39b1b, 0xc4c90ee7, 0x20060b4d, 0x256f4905, 0x4d0cf761, 0xcf9b1f13, 0xa213d74e, 0x0e1145d4, 0x50135b42, 0xcb4e398f, 0x20d79f27, 0x08865d80, - 0x186d5018, 0xa90f7142, 0x067342d7, 0x3f450420, 0x65002021, 0xe3560771, 0x24d38f23, 0x15333531, 0x0eb94d01, 0x451c9f41, 0x384322fb, 0x00092108, - 0x19af6b18, 0x6e0c6f5a, 0xbd770bfb, 0x22bb7718, 0x20090f57, 0x25e74204, 0x4207275a, 0xdb5408ef, 0x1769450f, 0x1b1b5518, 0x210b1f57, 0x5e4c8001, - 0x55012006, 0x802107f1, 0x0a306a80, 0x45808021, 0x0d850b88, 0x31744f18, 0x1808ec54, 0x2009575b, 0x45ffa505, 0x1b420c73, 0x180f9f0f, 0x4a0cf748, - 0x501805b2, 0x00210f40, 0x4d118f80, 0xd6823359, 0x072b5118, 0x314ad7aa, 0x8fc79f08, 0x45d78b1f, 0xfe20058f, 0x23325118, 0x7b54d9b5, 0x9fc38f46, - 0x10bb410f, 0x41077b42, 0xc1410faf, 0x27cf441d, 0x46051b4f, 0x04200683, 0x2121d344, 0x8f530043, 0x8fcf9f0e, 0x21df8c1f, 0x50188000, 0x5d180e52, - 0xfd201710, 0x4405c341, 0xd68528e3, 0x20071f6b, 0x1b734305, 0x6b080957, 0x7d422b1f, 0x67002006, 0x7f8317b1, 0x2024cb48, 0x08676e00, 0x8749a39b, - 0x18132006, 0x410a6370, 0x8f490b47, 0x7e1f8f13, 0x551805c3, 0x4c180915, 0xfe200e2f, 0x244d5d18, 0x270bcf44, 0xff000019, 0x04800380, 0x5f253342, - 0xff520df7, 0x13274c18, 0x5542dd93, 0x0776181b, 0xf94a1808, 0x084a4c0c, 0x4308ea5b, 0xde831150, 0x7900fd21, 0x00492c1e, 0x060f4510, 0x17410020, - 0x0ce74526, 0x6206b341, 0x1f561083, 0x9d6c181b, 0x08a0500e, 0x112e4118, 0x60000421, 0xbf901202, 0x4408e241, 0xc7ab0513, 0xb40f0950, 0x055943c7, - 0x4f18ff20, 0xc9ae1cad, 0x32b34f18, 0x7a180120, 0x3d520a05, 0x53d1b40a, 0x80200813, 0x1b815018, 0x832bf86f, 0x67731847, 0x297f4308, 0x6418d54e, - 0x734213f7, 0x056b4b27, 0xdba5fe20, 0x1828aa4e, 0x2031a370, 0x06cb6101, 0x2040ad41, 0x07365300, 0x2558d985, 0x83fe200c, 0x0380211c, 0x542c4743, - 0x052006b7, 0x6021df45, 0x897b0707, 0x18d3c010, 0x20090e70, 0x1d5843ff, 0x540a0e44, 0x002126c5, 0x322f7416, 0x636a5720, 0x0f317409, 0x610fe159, - 0x294617e7, 0x08555213, 0x2006a75d, 0x6cec84fd, 0xfb5907be, 0x3a317405, 0x83808021, 0x180f20ea, 0x4626434a, 0x531818e3, 0xdb59172d, 0x0cbb460c, - 0x2013d859, 0x18b94502, 0x8f46188d, 0x77521842, 0x0a184e38, 0x9585fd20, 0x6a180684, 0xc64507e9, 0x51cbb230, 0xd3440cf3, 0x17ff6a0f, 0x450f5b42, - 0x276407c1, 0x4853180a, 0x21ccb010, 0xcf580013, 0x0c15442d, 0x410a1144, 0x1144359d, 0x5cfe2006, 0xa1410a43, 0x2bb64519, 0x2f5b7618, 0xb512b745, - 0x0cfd6fd1, 0x42089f59, 0xb8450c70, 0x0000232d, 0x50180900, 0xb9491ae3, 0x0fc37610, 0x01210f83, 0x0f3b4100, 0xa01b2742, 0x0ccd426f, 0x6e8f6f94, - 0x9c808021, 0xc7511870, 0x17c74b08, 0x9b147542, 0x44fe2079, 0xd5480c7e, 0x95ef861d, 0x101b597b, 0xf5417594, 0x9f471808, 0x86868d0e, 0x3733491c, - 0x690f4d6d, 0x43440b83, 0x1ba94c0b, 0x660cd16b, 0x802008ae, 0x74126448, 0xcb4f38a3, 0x2cb74b0b, 0x47137755, 0xe3971777, 0x1b5d0120, 0x057a4108, - 0x6e08664d, 0x17421478, 0x11af4208, 0x850c3f42, 0x08234f0c, 0x4321eb4a, 0xf3451095, 0x0f394e0f, 0x4310eb45, 0xc09707b1, 0x54431782, 0xaec08d1d, - 0x0f434dbb, 0x9f0c0b45, 0x0a3b4dbb, 0x4618bdc7, 0x536032eb, 0x17354213, 0x4d134169, 0xc7a30c2f, 0x4e254342, 0x174332cf, 0x43cdae17, 0x6b4706e4, - 0x0e16430d, 0x530b5542, 0x2f7c26bb, 0x13075f31, 0x43175342, 0x60181317, 0x6550114e, 0x28624710, 0x58070021, 0x59181683, 0x2d540cf5, 0x05d5660c, - 0x20090c7b, 0x0e157e02, 0x8000ff2b, 0x14000080, 0x80ff8000, 0x27137e03, 0x336a4b20, 0x0f817107, 0x13876e18, 0x730f2f7e, 0x2f450b75, 0x6d02200b, - 0x6d66094c, 0x4b802009, 0x15820a02, 0x2f45fe20, 0x5e032006, 0x00202fd9, 0x450af741, 0xeb412e0f, 0x0ff3411f, 0x420a8b65, 0xf7410eae, 0x1c664810, - 0x540e1145, 0xbfa509f3, 0x42302f58, 0x80200c35, 0xcb066c47, 0x4b1120c1, 0x41492abb, 0x34854110, 0xa7097b72, 0x251545c7, 0x4b2c7f56, 0xc5b40bab, - 0x940cd54e, 0x2e6151c8, 0x09f35f18, 0x4b420420, 0x09677121, 0x8f24f357, 0x1b5418e1, 0x08915a1f, 0x3143d894, 0x22541805, 0x1b9b4b0e, 0x8c0d3443, - 0x1400240d, 0x18ff8000, 0x582e6387, 0xf99b2b3b, 0x8807a550, 0x17a14790, 0x2184fd20, 0x5758fe20, 0x2354882c, 0x15000080, 0x5e056751, 0x334c2c2f, - 0x97c58f0c, 0x1fd7410f, 0x0d4d4018, 0x4114dc41, 0x04470ed6, 0x0dd54128, 0x00820020, 0x02011523, 0x22008700, 0x86480024, 0x0001240a, 0x8682001a, - 0x0002240b, 0x866c000e, 0x8a03200b, 0x8a042017, 0x0005220b, 0x22218614, 0x84060000, 0x86012017, 0x8212200f, 0x250b8519, 0x000d0001, 0x0b850031, - 0x07000224, 0x0b862600, 0x11000324, 0x0b862d00, 0x238a0420, 0x0a000524, 0x17863e00, 0x17840620, 0x01000324, 0x57820904, 0x0b85a783, 0x0b85a785, - 0x0b85a785, 0x22000325, 0x85007a00, 0x85a7850b, 0x85a7850b, 0x22a7850b, 0x82300032, 0x00342201, 0x0805862f, 0x35003131, 0x54207962, 0x74736972, - 0x47206e61, 0x6d6d6972, 0x65527265, 0x616c7567, 0x58545472, 0x6f725020, 0x43796767, 0x6e61656c, 0x30325454, 0x822f3430, 0x35313502, 0x79006200, - 0x54002000, 0x69007200, 0x74007300, 0x6e006100, 0x47200f82, 0x6d240f84, 0x65006d00, 0x52200982, 0x67240582, 0x6c007500, 0x72201d82, 0x54222b82, - 0x23825800, 0x19825020, 0x67006f22, 0x79220182, 0x1b824300, 0x3b846520, 0x1f825420, 0x41000021, 0x1422099b, 0x0b410000, 0x87088206, 0x01012102, - 0x78080982, 0x01020101, 0x01040103, 0x01060105, 0x01080107, 0x010a0109, 0x010c010b, 0x010e010d, 0x0110010f, 0x01120111, 0x01140113, 0x01160115, - 0x01180117, 0x011a0119, 0x011c011b, 0x011e011d, 0x0020011f, 0x00040003, 0x00060005, 0x00080007, 0x000a0009, 0x000c000b, 0x000e000d, 0x0010000f, - 0x00120011, 0x00140013, 0x00160015, 0x00180017, 0x001a0019, 0x001c001b, 0x001e001d, 0x08bb821f, 0x22002142, 0x24002300, 0x26002500, 0x28002700, - 0x2a002900, 0x2c002b00, 0x2e002d00, 0x30002f00, 0x32003100, 0x34003300, 0x36003500, 0x38003700, 0x3a003900, 0x3c003b00, 0x3e003d00, 0x40003f00, - 0x42004100, 0x4b09f382, 0x00450044, 0x00470046, 0x00490048, 0x004b004a, 0x004d004c, 0x004f004e, 0x00510050, 0x00530052, 0x00550054, 0x00570056, - 0x00590058, 0x005b005a, 0x005d005c, 0x005f005e, 0x01610060, 0x01220121, 0x01240123, 0x01260125, 0x01280127, 0x012a0129, 0x012c012b, 0x012e012d, - 0x0130012f, 0x01320131, 0x01340133, 0x01360135, 0x01380137, 0x013a0139, 0x013c013b, 0x013e013d, 0x0140013f, 0x00ac0041, 0x008400a3, 0x00bd0085, - 0x00e80096, 0x008e0086, 0x009d008b, 0x00a400a9, 0x008a00ef, 0x008300da, 0x00f20093, 0x008d00f3, 0x00880097, 0x00de00c3, 0x009e00f1, 0x00f500aa, - 0x00f600f4, 0x00ad00a2, 0x00c700c9, 0x006200ae, 0x00900063, 0x00cb0064, 0x00c80065, 0x00cf00ca, 0x00cd00cc, 0x00e900ce, 0x00d30066, 0x00d100d0, - 0x006700af, 0x009100f0, 0x00d400d6, 0x006800d5, 0x00ed00eb, 0x006a0089, 0x006b0069, 0x006c006d, 0x00a0006e, 0x0071006f, 0x00720070, 0x00750073, - 0x00760074, 0x00ea0077, 0x007a0078, 0x007b0079, 0x007c007d, 0x00a100b8, 0x007e007f, 0x00810080, 0x00ee00ec, 0x6e750eba, 0x646f6369, 0x78302365, - 0x31303030, 0x32200e8d, 0x33200e8d, 0x34200e8d, 0x35200e8d, 0x36200e8d, 0x37200e8d, 0x38200e8d, 0x39200e8d, 0x61200e8d, 0x62200e8d, 0x63200e8d, - 0x64200e8d, 0x65200e8d, 0x66200e8d, 0x31210e8c, 0x8d0e8d30, 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, - 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, 0x66312def, 0x6c656406, 0x04657465, 0x6f727545, 0x3820ec8c, 0x3820ec8d, - 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, - 0x3820ec8d, 0x200ddc41, 0x0ddc4139, 0xef8d3920, 0xef8d3920, 0xef8d3920, 0xef8d3920, 0xef8d3920, 0xef8d3920, 0xef8d3920, 0xef8d3920, 0xef8d3920, - 0xef8d3920, 0xef8d3920, 0xef8d3920, 0xef8d3920, 0xef8d3920, 0x00663923, 0x48fa0500, 0x00f762f9, + 0x0000bc57, 0x00000000, 0xf8a00000, 0x00000400, 0x00010037, 0x000c0000, 0x00030080, 0x2f534f40, 0x74eb8832, 0x01000090, 0x2c158248, 0x616d634e, + 0x23120270, 0x03000075, 0x241382a0, 0x74766352, 0x82178220, 0xfc042102, 0x02380482, 0x66796c67, 0x5689af12, 0x04070000, 0x80920000, 0x64616568, + 0xd36691d7, 0xcc201b82, 0x36210382, 0x27108268, 0xc3014208, 0x04010000, 0x243b0f82, 0x78746d68, 0x807e008a, 0x98010000, 0x06020000, 0x61636f6c, + 0xd8b0738c, 0x82050000, 0x0402291e, 0x7078616d, 0xda00ae01, 0x28201f82, 0x202c1082, 0x656d616e, 0x96bb5925, 0x84990000, 0x9e2c1382, 0x74736f70, + 0xef83aca6, 0x249b0000, 0xd22c3382, 0x70657270, 0x12010269, 0xf4040000, 0x08202f82, 0x012ecb84, 0x553c0000, 0x0f5fd5e9, 0x0300f53c, 0x00830008, + 0x7767b722, 0x002b3f82, 0xa692bd00, 0xfe0000d7, 0x83800380, 0x21f1826f, 0x00850002, 0x41820120, 0x40fec026, 0x80030000, 0x05821083, 0x07830120, + 0x0221038a, 0x24118200, 0x90000101, 0x82798200, 0x00022617, 0x00400008, 0x2009820a, 0x82098276, 0x82002006, 0x9001213b, 0x0223c883, 0x828a02bc, + 0x858f2010, 0xc5012507, 0x00023200, 0x04210083, 0x91058309, 0x6c412b03, 0x40007374, 0xac200000, 0x00830008, 0x01000523, 0x834d8380, 0x80032103, + 0x012101bf, 0x23b88280, 0x00800000, 0x0b830382, 0x07820120, 0x83800021, 0x88012001, 0x84002009, 0x2005870f, 0x870d8301, 0x2023901b, 0x83199501, + 0x82002015, 0x84802000, 0x84238267, 0x88002027, 0x8561882d, 0x21058211, 0x13880000, 0x01800022, 0x05850d85, 0x0f828020, 0x03208384, 0x03200582, + 0x47901b84, 0x1b850020, 0x1f821d82, 0x3f831d88, 0x3f410383, 0x84058405, 0x210982cd, 0x09830000, 0x03207789, 0xf38a1384, 0x01203782, 0x13872384, + 0x0b88c983, 0x0d898f84, 0x00202982, 0x23900383, 0x87008021, 0x83df8301, 0x86118d03, 0x863f880d, 0x8f35880f, 0x2160820f, 0x04830300, 0x1c220382, + 0x05820100, 0x4c000022, 0x09831182, 0x04001c24, 0x11823000, 0x0800082e, 0x00000200, 0xff007f00, 0xffffac20, 0x00220982, 0x09848100, 0xdf216682, + 0x843586d5, 0x06012116, 0x04400684, 0xa58120d7, 0x00b127d8, 0x01b88d01, 0x2d8685ff, 0xc100c621, 0xf4be0801, 0x9e011c01, 0x88021402, 0x1403fc02, + 0x9c035803, 0x1404de03, 0x50043204, 0xa2046204, 0x66051605, 0x1206bc05, 0xd6067406, 0x7e073807, 0x4e08ec07, 0x96086c08, 0x1009d008, 0x88094a09, + 0x800a160a, 0x560b040b, 0x2e0cc80b, 0xea0c820c, 0xa40d5e0d, 0x500eea0d, 0x280f960e, 0x1210b00f, 0xe0107410, 0xb6115211, 0x6e120412, 0x4c13c412, + 0xf613ac13, 0xae145814, 0x4015ea14, 0xa6158015, 0x1216b815, 0xc6167e16, 0x8e173417, 0x5618e017, 0xee18ba18, 0x96193619, 0x481ad419, 0xf01a9c1a, + 0xc81b5c1b, 0x4c1c041c, 0xea1c961c, 0x921d2a1d, 0x401ed21d, 0xe01e8e1e, 0x761f241f, 0xa61fa61f, 0x01821020, 0x8a202e34, 0xc820b220, 0x74211421, + 0xee219821, 0x86226222, 0x01820c23, 0x83238021, 0x23983c01, 0x24d823b0, 0x244a2400, 0x24902468, 0x250625ae, 0x25822560, 0x26f825f8, 0x82aa2658, + 0xd8be0801, 0x9a274027, 0x68280a28, 0x0e29a828, 0xb8292029, 0x362af829, 0x602a602a, 0x2a2b022b, 0xac2b5e2b, 0x202ce62b, 0x9a2c342c, 0x5c2d282d, + 0xaa2d782d, 0x262ee82d, 0x262fa62e, 0xf42fb62f, 0xc8305e30, 0xb4313e31, 0x9e321e32, 0x82331e33, 0x5c34ee33, 0x3a35ce34, 0xd4358635, 0x72362636, + 0x7637e636, 0x3a38d837, 0x1239a638, 0xae397439, 0x9a3a2e3a, 0x7c3b063b, 0x3a3ce83b, 0x223d963c, 0xec3d863d, 0xc63e563e, 0x9a3f2a3f, 0x6a401240, + 0x3641d040, 0x0842a241, 0x7a424042, 0xf042b842, 0xcc436243, 0x8a442a44, 0x5845ee44, 0xe245b645, 0xb4465446, 0x7a471447, 0x5448da47, 0x4049c648, + 0x15462400, 0x034d0808, 0x0b000700, 0x13000f00, 0x1b001700, 0x23001f00, 0x2b002700, 0x33002f00, 0x3b003700, 0x43003f00, 0x4b004700, 0x53004f00, + 0x5b005700, 0x63005f00, 0x6b006700, 0x73006f00, 0x7b007700, 0x83007f00, 0x8b008700, 0x00008f00, 0x15333511, 0x20039631, 0x20178205, 0xd3038221, + 0x20739707, 0x25008580, 0x028080fc, 0x05be8080, 0x04204a85, 0x05ce0685, 0x0107002a, 0x02000080, 0x00000400, 0x250d8b41, 0x33350100, 0x03920715, + 0x13820320, 0x858d0120, 0x0e8d0320, 0xff260d83, 0x00808000, 0x54820106, 0x04800223, 0x845b8c80, 0x41332059, 0x078b068f, 0x82000121, 0x82fe2039, + 0x84802003, 0x83042004, 0x23598a0e, 0x00180000, 0x03210082, 0x42ab9080, 0x73942137, 0x2013bb41, 0x8f978205, 0x2027a39b, 0x20b68801, 0x84b286fd, + 0x91c88407, 0x41032011, 0x11a51130, 0x15000027, 0x80ff8000, 0x11af4103, 0x841b0341, 0x8bd983fd, 0x9be99bc9, 0x8343831b, 0x21f1821f, 0xb58300ff, + 0x0f84e889, 0xf78a0484, 0x8000ff22, 0x0020eeb3, 0x14200082, 0x2130ef41, 0xeb431300, 0x4133200a, 0xd7410ecb, 0x9a07200b, 0x2027871b, 0x21238221, + 0xe7828080, 0xe784fd20, 0xe8848020, 0xfe808022, 0x08880d85, 0xba41fd20, 0x82248205, 0x85eab02a, 0x008022e7, 0x2cd74200, 0x44010021, 0xd34406eb, + 0x44312013, 0xcf8b0eef, 0x0d422f8b, 0x82332007, 0x0001212f, 0x8023cf82, 0x83000180, 0x820583de, 0x830682d4, 0x820020d4, 0x82dc850a, 0x20e282e9, + 0xb2ff85fe, 0x010327e9, 0x02000380, 0x0f440400, 0x0c634407, 0x68825982, 0x85048021, 0x260a825d, 0x010b0000, 0x4400ff00, 0x2746103f, 0x08d74209, + 0x4d440720, 0x0eaf4406, 0xc3441d20, 0x23078406, 0xff800002, 0x04845b83, 0x8d05b241, 0x1781436f, 0x6b8c87a5, 0x1521878e, 0x06474505, 0x01210783, + 0x84688c00, 0x8904828e, 0x441e8cf7, 0x0b270cff, 0x80008000, 0x45030003, 0xfb430fab, 0x080f4107, 0x410bf942, 0xd34307e5, 0x070d4207, 0x80800123, + 0x205d85fe, 0x849183fe, 0x20128404, 0x82809702, 0x00002217, 0x41839a09, 0x6b4408cf, 0x0733440f, 0x3b460720, 0x82798707, 0x97802052, 0x0000296f, + 0xff800004, 0x01800100, 0x0021ef89, 0x0a914625, 0x410a4d41, 0x00250ed4, 0x00050000, 0x056d4280, 0x210a7b46, 0x21481300, 0x46ed8512, 0x00210bd1, + 0x89718202, 0x21738877, 0x2b850001, 0x00220582, 0x87450a00, 0x0ddb4606, 0x41079b42, 0x9d420c09, 0x0b09420b, 0x8d820720, 0x9742fc84, 0x42098909, + 0x00241e0f, 0x00800014, 0x0b47da82, 0x0833442a, 0x49078d41, 0x2f450f13, 0x42278f17, 0x01200751, 0x22063742, 0x44808001, 0x20450519, 0x88068906, + 0x83fe2019, 0x4203202a, 0x1a941a58, 0x00820020, 0xe7a40e20, 0x420ce146, 0x854307e9, 0x0fcb4713, 0xff20a182, 0xfe209b82, 0x0c867f8b, 0x0021aea4, + 0x219fa40f, 0x7d41003b, 0x07194214, 0xbf440520, 0x071d4206, 0x6941a590, 0x80802309, 0x028900ff, 0xa9a4b685, 0xc5808021, 0x449b82ab, 0x152007eb, + 0x42134d46, 0x61440a15, 0x051e4208, 0x222b0442, 0x47001100, 0xfd412913, 0x17194714, 0x410f5b41, 0x02220773, 0x09428080, 0x21a98208, 0xd4420001, + 0x481c840d, 0x00232bc9, 0x42120000, 0xe74c261b, 0x149d4405, 0x07209d87, 0x410db944, 0x14421c81, 0x42fd2005, 0x80410bd2, 0x203d8531, 0x06874100, + 0x48256f4a, 0xcb420c95, 0x13934113, 0x44075d44, 0x044c0855, 0x00ff2105, 0xfe228185, 0x45448000, 0x22c5b508, 0x410c0000, 0x7b412087, 0x1bb74514, + 0x32429c85, 0x0a574805, 0x21208943, 0x8ba01300, 0x440dfb4e, 0x77431437, 0x245b4113, 0x200fb145, 0x41108ffe, 0x80203562, 0x00200082, 0x46362b42, + 0x1742178d, 0x4527830f, 0x0f830b2f, 0x4a138146, 0x802409a1, 0xfe8000ff, 0x94419982, 0x09294320, 0x04000022, 0x49050f4f, 0xcb470a63, 0x48032008, + 0x2b48067b, 0x85022008, 0x82638338, 0x00002209, 0x05af4806, 0x900e9f49, 0x84c5873f, 0x214285bd, 0x064900ff, 0x0c894607, 0x00000023, 0x4903820a, + 0x714319f3, 0x0749410c, 0x8a07a145, 0x02152507, 0xfe808000, 0x74490386, 0x8080211b, 0x0c276f82, 0x00018000, 0x48028003, 0x2b2315db, 0x43002f00, + 0x6f82142f, 0x44011521, 0x93510da7, 0x20e68508, 0x06494d80, 0x8e838020, 0x06821286, 0x124bff20, 0x25f3830c, 0x03800080, 0xe74a0380, 0x207b8715, + 0x876b861d, 0x4a152007, 0x07870775, 0xf6876086, 0x8417674a, 0x0a0021f2, 0x431c9743, 0x8d421485, 0x200b830b, 0x06474d03, 0x71828020, 0x04510120, + 0x42da8606, 0x1f831882, 0x001a0022, 0xff4d0082, 0x0b0f532c, 0x0d449b94, 0x4e312007, 0x074f12e7, 0x0bf3490b, 0xbb412120, 0x413f820a, 0xef490857, + 0x80002313, 0xe2830001, 0x6441fc20, 0x8b802006, 0x00012108, 0xfd201582, 0x492c9b48, 0x802014ff, 0x51084347, 0x0f4327f3, 0x17bf4a14, 0x201b7944, + 0x06964201, 0x134ffe20, 0x20d6830b, 0x25d78280, 0xfd800002, 0x05888000, 0x9318dc41, 0x21d282d4, 0xdb481800, 0x0dff542a, 0x45107743, 0xe14813f5, + 0x0f034113, 0x83135d45, 0x47b28437, 0xe4510e73, 0x21f58e06, 0x2b8400fd, 0x1041fcac, 0x08db4b0b, 0x421fdb41, 0xdf4b18df, 0x011d210a, 0x420af350, + 0x6e8308af, 0xac85cb86, 0x1e461082, 0x82b7a407, 0x411420a3, 0xa34130ab, 0x178f4124, 0x41139741, 0x86410d93, 0x82118511, 0x057243d8, 0x8941d9a4, + 0x3093480c, 0x4a13474f, 0xfb5016a9, 0x07ad4108, 0x4a0f9d42, 0xfe200fad, 0x4708aa41, 0x83482dba, 0x288f4d06, 0xb398c3bb, 0x44267b41, 0xb34439d7, + 0x0755410f, 0x200ebb45, 0x0f5f4215, 0x20191343, 0x06df5301, 0xf04c0220, 0x2ba64d07, 0x82050841, 0x430020ce, 0xa78f3627, 0x5213ff42, 0x2f970bc1, + 0x4305ab55, 0xa084111b, 0x450bac45, 0x5f4238b8, 0x010c2106, 0x0220ed82, 0x441bb344, 0x875010af, 0x0737480f, 0x490c5747, 0x0c840c03, 0x4c204b42, + 0x8ba905d7, 0x8b948793, 0x510c0c51, 0xfb4b24b9, 0x1b174107, 0x5709d74c, 0xd1410ca5, 0x079d480f, 0x201ff541, 0x06804780, 0x7d520120, 0x80002205, + 0x20a983fe, 0x47bb83fe, 0x1b8409b4, 0x81580220, 0x4e00202c, 0x4f41282f, 0x0eab4f17, 0x57471520, 0x0e0f4808, 0x8221e041, 0x3e1b4a8b, 0x4407175d, + 0x1b4b071f, 0x4a0f8b07, 0x174a0703, 0x0ba5411b, 0x430fb141, 0x0120057b, 0xfc20dd82, 0x4a056047, 0xf4850c0c, 0x01221982, 0x02828000, 0x1a5d088b, + 0x20094108, 0x8c0e3941, 0x4900200e, 0x7744434f, 0x200b870b, 0x0e4b5a33, 0x2b41f78b, 0x8b138307, 0x0b9f450b, 0x2406f741, 0xfd808001, 0x09475a00, + 0x84000121, 0x5980200e, 0x85450e5d, 0x832c8206, 0x4106831e, 0x00213814, 0x28b34810, 0x410c2f4b, 0x5f4a13d7, 0x0b2b4113, 0x6e43a883, 0x11174b05, + 0x4b066a45, 0xcc470541, 0x5000202b, 0xcb472f4b, 0x44b59f0f, 0xc5430b5b, 0x0d654907, 0x21065544, 0xd6828080, 0xfe201982, 0x8230ec4a, 0x120025c2, + 0x80ff8000, 0x4128d74d, 0x3320408b, 0x410a9f50, 0xdb822793, 0x822bd454, 0x61134b2e, 0x410b214a, 0xad4117c9, 0x0001211f, 0x4206854f, 0x4b430596, + 0x06bb5530, 0x2025cf46, 0x0ddd5747, 0x500ea349, 0x0f840fa7, 0x5213c153, 0x634e08d1, 0x0bbe4809, 0x59316e4d, 0x5b50053f, 0x203f6323, 0x5117eb46, + 0x94450a63, 0x246e410a, 0x63410020, 0x0bdb5f2f, 0x4233ab44, 0x39480757, 0x112d4a07, 0x7241118f, 0x000e2132, 0x9f286f41, 0x0f8762c3, 0x33350723, + 0x094e6415, 0x2010925f, 0x067252fe, 0xd0438020, 0x63a68225, 0x11203a4f, 0x480e6360, 0x5748131f, 0x079b521f, 0x200e2f43, 0x864b8315, 0x113348e7, + 0x85084e48, 0x06855008, 0x5880fd21, 0x7c420925, 0x0c414824, 0x37470c86, 0x1b8b422b, 0x5b0a8755, 0x23410c21, 0x0b83420b, 0x5a082047, 0xf482067f, + 0xa80b4c47, 0x0c0021cf, 0x20207b42, 0x0fb74100, 0x420b8744, 0xeb43076f, 0x0f6f420b, 0x4261fe20, 0x439aa00c, 0x215034e3, 0x0ff9570f, 0x4b1f2d5d, + 0x2d5d0c6f, 0x09634d0b, 0x1f51b8a0, 0x620f200c, 0xaf681e87, 0x24f94d07, 0x4e0f4945, 0xfe200c05, 0x22139742, 0x57048080, 0x23950c20, 0x97601585, + 0x4813201f, 0xad620523, 0x200f8f0f, 0x9e638f15, 0x00002181, 0x41342341, 0x0f930f0b, 0x210b4b62, 0x978f0001, 0xfe200f84, 0x8425c863, 0x2704822b, + 0x80000a00, 0x00038001, 0x610e9768, 0x834514bb, 0x0bc3430f, 0x2107e357, 0x80848080, 0x4400fe21, 0x2e410983, 0x00002a1a, 0x00000700, 0x800380ff, + 0x0fdf5800, 0x59150021, 0xd142163d, 0x0c02410c, 0x01020025, 0x65800300, 0x00240853, 0x1d333501, 0x15220382, 0x35420001, 0x44002008, 0x376406d7, + 0x096f6b19, 0x480bc142, 0x8f4908a7, 0x211f8b1f, 0x9e830001, 0x0584fe20, 0x4180fd21, 0x11850910, 0x8d198259, 0x000021d4, 0x5a08275d, 0x275d1983, + 0x06d9420e, 0x9f08b36a, 0x0f7d47b5, 0x8d8a2f8b, 0x4c0e0b57, 0xe7410e17, 0x42d18c1a, 0xb351087a, 0x1ac36505, 0x4b4a2f20, 0x0b9f450d, 0x430beb53, + 0xa7881015, 0xa5826a83, 0x80200f82, 0x86185a65, 0x4100208e, 0x176c3367, 0x0fe7650b, 0x4a17ad4b, 0x0f4217ed, 0x112e4206, 0x41113a42, 0xf7423169, + 0x0cb34737, 0x560f8b46, 0xa75407e5, 0x5f01200f, 0x31590c48, 0x80802106, 0x42268841, 0x0020091e, 0x4207ef64, 0x69461df7, 0x138d4114, 0x820f5145, + 0x53802090, 0xff200529, 0xb944b183, 0x417e8505, 0x00202561, 0x15210082, 0x42378200, 0x9b431cc3, 0x004f220d, 0x0dd54253, 0x4213f149, 0x7d41133b, + 0x42c9870b, 0x802010f9, 0x420b2c42, 0x8f441138, 0x267c4408, 0x600cb743, 0x8f4109d3, 0x05ab701d, 0x83440020, 0x3521223f, 0x0b794733, 0xfb62fe20, + 0x4afd2010, 0xaf410ae7, 0x25ce8525, 0x01080000, 0x7b6b0000, 0x0973710b, 0x82010021, 0x49038375, 0x33420767, 0x052c4212, 0x58464b85, 0x41fe2005, + 0x50440c27, 0x000c2209, 0x1cb36b80, 0x9b06df44, 0x0f93566f, 0x52830220, 0xfe216e8d, 0x200f8200, 0x0fb86704, 0xb057238d, 0x050b5305, 0x7217eb47, + 0xbd410b6b, 0x0f214610, 0x871f9956, 0x1e91567e, 0x2029b741, 0x20008200, 0x18b7410a, 0x27002322, 0x41095543, 0x0f8f0fb3, 0x41000121, 0x889d111c, + 0x14207b82, 0x00200382, 0x73188761, 0x475013a7, 0x6e33200c, 0x234e0ea3, 0x9b138313, 0x08e54d17, 0x9711094e, 0x2ee74311, 0x4908875e, 0xd75d1f1f, + 0x19ab5238, 0xa2084d48, 0x63a7a9b3, 0x55450b83, 0x0fd74213, 0x440d814c, 0x4f481673, 0x05714323, 0x13000022, 0x412e1f46, 0xdf493459, 0x21c7550f, + 0x8408215f, 0x201d49cb, 0xb1103043, 0x0f0d65d7, 0x452b8d41, 0x594b0f8d, 0x0b004605, 0xb215eb46, 0x000a24d7, 0x47000080, 0x002118cf, 0x06436413, + 0x420bd750, 0x2b500743, 0x076a470c, 0x4105c050, 0xd942053f, 0x0d00211a, 0x5f44779c, 0x0ce94805, 0x51558186, 0x14a54c0b, 0x49082b41, 0x0a4b0888, + 0x8080261f, 0x0d000000, 0x20048201, 0x1deb6a03, 0x420cb372, 0x07201783, 0x4306854d, 0x8b830c59, 0x59093c74, 0x0020250f, 0x67070f4a, 0x2341160b, + 0x00372105, 0x431c515d, 0x554e17ef, 0x0e5d6b05, 0x41115442, 0xb74a1ac1, 0x2243420a, 0x5b4f878f, 0x7507200f, 0x384b086f, 0x09d45409, 0x0020869a, + 0x12200082, 0xab460382, 0x10075329, 0x54138346, 0xaf540fbf, 0x1ea75413, 0x9a0c9e54, 0x0f6b44c1, 0x41000021, 0x47412a4f, 0x07374907, 0x5310bf76, + 0xff2009b4, 0x9a09a64c, 0x8200208d, 0x34c34500, 0x970fe141, 0x1fd74b0f, 0x440a3850, 0x206411f0, 0x27934609, 0x470c5d41, 0x555c2947, 0x1787540f, + 0x6e0f234e, 0x7d540a1b, 0x1d736b08, 0x0026a088, 0x80000e00, 0x9b5200ff, 0x08ef4318, 0x450bff77, 0x1d4d0b83, 0x081f7006, 0xcb691b86, 0x4b022008, + 0xc34b0b33, 0x1d0d4a0c, 0x8025a188, 0x0b000000, 0x52a38201, 0xbf7d0873, 0x0c234511, 0x8f0f894a, 0x4101200f, 0x0c880c9d, 0x2b418ea1, 0x06c74128, + 0x66181341, 0x7b4c0bb9, 0x0c06630b, 0xfe200c87, 0x9ba10882, 0x27091765, 0x01000008, 0x02800380, 0x48113f4e, 0x29430cf5, 0x09a75a0b, 0x31618020, + 0x6d802009, 0x61840e33, 0x8208bf51, 0x0c637d61, 0x7f092379, 0x4f470f4b, 0x1797510c, 0x46076157, 0xf5500fdf, 0x0f616910, 0x1171fe20, 0x82802006, + 0x08696908, 0x41127a4c, 0x3f4a15f3, 0x01042607, 0x0200ff00, 0x1cf77700, 0xff204185, 0x00235b8d, 0x43100000, 0x3b22243f, 0x3b4d3f00, 0x0b937709, + 0xad42f18f, 0x0b1f420f, 0x51084b43, 0x8020104a, 0xb557ff83, 0x052b7f2a, 0x0280ff22, 0x250beb78, 0x00170013, 0xbf6d2500, 0x07db760e, 0x410e2b7f, + 0x00230e4f, 0x49030000, 0x0582055b, 0x07000326, 0x00000b00, 0x580bcd46, 0x00200cdd, 0x57078749, 0x8749160f, 0x0f994f0a, 0x41134761, 0x01200b31, + 0xeb796883, 0x0b41500b, 0x0e90b38e, 0x202e7b51, 0x05d95801, 0x41080570, 0x1d530fc9, 0x0b937a0f, 0xaf8eb387, 0xf743b98f, 0x07c74227, 0x80000523, + 0x0fcb4503, 0x430ca37b, 0x7782077f, 0x8d0a9947, 0x08af4666, 0xeb798020, 0x6459881e, 0xc3740bbf, 0x0feb6f0b, 0x20072748, 0x052b6102, 0x435e0584, + 0x7d088308, 0x03200afd, 0x92109e41, 0x28aa8210, 0x80001500, 0x80030000, 0x0fdb5805, 0x209f4018, 0xa7418d87, 0x0aa3440f, 0x20314961, 0x073a52ff, + 0x6108505d, 0x43181051, 0x00223457, 0xe7820500, 0x50028021, 0x81410d33, 0x063d7108, 0xdb41af84, 0x4d888205, 0x00201198, 0x463d835f, 0x152106d7, + 0x0a355a33, 0x6917614e, 0x75411f4d, 0x184b8b07, 0x1809c344, 0x21091640, 0x0b828000, 0x42808021, 0x26790519, 0x86058605, 0x2428422d, 0x22123b42, + 0x42000080, 0xf587513b, 0x7813677b, 0xaf4d139f, 0x00ff210c, 0x5e0a1d57, 0x3b421546, 0x01032736, 0x02000380, 0x41180480, 0x2f420f07, 0x0c624807, + 0x00000025, 0x18000103, 0x83153741, 0x430120c3, 0x042106b2, 0x088d4d00, 0x2f830620, 0x1810434a, 0x18140345, 0x8507fb41, 0x5ee582ea, 0x0023116c, + 0x8d000600, 0x053b56af, 0xa6554fa2, 0x0d704608, 0x40180d20, 0x47181a43, 0xd37b07ff, 0x0b79500c, 0x420fd745, 0x47450bd9, 0x8471830a, 0x095a777e, + 0x84137542, 0x82002013, 0x2f401800, 0x0007213b, 0x4405e349, 0x0d550ff3, 0x16254c0c, 0x820ffe4a, 0x0400218a, 0x89066f41, 0x106b414f, 0xc84d0120, + 0x80802206, 0x0c9a4b03, 0x00100025, 0x68000200, 0x9d8c2473, 0x44134344, 0xf36a0f33, 0x4678860f, 0x1b440a25, 0x41988c0a, 0x80201879, 0x43079b5e, + 0x4a18080b, 0x0341190b, 0x1259530c, 0x43251552, 0x908205c8, 0x0cac4018, 0x86000421, 0x0e504aa2, 0x0020b891, 0xfb450082, 0x51132014, 0x8f5205f3, + 0x35052108, 0x8505cb59, 0x0f6d4f70, 0x82150021, 0x29af5047, 0x4f004b24, 0x75795300, 0x1b595709, 0x460b6742, 0xbf4b0f0d, 0x5743870b, 0xcb6d1461, + 0x08f64505, 0x4e05ab6c, 0x334126c3, 0x0bcb6b0d, 0x1811034d, 0x4111ef4b, 0x814f1ce5, 0x20af8227, 0x07fd7b80, 0x41188e84, 0xef410f33, 0x80802429, + 0x410d0000, 0xa34205ab, 0x76b7881c, 0xff500b89, 0x0741430f, 0x20086f4a, 0x209d8200, 0x234c18fd, 0x05d4670a, 0x4509af51, 0x9642078d, 0x189e831d, + 0x7c1cc74b, 0xcd4c07b9, 0x0e7c440f, 0x8b7b0320, 0x21108210, 0xc76c8080, 0x03002106, 0x6b23bf41, 0xc549060b, 0x7946180b, 0x0ff7530f, 0x17ad4618, + 0x200ecd45, 0x208c83fd, 0x5e0488fe, 0x032009c6, 0x420d044e, 0x0d8f0d7f, 0x00820020, 0x18001021, 0x6d273b45, 0xfd4c0c93, 0xcf451813, 0x0fe5450f, + 0x5a47c382, 0x820a8b0a, 0x282b4998, 0x410a8b5b, 0x4b232583, 0x54004f00, 0x978f0ce3, 0x500f1944, 0xa95f1709, 0x0280220b, 0x05ba7080, 0xa1530682, + 0x06324c13, 0x91412582, 0x05536e2c, 0x63431020, 0x0f434706, 0x8c11374c, 0x176143d7, 0x4d0f454c, 0xd3680bed, 0x0bee4d17, 0x212b9a41, 0x0f530a00, + 0x140d531c, 0x43139143, 0x95610e8d, 0x0f094415, 0x4205fb56, 0x1b4205cf, 0x17015225, 0x5e0c477f, 0xaf6e0aeb, 0x0ff36218, 0x04849a84, 0x0a454218, + 0x9c430420, 0x23c6822b, 0x04000102, 0x45091b4b, 0xf05f0955, 0x82802007, 0x421c2023, 0x5218282b, 0x7b53173f, 0x0fe7480c, 0x74173b7f, 0x47751317, + 0x634d1807, 0x0f6f430f, 0x24086547, 0xfc808002, 0x0b3c7f80, 0x10840120, 0x188d1282, 0x20096b43, 0x0fc24403, 0x00260faf, 0x0180000b, 0x3f500280, + 0x18002019, 0x450b4941, 0xf3530fb9, 0x18002010, 0x8208a551, 0x06234d56, 0xcb58a39b, 0xc3421805, 0x1313461e, 0x0f855018, 0xd34b0120, 0x6cfe2008, + 0x574f0885, 0x09204114, 0x07000029, 0x00008000, 0x44028002, 0x01420f57, 0x10c95c10, 0x11184c18, 0x80221185, 0x7f421e00, 0x00732240, 0x09cd4977, + 0x6d0b2b42, 0x4f180f8f, 0x8f5a0bcb, 0x9b0f830f, 0x0fb9411f, 0x230b5756, 0x00fd8080, 0x82060745, 0x000121d5, 0x8e0fb277, 0x4a8d4211, 0x24061c53, + 0x04000007, 0x12275280, 0x430c954c, 0x80201545, 0x200f764f, 0x20008200, 0x20ce8308, 0x09534f02, 0x660edf64, 0x73731771, 0xe7411807, 0x20a2820c, + 0x13b64404, 0x8f5d6682, 0x1d6b4508, 0x0cff4d18, 0x3348c58f, 0x0fc34c07, 0x31558b84, 0x8398820f, 0x17514712, 0x240b0e46, 0x80000a00, 0x093b4502, + 0x420f9759, 0xa54c0bf1, 0x0f2b470c, 0x410d314b, 0x2584170c, 0x73b30020, 0xb55fe782, 0x204d8410, 0x08e043fe, 0x4f147e41, 0x022008ab, 0x4b055159, + 0x2950068f, 0x00022208, 0x48511880, 0x82002009, 0x00112300, 0x634dff00, 0x24415f27, 0x180f6d43, 0x4d0b5d45, 0x4d5f05ef, 0x01802317, 0x56188000, + 0xa7840807, 0xc6450220, 0x21ca8229, 0x4b781a00, 0x3359182c, 0x0cf3470f, 0x180bef46, 0x420b0354, 0xff470b07, 0x4515200a, 0x9758239b, 0x4a80200c, + 0xd2410a26, 0x05fb4a08, 0x4b05e241, 0x03200dc9, 0x92290941, 0x00002829, 0x00010900, 0x5b020001, 0x23201363, 0x460d776a, 0xef530fdb, 0x209a890c, + 0x13fc4302, 0x00008024, 0xc4820104, 0x08820220, 0x20086b5b, 0x18518700, 0x8408d349, 0x0da449a1, 0x00080024, 0x7b690280, 0x4c438b1a, 0x01220f63, + 0x4c878000, 0x5c149c53, 0xfb430868, 0x2f56181e, 0x0ccf7b1b, 0x0f075618, 0x2008e347, 0x14144104, 0x00207f83, 0x00207b82, 0x201adf47, 0x16c35a13, + 0x540fdf47, 0x802006c8, 0x5418f185, 0x29430995, 0x00002419, 0x58001600, 0x5720316f, 0x4d051542, 0x4b7b1b03, 0x138f4707, 0xb747b787, 0x4aab8213, + 0x058305fc, 0x20115759, 0x82128401, 0x0a0b44e8, 0x46800121, 0xe64210d0, 0x82129312, 0x4bffdffe, 0x3b41171b, 0x9b27870f, 0x808022ff, 0x085c68fe, + 0x41800021, 0x01410b20, 0x001a213a, 0x47480082, 0x11374e12, 0x56130b4c, 0xdf4b0c65, 0x0b0f590b, 0x0f574c18, 0x830feb4b, 0x075f480f, 0x480b4755, + 0x40490b73, 0x80012206, 0x09d74280, 0x80fe8022, 0x80210e86, 0x056643ff, 0x10820020, 0x420b2646, 0x0b58391a, 0xd74c1808, 0x078b4e22, 0x2007f55f, + 0x4b491807, 0x83802017, 0x65aa82a7, 0x3152099e, 0x068b7616, 0x9b431220, 0x09bb742c, 0x500e376c, 0x8342179b, 0x0a4d5d0f, 0x8020a883, 0x180cd349, + 0x2016bb4b, 0x14476004, 0x84136c43, 0x08cf7813, 0x4f4c0520, 0x156f420f, 0x20085f42, 0x6fd3be03, 0xd4d30803, 0xa7411420, 0x004b222c, 0x0d3b614f, + 0x3f702120, 0x1393410a, 0x8f132745, 0x47421827, 0x41e08209, 0xb05e2bb9, 0x18b7410c, 0x18082647, 0x4107a748, 0xeb8826bf, 0x0ca76018, 0x733ecb41, + 0xd0410d83, 0x43ebaf2a, 0x0420067f, 0x721dab4c, 0x472005bb, 0x4105d341, 0x334844cb, 0x20dba408, 0x47d6ac00, 0x034e3aef, 0x0f8f421b, 0x930f134d, + 0x3521231f, 0xb7421533, 0x42f5ad0a, 0x1e961eaa, 0x17000022, 0x4c367b50, 0x7d491001, 0x0bf5520f, 0x4c18fda7, 0xb8460c55, 0x83fe2005, 0x00fe25b9, + 0x80000180, 0x9e751085, 0x261b5c12, 0x82110341, 0x001123fb, 0x4518fe80, 0xf38c2753, 0x6d134979, 0x295107a7, 0xaf5f180f, 0x0fe3660c, 0x180b6079, + 0x2007bd5f, 0x9aab9103, 0x2f4d1811, 0x05002109, 0x44254746, 0x1d200787, 0x450bab75, 0x4f180f57, 0x4f181361, 0x3b831795, 0xeb4b0120, 0x0b734805, + 0x84078f48, 0x2e1b47bc, 0x00203383, 0xaf065f45, 0x831520d7, 0x130f51a7, 0x1797bf97, 0x2b47d783, 0x18fe2005, 0x4a18a44f, 0xa64d086d, 0x1ab0410d, + 0x6205a258, 0xdbab069f, 0x4f06f778, 0xa963081d, 0x133b670a, 0x8323d141, 0x13195b23, 0x530f5e70, 0xe5ad0824, 0x58001421, 0x1f472b4b, 0x47bf410c, + 0x82000121, 0x83fe20cb, 0x07424404, 0x68068243, 0xd7ad0d3d, 0x00010d26, 0x80020000, 0x4a1c6f43, 0x23681081, 0x10a14f13, 0x8a070e57, 0x430a848f, + 0x7372243e, 0x4397a205, 0xb56c1021, 0x43978f0f, 0x64180505, 0x99aa0ff2, 0x0e000022, 0x20223341, 0x094b4f37, 0x074a3320, 0x2639410a, 0xfe208e84, + 0x8b0e0048, 0x508020a3, 0x9e4308fe, 0x073f4115, 0xe3480420, 0x0c9b5f1b, 0x7c137743, 0x9a95185b, 0x6122b148, 0x979b08df, 0x0fe36c18, 0x48109358, + 0x23441375, 0x0ffd5c0b, 0x180fc746, 0x2011d157, 0x07e95702, 0x58180120, 0x18770ac3, 0x51032008, 0x7d4118e3, 0x80802315, 0x3b4c1900, 0xbb5a1830, + 0x0ceb6109, 0x5b0b3d42, 0x4f181369, 0x4f180b8d, 0x4f180f75, 0x355a1b81, 0x200d820d, 0x18e483fd, 0x4528854f, 0x89420846, 0x1321411f, 0x44086b60, + 0x07421d77, 0x107d4405, 0x4113fd41, 0x5a181bf1, 0x4f180db3, 0x8021128f, 0x20f68280, 0x44a882fe, 0x334d249a, 0x052f6109, 0x1520c3a7, 0xef4eb783, + 0x4ec39b1b, 0xc4c90ee7, 0x20060b4d, 0x256f4905, 0x4d0cf761, 0xcf9b1f13, 0xa213d74e, 0x0e1145d4, 0x50135b42, 0xcb4e398f, 0x20d79f27, 0x08865d80, + 0x186d5018, 0xa90f7142, 0x067342d7, 0x3f450420, 0x65002021, 0xe3560771, 0x24d38f23, 0x15333531, 0x0eb94d01, 0x451c9f41, 0x384322fb, 0x00092108, + 0x19af6b18, 0x6e0c6f5a, 0xbd770bfb, 0x22bb7718, 0x20090f57, 0x25e74204, 0x4207275a, 0xdb5408ef, 0x1769450f, 0x1b1b5518, 0x210b1f57, 0x5e4c8001, + 0x55012006, 0x802107f1, 0x0a306a80, 0x45808021, 0x0d850b88, 0x31744f18, 0x1808ec54, 0x2009575b, 0x45ffa505, 0x1b420c73, 0x180f9f0f, 0x4a0cf748, + 0x501805b2, 0x00210f40, 0x4d118f80, 0xd6823359, 0x072b5118, 0x314ad7aa, 0x8fc79f08, 0x45d78b1f, 0xfe20058f, 0x23325118, 0x7b54d9b5, 0x9fc38f46, + 0x10bb410f, 0x41077b42, 0xc1410faf, 0x27cf441d, 0x46051b4f, 0x04200683, 0x2121d344, 0x8f530043, 0x8fcf9f0e, 0x21df8c1f, 0x50188000, 0x5d180e52, + 0xfd201710, 0x4405c341, 0xd68528e3, 0x20071f6b, 0x1b734305, 0x6b080957, 0x7d422b1f, 0x67002006, 0x7f8317b1, 0x2024cb48, 0x08676e00, 0x8749a39b, + 0x18132006, 0x410a6370, 0x8f490b47, 0x7e1f8f13, 0x551805c3, 0x4c180915, 0xfe200e2f, 0x244d5d18, 0x270bcf44, 0xff000019, 0x04800380, 0x5f253342, + 0xff520df7, 0x13274c18, 0x5542dd93, 0x0776181b, 0xf94a1808, 0x084a4c0c, 0x4308ea5b, 0xde831150, 0x7900fd21, 0x00492c1e, 0x060f4510, 0x17410020, + 0x0ce74526, 0x6206b341, 0x1f561083, 0x9d6c181b, 0x08a0500e, 0x112e4118, 0x60000421, 0xbf901202, 0x4408e241, 0xc7ab0513, 0xb40f0950, 0x055943c7, + 0x4f18ff20, 0xc9ae1cad, 0x32b34f18, 0x7a180120, 0x3d520a05, 0x53d1b40a, 0x80200813, 0x1b815018, 0x832bf86f, 0x67731847, 0x297f4308, 0x6418d54e, + 0x734213f7, 0x056b4b27, 0xdba5fe20, 0x1828aa4e, 0x2031a370, 0x06cb6101, 0x2040ad41, 0x07365300, 0x2558d985, 0x83fe200c, 0x0380211c, 0x542c4743, + 0x052006b7, 0x6021df45, 0x897b0707, 0x18d3c010, 0x20090e70, 0x1d5843ff, 0x540a0e44, 0x002126c5, 0x322f7416, 0x636a5720, 0x0f317409, 0x610fe159, + 0x294617e7, 0x08555213, 0x2006a75d, 0x6cec84fd, 0xfb5907be, 0x3a317405, 0x83808021, 0x180f20ea, 0x4626434a, 0x531818e3, 0xdb59172d, 0x0cbb460c, + 0x2013d859, 0x18b94502, 0x8f46188d, 0x77521842, 0x0a184e38, 0x9585fd20, 0x6a180684, 0xc64507e9, 0x51cbb230, 0xd3440cf3, 0x17ff6a0f, 0x450f5b42, + 0x276407c1, 0x4853180a, 0x21ccb010, 0xcf580013, 0x0c15442d, 0x410a1144, 0x1144359d, 0x5cfe2006, 0xa1410a43, 0x2bb64519, 0x2f5b7618, 0xb512b745, + 0x0cfd6fd1, 0x42089f59, 0xb8450c70, 0x0000232d, 0x50180900, 0xb9491ae3, 0x0fc37610, 0x01210f83, 0x0f3b4100, 0xa01b2742, 0x0ccd426f, 0x6e8f6f94, + 0x9c808021, 0xc7511870, 0x17c74b08, 0x9b147542, 0x44fe2079, 0xd5480c7e, 0x95ef861d, 0x101b597b, 0xf5417594, 0x9f471808, 0x86868d0e, 0x3733491c, + 0x690f4d6d, 0x43440b83, 0x1ba94c0b, 0x660cd16b, 0x802008ae, 0x74126448, 0xcb4f38a3, 0x2cb74b0b, 0x47137755, 0xe3971777, 0x1b5d0120, 0x057a4108, + 0x6e08664d, 0x17421478, 0x11af4208, 0x850c3f42, 0x08234f0c, 0x4321eb4a, 0xf3451095, 0x0f394e0f, 0x4310eb45, 0xc09707b1, 0x54431782, 0xaec08d1d, + 0x0f434dbb, 0x9f0c0b45, 0x0a3b4dbb, 0x4618bdc7, 0x536032eb, 0x17354213, 0x4d134169, 0xc7a30c2f, 0x4e254342, 0x174332cf, 0x43cdae17, 0x6b4706e4, + 0x0e16430d, 0x530b5542, 0x2f7c26bb, 0x13075f31, 0x43175342, 0x60181317, 0x6550114e, 0x28624710, 0x58070021, 0x59181683, 0x2d540cf5, 0x05d5660c, + 0x20090c7b, 0x0e157e02, 0x8000ff2b, 0x14000080, 0x80ff8000, 0x27137e03, 0x336a4b20, 0x0f817107, 0x13876e18, 0x730f2f7e, 0x2f450b75, 0x6d02200b, + 0x6d66094c, 0x4b802009, 0x15820a02, 0x2f45fe20, 0x5e032006, 0x00202fd9, 0x450af741, 0xeb412e0f, 0x0ff3411f, 0x420a8b65, 0xf7410eae, 0x1c664810, + 0x540e1145, 0xbfa509f3, 0x42302f58, 0x80200c35, 0xcb066c47, 0x4b1120c1, 0x41492abb, 0x34854110, 0xa7097b72, 0x251545c7, 0x4b2c7f56, 0xc5b40bab, + 0x940cd54e, 0x2e6151c8, 0x09f35f18, 0x4b420420, 0x09677121, 0x8f24f357, 0x1b5418e1, 0x08915a1f, 0x3143d894, 0x22541805, 0x1b9b4b0e, 0x8c0d3443, + 0x1400240d, 0x18ff8000, 0x582e6387, 0xf99b2b3b, 0x8807a550, 0x17a14790, 0x2184fd20, 0x5758fe20, 0x2354882c, 0x15000080, 0x5e056751, 0x334c2c2f, + 0x97c58f0c, 0x1fd7410f, 0x0d4d4018, 0x4114dc41, 0x04470ed6, 0x0dd54128, 0x00820020, 0x02011523, 0x22008700, 0x86480024, 0x0001240a, 0x8682001a, + 0x0002240b, 0x866c000e, 0x8a03200b, 0x8a042017, 0x0005220b, 0x22218614, 0x84060000, 0x86012017, 0x8212200f, 0x250b8519, 0x000d0001, 0x0b850031, + 0x07000224, 0x0b862600, 0x11000324, 0x0b862d00, 0x238a0420, 0x0a000524, 0x17863e00, 0x17840620, 0x01000324, 0x57820904, 0x0b85a783, 0x0b85a785, + 0x0b85a785, 0x22000325, 0x85007a00, 0x85a7850b, 0x85a7850b, 0x22a7850b, 0x82300032, 0x00342201, 0x0805862f, 0x35003131, 0x54207962, 0x74736972, + 0x47206e61, 0x6d6d6972, 0x65527265, 0x616c7567, 0x58545472, 0x6f725020, 0x43796767, 0x6e61656c, 0x30325454, 0x822f3430, 0x35313502, 0x79006200, + 0x54002000, 0x69007200, 0x74007300, 0x6e006100, 0x47200f82, 0x6d240f84, 0x65006d00, 0x52200982, 0x67240582, 0x6c007500, 0x72201d82, 0x54222b82, + 0x23825800, 0x19825020, 0x67006f22, 0x79220182, 0x1b824300, 0x3b846520, 0x1f825420, 0x41000021, 0x1422099b, 0x0b410000, 0x87088206, 0x01012102, + 0x78080982, 0x01020101, 0x01040103, 0x01060105, 0x01080107, 0x010a0109, 0x010c010b, 0x010e010d, 0x0110010f, 0x01120111, 0x01140113, 0x01160115, + 0x01180117, 0x011a0119, 0x011c011b, 0x011e011d, 0x0020011f, 0x00040003, 0x00060005, 0x00080007, 0x000a0009, 0x000c000b, 0x000e000d, 0x0010000f, + 0x00120011, 0x00140013, 0x00160015, 0x00180017, 0x001a0019, 0x001c001b, 0x001e001d, 0x08bb821f, 0x22002142, 0x24002300, 0x26002500, 0x28002700, + 0x2a002900, 0x2c002b00, 0x2e002d00, 0x30002f00, 0x32003100, 0x34003300, 0x36003500, 0x38003700, 0x3a003900, 0x3c003b00, 0x3e003d00, 0x40003f00, + 0x42004100, 0x4b09f382, 0x00450044, 0x00470046, 0x00490048, 0x004b004a, 0x004d004c, 0x004f004e, 0x00510050, 0x00530052, 0x00550054, 0x00570056, + 0x00590058, 0x005b005a, 0x005d005c, 0x005f005e, 0x01610060, 0x01220121, 0x01240123, 0x01260125, 0x01280127, 0x012a0129, 0x012c012b, 0x012e012d, + 0x0130012f, 0x01320131, 0x01340133, 0x01360135, 0x01380137, 0x013a0139, 0x013c013b, 0x013e013d, 0x0140013f, 0x00ac0041, 0x008400a3, 0x00bd0085, + 0x00e80096, 0x008e0086, 0x009d008b, 0x00a400a9, 0x008a00ef, 0x008300da, 0x00f20093, 0x008d00f3, 0x00880097, 0x00de00c3, 0x009e00f1, 0x00f500aa, + 0x00f600f4, 0x00ad00a2, 0x00c700c9, 0x006200ae, 0x00900063, 0x00cb0064, 0x00c80065, 0x00cf00ca, 0x00cd00cc, 0x00e900ce, 0x00d30066, 0x00d100d0, + 0x006700af, 0x009100f0, 0x00d400d6, 0x006800d5, 0x00ed00eb, 0x006a0089, 0x006b0069, 0x006c006d, 0x00a0006e, 0x0071006f, 0x00720070, 0x00750073, + 0x00760074, 0x00ea0077, 0x007a0078, 0x007b0079, 0x007c007d, 0x00a100b8, 0x007e007f, 0x00810080, 0x00ee00ec, 0x6e750eba, 0x646f6369, 0x78302365, + 0x31303030, 0x32200e8d, 0x33200e8d, 0x34200e8d, 0x35200e8d, 0x36200e8d, 0x37200e8d, 0x38200e8d, 0x39200e8d, 0x61200e8d, 0x62200e8d, 0x63200e8d, + 0x64200e8d, 0x65200e8d, 0x66200e8d, 0x31210e8c, 0x8d0e8d30, 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, + 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, 0x8d3120ef, 0x66312def, 0x6c656406, 0x04657465, 0x6f727545, 0x3820ec8c, 0x3820ec8d, + 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, 0x3820ec8d, + 0x3820ec8d, 0x200ddc41, 0x0ddc4139, 0xef8d3920, 0xef8d3920, 0xef8d3920, 0xef8d3920, 0xef8d3920, 0xef8d3920, 0xef8d3920, 0xef8d3920, 0xef8d3920, + 0xef8d3920, 0xef8d3920, 0xef8d3920, 0xef8d3920, 0xef8d3920, 0x00663923, 0x48fa0500, 0x00f762f9, }; static void GetDefaultCompressedFontDataTTF(const void** ttf_compressed_data, unsigned int* ttf_compressed_size) diff --git a/3rdparty/ocornut-imgui/imgui.h b/3rdparty/ocornut-imgui/imgui.h index dbea1bc0a..49bc50c25 100644 --- a/3rdparty/ocornut-imgui/imgui.h +++ b/3rdparty/ocornut-imgui/imgui.h @@ -1,4 +1,4 @@ -// ImGui library v1.35 +// ImGui library v1.38 WIP // See .cpp file for documentation. // See ImGui::ShowTestWindow() for sample code. // Read 'Programmer guide' in .cpp for notes on how to setup ImGui in your codebase. @@ -9,9 +9,11 @@ #include "imconfig.h" // User-editable configuration file #include // FLT_MAX #include // va_list -#include // ptrdiff_t -#include // NULL, malloc -#include // memset, memmove +#include // ptrdiff_t, NULL +#include // NULL, malloc, free, qsort, atoi +#include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp + +#define IMGUI_VERSION "1.38 WIP" // Define assertion handler. #ifndef IM_ASSERT @@ -41,19 +43,20 @@ typedef int ImGuiCol; // enum ImGuiCol_ typedef int ImGuiStyleVar; // enum ImGuiStyleVar_ typedef int ImGuiKey; // enum ImGuiKey_ typedef int ImGuiColorEditMode; // enum ImGuiColorEditMode_ +typedef int ImGuiMouseCursor; // enum ImGuiMouseCursor_ typedef int ImGuiWindowFlags; // enum ImGuiWindowFlags_ -typedef int ImGuiSetCond; // enum ImGuiSetCondition_ +typedef int ImGuiSetCond; // enum ImGuiSetCond_ typedef int ImGuiInputTextFlags; // enum ImGuiInputTextFlags_ -struct ImGuiTextEditCallbackData; // for advanced uses of InputText() +struct ImGuiTextEditCallbackData; // for advanced uses of InputText() typedef int (*ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data); struct ImVec2 { float x, y; - ImVec2() {} + ImVec2() { x = y = 0.0f; } ImVec2(float _x, float _y) { x = _x; y = _y; } -#ifdef IM_VEC2_CLASS_EXTRA +#ifdef IM_VEC2_CLASS_EXTRA // Define constructor and implicit cast operators to convert back<>forth from your math types and ImVec2. IM_VEC2_CLASS_EXTRA #endif }; @@ -61,10 +64,10 @@ struct ImVec2 struct ImVec4 { float x, y, z, w; - ImVec4() {} + ImVec4() { x = y = z = w = 0.0f; } ImVec4(float _x, float _y, float _z, float _w) { x = _x; y = _y; z = _z; w = _w; } -#ifdef IM_VEC4_CLASS_EXTRA +#ifdef IM_VEC4_CLASS_EXTRA // Define constructor and implicit cast operators to convert back<>forth from your math types and ImVec4. IM_VEC4_CLASS_EXTRA #endif }; @@ -76,7 +79,7 @@ namespace ImGui IMGUI_API void MemFree(void* ptr); } -// std::vector<> like class to avoid dragging dependencies (also: windows implementation of STL with debug enabled is absurdly slow, so let's bypass it so our code runs fast in debug). +// std::vector<> like class to avoid dragging dependencies (also: windows implementation of STL with debug enabled is absurdly slow, so let's bypass it so our code runs fast in debug). // Use '#define ImVector std::vector' if you want to use the STL type or your own type. // Our implementation does NOT call c++ constructors! because the data types we use don't need them (but that could be added as well). Only provide the minimum functionalities we need. #ifndef ImVector @@ -117,14 +120,14 @@ public: inline void swap(ImVector& rhs) { const size_t rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; const size_t rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } inline void resize(size_t new_size) { if (new_size > Capacity) reserve(new_size); Size = new_size; } - inline void reserve(size_t new_capacity) - { + inline void reserve(size_t new_capacity) + { if (new_capacity <= Capacity) return; T* new_data = (value_type*)ImGui::MemAlloc(new_capacity * sizeof(value_type)); memcpy(new_data, Data, Size * sizeof(value_type)); ImGui::MemFree(Data); Data = new_data; - Capacity = new_capacity; + Capacity = new_capacity; } inline void push_back(const value_type& v) { if (Size == Capacity) reserve(Capacity ? Capacity * 2 : 4); Data[Size++] = v; } @@ -144,7 +147,7 @@ public: // - struct ImFont // TTF font loader, bake glyphs into bitmap // ImGui end-user API -// In a namespace so that user can add extra functions (e.g. Value() helpers for your vector or common types) +// In a namespace so that user can add extra functions in a separate file (e.g. Value() helpers for your vector or common types) namespace ImGui { // Main @@ -153,48 +156,49 @@ namespace ImGui IMGUI_API void NewFrame(); IMGUI_API void Render(); IMGUI_API void Shutdown(); - IMGUI_API void ShowUserGuide(); - IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); - IMGUI_API void ShowTestWindow(bool* open = NULL); + IMGUI_API void ShowUserGuide(); // help block + IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // style editor block + IMGUI_API void ShowTestWindow(bool* opened = NULL); // test window, demonstrate ImGui features + IMGUI_API void ShowMetricsWindow(bool* opened = NULL); // metrics window // Window // See implementation in .cpp for details - IMGUI_API bool Begin(const char* name = "Debug", bool* p_opened = NULL, const ImVec2& initial_size = ImVec2(0,0), float bg_alpha = -1.0f, ImGuiWindowFlags flags = 0); // return false when window is collapsed, so you can early out in your code. passing 'bool* p_opened' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed. + IMGUI_API bool Begin(const char* name = "Debug", bool* p_opened = NULL, ImGuiWindowFlags flags = 0); // return false when window is collapsed, so you can early out in your code. 'bool* p_opened' creates a widget on the upper-right to close the window (which sets your bool to false). + IMGUI_API bool Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_use, float bg_alpha = -1.0f, ImGuiWindowFlags flags = 0); // this is the older/longer API. call SetNextWindowSize() instead if you want to set a window size. For regular windows, 'size_on_first_use' only applies to the first time EVER the window is created and probably not what you want! maybe obsolete this API eventually. IMGUI_API void End(); - IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // size==0.0f: use remaining window size, size<0.0f: use remaining window size minus abs(size). on each axis. - IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // " + IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // size==0.0f: use remaining window size, size<0.0f: use remaining window size minus abs(size). on each axis. + IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // " IMGUI_API void EndChild(); - IMGUI_API bool GetWindowIsFocused(); IMGUI_API ImVec2 GetContentRegionMax(); // window or current column boundaries, in windows coordinates IMGUI_API ImVec2 GetWindowContentRegionMin(); // window boundaries, in windows coordinates IMGUI_API ImVec2 GetWindowContentRegionMax(); - IMGUI_API ImDrawList* GetWindowDrawList(); // get rendering command-list if you want to append your own draw primitives. + IMGUI_API ImDrawList* GetWindowDrawList(); // get rendering command-list if you want to append your own draw primitives IMGUI_API ImFont* GetWindowFont(); IMGUI_API float GetWindowFontSize(); // size (also height in pixels) of current font with current scale applied - IMGUI_API void SetWindowFontScale(float scale); // per-window font scale. Adjust IO.FontGlobalScale if you want to scale all windows. - IMGUI_API ImVec2 GetWindowPos(); // you should rarely need/care about the window position, but it can be useful if you want to do your own drawing. - IMGUI_API ImVec2 GetWindowSize(); // get current window position. + IMGUI_API void SetWindowFontScale(float scale); // per-window font scale. Adjust IO.FontGlobalScale if you want to scale all windows + IMGUI_API ImVec2 GetWindowPos(); // you should rarely need/care about the window position, but it can be useful if you want to do your own drawing + IMGUI_API ImVec2 GetWindowSize(); // get current window position IMGUI_API float GetWindowWidth(); IMGUI_API bool GetWindowCollapsed(); - IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiSetCond cond = 0); // set next window position - call before Begin(). - IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiSetCond cond = 0); // set next window size. set to ImVec2(0,0) to force an auto-fit. - IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiSetCond cond = 0); // set next window collapsed state. + IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiSetCond cond = 0); // set next window position - call before Begin() + IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiSetCond cond = 0); // set next window size. set to ImVec2(0,0) to force an auto-fit + IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiSetCond cond = 0); // set next window collapsed state IMGUI_API void SetNextWindowFocus(); // set next window to be focused / front-most - IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiSetCond cond = 0); // set current window position - call within Begin()/End(). may incur tearing. - IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiSetCond cond = 0); // set current window size. set to ImVec2(0,0) to force an auto-fit. may incur tearing. - IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiSetCond cond = 0); // set current window collapsed state. + IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiSetCond cond = 0); // set current window position - call within Begin()/End(). may incur tearing + IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiSetCond cond = 0); // set current window size. set to ImVec2(0,0) to force an auto-fit. may incur tearing + IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiSetCond cond = 0); // set current window collapsed state IMGUI_API void SetWindowFocus(); // set current window to be focused / front-most - IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiSetCond cond = 0); // set named window position - call within Begin()/End(). may incur tearing. - IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiSetCond cond = 0); // set named window size. set to ImVec2(0,0) to force an auto-fit. may incur tearing. - IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiSetCond cond = 0); // set named window collapsed state. - IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / front-most + IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiSetCond cond = 0); // set named window position - call within Begin()/End(). may incur tearing + IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiSetCond cond = 0); // set named window size. set to ImVec2(0,0) to force an auto-fit. may incur tearing + IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiSetCond cond = 0); // set named window collapsed state + IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / front-most. use NULL to remove focus. - IMGUI_API float GetScrollPosY(); // get scrolling position (0..GetScrollMaxY()) + IMGUI_API float GetScrollPosY(); // get scrolling position [0..GetScrollMaxY()] IMGUI_API float GetScrollMaxY(); // get maximum scrolling position == ContentSize.Y - WindowSize.Y - IMGUI_API void SetScrollPosHere(); // adjust scrolling position to center into the current cursor position. - 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. - IMGUI_API void SetStateStorage(ImGuiStorage* tree); // replace tree state storage with our own (if you want to manipulate it yourself, typically clear subsection of it). + IMGUI_API void SetScrollPosHere(); // adjust scrolling position to center into the current cursor position + 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 + IMGUI_API void SetStateStorage(ImGuiStorage* tree); // replace tree state storage with our own (if you want to manipulate it yourself, typically clear subsection of it) IMGUI_API ImGuiStorage* GetStateStorage(); // Parameters stacks (shared) @@ -210,26 +214,34 @@ namespace ImGui IMGUI_API void PushItemWidth(float item_width); // width of items for the common item+label case, pixels. 0.0f = default to ~2/3 of windows width, >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -0.01f always align width to the right side) IMGUI_API void PopItemWidth(); IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position - IMGUI_API void PushAllowKeyboardFocus(bool v); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets. + IMGUI_API void PushAllowKeyboardFocus(bool v); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets IMGUI_API void PopAllowKeyboardFocus(); - IMGUI_API void PushTextWrapPos(float wrap_pos_x = 0.0f); // word-wrapping 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 PushTextWrapPos(float wrap_pos_x = 0.0f); // word-wrapping 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(); // Tooltip - IMGUI_API void SetTooltip(const char* fmt, ...); // set tooltip under mouse-cursor, typically use with ImGui::IsHovered(). last call wins. + IMGUI_API void SetTooltip(const char* fmt, ...); // set tooltip under mouse-cursor, typically use with ImGui::IsHovered(). last call wins IMGUI_API void SetTooltipV(const char* fmt, va_list args); - IMGUI_API void BeginTooltip(); // use to create full-featured tooltip windows that aren't just text. + IMGUI_API void BeginTooltip(); // use to create full-featured tooltip windows that aren't just text IMGUI_API void EndTooltip(); + // Popup + IMGUI_API void BeginPopup(bool* p_opened); + IMGUI_API void EndPopup(); + // Layout + IMGUI_API void BeginGroup(); + IMGUI_API void EndGroup(); IMGUI_API void Separator(); // horizontal line - IMGUI_API void SameLine(int column_x = 0, int spacing_w = -1); // call between widgets to layout them horizontally - IMGUI_API void Spacing(); + IMGUI_API void SameLine(int column_x = 0, int spacing_w = -1); // call between widgets or groups to layout them horizontally + IMGUI_API void Spacing(); // add vertical spacing + IMGUI_API void Indent(); // move content position toward the right by style.IndentSpacing pixels + IMGUI_API void Unindent(); // move content position back to the left (cancel Indent) IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border=true); // setup number of columns IMGUI_API void NextColumn(); // next column IMGUI_API int GetColumnIndex(); // get current column index - 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 usually 0.0f and not resizable unless you call this. - 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 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 usually 0.0f and not resizable unless you call this + 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 float GetColumnWidth(int column_index = -1); // column width (== GetColumnOffset(GetColumnIndex()+1) - GetColumnOffset(GetColumnOffset()) IMGUI_API int GetColumnsCount(); // number of columns (what was passed to Columns()) IMGUI_API ImVec2 GetCursorPos(); // cursor position is relative to window position @@ -238,20 +250,22 @@ namespace ImGui IMGUI_API void SetCursorPos(const ImVec2& pos); // " IMGUI_API void SetCursorPosX(float x); // " IMGUI_API void SetCursorPosY(float y); // " - IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute screen coordinates (0..io.DisplaySize) - IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute screen coordinates (0..io.DisplaySize) - IMGUI_API void AlignFirstTextHeightToWidgets(); // call once if the first item on the line is a Text() item and you want to vertically lower it to match subsequent (bigger) widgets. + IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute screen coordinates [0..io.DisplaySize] + IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute screen coordinates [0..io.DisplaySize] + IMGUI_API void AlignFirstTextHeightToWidgets(); // call once if the first item on the line is a Text() item and you want to vertically lower it to match subsequent (bigger) widgets IMGUI_API float GetTextLineHeight(); // height of font == GetWindowFontSize() IMGUI_API float GetTextLineHeightWithSpacing(); // spacing (in pixels) between 2 consecutive lines of text == GetWindowFontSize() + GetStyle().ItemSpacing.y // ID scopes - // If you are creating widgets in a loop you most likely want to push a unique identifier so ImGui can differentiate them. + // If you are creating widgets in a loop you most likely want to push a unique identifier so ImGui can differentiate them // You can also use "##extra" within your widget name to distinguish them from each others (see 'Programmer Guide') IMGUI_API void PushID(const char* str_id); // push identifier into the ID stack. IDs are hash of the *entire* stack! + IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); IMGUI_API void PushID(const void* ptr_id); IMGUI_API void PushID(const int int_id); IMGUI_API void PopID(); - IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). useful if you want to query into ImGuiStorage yourself. otherwise rarely needed. + IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). useful if you want to query into ImGuiStorage yourself. otherwise rarely needed + IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end); IMGUI_API ImGuiID GetID(const void* ptr_id); // Widgets @@ -261,8 +275,8 @@ namespace ImGui IMGUI_API void TextColoredV(const ImVec4& col, const char* fmt, va_list args); IMGUI_API void TextWrapped(const char* fmt, ...); // shortcut for PushTextWrapPos(0.0f); Text(fmt, ...); PopTextWrapPos(); IMGUI_API void TextWrappedV(const char* fmt, va_list args); - IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // doesn't require null terminated string if 'text_end' is specified. no copy done to any bounded stack buffer, recommended for long chunks of text. - IMGUI_API void LabelText(const char* label, const char* fmt, ...); // display text+label aligned the same way as value+label widgets + IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // doesn't require null terminated string if 'text_end' is specified. no copy done to any bounded stack buffer, recommended for long chunks of text + IMGUI_API void LabelText(const char* label, const char* fmt, ...); // display text+label aligned the same way as value+label widgets IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args); IMGUI_API void Bullet(); IMGUI_API void BulletText(const char* fmt, ...); @@ -271,31 +285,12 @@ namespace ImGui IMGUI_API bool SmallButton(const char* label); IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size); IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0)); - 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,1), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no paddnig. + 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,1), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no padding IMGUI_API bool CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false); - IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); // adjust display_format to decorate the value with a prefix or a suffix. Use power!=1.0 for logarithmic sliders. - IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); - IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); - IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); - IMGUI_API bool SliderAngle(const char* label, float* v, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f); // *v in radians - IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* display_format = "%.0f"); - IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* display_format = "%.0f"); - IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* display_format = "%.0f"); - IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* display_format = "%.0f"); - 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), size_t 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), size_t 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)); IMGUI_API bool Checkbox(const char* label, bool* v); IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value); IMGUI_API bool RadioButton(const char* label, bool active); IMGUI_API bool RadioButton(const char* label, int* v, int v_button); - IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); - IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, int decimal_precision = -1, ImGuiInputTextFlags extra_flags = 0); - IMGUI_API bool InputFloat2(const char* label, float v[2], int decimal_precision = -1); - IMGUI_API bool InputFloat3(const char* label, float v[3], int decimal_precision = -1); - IMGUI_API bool InputFloat4(const char* label, float v[4], int decimal_precision = -1); - IMGUI_API bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags extra_flags = 0); IMGUI_API bool Combo(const char* label, int* current_item, const char** items, int items_count, int height_in_items = -1); IMGUI_API bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items = -1); // separate items with \0, end item-list with \0\0 IMGUI_API bool Combo(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); @@ -303,8 +298,41 @@ namespace ImGui IMGUI_API bool ColorEdit3(const char* label, float col[3]); IMGUI_API bool ColorEdit4(const char* label, float col[4], bool show_alpha = true); IMGUI_API void ColorEditMode(ImGuiColorEditMode mode); + 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), size_t 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), size_t 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)); - // Trees + // Widgets: Sliders (tip: ctrl+click on a slider to input text) + IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); // adjust display_format to decorate the value with a prefix or a suffix. Use power!=1.0 for logarithmic sliders + IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); + IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); + IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); + IMGUI_API bool SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f); + IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* display_format = "%.0f"); + IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* display_format = "%.0f"); + IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* display_format = "%.0f"); + IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* display_format = "%.0f"); + IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); + IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* display_format = "%.0f"); + + // Widgets: Drags (tip: ctrl+click on a drag box to input text) + // ImGui 1.38+ work-in-progress, may change name or API. + 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* display_format = "%.3f", float power = 1.0f); // If v_max >= v_max we have no bound + IMGUI_API bool DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* display_format = "%.0f"); // If v_max >= v_max we have no bound + + // Widgets: Input + IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, int decimal_precision = -1, ImGuiInputTextFlags extra_flags = 0); + IMGUI_API bool InputFloat2(const char* label, float v[2], int decimal_precision = -1); + IMGUI_API bool InputFloat3(const char* label, float v[3], int decimal_precision = -1); + IMGUI_API bool InputFloat4(const char* label, float v[4], int decimal_precision = -1); + IMGUI_API bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags extra_flags = 0); + IMGUI_API bool InputInt2(const char* label, int v[2]); + IMGUI_API bool InputInt3(const char* label, int v[3]); + IMGUI_API bool InputInt4(const char* label, int v[4]); + + // Widgets: Trees IMGUI_API bool TreeNode(const char* str_label_id); // if returning 'true' the node is open and the user is responsible for calling TreePop IMGUI_API bool TreeNode(const char* str_id, const char* fmt, ...); // " IMGUI_API bool TreeNode(const void* ptr_id, const char* fmt, ...); // " @@ -315,8 +343,8 @@ namespace ImGui IMGUI_API void TreePop(); IMGUI_API void SetNextTreeNodeOpened(bool opened, ImGuiSetCond cond = 0); // set next tree node to be opened. - // Selectable / Lists - IMGUI_API bool Selectable(const char* label, bool selected, const ImVec2& size = ImVec2(0,0)); + // Widgets: Selectable / Lists + IMGUI_API bool Selectable(const char* label, bool selected = false, const ImVec2& size = ImVec2(0,0)); IMGUI_API bool Selectable(const char* label, bool* p_selected, const ImVec2& size = ImVec2(0,0)); IMGUI_API bool ListBox(const char* label, int* current_item, const char** items, int items_count, int height_in_items = -1); IMGUI_API bool ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); @@ -324,7 +352,7 @@ namespace ImGui IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // " IMGUI_API void ListBoxFooter(); // terminate the scrolling region - // Value() Helpers: output single value in "name: value" format. Tip: freely declare your own within the ImGui namespace! + // Widgets: Value() Helpers. Output single value in "name: value" format (tip: freely declare your own within 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); @@ -332,7 +360,7 @@ namespace ImGui IMGUI_API void Color(const char* prefix, const ImVec4& v); IMGUI_API void Color(const char* prefix, unsigned int v); - // Logging: All text output from your interface are redirected to tty/file/clipboard. Tree nodes are automatically opened. + // Logging: all text output from interface is redirected to tty/file/clipboard. Tree nodes are automatically opened. IMGUI_API void LogToTTY(int max_depth = -1); // start logging to tty IMGUI_API void LogToFile(int max_depth = -1, const char* filename = NULL); // start logging to file IMGUI_API void LogToClipboard(int max_depth = -1); // start logging to OS clipboard @@ -342,26 +370,38 @@ namespace ImGui // Utilities IMGUI_API bool IsItemHovered(); // was the last item hovered by mouse? + IMGUI_API bool IsItemHoveredRect(); // was the last item hovered by mouse? even if another item is active while we are hovering this IMGUI_API bool IsItemActive(); // was the last item active? (e.g. button being held, text field being edited- items that don't interact will always return false) - IMGUI_API bool IsAnyItemActive(); // - IMGUI_API ImVec2 GetItemBoxMin(); // get bounding box of last item - IMGUI_API ImVec2 GetItemBoxMax(); // get bounding box of last item - IMGUI_API bool IsClipped(const ImVec2& item_size); // to perform coarse clipping on user's side (as an optimization) + IMGUI_API bool IsAnyItemActive(); // + IMGUI_API bool IsItemVisible(); + IMGUI_API ImVec2 GetItemRectMin(); // get bounding rect of last item in screen space + IMGUI_API ImVec2 GetItemRectMax(); // " + IMGUI_API ImVec2 GetItemRectSize(); // " + IMGUI_API bool IsWindowFocused(); // is current window focused (differentiate child windows from each others) + IMGUI_API bool IsRootWindowFocused(); // is current root window focused + IMGUI_API bool IsRootWindowOrAnyChildFocused(); // is current root window or any of its child (including current window) focused + IMGUI_API bool IsRectClipped(const ImVec2& size); // test if rectangle of given size starting from cursor pos is out of clipping region. to perform coarse clipping on user's side (as an optimization) IMGUI_API bool IsKeyPressed(int key_index, bool repeat = true); // key_index into the keys_down[512] array, imgui doesn't know the semantic of each entry IMGUI_API bool IsMouseClicked(int button, bool repeat = false); IMGUI_API bool IsMouseDoubleClicked(int button); IMGUI_API bool IsMouseHoveringWindow(); // is mouse hovering current window ("window" in API names always refer to current window) IMGUI_API bool IsMouseHoveringAnyWindow(); // is mouse hovering any active imgui window - IMGUI_API bool IsMouseHoveringBox(const ImVec2& box_min, const ImVec2& box_max); // is mouse hovering given bounding box + IMGUI_API bool IsMouseHoveringRect(const ImVec2& rect_min, const ImVec2& rect_max);// is mouse hovering given bounding rect + IMGUI_API bool IsMouseDragging(int button = 0, float lock_threshold = -1.0f); // is mouse dragging. if lock_threshold < -1.0f uses io.MouseDraggingThreshold IMGUI_API bool IsPosHoveringAnyWindow(const ImVec2& pos); // is given position hovering any active imgui window IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls + IMGUI_API ImVec2 GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f); // dragging amount since clicking, also see: GetItemActiveDragDelta(). if lock_threshold < -1.0f uses io.MouseDraggingThreshold + IMGUI_API void ResetMouseDragDelta(int button = 0); + IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this 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 type); // set desired cursor type IMGUI_API float GetTime(); IMGUI_API int GetFrameCount(); IMGUI_API const char* GetStyleColName(ImGuiCol idx); + IMGUI_API ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = +0.0f); // utility to find the closest point the last item bounding rectangle edge. useful to visually link items IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); - IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // helper to manually clip large list of items. see comments in implementation. + IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // helper to manually clip large list of items. see comments in implementation - IMGUI_API void BeginChildFrame(ImGuiID id, const ImVec2& size); // helper to create a child window / scrolling region that looks like a normal widget frame. + IMGUI_API void BeginChildFrame(ImGuiID id, const ImVec2& size); // helper to create a child window / scrolling region that looks like a normal widget frame IMGUI_API void EndChildFrame(); IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4& in); @@ -369,13 +409,19 @@ namespace ImGui IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b); // Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself + IMGUI_API const char* GetVersion(); IMGUI_API void* GetInternalState(); IMGUI_API size_t GetInternalStateSize(); IMGUI_API void SetInternalState(void* state, bool construct = false); // Obsolete (will be removed) - IMGUI_API void GetDefaultFontData(const void** fnt_data, unsigned int* fnt_size, const void** png_data, unsigned int* png_size); - static inline void OpenNextNode(bool open) { ImGui::SetNextTreeNodeOpened(open, 0); } + IMGUI_API void GetDefaultFontData(const void** fnt_data, unsigned int* fnt_size, const void** png_data, unsigned int* png_size); // OBSOLETE + static inline void OpenNextNode(bool open) { ImGui::SetNextTreeNodeOpened(open, 0); } // OBSOLETE + static inline bool GetWindowIsFocused() { return ImGui::IsWindowFocused(); } // OBSOLETE + static inline ImVec2 GetItemBoxMin() { return GetItemRectMin(); } // OBSOLETE + static inline ImVec2 GetItemBoxMax() { return GetItemRectMax(); } // OBSOLETE + static inline bool IsClipped(const ImVec2& size) { return IsRectClipped(size); } // OBSOLETE + static inline bool IsMouseHoveringBox(const ImVec2& rect_min, const ImVec2& rect_max) { return IsMouseHoveringRect(rect_min, rect_max); } // OBSOLETE } // namespace ImGui @@ -397,7 +443,8 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_ChildWindowAutoFitX = 1 << 10, // For internal use by BeginChild() ImGuiWindowFlags_ChildWindowAutoFitY = 1 << 11, // For internal use by BeginChild() ImGuiWindowFlags_ComboBox = 1 << 12, // For internal use by ComboBox() - ImGuiWindowFlags_Tooltip = 1 << 13 // For internal use by BeginTooltip() + ImGuiWindowFlags_Tooltip = 1 << 13, // For internal use by BeginTooltip() + ImGuiWindowFlags_Popup = 1 << 14 // For internal use by BeginPopup() }; // Flags for ImGui::InputText() @@ -448,6 +495,8 @@ enum ImGuiCol_ ImGuiCol_Border, ImGuiCol_BorderShadow, ImGuiCol_FrameBg, // Background of checkbox, radio button, plot, slider, text input + ImGuiCol_FrameBgHovered, + ImGuiCol_FrameBgActive, ImGuiCol_TitleBg, ImGuiCol_TitleBgCollapsed, ImGuiCol_ScrollbarBg, @@ -455,8 +504,6 @@ enum ImGuiCol_ ImGuiCol_ScrollbarGrabHovered, ImGuiCol_ScrollbarGrabActive, ImGuiCol_ComboBg, - ImGuiCol_CheckHovered, - ImGuiCol_CheckActive, ImGuiCol_CheckMark, ImGuiCol_SliderGrab, ImGuiCol_SliderGrabActive, @@ -496,7 +543,8 @@ enum ImGuiStyleVar_ ImGuiStyleVar_FrameRounding, // float ImGuiStyleVar_ItemSpacing, // ImVec2 ImGuiStyleVar_ItemInnerSpacing, // ImVec2 - ImGuiStyleVar_TreeNodeSpacing // float + ImGuiStyleVar_IndentSpacing, // float + ImGuiStyleVar_GrabMinSize // float }; // Enumeration for ColorEditMode() @@ -509,6 +557,19 @@ enum ImGuiColorEditMode_ ImGuiColorEditMode_HEX = 2 }; +// Enumeration for GetMouseCursor() +enum ImGuiMouseCursor_ +{ + ImGuiMouseCursor_Arrow = 0, + ImGuiMouseCursor_TextInput, // When hovering over InputText, etc. + ImGuiMouseCursor_Move, // Unused + ImGuiMouseCursor_ResizeNS, // Unused + ImGuiMouseCursor_ResizeEW, // When hovering over a column + ImGuiMouseCursor_ResizeNESW, // Unused + ImGuiMouseCursor_ResizeNWSE, // When hovering over the bottom-right corner of a window + ImGuiMouseCursor_Count_ +}; + // Condition flags for ImGui::SetWindow***(), SetNextWindow***(), SetNextTreeNode***() functions // All those functions treat 0 as a shortcut to ImGuiSetCond_Always enum ImGuiSetCond_ @@ -529,13 +590,14 @@ struct ImGuiStyle float FrameRounding; // Radius of frame corners rounding. Set to 0.0f to have rectangular frame (used by most widgets). 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 TouchExtraPadding; // Expand bounding box for touch-based system where touch position is not accurate enough (unnecessary for mouse inputs). Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget running. So dont grow this too much! + 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! ImVec2 AutoFitPadding; // Extra space after auto-fit (double-clicking on resize grip) float WindowFillAlphaDefault; // Default alpha of window background, if not specified in ImGui::Begin() - float TreeNodeSpacing; // Horizontal spacing when entering a tree node + float IndentSpacing; // Horizontal indentation when e.g. entering a tree node float ColumnsMinSpacing; // Minimum horizontal spacing between two columns float ScrollbarWidth; // Width of the vertical scrollbar float GrabMinSize; // Minimum width/height of a slider or scrollbar grab + ImVec2 DisplaySafeAreaPadding; // Window positions are clamped to be visible within the display area. If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. ImVec4 Colors[ImGuiCol_COUNT]; IMGUI_API ImGuiStyle(); @@ -556,6 +618,7 @@ struct ImGuiIO const char* LogFilename; // = "imgui_log.txt" // Path to .log file (default parameter to ImGui::LogToFile when no file is specified). 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 int KeyMap[ImGuiKey_COUNT]; // // Map of indices into the KeysDown[512] entries array void* UserData; // = NULL // Store your own data for retrieval by callbacks. @@ -569,9 +632,9 @@ struct ImGuiIO // User Functions //------------------------------------------------------------------ - // REQUIRED: rendering function. + // REQUIRED: rendering function. // See example code if you are unsure of how to implement this. - void (*RenderDrawListsFn)(ImDrawList** const draw_lists, int count); + void (*RenderDrawListsFn)(ImDrawList** const draw_lists, int count); // 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) @@ -594,10 +657,11 @@ struct ImGuiIO ImVec2 MousePos; // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) bool MouseDown[5]; // Mouse buttons. ImGui itself only uses button 0 (left button). Others buttons allows to track if mouse is being used by your application + available to user as a convenience via IsMouse** API. - float MouseWheel; // Mouse wheel: 1 unit scrolls about 5 lines text. + float MouseWheel; // Mouse wheel: 1 unit scrolls about 5 lines text. bool MouseDrawCursor; // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). bool KeyCtrl; // Keyboard modifier pressed: Control bool KeyShift; // Keyboard modifier pressed: Shift + bool KeyAlt; // Keyboard modifier pressed: Alt bool KeysDown[512]; // Keyboard keys that are pressed (in whatever storage order you naturally have access to keyboard data) ImWchar InputCharacters[16+1]; // List of characters input (translated by user from keypress+keyboard state). Fill using AddInputCharacter() helper. @@ -611,6 +675,7 @@ struct ImGuiIO bool WantCaptureMouse; // Mouse is hovering a window or widget is active (= ImGui will use your mouse input) bool WantCaptureKeyboard; // Widget is active (= ImGui will use your keyboard input) float Framerate; // Framerate estimation, in frame per second. Rolling average estimation based on IO.DeltaTime over 120 frames + int MetricsRenderVertices; // Vertices processed during last call to Render() //------------------------------------------------------------------ // [Internal] ImGui will maintain those fields for you @@ -624,6 +689,7 @@ struct ImGuiIO bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? bool MouseDownOwned[5]; // Track if button was clicked inside a window. We don't request mouse capture from the application if click started outside ImGui bounds. float MouseDownTime[5]; // Time the mouse button has been down + float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the click point float KeysDownTime[512]; // Time the keyboard key has been down IMGUI_API ImGuiIO(); @@ -686,7 +752,6 @@ struct ImGuiTextBuffer ImVector Buf; ImGuiTextBuffer() { Buf.push_back(0); } - ~ImGuiTextBuffer() { } const char* begin() const { return &Buf.front(); } const char* end() const { return &Buf.back(); } // Buf is zero-terminated, so end() will point on the zero-terminator size_t size() const { return Buf.size()-1; } @@ -706,13 +771,13 @@ struct ImGuiTextBuffer // - You want to store custom debug data easily without adding or editing structures in your code. struct ImGuiStorage { - struct Pair - { - ImGuiID key; - union { int val_i; float val_f; void* val_p; }; - Pair(ImGuiID _key, int _val_i) { key = _key; val_i = _val_i; } - Pair(ImGuiID _key, float _val_f) { key = _key; val_f = _val_f; } - Pair(ImGuiID _key, void* _val_p) { key = _key; val_p = _val_p; } + struct Pair + { + ImGuiID key; + union { int val_i; float val_f; void* val_p; }; + Pair(ImGuiID _key, int _val_i) { key = _key; val_i = _val_i; } + Pair(ImGuiID _key, float _val_f) { key = _key; val_f = _val_f; } + Pair(ImGuiID _key, void* _val_p) { key = _key; val_p = _val_p; } }; ImVector Data; @@ -727,7 +792,7 @@ struct ImGuiStorage 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. + // - 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: // float* pvar = ImGui::GetFloatRef(key); ImGui::SliderFloat("var", pvar, 0, 100.0f); some_var += *pvar; @@ -824,6 +889,7 @@ IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT; // At the moment, each ImGui window contains its own ImDrawList but they could potentially be merged in the future. // If you want to add custom rendering within a window, you can use ImGui::GetWindowDrawList() to access the current draw list and add your own primitives. // You can interleave normal ImGui:: calls and adding primitives to the current draw list. +// All positions are in screen coordinates (0,0=top-left, 1 pixel per unit). Primitives are always added to the list and not culled (culling is done at render time and at a higher-level by ImGui:: functions). // Note that this only gives you access to rendering polygons. If your intent is to create custom widgets and the publicly exposed functions/data aren't sufficient, you can add code in imgui_user.inl struct ImDrawList { @@ -833,38 +899,43 @@ struct ImDrawList // [Internal to ImGui] ImVector clip_rect_stack; // [Internal] - ImVector texture_id_stack; // [Internal] + ImVector texture_id_stack; // [Internal] ImDrawVert* vtx_write; // [Internal] point within vtx_buffer after each add command (to avoid using the ImVector<> operators too much) ImDrawList() { Clear(); } IMGUI_API void Clear(); + IMGUI_API void ClearFreeMemory(); IMGUI_API void PushClipRect(const ImVec4& clip_rect); // Scissoring. The values are x1, y1, x2, y2. + IMGUI_API void PushClipRectFullScreen(); IMGUI_API void PopClipRect(); IMGUI_API void PushTextureID(const ImTextureID& texture_id); IMGUI_API void PopTextureID(); - // Primitives - IMGUI_API void AddLine(const ImVec2& a, const ImVec2& b, ImU32 col); - IMGUI_API void AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners=0x0F); - IMGUI_API void AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners=0x0F); + // Primitives + IMGUI_API void AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners = 0x0F); + IMGUI_API void AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners = 0x0F); IMGUI_API void AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col); IMGUI_API void AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12); IMGUI_API void AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12); - IMGUI_API void AddArc(const ImVec2& center, float rad, ImU32 col, int a_min, int a_max, bool tris = false, const ImVec2& third_point_offset = ImVec2(0,0)); - 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 ImVec2* cpu_clip_max = NULL); + IMGUI_API void AddArcFast(const ImVec2& center, float radius, ImU32 col, int a_min_12, int a_max_12, bool filled = false, const ImVec2& third_point_offset = ImVec2(0,0)); // Angles in 0..12 range + IMGUI_API void AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec2* cpu_clip_max = NULL); IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv0, const ImVec2& uv1, ImU32 col = 0xFFFFFFFF); // Advanced - IMGUI_API void AddCallback(ImDrawCallback callback, void* callback_data); // Your rendering function must check for 'user_callback' in ImDrawCmd and call the function instead of rendering triangles. - 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 void AddCallback(ImDrawCallback callback, void* callback_data); // Your rendering function must check for 'user_callback' in ImDrawCmd and call the function instead of rendering triangles. + 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 // Internal helpers - IMGUI_API void ReserveVertices(unsigned int vtx_count); - IMGUI_API void AddVtx(const ImVec2& pos, ImU32 col); - IMGUI_API void AddVtxUV(const ImVec2& pos, ImU32 col, const ImVec2& uv); - IMGUI_API void AddVtxLine(const ImVec2& a, const ImVec2& b, ImU32 col); + IMGUI_API void PrimReserve(unsigned int vtx_count); + IMGUI_API void PrimTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col); + IMGUI_API void PrimRect(const ImVec2& a, const ImVec2& b, ImU32 col); + IMGUI_API void PrimRectUV(const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col); + IMGUI_API void PrimQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col); + IMGUI_API void PrimLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness = 1.0f); IMGUI_API void UpdateClipRect(); IMGUI_API void UpdateTextureID(); + IMGUI_API void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { vtx_write->pos = pos; vtx_write->uv = uv; vtx_write->col = col; vtx_write++; } }; // Load and rasterize multiple TTF fonts into a same texture. @@ -874,14 +945,15 @@ struct ImDrawList // 2. Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data. // 3. Upload the pixels data into a texture within your graphics system. // 4. Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture. This value will be passed back to you during rendering to identify the texture. -// 5. Call ClearPixelsData() to free textures memory on the heap. +// 5. Call ClearTexData() to free textures memory on the heap. struct ImFontAtlas { IMGUI_API ImFontAtlas(); IMGUI_API ~ImFontAtlas(); IMGUI_API ImFont* AddFontDefault(); IMGUI_API ImFont* AddFontFromFileTTF(const char* filename, float size_pixels, const ImWchar* glyph_ranges = NULL, int font_no = 0); - IMGUI_API ImFont* AddFontFromMemoryTTF(void* in_ttf_data, size_t in_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges = NULL, int font_no = 0); // Pass ownership of 'in_ttf_data' memory. + IMGUI_API ImFont* AddFontFromMemoryTTF(void* in_ttf_data, unsigned int in_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges = NULL, int font_no = 0); // Pass ownership of 'in_ttf_data' memory, will be deleted after build + IMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* in_compressed_ttf_data, unsigned int in_compressed_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges = NULL, int font_no = 0); // 'in_compressed_ttf_data' untouched and still owned by caller. compress with binary_to_compressed_c. IMGUI_API void ClearTexData(); // Saves RAM once the texture has been copied to graphics memory. IMGUI_API void Clear(); @@ -895,7 +967,7 @@ struct ImFontAtlas IMGUI_API void SetTexID(void* id) { TexID = id; } // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list) - // (Those functions could be static, aren't so simple use case doesn't have to refer to the ImFontAtlas:: type ever if in their code) + // (Those functions could be static but aren't so most users don't have to refer to the ImFontAtlas:: name ever if in their code; just using io.Fonts->) IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs IMGUI_API const ImWchar* GetGlyphRangesChinese(); // Japanese + full set of about 21000 CJK Unified Ideographs @@ -907,7 +979,6 @@ struct ImFontAtlas unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 int TexWidth; int TexHeight; - ImVec2 TexExtraDataPos; // Position of our rectangle where we draw non-font graphics ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel (part of the TexExtraData block) ImVector Fonts; @@ -916,7 +987,7 @@ struct ImFontAtlas ImVector InputData; // Internal data IMGUI_API bool Build(); // Build pixels data. This is automatically for you by the GetTexData*** functions. IMGUI_API void ClearInputData(); // Clear the input TTF data. - IMGUI_API void RenderCustomTexData(); + IMGUI_API void RenderCustomTexData(int pass, void* rects); }; // TTF font loading and rendering @@ -948,19 +1019,19 @@ struct ImFont // Methods IMGUI_API ImFont(); - IMGUI_API ~ImFont() { Clear(); } - IMGUI_API void Clear(); - IMGUI_API void BuildLookupTable(); - IMGUI_API const Glyph* FindGlyph(unsigned short c) const; - IMGUI_API void SetFallbackChar(ImWchar c); - IMGUI_API bool IsLoaded() const { return ContainerAtlas != NULL; } + IMGUI_API ~ImFont(); + IMGUI_API void Clear(); + IMGUI_API void BuildLookupTable(); + IMGUI_API const Glyph* FindGlyph(unsigned short c) const; + IMGUI_API void SetFallbackChar(ImWchar c); + IMGUI_API bool IsLoaded() const { return ContainerAtlas != NULL; } // '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 ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL) const; // utf8 - IMGUI_API ImVec2 CalcTextSizeW(float size, float max_width, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL) const; // wchar - IMGUI_API void RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, ImDrawVert*& out_vertices, float wrap_width = 0.0f, const ImVec2* cpu_clip_max = NULL) const; - IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const; + 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) const; // utf8 + IMGUI_API ImVec2 CalcTextSizeW(float size, float max_width, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL) const; // wchar + IMGUI_API void RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, ImDrawList* draw_list, float wrap_width = 0.0f, const ImVec2* cpu_clip_max = NULL) const; + IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const; }; //---- Include imgui_user.h at the end of imgui.h