# Extending GTML GTML is designed with a modular architecture that makes it easy to add new CSS properties, HTML elements, or customize existing behavior. ## Project Structure ``` addons/gtml/src/ ├── GmlView.gd # Main component (signals, API) ├── css/ │ ├── GmlCssParser.gd # CSS parsing and dispatch │ ├── GmlStyleResolver.gd # Resolves CSS rules to nodes │ └── values/ # CSS value parsers │ ├── GmlColorValues.gd # Colors (hex, rgb, rgba, named) │ ├── GmlDimensionValues.gd # Dimensions (px, %, auto) │ ├── GmlFontValues.gd # Font properties │ ├── GmlBackgroundValues.gd # Gradients, images │ ├── GmlBorderValues.gd # Borders, box-shadow │ └── GmlTransitionValues.gd # Transitions ├── html_parser/ │ ├── GmlHtmlParser.gd # HTML tokenizer/parser │ └── GmlNode.gd # DOM node class └── html_renderer/ ├── GmlRenderer.gd # Main renderer (dispatch) ├── GmlStyles.gd # Shared style utilities ├── GmlTransitionManager.gd # CSS transitions ├── SvgDrawControl.gd # SVG drawing control └── elements/ # Element builders ├── GmlContainerElements.gd ├── GmlTextElements.gd ├── GmlButtonElements.gd ├── GmlInputElements.gd ├── GmlMediaElements.gd ├── GmlListElements.gd └── GmlAnchorElements.gd ``` ## Adding a New CSS Property ### Step 1: Identify the Property Category CSS properties fall into these categories: | Category | Module | Example Properties | |----------|--------|-------------------| | Passthrough | Direct string | `display`, `flex-direction`, `text-align` | | Size | Integer pixels | `gap`, `padding-*`, `margin-*`, `font-size` | | Dimension | `{value, unit}` dict | `width`, `height`, `min-width`, `max-width` | | Color | Godot Color | `color`, `background-color`, `border-color` | | Float | Float number | `opacity`, `flex-grow`, `flex-shrink` | | Border | Complex dict | `border`, `border-top`, etc. | | Transition | Timing dict | `transition`, `transition-duration` | | Custom | Special handling | `background`, `font-family`, `box-shadow` | ### Step 2: Add the Parser For simple passthrough properties, add to the constant array in `GmlCssParser.gd`: ```gdscript # In GmlCssParser.gd const PASSTHROUGH_PROPS = [ "display", "flex-direction", "align-items", "justify-content", "text-align", "overflow", "visibility", "flex-wrap", "align-self", "cursor", "list-style-type", "text-transform", "white-space", "text-overflow", # Add your new property here: "my-new-property", ] ``` For properties needing custom parsing, add a value parser: ```gdscript # In css/values/GmlFontValues.gd static func parse_text_transform(value: String) -> String: value = value.strip_edges().to_lower() match value: "uppercase", "lowercase", "capitalize", "none": return value _: return "none" ``` Then register in `GmlCssParser._convert_property_value()`: ```gdscript func _convert_property_value(prop_name: String, value: String): # ... existing code ... if prop_name == "text-transform": return GmlFontValues.parse_text_transform(value) # ... rest of function ... ``` ### Step 3: Apply the Property Apply in the relevant element builder or `GmlStyles.gd`: ```gdscript # In GmlStyles.gd or element builder static func apply_text_styles(label: Label, style: Dictionary, defaults: Dictionary) -> void: # ... existing code ... # Apply text-transform if style.has("text-transform"): match style["text-transform"]: "uppercase": label.text = label.text.to_upper() "lowercase": label.text = label.text.to_lower() "capitalize": label.text = label.text.capitalize() ``` ### Complete Example: Adding `text-transform` **1. Add to GmlCssParser.gd:** ```gdscript const PASSTHROUGH_PROPS = [ # ... existing ... "text-transform", ] ``` **2. Apply in GmlTextElements.gd:** ```gdscript static func _build_text_inner(node, ctx: Dictionary, default_size: int, autowrap: bool) -> Control: # ... existing code ... if style.has("text-transform"): match style["text-transform"]: "uppercase": text = text.to_upper() "lowercase": text = text.to_lower() "capitalize": text = text.capitalize() label.text = text # ... rest of function ... ``` ## Adding a New HTML Element ### Step 1: Create the Element Builder Add to an existing module or create a new file: ```gdscript # In html_renderer/elements/GmlCustomElements.gd class_name GmlCustomElements extends RefCounted ## Build a custom