#1786: ink is translucent by its width in points, while drawn and once committed

Addresses CodeRabbit review on #3229, "Use the same translucency
threshold as committed ink": the preview judged the pen by its width in
points, the committed stroke by its width on screen, so at 50% a 12 pt
highlighter turned opaque once committed and at 200% a 6 pt pen turned
translucent. Both now use chartview::ink_color, which goes by the
stroke's width in points, so the two agree and neither changes with
the zoom.

Test: ink_render::ink_translucency_follows_the_pen_not_the_zoom.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Hector VillarrealandClaude Opus 5.5 committed 2026-11-03 03:58:23 -06:00
1 parent 2fe3bfc077
commit 2adfd5571f
4 files changed
+56 -3

No files matched your search

+9 -2
View File
@@ -316,11 +316,12 @@ pub(crate) fn paint_objects(app: &SheetApp, p: &Painter, geo: &Geo, wb: &Workboo
p.add(PathShape::convex_polygon(vec![pos2(r.center().x, r.top()), r.right_bottom(), r.left_bottom()], fill, Stroke::new(1.0, line)));
}
ShapeKind::Ink => {
let w = gridcraft_engine::cmd::draw::ink_width(sp) * geo.z;
let pt = gridcraft_engine::cmd::draw::ink_width(sp);
let w = pt * geo.z;
let pts: Vec<Pos2> =
gridcraft_engine::cmd::draw::ink_points(sp).iter().map(|q| pos2(r.left() + q[0] * geo.z, r.top() + q[1] * geo.z)).collect();
if pts.len() >= 2 {
let col = if w > 8.0 { line.gamma_multiply(0.45) } else { line };
let col = ink_color(line, pt);
p.add(PathShape::line(pts, PathStroke::new(w, col)));
}
label = false;
@@ -556,3 +557,9 @@ pub fn hit(app: &SheetApp, geo: &Geo, sh: &Sheet, p: Pos2) -> Option<(ObjRef, Re
}
None
}
/// The colour ink is painted in: a highlighter (a stroke over 8 pt wide) is translucent, by its
/// width in points, so the live pen stroke and the committed ink agree at every zoom.
pub(crate) fn ink_color(line: Color32, width_pt: f32) -> Color32 {
if width_pt > 8.0 { line.gamma_multiply(0.45) } else { line }
}
+1 -1
View File
@@ -257,7 +257,7 @@ pub(crate) fn pen_ink(color: &str, width: f32, theme: &gridcraft_engine::model::
let line = gridcraft_engine::model::Color::from_hex(color).unwrap_or(pen_blue);
let width = if width <= 0.0 { 2.0 } else { width }.clamp(0.5, 40.0).round().max(1.0);
let color = line.resolve(theme).map(crate::theme::color32).unwrap_or(Color32::from_rgb(0x1F, 0x5F, 0xC9));
(if width > 8.0 { color.gamma_multiply(0.45) } else { color }, width)
(crate::chartview::ink_color(color, width), width)
}
fn handle_header_autofit(app: &mut SheetApp, input: &InteractionInput<'_>) -> bool {
+45
View File
@@ -0,0 +1,45 @@
//! Committed ink is painted as the pen previews it, at any zoom.
use egui::Shape;
use egui::epaint::ColorMode;
use gridcraft_engine::Session;
use gridcraft_ui_egui::SheetApp;
use serde_json::json;
/// The colour of the ink stroke drawn from (40, 40) to (200, 40) sheet points, `width` points
/// wide: the two-point horizontal path whose width is `width` at its own scale (160 pt long).
fn painted_ink(h: &egui_kittest::Harness<'static, SheetApp>, width: f32) -> Option<egui::Color32> {
h.output().shapes.iter().find_map(|s| match &s.shape {
Shape::Path(p) if p.points.len() == 2 && (p.points[0].y - p.points[1].y).abs() < 0.01 => {
let z = (p.points[1].x - p.points[0].x).abs() / 160.0;
match p.stroke.color {
ColorMode::Solid(c) if z > 0.0 && (p.stroke.width - width * z).abs() < 0.01 => Some(c),
_ => None,
}
}
_ => None,
})
}
#[test]
fn ink_translucency_follows_the_pen_not_the_zoom() {
// A highlighter (over 8 pt) is translucent and a pen isn't, whatever the zoom: the committed
// stroke used its width on screen, so at 50% a 12 pt highlighter turned opaque and at 200% a
// 6 pt pen turned translucent, unlike the pen's preview.
for (width, zoom, translucent) in [(12.0_f32, 50, true), (6.0, 200, false), (12.0, 100, true), (6.0, 100, false)] {
let mut s = Session::new();
s.new_workbook();
s.execute("view.zoom", json!({"percent": zoom})).unwrap();
s.execute("draw.stroke", json!({"points": [[40, 40], [200, 40]], "color": "#FFFF00", "width": width})).unwrap();
let mut h = crate::common::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state(
|ui, app: &mut SheetApp| {
app.logic(&ui.ctx().clone());
app.ui(ui);
},
crate::common::app(s),
);
h.run_steps(4);
let c = painted_ink(&h, width).unwrap_or_else(|| panic!("the {width} pt stroke is painted at {zoom}%"));
assert_eq!(c.a() < 255, translucent, "{width} pt at {zoom}%: {c:?}");
}
}
+1
View File
@@ -58,6 +58,7 @@ mod hyperlink_ctrl_click;
mod hyperlink_dialog;
mod in_cell_editor_size;
mod in_cell_editor_wrap;
mod ink_render;
mod insert_copied_cells;
mod interaction;
mod interface_scale;