1
0
Fork 0
mirror of https://github.com/ocornut/imgui.git synced 2026-02-01 03:30:06 +00:00

Merge branch 'master' into docking

This commit is contained in:
ocornut 2024-05-24 16:08:37 +02:00
commit fee0210592
6 changed files with 263 additions and 165 deletions

View file

@ -6260,12 +6260,14 @@ static void ShowDemoWindowInputs()
// Display inputs submitted to ImGuiIO
IMGUI_DEMO_MARKER("Inputs & Focus/Inputs");
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
if (ImGui::TreeNode("Inputs"))
bool inputs_opened = ImGui::TreeNode("Inputs");
ImGui::SameLine();
HelpMarker(
"This is a simplified view. See more detailed input state:\n"
"- in 'Tools->Metrics/Debugger->Inputs'.\n"
"- in 'Tools->Debug Log->IO'.");
if (inputs_opened)
{
HelpMarker(
"This is a simplified view. See more detailed input state:\n"
"- in 'Tools->Metrics/Debugger->Inputs'.\n"
"- in 'Tools->Debug Log->IO'.");
if (ImGui::IsMousePosValid())
ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
else
@ -6296,15 +6298,17 @@ static void ShowDemoWindowInputs()
// Display ImGuiIO output flags
IMGUI_DEMO_MARKER("Inputs & Focus/Outputs");
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
if (ImGui::TreeNode("Outputs"))
bool outputs_opened = ImGui::TreeNode("Outputs");
ImGui::SameLine();
HelpMarker(
"The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui "
"to instruct your application of how to route inputs. Typically, when a value is true, it means "
"Dear ImGui wants the corresponding inputs and we expect the underlying application to ignore them.\n\n"
"The most typical case is: when hovering a window, Dear ImGui set io.WantCaptureMouse to true, "
"and underlying application should ignore mouse inputs (in practice there are many and more subtle "
"rules leading to how those flags are set).");
if (outputs_opened)
{
HelpMarker(
"The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui "
"to instruct your application of how to route inputs. Typically, when a value is true, it means "
"Dear ImGui wants the corresponding inputs and we expect the underlying application to ignore them.\n\n"
"The most typical case is: when hovering a window, Dear ImGui set io.WantCaptureMouse to true, "
"and underlying application should ignore mouse inputs (in practice there are many and more subtle "
"rules leading to how those flags are set).");
ImGui::Text("io.WantCaptureMouse: %d", io.WantCaptureMouse);
ImGui::Text("io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose);
ImGui::Text("io.WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
@ -6351,27 +6355,42 @@ static void ShowDemoWindowInputs()
IMGUI_DEMO_MARKER("Inputs & Focus/Shortcuts");
if (ImGui::TreeNode("Shortcuts"))
{
static ImGuiInputFlags route_options = ImGuiInputFlags_Repeat;
static ImGuiInputFlags route_type = ImGuiInputFlags_RouteFocused;
ImGui::CheckboxFlags("ImGuiInputFlags_Repeat", &route_options, ImGuiInputFlags_Repeat);
ImGui::RadioButton("ImGuiInputFlags_RouteActive", &route_type, ImGuiInputFlags_RouteActive);
ImGui::RadioButton("ImGuiInputFlags_RouteFocused (default)", &route_type, ImGuiInputFlags_RouteFocused);
ImGui::RadioButton("ImGuiInputFlags_RouteGlobal", &route_type, ImGuiInputFlags_RouteGlobal);
ImGui::Indent();
ImGui::BeginDisabled(route_type != ImGuiInputFlags_RouteGlobal);
ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverFocused", &route_options, ImGuiInputFlags_RouteOverFocused);
ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverActive", &route_options, ImGuiInputFlags_RouteOverActive);
ImGui::CheckboxFlags("ImGuiInputFlags_RouteUnlessBgFocused", &route_options, ImGuiInputFlags_RouteUnlessBgFocused);
ImGui::EndDisabled();
ImGui::Unindent();
ImGui::RadioButton("ImGuiInputFlags_RouteAlways", &route_type, ImGuiInputFlags_RouteAlways);
ImGuiInputFlags flags = route_type | route_options; // Merged flags
if (route_type != ImGuiInputFlags_RouteGlobal)
route_options &= ~(ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive | ImGuiInputFlags_RouteUnlessBgFocused);
ImGui::SeparatorText("Using SetNextItemShortcut()");
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S);
ImGui::Text("Ctrl+S");
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, flags | ImGuiInputFlags_Tooltip);
ImGui::Button("Save");
ImGui::SetItemTooltip("Ctrl+S"); // FIXME: Tooltip could be automatically submitted by SetNextItemShortcut
ImGui::Text("Alt+F");
ImGui::SetNextItemShortcut(ImGuiMod_Alt | ImGuiKey_F, flags | ImGuiInputFlags_Tooltip);
static float f = 0.5f;
ImGui::SliderFloat("Factor", &f, 0.0f, 1.0f);
ImGui::SeparatorText("Using Shortcut()");
const float line_height = ImGui::GetTextLineHeightWithSpacing();
const ImGuiKeyChord key_chord = ImGuiMod_Ctrl | ImGuiKey_A;
static ImGuiInputFlags other_flags = ImGuiInputFlags_Repeat;
static ImGuiInputFlags routing_flags = ImGuiInputFlags_RouteFocused;
ImGui::CheckboxFlags("ImGuiInputFlags_Repeat", &other_flags, ImGuiInputFlags_Repeat);
ImGui::RadioButton("ImGuiInputFlags_RouteFocused (default)", &routing_flags, ImGuiInputFlags_RouteFocused);
ImGui::RadioButton("ImGuiInputFlags_RouteAlways", &routing_flags, ImGuiInputFlags_RouteAlways);
ImGui::RadioButton("ImGuiInputFlags_RouteGlobal", &routing_flags, ImGuiInputFlags_RouteGlobal);
ImGui::RadioButton("ImGuiInputFlags_RouteGlobalOverFocused", &routing_flags, ImGuiInputFlags_RouteGlobalOverFocused);
ImGui::RadioButton("ImGuiInputFlags_RouteGlobalHighest", &routing_flags, ImGuiInputFlags_RouteGlobalHighest);
ImGui::CheckboxFlags("ImGuiInputFlags_RouteUnlessBgFocused", &other_flags, ImGuiInputFlags_RouteUnlessBgFocused);
const ImGuiInputFlags flags = other_flags | routing_flags; // Merged flags
ImGui::Text("Ctrl+A");
ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 0.0f, 1.0f, 0.1f));
ImGui::BeginChild("WindowA", ImVec2(-FLT_MIN, line_height * 14), true);
ImGui::Text("Press CTRL+A and see who receives it!");
ImGui::Separator();
@ -6414,6 +6433,7 @@ static void ShowDemoWindowInputs()
ImGui::EndPopup();
}
ImGui::EndChild();
ImGui::PopStyleColor();
ImGui::TreePop();
}
@ -8640,51 +8660,85 @@ void ShowExampleAppDockSpace(bool* p_open)
// Simplified structure to mimic a Document model
struct MyDocument
{
const char* Name; // Document title
char Name[32]; // Document title
int UID; // Unique ID (necessary as we can change title)
bool Open; // Set when open (we keep an array of all available documents to simplify demo code!)
bool OpenPrev; // Copy of Open from last update.
bool Dirty; // Set when the document has been modified
bool WantClose; // Set when 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(int uid, const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f))
{
Name = name;
UID = uid;
snprintf(Name, sizeof(Name), "%s", name);
Open = OpenPrev = open;
Dirty = false;
WantClose = false;
Color = color;
}
void DoOpen() { Open = true; }
void DoQueueClose() { WantClose = true; }
void DoForceClose() { Open = false; Dirty = false; }
void DoSave() { Dirty = false; }
};
struct ExampleAppDocuments
{
ImVector<MyDocument> Documents;
ImVector<MyDocument*> CloseQueue;
MyDocument* RenamingDoc = NULL;
bool RenamingStarted = false;
ExampleAppDocuments()
{
Documents.push_back(MyDocument(0, "Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f)));
Documents.push_back(MyDocument(1, "Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
Documents.push_back(MyDocument(2, "Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
Documents.push_back(MyDocument(3, "Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
Documents.push_back(MyDocument(4, "A Rather Long Title", false, ImVec4(0.4f, 0.8f, 0.8f, 1.0f)));
Documents.push_back(MyDocument(5, "Some Document", false, ImVec4(0.8f, 0.8f, 1.0f, 1.0f)));
}
// As we allow to change document name, we append a never-changing document ID so tabs are stable
void GetTabName(MyDocument* doc, char* out_buf, size_t out_buf_size)
{
snprintf(out_buf, out_buf_size, "%s###doc%d", doc->Name, doc->UID);
}
// Display placeholder contents for the Document
static void DisplayContents(MyDocument* doc)
void DisplayDocContents(MyDocument* doc)
{
ImGui::PushID(doc);
ImGui::Text("Document \"%s\"", doc->Name);
ImGui::PushStyleColor(ImGuiCol_Text, doc->Color);
ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
ImGui::PopStyleColor();
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_R, ImGuiInputFlags_Tooltip);
if (ImGui::Button("Rename.."))
{
RenamingDoc = doc;
RenamingStarted = true;
}
ImGui::SameLine();
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_M, ImGuiInputFlags_Tooltip);
if (ImGui::Button("Modify"))
doc->Dirty = true;
ImGui::SameLine();
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, ImGuiInputFlags_Tooltip);
if (ImGui::Button("Save"))
doc->DoSave();
ImGui::SameLine();
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_W, ImGuiInputFlags_Tooltip);
if (ImGui::Button("Close"))
doc->DoQueueClose();
CloseQueue.push_back(doc);
ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior.
ImGui::PopID();
}
// Display context menu for the Document
static void DisplayContextMenu(MyDocument* doc)
void DisplayDocContextMenu(MyDocument* doc)
{
if (!ImGui::BeginPopupContextItem())
return;
@ -8693,45 +8747,32 @@ struct MyDocument
sprintf(buf, "Save %s", doc->Name);
if (ImGui::MenuItem(buf, "Ctrl+S", false, doc->Open))
doc->DoSave();
if (ImGui::MenuItem("Rename...", "Ctrl+R", false, doc->Open))
RenamingDoc = doc;
if (ImGui::MenuItem("Close", "Ctrl+W", false, doc->Open))
doc->DoQueueClose();
CloseQueue.push_back(doc);
ImGui::EndPopup();
}
};
struct ExampleAppDocuments
{
ImVector<MyDocument> Documents;
ExampleAppDocuments()
// [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 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 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.
// Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
void NotifyOfDocumentsClosedElsewhere()
{
Documents.push_back(MyDocument("Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f)));
Documents.push_back(MyDocument("Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
Documents.push_back(MyDocument("Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
Documents.push_back(MyDocument("Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
Documents.push_back(MyDocument("A Rather Long Title", false));
Documents.push_back(MyDocument("Some Document", false));
for (MyDocument& doc : Documents)
{
if (!doc.Open && doc.OpenPrev)
ImGui::SetTabItemClosed(doc.Name);
doc.OpenPrev = doc.Open;
}
}
};
// [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 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 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.
// Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app)
{
for (MyDocument& doc : app.Documents)
{
if (!doc.Open && doc.OpenPrev)
ImGui::SetTabItemClosed(doc.Name);
doc.OpenPrev = doc.Open;
}
}
void ShowExampleAppDocuments(bool* p_open)
{
static ExampleAppDocuments app;
@ -8779,7 +8820,7 @@ void ShowExampleAppDocuments(bool* p_open)
}
if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0))
for (MyDocument& doc : app.Documents)
doc.DoQueueClose();
app.CloseQueue.push_back(&doc);
if (ImGui::MenuItem("Exit") && p_open)
*p_open = false;
ImGui::EndMenu();
@ -8825,7 +8866,7 @@ void ShowExampleAppDocuments(bool* p_open)
if (ImGui::BeginTabBar("##tabs", tab_bar_flags))
{
if (opt_reorderable)
NotifyOfDocumentsClosedElsewhere(app);
app.NotifyOfDocumentsClosedElsewhere();
// [DEBUG] Stress tests
//if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on.
@ -8837,20 +8878,23 @@ void ShowExampleAppDocuments(bool* p_open)
if (!doc.Open)
continue;
// As we allow to change document name, we append a never-changing document id so tabs are stable
char doc_name_buf[64];
app.GetTabName(&doc, doc_name_buf, sizeof(doc_name_buf));
ImGuiTabItemFlags tab_flags = (doc.Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0);
bool visible = ImGui::BeginTabItem(doc.Name, &doc.Open, tab_flags);
bool visible = ImGui::BeginTabItem(doc_name_buf, &doc.Open, tab_flags);
// Cancel attempt to close when unsaved add to save queue so we can display a popup.
if (!doc.Open && doc.Dirty)
{
doc.Open = true;
doc.DoQueueClose();
app.CloseQueue.push_back(&doc);
}
MyDocument::DisplayContextMenu(&doc);
app.DisplayDocContextMenu(&doc);
if (visible)
{
MyDocument::DisplayContents(&doc);
app.DisplayDocContents(&doc);
ImGui::EndTabItem();
}
}
@ -8862,7 +8906,7 @@ void ShowExampleAppDocuments(bool* p_open)
{
if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable)
{
NotifyOfDocumentsClosedElsewhere(app);
app.NotifyOfDocumentsClosedElsewhere();
// Create a DockSpace node where any window can be docked
ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
@ -8883,12 +8927,12 @@ void ShowExampleAppDocuments(bool* p_open)
if (!doc->Open && doc->Dirty)
{
doc->Open = true;
doc->DoQueueClose();
app.CloseQueue.push_back(doc);
}
MyDocument::DisplayContextMenu(doc);
app.DisplayDocContextMenu(doc);
if (visible)
MyDocument::DisplayContents(doc);
app.DisplayDocContents(doc);
ImGui::End();
}
@ -8906,33 +8950,44 @@ void ShowExampleAppDocuments(bool* p_open)
return;
}
// Update closing queue
static ImVector<MyDocument*> close_queue;
if (close_queue.empty())
// Display renaming UI
if (app.RenamingDoc != NULL)
{
// Close queue is locked once we started a popup
for (MyDocument& doc : app.Documents)
if (doc.WantClose)
if (app.RenamingStarted)
ImGui::OpenPopup("Rename");
if (ImGui::BeginPopup("Rename"))
{
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 30);
if (ImGui::InputText("###Name", app.RenamingDoc->Name, IM_ARRAYSIZE(app.RenamingDoc->Name), ImGuiInputTextFlags_EnterReturnsTrue))
{
doc.WantClose = false;
close_queue.push_back(&doc);
ImGui::CloseCurrentPopup();
app.RenamingDoc = NULL;
}
if (app.RenamingStarted)
ImGui::SetKeyboardFocusHere(-1);
ImGui::EndPopup();
}
else
{
app.RenamingDoc = NULL;
}
app.RenamingStarted = false;
}
// Display closing confirmation UI
if (!close_queue.empty())
if (!app.CloseQueue.empty())
{
int close_queue_unsaved_documents = 0;
for (int n = 0; n < close_queue.Size; n++)
if (close_queue[n]->Dirty)
for (int n = 0; n < app.CloseQueue.Size; n++)
if (app.CloseQueue[n]->Dirty)
close_queue_unsaved_documents++;
if (close_queue_unsaved_documents == 0)
{
// Close documents when all are unsaved
for (int n = 0; n < close_queue.Size; n++)
close_queue[n]->DoForceClose();
close_queue.clear();
for (int n = 0; n < app.CloseQueue.Size; n++)
app.CloseQueue[n]->DoForceClose();
app.CloseQueue.clear();
}
else
{
@ -8943,37 +8998,35 @@ void ShowExampleAppDocuments(bool* p_open)
ImGui::Text("Save change to the following items?");
float item_height = ImGui::GetTextLineHeightWithSpacing();
if (ImGui::BeginChild(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height), ImGuiChildFlags_FrameStyle))
{
for (int n = 0; n < close_queue.Size; n++)
if (close_queue[n]->Dirty)
ImGui::Text("%s", close_queue[n]->Name);
}
for (MyDocument* doc : app.CloseQueue)
if (doc->Dirty)
ImGui::Text("%s", doc->Name);
ImGui::EndChild();
ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f);
if (ImGui::Button("Yes", button_size))
{
for (int n = 0; n < close_queue.Size; n++)
for (MyDocument* doc : app.CloseQueue)
{
if (close_queue[n]->Dirty)
close_queue[n]->DoSave();
close_queue[n]->DoForceClose();
if (doc->Dirty)
doc->DoSave();
doc->DoForceClose();
}
close_queue.clear();
app.CloseQueue.clear();
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("No", button_size))
{
for (int n = 0; n < close_queue.Size; n++)
close_queue[n]->DoForceClose();
close_queue.clear();
for (MyDocument* doc : app.CloseQueue)
doc->DoForceClose();
app.CloseQueue.clear();
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("Cancel", button_size))
{
close_queue.clear();
app.CloseQueue.clear();
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();