Update imgui to 1.68.

This commit is contained in:
Bartosz Taudul 2019-02-21 18:40:27 +01:00
parent 938d8ce69e
commit b33c61cead
14 changed files with 1360 additions and 782 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
// dear imgui, v1.67 // dear imgui, v1.68
// (headers) // (headers)
// See imgui.cpp file for documentation. // See imgui.cpp file for documentation.
@ -45,8 +45,8 @@ Index of this file:
// Version // Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY00 then bounced up to XYY01 when release tagging happens) // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY00 then bounced up to XYY01 when release tagging happens)
#define IMGUI_VERSION "1.67" #define IMGUI_VERSION "1.68"
#define IMGUI_VERSION_NUM 16603 #define IMGUI_VERSION_NUM 16801
#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert)) #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert))
// Define attributes of all API symbols declarations (e.g. for DLL under Windows) // Define attributes of all API symbols declarations (e.g. for DLL under Windows)
@ -72,12 +72,15 @@ Index of this file:
#endif #endif
#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR))) // Size of a static C-style array. Don't use on pointers! #define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR))) // Size of a static C-style array. Don't use on pointers!
#define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Standardized as offsetof() in modern C++. #define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Standardized as offsetof() in modern C++.
#define IM_UNUSED(_VAR) ((void)_VAR) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds.
// Warnings // Warnings
#if defined(__clang__) #if defined(__clang__)
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wold-style-cast" #pragma clang diagnostic ignored "-Wold-style-cast"
#if __has_warning("-Wzero-as-null-pointer-constant")
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
#endif
#elif defined(__GNUC__) && __GNUC__ >= 8 #elif defined(__GNUC__) && __GNUC__ >= 8
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wclass-memaccess" #pragma GCC diagnostic ignored "-Wclass-memaccess"
@ -167,7 +170,8 @@ struct ImVec2
float x, y; float x, y;
ImVec2() { x = y = 0.0f; } ImVec2() { x = y = 0.0f; }
ImVec2(float _x, float _y) { x = _x; y = _y; } ImVec2(float _x, float _y) { x = _x; y = _y; }
float operator[] (size_t i) const { IM_ASSERT(i <= 1); return (&x)[i]; } // We very rarely use this [] operator, the assert overhead is fine. float operator[] (size_t idx) const { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine.
float& operator[] (size_t idx) { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine.
#ifdef IM_VEC2_CLASS_EXTRA #ifdef IM_VEC2_CLASS_EXTRA
IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2.
#endif #endif
@ -226,11 +230,11 @@ namespace ImGui
// Windows // Windows
// - Begin() = push window to the stack and start appending to it. End() = pop window from the stack. // - Begin() = push window to the stack and start appending to it. End() = pop window from the stack.
// - You may append multiple times to the same window during the same frame. // - You may append multiple times to the same window during the same frame.
// - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window, // - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window,
// which clicking will set the boolean to false when clicked. // which clicking will set the boolean to false when clicked.
// - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting
// anything to the window. Always call a matching End() for each Begin() call, regardless of its return value! // anything to the window. Always call a matching End() for each Begin() call, regardless of its return value!
// [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. // [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc.
// where the EndXXX call should only be called if the corresponding BeginXXX function returned true.] // where the EndXXX call should only be called if the corresponding BeginXXX function returned true.]
// - Note that the bottom of window stack always contains a window called "Debug". // - Note that the bottom of window stack always contains a window called "Debug".
IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0);
@ -251,7 +255,8 @@ namespace ImGui
IMGUI_API bool IsWindowCollapsed(); IMGUI_API bool IsWindowCollapsed();
IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options. IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options.
IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered (and typically: not blocked by a popup/modal)? see flags for options. NB: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that! Please read the FAQ! IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered (and typically: not blocked by a popup/modal)? see flags for options. NB: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that! Please read the FAQ!
IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the window, to append your own drawing primitives IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives
IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (useful if you want to do your own drawing via the DrawList API) IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (useful if you want to do your own drawing via the DrawList API)
IMGUI_API ImVec2 GetWindowSize(); // get current window size IMGUI_API ImVec2 GetWindowSize(); // get current window size
IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x) IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x)
@ -319,7 +324,7 @@ namespace ImGui
IMGUI_API void PopButtonRepeat(); IMGUI_API void PopButtonRepeat();
// Cursor / Layout // Cursor / Layout
// - By "cursor" we mean the current output position. // - By "cursor" we mean the current output position.
// - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down. // - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down.
IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator. IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator.
IMGUI_API void SameLine(float local_pos_x = 0.0f, float spacing_w = -1.0f); // call between widgets or groups to layout them horizontally. X position given in window coordinates. IMGUI_API void SameLine(float local_pos_x = 0.0f, float spacing_w = -1.0f); // call between widgets or groups to layout them horizontally. X position given in window coordinates.
@ -335,7 +340,7 @@ namespace ImGui
IMGUI_API float GetCursorPosY(); // other functions such as GetCursorScreenPos or everything in ImDrawList:: IMGUI_API float GetCursorPosY(); // other functions such as GetCursorScreenPos or everything in ImDrawList::
IMGUI_API void SetCursorPos(const ImVec2& local_pos); // are using the main, absolute coordinate system. IMGUI_API void SetCursorPos(const ImVec2& local_pos); // are using the main, absolute coordinate system.
IMGUI_API void SetCursorPosX(float local_x); // GetWindowPos() + GetCursorPos() == GetCursorScreenPos() etc.) IMGUI_API void SetCursorPosX(float local_x); // GetWindowPos() + GetCursorPos() == GetCursorScreenPos() etc.)
IMGUI_API void SetCursorPosY(float local_y); // IMGUI_API void SetCursorPosY(float local_y); //
IMGUI_API ImVec2 GetCursorStartPos(); // initial cursor position in window coordinates IMGUI_API ImVec2 GetCursorStartPos(); // initial cursor position in window coordinates
IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute screen coordinates [0..io.DisplaySize] (useful to work with ImDrawList API) IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute screen coordinates [0..io.DisplaySize] (useful to work with ImDrawList API)
IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // 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]
@ -348,13 +353,14 @@ namespace ImGui
// ID stack/scopes // ID stack/scopes
// - Read the FAQ for more details about how ID are handled in dear imgui. If you are creating widgets in a loop you most // - Read the FAQ for more details about how ID are handled in dear imgui. If you are creating widgets in a loop you most
// likely want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them. // likely want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them.
// - The resulting ID are hashes of the entire stack.
// - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others. // - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others.
// - In this header file we use the "label"/"name" terminology to denote a string that will be displayed and used as an ID, // - In this header file we use the "label"/"name" terminology to denote a string that will be displayed and used as an ID,
// whereas "str_id" denote a string that is only used as an ID and not normally displayed. // whereas "str_id" denote a string that is only used as an ID and not normally displayed.
IMGUI_API void PushID(const char* str_id); // push string identifier into the ID stack. IDs == hash of the entire stack! IMGUI_API void PushID(const char* str_id); // push string into the ID stack (will hash string).
IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); // push string into the ID stack (will hash string).
IMGUI_API void PushID(const void* ptr_id); // push pointer into the ID stack. IMGUI_API void PushID(const void* ptr_id); // push pointer into the ID stack (will hash pointer).
IMGUI_API void PushID(int int_id); // push integer into the ID stack. IMGUI_API void PushID(int int_id); // push integer into the ID stack (will hash integer).
IMGUI_API void PopID(); // pop from the ID stack. IMGUI_API void PopID(); // pop from the ID stack.
IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself
IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end); IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end);
@ -483,7 +489,7 @@ namespace ImGui
IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header
// Widgets: Selectables // Widgets: Selectables
// - A selectable highlights when hovered, and can display another color when selected. // - A selectable highlights when hovered, and can display another color when selected.
// - Neighbors selectable extend their highlight bounds in order to leave no gap between them. // - Neighbors selectable extend their highlight bounds in order to leave no gap between them.
IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height
IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper.
@ -502,7 +508,7 @@ namespace ImGui
IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));
IMGUI_API void PlotHistogram(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); IMGUI_API void PlotHistogram(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0));
// Widgets: Value() Helpers. // Widgets: Value() Helpers.
// - Those are merely shortcut to calling Text() with a format string. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace) // - Those are merely shortcut to calling Text() with a format string. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace)
IMGUI_API void Value(const char* prefix, bool b); IMGUI_API void Value(const char* prefix, bool b);
IMGUI_API void Value(const char* prefix, int v); IMGUI_API void Value(const char* prefix, int v);
@ -582,7 +588,7 @@ namespace ImGui
IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released. IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released.
IMGUI_API void EndDragDropTarget(); // only call EndDragDropTarget() if BeginDragDropTarget() returns true! IMGUI_API void EndDragDropTarget(); // only call EndDragDropTarget() if BeginDragDropTarget() returns true!
IMGUI_API const ImGuiPayload* GetDragDropPayload(); // peek directly into the current payload from anywhere. may return NULL. use ImGuiPayload::IsDataType() to test for the payload type. IMGUI_API const ImGuiPayload* GetDragDropPayload(); // peek directly into the current payload from anywhere. may return NULL. use ImGuiPayload::IsDataType() to test for the payload type.
// Clipping // Clipping
IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect); IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect);
IMGUI_API void PopClipRect(); IMGUI_API void PopClipRect();
@ -601,6 +607,7 @@ namespace ImGui
IMGUI_API bool IsItemClicked(int mouse_button = 0); // is the last item clicked? (e.g. button/node just clicked on) == IsMouseClicked(mouse_button) && IsItemHovered() IMGUI_API bool IsItemClicked(int mouse_button = 0); // is the last item clicked? (e.g. button/node just clicked on) == IsMouseClicked(mouse_button) && IsItemHovered()
IMGUI_API bool IsItemVisible(); // is the last item visible? (items may be out of sight because of clipping/scrolling) IMGUI_API bool IsItemVisible(); // is the last item visible? (items may be out of sight because of clipping/scrolling)
IMGUI_API bool IsItemEdited(); // did the last item modify its underlying value this frame? or was pressed? This is generally the same as the "bool" return value of many widgets. IMGUI_API bool IsItemEdited(); // did the last item modify its underlying value this frame? or was pressed? This is generally the same as the "bool" return value of many widgets.
IMGUI_API bool IsItemActivated(); // was the last item just made active (item was previously inactive).
IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active). Useful for Undo/Redo patterns with widgets that requires continuous editing. IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active). Useful for Undo/Redo patterns with widgets that requires continuous editing.
IMGUI_API bool IsItemDeactivatedAfterEdit(); // was the last item just made inactive and made a value change when it was active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with widgets that requires continuous editing. Note that you may get false positives (some widgets such as Combo()/ListBox()/Selectable() will return true even when clicking an already selected item). IMGUI_API bool IsItemDeactivatedAfterEdit(); // was the last item just made inactive and made a value change when it was active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with widgets that requires continuous editing. Note that you may get false positives (some widgets such as Combo()/ListBox()/Selectable() will return true even when clicking an already selected item).
IMGUI_API bool IsAnyItemHovered(); IMGUI_API bool IsAnyItemHovered();
@ -652,8 +659,8 @@ namespace ImGui
IMGUI_API void ResetMouseDragDelta(int button = 0); // IMGUI_API void ResetMouseDragDelta(int button = 0); //
IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you
IMGUI_API void SetMouseCursor(ImGuiMouseCursor type); // set desired cursor type IMGUI_API void SetMouseCursor(ImGuiMouseCursor type); // set desired cursor type
IMGUI_API void CaptureKeyboardFromApp(bool want_capture_keyboard_value = true); // attention: misleading name! manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application to handle). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard_value"; after the next NewFrame() call. IMGUI_API void CaptureKeyboardFromApp(bool want_capture_keyboard_value = true); // attention: misleading name! manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application to handle). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard_value"; after the next NewFrame() call.
IMGUI_API void CaptureMouseFromApp(bool want_capture_mouse_value = true); // attention: misleading name! manually override io.WantCaptureMouse flag next frame (said flag is entirely left for your application to handle). This is equivalent to setting "io.WantCaptureMouse = want_capture_mouse_value;" after the next NewFrame() call. IMGUI_API void CaptureMouseFromApp(bool want_capture_mouse_value = true); // attention: misleading name! manually override io.WantCaptureMouse flag next frame (said flag is entirely left for your application to handle). This is equivalent to setting "io.WantCaptureMouse = want_capture_mouse_value;" after the next NewFrame() call.
// Clipboard Utilities (also see the LogToClipboard() function to capture or output text data to the clipboard) // Clipboard Utilities (also see the LogToClipboard() function to capture or output text data to the clipboard)
IMGUI_API const char* GetClipboardText(); IMGUI_API const char* GetClipboardText();
@ -670,7 +677,7 @@ namespace ImGui
// Memory Utilities // Memory Utilities
// - All those functions are not reliant on the current context. // - All those functions are not reliant on the current context.
// - If you reload the contents of imgui.cpp at runtime, you may need to call SetCurrentContext() + SetAllocatorFunctions() again. // - If you reload the contents of imgui.cpp at runtime, you may need to call SetCurrentContext() + SetAllocatorFunctions() again.
IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data = NULL); IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL);
IMGUI_API void* MemAlloc(size_t size); IMGUI_API void* MemAlloc(size_t size);
IMGUI_API void MemFree(void* ptr); IMGUI_API void MemFree(void* ptr);
@ -804,15 +811,15 @@ enum ImGuiTabBarFlags_
ImGuiTabBarFlags_None = 0, ImGuiTabBarFlags_None = 0,
ImGuiTabBarFlags_Reorderable = 1 << 0, // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list ImGuiTabBarFlags_Reorderable = 1 << 0, // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list
ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, // Automatically select new tabs when they appear ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, // Automatically select new tabs when they appear
ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. ImGuiTabBarFlags_TabListPopupButton = 1 << 2,
ImGuiTabBarFlags_NoTabListPopupButton = 1 << 3, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false.
ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4,
ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab
ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit
ImGuiTabBarFlags_FittingPolicyScroll = 1 << 7, // Add scroll buttons when tabs don't fit ImGuiTabBarFlags_FittingPolicyScroll = 1 << 7, // Add scroll buttons when tabs don't fit
ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll, ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll,
ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown
}; };
// Flags for ImGui::BeginTabItem() // Flags for ImGui::BeginTabItem()
enum ImGuiTabItemFlags_ enum ImGuiTabItemFlags_
@ -1075,6 +1082,7 @@ enum ImGuiStyleVar_
ImGuiStyleVar_GrabRounding, // float GrabRounding ImGuiStyleVar_GrabRounding, // float GrabRounding
ImGuiStyleVar_TabRounding, // float TabRounding ImGuiStyleVar_TabRounding, // float TabRounding
ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign
ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign
ImGuiStyleVar_COUNT ImGuiStyleVar_COUNT
// Obsolete names (will be removed) // Obsolete names (will be removed)
@ -1159,7 +1167,7 @@ enum ImGuiCond_
// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). // Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug).
// You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it. // You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it.
// Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs. // Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs.
// Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that, // Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that,
// do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset. // do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -1219,7 +1227,7 @@ struct ImVector
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// ImGuiStyle // ImGuiStyle
// You may modify the ImGui::GetStyle() main instance during initialization and before NewFrame(). // You may modify the ImGui::GetStyle() main instance during initialization and before NewFrame().
// During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values, // During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values,
// and ImGui::PushStyleColor(ImGuiCol_XXX)/PopStyleColor() for colors. // and ImGui::PushStyleColor(ImGuiCol_XXX)/PopStyleColor() for colors.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -1248,8 +1256,9 @@ struct ImGuiStyle
float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar.
float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
float TabBorderSize; // Thickness of border around tabs. float TabBorderSize; // Thickness of border around tabs.
ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f,0.5f) for horizontally+vertically centered. ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered).
ImVec2 SelectableTextAlign; // Alignment of selectable text when selectable is larger than text. Defaults to (0.0f, 0.0f) (top-left aligned).
ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area by at least this amount. Only applies to regular windows. ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area by at least this amount. Only applies to regular windows.
ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly! ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly!
float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
@ -1264,7 +1273,7 @@ struct ImGuiStyle
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// ImGuiIO // ImGuiIO
// Communicate most settings and inputs/outputs to Dear ImGui using this structure. // Communicate most settings and inputs/outputs to Dear ImGui using this structure.
// Access via ImGui::GetIO(). Read 'Programmer guide' section in .cpp file for general usage. // Access via ImGui::GetIO(). Read 'Programmer guide' section in .cpp file for general usage.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -1276,7 +1285,7 @@ struct ImGuiIO
ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc. ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc.
ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by back-end (imgui_impl_xxx files or custom back-end) to communicate features supported by the back-end. ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by back-end (imgui_impl_xxx files or custom back-end) to communicate features supported by the back-end.
ImVec2 DisplaySize; // <unset> // Main display size, in pixels. For clamping windows positions. ImVec2 DisplaySize; // <unset> // Main display size, in pixels.
float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds. float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds.
float IniSavingRate; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds. float IniSavingRate; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds.
const char* IniFilename; // = "imgui.ini" // Path to .ini file. Set NULL to disable automatic .ini loading/saving, if e.g. you want to manually load/save from memory. const char* IniFilename; // = "imgui.ini" // Path to .ini file. Set NULL to disable automatic .ini loading/saving, if e.g. you want to manually load/save from memory.
@ -1293,16 +1302,14 @@ struct ImGuiIO
float FontGlobalScale; // = 1.0f // Global scale all fonts float FontGlobalScale; // = 1.0f // Global scale all fonts
bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel. bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel.
ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0].
ImVec2 DisplayFramebufferScale; // = (1.0f,1.0f) // For retina display or other situations where window coordinates are different from framebuffer coordinates. User storage only, presently not used by ImGui. ImVec2 DisplayFramebufferScale; // = (1, 1) // For retina display or other situations where window coordinates are different from framebuffer coordinates. This generally ends up in ImDrawData::FramebufferScale.
ImVec2 DisplayVisibleMin; // <unset> // [OBSOLETE] If you use DisplaySize as a virtual space larger than your screen, set DisplayVisibleMin/Max to the visible area.
ImVec2 DisplayVisibleMax; // <unset> // [OBSOLETE] Just use io.DisplaySize! If the values are the same, we defaults to Min=(0.0f) and Max=DisplaySize
// Miscellaneous configuration options // Miscellaneous options
bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations. bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations.
bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63) bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63)
bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63) bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63)
bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be the a per-window ImGuiWindowFlags_ResizeFromAnySide flag) bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be the a per-window ImGuiWindowFlags_ResizeFromAnySide flag)
bool ConfigWindowsMoveFromTitleBarOnly;// = false // [BETA] Set to true to only allow moving windows when clicked+dragged from the title bar. Windows without a title bar are not affected. bool ConfigWindowsMoveFromTitleBarOnly; // = false // [BETA] Set to true to only allow moving windows when clicked+dragged from the title bar. Windows without a title bar are not affected.
//------------------------------------------------------------------ //------------------------------------------------------------------
// Platform Functions // Platform Functions
@ -1352,7 +1359,7 @@ struct ImGuiIO
float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame(). float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame().
// Functions // Functions
IMGUI_API void AddInputCharacter(ImWchar c); // Queue new character input IMGUI_API void AddInputCharacter(ImWchar c); // Queue new character input
IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string
IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually
@ -1410,7 +1417,7 @@ struct ImGuiIO
// - ImGuiInputTextFlags_CallbackHistory: Callback on pressing Up/Down arrows // - ImGuiInputTextFlags_CallbackHistory: Callback on pressing Up/Down arrows
// - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration // - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration
// - ImGuiInputTextFlags_CallbackCharFilter: Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. // - ImGuiInputTextFlags_CallbackCharFilter: Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard.
// - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. // - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow.
struct ImGuiInputTextCallbackData struct ImGuiInputTextCallbackData
{ {
ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only
@ -1490,7 +1497,7 @@ namespace ImGui
// OBSOLETED in 1.60 (between Dec 2017 and Apr 2018) // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018)
static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); }
static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); }
static inline ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = 0.f) { (void)on_edge; (void)outward; IM_ASSERT(0); return pos; } static inline ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = 0.f) { IM_UNUSED(on_edge); IM_UNUSED(outward); IM_ASSERT(0); return pos; }
// OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017)
static inline void ShowTestWindow() { return ShowDemoWindow(); } static inline void ShowTestWindow() { return ShowDemoWindow(); }
static inline bool IsRootWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootWindow); } static inline bool IsRootWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootWindow); }
@ -1579,11 +1586,12 @@ struct ImGuiTextBuffer
inline char operator[](int i) { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; } inline char operator[](int i) { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; }
const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; } const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; }
const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator
int size() const { return Buf.Data ? Buf.Size - 1 : 0; } int size() const { return Buf.Size ? Buf.Size - 1 : 0; }
bool empty() { return Buf.Size <= 1; } bool empty() { return Buf.Size <= 1; }
void clear() { Buf.clear(); } void clear() { Buf.clear(); }
void reserve(int capacity) { Buf.reserve(capacity); } void reserve(int capacity) { Buf.reserve(capacity); }
const char* c_str() const { return Buf.Data ? Buf.Data : EmptyString; } const char* c_str() const { return Buf.Data ? Buf.Data : EmptyString; }
IMGUI_API void append(const char* str, const char* str_end = NULL);
IMGUI_API void appendf(const char* fmt, ...) IM_FMTARGS(2); IMGUI_API void appendf(const char* fmt, ...) IM_FMTARGS(2);
IMGUI_API void appendfv(const char* fmt, va_list args) IM_FMTLIST(2); IMGUI_API void appendfv(const char* fmt, va_list args) IM_FMTLIST(2);
}; };
@ -1714,7 +1722,7 @@ struct ImColor
// Draw callbacks for advanced uses. // Draw callbacks for advanced uses.
// NB: You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering, // NB: You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering,
// you can poke into the draw list for that! Draw callback may be useful for example to: A) Change your GPU render state, // you can poke into the draw list for that! Draw callback may be useful for example to: A) Change your GPU render state,
// B) render a complex 3D scene inside a UI element without an intermediate texture/render target, etc. // B) render a complex 3D scene inside a UI element without an intermediate texture/render target, etc.
// The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) { cmd.UserCallback(parent_list, cmd); } else { RenderTriangles() }' // The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) { cmd.UserCallback(parent_list, cmd); } else { RenderTriangles() }'
typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd); typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd);
@ -1887,13 +1895,14 @@ struct ImDrawData
int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size
ImVec2 DisplayPos; // Upper-left position of the viewport to render (== upper-left of the orthogonal projection matrix to use) ImVec2 DisplayPos; // Upper-left position of the viewport to render (== upper-left of the orthogonal projection matrix to use)
ImVec2 DisplaySize; // Size of the viewport to render (== io.DisplaySize for the main viewport) (DisplayPos + DisplaySize == lower-right of the orthogonal projection matrix to use) ImVec2 DisplaySize; // Size of the viewport to render (== io.DisplaySize for the main viewport) (DisplayPos + DisplaySize == lower-right of the orthogonal projection matrix to use)
ImVec2 FramebufferScale; // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display.
// Functions // Functions
ImDrawData() { Valid = false; Clear(); } ImDrawData() { Valid = false; Clear(); }
~ImDrawData() { Clear(); } ~ImDrawData() { Clear(); }
void Clear() { Valid = false; CmdLists = NULL; CmdListsCount = TotalVtxCount = TotalIdxCount = 0; DisplayPos = DisplaySize = ImVec2(0.f, 0.f); } // The ImDrawList are owned by ImGuiContext! void Clear() { Valid = false; CmdLists = NULL; CmdListsCount = TotalVtxCount = TotalIdxCount = 0; DisplayPos = DisplaySize = FramebufferScale = ImVec2(0.f, 0.f); } // The ImDrawList are owned by ImGuiContext!
IMGUI_API void DeIndexAllBuffers(); // Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! IMGUI_API void DeIndexAllBuffers(); // Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering!
IMGUI_API void ScaleClipRects(const ImVec2& sc); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than ImGui expects, or if there is a difference between your window resolution and framebuffer resolution. IMGUI_API void ScaleClipRects(const ImVec2& fb_scale); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than ImGui expects, or if there is a difference between your window resolution and framebuffer resolution.
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -1907,8 +1916,8 @@ struct ImFontConfig
bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself). bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself).
int FontNo; // 0 // Index of font within TTF/OTF file int FontNo; // 0 // Index of font within TTF/OTF file
float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height).
int OversampleH; // 3 // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis. int OversampleH; // 3 // Rasterize at higher quality for sub-pixel positioning. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details.
int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis. int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis.
bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1.
ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now. ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now.
ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input.
@ -1940,13 +1949,13 @@ struct ImFontGlyphRangesBuilder
{ {
ImVector<int> UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) ImVector<int> UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used)
ImFontGlyphRangesBuilder() { UsedChars.resize(0x10000 / 32); memset(UsedChars.Data, 0, 0x10000 / 32); } ImFontGlyphRangesBuilder() { UsedChars.resize(0x10000 / sizeof(int)); memset(UsedChars.Data, 0, 0x10000 / sizeof(int)); }
bool GetBit(int n) const { int off = (n >> 5); int mask = 1 << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array bool GetBit(int n) const { int off = (n >> 5); int mask = 1 << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array
void SetBit(int n) { int off = (n >> 5); int mask = 1 << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array void SetBit(int n) { int off = (n >> 5); int mask = 1 << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array
void AddChar(ImWchar c) { SetBit(c); } // Add character void AddChar(ImWchar c) { SetBit(c); } // Add character
IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added) IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added)
IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext
IMGUI_API void BuildRanges(ImVector<ImWchar>* out_ranges); // Output new ranges IMGUI_API void BuildRanges(ImVector<ImWchar>* out_ranges); // Output new ranges
}; };
enum ImFontAtlasFlags_ enum ImFontAtlasFlags_
@ -1964,13 +1973,13 @@ enum ImFontAtlasFlags_
// - Optionally, call any of the AddFont*** functions. If you don't call any, the default font embedded in the code will be loaded for you. // - Optionally, call any of the AddFont*** functions. If you don't call any, the default font embedded in the code will be loaded for you.
// - Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data. // - Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data.
// - Upload the pixels data into a texture within your graphics system (see imgui_impl_xxxx.cpp examples) // - Upload the pixels data into a texture within your graphics system (see imgui_impl_xxxx.cpp examples)
// - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API. // - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API.
// This value will be passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID for more details. // This value will be passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID for more details.
// Common pitfalls: // Common pitfalls:
// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the // - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the
// atlas is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data. // atlas is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data.
// - Important: By default, AddFontFromMemoryTTF() takes ownership of the data. Even though we are not writing to it, we will free the pointer on destruction. // - Important: By default, AddFontFromMemoryTTF() takes ownership of the data. Even though we are not writing to it, we will free the pointer on destruction.
// You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed, // You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed,
// - Even though many functions are suffixed with "TTF", OTF data is supported just as well. // - Even though many functions are suffixed with "TTF", OTF data is supported just as well.
// - This is an old API and it is currently awkward for those and and various other reasons! We will address them in the future! // - This is an old API and it is currently awkward for those and and various other reasons! We will address them in the future!
struct ImFontAtlas struct ImFontAtlas
@ -1991,7 +2000,7 @@ struct ImFontAtlas
// Build atlas, retrieve pixel data. // Build atlas, retrieve pixel data.
// User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID().
// The pitch is always = Width * BytesPerPixels (1 or 4) // The pitch is always = Width * BytesPerPixels (1 or 4)
// Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into // Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into
// the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste. // the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste.
IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions.
IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel
@ -2072,33 +2081,32 @@ struct ImFontAtlas
// ImFontAtlas automatically loads a default embedded font for you when you call GetTexDataAsAlpha8() or GetTexDataAsRGBA32(). // ImFontAtlas automatically loads a default embedded font for you when you call GetTexDataAsAlpha8() or GetTexDataAsRGBA32().
struct ImFont struct ImFont
{ {
// Members: Hot ~62/78 bytes // Members: Hot ~20/24 bytes (for CalcTextSize)
float FontSize; // <user set> // Height of characters, set during loading (don't change after loading) ImVector<float> IndexAdvanceX; // 12-16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this this info, and are often bottleneck in large UI).
float Scale; // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetFontScale() float FallbackAdvanceX; // 4 // out // = FallbackGlyph->AdvanceX
ImVec2 DisplayOffset; // = (0.f,0.f) // Offset font rendering by xx pixels float FontSize; // 4 // in // // Height of characters/line, set during loading (don't change after loading)
ImVector<ImFontGlyph> Glyphs; // // All glyphs.
ImVector<float> IndexAdvanceX; // // Sparse. Glyphs->AdvanceX in a directly indexable way (more cache-friendly, for CalcTextSize functions which are often bottleneck in large UI).
ImVector<ImWchar> IndexLookup; // // Sparse. Index glyphs by Unicode code-point.
const ImFontGlyph* FallbackGlyph; // == FindGlyph(FontFallbackChar)
float FallbackAdvanceX; // == FallbackGlyph->AdvanceX
ImWchar FallbackChar; // = '?' // Replacement glyph if one isn't found. Only set via SetFallbackChar()
// Members: Cold ~18/26 bytes // Members: Hot ~36/48 bytes (for CalcTextSize + render loop)
short ConfigDataCount; // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont. ImVector<ImWchar> IndexLookup; // 12-16 // out // // Sparse. Index glyphs by Unicode code-point.
ImFontConfig* ConfigData; // // Pointer within ContainerAtlas->ConfigData ImVector<ImFontGlyph> Glyphs; // 12-16 // out // // All glyphs.
ImFontAtlas* ContainerAtlas; // // What we has been loaded into const ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar)
float Ascent, Descent; // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] ImVec2 DisplayOffset; // 8 // in // = (0,0) // Offset font rendering by xx pixels
bool DirtyLookupTables;
int MetricsTotalSurface;// // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) // Members: Cold ~32/40 bytes
ImFontAtlas* ContainerAtlas; // 4-8 // out // // What we has been loaded into
const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData
short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont.
ImWchar FallbackChar; // 2 // in // = '?' // Replacement glyph if one isn't found. Only set via SetFallbackChar()
float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale()
float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize]
int MetricsTotalSurface;// 4 // out // // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs)
bool DirtyLookupTables; // 1 // out //
// Methods // Methods
IMGUI_API ImFont(); IMGUI_API ImFont();
IMGUI_API ~ImFont(); IMGUI_API ~ImFont();
IMGUI_API void ClearOutputData();
IMGUI_API void BuildLookupTable();
IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c) const; IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c) const;
IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c) const; IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c) const;
IMGUI_API void SetFallbackChar(ImWchar c);
float GetCharAdvance(ImWchar c) const { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; } float GetCharAdvance(ImWchar c) const { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; }
bool IsLoaded() const { return ContainerAtlas != NULL; } bool IsLoaded() const { return ContainerAtlas != NULL; }
const char* GetDebugName() const { return ConfigData ? ConfigData->Name : "<unknown>"; } const char* GetDebugName() const { return ConfigData ? ConfigData->Name : "<unknown>"; }
@ -2110,10 +2118,13 @@ struct ImFont
IMGUI_API void RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const; IMGUI_API void RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const;
IMGUI_API void RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; IMGUI_API void RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const;
// [Internal] // [Internal] Don't use!
IMGUI_API void BuildLookupTable();
IMGUI_API void ClearOutputData();
IMGUI_API void GrowIndex(int new_size); IMGUI_API void GrowIndex(int new_size);
IMGUI_API void AddGlyph(ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x); IMGUI_API void AddGlyph(ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x);
IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built.
IMGUI_API void SetFallbackChar(ImWchar c);
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
typedef ImFontGlyph Glyph; // OBSOLETE 1.52+ typedef ImFontGlyph Glyph; // OBSOLETE 1.52+

