Comments: an opacity control in the quick bar (per tool, 10-100 %)
The comment tools' quick bar had colour and line thickness but no opacity, though comments already carry it (/CA) and the Properties dialog edits it. An Opacity slider joins them for every tool; set_opacity clamps to 10-100 % so a comment can't be made invisible. Test: a strikeout made at 50 % carries /CA 0.5. Parity comment.properties-bar: shipped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
c02e1e91c2
commit
b4e1d488de
|
|
@ -275,6 +275,13 @@ impl CommentPrefs {
|
|||
}
|
||||
}
|
||||
|
||||
/// The tool's opacity, 10–100 % (an invisible comment can't be found again).
|
||||
pub fn set_opacity(&mut self, tool: CommentTool, o: f64) {
|
||||
if let Some((_, s)) = self.styles.iter_mut().find(|(t, _)| *t == tool) {
|
||||
s.opacity = if o.is_finite() { o.clamp(0.1, 1.0) } else { 1.0 };
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_style(&mut self, tool: CommentTool, style: Style) {
|
||||
if let Some((_, s)) = self.styles.iter_mut().find(|(t, _)| *t == tool) {
|
||||
*s = style;
|
||||
|
|
@ -1253,7 +1260,7 @@ pub fn swatch_grid(ui: &mut egui::Ui, current: Option<Rgb>) -> Option<Rgb> {
|
|||
picked
|
||||
}
|
||||
|
||||
/// The comment tools' extra quick-bar controls: pin, colour and thickness.
|
||||
/// The comment tools' extra quick-bar controls: pin, colour, opacity and thickness.
|
||||
pub(crate) fn quick_bar_controls(ui: &mut egui::Ui, tool: CommentTool, prefs: &mut CommentPrefs) {
|
||||
let style = prefs.style(tool);
|
||||
if icons::button(ui, "pin", 32.0, prefs.pinned, if prefs.pinned { "Keep tool selected: on" } else { "Keep tool selected" }).clicked() {
|
||||
|
|
@ -1269,6 +1276,15 @@ pub(crate) fn quick_bar_controls(ui: &mut egui::Ui, tool: CommentTool, prefs: &m
|
|||
ui.close();
|
||||
}
|
||||
});
|
||||
let resp = icons::button(ui, "blend", 32.0, false, "Opacity");
|
||||
egui::Popup::menu(&resp).align(egui::RectAlign::RIGHT_START).close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside).show(|ui| {
|
||||
ui.set_min_width(180.0);
|
||||
let mut percent = (style.opacity * 100.0).round();
|
||||
ui.label(egui::RichText::new("Opacity").font(theme::semibold(12.0)));
|
||||
if ui.add(egui::Slider::new(&mut percent, 10.0..=100.0).step_by(5.0).suffix(" %")).changed() {
|
||||
prefs.set_opacity(tool, percent / 100.0);
|
||||
}
|
||||
});
|
||||
if tool.has_width() {
|
||||
let resp = icons::button(ui, "sliders-horizontal", 32.0, false, "Line thickness");
|
||||
egui::Popup::menu(&resp).align(egui::RectAlign::RIGHT_START).close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside).show(|ui| {
|
||||
|
|
|
|||
|
|
@ -568,3 +568,33 @@ fn the_squiggly_tool_marks_selected_text() {
|
|||
assert!(printcraft_ui_egui::comments::GROUPS[1].contains(&printcraft_ui_egui::comments::CommentTool::Squiggly));
|
||||
assert_eq!(printcraft_ui_egui::comments::tool_for(&c[0]), Some(printcraft_ui_egui::comments::CommentTool::Squiggly));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_opacity_set_for_a_tool_goes_into_its_new_comments() {
|
||||
use printcraft_ui_egui::comments::CommentTool;
|
||||
let mut h = harness(|app| app.comment_prefs.set_opacity(CommentTool::StrikeOut, 0.5));
|
||||
// Clamped: an invisible comment can't be found again.
|
||||
h.state_mut().comment_prefs.set_opacity(CommentTool::Underline, 0.0);
|
||||
assert!((h.state().comment_prefs.style(CommentTool::Underline).opacity - 0.1).abs() < 1e-9);
|
||||
h.state_mut().views[0].select_text(0, 4, 8);
|
||||
assert!(h.state_mut().execute("comment.strikeout"));
|
||||
h.run_steps(2);
|
||||
let c = comments(&h);
|
||||
assert_eq!(c.len(), 1, "{c:?}");
|
||||
// The new comment carries /CA 0.5 (read back from the document's bytes).
|
||||
let bytes = h.state().session.get(h.state().views[0].id).unwrap().bytes.as_ref().clone();
|
||||
let doc = printcraft_cos::Document::open(std::sync::Arc::new(bytes)).unwrap();
|
||||
let opacities: Vec<f64> = doc
|
||||
.object_numbers()
|
||||
.into_iter()
|
||||
.filter_map(|n| doc.try_get(n).ok())
|
||||
.filter_map(|o| o.as_dict().cloned())
|
||||
.filter(|d| d.name(b"Subtype") == Some(b"StrikeOut"))
|
||||
.filter_map(|d| d.get(b"CA").and_then(|v| v.as_f64()))
|
||||
.collect();
|
||||
assert_eq!(opacities, [0.5]);
|
||||
// The quick bar offers the control.
|
||||
h.state_mut().set_option("quick", "strikeout").unwrap();
|
||||
h.run_steps(2);
|
||||
h.get_by_label("Opacity");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3767,11 +3767,11 @@ title = "Comment properties bar"
|
|||
area = "E"
|
||||
tier = "P1"
|
||||
milestone = "M5"
|
||||
status = "partial"
|
||||
status = "shipped"
|
||||
commands = ["comment.note"]
|
||||
tools = ["comment_edit"]
|
||||
evidence = ["crates/annot/src/tests.rs::restyle_and_resize_redraw_the_appearance"]
|
||||
notes = "quick-bar colour swatches and line thickness per tool, colour from the context menu; no opacity control in the UI yet"
|
||||
evidence = ["crates/annot/src/tests.rs::restyle_and_resize_redraw_the_appearance", "crates/ui-egui/tests/comments.rs::the_opacity_set_for_a_tool_goes_into_its_new_comments"]
|
||||
notes = "quick-bar colour swatches, opacity (10–100 %) and line thickness per tool; colour from the context menu"
|
||||
|
||||
[[feature]]
|
||||
id = "comment.lock-comment"
|
||||
|
|
|
|||
Loading…
Reference in New Issue