Hi everyone,
@eirannejad I see you’re the one focused on Python functionality. Would it be possible to implement an easy way to code the component’s metadata and input and output parameters? (Added bonus: potentially script a simple way to pass Value Listener values)
With the proliferation of LLMs as code assistants, I believe this can be really valuable for users to copy and paste code, they would just need to prompt the LLM to follow a specific format (whichever you feel is appropriate or required to set up the components data).
Let me show you what I do at the moment. It works, but it’s clunky, and scripting Value Listeners means getting into more complex stuff like object expiration and persistence.
class TextJustification:
"""Manages text justification options and validation.
This class encapsulates text justification functionality, providing a clean
interface for working with Rhino's text justification system. It converts
between human-readable position descriptions (e.g., "BottomLeft") and their
corresponding numeric values in the Rhino system.
The justification system uses a coordinate-based approach where:
- Vertical alignment uses the 1st and 2nd bytes (values 65536, 131072, 262144)
- Horizontal alignment uses the 1st and 2nd bits (values 1, 2, 4)
For example, BottomLeft (65537) combines:
- Bottom alignment (65536) with
- Left alignment (1)
"""
OPTIONS = {
"BottomLeft": 65537,
"BottomCenter": 65538,
"BottomRight": 65540,
"MiddleLeft": 131073,
"MiddleCenter": 131074,
"MiddleRight": 131076,
"TopLeft": 262145,
"TopCenter": 262146,
"TopRight": 262148
}
@classmethod
def get_default(cls):
"""Returns the default justification value (MiddleCenter)."""
return cls.OPTIONS["MiddleCenter"]
@classmethod
def is_valid(cls, value):
"""Checks if a value is a valid justification option."""
return value in cls.OPTIONS.values()
def setup_component():
"""Initialize and configure the Grasshopper component.
This function handles the complete setup of the component, including:
1. Setting basic component properties (name, category, etc.)
2. Configuring input parameters with appropriate data access patterns
3. Setting up dynamic behavior for parameter updates
4. Establishing default values and optional parameters
The setup ensures the component will behave consistently within the
Grasshopper environment and provides clear feedback through parameter
naming and descriptions.
"""
# Component setup
ghenv.Component.Name = "Text to Geometry"
ghenv.Component.NickName = "T2G"
ghenv.Component.Message = "Text2Geometry"
ghenv.Component.Category = "Text"
ghenv.Component.SubCategory = "Format"
# Make the component volatile so it updates when inputs change
ghenv.Component.Params.Input[4].DataMapping = Grasshopper.Kernel.GH_DataMapping.NONE
ghenv.Component.Params.Input[4].Optional = True
# Set component to recompute when anything changes
ghenv.Component.Attributes.Selected = True
# Input parameter setup
inputs = ghenv.Component.Params.Input
params_config = [
("Text", "T", "Text string to convert to curves", Grasshopper.Kernel.GH_ParamAccess.item),
("Font", "F", "Font name (defaults to Arial if not specified)", Grasshopper.Kernel.GH_ParamAccess.item),
("Size", "S", "Text height (defaults to 10 units if not specified)", Grasshopper.Kernel.GH_ParamAccess.item),
("Location", "L", "Location as either a Plane or Point3d", Grasshopper.Kernel.GH_ParamAccess.item),
("Text Justification", "J", "Text justification value (optional)", Grasshopper.Kernel.GH_ParamAccess.item)
]
for i, (name, nick, desc, access) in enumerate(params_config):
inputs[i].Name = name
inputs[i].NickName = nick
inputs[i].Description = desc
inputs[i].Access = access
def configure_connected_value_list():
"""Set up a connected Value List with text justification options.
This function provides a user-friendly interface for text justification by:
1. Detecting when a Value List component is connected to the justification input
2. Automatically populating it with available justification options
3. Maintaining the component's default behavior for the current execution
The configuration happens "just in time" - when a Value List is connected,
it's immediately configured but doesn't force a solution update, allowing
for smooth integration into existing Grasshopper definitions.
"""
# Get our justification input parameter
j_param = ghenv.Component.Params.Input[4]
# Look for connected components
sources = j_param.Sources
if sources and sources.Count > 0:
source = sources[0]
if source:
# Get the actual component
upstream = source.Attributes.GetTopLevel.DocObject
# Check if it's a Value List
if upstream.GetType().Name == "GH_ValueList":
try:
# Configure the Value List with justification options
upstream.ListItems.Clear()
# Add all justification options
for display_name, value in TextJustification.OPTIONS.items():
item = Grasshopper.Kernel.Special.GH_ValueListItem(display_name, str(value))
upstream.ListItems.Add(item)
# Set a descriptive name for the Value List
upstream.NickName = "TextJustification"
# Set component's description to indicate it's been configured
upstream.Description = "Configured with text justification options"
# Don't force a solution update - let Grasshopper handle it naturally
ghenv.Component.OnPingDocument().ScheduleSolution(10)
except Exception as e:
ghenv.Component.AddRuntimeMessage(
Grasshopper.Kernel.GH_RuntimeMessageLevel.Warning,
f"Error configuring Value List: {str(e)}"
)
class TextJustification:
"""Manages text justification options and validation.
This class encapsulates text justification functionality, providing a clean
interface for working with Rhino's text justification system. It converts
between human-readable position descriptions (e.g., "BottomLeft") and their
corresponding numeric values in the Rhino system.
The justification system uses a coordinate-based approach where:
- Vertical alignment uses the 1st and 2nd bytes (values 65536, 131072, 262144)
- Horizontal alignment uses the 1st and 2nd bits (values 1, 2, 4)
For example, BottomLeft (65537) combines:
- Bottom alignment (65536) with
- Left alignment (1)
"""
OPTIONS = {
"BottomLeft": 65537,
"BottomCenter": 65538,
"BottomRight": 65540,
"MiddleLeft": 131073,
"MiddleCenter": 131074,
"MiddleRight": 131076,
"TopLeft": 262145,
"TopCenter": 262146,
"TopRight": 262148
}
@classmethod
def get_default(cls):
"""Returns the default justification value (MiddleCenter)."""
return cls.OPTIONS["MiddleCenter"]
@classmethod
def is_valid(cls, value):
"""Checks if a value is a valid justification option."""
return value in cls.OPTIONS.values()
def setup_component():
"""Initialize and configure the Grasshopper component.
This function handles the complete setup of the component, including:
1. Setting basic component properties (name, category, etc.)
2. Configuring input parameters with appropriate data access patterns
3. Setting up dynamic behavior for parameter updates
4. Establishing default values and optional parameters
The setup ensures the component will behave consistently within the
Grasshopper environment and provides clear feedback through parameter
naming and descriptions.
"""
# Component setup
ghenv.Component.Name = "Text to Geometry"
ghenv.Component.NickName = "T2G"
ghenv.Component.Message = "Text2Geometry"
ghenv.Component.Category = "Text"
ghenv.Component.SubCategory = "Format"
# Make the component volatile so it updates when inputs change
ghenv.Component.Params.Input[4].DataMapping = Grasshopper.Kernel.GH_DataMapping.NONE
ghenv.Component.Params.Input[4].Optional = True
# Set component to recompute when anything changes
ghenv.Component.Attributes.Selected = True
# Input parameter setup
inputs = ghenv.Component.Params.Input
params_config = [
("Text", "T", "Text string to convert to curves", Grasshopper.Kernel.GH_ParamAccess.item),
("Font", "F", "Font name (defaults to Arial if not specified)", Grasshopper.Kernel.GH_ParamAccess.item),
("Size", "S", "Text height (defaults to 10 units if not specified)", Grasshopper.Kernel.GH_ParamAccess.item),
("Location", "L", "Location as either a Plane or Point3d", Grasshopper.Kernel.GH_ParamAccess.item),
("Text Justification", "J", "Text justification value (optional)", Grasshopper.Kernel.GH_ParamAccess.item)
]
for i, (name, nick, desc, access) in enumerate(params_config):
inputs[i].Name = name
inputs[i].NickName = nick
inputs[i].Description = desc
inputs[i].Access = access
def configure_connected_value_list():
"""Set up a connected Value List with text justification options.
This function provides a user-friendly interface for text justification by:
1. Detecting when a Value List component is connected to the justification input
2. Automatically populating it with available justification options
3. Maintaining the component's default behavior for the current execution
The configuration happens "just in time" - when a Value List is connected,
it's immediately configured but doesn't force a solution update, allowing
for smooth integration into existing Grasshopper definitions.
"""
# Get our justification input parameter
j_param = ghenv.Component.Params.Input[4]
# Look for connected components
sources = j_param.Sources
if sources and sources.Count > 0:
source = sources[0]
if source:
# Get the actual component
upstream = source.Attributes.GetTopLevel.DocObject
# Check if it's a Value List
if upstream.GetType().Name == "GH_ValueList":
try:
# Configure the Value List with justification options
upstream.ListItems.Clear()
# Add all justification options
for display_name, value in TextJustification.OPTIONS.items():
item = Grasshopper.Kernel.Special.GH_ValueListItem(display_name, str(value))
upstream.ListItems.Add(item)
# Set a descriptive name for the Value List
upstream.NickName = "TextJustification"
# Set component's description to indicate it's been configured
upstream.Description = "Configured with text justification options"
# Don't force a solution update - let Grasshopper handle it naturally
ghenv.Component.OnPingDocument().ScheduleSolution(10)
except Exception as e:
ghenv.Component.AddRuntimeMessage(
Grasshopper.Kernel.GH_RuntimeMessageLevel.Warning,
f"Error configuring Value List: {str(e)}"
)
# ... rest of methods
Cheers