Skip to content

Commit 3d5fde6

Browse files
committed
Demo: added variety of usage scenarios, hooking Alt, Mouse Wheel, Home, CTRL+Tab demos.
(relate to issues: 456, 2637, 2620, 2891, 3370, 3724, 4828, 5108, 5242, 5641)
1 parent 08b0705 commit 3d5fde6

File tree

1 file changed

+243
-0
lines changed

1 file changed

+243
-0
lines changed

imgui_demo.cpp

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8110,6 +8110,249 @@ static void DemoWindowInputs()
81108110
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key, false) ? "PRESSED!" : "..");
81118111
ImGui::TreePop();
81128112
}
8113+
8114+
// Miscellaneous examples
8115+
if (ImGui::TreeNode("Usage Scenarios"))
8116+
{
8117+
// We use colored buttons for the demo but this would generally apply to any widget.
8118+
const ImVec2 button_sz(60.0f, 60.0f);
8119+
const ImGuiColorEditFlags button_flags = ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop;
8120+
8121+
if (ImGui::TreeNode("1. Claiming Mouse Wheel"))
8122+
{
8123+
static float value1 = 0.0f;
8124+
ImGui::Text("%.2f", value1);
8125+
ImGui::SameLine();
8126+
HelpMarker("Hover button and use mouse wheel: window scrolling won't be activated.");
8127+
ImGui::ColorButton("Item1", ImVec4(0.4f, 0.4f, 0.8f, 1.0f), button_flags, button_sz);
8128+
ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY);
8129+
if (ImGui::IsItemHovered() || ImGui::IsItemActive())
8130+
value1 += io.MouseWheel;
8131+
8132+
static float value2 = 0.0f;
8133+
ImGui::Text("%.2f", value2);
8134+
ImGui::SameLine();
8135+
HelpMarker("Hold button and use mouse wheel: window scrolling won't be activated.");
8136+
ImGui::ColorButton("Item2", ImVec4(0.4f, 0.4f, 0.8f, 1.0f), button_flags, button_sz);
8137+
ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY, ImGuiInputFlags_CondActive);
8138+
if (ImGui::IsItemActive())
8139+
value2 += io.MouseWheel;
8140+
8141+
ImGui::TreePop();
8142+
}
8143+
8144+
if (ImGui::TreeNode("2. Claiming Alt key"))
8145+
{
8146+
ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
8147+
8148+
static float spinner0 = 0.0f;
8149+
ImGui::Text("%.3f", spinner0);
8150+
ImGui::SameLine();
8151+
HelpMarker("Click, hold ALT drag to tweak value. Notice that Alt doesn't move focus to menu bar.");
8152+
ImGui::Button("Spin me", button_sz);
8153+
if (ImGui::IsItemActive())
8154+
{
8155+
ImGui::SetKeyOwner(ImGuiMod_Alt, ImGui::GetItemID());
8156+
if (ImGui::IsKeyDown(ImGuiMod_Alt)) // Poll on Active: we don't need to check for ownership of ImGuiMod_Alt since we know we unconditionally own it.
8157+
spinner0 += io.MouseDelta.x;
8158+
}
8159+
8160+
// When using of keys is conditioned by item being hovered or active,
8161+
// it creates a natural exclusivity, since only one item can be hovered or active.
8162+
// SetItemKeyOwner(...) is a shortcut for doing 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(..., GetItemID()); }'
8163+
static int value1 = 0;
8164+
ImGui::Text("%d", value1);
8165+
ImGui::SameLine();
8166+
HelpMarker("Item1 claims ALT key when Hovered or Active, counter increase when pressing ALT while Hovered.");
8167+
ImGui::Button("Item1", button_sz);
8168+
ImGui::SetItemKeyOwner(ImGuiMod_Alt); // Claim Alt on Hover and Active
8169+
if (ImGui::IsItemHovered() && ImGui::IsKeyPressed(ImGuiMod_Alt, false)) // Poll on Hover: we don't need to check for ownership of ImGuiMod_Alt since we know we unconditionally own it.
8170+
value1++;
8171+
8172+
ImGui::TreePop();
8173+
}
8174+
8175+
// Routing options are only available for Shortcuts (not Key)
8176+
// Using shortcut functions with only ImGuiMod_Alt means that other modifiers e.g. CTRL+ALT+S won't be affected, which is often desirable.
8177+
// Here we use ImGuiInputFlags_RouteFocused which will claim the Alt shortcut when the window is focused.
8178+
// Notice that opening this node will claim Alt, therefore change the behavior of the key checks in section (2) above.
8179+
if (ImGui::TreeNode("3. Claiming Alt shortcut"))
8180+
{
8181+
// Using Shortcut() with ImGuiInputFlags_RouteFocused means we react when parent window is focused.
8182+
// - Passing 0 (== ImGuiKeyOwner_Any) means current location will be used to identify.
8183+
// As both calls are from the same location, both items will receive the shortcut.
8184+
// - Passing GetItemID() here means they both have their unique id,
8185+
// - Item2 will only receive the shortcut when parent window is focused.
8186+
// - Item3 will only receive the shortcut when active.
8187+
// Not passing an item id would use current location as id so both items will always receive shortcut.
8188+
static bool use_shared_owner = false;
8189+
ImGui::Checkbox("Item2 and Item3 use same owner/location", &use_shared_owner);
8190+
static int value2 = 0;
8191+
ImGui::Text("%d", value2);
8192+
ImGui::SameLine();
8193+
HelpMarker("Item2 reads ALT shortcut when its parent window is focused.");
8194+
ImGui::Button("Item2", button_sz);
8195+
if (ImGui::Shortcut(ImGuiMod_Alt, 0, use_shared_owner ? 0 : ImGui::GetItemID()))
8196+
value2++;
8197+
8198+
static int value3 = 0;
8199+
ImGui::Text("%d", value3);
8200+
ImGui::SameLine();
8201+
HelpMarker("Item3 reads ALT shortcut when its parent window is focused AND it is active. Therefore, only active previous button will get the shortcut");
8202+
ImGui::Button("Item3", button_sz);
8203+
if (ImGui::Shortcut(ImGuiMod_Alt, 0, use_shared_owner ? 0 : ImGui::GetItemID()))
8204+
value3++;
8205+
8206+
ImGui::TreePop();
8207+
}
8208+
8209+
if (ImGui::TreeNode("4. Claiming Home key globally"))
8210+
{
8211+
static bool enable_home_robbery = false;
8212+
static int home_presses = 0;
8213+
ImGui::Checkbox("Global steal ImGuiKey_Home", &enable_home_robbery);
8214+
ImGui::Text("Home presses: %d", home_presses);
8215+
if (enable_home_robbery)
8216+
{
8217+
// Claim ownership is enough to keep Key away from main library behavior or any owner-aware code.
8218+
// - We optionally use the ImGuiInputFlags_LockUntilRelease to keep key away from code that is not owner-aware,
8219+
// but Dear ImGui itself is so that's not technically needed (unless you are stealing from another piece of code).
8220+
ImGuiID robber_id = ImGui::GetID("Some Identifier");
8221+
ImGui::SetKeyOwner(ImGuiKey_Home, robber_id, ImGuiInputFlags_LockUntilRelease);
8222+
if (ImGui::IsKeyPressed(ImGuiKey_Home, ImGuiInputFlags_Repeat, robber_id)) // We unconditionally own the key so no need to test for ownership
8223+
home_presses++;
8224+
}
8225+
ImGui::TreePop();
8226+
}
8227+
8228+
if (ImGui::TreeNode("5. Claiming CTRL+A shortcut globally"))
8229+
{
8230+
// Using a priority of ImGuiInputFlags_RouteGlobal + RouteOverActive means we takes away even from an active item (e.g. InputText)
8231+
// This is better covered in "Shortcut Routing basics" above.
8232+
static bool enable_ctrl_a_robbery = false;
8233+
static int ctrl_a_presses = 0;
8234+
ImGui::Checkbox("Global steal CTRL+A", &enable_ctrl_a_robbery);
8235+
ImGui::Text("CTRL+A presses: %d", ctrl_a_presses);
8236+
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_A, enable_ctrl_a_robbery ? ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive : ImGuiInputFlags_RouteAlways))
8237+
ctrl_a_presses++;
8238+
8239+
ImGui::TreePop();
8240+
}
8241+
8242+
if (ImGui::TreeNode("6. Disable ESC key from InputText()"))
8243+
{
8244+
static char buf[9];
8245+
ImGui::InputText("Text", buf, IM_ARRAYSIZE(buf));
8246+
8247+
// - If you don't need to use the key, you can use 'owner_id=0', 'flags=ImGuiInputFlags_LockXXX'
8248+
// as a convenience to hide the key from everyone.
8249+
// - If you need to use the key yourself, you need to use any arbitrary ID, and then use this ID to read the key.
8250+
// e.g. ImGui::SetKeyOwner(ImGuiKey_Escape, ImGui::GetID("robber")); + later use same ID to access the key.
8251+
if (ImGui::IsItemActive())
8252+
ImGui::SetKeyOwner(ImGuiKey_Escape, 0, ImGuiInputFlags_LockUntilRelease);
8253+
ImGui::TreePop();
8254+
}
8255+
8256+
if (ImGui::TreeNode("7. Claiming ESC key away from InputText()"))
8257+
{
8258+
static char buf[9];
8259+
ImGui::InputText("Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_EscapeClearsAll);
8260+
if (ImGui::IsItemActive())
8261+
{
8262+
// Using a route which is higher priority than one claimed the ActiveId
8263+
ImGuiID robber_id = ImGui::GetID("robber");
8264+
if (ImGui::Shortcut(ImGuiKey_Escape, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive, robber_id))
8265+
{
8266+
strcpy(buf, "Esc!");
8267+
ImGui::ClearActiveID();
8268+
}
8269+
}
8270+
ImGui::TreePop();
8271+
}
8272+
8273+
if (ImGui::TreeNode("8. Claiming ESC away from nav logic (e.g. exiting a child)"))
8274+
{
8275+
ImGui::BeginChild("child", ImVec2(-FLT_MIN, 50), true);
8276+
ImGui::Button("Button in child");
8277+
if (ImGui::IsWindowFocused())
8278+
ImGui::SetKeyOwner(ImGuiKey_Escape, ImGui::GetID("")); // any id
8279+
ImGui::EndChild();
8280+
8281+
ImGui::TreePop();
8282+
}
8283+
8284+
if (ImGui::TreeNode("9. Claiming Tab, CTRL+Tab"))
8285+
{
8286+
static int mode = 0;
8287+
static int counter = 0;
8288+
8289+
HelpMarker("Showcasing many variants as a recap.\nPlease read code and comments carefully!");
8290+
8291+
const char* mode_names[] = { "None", "Disable Tab key (item)", "Disable Tab key (global)", "Disable CTRL+Tab (global)", "Disable CTRL+Tab (if focused)", "Read CTRL+Tab (global)", "Replace CTRL+Tab (global)", "Replace CTRL+Tab (if focused)" };
8292+
ImGui::Combo("Operation Mode", &mode, mode_names, IM_ARRAYSIZE(mode_names));
8293+
ImGui::Text("Counter = %d", counter);
8294+
8295+
switch (mode)
8296+
{
8297+
case 1:
8298+
// Item take ownership of Tab key when hovered/active (meaning ALL uses of Tab will be disabled, not just CTRL+Tab)
8299+
ImGui::Button("This Button Steals The Tab Key");
8300+
ImGui::SetItemKeyOwner(ImGuiKey_Tab);
8301+
ImGui::SameLine();
8302+
HelpMarker("While hovering or activating this button, TAB key is stolen (e.g. won't tab out into other systems)");
8303+
break;
8304+
case 2:
8305+
// Take ownership of Tab key (meaning ALL uses of Tab will be disabled, not just CTRL+Tab)
8306+
ImGui::SetKeyOwner(ImGuiKey_Tab, ImGui::GetID("some-id"));
8307+
break;
8308+
case 3:
8309+
// Disable CTRL+Tab shortcuts (global): assign an owner to steal the route to our two shortcuts
8310+
ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiKey_Tab, 0, ImGui::GetID("some-id"));
8311+
ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab, 0, ImGui::GetID("some-id"));
8312+
break;
8313+
case 4:
8314+
// Disable CTRL+Tab shortcuts (if focused): assign an owner to steal the route to our two shortcuts, applies focus testing so will only apply if window is in focus chain
8315+
ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiKey_Tab, ImGuiInputFlags_RouteFocused, ImGui::GetID("some-id"));
8316+
ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab, ImGuiInputFlags_RouteFocused, ImGui::GetID("some-id"));
8317+
break;
8318+
case 5:
8319+
// Read CTRL+Tab (global): reading keys without interfering with any behaviors (need to specify ImGuiInputFlags_RouteAlways as other policies will interfere)
8320+
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_Tab, ImGuiInputFlags_RouteAlways, ImGuiKeyOwner_Any))
8321+
counter++;
8322+
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab, ImGuiInputFlags_RouteAlways, ImGuiKeyOwner_Any))
8323+
counter--;
8324+
break;
8325+
case 6:
8326+
{
8327+
// Replace CTRL+Tab (global)
8328+
// - We steal the route and assign it to our ID (so core system won't access it). Our reading queries now need to specify that ID.
8329+
ImGuiID id = ImGui::GetID("My-Ctrl-Tab-Handler");
8330+
//ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiKey_Tab, id, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive);
8331+
//ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab, id, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive);
8332+
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_Tab, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive, id))
8333+
counter++; // You could perform some other action here.
8334+
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive, id))
8335+
counter--;
8336+
break;
8337+
}
8338+
case 7:
8339+
// Replace CTRL+Tab (if focused)
8340+
// - Passing ImGuiInputFlags_RouteFocused will test for focus and assign a route using a default owner id based on location (so we can use 0 as id)
8341+
// - This would also work if we replaced 0 with ImGui::GetID("My-Ctrl-Tab-Handler")
8342+
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_Tab))
8343+
counter++; // You could perform some other action here.
8344+
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab))
8345+
counter--;
8346+
break;
8347+
}
8348+
8349+
static char buf[8] = "";
8350+
ImGui::InputTextWithHint("Dummy", "(dummy input text to test effect of Tabbing)", buf, IM_ARRAYSIZE(buf));
8351+
8352+
ImGui::TreePop();
8353+
}
8354+
ImGui::TreePop();
8355+
}
81138356
ImGui::TreePop();
81148357
}
81158358

0 commit comments

Comments
 (0)