theme: uniform chip height, fix hamburger radius cascade, spotlight dot spec, first-paint trail bug
Decision #1 (one chip highlight height per bar, vertically centred): the .stat-pair/.stat-pair.icon-only/.media-widget/workspace-btn CSS all sized to their own content box before this (min-height: 0, or a stale 32/20px figure), which is why battery sat high and wifi/menu ran taller than their neighbours. Added a hardcoded approved_chip_height() (26/22/22 by WorkspaceStyle, matching the demo spec) since bread-ecosystem's own chip_height token (32/20/36) predates this pass and disagrees with it, and that repo is a sibling agent's this cycle. Also found and fixed a second copy of the hamburger-corner-mismatch bug: .control-panel-btn (hamburger only) hardcoded its own border-radius/ min-width/min-height *later* in the cascade than .stat-pair, silently winning over chip_radius/chip_height regardless of the icon-only fix already in place. Dropped the four conflicting properties so .stat-pair cascades through unchanged. Spotlight workspace dots: bumped to the approved Option B spec (10px tall, widths 8/13/17/22 by open-window count) — the prior pass landed 9px/[6,10,14,18], one generation behind. dot_widths is likewise theme.toml-derived and stale, so overridden locally with a comment rather than edited upstream. Workspace row "sits low on first paint" bug: root cause was the ws-in entrance animation (row-in keyframe, margin-top 8px -> 0) playing on every button during the very first rebuild_buttons call, racing WorkspaceTrail::place()'s single-shot geometry sample and freezing the trail pill a few px low until the next real switch re-measured settled layout. The demo never animates the initial row in at all — only subsequently-added workspaces should. Suppressed ws-in specifically on the first build (button_map starts empty exactly once). Also fixed: make_button's set_size_request was still pinning the stale tokens().chip_height() as a hard GTK minimum, which would have out-ranked the CSS min-height fix above for Trail/Pill workspace pills.
This commit is contained in:
parent
dd5618a5ea
commit
70fe814593
3 changed files with 123 additions and 27 deletions
|
|
@ -142,7 +142,13 @@ pub fn make_button(
|
||||||
btn.set_halign(gtk4::Align::Center);
|
btn.set_halign(gtk4::Align::Center);
|
||||||
btn.set_vexpand(false);
|
btn.set_vexpand(false);
|
||||||
btn.set_hexpand(false);
|
btn.set_hexpand(false);
|
||||||
btn.set_size_request(-1, crate::theme::shell_theme().tokens().chip_height() as i32);
|
// `crate::theme::approved_chip_height`, not `tokens().chip_height()`:
|
||||||
|
// the latter is the stale pre-demo `breadbar::CHIP_HEIGHT` token (32
|
||||||
|
// for this Trail/Pill style's theme) and, as a hard `set_size_request`
|
||||||
|
// minimum, would out-rank the CSS `min-height` the demo actually wants
|
||||||
|
// (26px Trail / 22px Pill) — see that function's doc comment.
|
||||||
|
let style = crate::theme::shell_theme().modules().workspaces.style;
|
||||||
|
btn.set_size_request(-1, crate::theme::approved_chip_height(style) as i32);
|
||||||
if let Some(child) = btn.child() {
|
if let Some(child) = btn.child() {
|
||||||
child.set_halign(gtk4::Align::Center);
|
child.set_halign(gtk4::Align::Center);
|
||||||
child.set_valign(gtk4::Align::Center);
|
child.set_valign(gtk4::Align::Center);
|
||||||
|
|
@ -156,21 +162,27 @@ pub fn make_button(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `style = "dots"` (theme 04/spotlight): a label-less pill whose WIDTH
|
/// `style = "dots"` (theme 04/spotlight): a label-less pill whose WIDTH
|
||||||
/// encodes `windows` (0/1/2/3-or-more open) via `dot_widths` — see
|
/// encodes `windows` (0/1/2/3-or-more open). Distinct from [`make_button`]
|
||||||
/// `bread_theme::shell::WorkspacesModule::dot_widths`. Distinct from
|
/// (Trail/Pill) rather than a variant of it because dots carry no text at
|
||||||
/// [`make_button`] (Trail/Pill) rather than a variant of it because dots
|
/// all (`04-spotlight.html`'s `.dots button` has no label); reusing
|
||||||
/// carry no text at all (`04-spotlight.html`'s `.dots button` has no label);
|
/// `Button::with_label("")` would still measure/lay out an empty label box
|
||||||
/// reusing `Button::with_label("")` would still measure/lay out an empty
|
/// that a genuinely childless button doesn't. Width is a hard
|
||||||
/// label box that a genuinely childless button doesn't. Width is a hard
|
|
||||||
/// `set_size_request` snap, not animated — GTK CSS min-width transitions
|
/// `set_size_request` snap, not animated — GTK CSS min-width transitions
|
||||||
/// don't participate in a directly-set size request the way an opacity/
|
/// don't participate in a directly-set size request the way an opacity/
|
||||||
/// background-color transition does, and the plan only calls out the
|
/// background-color transition does, and the plan only calls out the
|
||||||
/// capsule's own expand/collapse as worth the `anim::spring_to` treatment.
|
/// capsule's own expand/collapse as worth the `anim::spring_to` treatment.
|
||||||
|
///
|
||||||
|
/// `_dot_widths` (the manifest's `modules.workspaces.dot_widths`) is
|
||||||
|
/// accepted but deliberately unused — see `APPROVED_DOT_WIDTHS` below,
|
||||||
|
/// which overrides it with the approved Option B numbers the manifest's
|
||||||
|
/// own value predates. Kept in the signature rather than dropped so the
|
||||||
|
/// call site still documents where a real per-theme width would flow from
|
||||||
|
/// once `theme.toml` catches up.
|
||||||
pub fn make_dot_button(
|
pub fn make_dot_button(
|
||||||
id: WorkspaceId,
|
id: WorkspaceId,
|
||||||
active: WorkspaceId,
|
active: WorkspaceId,
|
||||||
windows: i32,
|
windows: i32,
|
||||||
dot_widths: bread_theme::shell::DotWidths,
|
_dot_widths: bread_theme::shell::DotWidths,
|
||||||
) -> gtk4::Button {
|
) -> gtk4::Button {
|
||||||
let btn = gtk4::Button::new();
|
let btn = gtk4::Button::new();
|
||||||
btn.add_css_class("workspace-dot");
|
btn.add_css_class("workspace-dot");
|
||||||
|
|
@ -186,17 +198,26 @@ pub fn make_dot_button(
|
||||||
btn.set_hexpand(false);
|
btn.set_hexpand(false);
|
||||||
// Height is a deliberate departure from `04-spotlight.html`'s own 6px
|
// Height is a deliberate departure from `04-spotlight.html`'s own 6px
|
||||||
// (see the demo's `.dots button { height: 6px }`): reported as "too
|
// (see the demo's `.dots button { height: 6px }`): reported as "too
|
||||||
// small and hard to click" — the click-target enlargement is a
|
// small and hard to click", and also genuinely hard to *see* on a real
|
||||||
// separate, non-visual fix elsewhere, but 6px is also genuinely hard
|
// display, not just hard to hit. Option B (approved): 10px tall — up
|
||||||
// to *see* on a real display, not just hard to hit. 9px keeps the
|
// from an earlier 9px pass that undershot the approved number by 1px.
|
||||||
// dots reading as slim pills rather than growing into little chips
|
// Keeps the dots reading as slim pills rather than growing into little
|
||||||
// (which would fight the capsule's minimal, text-first look), while
|
// chips (which would fight the capsule's minimal, text-first look),
|
||||||
// being clearly perceptible against the 36px-tall bar. Widths are left
|
// while being clearly perceptible against the 36px-tall bar.
|
||||||
// exactly as `dot_widths` (the manifest's own per-occupancy encoding,
|
const DOT_HEIGHT: i32 = 10;
|
||||||
// e.g. `[6, 10, 14, 18]`) specifies — only the height, which has no
|
// Option B widths (approved): 8/13/17/22px for 0/1/2/3-or-more open
|
||||||
// manifest token of its own, is breadbar's call to make.
|
// windows — `[8, 13, 17, 22]`, not the `dot_widths` parameter's own
|
||||||
const DOT_HEIGHT: i32 = 9;
|
// manifest value. `theme.toml`'s `modules.workspaces.dot_widths =
|
||||||
btn.set_size_request(dot_widths[dot_width_index(windows)], DOT_HEIGHT);
|
// [6, 10, 14, 18]` predates this pass and was never updated to match;
|
||||||
|
// hardcoded here (ignoring the passed-in `dot_widths`) rather than
|
||||||
|
// edited upstream, since bread-ecosystem is a sibling agent's repo
|
||||||
|
// this pass. Flagged in the task report — `dot_widths` should become
|
||||||
|
// `[8, 13, 17, 22]` in `assets/shell/spotlight/theme.toml`.
|
||||||
|
const APPROVED_DOT_WIDTHS: bread_theme::shell::DotWidths = [8, 13, 17, 22];
|
||||||
|
btn.set_size_request(
|
||||||
|
APPROVED_DOT_WIDTHS[dot_width_index(windows)],
|
||||||
|
DOT_HEIGHT,
|
||||||
|
);
|
||||||
btn.connect_clicked(move |_| {
|
btn.connect_clicked(move |_| {
|
||||||
relm4::spawn(async move {
|
relm4::spawn(async move {
|
||||||
switch_workspace(id).await;
|
switch_workspace(id).await;
|
||||||
|
|
|
||||||
22
src/main.rs
22
src/main.rs
|
|
@ -1995,6 +1995,13 @@ impl App {
|
||||||
self.workspace_trail.cancel();
|
self.workspace_trail.cancel();
|
||||||
let prev: std::collections::HashSet<WorkspaceId> =
|
let prev: std::collections::HashSet<WorkspaceId> =
|
||||||
self.button_map.keys().copied().collect();
|
self.button_map.keys().copied().collect();
|
||||||
|
// `button_map` only starts empty once — the very first call this
|
||||||
|
// App instance ever makes, before any workspace has ever been
|
||||||
|
// synced from Hyprland. A fully-emptied bar never happens after
|
||||||
|
// that (the active workspace's own row is always kept), so this
|
||||||
|
// doubles as a clean "is this the initial paint" signal without a
|
||||||
|
// dedicated flag — see its one use below.
|
||||||
|
let is_first_build = prev.is_empty();
|
||||||
while let Some(child) = self.workspace_box.first_child() {
|
while let Some(child) = self.workspace_box.first_child() {
|
||||||
self.workspace_box.remove(&child);
|
self.workspace_box.remove(&child);
|
||||||
}
|
}
|
||||||
|
|
@ -2038,7 +2045,20 @@ impl App {
|
||||||
bar::workspaces::make_button(ws.id, &ws.name, self.active_ws, ws.windows > 0)
|
bar::workspaces::make_button(ws.id, &ws.name, self.active_ws, ws.windows > 0)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if !prev.contains(&ws.id) {
|
// Never on the very first build (bug: "the [Trail] row sits
|
||||||
|
// ~5px low on first paint and only corrects after the first
|
||||||
|
// switch"). Root cause: `ws-in`'s `row-in` keyframe animates
|
||||||
|
// `margin-top` 8px → 0 over 320ms; `WorkspaceTrail::place`
|
||||||
|
// (called once, synchronously-ish, right after this loop for
|
||||||
|
// the initial row) samples each button's geometry via a
|
||||||
|
// single-shot tick callback that can fire while that margin
|
||||||
|
// is still mid-animation, freezing the trail pill a few px
|
||||||
|
// low until the next `place`/`stretch` call (the first real
|
||||||
|
// workspace switch) re-samples the by-then-settled layout.
|
||||||
|
// The demo itself never animates the initial row in at all
|
||||||
|
// (`OCC.forEach` builds plainly, only `place(0)` runs) — only
|
||||||
|
// *subsequently added* workspaces should ever play this.
|
||||||
|
if !is_first_build && !prev.contains(&ws.id) {
|
||||||
play_once(&btn, "ws-in", 360);
|
play_once(&btn, "ws-in", 360);
|
||||||
}
|
}
|
||||||
self.workspace_box.append(&btn);
|
self.workspace_box.append(&btn);
|
||||||
|
|
|
||||||
69
src/theme.rs
69
src/theme.rs
|
|
@ -35,6 +35,21 @@ pub fn set_shell_theme(theme: ShellTheme) {
|
||||||
SHELL_THEME.with(|cell| *cell.borrow_mut() = Rc::new(theme));
|
SHELL_THEME.with(|cell| *cell.borrow_mut() = Rc::new(theme));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The one bar-chip height every chip in the row shares (vol/wifi/battery/
|
||||||
|
/// menu/media, and the workspace pills for Trail/Pill styles) — see the
|
||||||
|
/// `chip_h` local in `load_css` for why this is a hardcoded per-`
|
||||||
|
/// WorkspaceStyle` override rather than `Tokens::chip_height()`. Used both
|
||||||
|
/// by that CSS and by `bar::workspaces::make_button`'s `set_size_request`,
|
||||||
|
/// which otherwise still forces the stale token value as a hard GTK
|
||||||
|
/// minimum that a CSS `min-height` alone cannot out-rank.
|
||||||
|
pub fn approved_chip_height(style: bread_theme::shell::WorkspaceStyle) -> i64 {
|
||||||
|
use bread_theme::shell::WorkspaceStyle::*;
|
||||||
|
match style {
|
||||||
|
Trail => 26,
|
||||||
|
Pill | Dots => 22,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn load_css() -> String {
|
fn load_css() -> String {
|
||||||
// breadbar-specific rules only — fonts, base colours, and generic widgets
|
// breadbar-specific rules only — fonts, base colours, and generic widgets
|
||||||
// come from the shared ecosystem stylesheet (applied first in `apply()`).
|
// come from the shared ecosystem stylesheet (applied first in `apply()`).
|
||||||
|
|
@ -118,6 +133,24 @@ fn load_css() -> String {
|
||||||
_ => radius_sm.clone(),
|
_ => radius_sm.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ONE chip highlight height per bar, vertically centred — every chip
|
||||||
|
// (vol/wifi/battery/menu/media, icon-only and labelled alike) shares
|
||||||
|
// it so their fills align, instead of each sizing to its own content
|
||||||
|
// box (reported: battery sits high, wifi/menu are taller than their
|
||||||
|
// neighbours). Liquid Motion 26px / Glass Workbench 22px / Spotlight
|
||||||
|
// 22px, per the approved demo spec.
|
||||||
|
//
|
||||||
|
// HARDCODED, not `tokens.chip_height()`: that token is `breadbar::
|
||||||
|
// CHIP_HEIGHT` (32) carried over from before this design pass and was
|
||||||
|
// never updated for the three builtin `theme.toml`s (32/20/36) — it
|
||||||
|
// predates and disagrees with the demo numbers above. bread-ecosystem
|
||||||
|
// is owned by a sibling agent this pass, so this stays a local
|
||||||
|
// override (same `WorkspaceStyle` this file already keys `chip_radius`
|
||||||
|
// off) rather than an edit to that repo's schema/manifests. Flagged in
|
||||||
|
// the task report: `chip_height` should become 26/22/22 upstream.
|
||||||
|
let chip_h = approved_chip_height(theme.modules().workspaces.style);
|
||||||
|
let chip_height_px = format!("{chip_h}px");
|
||||||
|
|
||||||
// `modules.workspaces.style` (plan §11 Phase 5): "trail" (default,
|
// `modules.workspaces.style` (plan §11 Phase 5): "trail" (default,
|
||||||
// liquid-motion) is exactly today's CSS, unchanged byte-for-byte —
|
// liquid-motion) is exactly today's CSS, unchanged byte-for-byte —
|
||||||
// dimmed/translucent buttons with the gradient trail overlay supplying
|
// dimmed/translucent buttons with the gradient trail overlay supplying
|
||||||
|
|
@ -140,7 +173,7 @@ fn load_css() -> String {
|
||||||
background-color: @accent; border-radius: {radius_sm}; }}\
|
background-color: @accent; border-radius: {radius_sm}; }}\
|
||||||
.workspace-btn {{ background: transparent; opacity: 0.36; color: @on-bg;\
|
.workspace-btn {{ background: transparent; opacity: 0.36; color: @on-bg;\
|
||||||
border-radius: {radius_sm}; border: none; outline: none; box-shadow: none;\
|
border-radius: {radius_sm}; border: none; outline: none; box-shadow: none;\
|
||||||
min-width: 28px; min-height: 26px; margin: 0; padding: 0 7px;\
|
min-width: 28px; min-height: {chip_height_px}; margin: 0; padding: 0 7px;\
|
||||||
font-size: 22px; font-weight: bold;\
|
font-size: 22px; font-weight: bold;\
|
||||||
transition: opacity 0.22s {spring_settle},\
|
transition: opacity 0.22s {spring_settle},\
|
||||||
background-color 0.22s {spring_settle}; }}\
|
background-color 0.22s {spring_settle}; }}\
|
||||||
|
|
@ -155,7 +188,7 @@ fn load_css() -> String {
|
||||||
format!(
|
format!(
|
||||||
".workspace-btn {{ background: transparent; opacity: 1; color: alpha(@on-bg, 0.4);\
|
".workspace-btn {{ background: transparent; opacity: 1; color: alpha(@on-bg, 0.4);\
|
||||||
border-radius: {radius_sm}; border: none; outline: none; box-shadow: none;\
|
border-radius: {radius_sm}; border: none; outline: none; box-shadow: none;\
|
||||||
min-width: 22px; min-height: 20px; margin: 0; padding: 0 6px;\
|
min-width: 22px; min-height: {chip_height_px}; margin: 0; padding: 0 6px;\
|
||||||
font-size: 12px; font-weight: 600;\
|
font-size: 12px; font-weight: 600;\
|
||||||
transition: background-color 0.22s {spring_settle},\
|
transition: background-color 0.22s {spring_settle},\
|
||||||
color 0.22s {spring_settle}, opacity 0.22s {spring_settle}; }}\
|
color 0.22s {spring_settle}, opacity 0.22s {spring_settle}; }}\
|
||||||
|
|
@ -253,7 +286,13 @@ fn load_css() -> String {
|
||||||
radius_pill for spotlight, so every theme's stat chips round\
|
radius_pill for spotlight, so every theme's stat chips round\
|
||||||
the way that theme's *other* rounded chrome already does,\
|
the way that theme's *other* rounded chrome already does,\
|
||||||
instead of all three sharing one borrowed hardcoded number. */\
|
instead of all three sharing one borrowed hardcoded number. */\
|
||||||
.stat-pair {{ margin: 0; border-radius: {chip_radius}; padding: 5px 9px; min-height: 0;\
|
/* min-height (not the old `min-height: 0`): decision #1 — ONE\
|
||||||
|
chip highlight height per bar, vertically centred, shared by\
|
||||||
|
every chip so their fills align instead of each sizing to its\
|
||||||
|
own content box (reported: battery sat high, wifi/menu were\
|
||||||
|
taller than their neighbours). See `chip_height_px` above. */\
|
||||||
|
.stat-pair {{ margin: 0; border-radius: {chip_radius}; padding: 5px 9px;\
|
||||||
|
min-height: {chip_height_px};\
|
||||||
transition: background-color 0.22s {spring_settle},\
|
transition: background-color 0.22s {spring_settle},\
|
||||||
opacity 0.18s ease; }}\
|
opacity 0.18s ease; }}\
|
||||||
.stat-pair:hover {{ background: alpha(@on-bg, 0.12); }}\
|
.stat-pair:hover {{ background: alpha(@on-bg, 0.12); }}\
|
||||||
|
|
@ -271,7 +310,7 @@ fn load_css() -> String {
|
||||||
out (spotlight has no icon-only chip today, but would get the\
|
out (spotlight has no icon-only chip today, but would get the\
|
||||||
same pill radius as its one `.stat-pair` sibling if it ever did). */\
|
same pill radius as its one `.stat-pair` sibling if it ever did). */\
|
||||||
.stat-pair.icon-only {{ padding: 4px;\
|
.stat-pair.icon-only {{ padding: 4px;\
|
||||||
min-width: 32px; min-height: 32px; }}\
|
min-width: {chip_height_px}; min-height: {chip_height_px}; }}\
|
||||||
.stat-icon {{ margin-right: 6px; }}\
|
.stat-icon {{ margin-right: 6px; }}\
|
||||||
.stat-pair.icon-only .stat-icon {{ margin: 0; }}\
|
.stat-pair.icon-only .stat-icon {{ margin: 0; }}\
|
||||||
.bt-icon {{ margin-right: 8px; }}
|
.bt-icon {{ margin-right: 8px; }}
|
||||||
|
|
@ -368,7 +407,10 @@ fn load_css() -> String {
|
||||||
border-bottom: 1px solid alpha(@on-bg, 0.10); box-shadow: none; }}\
|
border-bottom: 1px solid alpha(@on-bg, 0.10); box-shadow: none; }}\
|
||||||
.confirm-button {{ background-color: @accent; color: @on-accent; }}\
|
.confirm-button {{ background-color: @accent; color: @on-accent; }}\
|
||||||
.confirm-button:hover {{ background-color: alpha(@accent, 0.85); }}\
|
.confirm-button:hover {{ background-color: alpha(@accent, 0.85); }}\
|
||||||
.media-widget {{ border-radius: 10px; padding: 4px 8px; min-height: 0;\
|
/* min-height: decision #1 — the media chip is a bar chip like\
|
||||||
|
any other, so it shares the same row height instead of sizing\
|
||||||
|
to its own eq-bar/label content. */\
|
||||||
|
.media-widget {{ border-radius: 10px; padding: 4px 8px; min-height: {chip_height_px};\
|
||||||
transition: background-color 0.22s {spring_settle}; }}\
|
transition: background-color 0.22s {spring_settle}; }}\
|
||||||
.media-widget:hover {{ background: alpha(@on-bg, 0.08); }}\
|
.media-widget:hover {{ background: alpha(@on-bg, 0.08); }}\
|
||||||
.media-widget.media-in {{ animation: row-in 0.4s {spring} both; }}\
|
.media-widget.media-in {{ animation: row-in 0.4s {spring} both; }}\
|
||||||
|
|
@ -385,8 +427,20 @@ fn load_css() -> String {
|
||||||
.media-btn {{ min-width: 32px; padding: 4px 8px; border-radius: {radius_sm};\
|
.media-btn {{ min-width: 32px; padding: 4px 8px; border-radius: {radius_sm};\
|
||||||
transition: background-color 0.18s ease; }}\
|
transition: background-color 0.18s ease; }}\
|
||||||
.media-btn:hover {{ background: alpha(@on-bg, 0.10); }}\
|
.media-btn:hover {{ background: alpha(@on-bg, 0.10); }}\
|
||||||
.control-panel-btn {{ padding: 5px 8px; margin: 0; border-radius: 10px;\
|
/* No padding/border-radius/min-width/min-height here (was\
|
||||||
opacity: 0.92; font-size: 18px; line-height: 1; min-width: 0; min-height: 0;\
|
`padding: 5px 8px; border-radius: 10px; min-width: 0;\
|
||||||
|
min-height: 0`): the hamburger is the only button carrying both\
|
||||||
|
`.stat-pair.icon-only` AND `.control-panel-btn`, and because\
|
||||||
|
this rule sits later in the cascade its hardcoded 10px radius\
|
||||||
|
and 0 min-size were silently winning over `.stat-pair`'s own\
|
||||||
|
`chip_radius`/`chip_height_px` — the exact hamburger-corner-\
|
||||||
|
mismatch bug decision #2 describes, and a second copy of\
|
||||||
|
decision #1's height bug, both reintroduced by\
|
||||||
|
this one class alone. Dropping the four properties lets\
|
||||||
|
`.stat-pair`/`.stat-pair.icon-only` cascade through unchanged,\
|
||||||
|
same fix shape as the icon-only border-radius removal above. */\
|
||||||
|
.control-panel-btn {{ margin: 0;\
|
||||||
|
opacity: 0.92; font-size: 18px; line-height: 1;\
|
||||||
background: transparent; border: none; outline: none; box-shadow: none;\
|
background: transparent; border: none; outline: none; box-shadow: none;\
|
||||||
transition: background-color 0.22s {spring_settle},\
|
transition: background-color 0.22s {spring_settle},\
|
||||||
opacity 0.18s ease; }}\
|
opacity 0.18s ease; }}\
|
||||||
|
|
@ -508,6 +562,7 @@ fn load_css() -> String {
|
||||||
radius_sm = radius_sm,
|
radius_sm = radius_sm,
|
||||||
radius_pill = radius_pill,
|
radius_pill = radius_pill,
|
||||||
chip_radius = chip_radius,
|
chip_radius = chip_radius,
|
||||||
|
chip_height_px = chip_height_px,
|
||||||
pad = pad,
|
pad = pad,
|
||||||
spring = spring,
|
spring = spring,
|
||||||
spring_settle = spring_settle,
|
spring_settle = spring_settle,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue