diff --git a/.github/workflows/github_pages.yml b/.github/workflows/github_pages.yml index f883519..b60cf98 100644 --- a/.github/workflows/github_pages.yml +++ b/.github/workflows/github_pages.yml @@ -6,6 +6,8 @@ on: - main pull_request: +concurrency: preview-${{ github.ref }} + jobs: deploy: runs-on: ubuntu-20.04 @@ -28,3 +30,9 @@ jobs: with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./book/book + + - name: Deploy preview + uses: rossjrw/pr-preview-action@v1 + if: ${{ github.ref != 'refs/heads/main' }} + with: + source-dir: ./book/book \ No newline at end of file diff --git a/api/static/attribute.py b/api/static/attribute.py index 8038a5e..009a890 100644 --- a/api/static/attribute.py +++ b/api/static/attribute.py @@ -44,12 +44,19 @@ class Attribute: """ Creates a "Named Attribute" node with the correct arguments passed, and returns the "Attribute" socket. """ - from geometry_script import named_attribute - return named_attribute(data_type=self.data_type, name=self.name, *args, **kwargs).attribute + from geometry_script import named_attribute, Type + result = named_attribute(data_type=self.data_type, name=self.name, *args, **kwargs) + # Handle Blender 3.5+, which includes an `exists` result. + if isinstance(result, Type): + return result + else: + return result.attribute def exists(self, *args, **kwargs): """ Creates a "Named Attribute" node with the correct arguments passed, and returns the "Exists" socket. + + > Only available in Blender 3.5+ """ from geometry_script import named_attribute return named_attribute(data_type=self.data_type, name=self.name, *args, **kwargs).exists diff --git a/api/tree.py b/api/tree.py index a85e80d..c9ed29d 100644 --- a/api/tree.py +++ b/api/tree.py @@ -98,12 +98,20 @@ def tree(name): outputs = builder(**builder_inputs) # Create the output sockets - for i, result in enumerate(_as_iterable(outputs)): - if not issubclass(type(result), Type): - result = Type(value=result) - # raise Exception(f"Return value '{result}' is not a valid 'Type' subclass.") - node_group.outputs.new(result.socket_type, 'Result') - link = node_group.links.new(result._socket, group_output_node.inputs[i]) + if isinstance(outputs, dict): + # Use a dict to name each return value + for i, (k, v) in enumerate(outputs.items()): + if not issubclass(type(v), Type): + v = Type(value=v) + node_group.outputs.new(v.socket_type, k) + node_group.links.new(v._socket, group_output_node.inputs[i]) + else: + for i, result in enumerate(_as_iterable(outputs)): + if not issubclass(type(result), Type): + result = Type(value=result) + # raise Exception(f"Return value '{result}' is not a valid 'Type' subclass.") + node_group.outputs.new(result.socket_type, 'Result') + node_group.links.new(result._socket, group_output_node.inputs[i]) _arrange(node_group) diff --git a/api/types.py b/api/types.py index e1e9611..d8346bc 100644 --- a/api/types.py +++ b/api/types.py @@ -175,8 +175,8 @@ class Type(metaclass=_TypeMeta): def capture(self, value, **kwargs): data_type = socket_type_to_data_type(value._socket.type) - geometry, attribute = self.capture_attribute(data_type=data_type, value=value, **kwargs) - return geometry, attribute + res = self.capture_attribute(data_type=data_type, value=value, **kwargs) + return res.geometry, res.attribute def transfer(self, attribute, **kwargs): data_type = socket_type_to_data_type(attribute._socket.type) return self.transfer_attribute(data_type=data_type, attribute=attribute, **kwargs) diff --git a/book/src/api/basics/cube_tree_named_outputs.png b/book/src/api/basics/cube_tree_named_outputs.png new file mode 100644 index 0000000..a029c08 Binary files /dev/null and b/book/src/api/basics/cube_tree_named_outputs.png differ diff --git a/book/src/api/basics/tree-functions.md b/book/src/api/basics/tree-functions.md index c77ba00..888bcec 100644 --- a/book/src/api/basics/tree-functions.md +++ b/book/src/api/basics/tree-functions.md @@ -41,6 +41,19 @@ def cube_tree(): ![](./cube_tree_int.png) +By default, each output is named 'Result'. To customize the name, return a dictionary. + +```python +@tree("Cube Tree") +def cube_tree(): + return { + "My Cube": cube(), + "Scale Constant": 5 + } +``` + +![](./cube_tree_named_outputs.png) + ## Group Input All arguments in a tree function must be annotated with a valid socket type. These types are provided by Geometry Script, and are not equivalent to Python's built-in types. Let's add a size argument to our Cube Tree.