View File

@ -1,24 +1,24 @@
// dear imgui, v1.67 // dear imgui, v1.68
// (demo code) // (demo code)
// Message to the person tempted to delete this file when integrating Dear ImGui into their code base: // Message to the person tempted to delete this file when integrating Dear ImGui into their code base:
// Do NOT remove this file from your project! Think again! It is the most useful reference code that you and other coders // Do NOT remove this file from your project! Think again! It is the most useful reference code that you and other coders
// will want to refer to and call. Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of // will want to refer to and call. Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of
// your game/app! Removing this file from your project is hindering access to documentation for everyone in your team, // your game/app! Removing this file from your project is hindering access to documentation for everyone in your team,
// likely leading you to poorer usage of the library. // likely leading you to poorer usage of the library.
// Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow(). // Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow().
// If you want to link core Dear ImGui in your shipped builds but want an easy guarantee that the demo will not be linked, // If you want to link core Dear ImGui in your shipped builds but want an easy guarantee that the demo will not be linked,
// you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty. // you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty.
// In other situation, whenever you have Dear ImGui available you probably want this to be available for reference. // In other situation, whenever you have Dear ImGui available you probably want this to be available for reference.
// Thank you, // Thank you,
// -Your beloved friend, imgui_demo.cpp (that you won't delete) // -Your beloved friend, imgui_demo.cpp (that you won't delete)
// Message to beginner C/C++ programmers about the meaning of the 'static' keyword: // Message to beginner C/C++ programmers about the meaning of the 'static' keyword:
// In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls, so it is // In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls, so it is
// essentially like a global variable but declared inside the scope of the function. We do this as a way to gather code and data // essentially like a global variable but declared inside the scope of the function. We do this as a way to gather code and data
// in the same place, to make the demo source code faster to read, faster to write, and smaller in size. // in the same place, to make the demo source code faster to read, faster to write, and smaller in size.
// It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be reentrant // It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be reentrant
// or used in threads. This might be a pattern you will want to use in your code, but most of the real data you would be editing is // or used in threads. This might be a pattern you will want to use in your code, but most of the real data you would be editing is
// likely going to be stored outside your functions. // likely going to be stored outside your functions.
/* /*
@ -62,7 +62,6 @@ Index of this file:
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
#define vsnprintf _vsnprintf
#endif #endif
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
@ -70,7 +69,10 @@ Index of this file:
#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int'
#pragma clang diagnostic ignored "-Wformat-security" // warning : warning: format string is not a string literal #pragma clang diagnostic ignored "-Wformat-security" // warning : warning: format string is not a string literal
#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. #pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals.
#pragma clang diagnostic ignored "-Wunused-macros" // warning : warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used.
#if __has_warning("-Wzero-as-null-pointer-constant")
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0
#endif
#if __has_warning("-Wdouble-promotion") #if __has_warning("-Wdouble-promotion")
#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. #pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
#endif #endif
@ -89,9 +91,11 @@ Index of this file:
// Play it nice with Windows users. Notepad in 2017 still doesn't display text data with Unix-style \n. // Play it nice with Windows users. Notepad in 2017 still doesn't display text data with Unix-style \n.
#ifdef _WIN32 #ifdef _WIN32
#define IM_NEWLINE "\r\n" #define IM_NEWLINE "\r\n"
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#else #else
#define IM_NEWLINE "\n" #define IM_NEWLINE "\n"
#endif #endif
#define IM_MAX(_A,_B) (((_A) >= (_B)) ? (_A) : (_B)) #define IM_MAX(_A,_B) (((_A) >= (_B)) ? (_A) : (_B))
@ -336,6 +340,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
if (ImGui::TreeNode("Backend Flags")) if (ImGui::TreeNode("Backend Flags"))
{ {
ShowHelpMarker("Those flags are set by the back-ends (imgui_impl_xxx files) to specify their capabilities.");
ImGuiBackendFlags backend_flags = io.BackendFlags; // Make a local copy to avoid modifying the back-end flags. ImGuiBackendFlags backend_flags = io.BackendFlags; // Make a local copy to avoid modifying the back-end flags.
ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasGamepad); ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasGamepad);
ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasMouseCursors); ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasMouseCursors);
@ -419,7 +424,7 @@ static void ShowDemoWindowWidgets()
// Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
for (int i = 0; i < 7; i++) for (int i = 0; i < 7; i++)
{ {
if (i > 0) if (i > 0)
ImGui::SameLine(); ImGui::SameLine();
ImGui::PushID(i); ImGui::PushID(i);
ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i/7.0f, 0.6f, 0.6f)); ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i/7.0f, 0.6f, 0.6f));
@ -871,23 +876,44 @@ static void ShowDemoWindowWidgets()
} }
if (ImGui::TreeNode("Grid")) if (ImGui::TreeNode("Grid"))
{ {
static bool selected[16] = { true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true }; static bool selected[4*4] = { true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true };
for (int i = 0; i < 16; i++) for (int i = 0; i < 4*4; i++)
{ {
ImGui::PushID(i); ImGui::PushID(i);
if (ImGui::Selectable("Sailor", &selected[i], 0, ImVec2(50,50))) if (ImGui::Selectable("Sailor", &selected[i], 0, ImVec2(50,50)))
{ {
int x = i % 4, y = i / 4; // Note: We _unnecessarily_ test for both x/y and i here only to silence some static analyzer. The second part of each test is unnecessary.
if (x > 0) selected[i - 1] ^= 1; int x = i % 4;
if (x < 3) selected[i + 1] ^= 1; int y = i / 4;
if (y > 0) selected[i - 4] ^= 1; if (x > 0) { selected[i - 1] ^= 1; }
if (y < 3) selected[i + 4] ^= 1; if (x < 3 && i < 15) { selected[i + 1] ^= 1; }
if (y > 0 && i > 3) { selected[i - 4] ^= 1; }
if (y < 3 && i < 12) { selected[i + 4] ^= 1; }
} }
if ((i % 4) < 3) ImGui::SameLine(); if ((i % 4) < 3) ImGui::SameLine();
ImGui::PopID(); ImGui::PopID();
} }
ImGui::TreePop(); ImGui::TreePop();
} }
if (ImGui::TreeNode("Alignment"))
{
ShowHelpMarker("Alignment applies when a selectable is larger than its text content.\nBy default, Selectables uses style.SelectableTextAlign but it can be overriden on a per-item basis using PushStyleVar().");
static bool selected[3*3] = { true, false, true, false, true, false, true, false, true };
for (int y = 0; y < 3; y++)
{
for (int x = 0; x < 3; x++)
{
ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f);
char name[32];
sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y);
if (x > 0) ImGui::SameLine();
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment);
ImGui::Selectable(name, &selected[3*y+x], ImGuiSelectableFlags_None, ImVec2(80,80));
ImGui::PopStyleVar();
}
}
ImGui::TreePop();
}
ImGui::TreePop(); ImGui::TreePop();
} }
@ -912,7 +938,7 @@ static void ShowDemoWindowWidgets()
if (ImGui::TreeNode("Multi-line Text Input")) if (ImGui::TreeNode("Multi-line Text Input"))
{ {
// Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize
// and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings. // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings.
static bool read_only = false; static bool read_only = false;
static char text[1024*16] = static char text[1024*16] =
@ -947,7 +973,7 @@ static void ShowDemoWindowWidgets()
static float values[90] = { 0 }; static float values[90] = { 0 };
static int values_offset = 0; static int values_offset = 0;
static double refresh_time = 0.0; static double refresh_time = 0.0;
if (!animate || refresh_time == 0.0f) if (!animate || refresh_time == 0.0)
refresh_time = ImGui::GetTime(); refresh_time = ImGui::GetTime();
while (refresh_time < ImGui::GetTime()) // Create dummy data at fixed 60 hz rate for the demo while (refresh_time < ImGui::GetTime()) // Create dummy data at fixed 60 hz rate for the demo
{ {
@ -1000,7 +1026,7 @@ static void ShowDemoWindowWidgets()
if (ImGui::TreeNode("Color/Picker Widgets")) if (ImGui::TreeNode("Color/Picker Widgets"))
{ {
static ImVec4 color = ImColor(114, 144, 154, 200); static ImVec4 color = ImVec4(114.0f/255.0f, 144.0f/255.0f, 154.0f/255.0f, 200.0f/255.0f);
static bool alpha_preview = true; static bool alpha_preview = true;
static bool alpha_half_preview = false; static bool alpha_half_preview = false;
@ -1030,16 +1056,18 @@ static void ShowDemoWindowWidgets()
ImGui::Text("Color button with Custom Picker Popup:"); ImGui::Text("Color button with Custom Picker Popup:");
// Generate a dummy palette // Generate a dummy default palette. The palette will persist and can be edited.
static bool saved_palette_inited = false; static bool saved_palette_init = true;
static ImVec4 saved_palette[32]; static ImVec4 saved_palette[32] = { };
if (!saved_palette_inited) if (saved_palette_init)
{
for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
{ {
ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, saved_palette[n].x, saved_palette[n].y, saved_palette[n].z); ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, saved_palette[n].x, saved_palette[n].y, saved_palette[n].z);
saved_palette[n].w = 1.0f; // Alpha saved_palette[n].w = 1.0f; // Alpha
} }
saved_palette_inited = true; saved_palette_init = false;
}
static ImVec4 backup_color; static ImVec4 backup_color;
bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags); bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags);
@ -1052,12 +1080,12 @@ static void ShowDemoWindowWidgets()
} }
if (ImGui::BeginPopup("mypicker")) if (ImGui::BeginPopup("mypicker"))
{ {
// FIXME: Adding a drag and drop example here would be perfect!
ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!"); ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!");
ImGui::Separator(); ImGui::Separator();
ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
ImGui::SameLine(); ImGui::SameLine();
ImGui::BeginGroup();
ImGui::BeginGroup(); // Lock X position
ImGui::Text("Current"); ImGui::Text("Current");
ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60,40)); ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60,40));
ImGui::Text("Previous"); ImGui::Text("Previous");
@ -1073,6 +1101,8 @@ static void ShowDemoWindowWidgets()
if (ImGui::ColorButton("##palette", saved_palette[n], ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip, ImVec2(20,20))) if (ImGui::ColorButton("##palette", saved_palette[n], ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip, ImVec2(20,20)))
color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
// Allow user to drop colors into each palette entry
// (Note that ColorButton is already a drag source by default, unless using ImGuiColorEditFlags_NoDragDrop)
if (ImGui::BeginDragDropTarget()) if (ImGui::BeginDragDropTarget())
{ {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
@ -1149,15 +1179,15 @@ static void ShowDemoWindowWidgets()
if (ImGui::TreeNode("Data Types")) if (ImGui::TreeNode("Data Types"))
{ {
// The DragScalar/InputScalar/SliderScalar functions allow various data types: signed/unsigned int/long long and float/double // The DragScalar/InputScalar/SliderScalar functions allow various data types: signed/unsigned int/long long and float/double
// To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum to pass the type, // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum to pass the type,
// and passing all arguments by address. // and passing all arguments by address.
// This is the reason the test code below creates local variables to hold "zero" "one" etc. for each types. // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each types.
// In practice, if you frequently use a given type that is not covered by the normal API entry points, you can wrap it // In practice, if you frequently use a given type that is not covered by the normal API entry points, you can wrap it
// yourself inside a 1 line function which can take typed argument as value instead of void*, and then pass their address // yourself inside a 1 line function which can take typed argument as value instead of void*, and then pass their address
// to the generic function. For example: // to the generic function. For example:
// bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld")
// { // {
// return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format);
// } // }
// Limits (as helper variables that we can take the address of) // Limits (as helper variables that we can take the address of)
@ -1352,7 +1382,7 @@ static void ShowDemoWindowWidgets()
static int mode = 0; static int mode = 0;
if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine(); if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine();
if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine(); if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine();
if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; } if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; }
static const char* names[9] = { "Bobby", "Beatrice", "Betty", "Brianna", "Barry", "Bernard", "Bibi", "Blaine", "Bryn" }; static const char* names[9] = { "Bobby", "Beatrice", "Betty", "Brianna", "Barry", "Bernard", "Bibi", "Blaine", "Bryn" };
for (int n = 0; n < IM_ARRAYSIZE(names); n++) for (int n = 0; n < IM_ARRAYSIZE(names); n++)
{ {
@ -1411,7 +1441,7 @@ static void ShowDemoWindowWidgets()
static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f }; static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f };
ImGui::RadioButton("Text", &item_type, 0); ImGui::RadioButton("Text", &item_type, 0);
ImGui::RadioButton("Button", &item_type, 1); ImGui::RadioButton("Button", &item_type, 1);
ImGui::RadioButton("CheckBox", &item_type, 2); ImGui::RadioButton("Checkbox", &item_type, 2);
ImGui::RadioButton("SliderFloat", &item_type, 3); ImGui::RadioButton("SliderFloat", &item_type, 3);
ImGui::RadioButton("ColorEdit4", &item_type, 4); ImGui::RadioButton("ColorEdit4", &item_type, 4);
ImGui::RadioButton("ListBox", &item_type, 5); ImGui::RadioButton("ListBox", &item_type, 5);
@ -1419,7 +1449,7 @@ static void ShowDemoWindowWidgets()
bool ret = false; bool ret = false;
if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction
if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button
if (item_type == 2) { ret = ImGui::Checkbox("ITEM: CheckBox", &b); } // Testing checkbox if (item_type == 2) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox
if (item_type == 3) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item if (item_type == 3) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item
if (item_type == 4) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) if (item_type == 4) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
if (item_type == 5) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } if (item_type == 5) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
@ -1433,6 +1463,7 @@ static void ShowDemoWindowWidgets()
"IsItemHovered(_RectOnly) = %d\n" "IsItemHovered(_RectOnly) = %d\n"
"IsItemActive() = %d\n" "IsItemActive() = %d\n"
"IsItemEdited() = %d\n" "IsItemEdited() = %d\n"
"IsItemActivated() = %d\n"
"IsItemDeactivated() = %d\n" "IsItemDeactivated() = %d\n"
"IsItemDeactivatedEdit() = %d\n" "IsItemDeactivatedEdit() = %d\n"
"IsItemVisible() = %d\n" "IsItemVisible() = %d\n"
@ -1448,6 +1479,7 @@ static void ShowDemoWindowWidgets()
ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly),
ImGui::IsItemActive(), ImGui::IsItemActive(),
ImGui::IsItemEdited(), ImGui::IsItemEdited(),
ImGui::IsItemActivated(),
ImGui::IsItemDeactivated(), ImGui::IsItemDeactivated(),
ImGui::IsItemDeactivatedAfterEdit(), ImGui::IsItemDeactivatedAfterEdit(),
ImGui::IsItemVisible(), ImGui::IsItemVisible(),
@ -1497,7 +1529,7 @@ static void ShowDemoWindowWidgets()
if (embed_all_inside_a_child_window) if (embed_all_inside_a_child_window)
ImGui::EndChild(); ImGui::EndChild();
// Calling IsItemHovered() after begin returns the hovered status of the title bar. // Calling IsItemHovered() after begin returns the hovered status of the title bar.
// This is useful in particular if you want to create a context menu (with BeginPopupContextItem) associated to the title bar of a window. // This is useful in particular if you want to create a context menu (with BeginPopupContextItem) associated to the title bar of a window.
static bool test_window = false; static bool test_window = false;
ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window); ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window);
@ -1765,6 +1797,7 @@ static void ShowDemoWindowLayout()
static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable;
ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable); ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable);
ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs);
ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
@ -1975,9 +2008,9 @@ static void ShowDemoWindowLayout()
ImGui::EndChild(); ImGui::EndChild();
ImGui::PopStyleVar(2); ImGui::PopStyleVar(2);
float scroll_x_delta = 0.0f; float scroll_x_delta = 0.0f;
ImGui::SmallButton("<<"); if (ImGui::IsItemActive()) scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; ImGui::SameLine(); ImGui::SmallButton("<<"); if (ImGui::IsItemActive()) { scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; } ImGui::SameLine();
ImGui::Text("Scroll from code"); ImGui::SameLine(); ImGui::Text("Scroll from code"); ImGui::SameLine();
ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; ImGui::SameLine(); ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) { scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; } ImGui::SameLine();
ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x); ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x);
if (scroll_x_delta != 0.0f) if (scroll_x_delta != 0.0f)
{ {
@ -2023,7 +2056,7 @@ static void ShowDemoWindowPopups()
// if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); } // if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); }
// With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state. // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state.
// This may be a bit confusing at first but it should quickly make sense. Follow on the examples below. // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below.
if (ImGui::TreeNode("Popups")) if (ImGui::TreeNode("Popups"))
{ {
@ -2119,7 +2152,7 @@ static void ShowDemoWindowPopups()
ImGui::Text("(You can also right-click me to the same popup as above.)"); ImGui::Text("(You can also right-click me to the same popup as above.)");
ImGui::OpenPopupOnItemClick("item context menu", 1); ImGui::OpenPopupOnItemClick("item context menu", 1);
// When used after an item that has an ID (here the Button), we can skip providing an ID to BeginPopupContextItem(). // When used after an item that has an ID (here the Button), we can skip providing an ID to BeginPopupContextItem().
// BeginPopupContextItem() will use the last item ID as the popup ID. // BeginPopupContextItem() will use the last item ID as the popup ID.
// In addition here, we want to include your editable label inside the button label. We use the ### operator to override the ID (read FAQ about ID for details) // In addition here, we want to include your editable label inside the button label. We use the ### operator to override the ID (read FAQ about ID for details)
static char name[32] = "Label1"; static char name[32] = "Label1";
@ -2167,13 +2200,24 @@ static void ShowDemoWindowPopups()
if (ImGui::Button("Stacked modals..")) if (ImGui::Button("Stacked modals.."))
ImGui::OpenPopup("Stacked 1"); ImGui::OpenPopup("Stacked 1");
if (ImGui::BeginPopupModal("Stacked 1")) if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar))
{ {
if (ImGui::BeginMenuBar())
{
if (ImGui::BeginMenu("File"))
{
if (ImGui::MenuItem("Dummy menu item")) {}
ImGui::EndMenu();
}
ImGui::EndMenuBar();
}
ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it."); ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.");
// Testing behavior of widgets stacking their own regular popups over the modal.
static int item = 1; static int item = 1;
ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
static float color[4] = { 0.4f,0.7f,0.0f,0.5f }; static float color[4] = { 0.4f,0.7f,0.0f,0.5f };
ImGui::ColorEdit4("color", color); // This is to test behavior of stacked regular popups over a modal ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
ImGui::ColorEdit4("color", color);
if (ImGui::Button("Add another modal..")) if (ImGui::Button("Add another modal.."))
ImGui::OpenPopup("Stacked 2"); ImGui::OpenPopup("Stacked 2");
@ -2505,9 +2549,9 @@ static void ShowDemoWindowMisc()
// Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item
static float f3[3] = { 0.0f, 0.0f, 0.0f }; static float f3[3] = { 0.0f, 0.0f, 0.0f };
int focus_ahead = -1; int focus_ahead = -1;
if (ImGui::Button("Focus on X")) focus_ahead = 0; ImGui::SameLine(); if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine();
if (ImGui::Button("Focus on Y")) focus_ahead = 1; ImGui::SameLine(); if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine();
if (ImGui::Button("Focus on Z")) focus_ahead = 2; if (ImGui::Button("Focus on Z")) { focus_ahead = 2; }
if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead); if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead);
ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f); ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f);
@ -2667,6 +2711,7 @@ void ImGui::ShowAboutWindow(bool* p_open)
ImGui::Separator(); ImGui::Separator();
ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexWidth, io.Fonts->TexHeight); ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexWidth, io.Fonts->TexHeight);
ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y); ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y);
ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
ImGui::Separator(); ImGui::Separator();
ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y); ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y);
ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize); ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize);
@ -2714,8 +2759,13 @@ void ImGui::ShowFontSelector(const char* label)
if (ImGui::BeginCombo(label, font_current->GetDebugName())) if (ImGui::BeginCombo(label, font_current->GetDebugName()))
{ {
for (int n = 0; n < io.Fonts->Fonts.Size; n++) for (int n = 0; n < io.Fonts->Fonts.Size; n++)
if (ImGui::Selectable(io.Fonts->Fonts[n]->GetDebugName(), io.Fonts->Fonts[n] == font_current)) {
io.FontDefault = io.Fonts->Fonts[n]; ImFont* font = io.Fonts->Fonts[n];
ImGui::PushID((void*)font);
if (ImGui::Selectable(font->GetDebugName(), font == font_current))
io.FontDefault = font;
ImGui::PopID();
}
ImGui::EndCombo(); ImGui::EndCombo();
} }
ImGui::SameLine(); ImGui::SameLine();
@ -2772,7 +2822,6 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
{ {
ImGui::Text("Main"); ImGui::Text("Main");
ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 16.0f, "%.0f");
ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
@ -2787,15 +2836,17 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
ImGui::Text("Rounding"); ImGui::Text("Rounding");
ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 14.0f, "%.0f"); ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 16.0f, "%.0f"); ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
ImGui::Text("Alignment"); ImGui::Text("Alignment");
ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ShowHelpMarker("Alignment applies when a button is larger than its text content."); ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ShowHelpMarker("Alignment applies when a button is larger than its text content.");
ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ShowHelpMarker("Alignment applies when a selectable is larger than its text content.");
ImGui::Text("Safe Area Padding"); ImGui::SameLine(); ShowHelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); ImGui::Text("Safe Area Padding"); ImGui::SameLine(); ShowHelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f");
ImGui::EndTabItem(); ImGui::EndTabItem();
@ -2861,7 +2912,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
if (ImGui::BeginTabItem("Fonts")) if (ImGui::BeginTabItem("Fonts"))
{ {
ImFontAtlas* atlas = ImGui::GetIO().Fonts; ImGuiIO& io = ImGui::GetIO();
ImFontAtlas* atlas = io.Fonts;
ShowHelpMarker("Read FAQ and misc/fonts/README.txt for details on font loading."); ShowHelpMarker("Read FAQ and misc/fonts/README.txt for details on font loading.");
ImGui::PushItemWidth(120); ImGui::PushItemWidth(120);
for (int i = 0; i < atlas->Fonts.Size; i++) for (int i = 0; i < atlas->Fonts.Size; i++)
@ -2869,7 +2921,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImFont* font = atlas->Fonts[i]; ImFont* font = atlas->Fonts[i];
ImGui::PushID(font); ImGui::PushID(font);
bool font_details_opened = ImGui::TreeNode(font, "Font %d: \"%s\"\n%.2f px, %d glyphs, %d file(s)", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); bool font_details_opened = ImGui::TreeNode(font, "Font %d: \"%s\"\n%.2f px, %d glyphs, %d file(s)", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount);
ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) ImGui::GetIO().FontDefault = font; ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { io.FontDefault = font; }
if (font_details_opened) if (font_details_opened)
{ {
ImGui::PushFont(font); ImGui::PushFont(font);
@ -2880,9 +2932,10 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, "%.0f"); ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, "%.0f");
ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent);
ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar); ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar);
ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)sqrtf((float)font->MetricsTotalSurface), (int)sqrtf((float)font->MetricsTotalSurface)); const float surface_sqrt = sqrtf((float)font->MetricsTotalSurface);
ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)surface_sqrt, (int)surface_sqrt);
for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) for (int config_i = 0; config_i < font->ConfigDataCount; config_i++)
if (ImFontConfig* cfg = &font->ConfigData[config_i]) if (const ImFontConfig* cfg = &font->ConfigData[config_i])
ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH); ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH);
if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
{ {
@ -2934,9 +2987,9 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
} }
static float window_scale = 1.0f; static float window_scale = 1.0f;
if (ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f")) // scale only this window if (ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.2f")) // scale only this window
ImGui::SetWindowFontScale(window_scale); ImGui::SetWindowFontScale(window_scale);
ImGui::DragFloat("global scale", &ImGui::GetIO().FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale everything ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.2f"); // scale everything
ImGui::PopItemWidth(); ImGui::PopItemWidth();
ImGui::EndTabItem(); ImGui::EndTabItem();
@ -3064,10 +3117,12 @@ struct ExampleAppConsole
{ {
char InputBuf[256]; char InputBuf[256];
ImVector<char*> Items; ImVector<char*> Items;
bool ScrollToBottom; ImVector<const char*> Commands;
ImVector<char*> History; ImVector<char*> History;
int HistoryPos; // -1: new line, 0..History.Size-1 browsing history. int HistoryPos; // -1: new line, 0..History.Size-1 browsing history.
ImVector<const char*> Commands; ImGuiTextFilter Filter;
bool AutoScroll;
bool ScrollToBottom;
ExampleAppConsole() ExampleAppConsole()
{ {
@ -3078,6 +3133,8 @@ struct ExampleAppConsole
Commands.push_back("HISTORY"); Commands.push_back("HISTORY");
Commands.push_back("CLEAR"); Commands.push_back("CLEAR");
Commands.push_back("CLASSIFY"); // "classify" is only here to provide an example of "C"+[tab] completing to "CL" and displaying matches. Commands.push_back("CLASSIFY"); // "classify" is only here to provide an example of "C"+[tab] completing to "CL" and displaying matches.
AutoScroll = true;
ScrollToBottom = true;
AddLog("Welcome to Dear ImGui!"); AddLog("Welcome to Dear ImGui!");
} }
~ExampleAppConsole() ~ExampleAppConsole()
@ -3090,7 +3147,7 @@ struct ExampleAppConsole
// Portable helpers // Portable helpers
static int Stricmp(const char* str1, const char* str2) { int d; while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } return d; } static int Stricmp(const char* str1, const char* str2) { int d; while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } return d; }
static int Strnicmp(const char* str1, const char* str2, int n) { int d = 0; while (n > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; n--; } return d; } static int Strnicmp(const char* str1, const char* str2, int n) { int d = 0; while (n > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; n--; } return d; }
static char* Strdup(const char *str) { size_t len = strlen(str) + 1; void* buff = malloc(len); return (char*)memcpy(buff, (const void*)str, len); } static char* Strdup(const char *str) { size_t len = strlen(str) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)str, len); }
static void Strtrim(char* str) { char* str_end = str + strlen(str); while (str_end > str && str_end[-1] == ' ') str_end--; *str_end = 0; } static void Strtrim(char* str) { char* str_end = str + strlen(str); while (str_end > str && str_end[-1] == ' ') str_end--; *str_end = 0; }
void ClearLog() void ClearLog()
@ -3111,7 +3168,8 @@ struct ExampleAppConsole
buf[IM_ARRAYSIZE(buf)-1] = 0; buf[IM_ARRAYSIZE(buf)-1] = 0;
va_end(args); va_end(args);
Items.push_back(Strdup(buf)); Items.push_back(Strdup(buf));
ScrollToBottom = true; if (AutoScroll)
ScrollToBottom = true;
} }
void Draw(const char* title, bool* p_open) void Draw(const char* title, bool* p_open)
@ -3137,7 +3195,7 @@ struct ExampleAppConsole
// TODO: display items starting from the bottom // TODO: display items starting from the bottom
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 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 Error")) { AddLog("[error] something went wrong"); } ImGui::SameLine();
if (ImGui::SmallButton("Clear")) { ClearLog(); } ImGui::SameLine(); if (ImGui::SmallButton("Clear")) { ClearLog(); } ImGui::SameLine();
bool copy_to_clipboard = ImGui::SmallButton("Copy"); ImGui::SameLine(); bool copy_to_clipboard = ImGui::SmallButton("Copy"); ImGui::SameLine();
@ -3146,10 +3204,20 @@ struct ExampleAppConsole
ImGui::Separator(); ImGui::Separator();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0)); // Options menu
static ImGuiTextFilter filter; if (ImGui::BeginPopup("Options"))
filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180); {
ImGui::PopStyleVar(); if (ImGui::Checkbox("Auto-scroll", &AutoScroll))
if (AutoScroll)
ScrollToBottom = true;
ImGui::EndPopup();
}
// Options, Filter
if (ImGui::Button("Options"))
ImGui::OpenPopup("Options");
ImGui::SameLine();
Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
ImGui::Separator(); ImGui::Separator();
const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); // 1 separator, 1 input text const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); // 1 separator, 1 input text
@ -3174,18 +3242,19 @@ struct ExampleAppConsole
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4,1)); // Tighten spacing ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4,1)); // Tighten spacing
if (copy_to_clipboard) if (copy_to_clipboard)
ImGui::LogToClipboard(); ImGui::LogToClipboard();
ImVec4 col_default_text = ImGui::GetStyleColorVec4(ImGuiCol_Text);
for (int i = 0; i < Items.Size; i++) for (int i = 0; i < Items.Size; i++)
{ {
const char* item = Items[i]; const char* item = Items[i];
if (!filter.PassFilter(item)) if (!Filter.PassFilter(item))
continue; continue;
ImVec4 col = col_default_text;
if (strstr(item, "[error]")) col = ImColor(1.0f,0.4f,0.4f,1.0f); // Normally you would store more information in your item (e.g. make Items[] an array of structure, store color/type etc.)
else if (strncmp(item, "# ", 2) == 0) col = ImColor(1.0f,0.78f,0.58f,1.0f); bool pop_color = false;
ImGui::PushStyleColor(ImGuiCol_Text, col); if (strstr(item, "[error]")) { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.4f, 0.4f, 1.0f)); pop_color = true; }
else if (strncmp(item, "# ", 2) == 0) { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.8f, 0.6f, 1.0f)); pop_color = true; }
ImGui::TextUnformatted(item); ImGui::TextUnformatted(item);
ImGui::PopStyleColor(); if (pop_color)
ImGui::PopStyleColor();
} }
if (copy_to_clipboard) if (copy_to_clipboard)
ImGui::LogFinish(); ImGui::LogFinish();
@ -3252,6 +3321,9 @@ struct ExampleAppConsole
{ {
AddLog("Unknown command: '%s'\n", command_line); AddLog("Unknown command: '%s'\n", command_line);
} }
// On commad input, we scroll to bottom even if AutoScroll==false
ScrollToBottom = true;
} }
static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) // In C++11 you are better off using lambdas for this sort of forwarding callbacks static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) // In C++11 you are better off using lambdas for this sort of forwarding callbacks
@ -3380,12 +3452,20 @@ struct ExampleAppLog
ImGuiTextBuffer Buf; ImGuiTextBuffer Buf;
ImGuiTextFilter Filter; ImGuiTextFilter Filter;
ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls, allowing us to have a random access on lines ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls, allowing us to have a random access on lines
bool AutoScroll;
bool ScrollToBottom; bool ScrollToBottom;
void Clear() ExampleAppLog()
{ {
Buf.clear(); AutoScroll = true;
LineOffsets.clear(); ScrollToBottom = false;
Clear();
}
void Clear()
{
Buf.clear();
LineOffsets.clear();
LineOffsets.push_back(0); LineOffsets.push_back(0);
} }
@ -3399,7 +3479,8 @@ struct ExampleAppLog
for (int new_size = Buf.size(); old_size < new_size; old_size++) for (int new_size = Buf.size(); old_size < new_size; old_size++)
if (Buf[old_size] == '\n') if (Buf[old_size] == '\n')
LineOffsets.push_back(old_size + 1); LineOffsets.push_back(old_size + 1);
ScrollToBottom = true; if (AutoScroll)
ScrollToBottom = true;
} }
void Draw(const char* title, bool* p_open = NULL) void Draw(const char* title, bool* p_open = NULL)
@ -3409,13 +3490,31 @@ struct ExampleAppLog
ImGui::End(); ImGui::End();
return; return;
} }
if (ImGui::Button("Clear")) Clear();
// Options menu
if (ImGui::BeginPopup("Options"))
{
if (ImGui::Checkbox("Auto-scroll", &AutoScroll))
if (AutoScroll)
ScrollToBottom = true;
ImGui::EndPopup();
}
// Main window
if (ImGui::Button("Options"))
ImGui::OpenPopup("Options");
ImGui::SameLine();
bool clear = ImGui::Button("Clear");
ImGui::SameLine(); ImGui::SameLine();
bool copy = ImGui::Button("Copy"); bool copy = ImGui::Button("Copy");
ImGui::SameLine(); ImGui::SameLine();
Filter.Draw("Filter", -100.0f); Filter.Draw("Filter", -100.0f);
ImGui::Separator(); ImGui::Separator();
ImGui::BeginChild("scrolling", ImVec2(0,0), false, ImGuiWindowFlags_HorizontalScrollbar); ImGui::BeginChild("scrolling", ImVec2(0,0), false, ImGuiWindowFlags_HorizontalScrollbar);
if (clear)
Clear();
if (copy) if (copy)
ImGui::LogToClipboard(); ImGui::LogToClipboard();
@ -3424,6 +3523,10 @@ struct ExampleAppLog
const char* buf_end = Buf.end(); const char* buf_end = Buf.end();
if (Filter.IsActive()) if (Filter.IsActive())
{ {
// In this example we don't use the clipper when Filter is enabled.
// This is because we don't have a random access on the result on our filter.
// A real application processing logs with ten of thousands of entries may want to store the result of search/filter.
// especially if the filtering function is not trivial (e.g. reg-exp).
for (int line_no = 0; line_no < LineOffsets.Size; line_no++) for (int line_no = 0; line_no < LineOffsets.Size; line_no++)
{ {
const char* line_start = buf + LineOffsets[line_no]; const char* line_start = buf + LineOffsets[line_no];
@ -3435,11 +3538,11 @@ struct ExampleAppLog
else else
{ {
// The simplest and easy way to display the entire buffer: // The simplest and easy way to display the entire buffer:
// ImGui::TextUnformatted(buf_begin, buf_end); // ImGui::TextUnformatted(buf_begin, buf_end);
// And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward to skip non-visible lines. // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward to skip non-visible lines.
// Here we instead demonstrate using the clipper to only process lines that are within the visible area. // Here we instead demonstrate using the clipper to only process lines that are within the visible area.
// If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them on your side is recommended. // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them on your side is recommended.
// Using ImGuiListClipper requires A) random access into your data, and B) items all being the same height, // Using ImGuiListClipper requires A) random access into your data, and B) items all being the same height,
// both of which we can handle since we an array pointing to the beginning of each line of text. // both of which we can handle since we an array pointing to the beginning of each line of text.
// When using the filter (in the block of code above) we don't have random access into the data to display anymore, which is why we don't use the clipper. // When using the filter (in the block of code above) we don't have random access into the data to display anymore, which is why we don't use the clipper.
// Storing or skimming through the search result would make it possible (and would be recommended if you want to search through tens of thousands of entries) // Storing or skimming through the search result would make it possible (and would be recommended if you want to search through tens of thousands of entries)
@ -3471,18 +3574,19 @@ static void ShowExampleAppLog(bool* p_open)
{ {
static ExampleAppLog log; static ExampleAppLog log;
// For the demo: add a debug button before the normal log window contents // For the demo: add a debug button _BEFORE_ the normal log window contents
// We take advantage of the fact that multiple calls to Begin()/End() are appending to the same window. // We take advantage of the fact that multiple calls to Begin()/End() are appending to the same window.
// Most of the contents of the window will be added by the log.Draw() call.
ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
ImGui::Begin("Example: Log", p_open); ImGui::Begin("Example: Log", p_open);
if (ImGui::SmallButton("Add 5 entries")) if (ImGui::SmallButton("[Debug] Add 5 entries"))
{ {
static int counter = 0; static int counter = 0;
for (int n = 0; n < 5; n++) for (int n = 0; n < 5; n++)
{ {
const char* categories[3] = { "info", "warn", "error" }; const char* categories[3] = { "info", "warn", "error" };
const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" }; const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" };
log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n",
ImGui::GetFrameCount(), categories[counter % IM_ARRAYSIZE(categories)], ImGui::GetTime(), words[counter % IM_ARRAYSIZE(words)]); ImGui::GetFrameCount(), categories[counter % IM_ARRAYSIZE(categories)], ImGui::GetTime(), words[counter % IM_ARRAYSIZE(words)]);
counter++; counter++;
} }
@ -3726,8 +3830,8 @@ static void ShowExampleAppConstrainedResize(bool* p_open)
if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500 if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500
if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500 if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500
if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square
if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)100);// Fixed Step if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step
ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0; ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0;
if (ImGui::Begin("Example: Constrained Resize", p_open, flags)) if (ImGui::Begin("Example: Constrained Resize", p_open, flags))
@ -3765,17 +3869,20 @@ static void ShowExampleAppSimpleOverlay(bool* p_open)
{ {
const float DISTANCE = 10.0f; const float DISTANCE = 10.0f;
static int corner = 0; static int corner = 0;
ImVec2 window_pos = ImVec2((corner & 1) ? ImGui::GetIO().DisplaySize.x - DISTANCE : DISTANCE, (corner & 2) ? ImGui::GetIO().DisplaySize.y - DISTANCE : DISTANCE); ImGuiIO& io = ImGui::GetIO();
ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f);
if (corner != -1) if (corner != -1)
{
ImVec2 window_pos = ImVec2((corner & 1) ? io.DisplaySize.x - DISTANCE : DISTANCE, (corner & 2) ? io.DisplaySize.y - DISTANCE : DISTANCE);
ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f);
ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
}
ImGui::SetNextWindowBgAlpha(0.3f); // Transparent background ImGui::SetNextWindowBgAlpha(0.3f); // Transparent background
if (ImGui::Begin("Example: Simple overlay", p_open, (corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)) if (ImGui::Begin("Example: Simple overlay", p_open, (corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav))
{ {
ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)");
ImGui::Separator(); ImGui::Separator();
if (ImGui::IsMousePosValid()) if (ImGui::IsMousePosValid())
ImGui::Text("Mouse Position: (%.1f,%.1f)", ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y); ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y);
else else
ImGui::Text("Mouse Position: <invalid>"); ImGui::Text("Mouse Position: <invalid>");
if (ImGui::BeginPopupContextWindow()) if (ImGui::BeginPopupContextWindow())
@ -3850,27 +3957,30 @@ static void ShowExampleAppCustomRendering(bool* p_open)
static ImVec4 col = ImVec4(1.0f, 1.0f, 0.4f, 1.0f); static ImVec4 col = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f"); ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f");
ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f"); ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f");
ImGui::ColorEdit3("Color", &col.x); ImGui::ColorEdit4("Color", &col.x);
{ {
const ImVec2 p = ImGui::GetCursorScreenPos(); const ImVec2 p = ImGui::GetCursorScreenPos();
const ImU32 col32 = ImColor(col); const ImU32 col32 = ImColor(col);
float x = p.x + 4.0f, y = p.y + 4.0f, spacing = 8.0f; float x = p.x + 4.0f, y = p.y + 4.0f, spacing = 8.0f;
for (int n = 0; n < 2; n++) for (int n = 0; n < 2; n++)
{ {
float curr_thickness = (n == 0) ? 1.0f : thickness; // First line uses a thickness of 1.0, second line uses the configurable thickness
draw_list->AddCircle(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 20, curr_thickness); x += sz+spacing; float th = (n == 0) ? 1.0f : thickness;
draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 0.0f, ImDrawCornerFlags_All, curr_thickness); x += sz+spacing; draw_list->AddCircle(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 6, th); x += sz+spacing; // Hexagon
draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_All, curr_thickness); x += sz+spacing; draw_list->AddCircle(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 20, th); x += sz+spacing; // Circle
draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotRight, curr_thickness); x += sz+spacing; draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 0.0f, ImDrawCornerFlags_All, th); x += sz+spacing;
draw_list->AddTriangle(ImVec2(x+sz*0.5f, y), ImVec2(x+sz,y+sz-0.5f), ImVec2(x,y+sz-0.5f), col32, curr_thickness); x += sz+spacing; draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_All, th); x += sz+spacing;
draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y ), col32, curr_thickness); x += sz+spacing; // Horizontal line (note: drawing a filled rectangle will be faster!) draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotRight, th); x += sz+spacing;
draw_list->AddLine(ImVec2(x, y), ImVec2(x, y+sz), col32, curr_thickness); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!) draw_list->AddTriangle(ImVec2(x+sz*0.5f, y), ImVec2(x+sz,y+sz-0.5f), ImVec2(x,y+sz-0.5f), col32, th); x += sz+spacing;
draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, curr_thickness); x += sz+spacing; // Diagonal line draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y ), col32, th); x += sz+spacing; // Horizontal line (note: drawing a filled rectangle will be faster!)
draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x+sz*1.3f,y+sz*0.3f), ImVec2(x+sz-sz*1.3f,y+sz-sz*0.3f), ImVec2(x+sz, y+sz), col32, curr_thickness); draw_list->AddLine(ImVec2(x, y), ImVec2(x, y+sz), col32, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!)
draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, th); x += sz+spacing; // Diagonal line
draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x+sz*1.3f,y+sz*0.3f), ImVec2(x+sz-sz*1.3f,y+sz-sz*0.3f), ImVec2(x+sz, y+sz), col32, th);
x = p.x + 4; x = p.x + 4;
y += sz+spacing; y += sz+spacing;
} }
draw_list->AddCircleFilled(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 32); x += sz+spacing; draw_list->AddCircleFilled(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 6); x += sz+spacing; // Hexagon
draw_list->AddCircleFilled(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 32); x += sz+spacing; // Circle
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32); x += sz+spacing; draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32); x += sz+spacing;
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f); x += sz+spacing; draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f); x += sz+spacing;
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotRight); x += sz+spacing; draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotRight); x += sz+spacing;
@ -3945,16 +4055,16 @@ struct MyDocument
bool Open; // Set when the document is open (in this demo, we keep an array of all available documents to simplify the demo) bool Open; // Set when the document is open (in this demo, we keep an array of all available documents to simplify the demo)
bool OpenPrev; // Copy of Open from last update. bool OpenPrev; // Copy of Open from last update.
bool Dirty; // Set when the document has been modified bool Dirty; // Set when the document has been modified
bool WantClose; // Set when the document bool WantClose; // Set when the document
ImVec4 Color; // An arbitrary variable associated to the document ImVec4 Color; // An arbitrary variable associated to the document
MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f,1.0f,1.0f,1.0f)) MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f,1.0f,1.0f,1.0f))
{ {
Name = name; Name = name;
Open = OpenPrev = open; Open = OpenPrev = open;
Dirty = false; Dirty = false;
WantClose = false; WantClose = false;
Color = color; Color = color;
} }
void DoOpen() { Open = true; } void DoOpen() { Open = true; }
void DoQueueClose() { WantClose = true; } void DoQueueClose() { WantClose = true; }
@ -4011,8 +4121,8 @@ struct ExampleAppDocuments
// [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. // [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface.
// If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, as opposed // If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, as opposed
// to clicking on the regular tab closing button) and stops being submitted, it will take a frame for the tab bar to notice its absence. // to clicking on the regular tab closing button) and stops being submitted, it will take a frame for the tab bar to notice its absence.
// During this frame there will be a gap in the tab bar, and if the tab that has disappeared was the selected one, the tab bar // During this frame there will be a gap in the tab bar, and if the tab that has disappeared was the selected one, the tab bar
// will report no selected tab during the frame. This will effectively give the impression of a flicker for one frame. // will report no selected tab during the frame. This will effectively give the impression of a flicker for one frame.
// We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch. // We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch.
// Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag. // Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.

View File

@ -1,4 +1,4 @@
// dear imgui, v1.67 // dear imgui, v1.68
// (drawing and font code) // (drawing and font code)
/* /*
@ -57,7 +57,9 @@ Index of this file:
#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok. #pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok.
#pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it. #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 "-Wsign-conversion" // warning : implicit conversion changes signedness //
#if __has_warning("-Wzero-as-null-pointer-constant")
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0
#endif
#if __has_warning("-Wcomma") #if __has_warning("-Wcomma")
#pragma clang diagnostic ignored "-Wcomma" // warning : possible misuse of comma operator here // #pragma clang diagnostic ignored "-Wcomma" // warning : possible misuse of comma operator here //
#endif #endif
@ -687,7 +689,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
PrimReserve(idx_count, vtx_count); PrimReserve(idx_count, vtx_count);
// Temporary buffer // Temporary buffer
ImVec2* temp_normals = (ImVec2*)alloca(points_count * (thick_line ? 5 : 3) * sizeof(ImVec2)); ImVec2* temp_normals = (ImVec2*)alloca(points_count * (thick_line ? 5 : 3) * sizeof(ImVec2)); //-V630
ImVec2* temp_points = temp_normals + points_count; ImVec2* temp_points = temp_normals + points_count;
for (int i1 = 0; i1 < count; i1++) for (int i1 = 0; i1 < count; i1++)
@ -878,7 +880,7 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun
} }
// Compute normals // Compute normals
ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2)); ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2)); //-V630
for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++)
{ {
const ImVec2& p0 = points[i0]; const ImVec2& p0 = points[i0];
@ -955,6 +957,9 @@ void ImDrawList::PathArcTo(const ImVec2& centre, float radius, float a_min, floa
_Path.push_back(centre); _Path.push_back(centre);
return; return;
} }
// Note that we are adding a point at both a_min and a_max.
// If you are trying to draw a full closed circle you don't want the overlapping points!
_Path.reserve(_Path.Size + (num_segments + 1)); _Path.reserve(_Path.Size + (num_segments + 1));
for (int i = 0; i <= num_segments; i++) for (int i = 0; i <= num_segments; i++)
{ {
@ -1138,21 +1143,23 @@ void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec
void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments, float thickness) void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments, float thickness)
{ {
if ((col & IM_COL32_A_MASK) == 0) if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
return; return;
// Because we are filling a closed shape we remove 1 from the count of segments/points
const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments; const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
PathArcTo(centre, radius-0.5f, 0.0f, a_max, num_segments); PathArcTo(centre, radius-0.5f, 0.0f, a_max, num_segments - 1);
PathStroke(col, true, thickness); PathStroke(col, true, thickness);
} }
void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments) void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments)
{ {
if ((col & IM_COL32_A_MASK) == 0) if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
return; return;
// Because we are filling a closed shape we remove 1 from the count of segments/points
const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments; const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
PathArcTo(centre, radius, 0.0f, a_max, num_segments); PathArcTo(centre, radius, 0.0f, a_max, num_segments - 1);
PathFillConvex(col); PathFillConvex(col);
} }
@ -1280,8 +1287,10 @@ void ImDrawData::DeIndexAllBuffers()
} }
} }
// Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than ImGui expects, or if there is a difference between your window resolution and framebuffer resolution. // Helper to scale the ClipRect field of each ImDrawCmd.
void ImDrawData::ScaleClipRects(const ImVec2& scale) // Use if your final output buffer is at a different scale than draw_data->DisplaySize,
// or if there is a difference between your window resolution and framebuffer resolution.
void ImDrawData::ScaleClipRects(const ImVec2& fb_scale)
{ {
for (int i = 0; i < CmdListsCount; i++) for (int i = 0; i < CmdListsCount; i++)
{ {
@ -1289,7 +1298,7 @@ void ImDrawData::ScaleClipRects(const ImVec2& scale)
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{ {
ImDrawCmd* cmd = &cmd_list->CmdBuffer[cmd_i]; ImDrawCmd* cmd = &cmd_list->CmdBuffer[cmd_i];
cmd->ClipRect = ImVec4(cmd->ClipRect.x * scale.x, cmd->ClipRect.y * scale.y, cmd->ClipRect.z * scale.x, cmd->ClipRect.w * scale.y); cmd->ClipRect = ImVec4(cmd->ClipRect.x * fb_scale.x, cmd->ClipRect.y * fb_scale.y, cmd->ClipRect.z * fb_scale.x, cmd->ClipRect.w * fb_scale.y);
} }
} }
} }
@ -1352,7 +1361,7 @@ ImFontConfig::ImFontConfig()
FontDataOwnedByAtlas = true; FontDataOwnedByAtlas = true;
FontNo = 0; FontNo = 0;
SizePixels = 0.0f; SizePixels = 0.0f;
OversampleH = 3; OversampleH = 3; // FIXME: 2 may be a better default?
OversampleV = 1; OversampleV = 1;
PixelSnapH = false; PixelSnapH = false;
GlyphExtraSpacing = ImVec2(0.0f, 0.0f); GlyphExtraSpacing = ImVec2(0.0f, 0.0f);
@ -1518,7 +1527,7 @@ void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_wid
GetTexDataAsAlpha8(&pixels, NULL, NULL); GetTexDataAsAlpha8(&pixels, NULL, NULL);
if (pixels) if (pixels)
{ {
TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)(TexWidth * TexHeight * 4)); TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)TexWidth * (size_t)TexHeight * 4);
const unsigned char* src = pixels; const unsigned char* src = pixels;
unsigned int* dst = TexPixelsRGBA32; unsigned int* dst = TexPixelsRGBA32;
for (int n = TexWidth * TexHeight; n > 0; n--) for (int n = TexWidth * TexHeight; n > 0; n--)
@ -1585,8 +1594,10 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
font_cfg.OversampleH = font_cfg.OversampleV = 1; font_cfg.OversampleH = font_cfg.OversampleV = 1;
font_cfg.PixelSnapH = true; font_cfg.PixelSnapH = true;
} }
if (font_cfg.Name[0] == '\0') strcpy(font_cfg.Name, "ProggyClean.ttf, 13px"); if (font_cfg.SizePixels <= 0.0f)
if (font_cfg.SizePixels <= 0.0f) font_cfg.SizePixels = 13.0f; font_cfg.SizePixels = 13.0f * 1.0f;
if (font_cfg.Name[0] == '\0')
ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels);
const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85(); const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();
const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault(); const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault();
@ -1829,25 +1840,23 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
{ {
ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
ImFontConfig& cfg = atlas->ConfigData[src_i];
src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest + 1); src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest + 1);
if (dst_tmp.SrcCount > 1 && dst_tmp.GlyphsSet.Storage.empty()) if (dst_tmp.GlyphsSet.Storage.empty())
dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1); dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1);
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++)
{ {
if (cfg.MergeMode && dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite) if (dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option for MergeMode (e.g. MergeOverwrite==true)
continue; continue;
if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint)) // It is actually in the font? if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint)) // It is actually in the font?
continue; continue;
// Add to avail set/counters // Add to avail set/counters
src_tmp.GlyphsCount++; src_tmp.GlyphsCount++;
dst_tmp.GlyphsCount++; dst_tmp.GlyphsCount++;
src_tmp.GlyphsSet.SetBit(codepoint, true); src_tmp.GlyphsSet.SetBit(codepoint, true);
if (dst_tmp.SrcCount > 1) dst_tmp.GlyphsSet.SetBit(codepoint, true);
dst_tmp.GlyphsSet.SetBit(codepoint, true);
total_glyphs_count++; total_glyphs_count++;
} }
} }
@ -2012,7 +2021,7 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
float char_off_x = font_off_x; float char_off_x = font_off_x;
if (char_advance_x_org != char_advance_x_mod) if (char_advance_x_org != char_advance_x_mod)
char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f; char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
// Register glyph // Register glyph
stbtt_aligned_quad q; stbtt_aligned_quad q;
float dummy_x = 0.0f, dummy_y = 0.0f; float dummy_x = 0.0f, dummy_y = 0.0f;
@ -2056,6 +2065,7 @@ void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* f
void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque) void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque)
{ {
stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque; stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque;
IM_ASSERT(pack_context != NULL);
ImVector<ImFontAtlas::CustomRect>& user_rects = atlas->CustomRects; ImVector<ImFontAtlas::CustomRect>& user_rects = atlas->CustomRects;
IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong. IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong.
@ -2162,7 +2172,8 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseFull()
static const ImWchar ranges[] = static const ImWchar ranges[] =
{ {
0x0020, 0x00FF, // Basic Latin + Latin Supplement 0x0020, 0x00FF, // Basic Latin + Latin Supplement
0x3000, 0x30FF, // Punctuations, Hiragana, Katakana 0x2000, 0x206F, // General Punctuation
0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
0x31F0, 0x31FF, // Katakana Phonetic Extensions 0x31F0, 0x31FF, // Katakana Phonetic Extensions
0xFF00, 0xFFEF, // Half-width characters 0xFF00, 0xFFEF, // Half-width characters
0x4e00, 0x9FAF, // CJK Ideograms 0x4e00, 0x9FAF, // CJK Ideograms
@ -2238,9 +2249,10 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
static ImWchar base_ranges[] = // not zero-terminated static ImWchar base_ranges[] = // not zero-terminated
{ {
0x0020, 0x00FF, // Basic Latin + Latin Supplement 0x0020, 0x00FF, // Basic Latin + Latin Supplement
0x3000, 0x30FF, // Punctuations, Hiragana, Katakana 0x2000, 0x206F, // General Punctuation
0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
0x31F0, 0x31FF, // Katakana Phonetic Extensions 0x31F0, 0x31FF, // Katakana Phonetic Extensions
0xFF00, 0xFFEF, // Half-width characters 0xFF00, 0xFFEF // Half-width characters
}; };
static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 }; static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 };
if (!full_ranges[0]) if (!full_ranges[0])
@ -2291,14 +2303,14 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese()
3,7,6,3,1,2,3,9,1,3,1,6,3,2,1,3,11,3,1,6,10,3,2,3,1,2,1,5,1,1,11,3,6,4,1,7,2,1,2,5,5,34,4,14,18,4,19,7,5,8,2,6,79,1,5,2,14,8,2,9,2,1,36,28,16, 3,7,6,3,1,2,3,9,1,3,1,6,3,2,1,3,11,3,1,6,10,3,2,3,1,2,1,5,1,1,11,3,6,4,1,7,2,1,2,5,5,34,4,14,18,4,19,7,5,8,2,6,79,1,5,2,14,8,2,9,2,1,36,28,16,
4,1,1,1,2,12,6,42,39,16,23,7,15,15,3,2,12,7,21,64,6,9,28,8,12,3,3,41,59,24,51,55,57,294,9,9,2,6,2,15,1,2,13,38,90,9,9,9,3,11,7,1,1,1,5,6,3,2, 4,1,1,1,2,12,6,42,39,16,23,7,15,15,3,2,12,7,21,64,6,9,28,8,12,3,3,41,59,24,51,55,57,294,9,9,2,6,2,15,1,2,13,38,90,9,9,9,3,11,7,1,1,1,5,6,3,2,
1,2,2,3,8,1,4,4,1,5,7,1,4,3,20,4,9,1,1,1,5,5,17,1,5,2,6,2,4,1,4,5,7,3,18,11,11,32,7,5,4,7,11,127,8,4,3,3,1,10,1,1,6,21,14,1,16,1,7,1,3,6,9,65, 1,2,2,3,8,1,4,4,1,5,7,1,4,3,20,4,9,1,1,1,5,5,17,1,5,2,6,2,4,1,4,5,7,3,18,11,11,32,7,5,4,7,11,127,8,4,3,3,1,10,1,1,6,21,14,1,16,1,7,1,3,6,9,65,
51,4,3,13,3,10,1,1,12,9,21,110,3,19,24,1,1,10,62,4,1,29,42,78,28,20,18,82,6,3,15,6,84,58,253,15,155,264,15,21,9,14,7,58,40,39, 51,4,3,13,3,10,1,1,12,9,21,110,3,19,24,1,1,10,62,4,1,29,42,78,28,20,18,82,6,3,15,6,84,58,253,15,155,264,15,21,9,14,7,58,40,39,
}; };
static ImWchar base_ranges[] = // not zero-terminated static ImWchar base_ranges[] = // not zero-terminated
{ {
0x0020, 0x00FF, // Basic Latin + Latin Supplement 0x0020, 0x00FF, // Basic Latin + Latin Supplement
0x3000, 0x30FF, // Punctuations, Hiragana, Katakana 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
0x31F0, 0x31FF, // Katakana Phonetic Extensions 0x31F0, 0x31FF, // Katakana Phonetic Extensions
0xFF00, 0xFFEF, // Half-width characters 0xFF00, 0xFFEF // Half-width characters
}; };
static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 }; static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 };
if (!full_ranges[0]) if (!full_ranges[0])
@ -2378,38 +2390,36 @@ void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
ImFont::ImFont() ImFont::ImFont()
{ {
Scale = 1.0f; FontSize = 0.0f;
FallbackAdvanceX = 0.0f;
FallbackChar = (ImWchar)'?'; FallbackChar = (ImWchar)'?';
DisplayOffset = ImVec2(0.0f, 0.0f); DisplayOffset = ImVec2(0.0f, 0.0f);
ClearOutputData(); FallbackGlyph = NULL;
ContainerAtlas = NULL;
ConfigData = NULL;
ConfigDataCount = 0;
DirtyLookupTables = false;
Scale = 1.0f;
Ascent = Descent = 0.0f;
MetricsTotalSurface = 0;
} }
ImFont::~ImFont() 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().
// FIXME-CLEANUP
/*
ImGuiContext& g = *GImGui;
if (g.Font == this)
g.Font = NULL;
*/
ClearOutputData(); ClearOutputData();
} }
void ImFont::ClearOutputData() void ImFont::ClearOutputData()
{ {
FontSize = 0.0f; FontSize = 0.0f;
FallbackAdvanceX = 0.0f;
Glyphs.clear(); Glyphs.clear();
IndexAdvanceX.clear(); IndexAdvanceX.clear();
IndexLookup.clear(); IndexLookup.clear();
FallbackGlyph = NULL; FallbackGlyph = NULL;
FallbackAdvanceX = 0.0f;
ConfigDataCount = 0;
ConfigData = NULL;
ContainerAtlas = NULL; ContainerAtlas = NULL;
Ascent = Descent = 0.0f;
DirtyLookupTables = true; DirtyLookupTables = true;
Ascent = Descent = 0.0f;
MetricsTotalSurface = 0; MetricsTotalSurface = 0;
} }
@ -2999,13 +3009,14 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im
const float inv_rounding = 1.0f / rounding; const float inv_rounding = 1.0f / rounding;
const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding); const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding);
const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding); const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding);
const float half_pi = IM_PI * 0.5f; // We will == compare to this because we know this is the exact value ImAcos01 can return.
const float x0 = ImMax(p0.x, rect.Min.x + rounding); const float x0 = ImMax(p0.x, rect.Min.x + rounding);
if (arc0_b == arc0_e) if (arc0_b == arc0_e)
{ {
draw_list->PathLineTo(ImVec2(x0, p1.y)); draw_list->PathLineTo(ImVec2(x0, p1.y));
draw_list->PathLineTo(ImVec2(x0, p0.y)); draw_list->PathLineTo(ImVec2(x0, p0.y));
} }
else if (arc0_b == 0.0f && arc0_e == IM_PI*0.5f) else if (arc0_b == 0.0f && arc0_e == half_pi)
{ {
draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL
draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR
@ -3025,7 +3036,7 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im
draw_list->PathLineTo(ImVec2(x1, p0.y)); draw_list->PathLineTo(ImVec2(x1, p0.y));
draw_list->PathLineTo(ImVec2(x1, p1.y)); draw_list->PathLineTo(ImVec2(x1, p1.y));
} }
else if (arc1_b == 0.0f && arc1_e == IM_PI*0.5f) else if (arc1_b == 0.0f && arc1_e == half_pi)
{ {
draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR
draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3); // BR draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3); // BR
@ -3039,13 +3050,14 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im
draw_list->PathFillConvex(col); draw_list->PathFillConvex(col);
} }
// FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem for us... we cannot rely on font glyph having it, // FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem for us... we cannot rely on font glyph having it,
// and regular dot are typically too wide. If we render a dot/shape ourselves it comes with the risk that it wouldn't match // and regular dot are typically too wide. If we render a dot/shape ourselves it comes with the risk that it wouldn't match
// the boldness or positioning of what the font uses... // the boldness or positioning of what the font uses...
void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, int count, ImU32 col) void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, int count, ImU32 col)
{ {
ImFont* font = draw_list->_Data->Font; ImFont* font = draw_list->_Data->Font;
pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent + 0.5f - 1.0f); const float font_scale = draw_list->_Data->FontSize / font->FontSize;
pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent * font_scale + 0.5f - 1.0f);
for (int dot_n = 0; dot_n < count; dot_n++) for (int dot_n = 0; dot_n < count; dot_n++)
draw_list->AddRectFilled(ImVec2(pos.x + dot_n * 2.0f, pos.y), ImVec2(pos.x + dot_n * 2.0f + 1.0f, pos.y + 1.0f), col); draw_list->AddRectFilled(ImVec2(pos.x + dot_n * 2.0f, pos.y), ImVec2(pos.x + dot_n * 2.0f + 1.0f, pos.y + 1.0f), col);
} }

