Skip to content

Positioning and Alignment

In this example, we will show you how to use the CreativeEditor SDK’s CreativeEngine to modify scenes layout through the block API.

Layout of Blocks

The CreativeEngine supports three different modes for positioning blocks. These can be set for each block and both coordinates independently:

  • Absolute: the position value is interpreted in the scene’s current design unit.
  • Percent: the position value is interpreted as percentage of the block’s parent’s size, where 1F means 100%.
  • Auto : the position is automatically determined.

Likewise there are also three different modes for controlling a block’s size. Again both dimensions can be set independently:

  • Absolute: the size value is interpreted in the scene’s current design unit.
  • Percent: the size value is interpreted as percentage of the block’s parent’s size, where 1F means 100%.
  • Auto : the block’s size is automatically determined by the size of the block’s content.

Positioning

fun getPositionX(block: DesignBlock): Float

Query a block’s x position.

  • block: the block to query.

  • Returns the value of the x position.

fun getPositionY(block: DesignBlock): Float

Query a block’s y position.

  • block: the block to query.

  • Returns the value of the y position.

fun getPositionXMode(block: DesignBlock): PositionMode

Query a block’s mode for its x position.

  • block: the block to query.

  • Returns the current mode for the x position.

fun getPositionYMode(block: DesignBlock): PositionMode

Query a block’s mode for its y position.

  • block: the block to query.

  • Returns the current mode for the y position.

fun setPositionX(
block: DesignBlock,
value: Float,
)

Update a block’s x position.

The position refers to the block’s local space, relative to its parent with the origin at the top left.

Required scope: “layer/move”

  • block: the block to update.

  • value: the value of the x position.

fun setPositionY(
block: DesignBlock,
value: Float,
)

Update a block’s y position.

The position refers to the block’s local space, relative to its parent with the origin at the top left.

Required scope: “layer/move”

  • block: the block to update.

  • value: the value of the y position.

fun setPositionXMode(
block: DesignBlock,
mode: PositionMode,
)

Set a block’s mode for its x position.

The position refers to the block’s local space, relative to its parent with the origin at the top left.

Required scope: “layer/move”

  • block: the block to update.

  • mode: the x position mode.

fun setPositionYMode(
block: DesignBlock,
mode: PositionMode,
)

Set a block’s mode for its y position.

The position refers to the block’s local space, relative to its parent with the origin at the top left.

Required scope: “layer/move”

  • block: the block to update.

  • mode: the y position mode.

Size

fun getWidth(block: DesignBlock): Float

Query a block’s width.

  • block: the block to query.

  • Returns the value of the block’s width.

fun getWidthMode(block: DesignBlock): SizeMode

Query a block’s mode for its width.

  • block: the block to query.

  • Returns the current mode for the width.

fun getHeight(block: DesignBlock): Float

Query a block’s height.

  • block: the block to query.

  • Returns the value of the block’s height.

fun getHeightMode(block: DesignBlock): SizeMode

Query a block’s mode for its height.

  • block: the block to query.

  • Returns the current mode for the height.

fun setWidth(
block: DesignBlock,
value: Float,
maintainCrop: Boolean = false,
)

Update a block’s width and optionally maintain the crop.

If the crop is maintained, the crop values will be automatically adjusted.

The content fill mode Cover is only kept if the features/transformEditsRetainCoverMode setting is enabled, otherwise it will change to Crop.

Required scope: “layer/resize”

  • block: the block to update.

  • value: the new width of the block.

  • maintainCrop: whether or not the crop values, if available, should be automatically adjusted.

fun setWidthMode(
block: DesignBlock,
mode: SizeMode,
)

Set a block’s mode for its width.

Required scope: “layer/resize”

  • block: the block to update.

  • mode: the width mode.

fun setHeight(
block: DesignBlock,
value: Float,
maintainCrop: Boolean = false,
)

Update a block’s height and optionally maintain the crop.

If the crop is maintained, the crop values will be automatically adjusted.

The content fill mode Cover is only kept if the features/transformEditsRetainCoverMode setting is enabled, otherwise it will change to Crop.

Required scope: “layer/resize”

  • block: the block to update.

  • value: the new height of the block.

  • maintainCrop: whether or not the crop values, if available, should be automatically adjusted.

fun setHeightMode(
block: DesignBlock,
mode: SizeMode,
)

Set a block’s mode for its height.

