Panics · P05 Buttons: a segmented choice missing from its segments marks none; slide logs and shows no marker
This commit is contained in:
1 parent
9bb342cb16
commit
73a8bf2e34
4 files changed
+40
-13
No files matched your search
@@ -69,10 +69,7 @@ impl RenderOnce for SegmentedControl {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|(value, ..)| value.clone())
|
.map(|(value, ..)| value.clone())
|
||||||
.collect();
|
.collect();
|
||||||
let chosen = values
|
let chosen = values.iter().position(|value| *value == self.selected);
|
||||||
.iter()
|
|
||||||
.position(|value| *value == self.selected)
|
|
||||||
.unwrap_or_else(|| panic!("segmented control has no segment {}", self.selected));
|
|
||||||
let (state, marker) = slide(self.id.clone(), &values, &self.selected, window, cx);
|
let (state, marker) = slide(self.id.clone(), &values, &self.selected, window, cx);
|
||||||
let scroll = window
|
let scroll = window
|
||||||
.use_keyed_state((self.id.clone(), "scroll"), cx, |_, _| ScrollHandle::new())
|
.use_keyed_state((self.id.clone(), "scroll"), cx, |_, _| ScrollHandle::new())
|
||||||
@@ -133,7 +130,7 @@ impl RenderOnce for SegmentedControl {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(ix, (value, label, icon))| {
|
.map(|(ix, (value, label, icon))| {
|
||||||
let on = ix == chosen;
|
let on = Some(ix) == chosen;
|
||||||
let fg = if on { colors.fg } else { colors.fg_muted };
|
let fg = if on { colors.fg } else { colors.fg_muted };
|
||||||
let (focus, reveal) = stops.remove(0);
|
let (focus, reveal) = stops.remove(0);
|
||||||
let (named, labeled) = (value.clone(), value.clone());
|
let (named, labeled) = (value.clone(), value.clone());
|
||||||
|
|||||||
+29
-1
@@ -3,7 +3,7 @@ use gpui::{
|
|||||||
Render, Styled, TestAppContext, VisualTestContext, Window, div, point, px,
|
Render, Styled, TestAppContext, VisualTestContext, Window, div, point, px,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Button, ToggleButton, ToggleItem};
|
use super::{Button, SegmentedControl, ToggleButton, ToggleItem};
|
||||||
use crate::{
|
use crate::{
|
||||||
primitives::{FocusNext, FocusScope},
|
primitives::{FocusNext, FocusScope},
|
||||||
theme::Theme,
|
theme::Theme,
|
||||||
@@ -98,3 +98,31 @@ fn a_disabled_toggle_ignores_clicks(cx: &mut TestAppContext) {
|
|||||||
cx.simulate_click(point(px(4.0), px(4.0)), Modifiers::none());
|
cx.simulate_click(point(px(4.0), px(4.0)), Modifiers::none());
|
||||||
assert_eq!(view.read_with(cx, |toggles, _| toggles.presses), 1);
|
assert_eq!(view.read_with(cx, |toggles, _| toggles.presses), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Segments whose chosen value left with a change of list.
|
||||||
|
struct Stale;
|
||||||
|
|
||||||
|
impl Render for Stale {
|
||||||
|
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
div().w(px(300.0)).child(
|
||||||
|
SegmentedControl::new("views", "gone")
|
||||||
|
.segment("list", "List", None)
|
||||||
|
.segment("grid", "Grid", None),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn a_choice_missing_from_its_segments_marks_none(cx: &mut TestAppContext) {
|
||||||
|
cx.update(Theme::init);
|
||||||
|
let (_, cx) = cx.add_window_view(|_, _| Stale);
|
||||||
|
for _ in 0..3 {
|
||||||
|
cx.run_until_parked();
|
||||||
|
cx.update(|window, _| window.refresh());
|
||||||
|
}
|
||||||
|
assert!(cx.debug_bounds("segment list").is_some());
|
||||||
|
assert!(
|
||||||
|
cx.debug_bounds("segment-thumb").is_none(),
|
||||||
|
"no thumb marks a choice"
|
||||||
|
);
|
||||||
|
}
|
||||||
+7
-6
@@ -46,7 +46,7 @@ pub(crate) struct Marker {
|
|||||||
pub generation: u64,
|
pub generation: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The slide over `values` with `selected` chosen; no marker until that item is measured.
|
/// The slide over `values` with `selected` chosen; no marker until it is measured, or if it is not there.
|
||||||
pub(crate) fn slide(
|
pub(crate) fn slide(
|
||||||
id: impl Into<ElementId>,
|
id: impl Into<ElementId>,
|
||||||
values: &[SharedString],
|
values: &[SharedString],
|
||||||
@@ -54,14 +54,15 @@ pub(crate) fn slide(
|
|||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> (Entity<Slide>, Option<Marker>) {
|
) -> (Entity<Slide>, Option<Marker>) {
|
||||||
let chosen = values
|
let id = id.into();
|
||||||
.iter()
|
let state = window.use_keyed_state(id.clone(), cx, |_, _| Slide::default());
|
||||||
.position(|value| value == selected)
|
|
||||||
.unwrap_or_else(|| panic!("no item {selected} to slide to"));
|
|
||||||
let state = window.use_keyed_state(id, cx, |_, _| Slide::default());
|
|
||||||
if state.read(cx).spans.len() != values.len() {
|
if state.read(cx).spans.len() != values.len() {
|
||||||
state.update(cx, |slide, _| slide.spans = vec![None; values.len()]);
|
state.update(cx, |slide, _| slide.spans = vec![None; values.len()]);
|
||||||
}
|
}
|
||||||
|
let Some(chosen) = values.iter().position(|value| value == selected) else {
|
||||||
|
log::error!("slide {id:?}: no item {selected} among {values:?}; nothing marked");
|
||||||
|
return (state, None);
|
||||||
|
};
|
||||||
if state.read(cx).last.as_ref() != Some(selected) {
|
if state.read(cx).last.as_ref() != Some(selected) {
|
||||||
state.update(cx, |slide, _| {
|
state.update(cx, |slide, _| {
|
||||||
let previous = slide
|
let previous = slide
|
||||||
|
|||||||
+2
-1
@@ -19,7 +19,7 @@ Each item reads every site in its folders, fixes what the rules name, updates ca
|
|||||||
- [x] P02 Typography — `src/typography`
|
- [x] P02 Typography — `src/typography`
|
||||||
- [x] P03 Layout — `src/layout`
|
- [x] P03 Layout — `src/layout`
|
||||||
- [x] P04 Window & Shell — `src/shell`
|
- [x] P04 Window & Shell — `src/shell`
|
||||||
- [ ] P05 Buttons & Actions — `src/buttons`
|
- [x] P05 Buttons & Actions — `src/buttons`
|
||||||
- [ ] P06 Forms — `src/forms`
|
- [ ] P06 Forms — `src/forms`
|
||||||
- [ ] P07 Navigation — `src/navigation`
|
- [ ] P07 Navigation — `src/navigation`
|
||||||
- [ ] P08 Menus — `src/menus`
|
- [ ] P08 Menus — `src/menus`
|
||||||
@@ -69,3 +69,4 @@ One line per item: what changed, what stayed and why, review rounds.
|
|||||||
- P02: `Link::new` takes its handler; `system_zone` logs once and reads as jiff's unknown zone, which `datetime` marks UTC; an oversized highlight query logs and marks nothing; a cut line's paint fault logs. Kept: caller contracts (speed, digits, step, keystroke, heading level, pattern) and the exponent parse. Review: 3 rounds.
|
- P02: `Link::new` takes its handler; `system_zone` logs once and reads as jiff's unknown zone, which `datetime` marks UTC; an oversized highlight query logs and marks nothing; a cut line's paint fault logs. Kept: caller contracts (speed, digits, step, keystroke, heading level, pattern) and the exponent parse. Review: 3 rounds.
|
||||||
- P03: `PaneGroup` leaves a gone or last pane and logs (`split` returns `Option`); a stale split path sets nothing; `SplitPane` splits evenly when sizes lag or fail, seeds by the owner's raw sizes, and drops a drag over another pane count; masonry sorts with `total_cmp`. Kept: dock ids (panels never leave), one-value contracts, pane-id overflow, workspace JSON. Review: 2 rounds.
|
- P03: `PaneGroup` leaves a gone or last pane and logs (`split` returns `Option`); a stale split path sets nothing; `SplitPane` splits evenly when sizes lag or fail, seeds by the owner's raw sizes, and drops a drag over another pane count; masonry sorts with `total_cmp`. Kept: dock ids (panels never leave), one-value contracts, pane-id overflow, workspace JSON. Review: 2 rounds.
|
||||||
- P04: no change. Kept: splash progress and column count (caller contracts), the objc class under `Once`, `Tray::pick` (items fixed at creation). Review: 1 round.
|
- P04: no change. Kept: splash progress and column count (caller contracts), the objc class under `Once`, `Tray::pick` (items fixed at creation). Review: 1 round.
|
||||||
|
- P05: a `SegmentedControl` whose choice left its segments marks none; the cause, `motion::slide`, logs and returns no marker (P11 inherits it). Kept: one-value contracts (group and quick-action counts, toggle label or icon, share payload). Review: 1 round.
|
||||||
Reference in new issue
Block a user