View File

@ -1,4 +1,4 @@
// dear imgui, v1.67 // dear imgui, v1.68
// (internal structures/api) // (internal structures/api)
// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility!
@ -46,7 +46,9 @@ Index of this file:
#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h #pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h
#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h #pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h
#pragma clang diagnostic ignored "-Wold-style-cast" #pragma clang diagnostic ignored "-Wold-style-cast"
#if __has_warning("-Wzero-as-null-pointer-constant")
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
#endif
#if __has_warning("-Wdouble-promotion") #if __has_warning("-Wdouble-promotion")
#pragma clang diagnostic ignored "-Wdouble-promotion" #pragma clang diagnostic ignored "-Wdouble-promotion"
#endif #endif
@ -124,6 +126,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointe
#else #else
#define IM_NEWLINE "\n" #define IM_NEWLINE "\n"
#endif #endif
#define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__) #define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__)
#define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1] #define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1]
#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose #define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose
@ -145,7 +148,8 @@ IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const
IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8 IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8
// Helpers: Misc // Helpers: Misc
IMGUI_API ImU32 ImHash(const void* data, int data_size, ImU32 seed = 0); // Pass data_size==0 for zero-terminated strings IMGUI_API ImU32 ImHashData(const void* data, size_t data_size, ImU32 seed = 0);
IMGUI_API ImU32 ImHashStr(const char* data, size_t data_size, ImU32 seed = 0);
IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size = NULL, int padding_bytes = 0); IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size = NULL, int padding_bytes = 0);
IMGUI_API FILE* ImFileOpen(const char* filename, const char* file_open_mode); IMGUI_API FILE* ImFileOpen(const char* filename, const char* file_open_mode);
static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; }
@ -153,6 +157,9 @@ static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c =
static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; } static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; }
static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
#define ImQsort qsort #define ImQsort qsort
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
static inline ImU32 ImHash(const void* data, int size, ImU32 seed = 0) { return size ? ImHashData(data, (size_t)size, seed) : ImHashStr((const char*)data, 0, seed); } // [moved to ImHashStr/ImHashData in 1.68]
#endif
// Helpers: Geometry // Helpers: Geometry
IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p); IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p);
@ -177,7 +184,7 @@ IMGUI_API int ImFormatString(char* buf, size_t buf_size, const char* f
IMGUI_API int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3); IMGUI_API int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3);
IMGUI_API const char* ImParseFormatFindStart(const char* format); IMGUI_API const char* ImParseFormatFindStart(const char* format);
IMGUI_API const char* ImParseFormatFindEnd(const char* format); IMGUI_API const char* ImParseFormatFindEnd(const char* format);
IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, int buf_size); IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, size_t buf_size);
IMGUI_API int ImParseFormatPrecision(const char* format, int default_value); IMGUI_API int ImParseFormatPrecision(const char* format, int default_value);
// Helpers: ImVec2/ImVec4 operators // Helpers: ImVec2/ImVec4 operators
@ -280,14 +287,6 @@ struct IMGUI_API ImPool
// Misc data structures // Misc data structures
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// 1D vector (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches)
struct ImVec1
{
float x;
ImVec1() { x = 0.0f; }
ImVec1(float _x) { x = _x; }
};
enum ImGuiButtonFlags_ enum ImGuiButtonFlags_
{ {
ImGuiButtonFlags_None = 0, ImGuiButtonFlags_None = 0,
@ -346,6 +345,19 @@ enum ImGuiSeparatorFlags_
ImGuiSeparatorFlags_Vertical = 1 << 1 ImGuiSeparatorFlags_Vertical = 1 << 1
}; };
// Transient per-window flags, reset at the beginning of the frame. For child window, inherited from parent on first Begin().
// This is going to be exposed in imgui.h when stabilized enough.
enum ImGuiItemFlags_
{
ImGuiItemFlags_NoTabStop = 1 << 0, // false
ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings.
ImGuiItemFlags_Disabled = 1 << 2, // false // [BETA] Disable interactions but doesn't affect visuals yet. See github.com/ocornut/imgui/issues/211
ImGuiItemFlags_NoNav = 1 << 3, // false
ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false
ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window
ImGuiItemFlags_Default_ = 0
};
// Storage for LastItem data // Storage for LastItem data
enum ImGuiItemStatusFlags_ enum ImGuiItemStatusFlags_
{ {
@ -356,9 +368,9 @@ enum ImGuiItemStatusFlags_
#ifdef IMGUI_ENABLE_TEST_ENGINE #ifdef IMGUI_ENABLE_TEST_ENGINE
, // [imgui-test only] , // [imgui-test only]
ImGuiItemStatusFlags_Openable = 1 << 10, // ImGuiItemStatusFlags_Openable = 1 << 10, //
ImGuiItemStatusFlags_Opened = 1 << 11, // ImGuiItemStatusFlags_Opened = 1 << 11, //
ImGuiItemStatusFlags_Checkable = 1 << 12, // ImGuiItemStatusFlags_Checkable = 1 << 12, //
ImGuiItemStatusFlags_Checked = 1 << 13 // ImGuiItemStatusFlags_Checked = 1 << 13 //
#endif #endif
}; };
@ -411,7 +423,7 @@ enum ImGuiNavHighlightFlags_
ImGuiNavHighlightFlags_None = 0, ImGuiNavHighlightFlags_None = 0,
ImGuiNavHighlightFlags_TypeDefault = 1 << 0, ImGuiNavHighlightFlags_TypeDefault = 1 << 0,
ImGuiNavHighlightFlags_TypeThin = 1 << 1, ImGuiNavHighlightFlags_TypeThin = 1 << 1,
ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, // Draw rectangular highlight if (g.NavId == id) _even_ when using the mouse.
ImGuiNavHighlightFlags_NoRounding = 1 << 3 ImGuiNavHighlightFlags_NoRounding = 1 << 3
}; };
@ -454,6 +466,15 @@ enum ImGuiPopupPositionPolicy
ImGuiPopupPositionPolicy_ComboBox ImGuiPopupPositionPolicy_ComboBox
}; };
// 1D vector (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches)
struct ImVec1
{
float x;
ImVec1() { x = 0.0f; }
ImVec1(float _x) { x = _x; }
};
// 2D axis aligned bounding-box // 2D axis aligned bounding-box
// NB: we can't rely on ImVec2 math operators being available here // NB: we can't rely on ImVec2 math operators being available here
struct IMGUI_API ImRect struct IMGUI_API ImRect
@ -561,7 +582,7 @@ struct IMGUI_API ImGuiInputTextState
void CursorClamp() { StbState.cursor = ImMin(StbState.cursor, CurLenW); StbState.select_start = ImMin(StbState.select_start, CurLenW); StbState.select_end = ImMin(StbState.select_end, CurLenW); } void CursorClamp() { StbState.cursor = ImMin(StbState.cursor, CurLenW); StbState.select_start = ImMin(StbState.select_start, CurLenW); StbState.select_end = ImMin(StbState.select_end, CurLenW); }
bool HasSelection() const { return StbState.select_start != StbState.select_end; } bool HasSelection() const { return StbState.select_start != StbState.select_end; }
void ClearSelection() { StbState.select_start = StbState.select_end = StbState.cursor; } void ClearSelection() { StbState.select_start = StbState.select_end = StbState.cursor; }
void SelectAll() { StbState.select_start = 0; StbState.cursor = StbState.select_end = CurLenW; StbState.has_preferred_x = false; } void SelectAll() { StbState.select_start = 0; StbState.cursor = StbState.select_end = CurLenW; StbState.has_preferred_x = 0; }
void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation
}; };
@ -579,8 +600,8 @@ struct ImGuiWindowSettings
struct ImGuiSettingsHandler struct ImGuiSettingsHandler
{ {
const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']' const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']'
ImGuiID TypeHash; // == ImHash(TypeName, 0, 0) ImGuiID TypeHash; // == ImHashStr(TypeName, 0, 0)
void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); // Read: Called when entering into a new ini entry e.g. "[Window][Name]" void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); // Read: Called when entering into a new ini entry e.g. "[Window][Name]"
void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry
void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); // Write: Output every entries into 'out_buf' void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); // Write: Output every entries into 'out_buf'
@ -670,6 +691,7 @@ struct ImDrawDataBuilder
struct ImGuiNavMoveResult struct ImGuiNavMoveResult
{ {
ImGuiID ID; // Best candidate ImGuiID ID; // Best candidate
ImGuiID SelectScopeId;// Best candidate window current selectable group ID
ImGuiWindow* Window; // Best candidate window ImGuiWindow* Window; // Best candidate window
float DistBox; // Best candidate box distance to current NavId float DistBox; // Best candidate box distance to current NavId
float DistCenter; // Best candidate center distance to current NavId float DistCenter; // Best candidate center distance to current NavId
@ -677,7 +699,7 @@ struct ImGuiNavMoveResult
ImRect RectRel; // Best candidate bounding box in window relative space ImRect RectRel; // Best candidate bounding box in window relative space
ImGuiNavMoveResult() { Clear(); } ImGuiNavMoveResult() { Clear(); }
void Clear() { ID = 0; Window = NULL; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); } void Clear() { ID = SelectScopeId = 0; Window = NULL; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); }
}; };
// Storage for SetNexWindow** functions // Storage for SetNexWindow** functions
@ -720,6 +742,10 @@ struct ImGuiNextWindowData
} }
}; };
//-----------------------------------------------------------------------------
// Tabs
//-----------------------------------------------------------------------------
struct ImGuiTabBarSortItem struct ImGuiTabBarSortItem
{ {
int Index; int Index;
@ -767,10 +793,12 @@ struct ImGuiContext
float ActiveIdTimer; float ActiveIdTimer;
bool ActiveIdIsJustActivated; // Set at the time of activation for one frame bool ActiveIdIsJustActivated; // Set at the time of activation for one frame
bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always) bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always)
bool ActiveIdHasBeenPressed; // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch.
bool ActiveIdHasBeenEdited; // Was the value associated to the widget Edited over the course of the Active state. bool ActiveIdHasBeenEdited; // Was the value associated to the widget Edited over the course of the Active state.
bool ActiveIdPreviousFrameIsAlive; bool ActiveIdPreviousFrameIsAlive;
bool ActiveIdPreviousFrameHasBeenEdited; bool ActiveIdPreviousFrameHasBeenEdited;
int ActiveIdAllowNavDirFlags; // Active widget allows using directional navigation (e.g. can activate a button and move away from it) int ActiveIdAllowNavDirFlags; // Active widget allows using directional navigation (e.g. can activate a button and move away from it)
int ActiveIdBlockNavInputFlags;
ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior)
ImGuiWindow* ActiveIdWindow; ImGuiWindow* ActiveIdWindow;
ImGuiWindow* ActiveIdPreviousFrameWindow; ImGuiWindow* ActiveIdPreviousFrameWindow;
@ -796,8 +824,9 @@ struct ImGuiContext
ImGuiID NavActivatePressedId; // ~~ IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0 ImGuiID NavActivatePressedId; // ~~ IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0
ImGuiID NavInputId; // ~~ IsNavInputPressed(ImGuiNavInput_Input) ? NavId : 0 ImGuiID NavInputId; // ~~ IsNavInputPressed(ImGuiNavInput_Input) ? NavId : 0
ImGuiID NavJustTabbedId; // Just tabbed to this id. ImGuiID NavJustTabbedId; // Just tabbed to this id.
ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest) ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest).
ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame ImGuiID NavJustMovedToSelectScopeId; // Just navigated to this select scope id (result of a successfully MoveRequest).
ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame.
ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS WILL ONLY BE None or NavGamepad or NavKeyboard. ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS WILL ONLY BE None or NavGamepad or NavKeyboard.
ImRect NavScoringRectScreen; // Rectangle used for scoring, in screen space. Based of window->DC.NavRefRectRel[], modified for directional navigation scoring. ImRect NavScoringRectScreen; // Rectangle used for scoring, in screen space. Based of window->DC.NavRefRectRel[], modified for directional navigation scoring.
int NavScoringCount; // Metrics for debugging int NavScoringCount; // Metrics for debugging
@ -870,8 +899,13 @@ struct ImGuiContext
int TooltipOverrideCount; int TooltipOverrideCount;
ImVector<char> PrivateClipboard; // If no custom clipboard handler is defined ImVector<char> PrivateClipboard; // If no custom clipboard handler is defined
// Range-Select/Multi-Select
// [This is unused in this branch, but left here to facilitate merging/syncing multiple branches]
ImGuiID MultiSelectScopeId;
// Platform support // Platform support
ImVec2 PlatformImePos, PlatformImeLastPos; // Cursor position request & last passed to the OS Input Method Editor ImVec2 PlatformImePos; // Cursor position request & last passed to the OS Input Method Editor
ImVec2 PlatformImeLastPos;
// Settings // Settings
bool SettingsLoaded; bool SettingsLoaded;
@ -922,10 +956,12 @@ struct ImGuiContext
ActiveIdTimer = 0.0f; ActiveIdTimer = 0.0f;
ActiveIdIsJustActivated = false; ActiveIdIsJustActivated = false;
ActiveIdAllowOverlap = false; ActiveIdAllowOverlap = false;
ActiveIdHasBeenPressed = false;
ActiveIdHasBeenEdited = false; ActiveIdHasBeenEdited = false;
ActiveIdPreviousFrameIsAlive = false; ActiveIdPreviousFrameIsAlive = false;
ActiveIdPreviousFrameHasBeenEdited = false; ActiveIdPreviousFrameHasBeenEdited = false;
ActiveIdAllowNavDirFlags = 0; ActiveIdAllowNavDirFlags = 0x00;
ActiveIdBlockNavInputFlags = 0x00;
ActiveIdClickOffset = ImVec2(-1,-1); ActiveIdClickOffset = ImVec2(-1,-1);
ActiveIdWindow = ActiveIdPreviousFrameWindow = NULL; ActiveIdWindow = ActiveIdPreviousFrameWindow = NULL;
ActiveIdSource = ImGuiInputSource_None; ActiveIdSource = ImGuiInputSource_None;
@ -938,7 +974,7 @@ struct ImGuiContext
NavWindow = NULL; NavWindow = NULL;
NavId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0; NavId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0;
NavJustTabbedId = NavJustMovedToId = NavNextActivateId = 0; NavJustTabbedId = NavJustMovedToId = NavJustMovedToSelectScopeId = NavNextActivateId = 0;
NavInputSource = ImGuiInputSource_None; NavInputSource = ImGuiInputSource_None;
NavScoringRectScreen = ImRect(); NavScoringRectScreen = ImRect();
NavScoringCount = 0; NavScoringCount = 0;
@ -984,6 +1020,9 @@ struct ImGuiContext
DragSpeedDefaultRatio = 1.0f / 100.0f; DragSpeedDefaultRatio = 1.0f / 100.0f;
ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f); ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f);
TooltipOverrideCount = 0; TooltipOverrideCount = 0;
MultiSelectScopeId = 0;
PlatformImePos = PlatformImeLastPos = ImVec2(FLT_MAX, FLT_MAX); PlatformImePos = PlatformImeLastPos = ImVec2(FLT_MAX, FLT_MAX);
SettingsLoaded = false; SettingsLoaded = false;
@ -1002,18 +1041,9 @@ struct ImGuiContext
} }
}; };
// Transient per-window flags, reset at the beginning of the frame. For child window, inherited from parent on first Begin(). //-----------------------------------------------------------------------------
// This is going to be exposed in imgui.h when stabilized enough. // ImGuiWindow
enum ImGuiItemFlags_ //-----------------------------------------------------------------------------
{
ImGuiItemFlags_NoTabStop = 1 << 0, // false
ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings.
ImGuiItemFlags_Disabled = 1 << 2, // false // [BETA] Disable interactions but doesn't affect visuals yet. See github.com/ocornut/imgui/issues/211
ImGuiItemFlags_NoNav = 1 << 3, // false
ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false
ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window
ImGuiItemFlags_Default_ = 0
};
// Transient per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the DC variable name in ImGuiWindow. // Transient per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the DC variable name in ImGuiWindow.
// FIXME: That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered. // FIXME: That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered.
@ -1126,6 +1156,7 @@ struct IMGUI_API ImGuiWindow
bool Appearing; // Set during the frame where the window is appearing (or re-appearing) bool Appearing; // Set during the frame where the window is appearing (or re-appearing)
bool Hidden; // Do not display (== (HiddenFramesForResize > 0) || bool Hidden; // Do not display (== (HiddenFramesForResize > 0) ||
bool HasCloseButton; // Set when the window has a close button (p_open != NULL) bool HasCloseButton; // Set when the window has a close button (p_open != NULL)
signed char ResizeBorderHeld; // Current border being held for resize (-1: none, otherwise 0-3)
short BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) short BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs)
short BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0. short BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0.
short BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues. short BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues.
@ -1214,10 +1245,14 @@ struct ImGuiItemHoveredDataBackup
enum ImGuiTabBarFlagsPrivate_ enum ImGuiTabBarFlagsPrivate_
{ {
ImGuiTabBarFlags_DockNode = 1 << 20, // [Docking: Unused in Master Branch] Part of a dock node ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node
ImGuiTabBarFlags_DockNodeIsDockSpace = 1 << 21, // [Docking: Unused in Master Branch] Part of an explicit dockspace node node ImGuiTabBarFlags_IsFocused = 1 << 21,
ImGuiTabBarFlags_IsFocused = 1 << 22, ImGuiTabBarFlags_SaveSettings = 1 << 22 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs
ImGuiTabBarFlags_SaveSettings = 1 << 23 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs };
enum ImGuiTabItemFlagsPrivate_
{
ImGuiTabItemFlags_NoCloseButton = 1 << 20 // Store whether p_open is set or not, which we need to recompute WidthContents during layout.
}; };
// Storage for one active tab item (sizeof() 26~32 bytes) // Storage for one active tab item (sizeof() 26~32 bytes)
@ -1227,11 +1262,12 @@ struct ImGuiTabItem
ImGuiTabItemFlags Flags; ImGuiTabItemFlags Flags;
int LastFrameVisible; int LastFrameVisible;
int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance
int NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames
float Offset; // Position relative to beginning of tab float Offset; // Position relative to beginning of tab
float Width; // Width currently displayed float Width; // Width currently displayed
float WidthContents; // Width of actual contents, stored during BeginTabItem() call float WidthContents; // Width of actual contents, stored during BeginTabItem() call
ImGuiTabItem() { ID = Flags = 0; LastFrameVisible = LastFrameSelected = -1; Offset = Width = WidthContents = 0.0f; } ImGuiTabItem() { ID = Flags = 0; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = WidthContents = 0.0f; }
}; };
// Storage for a tab bar (sizeof() 92~96 bytes) // Storage for a tab bar (sizeof() 92~96 bytes)
@ -1256,9 +1292,16 @@ struct ImGuiTabBar
bool WantLayout; bool WantLayout;
bool VisibleTabWasSubmitted; bool VisibleTabWasSubmitted;
short LastTabItemIdx; // For BeginTabItem()/EndTabItem() short LastTabItemIdx; // For BeginTabItem()/EndTabItem()
ImVec2 FramePadding; // style.FramePadding locked at the time of BeginTabBar()
ImGuiTextBuffer TabsNames; // For non-docking tab bar we re-append names in a contiguous buffer.
ImGuiTabBar(); ImGuiTabBar();
int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); } int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); }
const char* GetTabName(const ImGuiTabItem* tab) const
{
IM_ASSERT(tab->NameOffset != -1 && tab->NameOffset < TabsNames.Buf.Size);
return TabsNames.Buf.Data + tab->NameOffset;
}
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -1290,6 +1333,9 @@ namespace ImGui
IMGUI_API float GetWindowScrollMaxX(ImGuiWindow* window); IMGUI_API float GetWindowScrollMaxX(ImGuiWindow* window);
IMGUI_API float GetWindowScrollMaxY(ImGuiWindow* window); IMGUI_API float GetWindowScrollMaxY(ImGuiWindow* window);
IMGUI_API ImRect GetWindowAllowedExtentRect(ImGuiWindow* window); IMGUI_API ImRect GetWindowAllowedExtentRect(ImGuiWindow* window);
IMGUI_API void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond);
IMGUI_API void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond);
IMGUI_API void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond);
IMGUI_API void SetCurrentFont(ImFont* font); IMGUI_API void SetCurrentFont(ImFont* font);
inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; }
@ -1309,6 +1355,7 @@ namespace ImGui
IMGUI_API void MarkIniSettingsDirty(ImGuiWindow* window); IMGUI_API void MarkIniSettingsDirty(ImGuiWindow* window);
IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name); IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name);
IMGUI_API ImGuiWindowSettings* FindWindowSettings(ImGuiID id); IMGUI_API ImGuiWindowSettings* FindWindowSettings(ImGuiID id);
IMGUI_API ImGuiWindowSettings* FindOrCreateWindowSettings(const char* name);
IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name); IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name);
// Basic Accessors // Basic Accessors
@ -1329,7 +1376,7 @@ namespace ImGui
IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL); IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL);
IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id); IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id);
IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged); IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged);
IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id, bool tab_stop = true); // Return true if focus is requested IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id, bool tab_stop = true); // Return true if focus is requested
IMGUI_API void FocusableItemUnregister(ImGuiWindow* window); IMGUI_API void FocusableItemUnregister(ImGuiWindow* window);
IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y); IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y);
IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x);
@ -1386,7 +1433,7 @@ namespace ImGui
IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags); IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags);
IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button); IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button);
IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col); IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col);
IMGUI_API bool TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, const char* label, ImGuiID tab_id, ImGuiID close_button_id); IMGUI_API bool TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id);
// Render helpers // Render helpers
// AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT. // AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT.
@ -1417,6 +1464,7 @@ namespace ImGui
IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos); IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos);
IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags); IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags);
IMGUI_API void Scrollbar(ImGuiLayoutType direction); IMGUI_API void Scrollbar(ImGuiLayoutType direction);
IMGUI_API ImGuiID GetScrollbarID(ImGuiLayoutType direction);
IMGUI_API void VerticalSeparator(); // Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout. IMGUI_API void VerticalSeparator(); // Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout.
// Widgets low-level behaviors // Widgets low-level behaviors
@ -1428,7 +1476,7 @@ namespace ImGui
IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextTreeNodeOpened() data, if any. May return true when logging IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextTreeNodeOpened() data, if any. May return true when logging
IMGUI_API void TreePushRawID(ImGuiID id); IMGUI_API void TreePushRawID(ImGuiID id);
// Template functions are instantiated in imgui_widgets.cpp for a finite number of types. // Template functions are instantiated in imgui_widgets.cpp for a finite number of types.
// To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036). // To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036).
// e.g. " extern template IMGUI_API float RoundScalarWithFormatT<float, float>(const char* format, ImGuiDataType data_type, float v); " // e.g. " extern template IMGUI_API float RoundScalarWithFormatT<float, float>(const char* format, ImGuiDataType data_type, float v); "
template<typename T, typename SIGNED_T, typename FLOAT_T> IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, const T v_min, const T v_max, const char* format, float power, ImGuiDragFlags flags); template<typename T, typename SIGNED_T, typename FLOAT_T> IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, const T v_min, const T v_max, const char* format, float power, ImGuiDragFlags flags);
@ -1446,7 +1494,7 @@ namespace ImGui
IMGUI_API void ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags); IMGUI_API void ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags);
// Plot // Plot
IMGUI_API void PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size); IMGUI_API void PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size);
// Shade functions (write over already created vertices) // Shade functions (write over already created vertices)
IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1); IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1);
@ -1469,7 +1517,7 @@ IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned ch
extern void ImGuiTestEngineHook_PreNewFrame(ImGuiContext* ctx); extern void ImGuiTestEngineHook_PreNewFrame(ImGuiContext* ctx);
extern void ImGuiTestEngineHook_PostNewFrame(ImGuiContext* ctx); extern void ImGuiTestEngineHook_PostNewFrame(ImGuiContext* ctx);
extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id); extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id);
extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, int flags); extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags);
#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register status flags #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register status flags
#else #else
#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) do { } while (0) #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) do { } while (0)