Required scope: “layer/resize”

  • block: the block to update.

  • mode: the height mode.

Rotation

fun getRotation(block: DesignBlock): Float

Query a block’s rotation in radians.

  • block: the block to query.

  • Returns the block’s rotation around its center in radians.

fun setRotation(
block: DesignBlock,
radians: Float,
)

Update a block’s rotation.

Required scope: “layer/rotate”

  • block: the block to update.

  • radians: the new rotation in radians. Rotation is applied around the block’s center.

Flipping

fun setFlipHorizontal(
block: DesignBlock,
flip: Boolean,
)

Update a block’s horizontal flip.

Required scope: “layer/flip”

  • block: the block to update.

  • flip: if the flip should be enabled.

fun isFlipHorizontal(block: DesignBlock): Boolean

Query a block’s horizontal flip state.

  • block: the block to query.

  • Returns a boolean indicating for whether the block is flipped in the queried direction.

fun setFlipVertical(
block: DesignBlock,
flip: Boolean,
)

Update a block’s vertical flip.

Required scope: “layer/flip”

  • block: the block to update.

  • flip: if the flip should be enabled.

fun isFlipVertical(block: DesignBlock): Boolean

Query a block’s vertical flip state.

  • block: the block to query.

  • Returns a boolean indicating for whether the block is flipped in the queried direction.

Scaling

fun scale(
block: DesignBlock,
scale: Float,
@FloatRange(from = 0.0, to = 1.0) anchorX: Float,
@FloatRange(from = 0.0, to = 1.0) anchorY: Float,
)

Scales the block and all of its children proportionally around the specified relative anchor point.

This updates the position, size and style properties (e.g. stroke width) of

the block and its children.

Required scope: “layer/resize”

  • block: the block that should be scaled.

  • scale: the scale factor to be applied to the current properties of the block.

  • anchorX: the relative position along the width of the block around which the

scaling should occur. (0F = left edge, 0.5F = center, 1F = right edge)

  • anchorY: the relative position along the height of the block around which the

scaling should occur. (0F = top edge, 0.5F = center, 1F = bottom edge)

Fill a Block’s Parent

fun fillParent(block: DesignBlock)

Resize and position a block to entirely fill its parent block.

The crop values of the block, except for the flip and crop rotation, are reset if it can be cropped.

If the size of the block’s fill is unknown, the content fill mode is changed from Crop to Cover to prevent invalid crop values.

Required scope: “layer/move”

  • “layer/resize”

  • block: The block that should fill its parent.

Resize Blocks Content-aware

fun resizeContentAware(
blocks: List<DesignBlock>,
width: Float,
height: Float,
)

Resize all blocks to the given size. The content of the blocks is automatically adjusted to fit the

new dimensions.

Required scope: “layer/resize”

  • blocks: The blocks to resize.

  • width: The new width of the blocks.

  • height: The new height of the blocks.

Even Distribution

fun isDistributable(blocks: List<DesignBlock>): Boolean

Confirms that a given set of blocks can be distributed.

  • blocks: a non-empty array of block ids.

  • Returns whether the blocks can be distributed.

fun distributeHorizontally(blocks: List<DesignBlock>)

Distribute multiple blocks vertically within their bounding box so that the space between them is even.

Required scope: “layer/move”

  • blocks: a non-empty array of block ids that should be distributed.
fun distributeVertically(blocks: List<DesignBlock>)

Distribute multiple blocks vertically within their bounding box so that the space between them is even.

Required scope: “layer/move”

  • blocks: a non-empty array of block ids that should be distributed.

Alignment

fun isAlignable(blocks: List<DesignBlock>): Boolean

Confirms that a given set of blocks can be aligned.

  • blocks: a non-empty array of block ids.

  • Returns whether the blocks can be aligned.

fun alignHorizontally(
blocks: List<DesignBlock>,
alignment: HorizontalBlockAlignment,
)

Align multiple blocks vertically within their bounding box or a single block to its parent.

Required scope: “layer/move”

  • blocks: a non-empty array of block ids that should be aligned.

  • alignment: How they should be aligned: left, right, or center

fun alignVertically(
blocks: List<DesignBlock>,
alignment: VerticalBlockAlignment,
)

Align multiple blocks vertically within their bounding box or a single block to its parent.

Required scope: “layer/move”

  • blocks: a non-empty array of block ids that should be aligned.

  • alignment: How they should be aligned: top, bottom, or center

