mirror of
https://github.com/storytold/figcraft.git
synced 2026-11-13 13:52:34 +00:00
M1: the page background opacity can be edited in the Page section (#1748)
The Design panel drew the page opacity as a "100 %" label, so it could not be changed from the panel although the model, page.setBackground and the colour picker already handled a translucent page. The label is now a percent number field like the other opacity fields (named Opacity for screen readers), committing page.setBackground; a scrub stays one undo step. The hex field keeps the current opacity unless the typed colour carries one, as the colour picker does. Regression test in field_tests. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
e04c5d2274
commit
40534ddf14
2 files changed
+71
-9
No files matched your search
@@ -1194,3 +1194,44 @@ fn sidebar_field_text_stays_in_place_on_focus() {
|
||||
assert!((before.center().y - after.center().y).abs() <= 0.5, "numeric={numeric}: before={before:?}, after={after:?}");
|
||||
}
|
||||
}
|
||||
|
||||
/// The Page section's opacity field edits the page background's alpha (#1748; it was a label),
|
||||
/// one undo step per commit, and the hex field keeps that opacity unless the typed colour
|
||||
/// carries its own.
|
||||
#[test]
|
||||
fn the_page_background_opacity_field_sets_the_page_colour_alpha() {
|
||||
let mut u = Ui::new(Session::new());
|
||||
u.ctx.enable_accesskit();
|
||||
u.frame(vec![]);
|
||||
let page_bg = |u: &Ui| {
|
||||
let page = u.app.session.page().unwrap();
|
||||
match &u.app.session.doc().unwrap().node(page).unwrap().kind {
|
||||
figcraft_doc::NodeKind::Page { background, .. } => *background,
|
||||
_ => panic!("the page"),
|
||||
}
|
||||
};
|
||||
// Within an 8-bit step: the colour travels as RRGGBBAA.
|
||||
let near = |a: f32, b: f32| (a - b).abs() < 1.0 / 255.0;
|
||||
assert!(near(page_bg(&u).a, 1.0));
|
||||
let steps = undo_steps(&u);
|
||||
type_into(&mut u, "Opacity", "50", Key::Enter);
|
||||
assert!(near(page_bg(&u).a, 0.5), "{:?}", page_bg(&u));
|
||||
assert_eq!(undo_steps(&u), steps + 1, "one undo step for the commit");
|
||||
// The hex field keeps the opacity when the typed colour has none, and takes one it carries.
|
||||
let hex = |u: &mut Ui| u.ctx.read_response(Id::unique("pagebg").with("click")).expect("the hex field").rect.center();
|
||||
let at = hex(&mut u);
|
||||
click(&mut u, at);
|
||||
u.frame(vec![Event::Text("FF0000".into())]);
|
||||
key(&mut u, Key::Enter, Modifiers::NONE);
|
||||
let c = page_bg(&u);
|
||||
assert!(near(c.r, 1.0) && near(c.g, 0.0) && near(c.a, 0.5), "{c:?}");
|
||||
let at = hex(&mut u);
|
||||
click(&mut u, at);
|
||||
u.frame(vec![Event::Text("00FF0080".into())]);
|
||||
key(&mut u, Key::Enter, Modifiers::NONE);
|
||||
let c = page_bg(&u);
|
||||
assert!(near(c.g, 1.0) && near(c.a, 128.0 / 255.0), "{c:?}");
|
||||
assert_eq!(undo_steps(&u), steps + 3);
|
||||
u.app.run("edit.undo", json!({}));
|
||||
assert!(near(page_bg(&u).r, 1.0) && near(page_bg(&u).a, 0.5), "undo takes back the last colour alone");
|
||||
}
|
||||
@@ -311,27 +311,48 @@ fn design(app: &mut FigApp, ui: &mut Ui) {
|
||||
/// Draw the page section: background and colour profile, local variables/styles, and the
|
||||
/// page export section.
|
||||
fn page_section(app: &mut FigApp, ui: &mut Ui, doc: &Document) {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
let Ok(page) = app.session.page() else { return };
|
||||
let bg = match doc.node(page).map(|n| &n.kind) {
|
||||
Some(NodeKind::Page { background, .. }) => *background,
|
||||
_ => figcraft_color::Color::DEFAULT_PAGE,
|
||||
};
|
||||
widgets::section_header(ui, tr("Page"), &[], false);
|
||||
let mut new_hex = None;
|
||||
// The new colour and, from a scrub, whether the scrub is over (live edits stay one undo step).
|
||||
let mut new_color: Option<(figcraft_color::Color, Option<bool>)> = None;
|
||||
row(ui, 32.0, |ui| {
|
||||
let p = Paint::solid(bg);
|
||||
let sw = widgets::swatch(ui, &p, 16.0);
|
||||
app.picker_control(crate::colorpicker::PickerTarget::PageBackground, &sw);
|
||||
if let Some(h) = widgets::text_field(ui, Id::unique("pagebg"), &bg.to_hex(), 96.0, "") {
|
||||
new_hex = Some(h);
|
||||
// A typed colour keeps the page's opacity unless it carries one (`FF000080`), as the
|
||||
// colour picker's hex field does.
|
||||
if let Some(h) = widgets::text_field(ui, Id::unique("pagebg"), &bg.to_hex(), 96.0, "")
|
||||
&& let Some(c) = figcraft_color::Color::from_hex_or_name(&h)
|
||||
{
|
||||
new_color = Some((c.with_alpha(if c.a < 1.0 { c.a } else { bg.a }), None));
|
||||
}
|
||||
// The opacity: a field like every other opacity field, not a label (#1748).
|
||||
let alpha = |v: f64| bg.with_alpha((v / 100.0).clamp(0.0, 1.0) as f32);
|
||||
let shown = Some(f64::from((bg.a * 100.0).round()));
|
||||
match widgets::number_field(ui, Id::unique("pagebg_a"), Lead::Named(tr("Opacity")), shown, "%", 56.0, 1.0) {
|
||||
Some(FieldEdit::Set(v)) => new_color = Some((alpha(v), None)),
|
||||
Some(FieldEdit::Scrub(v, done)) => new_color = Some((alpha(v), Some(done))),
|
||||
None => {}
|
||||
}
|
||||
widgets::label(ui, "100 %", t.text);
|
||||
});
|
||||
if let Some(h) = new_hex
|
||||
&& let Some(c) = figcraft_color::Color::from_hex_or_name(&h)
|
||||
{
|
||||
app.run("page.setBackground", json!({"color": c.to_css_hex()}));
|
||||
if let Some((c, scrub)) = new_color {
|
||||
let p = json!({"color": c.to_css_hex()});
|
||||
match scrub {
|
||||
None => {
|
||||
app.run("page.setBackground", p);
|
||||
}
|
||||
Some(done) => {
|
||||
let _ = app.session.begin_interaction("Page background");
|
||||
let _ = app.session.execute("page.setBackground", &p);
|
||||
if done {
|
||||
let _ = app.session.commit_interaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
widgets::separator(ui);
|
||||
widgets::section_header(ui, tr("Color profile"), &[], false);
|
||||
|
||||
Reference in new issue
Block a user