View File

@ -1,4 +1,4 @@
// dear imgui, v1.67 // dear imgui, v1.68
// (widgets code) // (widgets code)
/* /*
@ -56,7 +56,9 @@ Index of this file:
#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. #pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
#pragma clang diagnostic ignored "-Wformat-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 "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
#if __has_warning("-Wzero-as-null-pointer-constant")
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0
#endif
#if __has_warning("-Wdouble-promotion") #if __has_warning("-Wdouble-promotion")
#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. #pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
#endif #endif
@ -505,6 +507,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
bool held = false; bool held = false;
if (g.ActiveId == id) if (g.ActiveId == id)
{ {
if (pressed)
g.ActiveIdHasBeenPressed = true;
if (g.ActiveIdSource == ImGuiInputSource_Mouse) if (g.ActiveIdSource == ImGuiInputSource_Mouse)
{ {
if (g.ActiveIdIsJustActivated) if (g.ActiveIdIsJustActivated)
@ -575,6 +579,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags
//if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
// CloseCurrentPopup(); // CloseCurrentPopup();
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags);
return pressed; return pressed;
} }
@ -672,7 +677,7 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius)
// Render // Render
ImVec2 center = bb.GetCenter(); ImVec2 center = bb.GetCenter();
if (hovered) if (hovered)
window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered), 9); window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered), 9);
float cross_extent = (radius * 0.7071f) - 1.0f; float cross_extent = (radius * 0.7071f) - 1.0f;
ImU32 cross_col = GetColorU32(ImGuiCol_Text); ImU32 cross_col = GetColorU32(ImGuiCol_Text);
@ -705,6 +710,13 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos)
return pressed; return pressed;
} }
ImGuiID ImGui::GetScrollbarID(ImGuiLayoutType direction)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
return window->GetID((direction == ImGuiLayoutType_Horizontal) ? "#SCROLLX" : "#SCROLLY");
}
// Vertical/Horizontal scrollbar // Vertical/Horizontal scrollbar
// The entire piece of code below is rather confusing because: // The entire piece of code below is rather confusing because:
// - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab) // - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab)
@ -717,8 +729,8 @@ void ImGui::Scrollbar(ImGuiLayoutType direction)
const bool horizontal = (direction == ImGuiLayoutType_Horizontal); const bool horizontal = (direction == ImGuiLayoutType_Horizontal);
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(horizontal ? "#SCROLLX" : "#SCROLLY"); const ImGuiID id = GetScrollbarID(direction);
// Render background // Render background
bool other_scrollbar = (horizontal ? window->ScrollbarY : window->ScrollbarX); bool other_scrollbar = (horizontal ? window->ScrollbarY : window->ScrollbarX);
float other_scrollbar_size_w = other_scrollbar ? style.ScrollbarSize : 0.0f; float other_scrollbar_size_w = other_scrollbar ? style.ScrollbarSize : 0.0f;
@ -729,9 +741,21 @@ void ImGui::Scrollbar(ImGuiLayoutType direction)
: ImRect(window_rect.Max.x - style.ScrollbarSize, window->Pos.y + border_size, window_rect.Max.x - border_size, window_rect.Max.y - other_scrollbar_size_w - border_size); : ImRect(window_rect.Max.x - style.ScrollbarSize, window->Pos.y + border_size, window_rect.Max.x - border_size, window_rect.Max.y - other_scrollbar_size_w - border_size);
if (!horizontal) if (!horizontal)
bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f); bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f);
if (bb.GetWidth() <= 0.0f || bb.GetHeight() <= 0.0f)
const float bb_height = bb.GetHeight();
if (bb.GetWidth() <= 0.0f || bb_height <= 0.0f)
return; return;
// When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the resize grab)
float alpha = 1.0f;
if ((direction == ImGuiLayoutType_Vertical) && bb_height < g.FontSize + g.Style.FramePadding.y * 2.0f)
{
alpha = ImSaturate((bb_height - g.FontSize) / (g.Style.FramePadding.y * 2.0f));
if (alpha <= 0.0f)
return;
}
const bool allow_interaction = (alpha >= 1.0f);
int window_rounding_corners; int window_rounding_corners;
if (horizontal) if (horizontal)
window_rounding_corners = ImDrawCornerFlags_BotLeft | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight); window_rounding_corners = ImDrawCornerFlags_BotLeft | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight);
@ -762,7 +786,7 @@ void ImGui::Scrollbar(ImGuiLayoutType direction)
float scroll_max = ImMax(1.0f, win_size_contents_v - win_size_avail_v); float scroll_max = ImMax(1.0f, win_size_contents_v - win_size_avail_v);
float scroll_ratio = ImSaturate(scroll_v / scroll_max); float scroll_ratio = ImSaturate(scroll_v / scroll_max);
float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
if (held && grab_h_norm < 1.0f) if (held && allow_interaction && grab_h_norm < 1.0f)
{ {
float scrollbar_pos_v = horizontal ? bb.Min.x : bb.Min.y; float scrollbar_pos_v = horizontal ? bb.Min.x : bb.Min.y;
float mouse_pos_v = horizontal ? g.IO.MousePos.x : g.IO.MousePos.y; float mouse_pos_v = horizontal ? g.IO.MousePos.x : g.IO.MousePos.y;
@ -805,8 +829,8 @@ void ImGui::Scrollbar(ImGuiLayoutType direction)
*click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f; *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f;
} }
// Render // Render grab
const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab); const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab, alpha);
ImRect grab_rect; ImRect grab_rect;
if (horizontal) if (horizontal)
grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImMin(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, window_rect.Max.x), bb.Max.y); grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImMin(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, window_rect.Max.x), bb.Max.y);
@ -890,19 +914,10 @@ bool ImGui::Checkbox(const char* label, bool* v)
const ImGuiID id = window->GetID(label); const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 label_size = CalcTextSize(label, NULL, true);
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)); // We want a square shape to we use Y twice const float square_sz = GetFrameHeight();
ItemSize(check_bb, style.FramePadding.y); const ImVec2 pos = window->DC.CursorPos;
const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f));
ImRect total_bb = check_bb; ItemSize(total_bb, style.FramePadding.y);
if (label_size.x > 0)
SameLine(0, style.ItemInnerSpacing.x);
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()), 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)) if (!ItemAdd(total_bb, id))
return false; return false;
@ -914,19 +929,19 @@ bool ImGui::Checkbox(const char* label, bool* v)
MarkItemEdited(id); MarkItemEdited(id);
} }
const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz));
RenderNavHighlight(total_bb, id); RenderNavHighlight(total_bb, id);
RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
if (*v) if (*v)
{ {
const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight()); const float pad = ImMax(1.0f, (float)(int)(square_sz / 6.0f));
const float pad = ImMax(1.0f, (float)(int)(check_sz / 6.0f)); RenderCheckMark(check_bb.Min + ImVec2(pad, pad), GetColorU32(ImGuiCol_CheckMark), square_sz - pad*2.0f);
RenderCheckMark(check_bb.Min + ImVec2(pad,pad), GetColorU32(ImGuiCol_CheckMark), check_bb.GetWidth() - pad*2.0f);
} }
if (g.LogEnabled) if (g.LogEnabled)
LogRenderedText(&text_bb.Min, *v ? "[x]" : "[ ]"); LogRenderedText(&total_bb.Min, *v ? "[x]" : "[ ]");
if (label_size.x > 0.0f) if (label_size.x > 0.0f)
RenderText(text_bb.Min, label); RenderText(ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y), label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return pressed; return pressed;
@ -958,26 +973,18 @@ bool ImGui::RadioButton(const char* label, bool active)
const ImGuiID id = window->GetID(label); const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 label_size = CalcTextSize(label, NULL, true);
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)); const float square_sz = GetFrameHeight();
ItemSize(check_bb, style.FramePadding.y); const ImVec2 pos = window->DC.CursorPos;
const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz));
ImRect total_bb = check_bb; const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f));
if (label_size.x > 0) ItemSize(total_bb, style.FramePadding.y);
SameLine(0, style.ItemInnerSpacing.x);
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()), style.FramePadding.y);
total_bb.Add(text_bb);
}
if (!ItemAdd(total_bb, id)) if (!ItemAdd(total_bb, id))
return false; return false;
ImVec2 center = check_bb.GetCenter(); ImVec2 center = check_bb.GetCenter();
center.x = (float)(int)center.x + 0.5f; center.x = (float)(int)center.x + 0.5f;
center.y = (float)(int)center.y + 0.5f; center.y = (float)(int)center.y + 0.5f;
const float radius = check_bb.GetHeight() * 0.5f; const float radius = (square_sz - 1.0f) * 0.5f;
bool hovered, held; bool hovered, held;
bool pressed = ButtonBehavior(total_bb, id, &hovered, &held); bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
@ -988,21 +995,20 @@ bool ImGui::RadioButton(const char* label, bool active)
window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16); window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16);
if (active) if (active)
{ {
const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight()); const float pad = ImMax(1.0f, (float)(int)(square_sz / 6.0f));
const float pad = ImMax(1.0f, (float)(int)(check_sz / 6.0f)); window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark), 16);
window->DrawList->AddCircleFilled(center, radius-pad, GetColorU32(ImGuiCol_CheckMark), 16);
} }
if (style.FrameBorderSize > 0.0f) if (style.FrameBorderSize > 0.0f)
{ {
window->DrawList->AddCircle(center+ImVec2(1,1), radius, GetColorU32(ImGuiCol_BorderShadow), 16, style.FrameBorderSize); window->DrawList->AddCircle(center + ImVec2(1,1), radius, GetColorU32(ImGuiCol_BorderShadow), 16, style.FrameBorderSize);
window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16, style.FrameBorderSize); window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16, style.FrameBorderSize);
} }
if (g.LogEnabled) if (g.LogEnabled)
LogRenderedText(&text_bb.Min, active ? "(x)" : "( )"); LogRenderedText(&total_bb.Min, active ? "(x)" : "( )");
if (label_size.x > 0.0f) if (label_size.x > 0.0f)
RenderText(text_bb.Min, label); RenderText(ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y), label);
return pressed; return pressed;
} }
@ -1456,7 +1462,7 @@ bool ImGui::Combo(const char* label, int* current_item, const char* const items[
return value_changed; return value_changed;
} }
// Combo box helper allowing to pass all items in a single string literal holding multiple zero-terminated items "item1\0item2\0" // Combo box helper allowing to pass all items in a single string literal holding multiple zero-terminated items "item1\0item2\0"
bool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items) bool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items)
{ {
int items_count = 0; int items_count = 0;
@ -1666,7 +1672,7 @@ static float GetMinimumStepAtDecimalPrecision(int decimal_precision)
static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f }; static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f };
if (decimal_precision < 0) if (decimal_precision < 0)
return FLT_MIN; return FLT_MIN;
return (decimal_precision >= 0 && decimal_precision < 10) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision); return (decimal_precision < IM_ARRAYSIZE(min_steps)) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision);
} }
template<typename TYPE> template<typename TYPE>
@ -1868,15 +1874,12 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa
const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*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)); 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 ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, id, &frame_bb)) if (!ItemAdd(total_bb, id, &frame_bb))
{
ItemSize(total_bb, style.FramePadding.y);
return false; return false;
}
const bool hovered = ItemHoverable(frame_bb, id); const bool hovered = ItemHoverable(frame_bb, id);
// Default format string when passing NULL // Default format string when passing NULL
@ -1904,12 +1907,12 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa
} }
if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id)) if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id))
{ {
window->DC.CursorPos = frame_bb.Min;
FocusableItemUnregister(window); FocusableItemUnregister(window);
return InputScalarAsWidgetReplacement(frame_bb, id, label, data_type, v, format); return InputScalarAsWidgetReplacement(frame_bb, id, label, data_type, v, format);
} }
// Actual drag behavior // Actual drag behavior
ItemSize(total_bb, style.FramePadding.y);
const bool value_changed = DragBehavior(id, data_type, v, v_speed, v_min, v_max, format, power, ImGuiDragFlags_None); const bool value_changed = DragBehavior(id, data_type, v, v_speed, v_min, v_max, format, power, ImGuiDragFlags_None);
if (value_changed) if (value_changed)
MarkItemEdited(id); MarkItemEdited(id);
@ -1925,8 +1928,9 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa
RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));
if (label_size.x > 0.0f) if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags);
return value_changed; return value_changed;
} }
@ -1945,7 +1949,7 @@ bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* v, int
for (int i = 0; i < components; i++) for (int i = 0; i < components; i++)
{ {
PushID(i); PushID(i);
value_changed |= DragScalar("##v", data_type, v, v_speed, v_min, v_max, format, power); value_changed |= DragScalar("", data_type, v, v_speed, v_min, v_max, format, power);
SameLine(0, g.Style.ItemInnerSpacing.x); SameLine(0, g.Style.ItemInnerSpacing.x);
PopID(); PopID();
PopItemWidth(); PopItemWidth();
@ -2305,12 +2309,9 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); const 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 ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, id, &frame_bb)) if (!ItemAdd(total_bb, id, &frame_bb))
{
ItemSize(total_bb, style.FramePadding.y);
return false; return false;
}
// Default format string when passing NULL // Default format string when passing NULL
// Patch old "%.0f" format string to use "%d", read function comments for more details. // Patch old "%.0f" format string to use "%d", read function comments for more details.
@ -2338,12 +2339,11 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co
} }
if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id)) if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id))
{ {
window->DC.CursorPos = frame_bb.Min;
FocusableItemUnregister(window); FocusableItemUnregister(window);
return InputScalarAsWidgetReplacement(frame_bb, id, label, data_type, v, format); return InputScalarAsWidgetReplacement(frame_bb, id, label, data_type, v, format);
} }
ItemSize(total_bb, style.FramePadding.y);
// Draw frame // Draw frame
const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
RenderNavHighlight(frame_bb, id); RenderNavHighlight(frame_bb, id);
@ -2366,6 +2366,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co
if (label_size.x > 0.0f) if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags);
return value_changed; return value_changed;
} }
@ -2385,7 +2386,7 @@ bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, i
for (int i = 0; i < components; i++) for (int i = 0; i < components; i++)
{ {
PushID(i); PushID(i);
value_changed |= SliderScalar("##v", data_type, v, v_min, v_max, format, power); value_changed |= SliderScalar("", data_type, v, v_min, v_max, format, power);
SameLine(0, g.Style.ItemInnerSpacing.x); SameLine(0, g.Style.ItemInnerSpacing.x);
PopID(); PopID();
PopItemWidth(); PopItemWidth();
@ -2575,7 +2576,7 @@ const char* ImParseFormatFindEnd(const char* fmt)
// fmt = "%.3f" -> return fmt // fmt = "%.3f" -> return fmt
// fmt = "hello %.3f" -> return fmt + 6 // fmt = "hello %.3f" -> return fmt + 6
// fmt = "%.3f hello" -> return buf written with "%.3f" // fmt = "%.3f hello" -> return buf written with "%.3f"
const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, int buf_size) const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, size_t buf_size)
{ {
const char* fmt_start = ImParseFormatFindStart(fmt); const char* fmt_start = ImParseFormatFindStart(fmt);
if (fmt_start[0] != '%') if (fmt_start[0] != '%')
@ -2583,7 +2584,7 @@ const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, int buf_siz
const char* fmt_end = ImParseFormatFindEnd(fmt_start); const char* fmt_end = ImParseFormatFindEnd(fmt_start);
if (fmt_end[0] == 0) // If we only have leading decoration, we don't need to copy the data. if (fmt_end[0] == 0) // If we only have leading decoration, we don't need to copy the data.
return fmt_start; return fmt_start;
ImStrncpy(buf, fmt_start, ImMin((int)(fmt_end + 1 - fmt_start), buf_size)); ImStrncpy(buf, fmt_start, ImMin((size_t)(fmt_end - fmt_start) + 1, buf_size));
return buf; return buf;
} }
@ -2612,17 +2613,15 @@ int ImParseFormatPrecision(const char* fmt, int default_precision)
} }
// Create text input in place of an active drag/slider (used when doing a CTRL+Click on drag/slider widgets) // Create text input in place of an active drag/slider (used when doing a CTRL+Click on drag/slider widgets)
// FIXME: Logic is awkward and confusing. This should be reworked to facilitate using in other situations. // FIXME: Facilitate using this in variety of other situations.
bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format) bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow();
// Our replacement widget will override the focus ID (registered previously to allow for a TAB focus to happen) // On the first frame, g.ScalarAsInputTextId == 0, then on subsequent frames it becomes == id.
// On the first frame, g.ScalarAsInputTextId == 0, then on subsequent frames it becomes == id // We clear ActiveID on the first frame to allow the InputText() taking it back.
SetActiveID(g.ScalarAsInputTextId, window); if (g.ScalarAsInputTextId == 0)
SetHoveredID(0); ClearActiveID();
g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
char fmt_buf[32]; char fmt_buf[32];
char data_buf[32]; char data_buf[32];
@ -2631,11 +2630,11 @@ bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const c
ImStrTrimBlanks(data_buf); ImStrTrimBlanks(data_buf);
ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal);
bool value_changed = InputTextEx(label, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags); bool value_changed = InputTextEx(label, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags);
if (g.ScalarAsInputTextId == 0) // First frame we started displaying the InputText widget if (g.ScalarAsInputTextId == 0)
{ {
IM_ASSERT(g.ActiveId == id); // InputText ID expected to match the Slider ID // First frame we started displaying the InputText widget, we expect it to take the active id.
IM_ASSERT(g.ActiveId == id);
g.ScalarAsInputTextId = g.ActiveId; g.ScalarAsInputTextId = g.ActiveId;
SetHoveredID(id);
} }
if (value_changed) if (value_changed)
return DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialText.Data, data_type, data_ptr, NULL); return DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialText.Data, data_type, data_ptr, NULL);
@ -2720,7 +2719,7 @@ bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, in
for (int i = 0; i < components; i++) for (int i = 0; i < components; i++)
{ {
PushID(i); PushID(i);
value_changed |= InputScalar("##v", data_type, v, step, step_fast, format, flags); value_changed |= InputScalar("", data_type, v, step, step_fast, format, flags);
SameLine(0, g.Style.ItemInnerSpacing.x); SameLine(0, g.Style.ItemInnerSpacing.x);
PopID(); PopID();
PopItemWidth(); PopItemWidth();
@ -2852,8 +2851,9 @@ static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char**
static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line) static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line)
{ {
ImFont* font = GImGui->Font; ImGuiContext& g = *GImGui;
const float line_height = GImGui->FontSize; ImFont* font = g.Font;
const float line_height = g.FontSize;
const float scale = line_height / font->FontSize; const float scale = line_height / font->FontSize;
ImVec2 text_size = ImVec2(0,0); ImVec2 text_size = ImVec2(0,0);
@ -3121,7 +3121,7 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f
// Edit a string of text // Edit a string of text
// - buf_size account for the zero-terminator, so a buf_size of 6 can hold "Hello" but not "Hello!". // - buf_size account for the zero-terminator, so a buf_size of 6 can hold "Hello" but not "Hello!".
// This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match // This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match
// Note that in std::string world, capacity() would omit 1 byte used by the zero-terminator. // Note that in std::string world, capacity() would omit 1 byte used by the zero-terminator.
// - When active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while the InputText is active has no effect. // - When active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while the InputText is active has no effect.
// - If you want to use ImGui::InputText() with std::string, see misc/cpp/imgui_stdlib.h // - If you want to use ImGui::InputText() with std::string, see misc/cpp/imgui_stdlib.h
@ -3147,7 +3147,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
if (is_resizable) if (is_resizable)
IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag! IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag!
if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope, if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope,
BeginGroup(); BeginGroup();
const ImGuiID id = window->GetID(label); const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 label_size = CalcTextSize(label, NULL, true);
@ -3158,7 +3158,12 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
ImGuiWindow* draw_window = window; ImGuiWindow* draw_window = window;
if (is_multiline) if (is_multiline)
{ {
ItemAdd(total_bb, id, &frame_bb); if (!ItemAdd(total_bb, id, &frame_bb))
{
ItemSize(total_bb, style.FramePadding.y);
EndGroup();
return false;
}
if (!BeginChildFrame(id, frame_bb.GetSize())) if (!BeginChildFrame(id, frame_bb.GetSize()))
{ {
EndChildFrame(); EndChildFrame();
@ -3245,15 +3250,16 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
select_all = true; select_all = true;
} }
if (flags & ImGuiInputTextFlags_AlwaysInsertMode) if (flags & ImGuiInputTextFlags_AlwaysInsertMode)
edit_state.StbState.insert_mode = true; edit_state.StbState.insert_mode = 1;
if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl))) if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl)))
select_all = true; select_all = true;
} }
SetActiveID(id, window); SetActiveID(id, window);
SetFocusID(id, window); SetFocusID(id, window);
FocusWindow(window); FocusWindow(window);
g.ActiveIdBlockNavInputFlags = (1 << ImGuiNavInput_Cancel);
if (!is_multiline && !(flags & ImGuiInputTextFlags_CallbackHistory)) if (!is_multiline && !(flags & ImGuiInputTextFlags_CallbackHistory))
g.ActiveIdAllowNavDirFlags |= ((1 << ImGuiDir_Up) | (1 << ImGuiDir_Down)); g.ActiveIdAllowNavDirFlags = ((1 << ImGuiDir_Up) | (1 << ImGuiDir_Down));
} }
else if (io.MouseClicked[0]) else if (io.MouseClicked[0])
{ {
@ -3583,7 +3589,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
} }
// If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size. // If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size.
ImStrncpy(buf, edit_state.TempBuffer.Data, ImMin(apply_new_text_length + 1, buf_size)); ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size));
value_changed = true; value_changed = true;
} }
@ -3789,6 +3795,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
if (value_changed) if (value_changed)
MarkItemEdited(id); MarkItemEdited(id);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags);
if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0) if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0)
return enter_pressed; return enter_pressed;
else else
@ -3895,9 +3902,14 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
if (n + 1 == components) if (n + 1 == components)
PushItemWidth(w_item_last); PushItemWidth(w_item_last);
if (flags & ImGuiColorEditFlags_Float) if (flags & ImGuiColorEditFlags_Float)
value_changed = value_changed_as_float = value_changed | DragFloat(ids[n], &f[n], 1.0f/255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); {
value_changed |= DragFloat(ids[n], &f[n], 1.0f/255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]);
value_changed_as_float |= value_changed;
}
else else
{
value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]); value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]);
}
if (!(flags & ImGuiColorEditFlags_NoOptions)) if (!(flags & ImGuiColorEditFlags_NoOptions))
OpenPopupOnItemClick("context"); OpenPopupOnItemClick("context");
} }
@ -4000,7 +4012,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
{ {
if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
{ {
memcpy((float*)col, payload->Data, sizeof(float) * 3); memcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any //-V512
value_changed = true; value_changed = true;
} }
if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
@ -4582,7 +4594,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl
g.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags__PickerMask) | (picker_flags & ImGuiColorEditFlags__PickerMask); g.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags__PickerMask) | (picker_flags & ImGuiColorEditFlags__PickerMask);
SetCursorScreenPos(backup_pos); SetCursorScreenPos(backup_pos);
ImVec4 dummy_ref_col; ImVec4 dummy_ref_col;
memcpy(&dummy_ref_col.x, ref_col, sizeof(float) * (picker_flags & ImGuiColorEditFlags_NoAlpha ? 3 : 4)); memcpy(&dummy_ref_col, ref_col, sizeof(float) * ((picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4));
ColorPicker4("##dummypicker", &dummy_ref_col.x, picker_flags); ColorPicker4("##dummypicker", &dummy_ref_col.x, picker_flags);
PopID(); PopID();
} }
@ -4603,7 +4615,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl
// - TreeNodeV() // - TreeNodeV()
// - TreeNodeEx() // - TreeNodeEx()
// - TreeNodeExV() // - TreeNodeExV()
// - TreeNodeBehavior() [Internal] // - TreeNodeBehavior() [Internal]
// - TreePush() // - TreePush()
// - TreePop() // - TreePop()
// - TreeAdvanceToLabelPos() // - TreeAdvanceToLabelPos()
@ -4799,20 +4811,24 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
} }
// Flags that affects opening behavior: // Flags that affects opening behavior:
// - 0(default) ..................... single-click anywhere to open // - 0 (default) .................... single-click anywhere to open
// - OpenOnDoubleClick .............. double-click anywhere to open // - OpenOnDoubleClick .............. double-click anywhere to open
// - OpenOnArrow .................... single-click on arrow to open // - OpenOnArrow .................... single-click on arrow to open
// - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open // - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open
ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers | ((flags & ImGuiTreeNodeFlags_AllowItemOverlap) ? ImGuiButtonFlags_AllowItemOverlap : 0); ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers;
if (!is_leaf) if (flags & ImGuiTreeNodeFlags_AllowItemOverlap)
button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; button_flags |= ImGuiButtonFlags_AllowItemOverlap;
if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick)
button_flags |= ImGuiButtonFlags_PressedOnDoubleClick | ((flags & ImGuiTreeNodeFlags_OpenOnArrow) ? ImGuiButtonFlags_PressedOnClickRelease : 0); button_flags |= ImGuiButtonFlags_PressedOnDoubleClick | ((flags & ImGuiTreeNodeFlags_OpenOnArrow) ? ImGuiButtonFlags_PressedOnClickRelease : 0);
if (!is_leaf)
button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
bool hovered, held, pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags); bool selected = (flags & ImGuiTreeNodeFlags_Selected) != 0;
bool hovered, held;
bool pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags);
bool toggled = false;
if (!is_leaf) if (!is_leaf)
{ {
bool toggled = false;
if (pressed) if (pressed)
{ {
toggled = !(flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) || (g.NavActivateId == id); toggled = !(flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) || (g.NavActivateId == id);
@ -4847,11 +4863,12 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
// Render // Render
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
const ImVec2 text_pos = frame_bb.Min + ImVec2(text_offset_x, text_base_offset_y); const ImVec2 text_pos = frame_bb.Min + ImVec2(text_offset_x, text_base_offset_y);
ImGuiNavHighlightFlags nav_highlight_flags = ImGuiNavHighlightFlags_TypeThin;
if (display_frame) if (display_frame)
{ {
// Framed type // Framed type
RenderFrame(frame_bb.Min, frame_bb.Max, col, true, style.FrameRounding); RenderFrame(frame_bb.Min, frame_bb.Max, col, true, style.FrameRounding);
RenderNavHighlight(frame_bb, id, ImGuiNavHighlightFlags_TypeThin); RenderNavHighlight(frame_bb, id, nav_highlight_flags);
RenderArrow(frame_bb.Min + ImVec2(padding.x, text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 1.0f); RenderArrow(frame_bb.Min + ImVec2(padding.x, text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 1.0f);
if (g.LogEnabled) if (g.LogEnabled)
{ {
@ -4870,10 +4887,10 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
else else
{ {
// Unframed typed for tree nodes // Unframed typed for tree nodes
if (hovered || (flags & ImGuiTreeNodeFlags_Selected)) if (hovered || selected)
{ {
RenderFrame(frame_bb.Min, frame_bb.Max, col, false); RenderFrame(frame_bb.Min, frame_bb.Max, col, false);
RenderNavHighlight(frame_bb, id, ImGuiNavHighlightFlags_TypeThin); RenderNavHighlight(frame_bb, id, nav_highlight_flags);
} }
if (flags & ImGuiTreeNodeFlags_Bullet) if (flags & ImGuiTreeNodeFlags_Bullet)
@ -4985,7 +5002,7 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags
ImGuiItemHoveredDataBackup last_item_backup; ImGuiItemHoveredDataBackup last_item_backup;
float button_radius = g.FontSize * 0.5f; float button_radius = g.FontSize * 0.5f;
ImVec2 button_center = ImVec2(ImMin(window->DC.LastItemRect.Max.x, window->ClipRect.Max.x) - g.Style.FramePadding.x - button_radius, window->DC.LastItemRect.GetCenter().y); ImVec2 button_center = ImVec2(ImMin(window->DC.LastItemRect.Max.x, window->ClipRect.Max.x) - g.Style.FramePadding.x - button_radius, window->DC.LastItemRect.GetCenter().y);
if (CloseButton(window->GetID((void*)(intptr_t)(id+1)), button_center, button_radius)) if (CloseButton(window->GetID((void*)((intptr_t)id+1)), button_center, button_radius))
*p_open = false; *p_open = false;
last_item_backup.Restore(); last_item_backup.Restore();
} }
@ -5024,7 +5041,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
// Fill horizontal space. // Fill horizontal space.
ImVec2 window_padding = window->WindowPadding; ImVec2 window_padding = window->WindowPadding;
float max_x = (flags & ImGuiSelectableFlags_SpanAllColumns) ? GetWindowContentRegionMax().x : GetContentRegionMax().x; float max_x = (flags & ImGuiSelectableFlags_SpanAllColumns) ? GetWindowContentRegionMax().x : GetContentRegionMax().x;
float w_draw = ImMax(label_size.x, window->Pos.x + max_x - window_padding.x - window->DC.CursorPos.x); float w_draw = ImMax(label_size.x, window->Pos.x + max_x - window_padding.x - pos.x);
ImVec2 size_draw((size_arg.x != 0 && !(flags & ImGuiSelectableFlags_DrawFillAvailWidth)) ? size_arg.x : w_draw, size_arg.y != 0.0f ? size_arg.y : size.y); ImVec2 size_draw((size_arg.x != 0 && !(flags & ImGuiSelectableFlags_DrawFillAvailWidth)) ? size_arg.x : w_draw, size_arg.y != 0.0f ? size_arg.y : size.y);
ImRect bb(pos, pos + size_draw); ImRect bb(pos, pos + size_draw);
if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_DrawFillAvailWidth)) if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_DrawFillAvailWidth))
@ -5053,11 +5070,11 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
if (flags & ImGuiSelectableFlags_PressedOnRelease) button_flags |= ImGuiButtonFlags_PressedOnRelease; if (flags & ImGuiSelectableFlags_PressedOnRelease) button_flags |= ImGuiButtonFlags_PressedOnRelease;
if (flags & ImGuiSelectableFlags_Disabled) button_flags |= ImGuiButtonFlags_Disabled; if (flags & ImGuiSelectableFlags_Disabled) button_flags |= ImGuiButtonFlags_Disabled;
if (flags & ImGuiSelectableFlags_AllowDoubleClick) button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; if (flags & ImGuiSelectableFlags_AllowDoubleClick) button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick;
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags);
if (flags & ImGuiSelectableFlags_Disabled) if (flags & ImGuiSelectableFlags_Disabled)
selected = false; selected = false;
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags);
// Hovering selectable with mouse updates NavId accordingly so navigation can be resumed with gamepad/keyboard (this doesn't happen on most widgets) // Hovering selectable with mouse updates NavId accordingly so navigation can be resumed with gamepad/keyboard (this doesn't happen on most widgets)
if (pressed || hovered) if (pressed || hovered)
if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent)
@ -5083,7 +5100,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
} }
if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]);
RenderTextClipped(bb_inner.Min, bb.Max, label, NULL, &label_size, ImVec2(0.0f,0.0f)); RenderTextClipped(bb_inner.Min, bb_inner.Max, label, NULL, &label_size, style.SelectableTextAlign, &bb);
if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor(); if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor();
// Automatically close popups // Automatically close popups
@ -5130,6 +5147,13 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg)
ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
window->DC.LastItemRect = bb; // Forward storage for ListBoxFooter.. dodgy. window->DC.LastItemRect = bb; // Forward storage for ListBoxFooter.. dodgy.
if (!IsRectVisible(bb.Min, bb.Max))
{
ItemSize(bb.GetSize(), style.FramePadding.y);
ItemAdd(bb, 0, &frame_bb);
return false;
}
BeginGroup(); BeginGroup();
if (label_size.x > 0) if (label_size.x > 0)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
@ -5222,7 +5246,7 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v
// - PlotHistogram() // - PlotHistogram()
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size) void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems) if (window->SkipItems)
@ -5230,20 +5254,21 @@ void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_ge
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 label_size = CalcTextSize(label, NULL, true);
if (graph_size.x == 0.0f) if (frame_size.x == 0.0f)
graph_size.x = CalcItemWidth(); frame_size.x = CalcItemWidth();
if (graph_size.y == 0.0f) if (frame_size.y == 0.0f)
graph_size.y = label_size.y + (style.FramePadding.y * 2); frame_size.y = label_size.y + (style.FramePadding.y * 2);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(graph_size.x, graph_size.y)); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0)); const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0));
ItemSize(total_bb, style.FramePadding.y); ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, 0, &frame_bb)) if (!ItemAdd(total_bb, 0, &frame_bb))
return; return;
const bool hovered = ItemHoverable(inner_bb, 0); const bool hovered = ItemHoverable(frame_bb, id);
// Determine scale from values if not specified // Determine scale from values if not specified
if (scale_min == FLT_MAX || scale_max == FLT_MAX) if (scale_min == FLT_MAX || scale_max == FLT_MAX)
@ -5266,12 +5291,12 @@ void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_ge
if (values_count > 0) if (values_count > 0)
{ {
int res_w = ImMin((int)graph_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); int res_w = ImMin((int)frame_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0);
int item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); int item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0);
// Tooltip on hover // Tooltip on hover
int v_hovered = -1; int v_hovered = -1;
if (hovered) if (hovered && inner_bb.Contains(g.IO.MousePos))
{ {
const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f); const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f);
const int v_idx = (int)(t * item_count); const int v_idx = (int)(t * item_count);
@ -5478,7 +5503,7 @@ bool ImGui::BeginMainMenuBar()
End(); End();
return false; return false;
} }
return true; return true; //-V1020
} }
void ImGui::EndMainMenuBar() void ImGui::EndMainMenuBar()
@ -5580,7 +5605,9 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
if (menuset_is_open) if (menuset_is_open)
g.NavWindow = window; // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent) g.NavWindow = window; // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent)
// The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu (using FindBestWindowPosForPopup). // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu,
// However the final position is going to be different! It is choosen by FindBestWindowPosForPopup().
// e.g. Menus tend to overlap each other horizontally to amplify relative Z-ordering.
ImVec2 popup_pos, pos = window->DC.CursorPos; ImVec2 popup_pos, pos = window->DC.CursorPos;
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
{ {
@ -5620,13 +5647,14 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
{ {
if (ImGuiWindow* next_window = g.OpenPopupStack[g.BeginPopupStack.Size].Window) if (ImGuiWindow* next_window = g.OpenPopupStack[g.BeginPopupStack.Size].Window)
{ {
// FIXME-DPI: Values should be derived from a master "scale" factor.
ImRect next_window_rect = next_window->Rect(); ImRect next_window_rect = next_window->Rect();
ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta; ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta;
ImVec2 tb = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR(); ImVec2 tb = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR();
ImVec2 tc = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR(); ImVec2 tc = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR();
float extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, 5.0f, 30.0f); // add a bit of extra slack. float extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, 5.0f, 30.0f); // add a bit of extra slack.
ta.x += (window->Pos.x < next_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues ta.x += (window->Pos.x < next_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues
tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f); // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus // FIXME: Multiply by fb_scale? tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f); // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus // FIXME: Multiply by fb_scale?
tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f); tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f);
moving_within_opened_triangle = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos); moving_within_opened_triangle = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos);
//window->DrawList->PushClipRectFullScreen(); window->DrawList->AddTriangleFilled(ta, tb, tc, moving_within_opened_triangle ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); window->DrawList->PopClipRect(); // Debug //window->DrawList->PushClipRectFullScreen(); window->DrawList->AddTriangleFilled(ta, tb, tc, moving_within_opened_triangle ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); window->DrawList->PopClipRect(); // Debug
@ -5787,6 +5815,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected,
// - TabBarScrollToTab() [Internal] // - TabBarScrollToTab() [Internal]
// - TabBarQueueChangeTabOrder() [Internal] // - TabBarQueueChangeTabOrder() [Internal]
// - TabBarScrollingButtons() [Internal] // - TabBarScrollingButtons() [Internal]
// - TabBarTabListPopupButton() [Internal]
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
namespace ImGui namespace ImGui
@ -5797,6 +5826,7 @@ namespace ImGui
static float TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling); static float TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling);
static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
static ImGuiTabItem* TabBarScrollingButtons(ImGuiTabBar* tab_bar); static ImGuiTabItem* TabBarScrollingButtons(ImGuiTabBar* tab_bar);
static ImGuiTabItem* TabBarTabListPopupButton(ImGuiTabBar* tab_bar);
} }
ImGuiTabBar::ImGuiTabBar() ImGuiTabBar::ImGuiTabBar()
@ -5804,6 +5834,7 @@ ImGuiTabBar::ImGuiTabBar()
ID = 0; ID = 0;
SelectedTabId = NextSelectedTabId = VisibleTabId = 0; SelectedTabId = NextSelectedTabId = VisibleTabId = 0;
CurrFrameVisible = PrevFrameVisible = -1; CurrFrameVisible = PrevFrameVisible = -1;
ContentsHeight = 0.0f;
OffsetMax = OffsetNextTab = 0.0f; OffsetMax = OffsetNextTab = 0.0f;
ScrollingAnim = ScrollingTarget = 0.0f; ScrollingAnim = ScrollingTarget = 0.0f;
Flags = ImGuiTabBarFlags_None; Flags = ImGuiTabBarFlags_None;
@ -5861,7 +5892,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
return true; return true;
} }
// When toggling back from ordered to manually-reorderable, shuffle tabs to enforce the last visible order. // When toggling back from ordered to manually-reorderable, shuffle tabs to enforce the last visible order.
// Otherwise, the most recently inserted tabs would move at the end of visible list which can be a little too confusing or magic for the user. // Otherwise, the most recently inserted tabs would move at the end of visible list which can be a little too confusing or magic for the user.
if ((flags & ImGuiTabBarFlags_Reorderable) && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable) && tab_bar->Tabs.Size > 1 && tab_bar->PrevFrameVisible != -1) if ((flags & ImGuiTabBarFlags_Reorderable) && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable) && tab_bar->Tabs.Size > 1 && tab_bar->PrevFrameVisible != -1)
ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByVisibleOffset); ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByVisibleOffset);
@ -5875,8 +5906,9 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
tab_bar->WantLayout = true; // Layout will be done on the first call to ItemTab() tab_bar->WantLayout = true; // Layout will be done on the first call to ItemTab()
tab_bar->PrevFrameVisible = tab_bar->CurrFrameVisible; tab_bar->PrevFrameVisible = tab_bar->CurrFrameVisible;
tab_bar->CurrFrameVisible = g.FrameCount; tab_bar->CurrFrameVisible = g.FrameCount;
tab_bar->FramePadding = g.Style.FramePadding;
// Layout // Layout
ItemSize(ImVec2(tab_bar->OffsetMax, tab_bar->BarRect.GetHeight())); ItemSize(ImVec2(tab_bar->OffsetMax, tab_bar->BarRect.GetHeight()));
window->DC.CursorPos.x = tab_bar->BarRect.Min.x; window->DC.CursorPos.x = tab_bar->BarRect.Min.x;
@ -5884,8 +5916,8 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_Tab); const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_Tab);
const float y = tab_bar->BarRect.Max.y - 1.0f; const float y = tab_bar->BarRect.Max.y - 1.0f;
{ {
const float separator_min_x = tab_bar->BarRect.Min.x - ((flags & ImGuiTabBarFlags_DockNodeIsDockSpace) ? 0.0f : window->WindowPadding.x); const float separator_min_x = tab_bar->BarRect.Min.x - window->WindowPadding.x;
const float separator_max_x = tab_bar->BarRect.Max.x + ((flags & ImGuiTabBarFlags_DockNodeIsDockSpace) ? 0.0f : window->WindowPadding.x); const float separator_max_x = tab_bar->BarRect.Max.x + window->WindowPadding.x;
window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f); window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f);
} }
return true; return true;
@ -5972,6 +6004,12 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
tab_bar->ReorderRequestTabId = 0; tab_bar->ReorderRequestTabId = 0;
} }
// Tab List Popup (will alter tab_bar->BarRect and therefore the available width!)
const bool tab_list_popup_button = (tab_bar->Flags & ImGuiTabBarFlags_TabListPopupButton) != 0;
if (tab_list_popup_button)
if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Max.x!
scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID;
ImVector<ImGuiTabBarSortItem>& width_sort_buffer = g.TabSortByWidthBuffer; ImVector<ImGuiTabBarSortItem>& width_sort_buffer = g.TabSortByWidthBuffer;
width_sort_buffer.resize(tab_bar->Tabs.Size); width_sort_buffer.resize(tab_bar->Tabs.Size);
@ -5989,9 +6027,12 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
if (tab->ID == tab_bar->SelectedTabId) if (tab->ID == tab_bar->SelectedTabId)
found_selected_tab_id = true; found_selected_tab_id = true;
// Refresh tab width immediately if we can (for manual tab bar, WidthContent will lag by one frame which is mostly noticeable when changing style.FramePadding.x) // Refresh tab width immediately, otherwise changes of style e.g. style.FramePadding.x would noticeably lag in the tab bar.
// Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet, // Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet,
// and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window. // and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window.
const char* tab_name = tab_bar->GetTabName(tab);
tab->WidthContents = TabItemCalcSize(tab_name, (tab->Flags & ImGuiTabItemFlags_NoCloseButton) ? false : true).x;
width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->WidthContents; width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->WidthContents;
// Store data so we can build an array sorted by width if we need to shrink tabs down // Store data so we can build an array sorted by width if we need to shrink tabs down
@ -6069,6 +6110,10 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
const float scrolling_speed = (tab_bar->PrevFrameVisible + 1 < g.FrameCount) ? FLT_MAX : (g.IO.DeltaTime * g.FontSize * 70.0f); const float scrolling_speed = (tab_bar->PrevFrameVisible + 1 < g.FrameCount) ? FLT_MAX : (g.IO.DeltaTime * g.FontSize * 70.0f);
if (tab_bar->ScrollingAnim != tab_bar->ScrollingTarget) if (tab_bar->ScrollingAnim != tab_bar->ScrollingTarget)
tab_bar->ScrollingAnim = ImLinearSweep(tab_bar->ScrollingAnim, tab_bar->ScrollingTarget, scrolling_speed); tab_bar->ScrollingAnim = ImLinearSweep(tab_bar->ScrollingAnim, tab_bar->ScrollingTarget, scrolling_speed);
// Clear name buffers
if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0)
tab_bar->TabsNames.Buf.resize(0);
} }
// Dockables uses Name/ID in the global namespace. Non-dockable items use the ID stack. // Dockables uses Name/ID in the global namespace. Non-dockable items use the ID stack.
@ -6076,7 +6121,7 @@ static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label)
{ {
if (tab_bar->Flags & ImGuiTabBarFlags_DockNode) if (tab_bar->Flags & ImGuiTabBarFlags_DockNode)
{ {
ImGuiID id = ImHash(label, 0); ImGuiID id = ImHashStr(label, 0);
KeepAliveID(id); KeepAliveID(id);
return id; return id;
} }
@ -6210,6 +6255,41 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar)
return tab_to_select; return tab_to_select;
} }
static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
// We use g.Style.FramePadding.y to match the square ArrowButton size
const float tab_list_popup_button_width = g.FontSize + g.Style.FramePadding.y;
const ImVec2 backup_cursor_pos = window->DC.CursorPos;
window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x - g.Style.FramePadding.y, tab_bar->BarRect.Min.y);
tab_bar->BarRect.Min.x += tab_list_popup_button_width;
ImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text];
arrow_col.w *= 0.5f;
PushStyleColor(ImGuiCol_Text, arrow_col);
PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
bool open = BeginCombo("##v", NULL, ImGuiComboFlags_NoPreview);
PopStyleColor(2);
ImGuiTabItem* tab_to_select = NULL;
if (open)
{
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
{
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
const char* tab_name = tab_bar->GetTabName(tab);
if (Selectable(tab_name, tab_bar->SelectedTabId == tab->ID))
tab_to_select = tab;
}
EndCombo();
}
window->DC.CursorPos = backup_cursor_pos;
return tab_to_select;
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// [SECTION] Widgets: BeginTabItem, EndTabItem, etc. // [SECTION] Widgets: BeginTabItem, EndTabItem, etc.
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -6221,7 +6301,7 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar)
// - TabItemEx() [Internal] // - TabItemEx() [Internal]
// - SetTabItemClosed() // - SetTabItemClosed()
// - TabItemCalcSize() [Internal] // - TabItemCalcSize() [Internal]
// - TabItemRenderBackground() [Internal] // - TabItemBackground() [Internal]
// - TabItemLabelAndCloseButton() [Internal] // - TabItemLabelAndCloseButton() [Internal]
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -6296,12 +6376,19 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_ptr(tab); tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_ptr(tab);
tab->WidthContents = size.x; tab->WidthContents = size.x;
if (p_open == NULL)
flags |= ImGuiTabItemFlags_NoCloseButton;
const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount);
const bool tab_bar_focused = (tab_bar->Flags & ImGuiTabBarFlags_IsFocused) != 0; const bool tab_bar_focused = (tab_bar->Flags & ImGuiTabBarFlags_IsFocused) != 0;
const bool tab_appearing = (tab->LastFrameVisible + 1 < g.FrameCount); const bool tab_appearing = (tab->LastFrameVisible + 1 < g.FrameCount);
tab->LastFrameVisible = g.FrameCount; tab->LastFrameVisible = g.FrameCount;
tab->Flags = flags; tab->Flags = flags;
// Append name with zero-terminator
tab->NameOffset = tab_bar->TabsNames.size();
tab_bar->TabsNames.append(label, label + strlen(label) + 1);
// If we are not reorderable, always reset offset based on submission order. // If we are not reorderable, always reset offset based on submission order.
// (We already handled layout and sizing using the previous known order, but sizing is not affected by order!) // (We already handled layout and sizing using the previous known order, but sizing is not affected by order!)
if (!tab_appearing && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable)) if (!tab_appearing && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable))
@ -6398,7 +6485,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
// Enlarge tab display when hovering // Enlarge tab display when hovering
bb.Max.x = bb.Min.x + (float)(int)ImLerp(bb.GetWidth(), tab->WidthContents, ImSaturate((g.HoveredIdNotActiveTimer - 0.40f) * 6.0f)); bb.Max.x = bb.Min.x + (float)(int)ImLerp(bb.GetWidth(), tab->WidthContents, ImSaturate((g.HoveredIdNotActiveTimer - 0.40f) * 6.0f));
display_draw_list = GetOverlayDrawList(window); display_draw_list = GetOverlayDrawList(window);
TabItemRenderBackground(display_draw_list, bb, flags, GetColorU32(ImGuiCol_TitleBgActive)); TabItemBackground(display_draw_list, bb, flags, GetColorU32(ImGuiCol_TitleBgActive));
} }
#endif #endif
@ -6417,9 +6504,9 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton;
// Render tab label, process close button // Render tab label, process close button
const ImGuiID close_button_id = p_open ? window->GetID((void*)(intptr_t)(id + 1)) : 0; const ImGuiID close_button_id = p_open ? window->GetID((void*)((intptr_t)id + 1)) : 0;
bool just_closed = TabItemLabelAndCloseButton(display_draw_list, bb, flags, label, id, close_button_id); bool just_closed = TabItemLabelAndCloseButton(display_draw_list, bb, flags, tab_bar->FramePadding, label, id, close_button_id);
if (just_closed) if (just_closed && p_open != NULL)
{ {
*p_open = false; *p_open = false;
TabBarCloseTab(tab_bar, tab); TabBarCloseTab(tab_bar, tab);
@ -6468,40 +6555,45 @@ ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button)
void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col) void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col)
{ {
// While rendering tabs, we trim 1 pixel off the top of our bounding box so they can fit within a regular frame height while looking "detached" from it. // While rendering tabs, we trim 1 pixel off the top of our bounding box so they can fit within a regular frame height while looking "detached" from it.
(void)flags;
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
const float width = bb.GetWidth(); const float width = bb.GetWidth();
IM_UNUSED(flags);
IM_ASSERT(width > 0.0f); IM_ASSERT(width > 0.0f);
const float rounding = ImMax(0.0f, ImMin(g.Style.TabRounding, width * 0.5f - 1.0f)); const float rounding = ImMax(0.0f, ImMin(g.Style.TabRounding, width * 0.5f - 1.0f));
float y1 = bb.Min.y + 1.0f; const float y1 = bb.Min.y + 1.0f;
float y2 = bb.Max.y - 1.0f; const float y2 = bb.Max.y - 1.0f;
draw_list->PathLineTo(ImVec2(bb.Min.x, y2)); draw_list->PathLineTo(ImVec2(bb.Min.x, y2));
draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding, y1 + rounding), rounding, 6, 9); draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding, y1 + rounding), rounding, 6, 9);
draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding, y1 + rounding), rounding, 9, 12); draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding, y1 + rounding), rounding, 9, 12);
draw_list->PathLineTo(ImVec2(bb.Max.x, y2)); draw_list->PathLineTo(ImVec2(bb.Max.x, y2));
draw_list->AddConvexPolyFilled(draw_list->_Path.Data, draw_list->_Path.Size, col); draw_list->PathFillConvex(col);
if (g.Style.TabBorderSize > 0.0f) if (g.Style.TabBorderSize > 0.0f)
draw_list->AddPolyline(draw_list->_Path.Data, draw_list->_Path.Size, GetColorU32(ImGuiCol_Border), false, g.Style.TabBorderSize); {
draw_list->PathClear(); draw_list->PathLineTo(ImVec2(bb.Min.x + 0.5f, y2));
draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding + 0.5f, y1 + rounding + 0.5f), rounding, 6, 9);
draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding - 0.5f, y1 + rounding + 0.5f), rounding, 9, 12);
draw_list->PathLineTo(ImVec2(bb.Max.x - 0.5f, y2));
draw_list->PathStroke(GetColorU32(ImGuiCol_Border), false, g.Style.TabBorderSize);
}
} }
// Render text label (with custom clipping) + Unsaved Document marker + Close Button logic // Render text label (with custom clipping) + Unsaved Document marker + Close Button logic
bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, const char* label, ImGuiID tab_id, ImGuiID close_button_id) // We tend to lock style.FramePadding for a given tab-bar, hence the 'frame_padding' parameter.
bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiStyle& style = g.Style;
ImVec2 label_size = CalcTextSize(label, NULL, true); ImVec2 label_size = CalcTextSize(label, NULL, true);
if (bb.GetWidth() <= 1.0f) if (bb.GetWidth() <= 1.0f)
return false; return false;
// Render text label (with clipping + alpha gradient) + unsaved marker // Render text label (with clipping + alpha gradient) + unsaved marker
const char* TAB_UNSAVED_MARKER = "*"; const char* TAB_UNSAVED_MARKER = "*";
ImRect text_pixel_clip_bb(bb.Min.x + style.FramePadding.x, bb.Min.y + style.FramePadding.y, bb.Max.x - style.FramePadding.x, bb.Max.y); ImRect text_pixel_clip_bb(bb.Min.x + frame_padding.x, bb.Min.y + frame_padding.y, bb.Max.x - frame_padding.x, bb.Max.y);
if (flags & ImGuiTabItemFlags_UnsavedDocument) if (flags & ImGuiTabItemFlags_UnsavedDocument)
{ {
text_pixel_clip_bb.Max.x -= CalcTextSize(TAB_UNSAVED_MARKER, NULL, false).x; text_pixel_clip_bb.Max.x -= CalcTextSize(TAB_UNSAVED_MARKER, NULL, false).x;
ImVec2 unsaved_marker_pos(ImMin(bb.Min.x + style.FramePadding.x + label_size.x + 2, text_pixel_clip_bb.Max.x), bb.Min.y + style.FramePadding.y + (float)(int)(-g.FontSize * 0.25f)); ImVec2 unsaved_marker_pos(ImMin(bb.Min.x + frame_padding.x + label_size.x + 2, text_pixel_clip_bb.Max.x), bb.Min.y + frame_padding.y + (float)(int)(-g.FontSize * 0.25f));
RenderTextClippedEx(draw_list, unsaved_marker_pos, bb.Max - style.FramePadding, TAB_UNSAVED_MARKER, NULL, NULL); RenderTextClippedEx(draw_list, unsaved_marker_pos, bb.Max - frame_padding, TAB_UNSAVED_MARKER, NULL, NULL);
} }
ImRect text_ellipsis_clip_bb = text_pixel_clip_bb; ImRect text_ellipsis_clip_bb = text_pixel_clip_bb;
@ -6519,7 +6611,7 @@ bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
{ {
ImGuiItemHoveredDataBackup last_item_backup; ImGuiItemHoveredDataBackup last_item_backup;
const float close_button_sz = g.FontSize * 0.5f; const float close_button_sz = g.FontSize * 0.5f;
if (CloseButton(close_button_id, ImVec2(bb.Max.x - style.FramePadding.x - close_button_sz, bb.Min.y + style.FramePadding.y + close_button_sz), close_button_sz)) if (CloseButton(close_button_id, ImVec2(bb.Max.x - frame_padding.x - close_button_sz, bb.Min.y + frame_padding.y + close_button_sz), close_button_sz))
close_button_pressed = true; close_button_pressed = true;
last_item_backup.Restore(); last_item_backup.Restore();

View File

@ -1,4 +1,10 @@
// stb_rect_pack.h - v0.11 - public domain - rectangle packing // [DEAR IMGUI]
// This is a slightly modified version of stb_rect_pack.h 0.99.
// Those changes would need to be pushed into nothings/stb:
// - Added STBRP__CDECL
// Grep for [DEAR IMGUI] to find the changes.
// stb_rect_pack.h - v0.99 - public domain - rectangle packing
// Sean Barrett 2014 // Sean Barrett 2014
// //
// Useful for e.g. packing rectangular textures into an atlas. // Useful for e.g. packing rectangular textures into an atlas.
@ -34,6 +40,7 @@
// //
// Version history: // Version history:
// //
// 0.99 (2019-02-07) warning fixes
// 0.11 (2017-03-03) return packing success/fail result // 0.11 (2017-03-03) return packing success/fail result
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings // 0.10 (2016-10-25) remove cast-away-const to avoid warnings
// 0.09 (2016-08-27) fix compiler warnings // 0.09 (2016-08-27) fix compiler warnings
@ -204,6 +211,7 @@ struct stbrp_context
#define STBRP_ASSERT assert #define STBRP_ASSERT assert
#endif #endif
// [DEAR IMGUI] Added STBRP__CDECL
#ifdef _MSC_VER #ifdef _MSC_VER
#define STBRP__NOTUSED(v) (void)(v) #define STBRP__NOTUSED(v) (void)(v)
#define STBRP__CDECL __cdecl #define STBRP__CDECL __cdecl
@ -512,6 +520,7 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i
return res; return res;
} }
// [DEAR IMGUI] Added STBRP__CDECL
static int STBRP__CDECL rect_height_compare(const void *a, const void *b) static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
{ {
const stbrp_rect *p = (const stbrp_rect *) a; const stbrp_rect *p = (const stbrp_rect *) a;
@ -523,6 +532,7 @@ static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
return (p->w > q->w) ? -1 : (p->w < q->w); return (p->w > q->w) ? -1 : (p->w < q->w);
} }
// [DEAR IMGUI] Added STBRP__CDECL
static int STBRP__CDECL rect_original_order(const void *a, const void *b) static int STBRP__CDECL rect_original_order(const void *a, const void *b)
{ {
const stbrp_rect *p = (const stbrp_rect *) a; const stbrp_rect *p = (const stbrp_rect *) a;
@ -543,9 +553,6 @@ STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int nu
// we use the 'was_packed' field internally to allow sorting/unsorting // we use the 'was_packed' field internally to allow sorting/unsorting
for (i=0; i < num_rects; ++i) { for (i=0; i < num_rects; ++i) {
rects[i].was_packed = i; rects[i].was_packed = i;
#ifndef STBRP_LARGE_RECTS
STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff);
#endif
} }
// sort according to heuristic // sort according to heuristic

View File

@ -1,9 +1,10 @@
// [ImGui] this is a slightly modified version of stb_textedit.h 1.12. Those changes would need to be pushed into nothings/stb // [DEAR IMGUI]
// [ImGui] - 2018-06: fixed undo/redo after pasting large amount of text (over 32 kb). Redo will still fail when undo buffers are exhausted, but text won't be corrupted (see nothings/stb issue #620) // This is a slightly modified version of stb_textedit.h 1.13.
// [ImGui] - 2018-06: fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321) // Those changes would need to be pushed into nothings/stb:
// [ImGui] - fixed some minor warnings // - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
// Grep for [DEAR IMGUI] to find the changes.
// stb_textedit.h - v1.12 - public domain - Sean Barrett // stb_textedit.h - v1.13 - public domain - Sean Barrett
// Development of this library was sponsored by RAD Game Tools // Development of this library was sponsored by RAD Game Tools
// //
// This C header file implements the guts of a multi-line text-editing // This C header file implements the guts of a multi-line text-editing
@ -34,6 +35,7 @@
// //
// VERSION HISTORY // VERSION HISTORY
// //
// 1.13 (2019-02-07) fix bug in undo size management
// 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash // 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash
// 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield // 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield
// 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual // 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual
@ -563,7 +565,6 @@ static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *s
// now scan to find xpos // now scan to find xpos
find->x = r.x0; find->x = r.x0;
i = 0;
for (i=0; first+i < n; ++i) for (i=0; first+i < n; ++i)
find->x += STB_TEXTEDIT_GETWIDTH(str, first, i); find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
} }
@ -693,7 +694,7 @@ static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state)
static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
{ {
if (STB_TEXT_HAS_SELECTION(state)) { if (STB_TEXT_HAS_SELECTION(state)) {
stb_textedit_delete_selection(str,state); // implicity clamps stb_textedit_delete_selection(str,state); // implicitly clamps
state->has_preferred_x = 0; state->has_preferred_x = 0;
return 1; return 1;
} }
@ -745,7 +746,7 @@ retry:
state->has_preferred_x = 0; state->has_preferred_x = 0;
} }
} else { } else {
stb_textedit_delete_selection(str,state); // implicity clamps stb_textedit_delete_selection(str,state); // implicitly clamps
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
stb_text_makeundo_insert(state, state->cursor, 1); stb_text_makeundo_insert(state, state->cursor, 1);
++state->cursor; ++state->cursor;
@ -1133,7 +1134,14 @@ static void stb_textedit_discard_redo(StbUndoState *state)
state->undo_rec[i].char_storage += n; state->undo_rec[i].char_storage += n;
} }
// now move all the redo records towards the end of the buffer; the first one is at 'redo_point' // now move all the redo records towards the end of the buffer; the first one is at 'redo_point'
STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, (size_t) ((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0]))); // {DEAR IMGUI]
size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0]));
const char* buf_begin = (char*)state->undo_rec; (void)buf_begin;
const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end;
IM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin);
IM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end);
STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size);
// now move redo_point to point to the new one // now move redo_point to point to the new one
++state->redo_point; ++state->redo_point;
} }

View File

@ -1,4 +1,9 @@
// stb_truetype.h - v1.19 - public domain // [DEAR IMGUI]
// This is a slightly modified version of stb_truetype.h 1.20.
// Mostly fixing for compiler and static analyzer warnings.
// Grep for [DEAR IMGUI] to find the changes.
// stb_truetype.h - v1.20 - public domain
// authored from 2009-2016 by Sean Barrett / RAD Game Tools // authored from 2009-2016 by Sean Barrett / RAD Game Tools
// //
// This library processes TrueType files: // This library processes TrueType files:
@ -49,6 +54,7 @@
// //
// VERSION HISTORY // VERSION HISTORY
// //
// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod // 1.19 (2018-02-11) GPOS kerning, STBTT_fmod
// 1.18 (2018-01-29) add missing function // 1.18 (2018-01-29) add missing function
// 1.17 (2017-07-23) make more arguments const; doc fix // 1.17 (2017-07-23) make more arguments const; doc fix
@ -75,7 +81,7 @@
// //
// USAGE // USAGE
// //
// Include this file in whatever places neeed to refer to it. In ONE C/C++ // Include this file in whatever places need to refer to it. In ONE C/C++
// file, write: // file, write:
// #define STB_TRUETYPE_IMPLEMENTATION // #define STB_TRUETYPE_IMPLEMENTATION
// before the #include of this file. This expands out the actual // before the #include of this file. This expands out the actual
@ -247,8 +253,8 @@
// Documentation & header file 520 LOC \___ 660 LOC documentation // Documentation & header file 520 LOC \___ 660 LOC documentation
// Sample code 140 LOC / // Sample code 140 LOC /
// Truetype parsing 620 LOC ---- 620 LOC TrueType // Truetype parsing 620 LOC ---- 620 LOC TrueType
// Software rasterization 240 LOC \ . // Software rasterization 240 LOC \.
// Curve tesselation 120 LOC \__ 550 LOC Bitmap creation // Curve tessellation 120 LOC \__ 550 LOC Bitmap creation
// Bitmap management 100 LOC / // Bitmap management 100 LOC /
// Baked bitmap interface 70 LOC / // Baked bitmap interface 70 LOC /
// Font name matching & access 150 LOC ---- 150 // Font name matching & access 150 LOC ---- 150
@ -556,6 +562,8 @@ STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int p
// //
// It's inefficient; you might want to c&p it and optimize it. // It's inefficient; you might want to c&p it and optimize it.
STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap);
// Query the font vertical metrics without having to create a font first.
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -641,6 +649,12 @@ STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h
// To use with PackFontRangesGather etc., you must set it before calls // To use with PackFontRangesGather etc., you must set it before calls
// call to PackFontRangesGatherRects. // call to PackFontRangesGatherRects.
STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip);
// If skip != 0, this tells stb_truetype to skip any codepoints for which
// there is no corresponding glyph. If skip=0, which is the default, then
// codepoints without a glyph recived the font's "missing character" glyph,
// typically an empty box by convention.
STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above
int char_index, // character to display int char_index, // character to display
float *xpos, float *ypos, // pointers to current position in screen pixel space float *xpos, float *ypos, // pointers to current position in screen pixel space
@ -669,6 +683,7 @@ struct stbtt_pack_context {
int height; int height;
int stride_in_bytes; int stride_in_bytes;
int padding; int padding;
int skip_missing;
unsigned int h_oversample, v_oversample; unsigned int h_oversample, v_oversample;
unsigned char *pixels; unsigned char *pixels;
void *nodes; void *nodes;
@ -694,7 +709,7 @@ STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);
// file will only define one font and it always be at offset 0, so it will // file will only define one font and it always be at offset 0, so it will
// return '0' for index 0, and -1 for all other indices. // return '0' for index 0, and -1 for all other indices.
// The following structure is defined publically so you can declare one on // The following structure is defined publicly so you can declare one on
// the stack or as a global or etc, but you should treat it as opaque. // the stack or as a global or etc, but you should treat it as opaque.
struct stbtt_fontinfo struct stbtt_fontinfo
{ {
@ -733,6 +748,7 @@ STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codep
// and you want a speed-up, call this function with the character you're // and you want a speed-up, call this function with the character you're
// going to process, then use glyph-based functions instead of the // going to process, then use glyph-based functions instead of the
// codepoint-based functions. // codepoint-based functions.
// Returns 0 if the character codepoint is not defined in the font.
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -820,7 +836,7 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s
// returns # of vertices and fills *vertices with the pointer to them // returns # of vertices and fills *vertices with the pointer to them
// these are expressed in "unscaled" coordinates // these are expressed in "unscaled" coordinates
// //
// The shape is a series of countours. Each one starts with // The shape is a series of contours. Each one starts with
// a STBTT_moveto, then consists of a series of mixed // a STBTT_moveto, then consists of a series of mixed
// STBTT_lineto and STBTT_curveto segments. A lineto // STBTT_lineto and STBTT_curveto segments. A lineto
// draws a line from previous endpoint to its x,y; a curveto // draws a line from previous endpoint to its x,y; a curveto
@ -916,7 +932,7 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
// These functions compute a discretized SDF field for a single character, suitable for storing // These functions compute a discretized SDF field for a single character, suitable for storing
// in a single-channel texture, sampling with bilinear filtering, and testing against // in a single-channel texture, sampling with bilinear filtering, and testing against
// larger than some threshhold to produce scalable fonts. // larger than some threshold to produce scalable fonts.
// info -- the font // info -- the font
// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap // scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap
// glyph/codepoint -- the character to generate the SDF for // glyph/codepoint -- the character to generate the SDF for
@ -1825,7 +1841,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
if (comp_verts) STBTT_free(comp_verts, info->userdata); if (comp_verts) STBTT_free(comp_verts, info->userdata);
return 0; return 0;
} }
if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); //-V595
STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
if (vertices) STBTT_free(vertices, info->userdata); if (vertices) STBTT_free(vertices, info->userdata);
vertices = tmp; vertices = tmp;
@ -2196,7 +2212,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
} break; } break;
default: default:
if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) //-V560
return STBTT__CSERR("reserved operator"); return STBTT__CSERR("reserved operator");
// push immediate // push immediate
@ -2368,7 +2384,8 @@ static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
classDefTable = classDef1ValueArray + 2 * glyphCount; // [DEAR IMGUI] Commented to fix static analyzer warning
//classDefTable = classDef1ValueArray + 2 * glyphCount;
} break; } break;
case 2: { case 2: {
@ -2392,7 +2409,8 @@ static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
return (stbtt_int32)ttUSHORT(classRangeRecord + 4); return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
} }
classDefTable = classRangeRecords + 6 * classRangeCount; // [DEAR IMGUI] Commented to fix static analyzer warning
//classDefTable = classRangeRecords + 6 * classRangeCount;
} break; } break;
default: { default: {
@ -3024,6 +3042,8 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
dx = -dx; dx = -dx;
dy = -dy; dy = -dy;
t = x0, x0 = xb, xb = t; t = x0, x0 = xb, xb = t;
// [DEAR IMGUI] Fix static analyzer warning
(void)dx; // [ImGui: fix static analyzer warning]
} }
x1 = (int) x_top; x1 = (int) x_top;
@ -3161,7 +3181,13 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e,
if (e->y0 != e->y1) { if (e->y0 != e->y1) {
stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);
if (z != NULL) { if (z != NULL) {
STBTT_assert(z->ey >= scan_y_top); if (j == 0 && off_y != 0) {
if (z->ey < scan_y_top) {
// this can happen due to subpixel positioning and some kind of fp rounding error i think
z->ey = scan_y_top;
}
}
STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds
// insert at front // insert at front
z->next = active; z->next = active;
active = z; active = z;
@ -3230,7 +3256,7 @@ static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)
static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)
{ {
/* threshhold for transitioning to insertion sort */ /* threshold for transitioning to insertion sort */
while (n > 12) { while (n > 12) {
stbtt__edge t; stbtt__edge t;
int c01,c12,c,m,i,j; int c01,c12,c,m,i,j;
@ -3365,7 +3391,7 @@ static void stbtt__add_point(stbtt__point *points, int n, float x, float y)
points[n].y = y; points[n].y = y;
} }
// tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching // tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching
static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)
{ {
// midpoint // midpoint
@ -3790,6 +3816,7 @@ STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, in
spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;
spc->h_oversample = 1; spc->h_oversample = 1;
spc->v_oversample = 1; spc->v_oversample = 1;
spc->skip_missing = 0;
stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);
@ -3815,6 +3842,11 @@ STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h
spc->v_oversample = v_oversample; spc->v_oversample = v_oversample;
} }
STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip)
{
spc->skip_missing = skip;
}
#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) #define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1)
static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)
@ -3968,13 +4000,17 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stb
int x0,y0,x1,y1; int x0,y0,x1,y1;
int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
int glyph = stbtt_FindGlyphIndex(info, codepoint); int glyph = stbtt_FindGlyphIndex(info, codepoint);
stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, if (glyph == 0 && spc->skip_missing) {
scale * spc->h_oversample, rects[k].w = rects[k].h = 0;
scale * spc->v_oversample, } else {
0,0, stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
&x0,&y0,&x1,&y1); scale * spc->h_oversample,
rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); scale * spc->v_oversample,
rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); 0,0,
&x0,&y0,&x1,&y1);
rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
}
++k; ++k;
} }
} }
@ -4027,7 +4063,7 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const
sub_y = stbtt__oversample_shift(spc->v_oversample); sub_y = stbtt__oversample_shift(spc->v_oversample);
for (j=0; j < ranges[i].num_chars; ++j) { for (j=0; j < ranges[i].num_chars; ++j) {
stbrp_rect *r = &rects[k]; stbrp_rect *r = &rects[k];
if (r->was_packed) { if (r->was_packed && r->w != 0 && r->h != 0) {
stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];
int advance, lsb, x0,y0,x1,y1; int advance, lsb, x0,y0,x1,y1;
int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
@ -4141,6 +4177,19 @@ STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *
return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);
} }
STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap)
{
int i_ascent, i_descent, i_lineGap;
float scale;
stbtt_fontinfo info;
stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index));
scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size);
stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap);
*ascent = (float) i_ascent * scale;
*descent = (float) i_descent * scale;
*lineGap = (float) i_lineGap * scale;
}
STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)
{ {
float ipw = 1.0f / pw, iph = 1.0f / ph; float ipw = 1.0f / pw, iph = 1.0f / ph;
@ -4253,7 +4302,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
int winding = 0; int winding = 0;
orig[0] = x; orig[0] = x;
orig[1] = y; //orig[1] = y; // [DEAR IMGUI] commmented double assignment
// make sure y never passes through a vertex of the shape // make sure y never passes through a vertex of the shape
y_frac = (float) STBTT_fmod(y, 1.0f); y_frac = (float) STBTT_fmod(y, 1.0f);

View File

@ -5,12 +5,13 @@
// Changelog: // Changelog:
// - v0.50: (2017/08/16) imported from https://github.com/Vuhdo/imgui_freetype into http://www.github.com/ocornut/imgui_club, updated for latest changes in ImFontAtlas, minor tweaks. // - v0.50: (2017/08/16) imported from https://github.com/Vuhdo/imgui_freetype into http://www.github.com/ocornut/imgui_club, updated for latest changes in ImFontAtlas, minor tweaks.
// - v0.51: (2017/08/26) cleanup, optimizations, support for ImFontConfig::RasterizerFlags, ImFontConfig::RasterizerMultiply. // - v0.51: (2017/08/26) cleanup, optimizations, support for ImFontConfig::RasterizerFlags, ImFontConfig::RasterizerMultiply.
// - v0.52: (2017/09/26) fixes for imgui internal changes // - v0.52: (2017/09/26) fixes for imgui internal changes.
// - v0.53: (2017/10/22) minor inconsequential change to match change in master (removed an unnecessary statement) // - v0.53: (2017/10/22) minor inconsequential change to match change in master (removed an unnecessary statement).
// - v0.54: (2018/01/22) fix for addition of ImFontAtlas::TexUvscale member // - v0.54: (2018/01/22) fix for addition of ImFontAtlas::TexUvscale member.
// - v0.55: (2018/02/04) moved to main imgui repository (away from http://www.github.com/ocornut/imgui_club) // - v0.55: (2018/02/04) moved to main imgui repository (away from http://www.github.com/ocornut/imgui_club)
// - v0.56: (2018/06/08) added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX // - v0.56: (2018/06/08) added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX.
// - v0.60: (2019/01/10) re-factored to match big update in STB builder. fixed texture height waste. fixed redundant glyphs when merging. support for glyph padding. // - v0.60: (2019/01/10) re-factored to match big update in STB builder. fixed texture height waste. fixed redundant glyphs when merging. support for glyph padding.
// - v0.61: (2019/01/15) added support for imgui allocators + added FreeType only override function SetAllocatorFunctions().
// Gamma Correct Blending: // Gamma Correct Blending:
// FreeType assumes blending in linear space rather than gamma space. // FreeType assumes blending in linear space rather than gamma space.
@ -18,7 +19,6 @@
// For correct results you need to be using sRGB and convert to linear space in the pixel shader output. // For correct results you need to be using sRGB and convert to linear space in the pixel shader output.
// The default imgui styles will be impacted by this change (alpha values will need tweaking). // The default imgui styles will be impacted by this change (alpha values will need tweaking).
// FIXME: FreeType's memory allocator is not overridden.
// FIXME: cfg.OversampleH, OversampleV are not supported (but perhaps not so necessary with this rasterizer). // FIXME: cfg.OversampleH, OversampleV are not supported (but perhaps not so necessary with this rasterizer).
#include "imgui_freetype.h" #include "imgui_freetype.h"
@ -26,6 +26,7 @@
#include <stdint.h> #include <stdint.h>
#include <ft2build.h> #include <ft2build.h>
#include FT_FREETYPE_H // <freetype/freetype.h> #include FT_FREETYPE_H // <freetype/freetype.h>
#include FT_MODULE_H // <freetype/ftmodapi.h>
#include FT_GLYPH_H // <freetype/ftglyph.h> #include FT_GLYPH_H // <freetype/ftglyph.h>
#include FT_SYNTHESIS_H // <freetype/ftsynth.h> #include FT_SYNTHESIS_H // <freetype/ftsynth.h>
@ -37,7 +38,7 @@
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
#endif #endif
namespace namespace
{ {
// Glyph metrics: // Glyph metrics:
// -------------- // --------------
@ -71,7 +72,7 @@ namespace
// |------------- advanceX ----------->| // |------------- advanceX ----------->|
/// A structure that describe a glyph. /// A structure that describe a glyph.
struct GlyphInfo struct GlyphInfo
{ {
int Width; // Glyph's width in pixels. int Width; // Glyph's width in pixels.
int Height; // Glyph's height in pixels. int Height; // Glyph's height in pixels.
@ -115,7 +116,6 @@ namespace
bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags) bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags)
{ {
// FIXME: substitute allocator
FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &Face); FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &Face);
if (error != 0) if (error != 0)
return false; return false;
@ -139,7 +139,7 @@ namespace
LoadFlags |= FT_LOAD_TARGET_LIGHT; LoadFlags |= FT_LOAD_TARGET_LIGHT;
else if (UserFlags & ImGuiFreeType::MonoHinting) else if (UserFlags & ImGuiFreeType::MonoHinting)
LoadFlags |= FT_LOAD_TARGET_MONO; LoadFlags |= FT_LOAD_TARGET_MONO;
else else
LoadFlags |= FT_LOAD_TARGET_NORMAL; LoadFlags |= FT_LOAD_TARGET_NORMAL;
return true; return true;
@ -147,16 +147,16 @@ namespace
void FreeTypeFont::CloseFont() void FreeTypeFont::CloseFont()
{ {
if (Face) if (Face)
{ {
FT_Done_Face(Face); FT_Done_Face(Face);
Face = NULL; Face = NULL;
} }
} }
void FreeTypeFont::SetPixelHeight(int pixel_height) void FreeTypeFont::SetPixelHeight(int pixel_height)
{ {
// Vuhdo: I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height' // Vuhdo: I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height'
// is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me. // is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me.
// NB: FT_Set_Pixel_Sizes() doesn't seem to get us the same result. // NB: FT_Set_Pixel_Sizes() doesn't seem to get us the same result.
FT_Size_RequestRec req; FT_Size_RequestRec req;
@ -244,10 +244,12 @@ namespace
} }
} }
#ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
#define STBRP_ASSERT(x) IM_ASSERT(x) #define STBRP_ASSERT(x) IM_ASSERT(x)
#define STBRP_STATIC #define STBRP_STATIC
#define STB_RECT_PACK_IMPLEMENTATION #define STB_RECT_PACK_IMPLEMENTATION
#include "imstb_rectpack.h" #include "imstb_rectpack.h"
#endif
struct ImFontBuildSrcGlyphFT struct ImFontBuildSrcGlyphFT
{ {
@ -334,15 +336,14 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns
{ {
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
ImFontConfig& cfg = atlas->ConfigData[src_i];
src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest + 1); src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest + 1);
if (dst_tmp.SrcCount > 1 && dst_tmp.GlyphsSet.Storage.empty()) if (dst_tmp.GlyphsSet.Storage.empty())
dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1); dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1);
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++)
{ {
if (cfg.MergeMode && dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite) if (dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite)
continue; continue;
uint32_t glyph_index = FT_Get_Char_Index(src_tmp.Font.Face, codepoint); // It is actually in the font? (FIXME-OPT: We are not storing the glyph_index..) uint32_t glyph_index = FT_Get_Char_Index(src_tmp.Font.Face, codepoint); // It is actually in the font? (FIXME-OPT: We are not storing the glyph_index..)
if (glyph_index == 0) if (glyph_index == 0)
@ -352,8 +353,7 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns
src_tmp.GlyphsCount++; src_tmp.GlyphsCount++;
dst_tmp.GlyphsCount++; dst_tmp.GlyphsCount++;
src_tmp.GlyphsSet.SetBit(codepoint, true); src_tmp.GlyphsSet.SetBit(codepoint, true);
if (dst_tmp.SrcCount > 1) dst_tmp.GlyphsSet.SetBit(codepoint, true);
dst_tmp.GlyphsSet.SetBit(codepoint, true);
total_glyphs_count++; total_glyphs_count++;
} }
} }
@ -391,7 +391,7 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns
buf_rects.resize(total_glyphs_count); buf_rects.resize(total_glyphs_count);
memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes()); memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes());
// Allocate temporary rasterization data buffers. // Allocate temporary rasterization data buffers.
// We could not find a way to retrieve accurate glyph size without rendering them. // We could not find a way to retrieve accurate glyph size without rendering them.
// (e.g. slot->metrics->width not always matching bitmap->width, especially considering the Oblique transform) // (e.g. slot->metrics->width not always matching bitmap->width, especially considering the Oblique transform)
// We allocate in chunks of 256 KB to not waste too much extra memory ahead. Hopefully users of FreeType won't find the temporary allocations. // We allocate in chunks of 256 KB to not waste too much extra memory ahead. Hopefully users of FreeType won't find the temporary allocations.
@ -539,7 +539,7 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns
float char_off_x = font_off_x; float char_off_x = font_off_x;
if (char_advance_x_org != char_advance_x_mod) if (char_advance_x_org != char_advance_x_mod)
char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f; char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
// Register glyph // Register glyph
float x0 = info.OffsetX + char_off_x; float x0 = info.OffsetX + char_off_x;
float y0 = info.OffsetY + font_off_y; float y0 = info.OffsetY + font_off_y;
@ -566,15 +566,75 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns
return true; return true;
} }
// Default memory allocators
static void* ImFreeTypeDefaultAllocFunc(size_t size, void* user_data) { IM_UNUSED(user_data); return ImGui::MemAlloc(size); }
static void ImFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { IM_UNUSED(user_data); ImGui::MemFree(ptr); }
// Current memory allocators
static void* (*GImFreeTypeAllocFunc)(size_t size, void* user_data) = ImFreeTypeDefaultAllocFunc;
static void (*GImFreeTypeFreeFunc)(void* ptr, void* user_data) = ImFreeTypeDefaultFreeFunc;
static void* GImFreeTypeAllocatorUserData = NULL;
// FreeType memory allocation callbacks
static void* FreeType_Alloc(FT_Memory /*memory*/, long size)
{
return GImFreeTypeAllocFunc((size_t)size, GImFreeTypeAllocatorUserData);
}
static void FreeType_Free(FT_Memory /*memory*/, void* block)
{
GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData);
}
static void* FreeType_Realloc(FT_Memory /*memory*/, long cur_size, long new_size, void* block)
{
// Implement realloc() as we don't ask user to provide it.
if (block == NULL)
return GImFreeTypeAllocFunc((size_t)new_size, GImFreeTypeAllocatorUserData);
if (new_size == 0)
{
GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData);
return NULL;
}
if (new_size > cur_size)
{
void* new_block = GImFreeTypeAllocFunc((size_t)new_size, GImFreeTypeAllocatorUserData);
memcpy(new_block, block, (size_t)cur_size);
GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData);
return new_block;
}
return block;
}
bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags) bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags)
{ {
// FreeType memory management: https://www.freetype.org/freetype2/docs/design/design-4.html
FT_MemoryRec_ memory_rec = { 0 };
memory_rec.alloc = &FreeType_Alloc;
memory_rec.free = &FreeType_Free;
memory_rec.realloc = &FreeType_Realloc;
// https://www.freetype.org/freetype2/docs/reference/ft2-module_management.html#FT_New_Library
FT_Library ft_library; FT_Library ft_library;
FT_Error error = FT_Init_FreeType(&ft_library); FT_Error error = FT_New_Library(&memory_rec, &ft_library);
if (error != 0) if (error != 0)
return false; return false;
// If you don't call FT_Add_Default_Modules() the rest of code may work, but FreeType won't use our custom allocator.
FT_Add_Default_Modules(ft_library);
bool ret = ImFontAtlasBuildWithFreeType(ft_library, atlas, extra_flags); bool ret = ImFontAtlasBuildWithFreeType(ft_library, atlas, extra_flags);
FT_Done_FreeType(ft_library); FT_Done_Library(ft_library);
return ret; return ret;
} }
void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data)
{
GImFreeTypeAllocFunc = alloc_func;
GImFreeTypeFreeFunc = free_func;
GImFreeTypeAllocatorUserData = user_data;
}

