mirror of
				https://github.com/ocornut/imgui.git
				synced 2025-10-26 12:27:30 +00:00 
			
		
		
		
	Menus: rework to allow for an icon column (not yet exposed, but usable via internals) + fix menus being affected by style.SelectableTextAlign (#126)
This commit is contained in:
		| @@ -53,6 +53,7 @@ Other Changes: | |||||||
| - Tables: Fix invalid data in TableGetSortSpecs() when SpecsDirty flag is unset. (#4233) | - Tables: Fix invalid data in TableGetSortSpecs() when SpecsDirty flag is unset. (#4233) | ||||||
| - TabBar: Fixed using more than 32 KB-worth of tab names. (#4176) | - TabBar: Fixed using more than 32 KB-worth of tab names. (#4176) | ||||||
| - Drag and Drop: drop target highlight doesn't try to bypass host clipping rectangle. (#4281, #3272) | - Drag and Drop: drop target highlight doesn't try to bypass host clipping rectangle. (#4281, #3272) | ||||||
|  | - Menus: MenuItem() and BeginMenu() are not affected/overlapping when style.SelectableTextAlign is altered. | ||||||
| - Fixed printf-style format checks on non-MinGW flavors. (#4183, #3592) | - Fixed printf-style format checks on non-MinGW flavors. (#4183, #3592) | ||||||
| - Fonts: Functions with a 'float size_pixels' parameter can accept zero if it is set in ImFontSize::SizePixels. | - Fonts: Functions with a 'float size_pixels' parameter can accept zero if it is set in ImFontSize::SizePixels. | ||||||
| - Fonts: Prefer using U+FFFD character for fallback instead of '?', if available. (#4269) | - Fonts: Prefer using U+FFFD character for fallback instead of '?', if available. (#4269) | ||||||
|   | |||||||
| @@ -1038,13 +1038,15 @@ struct IMGUI_API ImGuiMenuColumns | |||||||
|     ImU32       TotalWidth; |     ImU32       TotalWidth; | ||||||
|     ImU32       NextTotalWidth; |     ImU32       NextTotalWidth; | ||||||
|     ImU16       Spacing; |     ImU16       Spacing; | ||||||
|     ImU16       OffsetShortcut;     // Offsets are locked in Update() |     ImU16       OffsetIcon;         // Always zero for now | ||||||
|  |     ImU16       OffsetLabel;        // Offsets are locked in Update() | ||||||
|  |     ImU16       OffsetShortcut; | ||||||
|     ImU16       OffsetMark; |     ImU16       OffsetMark; | ||||||
|     ImU16       Widths[3];          // Width of:   Label, Shortcut, Mark (accumulators for current frame) |     ImU16       Widths[4];          // Width of:   Icon, Label, Shortcut, Mark  (accumulators for current frame) | ||||||
|  |  | ||||||
|     ImGuiMenuColumns() { memset(this, 0, sizeof(*this)); } |     ImGuiMenuColumns() { memset(this, 0, sizeof(*this)); } | ||||||
|     void        Update(float spacing, bool window_reappearing); |     void        Update(float spacing, bool window_reappearing); | ||||||
|     float       DeclColumns(float w_label, float w_shortcut, float w_mark); |     float       DeclColumns(float w_icon, float w_label, float w_shortcut, float w_mark); | ||||||
|     void        CalcNextTotalWidth(bool update_offsets); |     void        CalcNextTotalWidth(bool update_offsets); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -2440,6 +2442,9 @@ namespace ImGui | |||||||
|     IMGUI_API ImVec2        FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy); |     IMGUI_API ImVec2        FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy); | ||||||
|     IMGUI_API bool          BeginViewportSideBar(const char* name, ImGuiViewport* viewport, ImGuiDir dir, float size, ImGuiWindowFlags window_flags); |     IMGUI_API bool          BeginViewportSideBar(const char* name, ImGuiViewport* viewport, ImGuiDir dir, float size, ImGuiWindowFlags window_flags); | ||||||
|  |  | ||||||
|  |     // Menus | ||||||
|  |     IMGUI_API bool          MenuItemEx(const char* label, const char* icon, const char* shortcut = NULL, bool selected = false, bool enabled = true); | ||||||
|  |  | ||||||
|     // Combos |     // Combos | ||||||
|     IMGUI_API bool          BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags); |     IMGUI_API bool          BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags); | ||||||
|     IMGUI_API bool          BeginComboPreview(); |     IMGUI_API bool          BeginComboPreview(); | ||||||
|   | |||||||
| @@ -6614,19 +6614,21 @@ void ImGuiMenuColumns::CalcNextTotalWidth(bool update_offsets) | |||||||
|         want_spacing |= (width > 0); |         want_spacing |= (width > 0); | ||||||
|         if (update_offsets) |         if (update_offsets) | ||||||
|         { |         { | ||||||
|             if (i == 1) { OffsetShortcut = offset; } |             if (i == 1) { OffsetLabel = offset; } | ||||||
|             if (i == 2) { OffsetMark = offset; } |             if (i == 2) { OffsetShortcut = offset; } | ||||||
|  |             if (i == 3) { OffsetMark = offset; } | ||||||
|         } |         } | ||||||
|         offset += width; |         offset += width; | ||||||
|     } |     } | ||||||
|     NextTotalWidth = offset; |     NextTotalWidth = offset; | ||||||
| } | } | ||||||
|  |  | ||||||
| float ImGuiMenuColumns::DeclColumns(float w_label, float w_shortcut, float w_mark) | float ImGuiMenuColumns::DeclColumns(float w_icon, float w_label, float w_shortcut, float w_mark) | ||||||
| { | { | ||||||
|     Widths[0] = ImMax(Widths[0], (ImU16)w_label); |     Widths[0] = ImMax(Widths[0], (ImU16)w_icon); | ||||||
|     Widths[1] = ImMax(Widths[1], (ImU16)w_shortcut); |     Widths[1] = ImMax(Widths[1], (ImU16)w_label); | ||||||
|     Widths[2] = ImMax(Widths[2], (ImU16)w_mark); |     Widths[2] = ImMax(Widths[2], (ImU16)w_shortcut); | ||||||
|  |     Widths[3] = ImMax(Widths[3], (ImU16)w_mark); | ||||||
|     CalcNextTotalWidth(false); |     CalcNextTotalWidth(false); | ||||||
|     return (float)ImMax(TotalWidth, NextTotalWidth); |     return (float)ImMax(TotalWidth, NextTotalWidth); | ||||||
| } | } | ||||||
| @@ -6818,6 +6820,10 @@ bool ImGui::BeginMenu(const char* label, bool enabled) | |||||||
|     // However the final position is going to be different! It is chosen by FindBestWindowPosForPopup(). |     // However the final position is going to be different! It is chosen by FindBestWindowPosForPopup(). | ||||||
|     // e.g. Menus tend to overlap each other horizontally to amplify relative Z-ordering. |     // 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; | ||||||
|  |     PushID(label); | ||||||
|  |     if (!enabled) | ||||||
|  |         PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); | ||||||
|  |     const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; | ||||||
|     if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) |     if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) | ||||||
|     { |     { | ||||||
|         // Menu inside an horizontal menu bar |         // Menu inside an horizontal menu bar | ||||||
| @@ -6827,7 +6833,9 @@ bool ImGui::BeginMenu(const char* label, bool enabled) | |||||||
|         window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); |         window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); | ||||||
|         PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); |         PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); | ||||||
|         float w = label_size.x; |         float w = label_size.x; | ||||||
|         pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); |         ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); | ||||||
|  |         pressed = Selectable("", menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); | ||||||
|  |         RenderText(text_pos, label); | ||||||
|         PopStyleVar(); |         PopStyleVar(); | ||||||
|         window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). |         window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). | ||||||
|     } |     } | ||||||
| @@ -6837,12 +6845,18 @@ bool ImGui::BeginMenu(const char* label, bool enabled) | |||||||
|         // (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f. |         // (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f. | ||||||
|         //  Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system. |         //  Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system. | ||||||
|         popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); |         popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); | ||||||
|         float min_w = window->DC.MenuColumns.DeclColumns(label_size.x, 0.0f, IM_FLOOR(g.FontSize * 1.20f)); // Feedback to next frame |         float icon_w = 0.0f; // FIXME: This not currently exposed for BeginMenu() however you can call window->DC.MenuColumns.DeclColumns(w, 0, 0, 0) yourself | ||||||
|  |         float checkmark_w = IM_FLOOR(g.FontSize * 1.20f); | ||||||
|  |         float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame | ||||||
|         float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); |         float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); | ||||||
|         pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_SpanAvailWidth | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(min_w, 0.0f)); |         ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); | ||||||
|         ImU32 text_col = GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled); |         pressed = Selectable("", menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_SpanAvailWidth | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(min_w, 0.0f)); | ||||||
|         RenderArrow(window->DrawList, pos + ImVec2(window->DC.MenuColumns.OffsetMark + extra_w + g.FontSize * 0.30f, 0.0f), text_col, ImGuiDir_Right); |         RenderText(text_pos, label); | ||||||
|  |         RenderArrow(window->DrawList, pos + ImVec2(offsets->OffsetMark + extra_w + g.FontSize * 0.30f, 0.0f), GetColorU32(ImGuiCol_Text), ImGuiDir_Right); | ||||||
|     } |     } | ||||||
|  |     if (!enabled) | ||||||
|  |         PopStyleColor(); | ||||||
|  |     PopID(); | ||||||
|  |  | ||||||
|     const bool hovered = enabled && ItemHoverable(window->DC.LastItemRect, id); |     const bool hovered = enabled && ItemHoverable(window->DC.LastItemRect, id); | ||||||
|     if (menuset_is_open) |     if (menuset_is_open) | ||||||
| @@ -6958,7 +6972,7 @@ void ImGui::EndMenu() | |||||||
|     EndPopup(); |     EndPopup(); | ||||||
| } | } | ||||||
|  |  | ||||||
| bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, bool enabled) | bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut, bool selected, bool enabled) | ||||||
| { | { | ||||||
|     ImGuiWindow* window = GetCurrentWindow(); |     ImGuiWindow* window = GetCurrentWindow(); | ||||||
|     if (window->SkipItems) |     if (window->SkipItems) | ||||||
| @@ -6973,6 +6987,10 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo | |||||||
|     // but I am unsure whether this should be kept at all. For now moved it to be an opt-in feature used by menus only. |     // but I am unsure whether this should be kept at all. For now moved it to be an opt-in feature used by menus only. | ||||||
|     ImGuiSelectableFlags flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_SetNavIdOnHover | (enabled ? 0 : ImGuiSelectableFlags_Disabled); |     ImGuiSelectableFlags flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_SetNavIdOnHover | (enabled ? 0 : ImGuiSelectableFlags_Disabled); | ||||||
|     bool pressed; |     bool pressed; | ||||||
|  |     PushID(label); | ||||||
|  |     if (!enabled) | ||||||
|  |         PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); | ||||||
|  |     const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; | ||||||
|     if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) |     if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) | ||||||
|     { |     { | ||||||
|         // Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful |         // Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful | ||||||
| @@ -6980,8 +6998,9 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo | |||||||
|         float w = label_size.x; |         float w = label_size.x; | ||||||
|         window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); |         window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); | ||||||
|         PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); |         PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); | ||||||
|         pressed = Selectable(label, selected, flags, ImVec2(w, 0.0f)); |         pressed = Selectable("", selected, flags, ImVec2(w, 0.0f)); | ||||||
|         PopStyleVar(); |         PopStyleVar(); | ||||||
|  |         RenderText(pos + ImVec2(offsets->OffsetLabel, 0.0f), label); | ||||||
|         window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). |         window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). | ||||||
|     } |     } | ||||||
|     else |     else | ||||||
| @@ -6989,27 +7008,40 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo | |||||||
|         // Menu item inside a vertical menu |         // Menu item inside a vertical menu | ||||||
|         // (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f. |         // (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f. | ||||||
|         //  Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system. |         //  Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system. | ||||||
|         float shortcut_w = shortcut ? CalcTextSize(shortcut, NULL).x : 0.0f; |         float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f; | ||||||
|         float min_w = window->DC.MenuColumns.DeclColumns(label_size.x, shortcut_w, IM_FLOOR(g.FontSize * 1.20f)); // Feedback for next frame |         float shortcut_w = (shortcut && shortcut[0]) ? CalcTextSize(shortcut, NULL).x : 0.0f; | ||||||
|         float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); |         float checkmark_w = IM_FLOOR(g.FontSize * 1.20f); | ||||||
|         pressed = Selectable(label, false, flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f)); |         float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame | ||||||
|  |         float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); | ||||||
|  |         pressed = Selectable("", false, flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f)); | ||||||
|  |         RenderText(pos + ImVec2(offsets->OffsetLabel, 0.0f), label); | ||||||
|  |         if (icon_w > 0.0f) | ||||||
|  |             RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); | ||||||
|         if (shortcut_w > 0.0f) |         if (shortcut_w > 0.0f) | ||||||
|         { |         { | ||||||
|             PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); |             PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); | ||||||
|             RenderText(pos + ImVec2(window->DC.MenuColumns.OffsetShortcut + extra_w, 0.0f), shortcut, NULL, false); |             RenderText(pos + ImVec2(offsets->OffsetShortcut + stretch_w, 0.0f), shortcut, NULL, false); | ||||||
|             PopStyleColor(); |             PopStyleColor(); | ||||||
|         } |         } | ||||||
|         if (selected) |         if (selected) | ||||||
|             RenderCheckMark(window->DrawList, pos + ImVec2(window->DC.MenuColumns.OffsetMark + extra_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled), g.FontSize  * 0.866f); |             RenderCheckMark(window->DrawList, pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize  * 0.866f); | ||||||
|     } |     } | ||||||
|  |     if (!enabled) | ||||||
|  |         PopStyleColor(); | ||||||
|  |     PopID(); | ||||||
|  |  | ||||||
|     IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.LastItemStatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0)); |     IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.LastItemStatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0)); | ||||||
|     return pressed; |     return pressed; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, bool enabled) | ||||||
|  | { | ||||||
|  |     return MenuItemEx(label, NULL, shortcut, selected, enabled); | ||||||
|  | } | ||||||
|  |  | ||||||
| bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled) | bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled) | ||||||
| { | { | ||||||
|     if (MenuItem(label, shortcut, p_selected ? *p_selected : false, enabled)) |     if (MenuItemEx(label, NULL, shortcut, p_selected ? *p_selected : false, enabled)) | ||||||
|     { |     { | ||||||
|         if (p_selected) |         if (p_selected) | ||||||
|             *p_selected = !*p_selected; |             *p_selected = !*p_selected; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 ocornut
					ocornut