@@ -16,6 +16,7 @@ use graph_craft::{Type, concrete};
1616use graphene_std:: NodeInputDecleration ;
1717use graphene_std:: animation:: RealTimeMode ;
1818use graphene_std:: extract_xy:: XY ;
19+ use graphene_std:: logic:: StringCapitalization ;
1920use graphene_std:: raster:: curve:: Curve ;
2021use graphene_std:: raster:: {
2122 BlendMode , CellularDistanceFunction , CellularReturnType , Color , DomainWarpType , FractalType , LuminanceCalculation , NoiseType , RedGreenBlue , RedGreenBlueAlpha , RelativeAbsolute ,
@@ -244,6 +245,7 @@ pub(crate) fn property_from_type(
244245 Some ( x) if x == TypeId :: of :: < RedGreenBlue > ( ) => enum_choice :: < RedGreenBlue > ( ) . for_socket ( default_info) . property_row ( ) ,
245246 Some ( x) if x == TypeId :: of :: < RedGreenBlueAlpha > ( ) => enum_choice :: < RedGreenBlueAlpha > ( ) . for_socket ( default_info) . property_row ( ) ,
246247 Some ( x) if x == TypeId :: of :: < XY > ( ) => enum_choice :: < XY > ( ) . for_socket ( default_info) . property_row ( ) ,
248+ Some ( x) if x == TypeId :: of :: < StringCapitalization > ( ) => enum_choice :: < StringCapitalization > ( ) . for_socket ( default_info) . property_row ( ) ,
247249 Some ( x) if x == TypeId :: of :: < NoiseType > ( ) => enum_choice :: < NoiseType > ( ) . for_socket ( default_info) . property_row ( ) ,
248250 Some ( x) if x == TypeId :: of :: < FractalType > ( ) => enum_choice :: < FractalType > ( ) . for_socket ( default_info) . disabled ( false ) . property_row ( ) ,
249251 Some ( x) if x == TypeId :: of :: < CellularDistanceFunction > ( ) => enum_choice :: < CellularDistanceFunction > ( ) . for_socket ( default_info) . disabled ( false ) . property_row ( ) ,
@@ -1588,6 +1590,101 @@ pub(crate) fn exposure_properties(node_id: NodeId, context: &mut NodePropertiesC
15881590 vec ! [ LayoutGroup :: row( exposure) , LayoutGroup :: row( offset) , LayoutGroup :: row( gamma_correction) ]
15891591}
15901592
1593+ pub ( crate ) fn string_capitalization_properties ( node_id : NodeId , context : & mut NodePropertiesContext ) -> Vec < LayoutGroup > {
1594+ use graphene_std:: logic:: string_capitalization:: * ;
1595+
1596+ // Read the current values before borrowing context mutably for widgets
1597+ let ( is_simple_case, use_joiner_enabled, joiner_value) = match get_document_node ( node_id, context) {
1598+ Ok ( document_node) => {
1599+ let is_simple = matches ! (
1600+ document_node. inputs. get( CapitalizationInput :: INDEX ) . and_then( |input| input. as_value( ) ) ,
1601+ Some ( TaggedValue :: StringCapitalization ( StringCapitalization :: LowerCase | StringCapitalization :: UpperCase ) )
1602+ ) ;
1603+ let use_joiner = match document_node. inputs . get ( UseJoinerInput :: INDEX ) . and_then ( |input| input. as_value ( ) ) {
1604+ Some ( & TaggedValue :: Bool ( x) ) => x,
1605+ _ => true ,
1606+ } ;
1607+ let joiner = match document_node. inputs . get ( JoinerInput :: INDEX ) . and_then ( |input| input. as_non_exposed_value ( ) ) {
1608+ Some ( TaggedValue :: String ( x) ) => Some ( x. clone ( ) ) ,
1609+ _ => None ,
1610+ } ;
1611+ ( is_simple, use_joiner, joiner)
1612+ }
1613+ Err ( err) => {
1614+ log:: error!( "Could not get document node in string_capitalization_properties: {err}" ) ;
1615+ return Vec :: new ( ) ;
1616+ }
1617+ } ;
1618+
1619+ // The joiner controls are disabled when lowercase/UPPERCASE are selected (they don't use word boundaries)
1620+ let joiner_disabled = is_simple_case || !use_joiner_enabled;
1621+
1622+ let capitalization = enum_choice :: < StringCapitalization > ( )
1623+ . for_socket ( ParameterWidgetsInfo :: new ( node_id, CapitalizationInput :: INDEX , true , context) )
1624+ . property_row ( ) ;
1625+
1626+ // Joiner row: the UseJoiner checkbox is drawn in the assist area, followed by the Joiner text input
1627+ let mut joiner_widgets = start_widgets ( ParameterWidgetsInfo :: new ( node_id, JoinerInput :: INDEX , false , context) ) ;
1628+ if let Some ( joiner) = joiner_value {
1629+ let joiner_is_empty = joiner. is_empty ( ) ;
1630+ joiner_widgets. extend_from_slice ( & [
1631+ Separator :: new ( SeparatorStyle :: Unrelated ) . widget_instance ( ) ,
1632+ Separator :: new ( SeparatorStyle :: Related ) . widget_instance ( ) ,
1633+ CheckboxInput :: new ( use_joiner_enabled)
1634+ . disabled ( is_simple_case)
1635+ . on_update ( update_value ( |x : & CheckboxInput | TaggedValue :: Bool ( x. checked ) , node_id, UseJoinerInput :: INDEX ) )
1636+ . on_commit ( commit_value)
1637+ . widget_instance ( ) ,
1638+ Separator :: new ( SeparatorStyle :: Related ) . widget_instance ( ) ,
1639+ Separator :: new ( SeparatorStyle :: Unrelated ) . widget_instance ( ) ,
1640+ TextInput :: new ( joiner)
1641+ . placeholder ( if joiner_is_empty { "Empty" } else { "" } )
1642+ . disabled ( joiner_disabled)
1643+ . on_update ( update_value ( |x : & TextInput | TaggedValue :: String ( x. value . clone ( ) ) , node_id, JoinerInput :: INDEX ) )
1644+ . on_commit ( commit_value)
1645+ . widget_instance ( ) ,
1646+ ] ) ;
1647+ }
1648+
1649+ // Preset buttons for common joiner values, indented to align with the input field
1650+ let mut joiner_preset_buttons = vec ! [ TextLabel :: new( "" ) . widget_instance( ) ] ;
1651+ add_blank_assist ( & mut joiner_preset_buttons) ;
1652+ joiner_preset_buttons. push ( Separator :: new ( SeparatorStyle :: Unrelated ) . widget_instance ( ) ) ;
1653+ for ( label, value, tooltip) in [
1654+ ( "Empty" , "" , "Join words without any separator." ) ,
1655+ ( "Space" , " " , "Join words with a space." ) ,
1656+ ( "Kebab" , "-" , "Join words with a hyphen." ) ,
1657+ ( "Snake" , "_" , "Join words with an underscore." ) ,
1658+ ] {
1659+ let value = value. to_string ( ) ;
1660+ joiner_preset_buttons. push (
1661+ TextButton :: new ( label)
1662+ . tooltip_description ( tooltip)
1663+ . disabled ( is_simple_case)
1664+ . on_update ( move |_: & TextButton | Message :: Batched {
1665+ messages : Box :: new ( [
1666+ NodeGraphMessage :: SetInputValue {
1667+ node_id,
1668+ input_index : UseJoinerInput :: INDEX ,
1669+ value : TaggedValue :: Bool ( true ) ,
1670+ }
1671+ . into ( ) ,
1672+ NodeGraphMessage :: SetInputValue {
1673+ node_id,
1674+ input_index : JoinerInput :: INDEX ,
1675+ value : TaggedValue :: String ( value. clone ( ) ) ,
1676+ }
1677+ . into ( ) ,
1678+ ] ) ,
1679+ } )
1680+ . on_commit ( commit_value)
1681+ . widget_instance ( ) ,
1682+ ) ;
1683+ }
1684+
1685+ vec ! [ capitalization, LayoutGroup :: row( joiner_widgets) , LayoutGroup :: row( joiner_preset_buttons) ]
1686+ }
1687+
15911688pub ( crate ) fn rectangle_properties ( node_id : NodeId , context : & mut NodePropertiesContext ) -> Vec < LayoutGroup > {
15921689 use graphene_std:: vector:: generator_nodes:: rectangle:: * ;
15931690
0 commit comments