View File

@ -12,10 +12,10 @@ namespace ImGuiFreeType
// When disabled, FreeType generates blurrier glyphs, more or less matches the stb's output. // When disabled, FreeType generates blurrier glyphs, more or less matches the stb's output.
// The Default hinting mode usually looks good, but may distort glyphs in an unusual way. // The Default hinting mode usually looks good, but may distort glyphs in an unusual way.
// The Light hinting mode generates fuzzier glyphs but better matches Microsoft's rasterizer. // The Light hinting mode generates fuzzier glyphs but better matches Microsoft's rasterizer.
// You can set those flags on a per font basis in ImFontConfig::RasterizerFlags. // You can set those flags on a per font basis in ImFontConfig::RasterizerFlags.
// Use the 'extra_flags' parameter of BuildFontAtlas() to force a flag on all your fonts. // Use the 'extra_flags' parameter of BuildFontAtlas() to force a flag on all your fonts.
enum RasterizerFlags enum RasterizerFlags
{ {
// By default, hinting is enabled and the font's native hinter is preferred over the auto-hinter. // By default, hinting is enabled and the font's native hinter is preferred over the auto-hinter.
NoHinting = 1 << 0, // Disable hinting. This generally generates 'blurrier' bitmap glyphs when the glyph are rendered in any of the anti-aliased modes. NoHinting = 1 << 0, // Disable hinting. This generally generates 'blurrier' bitmap glyphs when the glyph are rendered in any of the anti-aliased modes.
@ -28,4 +28,8 @@ namespace ImGuiFreeType
}; };
IMGUI_API bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags = 0); IMGUI_API bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags = 0);
// By default ImGuiFreeType will use ImGui::MemAlloc()/MemFree().
// However, as FreeType does lots of allocations we provide a way for the user to redirect it to a separate memory heap if desired:
IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL);
} }

