Search Docs
Loading...
Skip to content

Value Sets

Keep named alternative values for scene variables in value sets, and switch the values that the scene shows.

6 mins
estimated time
GitHub

A variable gets its value from two layers. The scene saves its variables with their default values, as the Text Variables and Variable Bindings guides show. A value set holds named alternative values for some of these variables, such as worst-case texts or another language. Text, bound properties, getters and exports show the value of the active value set, if it has one, else the default value.

Scene Variables#

A setter writes the default value of a new scene variable, and undo reverts the change. We create a text that shows first_name and a card whose fill follows accent.

// Scene variables belong to the scene. A save writes them, and undo reverts them.
engine.variable.set(key = "first_name", value = "Ada")
engine.variable.setColor(key = "accent", value = Color.fromRGBA(r = 0.48F, g = 0.23F, b = 0.93F, a = 1F))
val card = engine.block.create(DesignBlockType.Graphic)
engine.block.setShape(block = card, shape = engine.block.createShape(ShapeType.Rect))
engine.block.setFill(block = card, fill = engine.block.createFill(FillType.Color))
engine.block.setWidth(block = card, value = 720F)
engine.block.setHeight(block = card, value = 520F)
engine.block.setPositionX(block = card, value = 40F)
engine.block.setPositionY(block = card, value = 40F)
engine.block.appendChild(parent = page, child = card)
val cardFill = engine.block.getFill(block = card)
engine.block.setVariableBinding(block = cardFill, property = "fill/color/value", key = "accent")
val text = engine.block.create(DesignBlockType.Text)
engine.block.replaceText(block = text, text = "Hello {{first_name}}")
engine.block.setWidth(block = text, value = 640F)
engine.block.setHeightMode(block = text, mode = SizeMode.AUTO)
engine.block.setPositionX(block = text, value = 80F)
engine.block.setPositionY(block = text, value = 80F)
engine.block.appendChild(parent = page, child = text)

Creating Value Sets#

createValueSet adds an empty set to the scene and returns its id, a ValueSetId. Pass target = VariableTarget.ValueSet(id) to a setter to write a value into the set. A set holds values only for scene variables, and each value has the type of its variable.

// A value set holds alternative values for some scene variables.
val longNames = engine.variable.createValueSet(name = "Long names")
engine.variable.set(
key = "first_name",
value = "Maximiliane Huber-Schwarzenberg",
target = VariableTarget.ValueSet(longNames),
)
val valueSets = engine.variable.findAllValueSets() // [longNames]
val valueSetName = engine.variable.getValueSetName(set = longNames) // Long names

Set names are unique in a scene, must not be empty and must not start or end with whitespace. setValueSetName renames a set, findAllValueSets lists the ids in creation order, and findValueSetByName finds an id by its name. remove(key = _, target = VariableTarget.ValueSet(id)) removes one value from a set, and the variable shows its default again.

Activating a Value Set#

setActiveValueSet makes the values of one set win over the defaults. A variable that the set has no value for shows its default. Pass null to show the defaults again. A getter without a target returns the value that the scene shows. Pass target = VariableTarget.Default to read only the default value.

// The active set wins over the default values in text, bound properties and getters.
engine.variable.setActiveValueSet(set = longNames)
val shownName = engine.variable.get(key = "first_name") // Maximiliane Huber-Schwarzenberg
val defaultName = engine.variable.get(key = "first_name", target = VariableTarget.Default) // Ada
// A variable that the set has no value for shows its default.
val shownAccent = engine.variable.getColor(key = "accent") // the purple default

The scene saves the active set, and undo reverts a switch.

Writing Without a Target#

A setter without a target writes the layer that the getter reads. When the active set holds the key, the setter writes the set. Otherwise it writes the default value. So get always returns what set wrote.

// A setter without a target writes the layer that the getter reads: the active set
// when it holds the key, else the default value.
engine.variable.set(key = "first_name", value = "Maximiliane Huber")
val writtenName = engine.variable.get(key = "first_name") // Maximiliane Huber
val defaultAfterWrite = engine.variable.get(key = "first_name", target = VariableTarget.Default) // Ada
engine.variable.setColor(key = "accent", value = Color.fromRGBA(r = 0.95F, g = 0.45F, b = 0.1F, a = 1F))
val cardColor = engine.block.getColor(block = cardFill, property = "fill/color/value") // the new orange default

Exporting the Result#