Computed Dimensions

fun getFrameX(block: DesignBlock): Float

Get a block’s layout position on the x-axis. The layout position is only available after an

internal update loop, which may not happen immediately.

  • block: the block to query.

  • Returns the layout position.

fun getFrameY(block: DesignBlock): Float

Get a block’s layout position on the y-axis. The layout position is only available after an

internal update loop, which may not happen immediately.

  • block: the block to query.

  • Returns the layout position.

fun getFrameWidth(block: DesignBlock): Float

Get a block’s layout width. The layout width is only available after an internal update loop, which may not happen immediately.

  • block: the block to query.

  • Returns the layout width.

fun getFrameHeight(block: DesignBlock): Float

Get a block’s layout height. The layout height is only available after an internal update loop, which may not happen immediately.

  • block: the block to query.

  • Returns the layout height.

fun getGlobalBoundingBoxX(block: DesignBlock): Float

Get the x position of the block’s axis-aligned bounding box in the scene’s global coordinate space.

The scene’s global coordinate space has its origin at the top left.

  • block: the block to query.

  • Returns the x coordinate of the position of the axis-aligned bounding box.

fun getGlobalBoundingBoxY(block: DesignBlock): Float

Get the y position of the block’s axis-aligned bounding box in the scene’s global coordinate space.

The scene’s global coordinate space has its origin at the top left.

  • block: the block to query.

  • Returns the y coordinate of the position of the axis-aligned bounding box.

fun getGlobalBoundingBoxWidth(block: DesignBlock): Float

Get the width of the block’s axis-aligned bounding box in the scene’s global coordinate space.

The scene’s global coordinate space has its origin at the top left.

  • block: the block to query.

  • Returns the width of the axis-aligned bounding box.

fun getGlobalBoundingBoxHeight(block: DesignBlock): Float

Get the height of the block’s axis-aligned bounding box in the scene’s global coordinate space.

The scene’s global coordinate space has its origin at the top left.

  • block: the block to query.

  • Returns the height of the axis-aligned bounding box.

fun getScreenSpaceBoundingBoxRect(blocks: List<DesignBlock>): RectF

Get the position and size of the axis-aligned bounding box for the given blocks in screen space.

  • blocks: the blocks whose bounding box should be calculated.

  • Returns the position and size of the bounding box as RectF.

Layers

fun setAlwaysOnTop(
block: DesignBlock,
enabled: Boolean,
)

Update the block’s always-on-top property. If true, this blocks’s global sorting order is automatically

adjusted to be higher than all other siblings

without this property. If more than one block is set to be always-on-top, the child order decides which is on top.

  • block: the block to update.

  • enabled: whether the block shall be always-on-top.

fun isAlwaysOnTop(block: DesignBlock): Boolean

Query a block’s always-on-top property.

  • block: the block to query.

  • Returns true if the block is set to be always-on-top, false otherwise.

fun setAlwaysOnBottom(
block: DesignBlock,
enabled: Boolean,
)

Update the block’s always-on-bottom property. If true, this blocks’s global sorting order is automatically

adjusted to be lower than all other siblings

without this property. If more than one block is set to be always-on-bottom, the child order decides which is on the bottom.

  • block: the block to update.

  • enabled: whether the block shall be always-on-bottom.

fun isAlwaysOnBottom(block: DesignBlock): Boolean

Query a block’s always-on-bottom property.

  • block: the block to query.

  • Returns true if the block is set to be always-on-bottom, false otherwise.

fun bringToFront(block: DesignBlock)

Updates the sorting order of this block and all of its manually created siblings

so that the given block has the highest sorting order.

If the block is parented to a track, it is first moved up in the hierarchy.

  • block: the block to be given the highest sorting order among its siblings.
fun sendToBack(block: DesignBlock)

Updates the sorting order of this block and all of its manually created siblings

so that the given block has the lowest sorting order.

If the block is parented to a track, it is first moved up in the hierarchy.

  • block: the block to be given the lowest sorting order among its siblings.
fun bringForward(block: DesignBlock)

Updates the sorting order of this block and all of its superjacent siblings

so that the given block has a higher sorting order than the next superjacent sibling.

If the block is parented to a track, it is first moved up in the hierarchy.

Empty tracks and empty groups are passed by.

  • block: the block to be given a higher sorting than the next superjacent sibling.
fun sendBackward(block: DesignBlock)