View File

@ -97,7 +97,7 @@ void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yo
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{ {
if (g_PrevUserCallbackKey != NULL) if (g_PrevUserCallbackKey != NULL)
g_PrevUserCallbackKey(window, key, scancode, action, mods); g_PrevUserCallbackKey(window, key, scancode, action, mods);
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
@ -172,7 +172,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this. g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this.
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this. g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this.
g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR); g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
g_PrevUserCallbackMousebutton = NULL; g_PrevUserCallbackMousebutton = NULL;
g_PrevUserCallbackScroll = NULL; g_PrevUserCallbackScroll = NULL;
@ -265,6 +265,43 @@ static void ImGui_ImplGlfw_UpdateMouseCursor()
} }
} }
static void ImGui_ImplGlfw_UpdateGamepads()
{
ImGuiIO& io = ImGui::GetIO();
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
return;
// Update gamepad inputs
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; }
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; }
int axes_count = 0, buttons_count = 0;
const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A
MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B
MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X
MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y
MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left
MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right
MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up
MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down
MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB
MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB
MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB
MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB
MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f);
MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f);
MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f);
MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f);
#undef MAP_BUTTON
#undef MAP_ANALOG
if (axes_count > 0 && buttons_count > 0)
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
else
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
}
void ImGui_ImplGlfw_NewFrame() void ImGui_ImplGlfw_NewFrame()
{ {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
@ -286,37 +323,6 @@ void ImGui_ImplGlfw_NewFrame()
ImGui_ImplGlfw_UpdateMousePosAndButtons(); ImGui_ImplGlfw_UpdateMousePosAndButtons();
ImGui_ImplGlfw_UpdateMouseCursor(); ImGui_ImplGlfw_UpdateMouseCursor();
// Gamepad navigation mapping [BETA] // Gamepad navigation mapping
memset(io.NavInputs, 0, sizeof(io.NavInputs)); ImGui_ImplGlfw_UpdateGamepads();
if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad)
{
// Update gamepad inputs
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; }
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; }
int axes_count = 0, buttons_count = 0;
const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A
MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B
MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X
MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y
MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left
MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right
MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up
MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down
MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB
MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB
MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB
MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB
MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f);
MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f);
MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f);
MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f);
#undef MAP_BUTTON
#undef MAP_ANALOG
if (axes_count > 0 && buttons_count > 0)
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
else
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
}
} }

