When customizing Fusion 360’s user interface, there are two separate concepts: adding buttons to allow the user to run commands and creating custom dialogs for your commands. This topic discusses adding buttons to Fusion 360’s user interface. The creation and use of command dialogs are discussed separately as part of the discussion on commands.
Whenever you add a button into Fusion 360’s user interface, you need to carefully consider where it will go. There is a limited amount of room, and if every add-in writer puts their command in a permanently visible area, there won’t be room for all the commands. Consider what your command does and where the user would logically look for functionality similar to what your command provides. For example, if a command modifies an existing model, it should probably be added to the MODIFY panel in the Design workspace. If it helps control how the design is viewed, it should probably go in the Navigation toolbar at the bottom of the window. Only if your command is doing something unique from other Fusion functionality should you consider adding new tabs or panels.
When dissecting Fusion 360’s user interface, it can be broken down into two main topics; structure and contents.
Several elements provide structure to how the commands are presented in the user interface, as shown below. Shown in blue is the workspace, in red are the toolbars, in yellow are the toolbar tabs, and the toolbar panels are green. The buttons in toolbars and panels are represented by toolbar controls, which are discussed in the “Contents” section below.
A toolbar is a container for controls. A control can be a command button or a drop-down containing more controls and are described below. There are several available toolbars, but there are three that are always displayed. The content of these three is context independent so it remains the same regardless of what’s happening in Fusion 360. Each toolbar and all other user interface elements have unique ID’s that you can use to access a specific toolbar.
The toolbar in the upper-left is commonly known as the QAT or Quick Access Toolbar. Its ID is “QAT”. It provides access to all the file-related commands. The toolbar in the upper-right provides access to the user account and help-related commands, and its ID is “QATRight”. Finally, the toolbar at the bottom center of the window is the navigation toolbar and has all of the view-related commands, and its ID is “NavToolbar”.
All toolbars are accessible from the UserInterface object through its toolbars property which returns a Toolbars object. You can use the itemById property on this object to get a specific toolbar when you know its ID. The sample Python code below gets the Toolbar object that represents the QAT.
app = adsk.core.Application.get() ui = app.userInterface qatToolbar = ui.toolbars.itemById('QAT')
Workspaces are the top-level owner of the UI structure. The user chooses the active workspace using the large drop-down at the upper-left of the Fusion 360 window, as shown below. When changing workspaces, the entire UI morphs to show what's appropriate for the workflow needed by the workspace. For this discussion, we'll focus on the toolbar tabs and their contents, but changing the workspace can also change the contents of the browser and even the model graphics.
Each workspace has its own set of toolbar tabs. Toolbar tabs provide a way to organize the commands needed by the workspace into logical groups. For example, you have the SOLID, SURFACE, MESH, SHEET METAL, and TOOLS tabs in the Design workspace, and each tab represents a different type of data and workflow. For example, by choosing the SOLID tab, you can access the commands used when creating and modifying a solid model. However, only the commands useful when working with a mesh are shown when the MESH tab is selected.
A toolbar tab contains one or more toolbar panels. Toolbar panels organize commands into groups within the toolbar tab. Each toolbar panel consists of two parts; the panel and a drop-down. For example, in the picture below, the ASSEMBLE panel is outlined in red, and its drop-down is outlined in yellow.
The panel shows a subset of the commands in the drop-down and provides easy access to commonly used commands. The user can control which commands from the drop-down are shown in the panel by clicking the More button and checking or unchecking the “Pin to Toolbar” option, as shown below.
There are two ways to access toolbar panels through the API; from the toolbar tab that contains the panel or from a WorkSpace. Panels are guaranteed to be unique within a workspace, so you can access a specific panel if you know the workspace and panel ID. Getting the panel from a toolbar tab is another way to access the same panel.
If you iterate through the toolbar panels in a workspace, you will find the isVisible property for many of them is False, meaning that the panel is not currently visible. When the user selects a different tab, Fusion 360 turns the visibility of toolbar panels on and off, so only those that apply to the active tab are seen.
We’ve looked at the elements that define the structure, and now we’ll look at the content of the toolbars and panels, which are defined using controls.
Both toolbars and toolbar panels act as containers for toolbar controls. There are four different types of controls; command, drop-down, split-button, and separator. In the picture below, all of the buttons you see in the sketch toolbar panel and the associated drop-down menu are command controls and start a command when clicked. The Rectangle, Circle, Arc, and Polygon items are drop-down controls because they display a drop-down menu when they’re clicked. The divider line between the “Create Sketch” and “Line” commands is a separator control used to visually separate and structure the contents of a menu.
The control shown below is a split-button control, which is a button with a small arrow to the right. When the button is clicked, the command displayed on the button is executed, and when the arrow is clicked, a drop-down appears, allowing a choice of other commands. Optionally, the last command picked in the drop-down can become the default command at the top level.
As stated earlier, controls are the visible item you see in the user interface. However, a control serves as a placeholder within a toolbar, and all of the intelligence (text, icon, tooltip, etc.) that we see comes from an associated command definition. Therefore, every control references a command definition to be able to display itself.
Command definitions contain all of the information that defines how a control looks and behaves. A command definition isn’t directly visible but is referenced by a control, and the control uses the information in the command definition to display itself. Having the command definition separate from the control makes it possible to have the same command in more than one place in the user interface. For example, you can add your command to both the DESIGN and MANUFACTURE workspaces. Even when you add your command to a single toolbar panel, there are two controls when the user been pinned the command to the toolbar. In this case, these are two unique controls (one in the panel and one in its drop-down), but both controls reference the same command definition and will behave the same when clicked. If you modify a property of the command definition, that change is automatically reflected in all of the controls that reference that command definition. For example, if the isEnabled property of the command definition is set to False, all controls referencing that command definition will become disabled. Also, when the user clicks any of the controls associated with the command definition, the commandCreated event of the command definition is fired so you can do whatever action the command is supposed to do.
To create a new control, you have first to create a command definition. There is typically a one-to-one relationship between a command definition and what the user thinks of as a command. There are three different types of command definitions (button, check box, and list), and you choose the type based on how you want the command to be displayed in the user interface. For example, a button command definition results in creating a button, while a check box command definition results in a single check box. The example below shows a drop-down control that contains four check box commands (Layout Grid, Layout Grid Lock, Snap to Grid, and Incremental Move). It also contains two button commands (Grid Settings and Set Increments).
The list command definition defines a command displayed as a drop-down with an associated list of checkboxes, radio buttons, or text items. Below is an example of a checkbox list. When “Effects” is clicked, the drop-down is displayed while the user checks and unchecks items in the list. The list remembers any changes, showing the current state the next time it is displayed.
Below is an example of a radio button list. When “Visual Style” is clicked, the drop-down is displayed, and the user can select one item in the list, then the drop-down is dismissed. Like you expect with radio controls, the user can only select one item at a time. The list remembers the selected item, so the next time it is displayed, it will show the currently selected item.
Below is an example of a standard item list that consists of a list of text items. When “Programming Resources” is clicked, the drop-down is displayed, and the user can pick a single item from the list, and then the drop-down is dismissed. In the case of a standard item list, there’s no notion of a “selected” item or state, so nothing is pre-selected when it’s initially displayed.
The API has a single CommandDefinition object type, but each CommandDefinition has an associated ButtonControlDefinition, CheckBoxControlDefinition, or ListControlDefinition object. These three derive from the generic ControlDefinition class. This structure is represented in the object model chart below, along with the Toolbar, Workspace, ToolbarPanel, and various ToolbarControl objects discussed earlier.
Below is some Python code that demonstrates using some of these objects by creating a button and adding it to the bottom of the ADD-INS panel of the MODEL workspace. It also connects to the commandCreated event of the button definition to get a notification when the button is clicked. You can read more about commands in the Commands topic.
# Get the UserInterface object and the CommandDefinitions collection. ui = app.userInterface cmdDefs = ui.commandDefinitions # Create a button command definition. buttonExample = cmdDefs.addButtonDefinition('MyButtonDefId', 'Sample Button', 'Sample button tooltip', './/Resources//Sample') # Connect to the command created event. buttonExampleCreated = ButtonExampleCreatedEventHandler() buttonExample.commandCreated.add(buttonExampleCreated) handlers.append(buttonExampleCreated) # Get the "DESIGN" workspace. designWS = ui.workspaces.itemById('FusionSolidEnvironment') # Get the "ADD-INS" panel from the "DESIGN" workspace. addInsPanel = designWS.toolbarPanels.itemById('SolidScriptsAddinsPanel') # Add the button to the bottom. buttonControl = addInsPanel.controls.addCommand(buttonExample) # Make the button available in the panel. buttonControl.isPromotedByDefault = True buttonControl.isPromoted = True
Typically, you’ll add commands when your add-in is loaded, which modifies the Fusion 360 user interface only for the current session of Fusion 360. Fusion 360 does not remember any edits made to the user interface, so everything is restored to its default state the next time Fusion 360 runs, and your add-in will need to re-create its commands each time it starts up. If the user unloads an add-in using the Scripts and Add-Ins command, all of its commands will be displayed for that session but will be dead because the add-in is no longer running to handle the commandCreated events. Your add-in needs to clean up and delete any user interface elements it has created to prevent this. It does this in its stop function, which Fusion 360 calls when the add-in is unloaded. Your add-in should delete both the command definitions and controls.The Python code below demonstrates deleting the command definition and control that were created above.
# Get the UserInterface object and the CommandDefinitions collection. ui = app.userInterface cmdDefs = ui.commandDefinitions # Delete the button definition. buttonExample = ui.commandDefinitions.itemById('MyButtonDefId') if buttonExample: buttonExample.deleteMe() # Get the "DESIGN" workspace. designWS = ui.workspaces.itemById('FusionSolidEnvironment') # Get panel the control is in. addInsPanel = designWS.toolbarPanels.itemById('SolidScriptsAddinsPanel') # Get and delete the button control. buttonControl = addInsPanel.controls.itemById('MyButtonDefId') if buttonControl: buttonControl.deleteMe()
Many of the controls support using an icon. In Fusion 360, an icon is defined using a folder that contains all of the images for that command. Each icon has a folder of resource images. Fusion 360 often needs two icons for a command, so there are different sizes of the same image in the resource directory of a command. For example, when a command is added to a toolbar panel when running on a standard resolution display, the icon shown in the drop-down is 16x16 pixels. However, if the user pins it to the panel, then it uses a 32x32 pixel icon. When running on a high-resolution display, 32x32 and 64x64 pixel images are used instead. To support both standard and high resolutions, you need to provide three sizes for each icon. Fusion 360 uses a naming standard, so it knows which image is which. The file names for the default image are:
For each size, Fusion 360 also supports a disabled version of the image. Typically just a gray version of the standard image. If you don’t provide one, Fusion will create one from the standard image, if needed. The images are:
Finally, Fusion 360 also supports a version of the image that’s used when the command is active. In this case the button appears depressed and the background is a dark blue. You can create a custom image for this case so that any dark colors don’t disappear into the background. If you don't provide one, Fusion will create one from the standard image. The images are:
Below are the images used for the Fusion 360 extrude command as an example.
If you don’t provide a required image, Fusion 360 will automatically create a placeholder image with the correct name and the picture of a question mark. If you see a question mark for any of your commands, it means you’re missing one of the required images, and you’ll need to replace it with the correct image.
Resources are defined by specifying the path to the resource folder. The path to the resource folder can be defined using a relative or full path. A relative path is relative to the main .py, .dll, or .dylib file. For example, for the folder structure shown below, the relative path to the images for the Keyhole command in the SketchShapes add-in is "./Resources/Keyhole" since the SketchShapes.py file is in the SketchShapes folder..
You can see from the example above there is a folder for each command. Each folder contains its own set of icon image files, as described above.
There are two steps to positioning your command within the Fusion user interface. The first is to determine where you want to add your command. The ideal location is where someone familiar with Fusion would intuitively look for your command. The best approach to this is to run Fusion and see if you can find any existing commands that might be similar to your command. For example, if your command does something with a sketch, it should be with the other sketch commands. It will help if you are critical about your choice to create a new tab or panels. Creating tabs and panels only makes sense when your functionality is unique from any existing commands. This choice is subjective, and nothing prevents you from doing anything you choose, but your users will be annoyed if you do something illogical or take up unneeded space.
The second step is the most challenging part of adding a new command into Fusion 360's user interface. This step is to get the information you need to position the control in the location you want. For example, to create a new control in a panel, you'll need the ID of the workspace that contains the panel, the ID of the panel, and the ID of the command you want your command to be next to.
Let's look at a typical example and the process used to get the information you need. For this example, we want to insert a button for a command called "Custom Pocket". The command creates new geometry in a solid model, so we want to add it to the DESIGN workspace. In addition, because it works on solid models, we want to add it to the CREATE panel on the SOLID tab beneath the "Emboss" command, as shown below.
To position the button, we need the ID of the DESIGN workspace, the ID of the CREATE panel, and the ID of the "Emboss" command. A complete list of user interface IDs is not published because the user interface is dynamic since add-ins can customize it however they want. Instead, what's provided is a script that creates a report of the current state of the user interface. The script is the Write user interface to a file Sample sample script. To use it, create a new Python script, copy the sample code into the script, and run it. It will read your current Fusion user interface layout and export it as an XML file.
You can open the XML file in VS Code or any editor that works with XML files. The file is exported as XML to allow the data to be structured to make it easier to read and manipulate. You'll see the file is large, and looking through it for a specific item would be tedious. However, if you take advantage of the XML structure, it becomes much easier. If you press Ctrl + K and then Ctrl + 0 (zero), you'll invoke the Fold command to collapse the structure down to one visible level. Ctrl + K, Ctrl + J will unfold it, so the entire tree is visible. You can also fold to a specific level using Ctrl + K, Ctrl + (number), where (number) defines the number of levels to display. Clicking the > sign to left of an element will expand the structure below it. The picture below shows the tree fully folded; the middle picture shows it expanded one level where we can easily see there are 16 workspaces and 11 toolbars defined. The picture on the right shows the Workspaces node expanded, where we can see the names and IDs of all the workspaces. It's now relatively easy to scan this list and find the "Design" workspace, where we want to insert out button.
Now that we've found the workspace we want to use, we can continue to expand the tree to find the SOLID tab, the CREATE panel, and the Emboss command. The names underlined in yellow are the same names you see in the Fusion 360 interface and are what you would use when searching. However, it's the IDs of each of these elements, which are underlined in green, that we need.
Using the IDs underlined above, the code below adds the command button to the user interface.
# Get the DESIGN workspace. designWS = ui.workspaces.itemById('FusionSolidEnvironment') # Get the CREATE panel. createPanel = designWS.toolbarPanels.itemById('SolidCreatePanel') # Add a new button before after the Emboss control. buttonControl = createPanel.controls.addCommand(customPocketCmdDef, 'EmbossCmd', False)
You might notice that the code doesn't use the toolbar tab. Because panels are unique within a workspace, having the ID of the workspace and the panel is enough to get the panel. The code below will also work since it's possible to get the panel from the tab too.
# Get the DESIGN workspace. designWS = ui.workspaces.itemById('FusionSolidEnvironment') # Get the SOLID tab. solidTab = designWS.toolbarTabs.itemById('SolidTab') # Get the CREATE panel. createPanel = solidTab.toolbarPanels.itemById('SolidCreatePanel') # Add a new button before after the Emboss control. buttonControl = createPanel.controls.addCommand(customPocketCmdDef, 'EmbossCmd', False)
Here's another example that adds a command into the QAT toolbar. In this case, we want to insert "My Special File Command" in the file drop-down of the QAT above the "3D Print" command, as shown below.
To do this, you need the ID of the QAT toolbar, the ID of the File drop-down, and the ID of the "3D print command". By expanding the Toolbars sections of the XML, you can identify each and find their corresponding ID, as shown below.
Knowing the IDs, here's the code that adds the new button.
# Get the QAT toolbar. qat = ui.toolbars.itemById('QAT') # Get the drop-down that contains the file related commands. fileDropDown = qat.controls.itemById('FileSubMenuCommand') # Add a new button before the 3D Print control. buttonControl = fileDropDown.controls.addCommand(myCommandDef, 'ThreeDprintCmdDef', True)