| 45 |
45 |
|
//! constraint layer per app, which is how the divergence this crate exists to
|
| 46 |
46 |
|
//! end got started.
|
| 47 |
47 |
|
//!
|
|
48 |
+ |
//! 0.3.0 closes a gap the first real adoption found, which is what adopting
|
|
49 |
+ |
//! against goingson first was for. [`Selector`] described only the *chosen*
|
|
50 |
+ |
//! option, so an unchosen one fell through to [`Depth::Flat`] and no renderer
|
|
51 |
+ |
//! drew it; goingson's tab strip recesses its unchosen tabs by hand and could
|
|
52 |
+ |
//! not delete the line, because being recessed is *why* the chosen tab reads as
|
|
53 |
+ |
//! coming forward. So [`Selector::unchosen`] joins `chosen`, and saying it
|
|
54 |
+ |
//! needed [`Fill::Sunken`] and [`Depth::Sunken`]: a surface set back by colour
|
|
55 |
+ |
//! with no edge, which is neither a well nor level-with.
|
|
56 |
+ |
//!
|
| 48 |
57 |
|
//! # Where the description stops
|
| 49 |
58 |
|
//!
|
| 50 |
59 |
|
//! The bespoke widgets, a day-plan timeline and a kanban board and a calendar,
|
| 142 |
151 |
|
Overlay,
|
| 143 |
152 |
|
/// The inside of a well.
|
| 144 |
153 |
|
Well,
|
|
154 |
+ |
/// A surface set back from the one it sits on, by colour and nothing else.
|
|
155 |
+ |
///
|
|
156 |
+ |
/// Not a well. A well is a hole with an edge, and the two are authored in
|
|
157 |
+ |
/// opposite directions: `makeover` derives `surface-well` by inverting
|
|
158 |
+ |
/// against the theme's own content colour, while `surface-sunken` is
|
|
159 |
+ |
/// authored and free to sit darker than raised (goingson's does). Naming
|
|
160 |
+ |
/// only the well left the recessed-with-no-edge surface unsayable, which is
|
|
161 |
+ |
/// what an unchosen tab is: it recedes so the chosen one can come forward,
|
|
162 |
+ |
/// and it carries no bevel of its own.
|
|
163 |
+ |
///
|
|
164 |
+ |
/// Added 0.3.0, from goingson's tab strip, which hand-writes exactly this
|
|
165 |
+ |
/// and could not delete the line because no member described it.
|
|
166 |
+ |
Sunken,
|
| 145 |
167 |
|
}
|
| 146 |
168 |
|
|
| 147 |
169 |
|
// No `fallback` here, deliberately. An earlier cut had `Fill::Well` fall back
|
| 161 |
183 |
|
Self::Raised => "surface-raised",
|
| 162 |
184 |
|
Self::Overlay => "surface-overlay",
|
| 163 |
185 |
|
Self::Well => "surface-well",
|
|
186 |
+ |
Self::Sunken => "surface-sunken",
|
| 164 |
187 |
|
}
|
| 165 |
188 |
|
}
|
| 166 |
189 |
|
}
|
| 182 |
205 |
|
/// A hole in the panel, with content down inside it. For anything the
|
| 183 |
206 |
|
/// user looks *into*: a table body, a tag tree, a text field.
|
| 184 |
207 |
|
Well,
|
|
208 |
+ |
/// Set back from what it sits on, by colour alone. No edge.
|
|
209 |
+ |
///
|
|
210 |
+ |
/// The one member carrying a fill without a bevel, so a renderer cannot
|
|
211 |
+ |
/// assume the two arrive together. That is deliberate and it is still the
|
|
212 |
+ |
/// pairing rule: both halves come off the same `Depth`, so they cannot
|
|
213 |
+ |
/// disagree, and here one half is legitimately absent.
|
|
214 |
+ |
///
|
|
215 |
+ |
/// Distinct from [`Depth::Flat`], which has no fill either and inherits.
|
|
216 |
+ |
/// Recessed and level-with are different claims, and only one of them
|
|
217 |
+ |
/// needs a colour.
|
|
218 |
+ |
Sunken,
|
| 185 |
219 |
|
}
|
| 186 |
220 |
|
|
| 187 |
221 |
|
impl Depth {
|
| 189 |
223 |
|
#[must_use]
|
| 190 |
224 |
|
pub const fn bevel(self) -> Option<Bevel> {
|
| 191 |
225 |
|
match self {
|
| 192 |
|
- |
Self::Flat => None,
|
|
226 |
+ |
// Sunken joins Flat here, for the opposite reason: Flat has no edge
|
|
227 |
+ |
// because nothing separates it from its surroundings, and Sunken has
|
|
228 |
+ |
// none because its colour is already doing the separating.
|
|
229 |
+ |
Self::Flat | Self::Sunken => None,
|
| 193 |
230 |
|
Self::Raised => Some(Bevel::Raised),
|
| 194 |
231 |
|
Self::Well => Some(Bevel::Inset),
|
| 195 |
232 |
|
}
|
| 205 |
242 |
|
Self::Flat => None,
|
| 206 |
243 |
|
Self::Raised => Some(Fill::Raised),
|
| 207 |
244 |
|
Self::Well => Some(Fill::Well),
|
|
245 |
+ |
Self::Sunken => Some(Fill::Sunken),
|
| 208 |
246 |
|
}
|
| 209 |
247 |
|
}
|
| 210 |
248 |
|
|
| 457 |
495 |
|
}
|
| 458 |
496 |
|
}
|
| 459 |
497 |
|
|
|
498 |
+ |
/// How the options that were *not* picked sit.
|
|
499 |
+ |
///
|
|
500 |
+ |
/// Added 0.3.0. Describing only [`Selector::chosen`] left the unchosen
|
|
501 |
+ |
/// option falling through to [`Depth::Flat`], which says it is level with
|
|
502 |
+ |
/// the strip it sits in, and no renderer emitted anything for it. That is
|
|
503 |
+ |
/// wrong in both directions and goingson proved it: its unchosen tabs are
|
|
504 |
+ |
/// recessed by hand, and being recessed is *why* the chosen one reads as
|
|
505 |
+ |
/// coming forward. Against a flat strip, a raised chosen tab is a bevel
|
|
506 |
+ |
/// drawn on the strip's own colour, which is a much weaker folder effect
|
|
507 |
+ |
/// than the contrast the idiom is named after.
|
|
508 |
+ |
///
|
|
509 |
+ |
/// Each member is the inverse of its chosen state, which is the whole
|
|
510 |
+ |
/// content of "picked" once colour is deferred:
|
|
511 |
+ |
///
|
|
512 |
+ |
/// - Tabs recede, so the chosen one comes forward.
|
|
513 |
+ |
/// - A segment and a toggle stand up, so the chosen one is held in.
|
|
514 |
+ |
#[must_use]
|
|
515 |
+ |
pub const fn unchosen(self) -> Depth {
|
|
516 |
+ |
match self {
|
|
517 |
+ |
Self::Tabs => Depth::Sunken,
|
|
518 |
+ |
Self::Segmented | Self::Toggle => Depth::Raised,
|
|
519 |
+ |
}
|
|
520 |
+ |
}
|
|
521 |
+ |
|
| 460 |
522 |
|
/// Whether the options touch.
|
| 461 |
523 |
|
///
|
| 462 |
524 |
|
/// The gap is the entire difference between a segmented control and a row
|
| 793 |
855 |
|
assert_eq!(Depth::Flat.fill(), None);
|
| 794 |
856 |
|
}
|
| 795 |
857 |
|
|
|
858 |
+ |
#[test]
|
|
859 |
+ |
fn sunken_is_recessed_by_colour_with_no_edge() {
|
|
860 |
+ |
// The one member carrying a fill without a bevel. A renderer that
|
|
861 |
+ |
// assumes the two arrive together drops the fill silently, which is
|
|
862 |
+ |
// exactly what makeover-webview did before 0.3.0.
|
|
863 |
+ |
assert_eq!(Depth::Sunken.fill(), Some(Fill::Sunken));
|
|
864 |
+ |
assert_eq!(Depth::Sunken.bevel(), None);
|
|
865 |
+ |
}
|
|
866 |
+ |
|
|
867 |
+ |
#[test]
|
|
868 |
+ |
fn sunken_and_flat_are_different_claims() {
|
|
869 |
+ |
// Both edgeless, and only one of them needs a colour. Collapsing them
|
|
870 |
+ |
// is what left an unchosen tab unsayable.
|
|
871 |
+ |
assert_eq!(Depth::Flat.bevel(), Depth::Sunken.bevel());
|
|
872 |
+ |
assert_ne!(Depth::Flat.fill(), Depth::Sunken.fill());
|
|
873 |
+ |
}
|
|
874 |
+ |
|
|
875 |
+ |
#[test]
|
|
876 |
+ |
fn a_sunken_surface_is_not_a_well() {
|
|
877 |
+ |
// Authored in opposite directions: makeover derives surface-well by
|
|
878 |
+ |
// inverting against the theme's content colour, while surface-sunken is
|
|
879 |
+ |
// authored and may sit darker than raised.
|
|
880 |
+ |
assert_ne!(Fill::Sunken, Fill::Well);
|
|
881 |
+ |
assert_eq!(Fill::Sunken.token(), "surface-sunken");
|
|
882 |
+ |
assert_eq!(Fill::Well.token(), "surface-well");
|
|
883 |
+ |
}
|
|
884 |
+ |
|
|
885 |
+ |
#[test]
|
|
886 |
+ |
fn every_selector_describes_both_of_its_states() {
|
|
887 |
+ |
// The gap 0.3.0 closed. Before it, only `chosen` existed and the
|
|
888 |
+ |
// unchosen option fell through to Flat at every renderer.
|
|
889 |
+ |
for s in [Selector::Tabs, Selector::Segmented, Selector::Toggle] {
|
|
890 |
+ |
assert_ne!(
|
|
891 |
+ |
s.chosen(),
|
|
892 |
+ |
s.unchosen(),
|
|
893 |
+ |
"{s:?} cannot tell picked from unpicked"
|
|
894 |
+ |
);
|
|
895 |
+ |
}
|
|
896 |
+ |
}
|
|
897 |
+ |
|
|
898 |
+ |
#[test]
|
|
899 |
+ |
fn only_a_tab_inverts_the_other_way() {
|
|
900 |
+ |
// Tabs recede so the chosen one comes forward; a segment and a toggle
|
|
901 |
+ |
// stand up so the chosen one is held in. That inversion is the whole
|
|
902 |
+ |
// content of "picked" once colour is deferred, and it is why the three
|
|
903 |
+ |
// are not one member with a flag.
|
|
904 |
+ |
assert_eq!(Selector::Tabs.unchosen(), Depth::Sunken);
|
|
905 |
+ |
assert_eq!(Selector::Tabs.chosen(), Depth::Raised);
|
|
906 |
+ |
|
|
907 |
+ |
for s in [Selector::Segmented, Selector::Toggle] {
|
|
908 |
+ |
assert_eq!(s.unchosen(), Depth::Raised);
|
|
909 |
+ |
assert_eq!(s.chosen(), Depth::Well);
|
|
910 |
+ |
// Held in is what pressing produces: one appearance, two reasons.
|
|
911 |
+ |
assert_eq!(s.unchosen().pressed(), s.chosen());
|
|
912 |
+ |
}
|
|
913 |
+ |
}
|
|
914 |
+ |
|
| 796 |
915 |
|
#[test]
|
| 797 |
916 |
|
fn pressing_a_card_makes_a_well() {
|
| 798 |
917 |
|
assert_eq!(Depth::Raised.pressed(), Depth::Well);
|