Repository navigation
feat(profiles): add a settings strip and live profile switching - #44
Open
inayayousfi wants to merge 14 commits into
Open
inayayousfi wants to merge 14 commits into
inayayousfi wants to merge 14 commits into
Conversation
inayayousfi
added this pull request to stack #45
October 10, 2026 16:23
inayayousfi
force-pushed
the
feat/settings-strip
branch
2 times, most recently
from
October 12, 2026 13:14
b9b854c to
97c2e01
Compare
inayayousfi
force-pushed
the
feat/settings-strip
branch
from
October 13, 2026 11:15
97c2e01 to
302319c
Compare
inayayousfi directed the work and made every decision. Claude Opus 5.5, running in Claude Code, carried inayayousfi's decisions out. A profile can put a strip of checkboxes, steppers, dropdowns, and menus at the bottom of any window, built in osk.std from existing node kinds and bound to registry variables. Dropdowns and menus open as inline panels because Qt popups fail on layer-shell windows. Profiles switch at runtime, keep a shared window's position, and roll back when the new one fails to build. The default keyboard gets a settings strip, and a small social profile gives switching a target.
inayayousfi directed the work and made every decision. Claude Opus 5.5, running in Claude Code, carried inayayousfi's decisions out. A window now refits to its content: when a panel shows or hides, it resizes to its new minimum size, so it grows for the panel and shrinks back afterwards. osk.std.controls adds checkbox, stepper, menu, dropdown, and strip, built from existing node kinds and bound to state. Menus open as inline panels; menus in one group close each other. A strip shows only a small ⋯ button until it is opened, then its controls beside it and their panels above it. profile.switch runs another profile of the root config once the queue is empty. It closes the old windows and drops their bindings at once, reopens a window with the same ID where it was, and builds the previous profile again when the new one fails. app.profile and app.profiles are read-only, a profile without hot corners turns them off, and a prepared lock-screen panel refuses a profile without one. Every window of the bundled config gets the same strip, in place of its content's bottom margin: profile, keyboard opacity, and dwell settings. A social profile with Up, Down, L, and K gives switching a target. AGENTS.md documents the strip and switching, and the plan's steps are done.
…tching inayayousfi directed the work and made every decision. Claude Opus 5.5, running in Claude Code, carried inayayousfi's decisions out. A profile switch now runs in two steps. profile.switch tears the running profile down, releasing held keys, then sends profile.start, which also waits for an empty queue, so the closing windows' reports reach no profile. A switch requested in between only replaces the target, so the last one requested starts and two queued switches no longer loop. When the previous profile cannot start again after a failed switch, the report's exception type is ProfileRollbackFailed. Startup and a switch show start windows through one helper, and a floating window restored or moved off screen is moved back inside it. NodeBuilder.build_tree returns a tree's widget with its unbinds, and a window drops them all when Qt deletes it, so a failed build leaves no bindings behind. Setting window factories no longer closes windows, and starting attachments no longer stops them. SETTINGS_STRIP_PLAN.md now matches the code: menus keep the open menu's ID in std.menus.<group>, and every window of both profiles has the full strip. AGENTS.md describes the two-step switch. The default profile's parity data is unchanged.
inayayousfi directed the work and made every decision. Claude Opus 5.5, running in Claude Code, carried inayayousfi's decisions out. Between two profiles, a window action now reports action.failed instead of building one of the old profile's windows, which the new profile then reused. Tearing a profile down empties the window factories, and stopping attachments forgets the lock-screen panel's window. Starting attachments while others still run, or replacing window factories while windows are live, raises instead of relying on the caller's order. Startup still shows its windows outside a queue drain. That is safe now that a binding failing while it is bound posts its report, and the docstring says so. A nested build_tree keeps the outer build's bindings. The bundled profiles and the profile menu read one table of names, captions, and builders, so the two cannot disagree. Smaller cleanups: the position restore trusts the state registry's types, a float is no longer converted to float, and the strip docstring wraps evenly. AGENTS.md describes the gap between two profiles.
inayayousfi directed the work and made every decision. Claude Opus 5.5, running in Claude Code, carried inayayousfi's decisions out. SETTINGS_STRIP_PLAN.md is deleted because its steps are done. AGENTS.md adds profile switching to the lifecycle the engine keeps; the switch itself is described in the runtime's docstrings. ConfigDecoder.decode_root only wrapped decode_config for tests, so the tests call decode_config(...).active instead.
inayayousfi
force-pushed
the
feat/settings-strip
branch
from
October 13, 2026 13:47
302319c to
897f02d
Compare
inayayousfi directed the work and made every decision. Claude Opus 5.5, running in Claude Code, carried inayayousfi's decisions out. Brings in timers, hover, pointer reports, and the move of key looks to std. The settings controls now light their buttons through std.lit instead of the removed latched option, and std exports controls beside lit and styles. A profile switch drops the old profile's timers through the profile's stop hook.
inayayousfi directed the work and made every decision. Claude Opus 5.5, running in Claude Code, carried inayayousfi's decisions out. Brings in the dwell tests' wait for clicks.
inayayousfi
marked this pull request as ready for review
October 13, 2026 15:16
inayayousfi directed the work and made every decision. Claude Opus 5.5, running in Claude Code, carried inayayousfi's decisions out. Brings in the dwell indicator options and the close_label window value.
inayayousfi directed the work and made every decision. Claude Opus 5.5, running in Claude Code, carried inayayousfi's decisions out. Brings in the interaction reports: mouse buttons, title-bar and grip drags, and finished dwells, with std giving them their usual meaning.
inayayousfi directed the work and made every decision. Claude Opus 5.5, running in Claude Code, carried inayayousfi's decisions out. Brings in optional built-ins and their raw reports: any-button drags, hover, wheel, and geometry reports, hot-corner and dwell options, std.locator, and window anchors. Both bundled profiles color their keys through std.locator, so the settings-strip buttons glow the gap color. keep_on_screen now also governs the window's keep_on_screen method, so a restored position or a grown window stays where it is when the option is off.
inayayousfi directed the work and made every decision. Claude Opus 5.5, running in Claude Code, carried inayayousfi's decisions out. A content change now refits the window through the shared _refit, so fit_content governs it too, and the window stays on screen after any refit.
inayayousfi directed the work and made every decision. Claude Opus 5.5, running in Claude Code, carried inayayousfi's decisions out. A window's fixed keep_position field (default on) decides whether a profile switch builds it where a window with the same ID last was. With it off, the window starts where its overlay places it, and the profile can place it itself with window.move_to and the observed windows.<id>.position.
inayayousfi directed the work and made every decision. Claude Opus 5.5, running in Claude Code, carried inayayousfi's decisions out. Brings the Windows mouse-button fix.
inayayousfi directed the work and made every decision. Claude Opus 5.5, running in Claude Code, carried inayayousfi's decisions out. Brings plain-window moves and resizes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
inayayousfi directed the work and made every decision.
Claude Opus 5.5, running in Claude Code, carried inayayousfi's decisions out.
This sits on top of #36 and depends on its state registry, where every setting is a declared variable that any value option can bind to.
The idea is to let a profile put a strip of controls at the bottom of any window, with checkboxes, steppers, dropdowns and menus that read and write those variables. The profile decides what the strip shows and what each control does. These controls are axidev_osk.std helpers built from the node kinds that already exist, so the engine gets no menu concept of its own.
Dropdowns and menus open as panels inside the window instead of Qt popups. I tried real popups on a layer-shell window under KDE Plasma Wayland, and LayerShellQt 6.7.5 refused both a dropdown list and a menu with "Cannot attach popup of unknown type". An inline panel does work there, but the window never shrank back after the panel closed, so the engine has to resize it to its minimum when content shrinks.
Profiles also switch while the app runs, through a profile.switch action. A window whose id exists in both profiles keeps its position, and a profile that fails to build rolls back to the previous one.
To show all of it, the default keyboard gets a strip with a profile dropdown, an opacity stepper and a panel holding every dwell option. A second profile named social has four keys (Up, Down, L and K) for scrolling a feed, and its strip only offers the way back. Opacity and the dwell settings live in the root config, so they survive a switch.
Open risks: opening a panel re-centers the keyboard on layer shell, so keys move under a dwell pointer while it is open. Live theme bindings have not been measured, and keeping a window's position across a switch is untested on every backend.