mirror of
https://github.com/storytold/photocraft.git
synced 2026-11-15 14:43:28 +00:00
Free Transform: W/H fields reach 1000000% and X/Y the 300000 px document limit (#1267)
The options bar clamped W/H to ±10000% and X/Y to ±30000 px, while the engine takes any scale and documents go up to 300000 px a side. Overlays on large stitched mosaics need more. The limits are now named constants: ±1000000% (a 300 px layer can span the largest document) and ±300000 px.
This commit is contained in:
1 parent
3bab0d4f52
commit
bb723b12eb
1 file changed
+49
-4
@@ -1305,6 +1305,12 @@ fn readout(t: &TransformSession) -> (f64, f64, f64, f64) {
|
||||
/// Width of the mode, cancel and commit cluster kept on the right of the options bar.
|
||||
const ACTIONS_W: f32 = 140.0;
|
||||
|
||||
/// Reach of the reference point X/Y fields: the largest document side (`image.canvasSize`'s limit).
|
||||
const POSITION_LIMIT_PX: f32 = 300_000.0;
|
||||
/// Reach of the W/H fields. The engine takes any scale; this lets a 300 px layer span the largest
|
||||
/// document (#1267).
|
||||
const SCALE_LIMIT_PCT: f32 = 1_000_000.0;
|
||||
|
||||
/// Options bar while transforming: reference point X/Y, W/H %, angle, interpolation, and, pinned
|
||||
/// to the right, the warp switch, cancel and commit.
|
||||
pub fn options_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
|
||||
@@ -1336,9 +1342,9 @@ fn transform_fields(app: &mut PhotocraftApp, ui: &mut egui::Ui, t: &TransformSes
|
||||
let mut px = t.pivot[0] as f32;
|
||||
let mut py = t.pivot[1] as f32;
|
||||
lbl(ui, "X:");
|
||||
let rx = crate::widgets::value_field(ui, &mut px, -30000.0..=30000.0, "px", 72.0);
|
||||
let rx = crate::widgets::value_field(ui, &mut px, -POSITION_LIMIT_PX..=POSITION_LIMIT_PX, "px", 72.0);
|
||||
lbl(ui, "Y:");
|
||||
let ry = crate::widgets::value_field(ui, &mut py, -30000.0..=30000.0, "px", 72.0);
|
||||
let ry = crate::widgets::value_field(ui, &mut py, -POSITION_LIMIT_PX..=POSITION_LIMIT_PX, "px", 72.0);
|
||||
if (rx.changed() || ry.changed())
|
||||
&& let Some(s) = app.ui.transform.as_mut()
|
||||
{
|
||||
@@ -1349,7 +1355,7 @@ fn transform_fields(app: &mut PhotocraftApp, ui: &mut egui::Ui, t: &TransformSes
|
||||
crate::widgets::vline(ui, 22.0);
|
||||
let (mut w, mut h) = (sx as f32, sy as f32);
|
||||
lbl(ui, "W:");
|
||||
let rw = crate::widgets::value_field(ui, &mut w, -10000.0..=10000.0, "%", 66.0);
|
||||
let rw = crate::widgets::value_field(ui, &mut w, -SCALE_LIMIT_PCT..=SCALE_LIMIT_PCT, "%", 66.0);
|
||||
let link_id = egui::Id::new("transform-link");
|
||||
let mut link: bool = ui.data(|d| d.get_temp(link_id)).unwrap_or(true);
|
||||
if crate::icons::button(ui, if link { "link" } else { "unlink" }, 22.0, link, tl!("Maintain aspect ratio")).clicked() {
|
||||
@@ -1357,7 +1363,7 @@ fn transform_fields(app: &mut PhotocraftApp, ui: &mut egui::Ui, t: &TransformSes
|
||||
ui.data_mut(|d| d.insert_temp(link_id, link));
|
||||
}
|
||||
lbl(ui, "H:");
|
||||
let rh = crate::widgets::value_field(ui, &mut h, -10000.0..=10000.0, "%", 66.0);
|
||||
let rh = crate::widgets::value_field(ui, &mut h, -SCALE_LIMIT_PCT..=SCALE_LIMIT_PCT, "%", 66.0);
|
||||
if rw.changed() || rh.changed() {
|
||||
let (kx, ky) = if link {
|
||||
let k = if rw.changed() { w as f64 / sx.max(1e-9) } else { h as f64 / sy.max(1e-9) };
|
||||
@@ -1631,6 +1637,45 @@ mod tests {
|
||||
assert!(h.state().ui.transform.is_none());
|
||||
}
|
||||
|
||||
/// Types `text` + Enter into the `n`th numeric field of the transform bar (X, Y, W, H, angle…).
|
||||
fn type_into_bar_field(n: usize, text: &str) -> TransformSession {
|
||||
use egui_kittest::Harness;
|
||||
use egui_kittest::kittest::Queryable;
|
||||
let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());
|
||||
app.ui.transform = Some(session());
|
||||
let mut h = Harness::builder().with_size(vec2(900.0, 48.0)).build_ui_state(
|
||||
|ui, app: &mut PhotocraftApp| {
|
||||
if !ui.ctx().fonts(|f| f.families().contains(&egui::FontFamily::Name("medium".into()))) {
|
||||
return;
|
||||
}
|
||||
ui.horizontal_centered(|ui| options_bar(app, ui));
|
||||
},
|
||||
app,
|
||||
);
|
||||
PhotocraftApp::setup_context(&h.ctx, crate::theme::ThemeKind::Studio);
|
||||
h.run_steps(6);
|
||||
h.get_all_by_role(egui::accesskit::Role::SpinButton).nth(n).unwrap().click();
|
||||
h.run();
|
||||
for c in text.chars() {
|
||||
h.event(egui::Event::Text(c.to_string()));
|
||||
h.run();
|
||||
}
|
||||
h.key_press(egui::Key::Enter);
|
||||
h.run_steps(2);
|
||||
h.state().ui.transform.clone().unwrap()
|
||||
}
|
||||
|
||||
/// Large documents need scales past 10000% and positions past 30000 px (#1267).
|
||||
#[test]
|
||||
fn transform_fields_reach_large_documents() {
|
||||
let t = type_into_bar_field(2, "15000");
|
||||
let (sx, sy, _, _) = readout(&t);
|
||||
assert!((sx - 15000.0).abs() < 0.5 && (sy - 15000.0).abs() < 0.5, "{sx} {sy}");
|
||||
assert!((t.quad[1][0] - t.quad[0][0] - 15_000.0).abs() < 1.0, "{:?}", t.quad);
|
||||
let t = type_into_bar_field(0, "250000");
|
||||
assert!((t.pivot[0] - 250_000.0).abs() < 1.0, "{:?}", t.pivot);
|
||||
}
|
||||
|
||||
fn drag(s: &mut TransformSession, from: [f64; 2], to: [f64; 2], mods: egui::Modifiers) {
|
||||
let g = Gesture { hit: hit(s, from, 8.0), start: from, quad0: s.quad, pivot0: s.pivot };
|
||||
apply_drag(s, g, to, mods);
|
||||
|
||||
Reference in new issue
Block a user