#885: every checkbox keeps a visible box at rest
The theme leaves egui's own checkbox without an outline while inactive, so an unchecked box was invisible and a checked one a bare tick. #1080 moved Preferences to widgets::check; the remaining ui.checkbox uses follow: the Properties panel's Snap to Point, Snap to Grid and Scale Strokes & Effects, Revolve's Keep visible surfaces and Shading, Save options, Export for Screens, the Variables dialog and plug-in forms. widgets::check_name shows a document's name (an artboard's, an asset's) as it is, never translated; the check and radio rows translate their labels in the public functions, so choice_row draws text as given. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
389f75fa7b
commit
c4e139af19
File diff suppressed because one or more lines are too long
|
|
@ -353,8 +353,10 @@ fn artboards(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) {
|
|||
ui.painter().rect_filled(r, 2.0, egui::Color32::WHITE);
|
||||
}
|
||||
}
|
||||
if let Some(b) = boards.get_mut(i) {
|
||||
ui.checkbox(b, name);
|
||||
if let Some(b) = boards.get_mut(i)
|
||||
&& crate::widgets::check_name(ui, name, *b)
|
||||
{
|
||||
*b ^= true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -399,10 +401,10 @@ fn assets(app: &VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) {
|
|||
ui.horizontal(|ui| {
|
||||
let (r, _) = ui.allocate_exact_size(egui::vec2(46.0, 46.0), egui::Sense::hover());
|
||||
crate::panels::asset_export::paint_thumb(ui, st, a, r);
|
||||
let mut checked = on.contains(&a.id);
|
||||
if ui.checkbox(&mut checked, a.name.as_str()).changed() {
|
||||
let checked = on.contains(&a.id);
|
||||
if crate::widgets::check_name(ui, &a.name, checked) {
|
||||
on.retain(|id| *id != a.id);
|
||||
if checked {
|
||||
if !checked {
|
||||
on.push(a.id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -320,8 +320,8 @@ pub(super) fn schema_fields(ui: &mut egui::Ui, d: &mut Dialog, specs: &[(String,
|
|||
crate::widgets::range_field(ui, ("plugin-int", k), x, *min as f64..=*max as f64, "", 0, 100.0).map(|x| json!(x as i64))
|
||||
}
|
||||
ParamSpec::Bool { .. } => {
|
||||
let mut b = cur.as_bool().unwrap_or(false);
|
||||
ui.checkbox(&mut b, "").changed().then(|| json!(b))
|
||||
let b = cur.as_bool().unwrap_or(false);
|
||||
crate::widgets::check(ui, "", b, true).then(|| json!(!b))
|
||||
}
|
||||
ParamSpec::Choice { options, .. } => {
|
||||
let labels: Vec<&str> = options.iter().map(String::as_str).collect();
|
||||
|
|
|
|||
|
|
@ -93,14 +93,15 @@ fn controls(app: &VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) {
|
|||
super::form::check(ui, d, "__showAxis", tl!("Show axis"));
|
||||
ui.add_space(6.0);
|
||||
ui.horizontal(|ui| {
|
||||
let mut visible = d.fields.get("expandVisibleOnly").and_then(Value::as_bool).unwrap_or(true);
|
||||
let response = ui.allocate_ui_with_layout(
|
||||
let visible = d.fields.get("expandVisibleOnly").and_then(Value::as_bool).unwrap_or(true);
|
||||
let tip = tl!("Trim covered geometry on Expand Appearance. Live preview keeps the full surface. Transparent paints and surfaces exceeding visibility limits retain all faces.");
|
||||
let toggled = ui.allocate_ui_with_layout(
|
||||
vec2((ui.available_width() - 30.0).max(100.0), 24.0), egui::Layout::left_to_right(egui::Align::Center), |ui| {
|
||||
ui.checkbox(&mut visible, egui::RichText::new(tl!("Keep visible surfaces only when expanding")).size(12.0))
|
||||
widgets::check_tip(ui, tl!("Keep visible surfaces only when expanding"), visible, true, tip)
|
||||
},
|
||||
).inner;
|
||||
if response.on_hover_text(tl!("Trim covered geometry on Expand Appearance. Live preview keeps the full surface. Transparent paints and surfaces exceeding visibility limits retain all faces.")).changed() {
|
||||
d.fields.insert("expandVisibleOnly".into(), json!(visible));
|
||||
if toggled {
|
||||
d.fields.insert("expandVisibleOnly".into(), json!(!visible));
|
||||
}
|
||||
if reset_dot(ui, "expandVisibleOnly", !visible, "true") {
|
||||
d.fields.insert("expandVisibleOnly".into(), json!(true));
|
||||
|
|
@ -111,9 +112,9 @@ fn controls(app: &VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) {
|
|||
|
||||
fn lighting_controls(ui: &mut egui::Ui, d: &mut Dialog) {
|
||||
ui.horizontal(|ui| {
|
||||
let mut shade = d.bool("shade");
|
||||
if ui.checkbox(&mut shade, tl!("Shading")).changed() {
|
||||
d.fields.insert("shade".into(), json!(shade));
|
||||
let shade = d.bool("shade");
|
||||
if widgets::check(ui, tl!("Shading"), shade, true) {
|
||||
d.fields.insert("shade".into(), json!(!shade));
|
||||
}
|
||||
ui.add_space((ui.available_width() - 24.0).max(0.0));
|
||||
if reset_dot(ui, "shade", !shade, "true") {
|
||||
|
|
|
|||
|
|
@ -145,9 +145,9 @@ fn option_row(app: &VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog, o: &Forma
|
|||
let value = d.fields.get(o.name).cloned().unwrap_or(Value::Null);
|
||||
if o.ty == "boolean" {
|
||||
ui.label("");
|
||||
let mut on = value.as_bool().unwrap_or(false);
|
||||
if ui.checkbox(&mut on, label.trim_end_matches(':')).on_hover_text(o.description).changed() {
|
||||
d.fields.insert(o.name.into(), json!(on));
|
||||
let on = value.as_bool().unwrap_or(false);
|
||||
if widgets::check_tip(ui, label.trim_end_matches(':'), on, true, o.description) {
|
||||
d.fields.insert(o.name.into(), json!(!on));
|
||||
}
|
||||
ui.end_row();
|
||||
if o.name == "separateArtboards" {
|
||||
|
|
|
|||
|
|
@ -202,9 +202,11 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
|
|||
label(ui, &v.name);
|
||||
let key = value_key(&v.name);
|
||||
match v.kind {
|
||||
VariableKind::Text => text(ui, d, &key, 220.0),
|
||||
VariableKind::Text => {
|
||||
text(ui, d, &key, 220.0);
|
||||
}
|
||||
VariableKind::Visibility => checkbox(ui, d, &key),
|
||||
};
|
||||
}
|
||||
ui.end_row();
|
||||
}
|
||||
}
|
||||
|
|
@ -224,13 +226,11 @@ fn text(ui: &mut egui::Ui, d: &mut Dialog, key: &str, width: f32) -> egui::Respo
|
|||
}
|
||||
|
||||
/// A checkbox for `key`, written back as it is toggled.
|
||||
fn checkbox(ui: &mut egui::Ui, d: &mut Dialog, key: &str) -> egui::Response {
|
||||
let mut b = d.bool(key);
|
||||
let r = ui.checkbox(&mut b, "");
|
||||
if r.changed() {
|
||||
d.fields.insert(key.into(), json!(b));
|
||||
fn checkbox(ui: &mut egui::Ui, d: &mut Dialog, key: &str) {
|
||||
let b = d.bool(key);
|
||||
if widgets::check(ui, "", b, true) {
|
||||
d.fields.insert(key.into(), json!(!b));
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
/// A dropdown over the document's names `options` (shown as they are, never translated) for
|
||||
|
|
|
|||
|
|
@ -356,13 +356,11 @@ fn document_sections(app: &mut VectorcraftApp, ui: &mut Ui) {
|
|||
});
|
||||
divider(ui);
|
||||
section_header(ui, tl!("Snap Options"));
|
||||
let mut sp = app.ui.view.snap_to_point;
|
||||
if ui.checkbox(&mut sp, tl!("Snap to Point")).changed() {
|
||||
app.ui.view.snap_to_point = sp;
|
||||
if widgets::check(ui, tl!("Snap to Point"), app.ui.view.snap_to_point, true) {
|
||||
app.ui.view.snap_to_point ^= true;
|
||||
}
|
||||
let mut sg = app.ui.view.snap_to_grid;
|
||||
if ui.checkbox(&mut sg, tl!("Snap to Grid")).changed() {
|
||||
app.ui.view.snap_to_grid = sg;
|
||||
if widgets::check(ui, tl!("Snap to Grid"), app.ui.view.snap_to_grid, true) {
|
||||
app.ui.view.snap_to_grid ^= true;
|
||||
}
|
||||
divider(ui);
|
||||
section_header(ui, tl!("Preferences"));
|
||||
|
|
@ -373,9 +371,9 @@ fn document_sections(app: &mut VectorcraftApp, ui: &mut Ui) {
|
|||
app.session.prefs.keyboard_increment = v.max(0.001);
|
||||
}
|
||||
});
|
||||
let mut ss = app.session.prefs.scale_strokes;
|
||||
if ui.checkbox(&mut ss, tl!("Scale Strokes & Effects")).changed() {
|
||||
super::transform::set_pref(app, "scaleStrokes", ss);
|
||||
let ss = app.session.prefs.scale_strokes;
|
||||
if widgets::check(ui, tl!("Scale Strokes & Effects"), ss, true) {
|
||||
super::transform::set_pref(app, "scaleStrokes", !ss);
|
||||
}
|
||||
divider(ui);
|
||||
section_header(ui, tl!("Quick Actions"));
|
||||
|
|
@ -584,6 +582,40 @@ mod tests {
|
|||
frame(app, ctx, vec![b(false)]);
|
||||
}
|
||||
|
||||
/// The Snap Options and Scale Strokes & Effects checkboxes keep a visible box at rest in every
|
||||
/// theme, as the Preferences ones do (#1080), and toggle when clicked.
|
||||
#[test]
|
||||
fn the_document_checkboxes_show_their_boxes_and_toggle() {
|
||||
for brightness in crate::theme::Brightness::ALL {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.run("file.new", json!({"width": 200, "height": 100})).unwrap();
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
crate::theme::apply(&ctx, brightness);
|
||||
frame(&mut app, &ctx, vec![]);
|
||||
let raw = egui::RawInput { screen_rect: Some(Rect::from_min_size(Pos2::ZERO, vec2(300.0, 700.0))), ..Default::default() };
|
||||
let mut out = ctx.run_ui(raw, |ui| show(&mut app, ui));
|
||||
out.textures_delta.clear();
|
||||
let boxes = out
|
||||
.shapes
|
||||
.iter()
|
||||
.filter(|s| matches!(&s.shape, egui::Shape::Rect(r) if r.stroke.width > 0.0 && (r.rect.width() - 13.0).abs() < 0.5 && (r.rect.height() - 13.0).abs() < 0.5))
|
||||
.count();
|
||||
assert!(boxes >= 3, "{brightness:?}: {boxes} checkbox outlines");
|
||||
}
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.run("file.new", json!({"width": 200, "height": 100})).unwrap();
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
let texts = frame(&mut app, &ctx, vec![]);
|
||||
let (grid, strokes) = (app.ui.view.snap_to_grid, app.session.prefs.scale_strokes);
|
||||
click(&mut app, &ctx, &texts, "Snap to Grid");
|
||||
assert_eq!(app.ui.view.snap_to_grid, !grid);
|
||||
let texts = frame(&mut app, &ctx, vec![]);
|
||||
click(&mut app, &ctx, &texts, "Scale Strokes & Effects");
|
||||
assert_eq!(app.session.prefs.scale_strokes, !strokes);
|
||||
}
|
||||
|
||||
/// #921: with the Gradient tool, a Gradient section: the type, and for a freeform gradient
|
||||
/// Draw as Points or Lines radio buttons.
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -982,12 +982,11 @@ pub fn link_label(ui: &mut Ui, text: &str) -> Response {
|
|||
resp
|
||||
}
|
||||
|
||||
/// The row of a checkbox or radio button: allocates a 13 pt box plus `label`, draws the label and
|
||||
/// returns the box, the response and the box's border colour.
|
||||
fn choice_row(ui: &mut Ui, label: &str, enabled: bool) -> (Rect, Response, Color32) {
|
||||
/// The row of a checkbox or radio button: allocates a 13 pt box plus `text` (already translated),
|
||||
/// draws the text and returns the box, the response and the box's border colour.
|
||||
fn choice_row(ui: &mut Ui, text: &str, enabled: bool) -> (Rect, Response, Color32) {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
let galley =
|
||||
ui.painter().layout_no_wrap(tl!(label).to_string(), egui::FontId::proportional(12.5), if enabled { t.text } else { t.text_disabled });
|
||||
let galley = ui.painter().layout_no_wrap(text.to_string(), egui::FontId::proportional(12.5), if enabled { t.text } else { t.text_disabled });
|
||||
let (rect, resp) =
|
||||
ui.allocate_exact_size(vec2(18.0 + galley.size().x, 20.0f32.max(galley.size().y)), if enabled { Sense::click() } else { Sense::hover() });
|
||||
let bx = Rect::from_min_size(pos2(rect.left(), rect.center().y - 6.5), Vec2::splat(13.0));
|
||||
|
|
@ -1009,21 +1008,27 @@ pub fn check(ui: &mut Ui, label: &str, value: bool, enabled: bool) -> bool {
|
|||
|
||||
/// [`check`] with tooltip `tip` on the box and its label. Returns true when toggled.
|
||||
pub fn check_tip(ui: &mut Ui, label: &str, value: bool, enabled: bool, tip: &str) -> bool {
|
||||
let (clicked, resp) = check_row(ui, label, Some(value), enabled);
|
||||
let (clicked, resp) = check_row(ui, tl!(label), Some(value), enabled);
|
||||
resp.on_hover_text(tip);
|
||||
clicked
|
||||
}
|
||||
|
||||
/// Three-state [`check`]: `None` shows a dash (a neutral or mixed state). Returns true when clicked.
|
||||
pub fn check3(ui: &mut Ui, label: &str, value: Option<bool>, enabled: bool) -> bool {
|
||||
check_row(ui, label, value, enabled).0
|
||||
check_row(ui, tl!(label), value, enabled).0
|
||||
}
|
||||
|
||||
/// [`check3`], also returning the row's response (what a tooltip goes on: a widget around it never
|
||||
/// counts as hovered under the box).
|
||||
fn check_row(ui: &mut Ui, label: &str, value: Option<bool>, enabled: bool) -> (bool, Response) {
|
||||
/// [`check`] for a name of the document's (an artboard's, an asset's), shown as it is, never
|
||||
/// translated. Returns true when toggled.
|
||||
pub fn check_name(ui: &mut Ui, name: &str, value: bool) -> bool {
|
||||
check_row(ui, name, Some(value), true).0
|
||||
}
|
||||
|
||||
/// [`check3`] with its `text` already translated, also returning the row's response (what a
|
||||
/// tooltip goes on: a widget around it never counts as hovered under the box).
|
||||
fn check_row(ui: &mut Ui, text: &str, value: Option<bool>, enabled: bool) -> (bool, Response) {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
let (bx, resp, border) = choice_row(ui, label, enabled);
|
||||
let (bx, resp, border) = choice_row(ui, text, enabled);
|
||||
let checked = value == Some(true);
|
||||
ui.painter().rect_filled(bx, CornerRadius::same(2), if checked && enabled { t.accent_strong } else { t.input });
|
||||
ui.painter().rect_stroke(bx, CornerRadius::same(2), Stroke::new(1.0, border), StrokeKind::Inside);
|
||||
|
|
@ -1045,7 +1050,7 @@ fn check_row(ui: &mut Ui, label: &str, value: Option<bool>, enabled: bool) -> (b
|
|||
/// Radio button in the style of [`check`], with a disabled state. Returns true when clicked.
|
||||
pub fn radio(ui: &mut Ui, label: &str, selected: bool, enabled: bool) -> bool {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
let (bx, resp, border) = choice_row(ui, label, enabled);
|
||||
let (bx, resp, border) = choice_row(ui, tl!(label), enabled);
|
||||
let c = bx.center();
|
||||
ui.painter().circle(c, 6.0, if selected && enabled { t.accent_strong } else { t.input }, Stroke::new(1.0, border));
|
||||
if selected {
|
||||
|
|
|
|||
Loading…
Reference in New Issue