Add minimize/maximize window flags

TODO: actual work of rendering window
This commit is contained in:
Andersama 2024-09-06 08:51:26 -07:00
parent a2366f9022
commit dd15544751
4 changed files with 143 additions and 0 deletions

View File

@ -6470,6 +6470,8 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
const bool has_close_button = (p_open != NULL); const bool has_close_button = (p_open != NULL);
const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None); const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None);
const bool has_minimize_button = flags & ImGuiWindowFlags_Minimize;
const bool has_maximize_button = flags & ImGuiWindowFlags_Maximize;
// Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer) // Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer)
// FIXME-NAV: Might want (or not?) to set the equivalent of ImGuiButtonFlags_NoNavFocus so that mouse clicks on standard title bar items don't necessarily set nav/keyboard ref? // FIXME-NAV: Might want (or not?) to set the equivalent of ImGuiButtonFlags_NoNavFocus so that mouse clicks on standard title bar items don't necessarily set nav/keyboard ref?
@ -6483,12 +6485,24 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
float pad_r = style.FramePadding.x; float pad_r = style.FramePadding.x;
float button_sz = g.FontSize; float button_sz = g.FontSize;
ImVec2 close_button_pos; ImVec2 close_button_pos;
ImVec2 minimize_button_pos;
ImVec2 maximize_button_pos;
ImVec2 collapse_button_pos; ImVec2 collapse_button_pos;
if (has_close_button) if (has_close_button)
{ {
close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y); close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y);
pad_r += button_sz + style.ItemInnerSpacing.x; pad_r += button_sz + style.ItemInnerSpacing.x;
} }
if (has_maximize)
{
maximize_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y);
pad_r += button_sz + style.ItemInnerSpacing.x;
}
if (has_minimize)
{
minimize_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y);
pad_r += button_sz + style.ItemInnerSpacing.x;
}
if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right) if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right)
{ {
collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y); collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y);
@ -6510,6 +6524,20 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
if (CloseButton(window->GetID("#CLOSE"), close_button_pos)) if (CloseButton(window->GetID("#CLOSE"), close_button_pos))
*p_open = false; *p_open = false;
// Maximize button
if (has_maximize_button) {
if (CloseButton(window->GetID("#MAXIMIZE"), maximize_button_pos, window->Maximized)) {
window->WantMaximizeToggle = true;
}
}
// Minimize button
if (has_minimize_button) {
if (CloseButton(window->GetID("#MINIMIZE"), minimize_button_pos, window->Minimized)) {
window->WantMinimizeToggle = true;
}
}
window->DC.NavLayerCurrent = ImGuiNavLayer_Main; window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
g.CurrentItemFlags = item_flags_backup; g.CurrentItemFlags = item_flags_backup;
@ -6924,6 +6952,26 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
} }
window->WantCollapseToggle = false; window->WantCollapseToggle = false;
if (flags & ImGuiWindowFlags_Maximize) {
if (window->WantMaximizeToggle) {
window->Maximized = !window->Maximized;
MarkIniSettingsDirty(window);
}
} else {
window->Maximized = false;
}
window->WantMaximizeToggle = false;
if (flags & ImGuiWindowFlags_Minimize) {
if (window->WantMinimizeToggle) {
window->Minimized = !window->Minimized;
MarkIniSettingsDirty(window);
}
} else {
window->Minimized = false;
}
window->WantMinimizeToggle = false;
// SIZE // SIZE
// Outer Decoration Sizes // Outer Decoration Sizes
@ -8033,6 +8081,18 @@ bool ImGui::IsWindowCollapsed()
return window->Collapsed; return window->Collapsed;
} }
bool ImGui::IsWindowMinimized()
{
ImGuiWindow* window = GetCurrentWindowRead();
return window->Minimized;
}
bool ImGui::IsWindowMaximized()
{
ImGuiWindow* window = GetCurrentWindowRead();
return window->Maximized;
}
bool ImGui::IsWindowAppearing() bool ImGui::IsWindowAppearing()
{ {
ImGuiWindow* window = GetCurrentWindowRead(); ImGuiWindow* window = GetCurrentWindowRead();

View File

@ -392,6 +392,8 @@ namespace ImGui
// - 'current window' = the window we are appending into while inside a Begin()/End() block. 'next window' = next window we will Begin() into. // - 'current window' = the window we are appending into while inside a Begin()/End() block. 'next window' = next window we will Begin() into.
IMGUI_API bool IsWindowAppearing(); IMGUI_API bool IsWindowAppearing();
IMGUI_API bool IsWindowCollapsed(); IMGUI_API bool IsWindowCollapsed();
IMGUI_API bool IsWindowMinimized();
IMGUI_API bool IsWindowMaximized();
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 hoverable (e.g. not blocked by a popup/modal)? See ImGuiHoveredFlags_ for options. IMPORTANT: If you are trying to check whether your mouse should be dispatched to Dear ImGui or to your underlying app, you should not use this function! Use the 'io.WantCaptureMouse' boolean for that! Refer to FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" for details. IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered and hoverable (e.g. not blocked by a popup/modal)? See ImGuiHoveredFlags_ for options. IMPORTANT: If you are trying to check whether your mouse should be dispatched to Dear ImGui or to your underlying app, you should not use this function! Use the 'io.WantCaptureMouse' boolean for that! Refer to FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" for details.
IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives
@ -1079,6 +1081,9 @@ enum ImGuiWindowFlags_
ImGuiWindowFlags_NoNavInputs = 1 << 16, // No gamepad/keyboard navigation within the window ImGuiWindowFlags_NoNavInputs = 1 << 16, // No gamepad/keyboard navigation within the window
ImGuiWindowFlags_NoNavFocus = 1 << 17, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB) ImGuiWindowFlags_NoNavFocus = 1 << 17, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB)
ImGuiWindowFlags_UnsavedDocument = 1 << 18, // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. ImGuiWindowFlags_UnsavedDocument = 1 << 18, // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar.
ImGuiWindowFlags_Minimize = 1 << 19, // Enable minimize button
ImGuiWindowFlags_Maximize = 1 << 20, // Enable maximize and restore button
ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse,
ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,

