Differentiate between scale and dimensions (#570)
* Differentiate between scale and dimensions * Fix layout and naming of properties
This commit is contained in:
parent
9ced465150
commit
0ee492a857
|
|
@ -22,6 +22,8 @@ pub enum PropertiesPanelMessage {
|
|||
pub enum TransformOp {
|
||||
X,
|
||||
Y,
|
||||
ScaleX,
|
||||
ScaleY,
|
||||
Width,
|
||||
Height,
|
||||
Rotation,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
})),
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
Loading…
Reference in New Issue