mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-30 20:51:06 +01:00 
			
		
		
		
	Refactor: Moved Tree/Selectable functions from imgui.cpp to imgui_widgets.cpp (#2036)
This commit is contained in:
		
							
								
								
									
										481
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										481
									
								
								imgui.cpp
									
									
									
									
									
								
							| @@ -7945,341 +7945,6 @@ void ImGui::LogButtons() | ||||
|         LogToClipboard(g.LogAutoExpandMaxDepth); | ||||
| } | ||||
|  | ||||
| bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags) | ||||
| { | ||||
|     if (flags & ImGuiTreeNodeFlags_Leaf) | ||||
|         return true; | ||||
|  | ||||
|     // We only write to the tree storage if the user clicks (or explicitly use SetNextTreeNode*** functions) | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     ImGuiWindow* window = g.CurrentWindow; | ||||
|     ImGuiStorage* storage = window->DC.StateStorage; | ||||
|  | ||||
|     bool is_open; | ||||
|     if (g.NextTreeNodeOpenCond != 0) | ||||
|     { | ||||
|         if (g.NextTreeNodeOpenCond & ImGuiCond_Always) | ||||
|         { | ||||
|             is_open = g.NextTreeNodeOpenVal; | ||||
|             storage->SetInt(id, is_open); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             // We treat ImGuiCond_Once and ImGuiCond_FirstUseEver the same because tree node state are not saved persistently. | ||||
|             const int stored_value = storage->GetInt(id, -1); | ||||
|             if (stored_value == -1) | ||||
|             { | ||||
|                 is_open = g.NextTreeNodeOpenVal; | ||||
|                 storage->SetInt(id, is_open); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 is_open = stored_value != 0; | ||||
|             } | ||||
|         } | ||||
|         g.NextTreeNodeOpenCond = 0; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         is_open = storage->GetInt(id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0; | ||||
|     } | ||||
|  | ||||
|     // When logging is enabled, we automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behavior). | ||||
|     // NB- If we are above max depth we still allow manually opened nodes to be logged. | ||||
|     if (g.LogEnabled && !(flags & ImGuiTreeNodeFlags_NoAutoOpenOnLog) && window->DC.TreeDepth < g.LogAutoExpandMaxDepth) | ||||
|         is_open = true; | ||||
|  | ||||
|     return is_open; | ||||
| } | ||||
|  | ||||
| bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindow(); | ||||
|     if (window->SkipItems) | ||||
|         return false; | ||||
|  | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     const ImGuiStyle& style = g.Style; | ||||
|     const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0; | ||||
|     const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, 0.0f); | ||||
|  | ||||
|     if (!label_end) | ||||
|         label_end = FindRenderedTextEnd(label); | ||||
|     const ImVec2 label_size = CalcTextSize(label, label_end, false); | ||||
|  | ||||
|     // We vertically grow up to current line height up the typical widget height. | ||||
|     const float text_base_offset_y = ImMax(padding.y, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it | ||||
|     const float frame_height = ImMax(ImMin(window->DC.CurrentLineSize.y, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2); | ||||
|     ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(window->Pos.x + GetContentRegionMax().x, window->DC.CursorPos.y + frame_height)); | ||||
|     if (display_frame) | ||||
|     { | ||||
|         // Framed header expand a little outside the default padding | ||||
|         frame_bb.Min.x -= (float)(int)(window->WindowPadding.x*0.5f) - 1; | ||||
|         frame_bb.Max.x += (float)(int)(window->WindowPadding.x*0.5f) - 1; | ||||
|     } | ||||
|  | ||||
|     const float text_offset_x = (g.FontSize + (display_frame ? padding.x*3 : padding.x*2));   // Collapser arrow width + Spacing | ||||
|     const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x*2 : 0.0f);   // Include collapser | ||||
|     ItemSize(ImVec2(text_width, frame_height), text_base_offset_y); | ||||
|  | ||||
|     // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing | ||||
|     // (Ideally we'd want to add a flag for the user to specify if we want the hit test to be done up to the right side of the content or not) | ||||
|     const ImRect interact_bb = display_frame ? frame_bb : ImRect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + text_width + style.ItemSpacing.x*2, frame_bb.Max.y); | ||||
|     bool is_open = TreeNodeBehaviorIsOpen(id, flags); | ||||
|  | ||||
|     // Store a flag for the current depth to tell if we will allow closing this node when navigating one of its child. | ||||
|     // For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop(). | ||||
|     // This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero. | ||||
|     if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) | ||||
|         window->DC.TreeDepthMayJumpToParentOnPop |= (1 << window->DC.TreeDepth); | ||||
|  | ||||
|     bool item_add = ItemAdd(interact_bb, id); | ||||
|     window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; | ||||
|     window->DC.LastItemDisplayRect = frame_bb; | ||||
|  | ||||
|     if (!item_add) | ||||
|     { | ||||
|         if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) | ||||
|             TreePushRawID(id); | ||||
|         return is_open; | ||||
|     } | ||||
|  | ||||
|     // Flags that affects opening behavior: | ||||
|     // - 0(default) ..................... single-click anywhere to open | ||||
|     // - OpenOnDoubleClick .............. double-click anywhere to open | ||||
|     // - OpenOnArrow .................... single-click on arrow to open | ||||
|     // - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open | ||||
|     ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers | ((flags & ImGuiTreeNodeFlags_AllowItemOverlap) ? ImGuiButtonFlags_AllowItemOverlap : 0); | ||||
|     if (!(flags & ImGuiTreeNodeFlags_Leaf)) | ||||
|         button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; | ||||
|     if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) | ||||
|         button_flags |= ImGuiButtonFlags_PressedOnDoubleClick | ((flags & ImGuiTreeNodeFlags_OpenOnArrow) ? ImGuiButtonFlags_PressedOnClickRelease : 0); | ||||
|  | ||||
|     bool hovered, held, pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags); | ||||
|     if (!(flags & ImGuiTreeNodeFlags_Leaf)) | ||||
|     { | ||||
|         bool toggled = false; | ||||
|         if (pressed) | ||||
|         { | ||||
|             toggled = !(flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) || (g.NavActivateId == id); | ||||
|             if (flags & ImGuiTreeNodeFlags_OpenOnArrow) | ||||
|                 toggled |= IsMouseHoveringRect(interact_bb.Min, ImVec2(interact_bb.Min.x + text_offset_x, interact_bb.Max.y)) && (!g.NavDisableMouseHover); | ||||
|             if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) | ||||
|                 toggled |= g.IO.MouseDoubleClicked[0]; | ||||
|             if (g.DragDropActive && is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again. | ||||
|                 toggled = false; | ||||
|         } | ||||
|  | ||||
|         if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Left && is_open) | ||||
|         { | ||||
|             toggled = true; | ||||
|             NavMoveRequestCancel(); | ||||
|         } | ||||
|         if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority? | ||||
|         { | ||||
|             toggled = true; | ||||
|             NavMoveRequestCancel(); | ||||
|         } | ||||
|  | ||||
|         if (toggled) | ||||
|         { | ||||
|             is_open = !is_open; | ||||
|             window->DC.StateStorage->SetInt(id, is_open); | ||||
|         } | ||||
|     } | ||||
|     if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) | ||||
|         SetItemAllowOverlap(); | ||||
|  | ||||
|     // Render | ||||
|     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); | ||||
|     if (display_frame) | ||||
|     { | ||||
|         // Framed type | ||||
|         RenderFrame(frame_bb.Min, frame_bb.Max, col, true, style.FrameRounding); | ||||
|         RenderNavHighlight(frame_bb, id, ImGuiNavHighlightFlags_TypeThin); | ||||
|         RenderArrow(frame_bb.Min + ImVec2(padding.x, text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 1.0f); | ||||
|         if (g.LogEnabled) | ||||
|         { | ||||
|             // NB: '##' is normally used to hide text (as a library-wide feature), so we need to specify the text range to make sure the ## aren't stripped out here. | ||||
|             const char log_prefix[] = "\n##"; | ||||
|             const char log_suffix[] = "##"; | ||||
|             LogRenderedText(&text_pos, log_prefix, log_prefix+3); | ||||
|             RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); | ||||
|             LogRenderedText(&text_pos, log_suffix+1, log_suffix+3); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // Unframed typed for tree nodes | ||||
|         if (hovered || (flags & ImGuiTreeNodeFlags_Selected)) | ||||
|         { | ||||
|             RenderFrame(frame_bb.Min, frame_bb.Max, col, false); | ||||
|             RenderNavHighlight(frame_bb, id, ImGuiNavHighlightFlags_TypeThin); | ||||
|         } | ||||
|  | ||||
|         if (flags & ImGuiTreeNodeFlags_Bullet) | ||||
|             RenderBullet(frame_bb.Min + ImVec2(text_offset_x * 0.5f, g.FontSize*0.50f + text_base_offset_y)); | ||||
|         else if (!(flags & ImGuiTreeNodeFlags_Leaf)) | ||||
|             RenderArrow(frame_bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f); | ||||
|         if (g.LogEnabled) | ||||
|             LogRenderedText(&text_pos, ">"); | ||||
|         RenderText(text_pos, label, label_end, false); | ||||
|     } | ||||
|  | ||||
|     if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) | ||||
|         TreePushRawID(id); | ||||
|     return is_open; | ||||
| } | ||||
|  | ||||
| // CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag). | ||||
| // This is basically the same as calling TreeNodeEx(label, ImGuiTreeNodeFlags_CollapsingHeader). You can remove the _NoTreePushOnOpen flag if you want behavior closer to normal TreeNode(). | ||||
| bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindow(); | ||||
|     if (window->SkipItems) | ||||
|         return false; | ||||
|  | ||||
|     return TreeNodeBehavior(window->GetID(label), flags | ImGuiTreeNodeFlags_CollapsingHeader, label); | ||||
| } | ||||
|  | ||||
| bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindow(); | ||||
|     if (window->SkipItems) | ||||
|         return false; | ||||
|  | ||||
|     if (p_open && !*p_open) | ||||
|         return false; | ||||
|  | ||||
|     ImGuiID id = window->GetID(label); | ||||
|     bool is_open = TreeNodeBehavior(id, flags | ImGuiTreeNodeFlags_CollapsingHeader | (p_open ? ImGuiTreeNodeFlags_AllowItemOverlap : 0), label); | ||||
|     if (p_open) | ||||
|     { | ||||
|         // Create a small overlapping close button // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc. | ||||
|         ImGuiContext& g = *GImGui; | ||||
|         ImGuiItemHoveredDataBackup last_item_backup; | ||||
|         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); | ||||
|         if (CloseButton(window->GetID((void*)(intptr_t)(id+1)), button_center, button_radius)) | ||||
|             *p_open = false; | ||||
|         last_item_backup.Restore(); | ||||
|     } | ||||
|  | ||||
|     return is_open; | ||||
| } | ||||
|  | ||||
| bool ImGui::TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindow(); | ||||
|     if (window->SkipItems) | ||||
|         return false; | ||||
|  | ||||
|     return TreeNodeBehavior(window->GetID(label), flags, label, NULL); | ||||
| } | ||||
|  | ||||
| bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindow(); | ||||
|     if (window->SkipItems) | ||||
|         return false; | ||||
|  | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); | ||||
|     return TreeNodeBehavior(window->GetID(str_id), flags, g.TempBuffer, label_end); | ||||
| } | ||||
|  | ||||
| bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindow(); | ||||
|     if (window->SkipItems) | ||||
|         return false; | ||||
|  | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); | ||||
|     return TreeNodeBehavior(window->GetID(ptr_id), flags, g.TempBuffer, label_end); | ||||
| } | ||||
|  | ||||
| bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args) | ||||
| { | ||||
|     return TreeNodeExV(str_id, 0, fmt, args); | ||||
| } | ||||
|  | ||||
| bool ImGui::TreeNodeV(const void* ptr_id, const char* fmt, va_list args) | ||||
| { | ||||
|     return TreeNodeExV(ptr_id, 0, fmt, args); | ||||
| } | ||||
|  | ||||
| bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) | ||||
| { | ||||
|     va_list args; | ||||
|     va_start(args, fmt); | ||||
|     bool is_open = TreeNodeExV(str_id, flags, fmt, args); | ||||
|     va_end(args); | ||||
|     return is_open; | ||||
| } | ||||
|  | ||||
| bool ImGui::TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) | ||||
| { | ||||
|     va_list args; | ||||
|     va_start(args, fmt); | ||||
|     bool is_open = TreeNodeExV(ptr_id, flags, fmt, args); | ||||
|     va_end(args); | ||||
|     return is_open; | ||||
| } | ||||
|  | ||||
| bool ImGui::TreeNode(const char* str_id, const char* fmt, ...) | ||||
| { | ||||
|     va_list args; | ||||
|     va_start(args, fmt); | ||||
|     bool is_open = TreeNodeExV(str_id, 0, fmt, args); | ||||
|     va_end(args); | ||||
|     return is_open; | ||||
| } | ||||
|  | ||||
| bool ImGui::TreeNode(const void* ptr_id, const char* fmt, ...) | ||||
| { | ||||
|     va_list args; | ||||
|     va_start(args, fmt); | ||||
|     bool is_open = TreeNodeExV(ptr_id, 0, fmt, args); | ||||
|     va_end(args); | ||||
|     return is_open; | ||||
| } | ||||
|  | ||||
| bool ImGui::TreeNode(const char* label) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindow(); | ||||
|     if (window->SkipItems) | ||||
|         return false; | ||||
|     return TreeNodeBehavior(window->GetID(label), 0, label, NULL); | ||||
| } | ||||
|  | ||||
| void ImGui::TreeAdvanceToLabelPos() | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     g.CurrentWindow->DC.CursorPos.x += GetTreeNodeToLabelSpacing(); | ||||
| } | ||||
|  | ||||
| // Horizontal distance preceding label when using TreeNode() or Bullet() | ||||
| float ImGui::GetTreeNodeToLabelSpacing() | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     return g.FontSize + (g.Style.FramePadding.x * 2.0f); | ||||
| } | ||||
|  | ||||
| void ImGui::SetNextTreeNodeOpen(bool is_open, ImGuiCond cond) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     if (g.CurrentWindow->SkipItems) | ||||
|         return; | ||||
|     g.NextTreeNodeOpenVal = is_open; | ||||
|     g.NextTreeNodeOpenCond = cond ? cond : ImGuiCond_Always; | ||||
| } | ||||
|  | ||||
| void ImGui::PushID(const char* str_id) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindowRead(); | ||||
| @@ -10540,109 +10205,6 @@ bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags extra_fla | ||||
|     return InputScalarN(label, ImGuiDataType_S32, v, 4, NULL, NULL, "%d", extra_flags); | ||||
| } | ||||
|  | ||||
| // Tip: pass an empty label (e.g. "##dummy") then you can use the space to draw other text or image. | ||||
| // But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID or use ##unique_id. | ||||
| bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindow(); | ||||
|     if (window->SkipItems) | ||||
|         return false; | ||||
|  | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     const ImGuiStyle& style = g.Style; | ||||
|  | ||||
|     if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet) // FIXME-OPT: Avoid if vertically clipped. | ||||
|         PopClipRect(); | ||||
|  | ||||
|     ImGuiID id = window->GetID(label); | ||||
|     ImVec2 label_size = CalcTextSize(label, NULL, true); | ||||
|     ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y); | ||||
|     ImVec2 pos = window->DC.CursorPos; | ||||
|     pos.y += window->DC.CurrentLineTextBaseOffset; | ||||
|     ImRect bb_inner(pos, pos + size); | ||||
|     ItemSize(bb_inner); | ||||
|  | ||||
|     // Fill horizontal space. | ||||
|     ImVec2 window_padding = window->WindowPadding; | ||||
|     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); | ||||
|     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); | ||||
|     if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_DrawFillAvailWidth)) | ||||
|         bb.Max.x += window_padding.x; | ||||
|  | ||||
|     // Selectables are tightly packed together, we extend the box to cover spacing between selectable. | ||||
|     float spacing_L = (float)(int)(style.ItemSpacing.x * 0.5f); | ||||
|     float spacing_U = (float)(int)(style.ItemSpacing.y * 0.5f); | ||||
|     float spacing_R = style.ItemSpacing.x - spacing_L; | ||||
|     float spacing_D = style.ItemSpacing.y - spacing_U; | ||||
|     bb.Min.x -= spacing_L; | ||||
|     bb.Min.y -= spacing_U; | ||||
|     bb.Max.x += spacing_R; | ||||
|     bb.Max.y += spacing_D; | ||||
|     if (!ItemAdd(bb, (flags & ImGuiSelectableFlags_Disabled) ? 0 : id)) | ||||
|     { | ||||
|         if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet) | ||||
|             PushColumnClipRect(); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // We use NoHoldingActiveID on menus so user can click and _hold_ on a menu then drag to browse child entries | ||||
|     ImGuiButtonFlags button_flags = 0; | ||||
|     if (flags & ImGuiSelectableFlags_NoHoldingActiveID) button_flags |= ImGuiButtonFlags_NoHoldingActiveID; | ||||
|     if (flags & ImGuiSelectableFlags_PressedOnClick) button_flags |= ImGuiButtonFlags_PressedOnClick; | ||||
|     if (flags & ImGuiSelectableFlags_PressedOnRelease) button_flags |= ImGuiButtonFlags_PressedOnRelease; | ||||
|     if (flags & ImGuiSelectableFlags_Disabled) button_flags |= ImGuiButtonFlags_Disabled; | ||||
|     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) | ||||
|         selected = false; | ||||
|  | ||||
|     // 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 (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) | ||||
|         { | ||||
|             g.NavDisableHighlight = true; | ||||
|             SetNavID(id, window->DC.NavLayerCurrent); | ||||
|         } | ||||
|     if (pressed) | ||||
|         MarkItemEdited(id); | ||||
|  | ||||
|     // Render | ||||
|     if (hovered || selected) | ||||
|     { | ||||
|         const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); | ||||
|         RenderFrame(bb.Min, bb.Max, col, false, 0.0f); | ||||
|         RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); | ||||
|     } | ||||
|  | ||||
|     if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet) | ||||
|     { | ||||
|         PushColumnClipRect(); | ||||
|         bb.Max.x -= (GetContentRegionMax().x - max_x); | ||||
|     } | ||||
|  | ||||
|     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)); | ||||
|     if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor(); | ||||
|  | ||||
|     // Automatically close popups | ||||
|     if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(window->DC.ItemFlags & ImGuiItemFlags_SelectableDontClosePopup)) | ||||
|         CloseCurrentPopup(); | ||||
|     return pressed; | ||||
| } | ||||
|  | ||||
| bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) | ||||
| { | ||||
|     if (Selectable(label, *p_selected, flags, size_arg)) | ||||
|     { | ||||
|         *p_selected = !*p_selected; | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| // Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. | ||||
| void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags) | ||||
| { | ||||
| @@ -12026,49 +11588,6 @@ void ImGui::Unindent(float indent_w) | ||||
|     window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; | ||||
| } | ||||
|  | ||||
| void ImGui::TreePush(const char* str_id) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindow(); | ||||
|     Indent(); | ||||
|     window->DC.TreeDepth++; | ||||
|     PushID(str_id ? str_id : "#TreePush"); | ||||
| } | ||||
|  | ||||
| void ImGui::TreePush(const void* ptr_id) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindow(); | ||||
|     Indent(); | ||||
|     window->DC.TreeDepth++; | ||||
|     PushID(ptr_id ? ptr_id : (const void*)"#TreePush"); | ||||
| } | ||||
|  | ||||
| void ImGui::TreePushRawID(ImGuiID id) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindow(); | ||||
|     Indent(); | ||||
|     window->DC.TreeDepth++; | ||||
|     window->IDStack.push_back(id); | ||||
| } | ||||
|  | ||||
| void ImGui::TreePop() | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     ImGuiWindow* window = g.CurrentWindow; | ||||
|     Unindent(); | ||||
|  | ||||
|     window->DC.TreeDepth--; | ||||
|     if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) | ||||
|         if (g.NavIdIsAlive && (window->DC.TreeDepthMayJumpToParentOnPop & (1 << window->DC.TreeDepth))) | ||||
|         { | ||||
|             SetNavID(window->IDStack.back(), g.NavLayer); | ||||
|             NavMoveRequestCancel(); | ||||
|         } | ||||
|     window->DC.TreeDepthMayJumpToParentOnPop &= (1 << window->DC.TreeDepth) - 1; | ||||
|  | ||||
|     IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much. | ||||
|     PopID(); | ||||
| } | ||||
|  | ||||
| //----------------------------------------------------------------------------- | ||||
| // DRAG AND DROP | ||||
| //----------------------------------------------------------------------------- | ||||
|   | ||||
		Reference in New Issue
	
	Block a user