In this example, we will show you how to make canvas menu configurations for the mobile editor. The example is based on the Design Editor
, however, it is exactly the same for all the other solutions.
Explore a full code sample on GitHub.
Canvas Menu Architecture#
The canvas menu is a list of items placed horizontally that is displayed when a design block is selected. Items in this list provide different editing capabilities to the selected design block. Every item in the canvas menu conforms to CanvasMenu.Item: EditorComponent
where its Context
is constraint to be of type CanvasMenu.Context
. CanvasMenu.Button
is a provided implementation of the CanvasMenu.Item
protocol that has an action and a label and CanvasMenu.Divider
is a component that renders a divider between items. You can also create your own fully custom editor component that allows drawing arbitrary content by conforming your type to CanvasMenu.Item
.
Modifiers#
After initializing an editor SwiftUI view you can apply any SwiftUI modifier to customize it like for any other SwiftUI view.
All public Swift extension
s of existing types provided by IMG.LY, e.g., for the SwiftUI View
protocol, are exposed in a separate .imgly
property namespace.
The canvas menu configuration to customize the editor is no exception to this rule and is implemented as SwiftUI modifiers.
All canvas menu modifiers and CanvasMenu.Item
s provide the CanvasMenu.Context
to access the engine, the asset library configuration, the EditorEventHandler
, and the current selected design block. Prefer using this provided selection for any logic instead of accessing the same values from the engine because the engine values will update immediately on changes whereas the provided selection value is cached for the presentation time of the canvas menu including its appear and disappear animations.
-
canvasMenuItems
- the@CanvasMenu.Builder
that registers theCanvasMenu.Item
s and defines their order. Note that registering does not mean displaying. The items will be displayed ifCanvasMenu.Item.isVisible(_:)
returns true for them. By default, the items shown in this example are defined for all editor solutions. -
modifyCanvasMenuItems
- the modifications that should be applied to the order of items defined by the.imgly.canvasMenuItems
builder above. This modifier can be used, when you do not want to touch the default general order of the items, but rather add additional items and replace/hide some of the default items. To achieve that, use theCanvasMenu.Modifier
provided as the second closure argument, nameditems
in this example, to add, replace, and remove items as highlighted in modify canvas menu items. By default, no modifications are applied.
Modify Canvas Menu Items#
In this example, we will modify the default canvas menu items
with the .imgly.modifyCanvasMenuItems
modifier. Each modification is only applied to the items defined by .imgly.canvasMenuItems
. The operations also accept a @CanvasMenu.Builder
so that you can define multiple items in the closures.
-
addFirst
- prepends newCanvasMenu.Item
s. -
addLast
- appends newCanvasMenu.Item
s. -
addAfter
- adds newCanvasMenu.Item
s right after the item with the provided id. An error will be thrown if no item exists with the provided id. -
addBefore
- adds newCanvasMenu.Item
s right before the item with the provided id. An error will be thrown if no item exists with the provided id. -
replace
- replaces theCanvasMenu.Item
with the provided id with newCanvasMenu.Item
s. An error will be thrown if no item exists with the provided id. The new items don’t need to have the same id as the replaced item. -
remove
- removes theCanvasMenu.Item
with the provided id. An error will be thrown if no item exists with the provided id.
CanvasMenu.Item Configuration#
As mentioned in the Canvas Menu Architecture section, CanvasMenu.Item
conforms to EditorComponent
. Its id
must be unique which is a requirement of the underlying SwiftUI ForEach
type.
Depending on your needs there are multiple ways to define an item. In this example, we demonstrate your options with increasing complexity.
Use Predefined Buttons#
The most basic option is to use our predefined buttons which are provided in the nested CanvasMenu.Buttons.
namespace. All available predefined buttons are listed below.
Customize Predefined Buttons#
All parameters of our predefined buttons are initialized with default values which allows you to change any of them if needed to finetune the button’s behavior and style. This example uses the default values of this particular predefined button.
-
action
- the action to perform when the user triggers the button. In this example, the event handler is used to delete the selected design block. -
label
- the view that describes the purpose of the button’saction
. Don’t encode the visibility in this view. UseisVisible
instead. In this example, aLabel
view is used. -
isEnabled
- whether the button is enabled. In this example, true is always used. -
isVisible
- whether the button should be visible. Prefer using this parameter to toggle the visibility instead of encoding it in thelabel
view. In this example, true is only used when the selected design block’s scope allows deleting.
Create New Buttons#
If our predefined buttons don’t fit your needs you can create your own.
-
id
- the unique id of the button. This parameter is required. -
action
- the action to perform when the user triggers the button. This parameter is required. -
label
- aView
that describes the purpose of the button’saction
. Don’t encode the visibility in this view. UseisVisible
instead. This parameter is required. -
isEnabled
- whether the button is enabled. By default, true is always used. -
isVisible
- whether the button should be visible. Prefer using this parameter to toggle the visibility instead of encoding it in thelabel
view. By default, true is always used.
Create New Custom Items#
If you need something completely custom you can use arbitrary views as items.
Therefore, you need to conform your type to the CanvasMenu.Item
protocol.
-
var id: EditorComponentID { get }
- the unique id of the item. This property is required. -
func body(_: CanvasMenu.Context) throws -> some View
- the body of your view. Don’t encode the visibility in this view. UseisVisible
instead. This property is required. -
func isVisible(_: CanvasMenu.Context) throws -> Bool
- whether the item should be visible. Prefer using this parameter to toggle the visibility instead of encoding it in thebody
view. By default, true is always used.
List of Available CanvasMenu.Buttons#
This is a comprehensive list of all predefined buttons. Some of them were already used in the previous sections. They are static functions that look like this: CanvasMenu.Buttons.{name}
. All these functions return a CanvasMenu.Button
. They are public and can be used in your application. Note that all the parameters of these functions have default values, therefore, you do not need to provide any values, however, if you want to modify any of the parameters, it is exactly the same as described in the Customize Predefined Buttons section.
Button | ID | Description |
---|---|---|
CanvasMenu.Buttons.bringForward | CanvasMenu.Buttons.ID.bringForward | Brings forward currently selected design block via editor event .bringSelectionForward . |
CanvasMenu.Buttons.sendBackward | CanvasMenu.Buttons.ID.sendBackward | Sends backward currently selected design block via editor event .sendSelectionBackward . |
CanvasMenu.Buttons.duplicate | CanvasMenu.Buttons.ID.duplicate | Duplicates currently selected design block via editor event .duplicateSelection . |
CanvasMenu.Buttons.delete | CanvasMenu.Buttons.ID.delete | Deletes currently selected design block via editor event .deleteSelection . |
CanvasMenu.Buttons.selectGroup | CanvasMenu.Buttons.ID.selectGroup | Selects the group design block that contains the currently selected design block via editor event .selectGroupForSelection . |