Differentiate between scale and dimensions (#570)

* Differentiate between scale and dimensions

* Fix layout and naming of properties
This commit is contained in:
TrueDoctor 2022-03-27 01:48:40 +01:00 committed by Keavon Chambers
parent 9ced465150
commit 0ee492a857
6 changed files with 114 additions and 52 deletions

View File

@ -22,6 +22,8 @@ pub enum PropertiesPanelMessage {
pub enum TransformOp {
X,
Y,
ScaleX,
ScaleY,
Width,
Height,
Rotation,

View File

@ -18,10 +18,10 @@ use std::f64::consts::PI;
use std::rc::Rc;
trait DAffine2Utils {
fn width(&self) -> f64;
fn update_width(self, new_width: f64) -> Self;
fn height(&self) -> f64;
fn update_height(self, new_height: f64) -> Self;
fn scale_x(&self) -> f64;
fn update_scale_x(self, new_width: f64) -> Self;
fn scale_y(&self) -> f64;
fn update_scale_y(self, new_height: f64) -> Self;
fn x(&self) -> f64;
fn update_x(self, new_x: f64) -> Self;
fn y(&self) -> f64;
@ -31,20 +31,20 @@ trait DAffine2Utils {
}
impl DAffine2Utils for DAffine2 {
fn width(&self) -> f64 {
fn scale_x(&self) -> f64 {
self.transform_vector2((1., 0.).into()).length()
}
fn update_width(self, new_width: f64) -> Self {
self * DAffine2::from_scale((new_width / self.width(), 1.).into())
fn update_scale_x(self, new_width: f64) -> Self {
self * DAffine2::from_scale((new_width / self.scale_x(), 1.).into())
}
fn height(&self) -> f64 {
fn scale_y(&self) -> f64 {
self.transform_vector2((0., 1.).into()).length()
}
fn update_height(self, new_height: f64) -> Self {
self * DAffine2::from_scale((1., new_height / self.height()).into())
fn update_scale_y(self, new_height: f64) -> Self {
self * DAffine2::from_scale((1., new_height / self.scale_y()).into())
}
fn x(&self) -> f64 {
@ -66,14 +66,14 @@ impl DAffine2Utils for DAffine2 {
}
fn rotation(&self) -> f64 {
let cos = self.matrix2.col(0).x / self.width();
let sin = self.matrix2.col(0).y / self.width();
let cos = self.matrix2.col(0).x / self.scale_x();
let sin = self.matrix2.col(0).y / self.scale_x();
sin.atan2(cos)
}
fn update_rotation(self, new_rotation: f64) -> Self {
let width = self.width();
let height = self.height();
let width = self.scale_x();
let height = self.scale_y();
let half_width = width / 2.;
let half_height = height / 2.;
@ -138,15 +138,21 @@ impl MessageHandler<PropertiesPanelMessage, &GrapheneDocument> for PropertiesPan
let action = match transform_op {
X => DAffine2::update_x,
Y => DAffine2::update_y,
Width => DAffine2::update_width,
Height => DAffine2::update_height,
ScaleX | Width => DAffine2::update_scale_x,
ScaleY | Height => DAffine2::update_scale_y,
Rotation => DAffine2::update_rotation,
};
let scale = match transform_op {
Width => layer.bounding_transform().scale_x() / layer.transform.scale_x(),
Height => layer.bounding_transform().scale_y() / layer.transform.scale_y(),
_ => 1.,
};
responses.push_back(
Operation::SetLayerTransform {
path: path.clone(),
transform: action(layer.transform, value).to_cols_array(),
transform: action(layer.transform, value / scale).to_cols_array(),
}
.into(),
);
@ -297,7 +303,7 @@ fn node_section_transform(layer: &Layer) -> LayoutRow {
name: "".into(),
widgets: vec![
WidgetHolder::new(Widget::TextLabel(TextLabel {
value: "Position".into(),
value: "Location".into(),
..TextLabel::default()
})),
WidgetHolder::new(Widget::Separator(Separator {
@ -336,6 +342,75 @@ fn node_section_transform(layer: &Layer) -> LayoutRow {
})),
],
},
LayoutRow::Row {
name: "".into(),
widgets: vec![
WidgetHolder::new(Widget::TextLabel(TextLabel {
value: "Rotation".into(),
..TextLabel::default()
})),
WidgetHolder::new(Widget::Separator(Separator {
separator_type: SeparatorType::Unrelated,
direction: SeparatorDirection::Horizontal,
})),
WidgetHolder::new(Widget::NumberInput(NumberInput {
value: layer.transform.rotation() * 180. / PI,
label: "".into(),
unit: "°".into(),
on_update: WidgetCallback::new(|number_input: &NumberInput| {
PropertiesPanelMessage::ModifyTransform {
value: number_input.value / 180. * PI,
transform_op: TransformOp::Rotation,
}
.into()
}),
..NumberInput::default()
})),
],
},
LayoutRow::Row {
name: "".into(),
widgets: vec![
WidgetHolder::new(Widget::TextLabel(TextLabel {
value: "Scale".into(),
..TextLabel::default()
})),
WidgetHolder::new(Widget::Separator(Separator {
separator_type: SeparatorType::Unrelated,
direction: SeparatorDirection::Horizontal,
})),
WidgetHolder::new(Widget::NumberInput(NumberInput {
value: layer.transform.scale_x(),
label: "X".into(),
unit: "".into(),
on_update: WidgetCallback::new(|number_input: &NumberInput| {
PropertiesPanelMessage::ModifyTransform {
value: number_input.value,
transform_op: TransformOp::ScaleX,
}
.into()
}),
..NumberInput::default()
})),
WidgetHolder::new(Widget::Separator(Separator {
separator_type: SeparatorType::Related,
direction: SeparatorDirection::Horizontal,
})),
WidgetHolder::new(Widget::NumberInput(NumberInput {
value: layer.transform.scale_y(),
label: "Y".into(),
unit: "".into(),
on_update: WidgetCallback::new(|number_input: &NumberInput| {
PropertiesPanelMessage::ModifyTransform {
value: number_input.value,
transform_op: TransformOp::ScaleY,
}
.into()
}),
..NumberInput::default()
})),
],
},
LayoutRow::Row {
name: "".into(),
widgets: vec![
@ -348,7 +423,7 @@ fn node_section_transform(layer: &Layer) -> LayoutRow {
direction: SeparatorDirection::Horizontal,
})),
WidgetHolder::new(Widget::NumberInput(NumberInput {
value: layer.transform.width(),
value: layer.bounding_transform().scale_x(),
label: "W".into(),
unit: " px".into(),
on_update: WidgetCallback::new(|number_input: &NumberInput| {
@ -365,7 +440,7 @@ fn node_section_transform(layer: &Layer) -> LayoutRow {
direction: SeparatorDirection::Horizontal,
})),
WidgetHolder::new(Widget::NumberInput(NumberInput {
value: layer.transform.height(),
value: layer.bounding_transform().scale_y(),
label: "H".into(),
unit: " px".into(),
on_update: WidgetCallback::new(|number_input: &NumberInput| {
@ -379,32 +454,6 @@ fn node_section_transform(layer: &Layer) -> LayoutRow {
})),
],
},
LayoutRow::Row {
name: "".into(),
widgets: vec![
WidgetHolder::new(Widget::TextLabel(TextLabel {
value: "Rotation".into(),
..TextLabel::default()
})),
WidgetHolder::new(Widget::Separator(Separator {
separator_type: SeparatorType::Unrelated,
direction: SeparatorDirection::Horizontal,
})),
WidgetHolder::new(Widget::NumberInput(NumberInput {
value: layer.transform.rotation() * 180. / PI,
label: "R".into(),
unit: "°".into(),
on_update: WidgetCallback::new(|number_input: &NumberInput| {
PropertiesPanelMessage::ModifyTransform {
value: number_input.value / 180. * PI,
transform_op: TransformOp::Rotation,
}
.into()
}),
..NumberInput::default()
})),
],
},
],
}
}

View File

@ -221,7 +221,7 @@ impl<'a> Selected<'a> {
.document
.layer(path)
.unwrap()
.current_bounding_box_with_transform(multiplied_transform)
.aabounding_box_for_transform(multiplied_transform)
.unwrap_or([multiplied_transform.translation; 2]);
(bounds[0] + bounds[1]) / 2.

View File

@ -81,7 +81,7 @@ impl Default for GradientToolFsmState {
/// Computes the transform from gradient space to layer space (where gradient space is 0..1 in layer space)
fn gradient_space_transform(path: &[LayerId], layer: &Layer, document: &DocumentMessageHandler) -> DAffine2 {
let bounds = layer.current_bounding_box().unwrap();
let bounds = layer.aabounding_box().unwrap();
let bound_transform = DAffine2::from_scale_angle_translation(bounds[1] - bounds[0], 0., bounds[0]);
document.graphene_document.multiply_transforms(&path[..path.len() - 1]).unwrap() * bound_transform

View File

@ -166,7 +166,7 @@ fn update_overlays(document: &DocumentMessageHandler, data: &mut TextToolData, r
.graphene_document
.layer(layer_path)
.unwrap()
.current_bounding_box_with_transform(document.graphene_document.multiply_transforms(layer_path).unwrap())
.aabounding_box_for_transform(document.graphene_document.multiply_transforms(layer_path).unwrap())
.unwrap();
let operation = Operation::SetLayerTransformInViewport {

View File

@ -146,12 +146,23 @@ impl Layer {
self.data.intersects_quad(transformed_quad, path, intersections)
}
pub fn current_bounding_box_with_transform(&self, transform: DAffine2) -> Option<[DVec2; 2]> {
pub fn aabounding_box_for_transform(&self, transform: DAffine2) -> Option<[DVec2; 2]> {
self.data.bounding_box(transform)
}
pub fn current_bounding_box(&self) -> Option<[DVec2; 2]> {
self.current_bounding_box_with_transform(self.transform)
pub fn aabounding_box(&self) -> Option<[DVec2; 2]> {
self.aabounding_box_for_transform(self.transform)
}
pub fn bounding_transform(&self) -> DAffine2 {
let scale = match self.aabounding_box_for_transform(DAffine2::IDENTITY) {
Some([a, b]) => {
let dimensions = b - a;
DAffine2::from_scale(dimensions)
}
_ => DAffine2::IDENTITY,
};
self.transform * scale
}
pub fn as_folder_mut(&mut self) -> Result<&mut FolderLayer, DocumentError> {