An export shows the values of the active set, as the canvas does. Here the card shows Maximiliane Huber, which the write above put into the active set, and the orange color.

// Exports show the values of the active set, as the canvas does.
val previewPng = engine.block.export(block = page, mimeType = MimeType.PNG)

Saving and Loading#

A save writes the default values, the value sets and the active set. A load replaces the scene variables and value sets with those of the loaded scene. The scene saves the id of each set, so an id stays the same across saves, loads and renames.

// A save holds the default values, the value sets and the active set.
val saved = engine.scene.saveToString(scene = scene)
engine.scene.load(scene = saved)
// The scene saves the id of a set, so it stays the same across a load.
val activeSetKeepsId = engine.variable.getActiveValueSet() == longNames // true
val foundSetKeepsId = engine.variable.findValueSetByName(name = "Long names") == longNames // true

Applying a template keeps the variables, the value sets and the active set of the current scene. It adds the variables and value sets of the template that the scene lacks.

Setting Variables Before a Load#

A variable that you set while no scene exists waits for the next scene. The next created or loaded scene takes it as a setter without a target writes it. That is the active set when the set holds the key, else the default. A value of another type than the loaded variable is dropped. Use it to fill a template with the data of one record.

// A variable set while no scene exists waits for the next scene. That scene takes it over
// its own value, for example to fill a template with the data of one record.
engine.block.destroy(block = requireNotNull(engine.scene.get()))
engine.variable.set(key = "city", value = "Berlin")
engine.scene.load(scene = saved)
val cityAfterLoad = engine.variable.get(key = "city") // Berlin

Handling Errors#

A value set holds values only for variables of the scene. A second set with a taken name fails too. Each call throws an EngineException whose code names the error.

// A value set holds values only for variables of the scene.
val missingVariableErrorCode = try {
engine.variable.set(key = "missing", value = "x", target = VariableTarget.ValueSet(longNames))
null
} catch (error: EngineException) {
// EngineErrorCode.BLOCK_VARIABLE_NOT_FOUND
error.code
}
val nameTakenErrorCode = try {
engine.variable.createValueSet(name = "Long names")
null
} catch (error: EngineException) {
// EngineErrorCode.BLOCK_VALUE_SET_NAME_TAKEN
error.code
}

Destroying Value Sets#

destroyValueSet removes a set and its values. When the set is active, the defaults show again. Undo restores the set with the same id.

// Destroying the active set shows the default values again.
engine.variable.destroyValueSet(set = longNames)
val activeSetAfterDestroy = engine.variable.getActiveValueSet() // null
val nameAfterDestroy = engine.variable.get(key = "first_name") // Ada

Troubleshooting#

  • The name of the set is taken (BLOCK.VALUE_SET_NAME_TAKEN): pick a name that no set of the scene uses.
  • The name of the set is not valid (BLOCK.VALUE_SET_NAME_INVALID): use a name that is not empty and has no leading or trailing whitespace.
  • The set does not exist (BLOCK.VALUE_SET_NOT_FOUND): the set was destroyed, or the scene was replaced. Find the set again with findValueSetByName.
  • A set value without a variable (BLOCK.VARIABLE_NOT_FOUND): create the scene variable first.
  • The value has another type (BLOCK.VARIABLE_TYPE_MISMATCH): use the type of the scene variable of the same key.
  • No scene exists (SCENE.MUST_EXIST): create or load a scene before you create, change or read a value set. Without a scene, findAllValueSets returns an empty list, and findValueSetByName and getActiveValueSet return null.

The Error Catalog lists every error code.

API Reference#

Method Description
engine.variable.set(key=_, value=_, target=_) and the other setters Write the shown layer, the default (VariableTarget.Default) or a set value (VariableTarget.ValueSet(id))
engine.variable.get(key=_, target=_) and the other getters Read the shown value, or one layer
engine.variable.remove(key=_, target=_) Remove a variable, or the value of one set
engine.variable.createValueSet(name=_) Create a value set
engine.variable.destroyValueSet(set=_) Destroy a value set and its values
engine.variable.setValueSetName(set=_, name=_) / getValueSetName(set=_) Rename a set, or read its name
engine.variable.findAllValueSets() List the sets of the scene
engine.variable.findValueSetByName(name=_) Find a set by its name, or null
engine.variable.setActiveValueSet(set=_) / getActiveValueSet() Activate a set or null, or read the active set

Next Steps#