Extending the functionality of Kanzi Engine with Java

With a Kanzi Engine plugin you can extend the functionality of Kanzi Engine and set how Kanzi Studio shows the custom content you create:

Creating custom nodes and property types

In a Java Kanzi Engine plugin you can create custom nodes with custom property types. You can set how Kanzi Studio shows and lets users interact with these nodes.

To create a custom node with custom property types:

  1. To pass to Kanzi Studio information about the custom node, declare the editor info as an annotation on the node metadata:

    @Metadata
    @EditorInfo(
        // Set the name that you want to use for your node in Kanzi Studio.
        displayName = "My Node",
        // Set the tooltip that you want to use in the Kanzi Studio Create menu.
        tooltip = "This example custom node uses custom properties.",
        customAttributes =
        {
            // Add the Horizontal Alignment and Vertical Alignment properties to the node.
            @EditorInfoAttribute(key = "AutomaticallyAddedProperties", value = "Node.HorizontalAlignment, Node.VerticalAlignment"),
            // Add the State Manager property as a frequently used property,
            // which users can add by clicking the + next to the property name.
            @EditorInfoAttribute(key = "FrequentlyAddedProperties", value = "Node.StateManager"),
            // Let the user add the Focusable property using the Add Property
            // context menu or the context tab of the Add Properties window.
            @EditorInfoAttribute(key = "ContextProperties", value = "Node.Focusable"),
        })
    public static Metaclass metaclass = new Metaclass("MyNode");
    
    companion object {
        @Metadata
        @EditorInfo(
            // Set the name that you want to use for your node in Kanzi Studio.
            displayName = "My Node",
            // Set the tooltip that you want to use in the Kanzi Studio Create menu.
            tooltip = "This example custom node uses custom properties.",
            customAttributes =
            {
                // Add the Horizontal Alignment and Vertical Alignment properties to the node.
                @EditorInfoAttribute(key = "AutomaticallyAddedProperties", value = "Node.HorizontalAlignment, Node.VerticalAlignment"),
                // Add the State Manager property as a frequently used property,
                // which users can add by clicking the + next to the property name.
                @EditorInfoAttribute(key = "FrequentlyAddedProperties", value = "Node.StateManager"),
                // Let the user add the Focusable property using the Add Property
                // context menu or the context tab of the Add Properties window.
                @EditorInfoAttribute(key = "ContextProperties", value = "Node.Focusable"),
            })
        val metaclass = Metaclass("MyNode");
    }
    
  2. Create the custom property types and their metadata.

    For example:

    • String property with a one-line text editor:

      // Creates a string property.
      // This example does not set the editor. If you do not set the editor, Kanzi Studio uses
      // the default editor for this property type.
      @Metadata
      @EditorInfo(displayName = "String")
      public static final PropertyType<String> StringProperty =
          new PropertyType("MyPlugin.String", String.class);
      
      companion object {
          // Creates a string property.
          // This example does not set the editor. If you do not set the editor, Kanzi Studio uses
          // the default editor for this property type.
          @Metadata
          @EditorInfo(displayName = "String")
          val StringProperty = PropertyType("MyPlugin.String", String::class.java)
      }
      
      ../../_images/custom-component-string.png
    • String reference to a 3D node the user can select from a dropdown menu:

      // Creates a string reference to a node.
      @Metadata
      @EditorInfo(displayName = "Node Reference by String",
                  // When you set valueProvider to ProjectObject:Node3D,
                  // Kanzi Studio automatically uses the Node 3D selector editor.
                  valueProvider = "ProjectObject:Node3D")
      public static final PropertyType<String> NodeRefByStringProperty =
          new PropertyType("MyPlugin.NodeRefByString", String.class);
      
      companion object {
          // Creates a string reference to a node.
          @Metadata
          @EditorInfo(displayName = "Node Reference by String",
                      // When you set valueProvider to ProjectObject:Node3D,
                      // Kanzi Studio automatically uses the Node 3D selector editor.
                      valueProvider = "ProjectObject:Node3D")
          val NodeRefByStringProperty = PropertyType("MyPlugin.NodeRefByString", String::class.java)
      }
      
      ../../_images/custom-component-node-reference-by-string.png
    • String reference to a prefab the user can select from a dropdown menu:

      // Creates a string reference to a prefab resource.
      @Metadata
      @EditorInfo(displayName = "Prefab Reference by String",
                  // When you set valueProvider to ProjectObject:PrefabTemplate,
                  // Kanzi Studio automatically uses the Prefab template selector editor.
                  valueProvider = "ProjectObject:PrefabTemplate")
      public static final PropertyType<String> PrefabRefByStringProperty =
          new PropertyType("MyPlugin.PrefabRefByString", String.class);
      
      companion object {
          // Creates a string reference to a prefab resource.
          @Metadata
          @EditorInfo(displayName = "Prefab Reference by String",
                      // When you set valueProvider to ProjectObject:PrefabTemplate,
                      // Kanzi Studio automatically uses the Prefab template selector editor.
                      valueProvider = "ProjectObject:PrefabTemplate")
          val PrefabRefByStringProperty = PropertyType("MyPlugin.PrefabRefByString", String::class.java)
      }
      
      ../../_images/custom-component-prefab-reference-by-string.png
    • Resource reference to a prefab resource the user can select from a dropdown menu:

      // Creates a resource reference to a prefab resource.
      @Metadata
      @EditorInfo(displayName = "Prefab Reference by Resource",
                  // When you set valueProvider to ProjectObject:PrefabTemplate,
                  // Kanzi Studio automatically uses the Prefab template selector editor.
                  valueProvider = "ProjectObject:PrefabTemplate")
      public static final PropertyType<Resource> PrefabRefByResourceProperty =
          new PropertyType("MyPlugin.MaterialRefByResource", Resource.class);
      
      companion object {
          // Creates a resource reference to a prefab resource.
          @Metadata
          @EditorInfo(displayName = "Prefab Reference by Resource",
                      // When you set valueProvider to ProjectObject:PrefabTemplate,
                      // Kanzi Studio automatically uses the Prefab template selector editor.
                      valueProvider = "ProjectObject:PrefabTemplate")
          val PrefabRefByResourceProperty = PropertyType("MyPlugin.MaterialRefByResource", Resource::class.java)
      }
      
      ../../_images/custom-component-prefab-reference-by-resource.png
    • Resource reference to a material resource the user can select from a dropdown menu:

      // Creates a resource reference to a material resource.
      @Metadata
      @EditorInfo(displayName = "Material Reference by Resource",
                  // When you set valueProvider to ProjectObject:Material,
                  // Kanzi Studio automatically uses the Material dropdown editor.
                  valueProvider = "ProjectObject:Material")
      public static final PropertyType<Resource> MaterialRefByResourceProperty =
          new PropertyType("MyPlugin.MaterialRefByResource", Resource.class);
      
      companion object {
          // Creates a resource reference to a material resource.
          @Metadata
          @EditorInfo(displayName = "Material Reference by Resource",
                      // When you set valueProvider to ProjectObject:Material,
                      // Kanzi Studio automatically uses the Material dropdown editor.
                      valueProvider = "ProjectObject:Material")
          val MaterialRefByResourceProperty = PropertyType("MyPlugin.MaterialRefByResource", Resource::class.java)
      }
      
      ../../_images/custom-component-material-reference-by-resource.png
  3. Build and install your plugin. See Adding a Kanzi Engine plugin to a Kanzi Studio project.

  4. In Kanzi Studio in the Library > Kanzi Engine Plugins select your plugin. In the Properties you can see the custom property types.

    ../../_images/myplugin-properties-java.png
  5. In the Node Tree press Alt and right-click the node where you want to create your node and select your node.

    ../../_images/create-custom-component-node.png
  6. (Optional) By default Kanzi Studio adds custom properties as frequently used properties to the nodes of the type for which you created the property type. To set the node types for which Kanzi Studio suggests the property, and whether Kanzi Studio adds the property automatically or lets the user add it, set the @EditorInfo host attribute. See host.

    ../../_images/custom-component-properties-java.png