Updates the sorting order of this block and all of its manually created and subjacent siblings

so that the given block will have a lower sorting order than the next subjacent sibling.

If the block is parented to a track, it is first moved up in the hierarchy.

Empty tracks and empty groups are passed by.

  • block: the block to be given a lower sorting order than the next subjacent sibling.

Transform Locking

You can lock the transform of a block to prevent changes to any of its transformations. That is the block’s position, rotation, scale, and sizing.

fun isTransformLocked(block: DesignBlock): Boolean

Query a block’s transform locked state. If true, the block’s transform can’t be changed.

  • block: the block to query.

  • Returns true if block is locked, false otherwise.

fun setTransformLocked(
block: DesignBlock,
locked: Boolean,
)

Update a block’s transform locked state.

  • block: the block to update.

  • locked: whether the block’s transform should be locked.

Full Code

Here’s the full code:

val x = engine.block.getPositionX(block)
val xMode = engine.block.getPositionXMode(block)
val y = engine.block.getPositionY(block)
val yMode = engine.block.getPositionYMode(block)
engine.block.setPositionX(block, value = 0.25F)
engine.block.setPositionXMode(block, mode = PositionMode.PERCENT)
engine.block.setPositionY(block, value = 0.25)
engine.block.setPositionYMode(block, mode = PositionMode.PERCENT)
val rad = engine.block.getRotation(block)
engine.block.setRotation(block, radians = PI.toFloat())
val isFlipHorizontal = engine.block.isFlipHorizontal(block)
val isFlipVertical = engine.block.isFlipVertical(block)
engine.block.setFlipHorizontal(block, flip = true)
engine.block.setFlipVertical(block, flip = false)
val width = engine.block.getWidth(block)
val widthMode = engine.block.getWidthMode(block)
val height = engine.block.getHeight(block)
val heightMode = engine.block.getHeightMode(block)
engine.block.setWidth(block, value = 0.5F)
engine.block.setWidth(block, value = 2.5F, maintainCrop = true)
engine.block.setWidthMode(block, mode = SizeMode.PERCENT)
engine.block.setHeight(block, value = 0.5F)
engine.block.setHeight(block, value = 2.5F, maintainCrop = true)
engine.block.setHeightMode(block, mode = SizeMode.PERCENT)
val frameX = engine.block.getFrameX(block)
val frameY = engine.block.getFrameY(block)
val frameWidth = engine.block.getFrameWidth(block)
val frameHeight = engine.block.getFrameHeight(block)
engine.block.setAlwaysOnTop(block, false)
val isAlwaysOnTop = engine.block.isAlwaysOnTop(block)
engine.block.setAlwaysOnBottom(block, false)
val isAlwaysOnBottom = engine.block.isAlwaysOnBottom(block)
engine.block.bringToFront(block)
engine.block.sendToBack(block)
engine.block.bringForward(block)
engine.block.sendBackward(block)
val globalX = engine.block.getGlobalBoundingBoxX(block)
val globalY = engine.block.getGlobalBoundingBoxY(block)
val globalWidth = engine.block.getGlobalBoundingBoxWidth(block)
val globalHeight = engine.block.getGlobalBoundingBoxHeight(block)
val screenSpaceRect = engine.block.getScreenSpaceBoundingBoxRect(listOf(block))
engine.block.scale(block, scale = 2F, anchorX = 0.5F, anchorY = 0.5F)
engine.block.fillParent(block)
val pages = engine.scene.getPages()
engine.block.resizeContentAware(pages, width = 100F, height = 100F)
// Create blocks and append to scene
val member1 = engine.block.create(DesignBlockType.Graphic)
val member2 = engine.block.create(DesignBlockType.Graphic)
engine.block.appendChild(scene, child = member1)
engine.block.appendChild(scene, child = member2)
if (engine.block.isDistributable(listOf(member1, member2))) {
engine.block.distributeHorizontally(listOf(member1, member2))
engine.block.distributeVertically(listOf(member1, member2))
}
if (engine.block.isAlignable(listOf(member1, member2))) {
engine.block.alignHorizontally(listOf(member1, member2), alignment = HorizontalBlockAlignment.LEFT)
engine.block.alignVertically(listOf(member1, member2), alignment = VerticalBlockAlignment.TOP)
}
val isTransformLocked = engine.block.isTransformLocked(block)
if (!isTransformLocked) {
engine.block.setTransformLocked(block, locked = true)
}