mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-17 18:37:07 +02:00
Launcher: controller reaches every panel; pad pointer without cursor warps
- Settings' and Mods' rails, pages and lists are NavFlattened children, so the D-pad crosses between them instead of treating each as one item that only B could leave. - The pad's pointer no longer moves the system cursor. Under Proton that move came back late as a mouse move and dropped the pointer; now a mouse move counts only when it lands somewhere new. - The first R3 only shows the pointer, so a stray click does not press whatever the mouse last rested on.
This commit is contained in:
1 parent
360338e6e1
commit
8c7c30e3bb
7 files changed
+96
-73
No files matched your search
@@ -31,12 +31,11 @@ struct Seen {
|
||||
|
||||
// One launcher frame: the pad goes in before NewFrame, as gui.cpp does it.
|
||||
// Two buttons stacked at the top left, and a menu popup opened on request.
|
||||
Seen frame(PadFeed& feed, const PadState& pad, bool open_menu = false, std::optional<ImVec2>* warp = nullptr) {
|
||||
Seen frame(PadFeed& feed, const PadState& pad, bool open_menu = false, bool panels = false) {
|
||||
auto& io = ImGui::GetIO();
|
||||
io.DisplaySize = ImVec2(800, 600);
|
||||
io.DeltaTime = 1.0f / 60.0f;
|
||||
const auto moved = feed.update(io, pad, 1.0f);
|
||||
if (warp) *warp = moved;
|
||||
feed.update(io, pad, 1.0f);
|
||||
ImGui::NewFrame();
|
||||
Seen seen;
|
||||
ImGui::SetNextWindowPos(ImVec2(0, 0));
|
||||
@@ -46,6 +45,17 @@ Seen frame(PadFeed& feed, const PadState& pad, bool open_menu = false, std::opti
|
||||
if (ImGui::InvisibleButton("first", ImVec2(200, 50), ImGuiButtonFlags_EnableNav)) seen.pressed = "first";
|
||||
ImGui::SetCursorScreenPos(ImVec2(100, 200));
|
||||
if (ImGui::InvisibleButton("second", ImVec2(200, 50), ImGuiButtonFlags_EnableNav)) seen.pressed = "second";
|
||||
if (panels) {
|
||||
// A page's rail and content, side by side, as Settings and Mods lay them out.
|
||||
ImGui::SetCursorScreenPos(ImVec2(400, 200));
|
||||
ImGui::BeginChild("##rail", ImVec2(150, 200), ImGuiChildFlags_NavFlattened);
|
||||
if (ImGui::Button("tab", ImVec2(120, 40))) seen.pressed = "tab";
|
||||
ImGui::EndChild();
|
||||
ImGui::SetCursorScreenPos(ImVec2(580, 200));
|
||||
ImGui::BeginChild("##content", ImVec2(200, 200), ImGuiChildFlags_NavFlattened);
|
||||
if (ImGui::Button("option", ImVec2(120, 40))) seen.pressed = "option";
|
||||
ImGui::EndChild();
|
||||
}
|
||||
if (open_menu) ImGui::OpenPopup("##menu");
|
||||
if (ImGui::BeginPopup("##menu")) {
|
||||
seen.menu_open = true;
|
||||
@@ -145,38 +155,55 @@ int main() {
|
||||
check(ImGui::IsKeyDown(ImGuiKey_Escape), "An idle pad does not let go of the keyboard's Escape");
|
||||
}
|
||||
|
||||
{
|
||||
fresh();
|
||||
PadFeed feed;
|
||||
constexpr std::uint16_t dpad_right = 0x0008;
|
||||
for (int i = 0; i < 2; ++i) frame(feed, pad(), false, true);
|
||||
const auto tap = [&](std::uint16_t button) { frame(feed, pad(button), false, true); frame(feed, pad(), false, true); };
|
||||
tap(dpad_down); // onto "first"
|
||||
tap(dpad_down); // "second", level with the panels
|
||||
tap(dpad_right); // the rail
|
||||
tap(dpad_right); // the content
|
||||
std::string pressed = frame(feed, pad(button_a), false, true).pressed;
|
||||
const auto released = frame(feed, pad(), false, true).pressed;
|
||||
check((pressed.empty() ? released : pressed) == "option",
|
||||
"The D-pad crosses from a page's rail into its content");
|
||||
}
|
||||
|
||||
// ------------------------------------------------ trackpad pointer
|
||||
{
|
||||
fresh();
|
||||
PadFeed feed;
|
||||
ImGui::GetIO().AddMousePosEvent(400, 300);
|
||||
auto& io = ImGui::GetIO();
|
||||
io.AddMousePosEvent(400, 300);
|
||||
feed.mouse_moved(ImVec2(400, 300));
|
||||
frame(feed, pad());
|
||||
std::optional<ImVec2> warp;
|
||||
frame(feed, pad(0, 3000, 0), false, &warp);
|
||||
check(!warp && !feed.pointing(), "A thumb resting near the middle does not move the pointer");
|
||||
frame(feed, pad(0, 3000, 0));
|
||||
check(!feed.pointing() && io.MousePos.x == 400, "A thumb resting near the middle does not move the pointer");
|
||||
|
||||
frame(feed, pad(0, 16000, 0), false, &warp);
|
||||
check(feed.pointing() && ImGui::GetIO().MouseDrawCursor, "Tilting takes the pointer and draws it");
|
||||
check(warp && warp->x > 400 && warp->y == 300, "Tilting right moves the pointer right, from the mouse's place");
|
||||
for (int i = 0; i < 120; ++i) frame(feed, pad(0, 32767, 32767), false, &warp);
|
||||
check(warp && warp->x == 799 && warp->y == 0, "The pointer stays inside the window");
|
||||
frame(feed, pad(0, 16000, 0));
|
||||
frame(feed, pad());
|
||||
check(ImGui::GetIO().MousePos.x == 799 && ImGui::GetIO().MousePos.y == 0, "ImGui's mouse is where the pad left it");
|
||||
check(feed.pointing() && io.MouseDrawCursor, "Tilting takes the pointer and draws it");
|
||||
check(io.MousePos.x > 400 && io.MousePos.y == 300, "Tilting right moves the pointer right, from the mouse's place");
|
||||
for (int i = 0; i < 120; ++i) frame(feed, pad(0, 32767, 32767));
|
||||
frame(feed, pad());
|
||||
check(io.MousePos.x == 799 && io.MousePos.y == 0, "The pointer stays inside the window");
|
||||
|
||||
// The system cursor reporting a stale place (Proton, gamescope) does not take the pointer back.
|
||||
ImGui::GetIO().AddMousePosEvent(10, 10);
|
||||
frame(feed, pad(), false, &warp);
|
||||
// The system cursor stays where the mouse left it, and is reported every frame.
|
||||
io.AddMousePosEvent(400, 300);
|
||||
frame(feed, pad());
|
||||
check(!warp && ImGui::GetIO().MousePos.x == 799, "Without tilt the pointer stays put");
|
||||
frame(feed, pad());
|
||||
check(io.MousePos.x == 799, "The system cursor's old place does not take the pointer back");
|
||||
feed.mouse_moved(ImVec2(400, 300)); // the same place, repeated by Windows
|
||||
check(feed.pointing(), "A mouse move repeated in the same place keeps the pointer");
|
||||
|
||||
feed.mouse_moved(ImVec2(799, 0)); // the echo of our own cursor move
|
||||
check(feed.pointing(), "The echo of our own cursor move keeps the pointer");
|
||||
feed.mouse_moved(ImVec2(50, 60)); // the mouse, or a finger on the screen
|
||||
ImGui::GetIO().AddMousePosEvent(50, 60);
|
||||
feed.mouse_moved(ImVec2(50, 60)); // the mouse, or a finger on the screen
|
||||
io.AddMousePosEvent(50, 60);
|
||||
frame(feed, pad());
|
||||
frame(feed, pad());
|
||||
check(!feed.pointing() && !ImGui::GetIO().MouseDrawCursor, "The mouse takes the pointer back");
|
||||
check(ImGui::GetIO().MousePos.x == 50, "The mouse's place wins once it moved");
|
||||
check(!feed.pointing() && !io.MouseDrawCursor, "The mouse takes the pointer back");
|
||||
check(io.MousePos.x == 50, "The mouse's place wins once it moved");
|
||||
}
|
||||
{
|
||||
fresh();
|
||||
@@ -185,14 +212,15 @@ int main() {
|
||||
frame(feed, pad());
|
||||
frame(feed, pad());
|
||||
std::string pressed = frame(feed, pad(right_thumb)).pressed;
|
||||
check(ImGui::GetIO().MouseDown[0], "The trackpad's click (R3) holds the left button");
|
||||
const auto released = frame(feed, pad()).pressed;
|
||||
if (pressed.empty()) pressed = released;
|
||||
pressed += frame(feed, pad()).pressed;
|
||||
check(feed.pointing() && pressed.empty() && !ImGui::GetIO().MouseDown[0],
|
||||
"The first trackpad click (R3) only shows the pointer");
|
||||
pressed = frame(feed, pad(right_thumb)).pressed;
|
||||
check(ImGui::GetIO().MouseDown[0], "The next click holds the left button");
|
||||
pressed += frame(feed, pad()).pressed;
|
||||
check(pressed == "second", "The trackpad's click presses what the pointer is over");
|
||||
check(!ImGui::GetIO().MouseDown[0], "Letting go of R3 lets go of the left button");
|
||||
|
||||
frame(feed, pad(0, 20000, 0));
|
||||
check(feed.pointing(), "The pointer is the pad's");
|
||||
press(feed, dpad_down);
|
||||
check(!feed.pointing() && ImGui::GetIO().NavVisible, "The D-pad hands the screen back to the focus");
|
||||
}
|
||||
|
||||
+16
-19
@@ -29,8 +29,7 @@ constexpr float left_dead_zone = 7849.0f / 32767.0f;
|
||||
constexpr float right_dead_zone = 0.2f;
|
||||
// Pointer speed at full tilt, in design pixels a second.
|
||||
constexpr float pointer_speed = 1400.0f;
|
||||
// A mouse move this close to the pad's pointer is the echo of moving the
|
||||
// system cursor there; one further away is the mouse or a finger.
|
||||
// A mouse move this close to the last one is the same place reported again.
|
||||
constexpr float pointer_slack = 2.0f;
|
||||
|
||||
float axis(std::int16_t value) { return std::clamp(static_cast<float>(value) / 32767.0f, -1.0f, 1.0f); }
|
||||
@@ -52,13 +51,13 @@ bool imgui_cancels() {
|
||||
return top && !(top->Flags & ImGuiWindowFlags_Modal);
|
||||
}
|
||||
|
||||
bool moved_away(ImVec2 position, ImVec2 pointer) {
|
||||
return std::abs(position.x - pointer.x) > pointer_slack || std::abs(position.y - pointer.y) > pointer_slack;
|
||||
bool moved_away(ImVec2 position, ImVec2 before) {
|
||||
return std::abs(position.x - before.x) > pointer_slack || std::abs(position.y - before.y) > pointer_slack;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::optional<ImVec2> PadFeed::update(ImGuiIO& io, const PadState& input, float scale) {
|
||||
void PadFeed::update(ImGuiIO& io, const PadState& input, float scale) {
|
||||
// A pad that went away lets go of everything it held.
|
||||
const PadState pad = input.connected ? input : PadState{};
|
||||
const auto changed = static_cast<std::uint16_t>(pad.buttons ^ buttons_);
|
||||
@@ -90,12 +89,13 @@ std::optional<ImVec2> PadFeed::update(ImGuiIO& io, const PadState& input, float
|
||||
if ((pressed & focus_bits) || std::abs(left_x) > left_dead_zone || std::abs(left_y) > left_dead_zone)
|
||||
pointing_ = false;
|
||||
|
||||
bool warp = false;
|
||||
const float x = axis(pad.right_x), y = -axis(pad.right_y); // screen Y grows downward
|
||||
const float tilt = std::min(1.0f, std::sqrt(x * x + y * y));
|
||||
// The first R3 only shows the pointer: a stray click must not press
|
||||
// whatever the mouse last rested on.
|
||||
const bool click = pointing_ && (pressed & right_thumb);
|
||||
if (!pointing_ && (tilt > right_dead_zone || (pressed & right_thumb))) {
|
||||
pointing_ = true;
|
||||
warp = true;
|
||||
// From wherever the mouse left it, which may be outside the window.
|
||||
pointer_ = ImGui::IsMousePosValid(&io.MousePos) ? io.MousePos
|
||||
: ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f);
|
||||
@@ -107,31 +107,28 @@ std::optional<ImVec2> PadFeed::update(ImGuiIO& io, const PadState& input, float
|
||||
const float step = speed * speed * pointer_speed * scale * io.DeltaTime / tilt;
|
||||
pointer_.x += x * step;
|
||||
pointer_.y += y * step;
|
||||
warp = true;
|
||||
}
|
||||
if (pointing_) {
|
||||
pointer_.x = std::clamp(pointer_.x, 0.0f, std::max(0.0f, io.DisplaySize.x - 1));
|
||||
pointer_.y = std::clamp(pointer_.y, 0.0f, std::max(0.0f, io.DisplaySize.y - 1));
|
||||
// Every frame, after the backend's own: it may report a system cursor
|
||||
// that Proton or gamescope did not move along with ours.
|
||||
// Every frame, after the backend's own report of the system cursor,
|
||||
// which stays where the mouse left it.
|
||||
io.AddMouseSourceEvent(ImGuiMouseSource_Mouse);
|
||||
io.AddMousePosEvent(pointer_.x, pointer_.y);
|
||||
}
|
||||
// The release is sent even when the mouse took the pointer meanwhile: the
|
||||
// press was ours.
|
||||
if (changed & right_thumb) {
|
||||
if (click || (clicking_ && (changed & right_thumb))) {
|
||||
clicking_ = click;
|
||||
io.AddMouseSourceEvent(ImGuiMouseSource_Mouse);
|
||||
io.AddMouseButtonEvent(ImGuiMouseButton_Left, (pad.buttons & right_thumb) != 0);
|
||||
io.AddMouseButtonEvent(ImGuiMouseButton_Left, click);
|
||||
}
|
||||
io.MouseDrawCursor = pointing_;
|
||||
if (warp) return pointer_;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void PadFeed::mouse_moved(ImVec2 position) {
|
||||
// Our own cursor move comes back as a mouse move too; only one that lands
|
||||
// somewhere else is the mouse or a finger.
|
||||
if (pointing_ && moved_away(position, pointer_)) pointing_ = false;
|
||||
// Windows repeats a mouse move where the mouse already was when a window
|
||||
// changes under it; only a move to a new place is the mouse or a finger.
|
||||
if (pointing_ && moved_away(position, mouse_)) pointing_ = false;
|
||||
mouse_ = position;
|
||||
}
|
||||
|
||||
} // namespace dingosdk::launcher_gui
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <imgui.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
// Controller input for the launcher window. Kept free of Windows headers so
|
||||
// the mapping can be tested anywhere; gui_gamepad.cpp reads the pads.
|
||||
@@ -29,15 +28,14 @@ struct PadState {
|
||||
class PadFeed {
|
||||
public:
|
||||
// Call once a frame after the backends' NewFrame and before
|
||||
// ImGui::NewFrame(), which takes the events in. Returns where the OS
|
||||
// cursor should move (client area pixels) when the pad moved the pointer.
|
||||
std::optional<ImVec2> update(ImGuiIO& io, const PadState& pad, float scale);
|
||||
// ImGui::NewFrame(), which takes the events in.
|
||||
void update(ImGuiIO& io, const PadState& pad, float scale);
|
||||
// A mouse move or a touch the window received (WM_MOUSEMOVE, client area
|
||||
// pixels). One that is not the echo of our own cursor move takes the
|
||||
// pointer back from the pad.
|
||||
// pixels). A move to a new place takes the pointer back from the pad.
|
||||
void mouse_moved(ImVec2 position);
|
||||
// The right stick owns the pointer; ImGui draws it, since the Steam
|
||||
// Deck's Game Mode may not show the system cursor.
|
||||
// The right stick owns the pointer. ImGui draws it and the system cursor
|
||||
// stays put: under Proton a moved system cursor comes back late as a
|
||||
// mouse move, which would look like the mouse taking over.
|
||||
bool pointing() const { return pointing_; }
|
||||
|
||||
private:
|
||||
@@ -45,7 +43,9 @@ private:
|
||||
ImGuiKey back_key_{ImGuiKey_Escape};
|
||||
bool connected_{};
|
||||
bool pointing_{};
|
||||
bool clicking_{}; // R3 holds the left button
|
||||
ImVec2 pointer_{};
|
||||
ImVec2 mouse_{-1, -1}; // where the last mouse move was
|
||||
};
|
||||
|
||||
} // namespace dingosdk::launcher_gui
|
||||
+1
-7
@@ -472,13 +472,7 @@ int run(const launcher_app::Session& session, const std::vector<std::wstring>& a
|
||||
// A pad pressed while another window has the focus is not meant for us;
|
||||
// it reads as let go, so nothing stays held while we are in the background.
|
||||
const bool foreground = GetForegroundWindow() == window;
|
||||
if (const auto pointer = pad_feed.update(ImGui::GetIO(), foreground ? read_pad() : PadState{}, g_scale)) {
|
||||
// The system cursor follows the pad's pointer, so the two agree when the
|
||||
// mouse or the touch screen is used next. ImGui draws the pointer itself,
|
||||
// so a cursor the system will not move (Proton, gamescope) costs nothing.
|
||||
POINT point{static_cast<LONG>(pointer->x), static_cast<LONG>(pointer->y)};
|
||||
if (ClientToScreen(window, &point)) SetCursorPos(point.x, point.y);
|
||||
}
|
||||
pad_feed.update(ImGui::GetIO(), foreground ? read_pad() : PadState{}, g_scale);
|
||||
ImGui::NewFrame();
|
||||
frame(launcher, fonts, window, ui, mods_panel);
|
||||
ImGui::Render();
|
||||
|
||||
@@ -571,7 +571,7 @@ void installed_page(Launcher& launcher, const Fonts& fonts, ModsPanel& panel, co
|
||||
// ------------------------------------------------ the list, and under it how its order works
|
||||
const float hint = ImGui::GetTextLineHeightWithSpacing();
|
||||
const float body = std::max(S(120), height - (ImGui::GetCursorPosY() - top) - hint);
|
||||
ImGui::BeginChild("##mod_list", ImVec2(0, body), ImGuiChildFlags_Borders);
|
||||
ImGui::BeginChild("##mod_list", ImVec2(0, body), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened);
|
||||
const auto note = [](const char* first, const char* second = nullptr) {
|
||||
ImGui::Spacing();
|
||||
ImGui::Indent(S(14));
|
||||
@@ -670,7 +670,8 @@ void mod_overview(const Fonts& fonts, ModsPanel& panel, const thunderstore::Inst
|
||||
ImGui::Spacing();
|
||||
|
||||
ImGui::BeginChild("##mod_overview_body",
|
||||
ImVec2(0, std::max(S(80), extent.y - ImGui::GetCursorPosY() - S(24) - ImGui::GetFrameHeight())));
|
||||
ImVec2(0, std::max(S(80), extent.y - ImGui::GetCursorPosY() - S(24) - ImGui::GetFrameHeight())),
|
||||
ImGuiChildFlags_NavFlattened);
|
||||
ImGui::PushTextWrapPos(0);
|
||||
if (!mod.outdated.empty())
|
||||
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(color::danger),
|
||||
@@ -850,7 +851,7 @@ void mods_broken_window(Launcher& launcher, const Fonts& fonts, ImVec2 size, Ui&
|
||||
|
||||
const float footer = ImGui::GetFrameHeight() + ImGui::GetTextLineHeight() + S(56);
|
||||
ImGui::BeginChild("##broken_list", ImVec2(0, frame.y - ImGui::GetCursorPosY() - footer),
|
||||
ImGuiChildFlags_Borders);
|
||||
ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened);
|
||||
for (const auto& problem : problems) {
|
||||
ImGui::PushFont(fonts.bold);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::ColorConvertU32ToFloat4(color::danger));
|
||||
@@ -934,7 +935,7 @@ void mods_outdated_window(Launcher& launcher, const Fonts& fonts, ImVec2 size, U
|
||||
|
||||
const float footer = ImGui::GetFrameHeight() + S(44);
|
||||
ImGui::BeginChild("##outdated_list", ImVec2(0, frame.y - ImGui::GetCursorPosY() - footer),
|
||||
ImGuiChildFlags_Borders);
|
||||
ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened);
|
||||
for (const auto* package : pending) {
|
||||
const auto found = installed.find(thunderstore::folder_for(package->full_name));
|
||||
ImGui::PushFont(fonts.bold);
|
||||
@@ -1013,12 +1014,13 @@ void mods_window(Launcher& launcher, const Fonts& fonts, ImVec2 size, Ui& ui, Mo
|
||||
|
||||
const float rail_top = top + title_size * 2 + S(16);
|
||||
ImGui::SetCursorPos(ImVec2(rail_x, rail_top));
|
||||
ImGui::BeginChild("##rail", ImVec2(rail_width, bottom - rail_top));
|
||||
// Flattened, so a controller's D-pad crosses from the rail into the list and back.
|
||||
ImGui::BeginChild("##rail", ImVec2(rail_width, bottom - rail_top), ImGuiChildFlags_NavFlattened);
|
||||
const bool leave = rail(fonts, panel, window, rail_width, pending, installing);
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SetCursorPos(ImVec2(content_x, top));
|
||||
ImGui::BeginChild("##content", ImVec2(frame.x - content_x - S(28), bottom - top));
|
||||
ImGui::BeginChild("##content", ImVec2(frame.x - content_x - S(28), bottom - top), ImGuiChildFlags_NavFlattened);
|
||||
// With nothing to say, the list runs all the way down to BACK's bottom
|
||||
// edge; a message takes two lines off it until it is gone.
|
||||
const float status = panel.message.empty() ? S(4) : ImGui::GetTextLineHeight() * 2 + S(12);
|
||||
|
||||
@@ -474,7 +474,7 @@ void browse_page(Launcher& launcher, const Fonts& fonts, ModsPanel& panel, float
|
||||
const auto packages = visible_packages(store, installed);
|
||||
|
||||
// ------------------------------------------------ the list
|
||||
ImGui::BeginChild("##store_list", ImVec2(0, body), ImGuiChildFlags_Borders);
|
||||
ImGui::BeginChild("##store_list", ImVec2(0, body), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened);
|
||||
const auto note = [](const char* text) {
|
||||
ImGui::Spacing();
|
||||
ImGui::Indent(S(14));
|
||||
@@ -653,7 +653,8 @@ void package_overview(const Fonts& fonts, ModsPanel& panel, ImVec2 size, bool in
|
||||
ImGui::Spacing();
|
||||
|
||||
ImGui::BeginChild("##overview_body",
|
||||
ImVec2(0, std::max(S(80), extent.y - ImGui::GetCursorPosY() - S(24) - ImGui::GetFrameHeight())));
|
||||
ImVec2(0, std::max(S(80), extent.y - ImGui::GetCursorPosY() - S(24) - ImGui::GetFrameHeight())),
|
||||
ImGuiChildFlags_NavFlattened);
|
||||
ImGui::PushTextWrapPos(0);
|
||||
if (package.deprecated)
|
||||
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(color::warning),
|
||||
|
||||
@@ -123,7 +123,8 @@ void settings_window(Launcher& launcher, const Fonts& fonts, ImVec2 size, Ui& ui
|
||||
// ------------------------------------------------ rail
|
||||
const float rail_top = top + title_size + S(20);
|
||||
ImGui::SetCursorPos(ImVec2(rail_x, rail_top));
|
||||
ImGui::BeginChild("##settings_rail", ImVec2(rail_width, bottom - rail_top));
|
||||
// Flattened, so a controller's D-pad crosses from the rail into the page and back.
|
||||
ImGui::BeginChild("##settings_rail", ImVec2(rail_width, bottom - rail_top), ImGuiChildFlags_NavFlattened);
|
||||
static constexpr std::array<const char*, 4> names{"GAME", "DISPLAY", "KEYS", "ADVANCED"};
|
||||
ImGui::BeginDisabled(binding);
|
||||
for (int i = 0; i < static_cast<int>(names.size()); ++i)
|
||||
@@ -140,9 +141,9 @@ void settings_window(Launcher& launcher, const Fonts& fonts, ImVec2 size, Ui& ui
|
||||
// Kept to a readable column: settings are sentences, not a table.
|
||||
ImGui::SetCursorPos(ImVec2(content_x, top));
|
||||
ImGui::BeginChild("##settings_content",
|
||||
ImVec2(std::min(S(760), frame.x - content_x - S(28)), bottom - top));
|
||||
ImVec2(std::min(S(760), frame.x - content_x - S(28)), bottom - top), ImGuiChildFlags_NavFlattened);
|
||||
const float footer = ImGui::GetTextLineHeight() + S(16);
|
||||
ImGui::BeginChild("##settings_page", ImVec2(0, ImGui::GetWindowHeight() - footer));
|
||||
ImGui::BeginChild("##settings_page", ImVec2(0, ImGui::GetWindowHeight() - footer), ImGuiChildFlags_NavFlattened);
|
||||
switch (ui.settings_tab) {
|
||||
case 0: {
|
||||
section_caption(fonts, "GAME FOLDER");
|
||||
|
||||
Reference in new issue
Block a user