Setting custom property types

To pass to Kanzi Studio information about the custom property types that you create in a Java Kanzi Engine plugin, declare metadata that describes the property types.

The metadata enable Kanzi Engine plugin users to interact with the plugin content in Kanzi Studio.

See Reference for showing Kanzi Engine plugin custom types in Kanzi Studio.

For example, to create the metadata for the custom property type VideoFileNameProperty to allow Kanzi Studio user to select a video file:

@Metadata
@EditorInfo(displayName = "Video Filename",
            tooltip = "Name of the video file to be played.",
            category = "Video",
            editor = "BrowseFileTextEditor",
            defaultValue = "video.mp4")
public static final PropertyType<String> VideoFileNameProperty = new PropertyType("MyPlugin.VideoFileName", String.class);
companion object {
    @Metadata
    @EditorInfo(displayName = "Video Filename",
                tooltip = "Name of the video file to be played.",
                category = "Video",
                editor = "BrowseFileTextEditor",
                defaultValue = "video.mp4")
    val VideoFileNameProperty = PropertyType("MyPlugin.VideoFileName", String::class.java)
}

When the user creates a VideoView2D node, Kanzi Studio adds to the properties of the node in the category Video the Video Filename property, which has a text editor with a Browse button, a tooltip, and the default value set to video.mp4. See Ordering property categories in the Properties window.

