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 try engine.editor.findAllScopes()
.
let scopes = try engine.editor.findAllScopes()
We currently support the following scopes:
Scope | Explanation |
---|---|
"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 try engine.editor.setGlobalScope(key: "layer/move", value: .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.
Value | Explanation |
---|---|
.allow | Manipulation of properties covered by the scope is always allowed |
.deny | Manipulation of properties covered by the scope is always denied |
.defer | Permission is deferred to the scope of the individual blocks |
/* Let the global scope defer to the block-level. */ try engine.editor.setGlobalScope(key: "layer/move", value: .defer)
/* Manipulation of layout properties of any block will fail at this point. */ do { try engine.block.setPositionX(block, value: 100) // Not allowed } catch { print(error.localizedDescription) }
We can verify the current state of the global "layer/move"
scope using try engine.editor.getGlobalScope(key: "layer/move")
.
/* This will return `.defer`. */try engine.editor.getGlobalScope(key: "layer/move")
Now we can allow the "layer/move"
scope for a single block by setting it to true
using func setScopeEnabled(_ id: DesignBlockID, key: String, enabled: Bool) throws
.
/* Allow the user to control the layout properties of the image block. */ try engine.block.setScopeEnabled(block, key: "layer/move", enabled: true)
/* Manipulation of layout properties of any block is now allowed. */ do { try engine.block.setPositionX(block, value: 100) // Allowed } catch { print(error.localizedDescription) }
Again we can verify this change by calling func isScopeEnabled(_ id: DesignBlockID, key: String) throws -> Bool
.
/* Verify that the "layer/move" scope is now enabled for the image block. */try engine.block.isScopeEnabled(block, key: "layer/move")
Finally, func isAllowedByScope(_ id: DesignBlockID, key: String) throws -> Bool
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 `.defer`. */try engine.block.isAllowedByScope(block, key: "layer/move")
Full Code
Here’s the full code:
import Foundationimport IMGLYEngine
@MainActorfunc scopes(engine: Engine) async throws { let scene = try await engine.scene.create(fromImage: .init(string: "https://img.ly/static/ubq_samples/imgly_logo.jpg")!) let block = try engine.block.find(byType: .graphic).first!
let scopes = try engine.editor.findAllScopes()
/* Let the global scope defer to the block-level. */ try engine.editor.setGlobalScope(key: "layer/move", value: .defer)
/* Manipulation of layout properties of any block will fail at this point. */ do { try engine.block.setPositionX(block, value: 100) // Not allowed } catch { print(error.localizedDescription) }
/* This will return `.defer`. */ try engine.editor.getGlobalScope(key: "layer/move")
/* Allow the user to control the layout properties of the image block. */ try engine.block.setScopeEnabled(block, key: "layer/move", enabled: true)
/* Manipulation of layout properties of any block is now allowed. */ do { try engine.block.setPositionX(block, value: 100) // Allowed } catch { print(error.localizedDescription) }
/* Verify that the "layer/move" scope is now enabled for the image block. */ try engine.block.isScopeEnabled(block, key: "layer/move")
/* This will return true as well since the global scope is set to `.defer`. */ try engine.block.isAllowedByScope(block, key: "layer/move")}