Skip to content

Differentiate between scale and dimensions #570

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions editor/src/document/properties_panel_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub enum PropertiesPanelMessage {
pub enum TransformOp {
X,
Y,
ScaleX,
ScaleY,
Width,
Height,
Rotation,
Expand Down
115 changes: 82 additions & 33 deletions editor/src/document/properties_panel_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -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.;

Expand Down Expand Up @@ -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(),
);
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -340,21 +346,47 @@ fn node_section_transform(layer: &Layer) -> LayoutRow {
name: "".into(),
widgets: vec![
WidgetHolder::new(Widget::TextLabel(TextLabel {
value: "Dimensions".into(),
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.width(),
label: "W".into(),
unit: " px".into(),
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::Width,
transform_op: TransformOp::ScaleX,
}
.into()
}),
Expand All @@ -365,13 +397,13 @@ fn node_section_transform(layer: &Layer) -> LayoutRow {
direction: SeparatorDirection::Horizontal,
})),
WidgetHolder::new(Widget::NumberInput(NumberInput {
value: layer.transform.height(),
label: "H".into(),
unit: " px".into(),
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::Height,
transform_op: TransformOp::ScaleY,
}
.into()
}),
Expand All @@ -383,21 +415,38 @@ fn node_section_transform(layer: &Layer) -> LayoutRow {
name: "".into(),
widgets: vec![
WidgetHolder::new(Widget::TextLabel(TextLabel {
value: "Rotation".into(),
value: "Dimensions".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(),
value: layer.bounding_transform().scale_x(),
label: "W".into(),
unit: " px".into(),
on_update: WidgetCallback::new(|number_input: &NumberInput| {
PropertiesPanelMessage::ModifyTransform {
value: number_input.value / 180. * PI,
transform_op: TransformOp::Rotation,
value: number_input.value,
transform_op: TransformOp::Width,
}
.into()
}),
..NumberInput::default()
})),
WidgetHolder::new(Widget::Separator(Separator {
separator_type: SeparatorType::Related,
direction: SeparatorDirection::Horizontal,
})),
WidgetHolder::new(Widget::NumberInput(NumberInput {
value: layer.bounding_transform().scale_y(),
label: "H".into(),
unit: " px".into(),
on_update: WidgetCallback::new(|number_input: &NumberInput| {
PropertiesPanelMessage::ModifyTransform {
value: number_input.value,
transform_op: TransformOp::Height,
}
.into()
}),
Expand Down
2 changes: 1 addition & 1 deletion editor/src/document/transformation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion editor/src/viewport_tools/tools/gradient_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion editor/src/viewport_tools/tools/text_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
17 changes: 14 additions & 3 deletions graphene/src/layers/layer_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down