../../_images/video-filename-with-category-and-tooltip.png

Property type names cannot contain:

  • A period (.) in the beginning or at the end of a property name

  • Spaces

  • Tabs

  • Slashes (/)

  • Backslashes ()

  • Hashes (#)

  • Opening or closing braces ({})

  • At signs (@)

Setting the default value of a property type

In a custom node you can set the default value of any property type that is defined in the node on which you base your node.

For example, if your node inherits from the Node2D class, to set the default value of the Node.Opacity property type to 0.44, in the makeEditorInfo of your node:

@Metadata
@EditorInfo(
    displayName = "My Node",
    customAttributes =
    {
        // Set the default value of the Node.Opacity property to 0.44.
        @EditorInfoAttribute(key = "override:Node.Opacity:defaultValue", value = "0.44"),
        // (Optional) Set how Kanzi Studio suggests the use of this property type.
        // If the "host" value of the property in the base node is:
        // - "auto", you can use "auto" or "fixed"
        // - "context", you can use "auto", "context", "fixed", or "freq"
        // - "fixed", you can use "fixed"
        // - "freq", you can use "auto", "fixed", or "freq"
        // For example, to automatically add the Node.Opacity property
        // when a user adds your node.
        @EditorInfoAttribute(key = "override:Node.Opacity:host", value = "auto"),
    })
public static Metaclass metaclass = new Metaclass("MyPlugin.MyNode");
companion object {
    @Metadata
    @EditorInfo(
        displayName = "My Node",
        customAttributes =
        {
            // Set the default value of the Node.Opacity property to 0.44.
            @EditorInfoAttribute(key = "override:Node.Opacity:defaultValue", value = "0.44"),
            // (Optional) Set how Kanzi Studio suggests the use of this property type.
            // If the "host" value of the property in the base node is:
            // - "auto", you can use "auto" or "fixed"
            // - "context", you can use "auto", "context", "fixed", or "freq"
            // - "fixed", you can use "fixed"
            // - "freq", you can use "auto", "fixed", or "freq"
            // For example, to automatically add the Node.Opacity property
            // when a user adds your node.
            @EditorInfoAttribute(key = "override:Node.Opacity:host", value = "auto"),
        })
    val metaclass = Metaclass("MyPlugin.MyNode")
}

See host.

Creating custom actions

In a Java Kanzi Engine plugin you can create custom actions with custom property types.

To create a custom action:

  1. In the plugin project create a class.

    For example, create a class named LogAction.

    import com.rightware.kanzi.Action;
    import com.rightware.kanzi.Domain;
    import com.rightware.kanzi.Log;
    import com.rightware.kanzi.Metaclass;
    import com.rightware.kanzi.Metadata;
    import com.rightware.kanzi.EditorInfo;
    
    public class LogAction extends Action
    {
        @Metadata
        @EditorInfo(displayName = "Log Action")
        public static final Metaclass metaclass = new Metaclass("MyPlugin.LogAction");
    
        public static ObjectRef<LogAction> create(Domain domain, String name)
        {
            return Action.createDerived(domain, name, metaclass);
        }
    
        private LogAction(Domain domain, long native, Metaclass metaclass)
        {
            super(domain, native, metaclass);
        }
    
        @Override
        public void onInvoke()
        {
            Log.info("Hello from Java!");
        }
    }
    
    import com.rightware.kanzi.Action
    import com.rightware.kanzi.Domain
    import com.rightware.kanzi.Log
    import com.rightware.kanzi.Metaclass
    import com.rightware.kanzi.Metadata
    import com.rightware.kanzi.EditorInfo
    
    class LogAction private constructor(domain: Domain, native: long, metaclass: Metaclass) :
        Action(domain, native, metaclass) {
    
        override fun onInvoke() {
            Log.info("Hello from Kotlin!")
        }
    
        companion object {
            @Metadata
            @EditorInfo(displayName = "Log Action")
            val metaclass = Metaclass("MyPlugin.LogAction")
    
            @JvmStatic
            fun create(domain: Domain, name: String): ObjectRef<LogAction> {
                return Action.createDerived(domain, name, metaclass)
            }
        }
    }
    
  2. Register the class with the plugin. Adding to your plugin class registerClasses method:

    metaclassRegistry.registerClass(LogAction.class);
    
    metaclassRegistry.registerClass(LogAction::class.java);