Files
vectorcraft/crates/ui-egui/src/dialogs/halftone.rs
T
bflatastic f4c245286e Add-ons: Color Effects — live Vector Halftone effect
Effect › Color Effects › Vector Halftone… (addon.color.halftone, also in
Object › Plug-ins › Color Effects) draws its object as the halftone dots
Object › Vector Halftone makes, live: mono (one dot colour, or each dot in
the art's colour under it) or CMYK screens, the five dot shapes,
frequency, angle, invert and clip to the art's outline.

- The screens, dots and caps move to vectorcraft_effects::addons::halftone,
  shared by the command (its behaviour and tests unchanged) and the effect.
- The renderer samples the art (vectorcraft_render::addons::halftone) and
  keeps the dots by the object's content and what it reads from the
  document, so unchanged art isn't sampled again; past 100000 cells per
  screen the object draws as it is.
- Expand Appearance turns the object into its dots, and the SVG, PDF, EPS
  and AI exporters write them as paths.
- Its dialog reuses the command's fields, without Keep Original.

Deferred: stochastic and radial patterns, a dot-gain curve, per-screen
separation settings, type or symbols as dots.
2026-10-30 22:13:33 +07:00

69 lines
3.0 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Object → Vector Halftone: the dot shape, the screen frequency and angle, mono (in one colour)
//! or CMYK screens, Invert, Clip to Art and Keep Original, previewed live on the canvas; OK keeps
//! the preview as one undo step (`object.vectorHalftone`).
//!
//! Fields: `shape`, `frequency`, `angle`, `mode`, `color`, `invert`, `clip`, `keepOriginal` (the
//! command's parameters) and `preview`. The live effect's dialog shows the same fields but Keep
//! Original ([`screen_fields`]).
use serde_json::{Value, json};
use vectorcraft_color::Color;
use super::{DialogSpec, form};
use crate::panels::c32;
use crate::state::Dialog;
use crate::{VectorcraftApp, widgets};
/// The dialog kind of Vector Halftone.
pub const KIND: &str = "vectorHalftone";
const CMD: &str = "object.vectorHalftone";
/// Width of the label column.
const LABEL_W: f32 = 84.0;
pub(super) const SPEC: DialogSpec = DialogSpec { heading: |_| tl!("Vector Halftone").into(), body, confirm, preview: true, ..DialogSpec::FORM };
/// The dialog's fields as it opens: the command's defaults, previewed.
pub fn fields() -> Value {
json!({"shape": "circle", "frequency": 20, "angle": 45, "mode": "mono", "color": "#000000", "invert": false, "clip": true, "keepOriginal": false, "preview": true})
}
fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
screen_fields(ui, d);
form::check(ui, d, "keepOriginal", tl!("Keep Original"));
let p = form::params(d);
form::preview(app, ui, d, "Vector Halftone", CMD, p);
false
}
/// The fields Object › Vector Halftone and the live effect (Effect › Color Effects › Vector
/// Halftone…) share: the dot shape, the screen frequency and angle, mono or CMYK screens, the dot
/// colour (or, with the effect's `fromArt`, the art's), Invert and Clip to Art.
pub(super) fn screen_fields(ui: &mut egui::Ui, d: &mut Dialog) {
let shapes =
[("circle", tl!("Circle")), ("ellipse", tl!("Ellipse")), ("square", tl!("Square")), ("diamond", tl!("Diamond")), ("line", tl!("Line"))];
form::choice(ui, d, "shape", tl!("Shape"), (LABEL_W, 140.0), &shapes);
form::slider_w(ui, d, ("frequency", tl!("Frequency"), LABEL_W), 1.0..=150.0, " lpi", &|x| c32(&Color::gray(1.0 - x)));
form::slider_w(ui, d, ("angle", tl!("Angle"), LABEL_W), -90.0..=90.0, "°", &|x| c32(&Color::gray(0.2 + 0.6 * x)));
form::choice(ui, d, "mode", tl!("Screens"), (LABEL_W, 140.0), &[("mono", tl!("Mono")), ("cmyk", tl!("CMYK"))]);
if d.str("mode") != "cmyk" {
if d.fields.contains_key("fromArt") {
form::check(ui, d, "fromArt", tl!("Dot Color from Art"));
}
if !d.bool("fromArt") {
widgets::label_row(ui, tl!("Color"), LABEL_W, |ui| {
form::text(ui, d, "color", 120.0);
});
}
}
ui.add_space(4.0);
for (key, label) in [("invert", tl!("Invert")), ("clip", tl!("Clip to Art"))] {
form::check(ui, d, key, label);
}
}
fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
form::commit_preview(app, CMD, form::params(d))
}