Skip to content

Lock the Template

CE.SDK allows you to control which parts of a block can be manipulated. Scopes describe different aspects of a block, e.g. layout or style and can be enabled or disabled for every single block. There’s also the option to control a scope globally. When configuring a scope globally you can set an override to always allow or deny a certain type of manipulation for every block. Or you can configure the global scope to defer to the individual block scopes.

Initially, the block-level scopes are all disabled while at the global level all scopes are set to "Allow". This overrides the block-level and allows for any kind of manipulation.

If you want to implement a limited editing mode in your software you can set the desired scopes on the blocks you want the user to manipulate and then restrict the available actions by globally setting the scopes to "Defer". In the same way you can prevent any manipulation of properties covered by a scope by setting the respective global scope to "Deny".

Available Scopes

You can retrieve all available scopes by calling engine.editor.findAllScopes().

val scopes = engine.editor.findAllScopes()

We currently support the following scopes:

ScopeExplanation
"layer/move"Whether the block’s position can be changed
"layer/resize"Whether the block can be resized
"layer/rotate"Whether the block’s rotation can be changed
"layer/flip"Whether the block can be flipped
"layer/crop"Whether the block’s content can be cropped
"layer/clipping"Whether the block’s clipping can be changed
"layer/opacity"Whether the block’s opacity can be changed
"layer/blendMode"Whether the block’s blend mode can be changed
"layer/visibility"Whether the block’s visibility can be changed
"appearance/adjustments"Whether the block’s adjustments can be changed
"appearance/filter"Whether the block’s filter can be changed
"appearance/effect"Whether the block’s effect can be changed
"appearance/blur"Whether the block’s blur can be changed
"appearance/shadow"Whether the block’s shadow can be changed
"lifecycle/destroy"Whether the block can be deleted
"lifecycle/duplicate"Whether the block can be duplicated
"editor/add"Whether new blocks can be added
"editor/select"Whether a block can be selected or not
"fill/change"Whether the block’s fill can be changed
"fill/changeType"Whether the block’s fill type can be changed
"stroke/change"Whether the block’s stroke can be changed
"shape/change"Whether the block’s shape can be changed
"text/edit"Whether the block’s text can be changed
"text/character"Whether the block’s text properties can be changed

Managing Scopes

First, we globally defer the "layer/move" scope to the block-level using engine.editor.setGlobalScope(key = "layer/move", globalScope = GlobalScope.DEFER). Since all blocks default to having their scopes set to false initially, modifying the layout properties of any block will fail at this point.

ValueExplanation
.allowManipulation of properties covered by the scope is always allowed
.denyManipulation of properties covered by the scope is always denied
.deferPermission is deferred to the scope of the individual blocks
// Let the global scope defer to the block-level.
engine.editor.setGlobalScope(key = "layer/move", globalScope = GlobalScope.DEFER)
// Manipulation of layout properties of any block will fail at this point.
try {
engine.block.setPositionX(block, value = 100F) // Not allowed
} catch (exception: Exception) {
exception.printStackTrace()
}

We can verify the current state of the global "layer/move" scope using engine.editor.getGlobalScope(key = "layer/move").

// This will return `GlobalScope.DEFER`.
engine.editor.getGlobalScope(key = "layer/move")

Now we can allow the "layer/move" scope for a single block by setting it to true using fun setScopeEnabled(block: DesignBlock, key: String, enabled: Boolean).

// Allow the user to control the layout properties of the image block.
engine.block.setScopeEnabled(block, key = "layer/move", enabled = true)
// Manipulation of layout properties of any block is now allowed.
try {
engine.block.setPositionX(block, value = 100F) // Allowed
} catch (exception: Exception) {
exception.printStackTrace()
}

Again we can verify this change by calling fun isScopeEnabled(block: DesignBlock, key: String): Boolean.

// Verify that the "layer/move" scope is now enabled for the image block.
engine.block.isScopeEnabled(block, key = "layer/move")

Finally, fun isAllowedByScope(block: DesignBlock, key: String): Boolean will allow us to verify a block’s final scope state by taking both the global state as well as block-level state into account.

// This will return true as well since the global scope is set to `GlobalScope.DEFER`.
engine.block.isAllowedByScope(block, key = "layer/move")

Full Code

Here’s the full code:

import android.net.Uri
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import ly.img.engine.DesignBlockType
import ly.img.engine.Engine
import ly.img.engine.GlobalScope
fun scopes(
license: String,
userId: String,
) = CoroutineScope(Dispatchers.Main).launch {
val engine = Engine.getInstance(id = "ly.img.engine.example")
engine.start(license = license, userId = userId)
engine.bindOffscreen(width = 100, height = 100)
engine.scene.createFromImage(Uri.parse("https://img.ly/static/ubq_samples/imgly_logo.jpg"))
val block = engine.block.findByType(DesignBlockType.Graphic).first()
val scopes = engine.editor.findAllScopes()
// Let the global scope defer to the block-level.
engine.editor.setGlobalScope(key = "layer/move", globalScope = GlobalScope.DEFER)
// Manipulation of layout properties of any block will fail at this point.
try {
engine.block.setPositionX(block, value = 100F) // Not allowed
} catch (exception: Exception) {
exception.printStackTrace()
}
// This will return `GlobalScope.DEFER`.
engine.editor.getGlobalScope(key = "layer/move")
// Allow the user to control the layout properties of the image block.
engine.block.setScopeEnabled(block, key = "layer/move", enabled = true)
// Manipulation of layout properties of any block is now allowed.
try {
engine.block.setPositionX(block, value = 100F) // Allowed
} catch (exception: Exception) {
exception.printStackTrace()
}
// Verify that the "layer/move" scope is now enabled for the image block.
engine.block.isScopeEnabled(block, key = "layer/move")
// This will return true as well since the global scope is set to `GlobalScope.DEFER`.
engine.block.isAllowedByScope(block, key = "layer/move")
engine.stop()
}