View File

@ -2639,6 +2639,10 @@ struct IMGUI_API ImGuiWindow
bool WriteAccessed; // Set to true when any widget access the current window bool WriteAccessed; // Set to true when any widget access the current window
bool Collapsed; // Set when collapsing window to become only title-bar bool Collapsed; // Set when collapsing window to become only title-bar
bool WantCollapseToggle; bool WantCollapseToggle;
bool Minimized;
bool WantMinimizeToggle;
bool Maximized;
bool WantMaximizeToggle;
bool SkipItems; // Set when items can safely be all clipped (e.g. window not visible or collapsed) bool SkipItems; // Set when items can safely be all clipped (e.g. window not visible or collapsed)
bool SkipRefresh; // [EXPERIMENTAL] Reuse previous frame drawn contents, Begin() returns false. bool SkipRefresh; // [EXPERIMENTAL] Reuse previous frame drawn contents, Begin() returns false.
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)
@ -3545,6 +3549,8 @@ namespace ImGui
// Widgets: Window Decorations // Widgets: Window Decorations
IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos); IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos);
IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos); IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos);
IMGUI_API bool MinimizeButton(ImGuiID id, const ImVec2& pos, bool minimized);
IMGUI_API bool MaximizeButton(ImGuiID id, const ImVec2& pos, bool maximized);
IMGUI_API void Scrollbar(ImGuiAxis axis); IMGUI_API void Scrollbar(ImGuiAxis axis);
IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 avail_v, ImS64 contents_v, ImDrawFlags flags); IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 avail_v, ImS64 contents_v, ImDrawFlags flags);
IMGUI_API ImRect GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis); IMGUI_API ImRect GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis);

View File

@ -863,6 +863,78 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos)
return pressed; return pressed;
} }
// Button to close a window
bool ImGui::MinimizeButton(ImGuiID id, const ImVec2& pos, bool minimized)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
// Tweak 1: Shrink hit-testing area if button covers an abnormally large proportion of the visible region. That's in order to facilitate moving the window away. (#3825)
// This may better be applied as a general hit-rect reduction mechanism for all widgets to ensure the area to move window is always accessible?
const ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize));
ImRect bb_interact = bb;
const float area_to_visible_ratio = window->OuterRectClipped.GetArea() / bb.GetArea();
if (area_to_visible_ratio < 1.5f)
bb_interact.Expand(ImTrunc(bb_interact.GetSize() * -0.25f));
// Tweak 2: We intentionally allow interaction when clipped so that a mechanical Alt,Right,Activate sequence can always close a window.
// (this isn't the common behavior of buttons, but it doesn't affect the user because navigation tends to keep items visible in scrolling layer).
bool is_clipped = !ItemAdd(bb_interact, id);
bool hovered, held;
bool pressed = ButtonBehavior(bb_interact, id, &hovered, &held);
if (is_clipped)
return pressed;
// Render
ImU32 bg_col = GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered);
if (hovered)
window->DrawList->AddRectFilled(bb.Min, bb.Max, bg_col);
RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_Compact);
ImU32 cross_col = GetColorU32(ImGuiCol_Text);
ImVec2 cross_center = bb.GetCenter() - ImVec2(0.5f, 0.5f);
float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f;
window->DrawList->AddLine(cross_center + ImVec2(+cross_extent, 0.0f), cross_center + ImVec2(-cross_extent, 0.0f), cross_col, 1.0f);
return pressed;
}
// Button to close a window
bool ImGui::MaximizeButton(ImGuiID id, const ImVec2& pos, bool maximized)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
// Tweak 1: Shrink hit-testing area if button covers an abnormally large proportion of the visible region. That's in order to facilitate moving the window away. (#3825)
// This may better be applied as a general hit-rect reduction mechanism for all widgets to ensure the area to move window is always accessible?
const ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize));
ImRect bb_interact = bb;
const float area_to_visible_ratio = window->OuterRectClipped.GetArea() / bb.GetArea();
if (area_to_visible_ratio < 1.5f)
bb_interact.Expand(ImTrunc(bb_interact.GetSize() * -0.25f));
// Tweak 2: We intentionally allow interaction when clipped so that a mechanical Alt,Right,Activate sequence can always close a window.
// (this isn't the common behavior of buttons, but it doesn't affect the user because navigation tends to keep items visible in scrolling layer).
bool is_clipped = !ItemAdd(bb_interact, id);
bool hovered, held;
bool pressed = ButtonBehavior(bb_interact, id, &hovered, &held);
if (is_clipped)
return pressed;
// Render
ImU32 bg_col = GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered);
if (hovered)
window->DrawList->AddRectFilled(bb.Min, bb.Max, bg_col);
RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_Compact);
ImU32 cross_col = GetColorU32(ImGuiCol_Text);
ImVec2 cross_center = bb.GetCenter() - ImVec2(0.5f, 0.5f);
float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f;
window->DrawList->AddRect(cross_center + ImVec2(-cross_extent, -cross_extent), cross_center + ImVec2( + cross_extent, + cross_extent), cross_col, 0.0f, 0, 1.0f);
return pressed;
}
bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;