diff --git a/README.rst b/README.rst
index e92fc49..e439b33 100644
--- a/README.rst
+++ b/README.rst
@@ -2,7 +2,7 @@
trame-simput
============
-Simput implementation for trame
+SimPut implementation for Trame.
* Free software: Apache Software License
@@ -10,6 +10,7 @@ Simput implementation for trame
Installing
----------
+
Build and install the Vue components
.. code-block:: console
@@ -26,8 +27,39 @@ Install the application
pip install -e .
+Introduction
+------------
+
+SimPut empowers developers to create applications with complex user input in no time.
+High level definition files allow developers to describe in a concise manner what they want rather
+than how to make their data editing possible within their application.
+
+SimPut relies on **definitions** to describe a set of **proxies** that it can control.
+A **proxy** is a virtual object that gathers a set of **properties**, which as a whole
+represents its **state**. **Proxies** are meant to streamline **state** update and exchange.
+
+A **proxy** can also be used to control a **concrete object** by mapping its state to it.
+This is particulary important when a **concrete object** needs to live on a remote location
+or inside another thread or service. Having a **proxy** allows us to present and edit its **properties**
+in a way that we can easily reconciliate its **state** with its **concrete object** counter-part.
+
+When initializing or editing a **property**, we may want to bind the values to a limited set.
+To apply constraints to a **property**, you can define a **domains** section.
+A **domain** can be used to compute a reasonable **initial value** once all its dependency have
+been resolved or limit a value to be within a set of available ones (list, range).
+
+On top of the data model, SimPut aims to provide UI/forms to help users input and update
+any user data. And for that we have some UI needs that could be defined to refine how
+the information should be displayed to the user. By default the data model **definition**
+is all we need, but if you want to add internationalization, you can provide a **language**
+definition to describe **label** and **help** of any **property**. Then if the automatic
+property layout is not to your liking, you can create a **layout** definition to manually place
+into a grid where each **property** of a given **proxy** should go. Also, you can use that
+**layout** to optionally show/hide a subset of properties based on a **domain**.
+
-Features
---------
+Detailed documents
+------------------
-* TODO
+* `Definitions <./docs/definitions.md/>`_
+* `API <./docs/api.md>`_
diff --git a/docs/api.md b/docs/api.md
new file mode 100644
index 0000000..2315a54
--- /dev/null
+++ b/docs/api.md
@@ -0,0 +1,492 @@
+# API
+
+SimPut relies on 3 types of managers that build on top of each other and are responsible for handling Proxy, UI and Domains.
+
+- **ProxyManager**:
+
+ - Loads proxy definitions
+ - Creates/Deletes proxies
+ - Finds/Gets proxies
+ - Updates proxies from a changeset
+ - Commits/Resets all modified proxies
+ - Imports/Exports state of all created proxies
+ - (optional) Maps proxy state to concrete object
+
+- **UIManager**:
+
+ - Requires **ProxyManager** and **UI resolver**
+ - Loads language/layout definitions
+ - Gets proxy state for UI
+ - Gets proxy form for UI (include language + layout)
+
+- **ProxyDomainManager**:
+
+ - Attaches to **ProxyManager** to add behavior to proxy initialization and update.
+ - Creates a **ProxyDomain** for each newly created proxy.
+ - Monitors dirty proxies during an update, so modified domains can be applied in one sweep.
+ - Gets **ProxyDomain** from proxy id.
+
+## ProxyManager
+
+**Definition handling**
+
+```python
+def load_model(self, yaml_file=None, yaml_content=None):
+ """Load Data Model from YAML definition"""
+
+def get_definition(self, proxy_type):
+ """Return a loaded definition for a given object_type"""
+
+def types(self, *with_tags):
+ """List proxy_types from definition that has the set of provided tags"""
+```
+
+**Proxy Management**
+
+```python
+def create(self, proxy_type, **initial_values):
+ """
+ Create a new instance of a proxy using an proxy_type along with
+ maybe a set of property values that we want to pre-initialise using the
+ **kwargs approach.
+ """
+
+def delete(self, proxy_id, trigger_modified=True):
+ """
+ Delete object along with its dependency that it is owner of
+ """
+
+def get(self, proxy_id: str) -> Proxy:
+ """
+ return proxy instance
+ """
+
+def update(self, change_set):
+ """
+ changeSet = [
+ { id: 2143, name: 'Origin', value: [0, 1, 3] },
+ ...
+ ]
+ """
+```
+
+**Import / Export**
+
+```python
+def save(self, file_output=None):
+ """Export state (definition+data) into a file"""
+
+def load(self, file_input=None, file_content=None):
+ """Load previously exported state from a file"""
+```
+
+**Commit / Reset**
+
+```python
+def commit_all(self):
+ """Commit all dirty proxies"""
+
+def reset_all(self):
+ """Reset all dirty proxies"""
+```
+
+**Find / Query Proxy**
+
+```python
+def get_instances_of_type(self, proxy_type):
+ """
+ Return all the instances of the given type
+ """
+
+def tags(self, *args):
+ """List all instances containing all the listed tags"""
+```
+
+### Proxy
+
+Core proxy properties
+
+```python
+@property
+def manager(self):
+ """Return ProxyManager that owns us"""
+
+@property
+def definition(self):
+ """Return Proxy definition"""
+
+@property
+def type(self):
+ """Return Proxy Type"""
+
+@property
+def id(self):
+ """Return Proxy ID"""
+
+@property
+def object(self):
+ """Return Proxy concrete object if any"""
+```
+
+Advanced Read/Write properties
+
+```python
+@property
+def tags(self):
+ """Return the list of tags of that proxy"""
+
+@property
+def own(self):
+ """List of proxy ids we created"""
+```
+
+Property management
+
+```python
+def set_property(self, name, value):
+ """Update a property on that proxy"""
+
+def get_property(self, name, default=None):
+ """Return a property value"""
+
+def list_property_names(self):
+ """Return the list of property names"""
+
+# ---------------------------------------------------------
+# Attribute/Item usage
+# ---------------------------------------------------------
+# - Get property:
+# - print(proxy_inst.prop_name)
+# - print(proxy_inst["prop_name"])
+# - Set property
+# - proxy_inst.prop_name = 3
+# - proxy_inst["prop_name"] = 3
+# ---------------------------------------------------------
+```
+
+Commit / Reset property edit
+
+```python
+def commit(self):
+ """Flush modified properties"""
+
+def reset(self):
+ """Undo any uncommited properties"""
+```
+
+State management for IO and import/export
+
+```python
+@property
+def state(self):
+ """Return proxy state that is easily serializable"""
+
+@state.setter
+def state(self, value):
+ """Use to rebuild a proxy state from an exported state"""
+
+def remap_ids(self, id_map):
+ """Use to remap id when reloading an exported state"""
+```
+
+### ObjectValue
+
+Base class for objects that can be used as a value for properties.
+They can be passed around by copy instead of reference. A proxy still provides the same reference, on which you can interact with method calls, but when the value needs to be shared to another location or service, the object gets serialized and re-created on the other side in a transparent manner.
+
+The expected API is as follow:
+
+```python
+ @property
+ def state(self):
+ """
+ Return a serialized version of its state.
+ The type of ObjectValue is not included in the state and
+ therefore the initial instantiation is left to the proxy.
+ """
+
+ @state.setter
+ def state(self, value):
+ """Update internal data from provided serialized state"""
+```
+
+## UIManager
+
+The **UIManager** needs a **ProxyManager** and a **UIResolver** at construction time.
+
+**Load language/layout definitions**
+
+```python
+def load_language(self, yaml_file=None, yaml_content=None, clear_ui=False):
+ """Load langage for the objects form"""
+
+def load_ui(self, xml_file=None, xml_content=None, clear_ui=False):
+ """Load layout for the objects form"""
+
+def clear_ui(self):
+ """
+ Clear any loaded UI definition
+ => This will force auto-generation if nothing new gets loaded
+ """
+```
+
+**Data exchange for UI handling**
+
+```python
+def data(self, proxy_id):
+ """Return proxy state to fill UI with"""
+
+def ui(self, _type):
+ """Return resolved layout (xml string with resolved elements+attributes)"""
+```
+
+### UIResolver
+
+A **UIResolver** is responsible to process the XML from a `` definition and convert it into another XML that can then be used by a UI backend (Vuetify, Qt, ...) without much processing logic.
+The resolver has access to labels and helps from the language file along with the model definition that can include domains.
+
+Below you can see how a `` element will be transformed for the Vuetify target.
+
+**Input**
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output**
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## ProxyDomainManager
+
+A **ProxyDomainManager** is responsible to add behavior on a **ProxyManager** by listening to proxy creation and update. For that it needs to be registered to the **ProxyManager** by calling `pxm.add_life_cycle_listener(pdm)`.
+
+Once registered, it will track **ProxyDomain** for each created proxy. Also, whenever proxy updates happen, it will keep track of the modified one to only re-execute any domain that needs to be updated.
+Users just need to call `apply_all()` after any batch update to flush the domain and set any missing property initialization.
+
+### ProxyDomain
+
+```python
+def apply(self, *property_names):
+ """
+ Ask domains to set values or just for one property if property_name is provided.
+ Return the number of properties that have been updated.
+ """
+
+def get_property_domains(self, prop_name):
+ """Helper to get the map of domains linked to a property"""
+
+@property
+def state(self):
+ """
+ Return a serializable state of the domains linked to a proxy.
+ This include for each property and each domain a `valid` and `available` property.
+ Also at the property level a list of `hints`.
+
+ state = {
+ ContourBy: {
+ FieldSelector: {
+ valid: True,
+ available: [
+ { text: "Temperature", value: "Point::Temperature", ... },
+ ...
+ ]
+ },
+ hints: [],
+ },
+ Scalar: {
+ Range: {
+ valid: True,
+ available: [0.5, 123.5],
+ },
+ hints: [
+ { level: 0, message: "Outside of range (0.5, 123.5)" },
+ ],
+ },
+ }
+ """
+```
+
+### PropertyDomain
+
+```python
+def enable_set_value(self):
+ """Reset domain set so it can re-compute a default value"""
+
+def set_value(self):
+ """
+ Ask domain to compute and set a value to a property.
+ return True if the action was succesful.
+ """
+
+def available(self):
+ """List the available options"""
+
+@property
+def value(self):
+ """Return the current proxy property value on which the domain is bound"""
+
+@value.setter
+def value(self, v):
+ """Set the proxy property value"""
+
+def valid(self, required_level=2):
+ """Return true if the current proxy property value is valid for the given level"""
+
+@property
+def level(self):
+ """Return current domain level (0:info, 1:warn, 2:error)"""
+
+@level.setter
+def level(self, value):
+ """Update domain level"""
+
+@property
+def message(self):
+ """Associated domain message that is used for hints"""
+
+@message.setter
+def message(self, value):
+ """Update domain message"""
+
+def hints(self):
+ """Return a set of (level, message) when running the validation for the info level"""
+```
+
+## Domains
+
+Concrete implementation of domains.
+
+### ProxyBuilder
+
+```
+ initial: xyz | set name=xyz proxy to the property as default
+ values: | list all possible proxy that can be set
+ - name: xyz | proxy entry: - name
+ type: Representation | - proxy type
+ bind: Input | set self to SubProxy.Input property (optional)
+```
+
+### IsEqual
+
+```
+ name: Scalars | (optional) provide another name than its type
+ available: {type/name} | Which domain available list on prop to use
+ value: Scalar | Value that our prop needs to match to be "valid"
+```
+
+### FieldSelector
+
+```
+ name: List | (optional) provide another name than its type
+ input: Input | Specify property on which field inspection happen
+ location: Point | Filtering arrays to be only on [Point/Cell/Field]
+ size: 1 | Number of components for available arrays
+ initial: first | (optional) if provided, domain will set array to prop
+ isA: | (optional) filter arrays by their type
+ - vtkDataArray | => Only numerical arrays
+```
+
+### Range
+
+```
+ name: xxxx | (optional) provide another name than its type
+ -----------------------------------------------------------------------------
+ value_range: [0, 1] | Static range
+ -----------------------------------------------------------------------------
+ property: PropArray | Specify property on which an array is defined
+ initial: [mean, min, max] | Computation to use for setting the value
+ component: -1 (mag) | Component to use for range computation
+```
+
+### ResetOnChange \*\*
+
+```
+ name: xxxx | (optional) provide another name than its type
+ -----------------------------------------------------------------------------
+ property: Property name | When current property change reset domain on
+ domain: Domain name/type | property so default values could be regenerated
+```
+
+### BoundsCenter
+
+```
+ name: xxxx | (optional) provide another name than its type
+ -----------------------------------------------------------------------------
+ proxy: Property name containing data object proxy
+ property: Property on Proxy that is the data object
+```
+
+### LabelList
+
+```
+ name: xxxx | (optional) provide another name than its type
+ -----------------------------------------------------------------------------
+ values: [{ text, value}, ...]
+```
+
+## ObjectValue
+
+Concrete implementation of object values
+
+### Array
+
+Capture Array name and location (point/cell/field)
diff --git a/docs/definitions.md b/docs/definitions.md
new file mode 100644
index 0000000..7bbbba6
--- /dev/null
+++ b/docs/definitions.md
@@ -0,0 +1,230 @@
+# Data model definition
+
+In order to describe the various **proxies** and **properties** we want to use, we rely on
+a __YAML__ file like the one below.
+
+```yaml
+vtkSphereSource: # `Type` of proxy
+ _tags: # (optional) metadata binding
+ - Source # tag name to be assotiated to this kind of proxy
+ Radius: # `Property name`
+ size: 1 # how many values expected (default: 1)
+ type: float64 # value type: (u)int(8,16,32,64), float(32,64), bool, proxy, value::{kind}
+ initial: 0.5 # initial value to set
+ Center: # Property `Center` contains 3 floats with an initial value of [0, 0, 0]
+ size: 3
+ type: float64
+ initial: [0, 0, 0]
+ ThetaResolution: # Property `ThetaResolution` contains a single positive integer
+ type: uint16
+ PhiResolution:
+ type: uint16
+ StartTheta:
+ type: float64
+ EndTheta:
+ type: float64
+ StartPhi:
+ type: float64
+ EndPhi:
+ type: float64
+ LatLongTesselation: # Property `LatLongTesselation` contains a single boolean value
+ type: bool
+ OuptuPointsPrecision:
+ type: uint8
+ GenerateNormal:
+ type: bool
+
+vtkConeSource: # Another proxy `Type`
+ _tags:
+ - Source
+ Height:
+ type: float64
+ # ...
+
+# ...
+```
+
+The __YAML__ structure follow the given hierarchy:
+
+1. Proxy type: Unique string representing the type of a given proxy.
+ 1. _tags: Internal key use to capture a list of `labels` for a given proxy so they can be found/filtered later on.
+ 2. Property name: Unique string within current proxy representing an entry in your data model.
+ 1. Property caracteristics:
+ 1. size: How many values should be stored for that property. Skipping size attribute will imply a size of 1.
+ 2. type: What kind of values that property is holding.
+ 1. uint(8,16,32,64): Unsigned integer encoded on 8, 16, 32, 64 bytes.
+ 2. int(8,16,32,64): Signed integer encoded on 8, 16, 32, 64 bytes.
+ 3. float(32,64): Floating point encoded on 32 or 64 bytes.
+ 4. bool: Boolean (true/false)
+ 5. proxy: Reference to another proxy inside our database.
+ 6. value::{kind}: Object that can be defined by the user, which can be assimilated as a type.
+ 2. Optional internal hints:
+ 1. _label: Internal key for replacing the property name for a given **language** for the UI layer
+ 2. _help: Internal key for providing help on the property for a given **language** for the UI layer
+ 3. _ui: Internal key to help the UI layer to dynamically build a corresponding **layout** definition if one was not provided.
+ 1. skip: Will skip showing that entry in the layout
+ 2. proxy: Will show the content of the linked proxy rather than (proxy selection + selected proxy content)
+ 4. _set: Internal key to help map proxy state to a concrete object
+ 5. _get: Internal key to help map concrete object to proxy state
+ 6. _***: Internal key that will be skipped unless needed by some specific implementation
+ 3. Optional domain related:
+ 1. domains: Container for listing any domain that should be linked to a property.
+ 1. A domain entry should contain:
+ 1. type: Name of the domain class
+ 2. name: (optional) Identifier when we don't want to use its `type` as an identifier.
+ 3. **: Additional parameters specific to domain type expectation.
+
+# Domain definitions
+
+Domains help to compute initial values or constraint user input.
+
+An example for **compute initial value** could be the following use case where we have a vtkAlgorithm
+that will perform some operation on its input dataset using one of the input fields. Such a vtkAlgorithm will need to select which `Field` should be used for the processing and which `Value` should be used as a seed for the computation while the `Value` should be within range of the selectedd `Field`. The following definition describes exactly that in the context of a `vtkCountourFilter`.
+
+```yaml
+vtkContourFilter:
+ Input:
+ _ui: skip
+ type: proxy
+
+ ContourBy:
+ type: value::Array
+ domains:
+ - name: List
+ type: FieldSelector
+ input: Input
+ location: Point
+ size: 1
+ initial: first # Among the available list use the first one as initial value
+ isA:
+ - vtkDataArray
+
+ Contours:
+ type: float64
+ size: -1 # Undetermined size
+ domains:
+ - type: Range
+ property: ContourBy
+ initial: mean # Using the array selected by `ContourBy` compute the `mean` as initial value
+ level: 1 # 2=slider 1-0=text
+ - type: UI
+ properties:
+ layout: vertical
+ sizeControl: 1
+```
+
+A property **domain** has the following set of reserved keys:
+- type: Name of a registered domain class
+- name: (optional) Application identifier when its `type` is not sufficient. (e.g. if several domains with same type are used by another domain)
+- initial: (optional) When provided, the domain will try to set an initial value to the property.
+- level: (optional) How severe that domain shoud be.
+ - 0: (default) information
+ - 1: warning
+ - 2: error
+- message: (optional) Text that should be displayed if the domain is not valid, so the user can understand what's wrong.
+- **: Any other key required by a specific domain type.
+
+# Langage definition
+
+SimPut does not provide an API for switching languages, but simply focuses on loading **labels** and **helps** from definition files. Within your application you then have the opportunity to load different files based on a selected language. And you have the choice to clear previous content or simply override any definition read.
+
+In order to support several languages easily, we allow the user to separate them from the core model definition and just write what matters. But as an initial pass, the core model definition can be used as a language file with or without `_label` and `_help` entries. Then a more light-weight file can be read with just the translation part. As you can see below the structure remains similar to our core model definition, but we only focus on `_label` and `_help` for each section. Also it is possible to change the **order** in which the properties should appear. This will take into account when a **layout** file is not provided.
+
+```yaml
+# fr.yaml
+vtkSphereSource:
+ _label: Sphère
+ _help: Génère un maillage représentant une sphère
+ Radius:
+ _label: Rayon
+ Center:
+ _label: Centre
+ ThetaResolution:
+ _label: Résolution autour de theta
+ PhiResolution:
+ _label: Résolution autour de phi
+ StartTheta:
+ _label: Angle initial pour theta
+ EndTheta:
+ _label: Angle final pour theta
+ StartPhi:
+ _label: Angle initial pour phi
+ EndPhi:
+ _label: Angle final pour phi
+```
+
+# Layout definition
+
+The layout definition is mainly there to control the flow of properties by being explicit. By default, if not provided, the property order defined in the loaded **language** definition will be used in a vertical layout. But if the user wants full control of it, an XML file can be provided. The example below captures most of the syntax to illustrate its capabilities.
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+Each proxy UI is defined by a `` element, which can be gathered inside a single XML file by nesting them under a `` container. Each `` element must contain an `id=` attribute to bind such UI layout to a proxy type defintion.
+
+Inside a `` element you can use `
` and `` to control the direction of the flow of properties. A `` and `` is also available to push properties to the end of the current flow or create a line separator between them. When a simple text annotation should be placed, the `` can be used.
+
+A property gets exposed by adding a `` entry.
+
+When a property is of `type: proxy`, the `` will display a drop-down assuming a "ListDomain" is used to define the possible set of proxies that can be set for that property while `` will inline the UI for the proxy that the property is refering to. By default, a generated layout will add `` and `` one after the other unless an attribute `_ui: skip` or `_ui: proxy` is defined on that property. The **skip** option will skip both while the **proxy** will only show the `` part.
+
+On top of those core elements, we also have containers that can be used to **show** or **hide** a set of properties. They work by using a domain to perform their action `` or ``.
+
+```yaml
+Clip:
+ ClipFunction:
+ type: proxy
+ domains:
+ - type: ProxyBuilder
+ initial: Plane
+ values:
+ - name: Plane
+ type: ImplicitPlane
+ - name: Box
+ type: ImplicitBox
+ - name: Sphere
+ type: ImplicitSphere
+ - name: Scalar
+ type: ImplicitPlaceHolder
+ - name: Scalars
+ type: IsEqual
+ available: ProxyBuilder
+ value: Scalar
+ # ...
+```
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+Using the following set of elements you should be able to layout your various properties. But depending on the UI resolver used in the processing of your layout file, you can provide additional attributes that could control component styles such as `class=""` or `layout="m3-half"` for lenghty properties. So far, the supported layout values for a property are: `vertical`, `l2`, `l3`, `l4`, `m3-half`. The `l{number}` are for grouping `number` entries per line. No layout is similar to `horizontal`.
\ No newline at end of file