@@ -21,7 +21,7 @@ use graphene_std::raster::{
2121} ;
2222use graphene_std:: raster_types:: { CPU , GPU , RasterDataTable } ;
2323use graphene_std:: text:: Font ;
24- use graphene_std:: transform:: { Footprint , ReferencePoint } ;
24+ use graphene_std:: transform:: { Footprint , ReferencePoint , Transform } ;
2525use graphene_std:: vector:: VectorDataTable ;
2626use graphene_std:: vector:: misc:: GridType ;
2727use graphene_std:: vector:: misc:: { ArcType , MergeByDistanceAlgorithm } ;
@@ -176,6 +176,7 @@ pub(crate) fn property_from_type(
176176 Some ( x) if x == TypeId :: of :: < bool > ( ) => bool_widget ( default_info, CheckboxInput :: default ( ) ) . into ( ) ,
177177 Some ( x) if x == TypeId :: of :: < String > ( ) => text_widget ( default_info) . into ( ) ,
178178 Some ( x) if x == TypeId :: of :: < DVec2 > ( ) => coordinate_widget ( default_info, "X" , "Y" , "" , None , false ) ,
179+ Some ( x) if x == TypeId :: of :: < DAffine2 > ( ) => transform_widget ( default_info, & mut extra_widgets) ,
179180 // ==========================
180181 // PRIMITIVE COLLECTION TYPES
181182 // ==========================
@@ -504,6 +505,126 @@ pub fn footprint_widget(parameter_widgets_info: ParameterWidgetsInfo, extra_widg
504505 last. clone ( )
505506}
506507
508+ pub fn transform_widget ( parameter_widgets_info : ParameterWidgetsInfo , extra_widgets : & mut Vec < LayoutGroup > ) -> LayoutGroup {
509+ let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info;
510+
511+ let mut location_widgets = start_widgets ( parameter_widgets_info) ;
512+ location_widgets. push ( Separator :: new ( SeparatorType :: Unrelated ) . widget_holder ( ) ) ;
513+
514+ let mut rotation_widgets = vec ! [ TextLabel :: new( "" ) . widget_holder( ) ] ;
515+ add_blank_assist ( & mut rotation_widgets) ;
516+ rotation_widgets. push ( Separator :: new ( SeparatorType :: Unrelated ) . widget_holder ( ) ) ;
517+
518+ let mut scale_widgets = vec ! [ TextLabel :: new( "" ) . widget_holder( ) ] ;
519+ add_blank_assist ( & mut scale_widgets) ;
520+ scale_widgets. push ( Separator :: new ( SeparatorType :: Unrelated ) . widget_holder ( ) ) ;
521+
522+ let Some ( document_node) = document_node else { return LayoutGroup :: default ( ) } ;
523+ let Some ( input) = document_node. inputs . get ( index) else {
524+ log:: warn!( "A widget failed to be built because its node's input index is invalid." ) ;
525+ return Vec :: new ( ) . into ( ) ;
526+ } ;
527+
528+ let widgets = if let Some ( & TaggedValue :: DAffine2 ( transform) ) = input. as_non_exposed_value ( ) {
529+ let translation = transform. translation ;
530+ let rotation = transform. decompose_rotation ( ) ;
531+ let scale = transform. decompose_scale ( ) ;
532+
533+ location_widgets. extend_from_slice ( & [
534+ NumberInput :: new ( Some ( translation. x ) )
535+ . label ( "X" )
536+ . unit ( " px" )
537+ . on_update ( update_value (
538+ move |x : & NumberInput | {
539+ let mut transform = transform;
540+ transform. translation . x = x. value . unwrap_or ( transform. translation . x ) ;
541+ TaggedValue :: DAffine2 ( transform)
542+ } ,
543+ node_id,
544+ index,
545+ ) )
546+ . on_commit ( commit_value)
547+ . widget_holder ( ) ,
548+ Separator :: new ( SeparatorType :: Related ) . widget_holder ( ) ,
549+ NumberInput :: new ( Some ( translation. y ) )
550+ . label ( "Y" )
551+ . unit ( " px" )
552+ . on_update ( update_value (
553+ move |y : & NumberInput | {
554+ let mut transform = transform;
555+ transform. translation . y = y. value . unwrap_or ( transform. translation . y ) ;
556+ TaggedValue :: DAffine2 ( transform)
557+ } ,
558+ node_id,
559+ index,
560+ ) )
561+ . on_commit ( commit_value)
562+ . widget_holder ( ) ,
563+ ] ) ;
564+
565+ rotation_widgets. extend_from_slice ( & [ NumberInput :: new ( Some ( rotation. to_degrees ( ) ) )
566+ . unit ( "°" )
567+ . mode ( NumberInputMode :: Range )
568+ . range_min ( Some ( -180. ) )
569+ . range_max ( Some ( 180. ) )
570+ . on_update ( update_value (
571+ move |r : & NumberInput | {
572+ let transform = DAffine2 :: from_scale_angle_translation ( scale, r. value . map ( |r| r. to_radians ( ) ) . unwrap_or ( rotation) , translation) ;
573+ TaggedValue :: DAffine2 ( transform)
574+ } ,
575+ node_id,
576+ index,
577+ ) )
578+ . on_commit ( commit_value)
579+ . widget_holder ( ) ] ) ;
580+
581+ scale_widgets. extend_from_slice ( & [
582+ NumberInput :: new ( Some ( scale. x ) )
583+ . label ( "W" )
584+ . unit ( "x" )
585+ . on_update ( update_value (
586+ move |w : & NumberInput | {
587+ let transform = DAffine2 :: from_scale_angle_translation ( DVec2 :: new ( w. value . unwrap_or ( scale. x ) , scale. y ) , rotation, translation) ;
588+ TaggedValue :: DAffine2 ( transform)
589+ } ,
590+ node_id,
591+ index,
592+ ) )
593+ . on_commit ( commit_value)
594+ . widget_holder ( ) ,
595+ Separator :: new ( SeparatorType :: Related ) . widget_holder ( ) ,
596+ NumberInput :: new ( Some ( scale. y ) )
597+ . label ( "H" )
598+ . unit ( "x" )
599+ . on_update ( update_value (
600+ move |h : & NumberInput | {
601+ let transform = DAffine2 :: from_scale_angle_translation ( DVec2 :: new ( scale. x , h. value . unwrap_or ( scale. y ) ) , rotation, translation) ;
602+ TaggedValue :: DAffine2 ( transform)
603+ } ,
604+ node_id,
605+ index,
606+ ) )
607+ . on_commit ( commit_value)
608+ . widget_holder ( ) ,
609+ ] ) ;
610+
611+ vec ! [
612+ LayoutGroup :: Row { widgets: location_widgets } ,
613+ LayoutGroup :: Row { widgets: rotation_widgets } ,
614+ LayoutGroup :: Row { widgets: scale_widgets } ,
615+ ]
616+ } else {
617+ vec ! [ LayoutGroup :: Row { widgets: location_widgets } ]
618+ } ;
619+
620+ if let Some ( ( last, rest) ) = widgets. split_last ( ) {
621+ * extra_widgets = rest. to_vec ( ) ;
622+ last. clone ( )
623+ } else {
624+ LayoutGroup :: default ( )
625+ }
626+ }
627+
507628pub fn coordinate_widget ( parameter_widgets_info : ParameterWidgetsInfo , x : & str , y : & str , unit : & str , min : Option < f64 > , is_integer : bool ) -> LayoutGroup {
508629 let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info;
509630
@@ -1345,9 +1466,9 @@ pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodeProperties
13451466
13461467pub ( crate ) fn node_no_properties ( node_id : NodeId , context : & mut NodePropertiesContext ) -> Vec < LayoutGroup > {
13471468 let text = if context. network_interface . is_layer ( & node_id, context. selection_network_path ) {
1348- "Layer has no properties "
1469+ "Layer has no parameters "
13491470 } else {
1350- "Node has no properties "
1471+ "Node has no parameters "
13511472 } ;
13521473 string_properties ( text)
13531474}
0 commit comments