View File

@ -11,6 +11,8 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT). // 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT).
// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used. // 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
@ -76,7 +78,7 @@
#include <GLES3/gl3.h> // Use GL ES 3 #include <GLES3/gl3.h> // Use GL ES 3
#else #else
// Regular OpenGL // Regular OpenGL
// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually. // About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually.
// Helper libraries are often used for this purpose! Here we are supporting a few common ones: gl3w, glew, glad. // Helper libraries are often used for this purpose! Here we are supporting a few common ones: gl3w, glew, glad.
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. // You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) #if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
@ -136,12 +138,10 @@ void ImGui_ImplOpenGL3_NewFrame()
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
{ {
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
ImGuiIO& io = ImGui::GetIO(); int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int fb_width = (int)(draw_data->DisplaySize.x * io.DisplayFramebufferScale.x); int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
int fb_height = (int)(draw_data->DisplaySize.y * io.DisplayFramebufferScale.y);
if (fb_width <= 0 || fb_height <= 0) if (fb_width <= 0 || fb_height <= 0)
return; return;
draw_data->ScaleClipRects(io.DisplayFramebufferScale);
// Backup GL state // Backup GL state
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture); GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
@ -219,12 +219,15 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
glVertexAttribPointer(g_AttribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv)); glVertexAttribPointer(g_AttribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv));
glVertexAttribPointer(g_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col)); glVertexAttribPointer(g_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col));
// Draw // Will project scissor/clipping rectangles into framebuffer space
ImVec2 pos = draw_data->DisplayPos; ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++) for (int n = 0; n < draw_data->CmdListsCount; n++)
{ {
const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawList* cmd_list = draw_data->CmdLists[n];
const ImDrawIdx* idx_buffer_offset = 0; size_t idx_buffer_offset = 0;
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW); glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);
@ -242,7 +245,13 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
} }
else else
{ {
ImVec4 clip_rect = ImVec4(pcmd->ClipRect.x - pos.x, pcmd->ClipRect.y - pos.y, pcmd->ClipRect.z - pos.x, pcmd->ClipRect.w - pos.y); // Project scissor/clipping rectangles into framebuffer space
ImVec4 clip_rect;
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
{ {
// Apply scissor/clipping rectangle // Apply scissor/clipping rectangle
@ -253,10 +262,10 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
// Bind texture, Draw // Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)idx_buffer_offset);
} }
} }
idx_buffer_offset += pcmd->ElemCount; idx_buffer_offset += pcmd->ElemCount * sizeof(ImDrawIdx);
} }
} }
glDeleteVertexArrays(1, &vao_handle); glDeleteVertexArrays(1, &vao_handle);
@ -477,7 +486,7 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
vertex_shader = vertex_shader_glsl_120; vertex_shader = vertex_shader_glsl_120;
fragment_shader = fragment_shader_glsl_120; fragment_shader = fragment_shader_glsl_120;
} }
else if (glsl_version == 410) else if (glsl_version >= 410)
{ {
vertex_shader = vertex_shader_glsl_410_core; vertex_shader = vertex_shader_glsl_410_core;
fragment_shader = fragment_shader_glsl_410_core; fragment_shader = fragment_shader_glsl_410_core;

View File

@ -9,9 +9,9 @@
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui // https://github.com/ocornut/imgui
// About OpenGL function loaders: // About OpenGL function loaders:
// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually. // About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually.
// Helper libraries are often used for this purpose! Here we are supporting a few common ones: gl3w, glew, glad. // Helper libraries are often used for this purpose! Here we are supporting a few common ones: gl3w, glew, glad.
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. // You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
// About GLSL version: // About GLSL version: