├── .gitignore ├── _config.yml ├── Fusion360Utilities ├── .gitignore ├── Fusion360DebugUtilities.py ├── Fusion360Utilities.py └── Fusion360CommandBase.py ├── resources ├── 16x16.png ├── 32x32.png ├── 64x64.png ├── cover_image.png ├── AddinsDialog.png ├── changeParams.png ├── 16x16-disabled.png └── 32x32-disabled.png ├── ParamEdit.manifest ├── ParamEdit.py ├── README.md └── ParamEditCommand.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | .idea/ 3 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /Fusion360Utilities/.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | .idea/ 3 | -------------------------------------------------------------------------------- /resources/16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tapnair/ParamEdit/HEAD/resources/16x16.png -------------------------------------------------------------------------------- /resources/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tapnair/ParamEdit/HEAD/resources/32x32.png -------------------------------------------------------------------------------- /resources/64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tapnair/ParamEdit/HEAD/resources/64x64.png -------------------------------------------------------------------------------- /resources/cover_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tapnair/ParamEdit/HEAD/resources/cover_image.png -------------------------------------------------------------------------------- /resources/AddinsDialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tapnair/ParamEdit/HEAD/resources/AddinsDialog.png -------------------------------------------------------------------------------- /resources/changeParams.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tapnair/ParamEdit/HEAD/resources/changeParams.png -------------------------------------------------------------------------------- /resources/16x16-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tapnair/ParamEdit/HEAD/resources/16x16-disabled.png -------------------------------------------------------------------------------- /resources/32x32-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tapnair/ParamEdit/HEAD/resources/32x32-disabled.png -------------------------------------------------------------------------------- /ParamEdit.manifest: -------------------------------------------------------------------------------- 1 | { 2 | "autodeskProduct": "Fusion360", 3 | "type": "addin", 4 | "id": "20984b2f-e336-4891-b64e-5e542449b15b", 5 | "author": "Patrick Rainsberry", 6 | "description": { 7 | "": "Creates a GUI for all User Parameters" 8 | }, 9 | "version": "0.1", 10 | "runOnStartup": false, 11 | "supportedOS": "windows|mac" 12 | } -------------------------------------------------------------------------------- /ParamEdit.py: -------------------------------------------------------------------------------- 1 | # Author-Patrick Rainsberry 2 | # Description-Creates a GUI for all User Parameters 3 | 4 | # Script to update all user parameters in a model 5 | # Any variables will be loaded into the UI form with current value 6 | # New values are validated before applying to the model. 7 | 8 | # Importing sample Fusion Command 9 | # Could import multiple Command definitions here 10 | from .ParamEditCommand import ParamEditCommand 11 | 12 | commands = [] 13 | command_definitions = [] 14 | 15 | # Define parameters for vent maker command 16 | cmd = { 17 | 'cmd_name': 'ParamEdit', 18 | 'cmd_description': 'Enables you to edit all User Parameters', 19 | 'cmd_resources': './resources', 20 | 'cmd_id': 'cmdID_ParamEdit', 21 | 'workspace': 'FusionSolidEnvironment', 22 | 'toolbar_panel_id': 'SolidModifyPanel', 23 | 'class': ParamEditCommand 24 | } 25 | command_definitions.append(cmd) 26 | 27 | # Set to True to display various useful messages when debugging your app 28 | debug = False 29 | 30 | # Don't change anything below here: 31 | for cmd_def in command_definitions: 32 | command = cmd_def['class'](cmd_def, debug) 33 | commands.append(command) 34 | 35 | 36 | def run(context): 37 | for run_command in commands: 38 | run_command.on_run() 39 | 40 | 41 | def stop(context): 42 | for stop_command in commands: 43 | stop_command.on_stop() 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ![](./resources/32x32.png) EditParam 2 | 3 | This is an [Autodesk Fusion 360](http://fusion360.autodesk.com/) script that's used for simply editing user parameters. 4 | 5 | 6 | ![Change Parameters](./resources/cover_image.png) 7 | 8 | 9 | # Installation 10 | [Click here to download the Add-in](https://github.com/tapnair/ParamEdit/archive/master.zip) 11 | 12 | After downloading the zip file follow the [installation instructions here](https://tapnair.github.io/installation.html) for your particular OS version of Fusion 360 13 | 14 | ## Usage 15 | 16 | 1. Enter the Model environment 17 | 2. You can create User parameters to drive dimensions in your design here: 18 | - Select Modify->Change Parameters 19 | 20 | ![Change Parameters](./resources/changeParams.png) 21 | 3. Now you can easily modify and User Generated parameters in a simplified UI by selecting paramEdit 22 | - Select Modify->paramEdit 23 | - Update changes are now previewed live in the UI 24 | 25 | 26 | ## License 27 | Samples are licensed under the terms of the [MIT License](http://opensource.org/licenses/MIT). Please see the [LICENSE](LICENSE) file for full details. 28 | 29 | ## Written by 30 | 31 | Written by [Patrick Rainsberry](https://twitter.com/prrainsberry)
(Autodesk Fusion 360 Business Development) 32 | 33 | See more useful [Fusion 360 Utilities](https://tapnair.github.io/index.html) 34 | 35 | [![Analytics](https://ga-beacon.appspot.com/UA-41076924-3/paramEdit)](https://github.com/igrigorik/ga-beacon) 36 | -------------------------------------------------------------------------------- /ParamEditCommand.py: -------------------------------------------------------------------------------- 1 | __author__ = 'rainsbp' 2 | 3 | import adsk.core 4 | import adsk.fusion 5 | import traceback 6 | 7 | from .Fusion360Utilities.Fusion360Utilities import get_app_objects 8 | from .Fusion360Utilities.Fusion360CommandBase import Fusion360CommandBase 9 | 10 | 11 | def update_params(inputs): 12 | # Gets necessary application objects from utility function 13 | app_objects = get_app_objects() 14 | design = app_objects['design'] 15 | units_manager = app_objects['units_manager'] 16 | 17 | if inputs.count < 1: 18 | app_objects['ui'].messageBox('No User Parameters in the model') 19 | return 20 | 21 | # Set all parameter values based on the input form 22 | for param in design.userParameters: 23 | input_expression = inputs.itemById(param.name).value 24 | 25 | # Use Fusion Units Manager to validate user expression 26 | if units_manager.isValidExpression(input_expression, units_manager.defaultLengthUnits): 27 | 28 | # Set parameter value from input form 29 | param.expression = input_expression 30 | 31 | else: 32 | app_objects['ui'].messageBox("The following expression was invalid: \n" + 33 | param.name + '\n' + 34 | input_expression) 35 | 36 | 37 | class ParamEditCommand(Fusion360CommandBase): 38 | def on_preview(self, command, inputs, args, input_values): 39 | update_params(inputs) 40 | 41 | def on_execute(self, command, inputs, args, input_values): 42 | update_params(inputs) 43 | 44 | def on_create(self, command, inputs): 45 | # Gets necessary application objects from utility function 46 | app_objects = get_app_objects() 47 | design = app_objects['design'] 48 | 49 | for param in design.userParameters: 50 | inputs.addStringValueInput(param.name, 51 | param.name, 52 | param.expression) 53 | -------------------------------------------------------------------------------- /Fusion360Utilities/Fusion360DebugUtilities.py: -------------------------------------------------------------------------------- 1 | __author__ = 'rainsbp' 2 | 3 | import time 4 | import os 5 | from os.path import expanduser 6 | 7 | import adsk.core 8 | import adsk.fusion 9 | import traceback 10 | 11 | 12 | # Print a list of list of variables 13 | # Format of variables should be [[Variable name 1, variable value 1], [Variable name 2, variable value 2], ...] 14 | def variable_message(variables): 15 | 16 | message_string = '' 17 | for variable in variables: 18 | message_string += variable[0] + ' = ' + str(variable[1]) + '\n' 19 | 20 | app = adsk.core.Application.get() 21 | ui = app.userInterface 22 | 23 | if ui: 24 | ui.messageBox(message_string) 25 | 26 | 27 | # Performance time logging function 28 | def perf_log(log, function_reference, command, identifier=''): 29 | log.append((function_reference, command, identifier, time.process_time())) 30 | 31 | 32 | def perf_message(log): 33 | 34 | minimum_perf_time = .01 35 | message_string = '' 36 | 37 | log_file_name = get_log_file_name() 38 | log_file = open(log_file_name, 'w') 39 | 40 | total_t = log[-1][3] - log[0][3] 41 | 42 | message_string += 'Total Time = ' + "%0.6f" % total_t + '\n' 43 | 44 | for index, entry in enumerate(log[1:]): 45 | delta_t = entry[3] - log[index][3] 46 | 47 | if delta_t > minimum_perf_time: 48 | message_string += entry[0] + ' ' + entry[1] + ' ' + entry[2] + ' = ' + "%0.6f" % delta_t + '\n' 49 | 50 | log_file.write(entry[0] + ',' + entry[1] + ',' + entry[2] + ',' + str(delta_t) + '\n') 51 | 52 | log_file.close() 53 | 54 | app = adsk.core.Application.get() 55 | ui = app.userInterface 56 | 57 | if ui: 58 | ui.messageBox(message_string) 59 | 60 | 61 | # Creates directory and returns file name for log file 62 | def get_log_file_name(): 63 | 64 | # Get Home directory 65 | home = expanduser("~") 66 | home += '/Fusion360DebugUtilities/' 67 | 68 | # Create if doesn't exist 69 | if not os.path.exists(home): 70 | os.makedirs(home) 71 | 72 | time_stamp = time.strftime("%Y-%m-%d-%H-%M-%S", time.gmtime()) 73 | 74 | # Create file name in this path 75 | log_file_name = home + 'FusionDebugUtilities-PerfLog-' + time_stamp + '.csv' 76 | return log_file_name 77 | 78 | -------------------------------------------------------------------------------- /Fusion360Utilities/Fusion360Utilities.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Patrick Rainsberry' 2 | 3 | import adsk.core 4 | import adsk.fusion 5 | import traceback 6 | 7 | 8 | # Externally usable function to get all relevant application objects easily in a dictionary 9 | def get_app_objects(): 10 | 11 | app = adsk.core.Application.cast(adsk.core.Application.get()) 12 | 13 | # Get import manager 14 | import_manager = app.importManager 15 | 16 | # Get User Interface 17 | ui = app.userInterface 18 | 19 | # Get active design 20 | product = app.activeProduct 21 | design = adsk.fusion.Design.cast(product) 22 | document = app.activeDocument 23 | 24 | # Get Design specific elements 25 | units_manager = design.fusionUnitsManager 26 | export_manager = design.exportManager 27 | root_comp = design.rootComponent 28 | time_line = product.timeline 29 | 30 | # Get top level collections 31 | all_occurrences = root_comp.allOccurrences 32 | all_components = design.allComponents 33 | 34 | app_objects = { 35 | 'app': app, 36 | 'design': design, 37 | 'import_manager': import_manager, 38 | 'ui': ui, 39 | 'units_manager': units_manager, 40 | 'all_occurrences': all_occurrences, 41 | 'all_components': all_components, 42 | 'root_comp': root_comp, 43 | 'time_line': time_line, 44 | 'export_manager': export_manager, 45 | 'document': document 46 | } 47 | return app_objects 48 | 49 | 50 | def start_group(): 51 | """ 52 | Starts a time line group 53 | :return: The index of the time line 54 | :rtype: int 55 | """ 56 | # Gets necessary application objects 57 | app_objects = get_app_objects() 58 | 59 | # Start time line group 60 | start_index = app_objects['time_line'].markerPosition 61 | 62 | return start_index 63 | 64 | 65 | def end_group(start_index): 66 | """ 67 | Ends a time line group 68 | :param start_index: Time line index 69 | :type start_index: int 70 | :return: 71 | :rtype: 72 | """ 73 | 74 | # Gets necessary application objects 75 | app_objects = get_app_objects() 76 | 77 | end_index = app_objects['time_line'].markerPosition - 1 78 | 79 | app_objects['time_line'].timelineGroups.add(start_index, end_index) 80 | 81 | 82 | def import_dxf(dxf_file, component, plane) -> adsk.core.ObjectCollection: 83 | """ 84 | Import dxf file with one sketch per layer. 85 | :param dxf_file: The full path to the dxf file 86 | :type dxf_file: str 87 | :param component: The target component for the new sketch(es) 88 | :type component: adsk.fusion.Component 89 | :param plane: The plane on which to import the DXF file. 90 | :type plane: adsk.fusion.ConstructionPlane or adsk.fusion.BRepFace 91 | :return: A Collection of the created sketches 92 | :rtype: adsk.core.ObjectCollection 93 | """ 94 | import_manager = get_app_objects()['import_manager'] 95 | dxf_options = import_manager.createDXF2DImportOptions(dxf_file, plane) 96 | import_manager.importToTarget(dxf_options, component) 97 | sketches = dxf_options.results 98 | return sketches 99 | 100 | 101 | def sketch_by_name(sketches, name): 102 | """ 103 | Finds a sketch by name in a list of sketches 104 | Useful for parsing a collection of sketches such as DXF import results. 105 | :param sketches: A list of sketches. 106 | :type sketches: adsk.fusion.Sketches 107 | :param name: The name of the sketch to find. 108 | :return: The sketch matching the name if it is found. 109 | :rtype: adsk.fusion.Sketch 110 | """ 111 | return_sketch = None 112 | for sketch in sketches: 113 | if sketch.name == name: 114 | return_sketch = sketch 115 | return return_sketch 116 | 117 | 118 | def extrude_all_profiles(sketch, distance, component, operation) -> adsk.fusion.ExtrudeFeature: 119 | """ 120 | Create extrude features of all profiles in a sketch 121 | The new feature will be created in the given target component and extruded by a distance 122 | :param sketch: The sketch from which to get profiles 123 | :type sketch: adsk.fusion.Sketch 124 | :param distance: The distance to extrude the profiles. 125 | :type distance: float 126 | :param component: The target component for the extrude feature 127 | :type component: adsk.fusion.Component 128 | :param operation: The feature operation type from enumerator. 129 | :type operation: adsk.fusion.FeatureOperations 130 | :return: THe new extrude feature. 131 | :rtype: adsk.fusion.ExtrudeFeature 132 | """ 133 | profile_collection = adsk.core.ObjectCollection.create() 134 | for profile in sketch.profiles: 135 | profile_collection.add(profile) 136 | 137 | extrudes = component.features.extrudeFeatures 138 | ext_input = extrudes.createInput(profile_collection, operation) 139 | distance_input = adsk.core.ValueInput.createByReal(distance) 140 | ext_input.setDistanceExtent(False, distance_input) 141 | extrude_feature = extrudes.add(ext_input) 142 | return extrude_feature 143 | 144 | 145 | def create_component(target_component, name) -> adsk.fusion.Occurrence: 146 | """ 147 | Creates a new empty component in the target component 148 | :param target_component: The target component for the new component 149 | :type target_component: 150 | :param name: The name of the new component 151 | :type name: str 152 | :return: The reference to the occurrence of the newly created component. 153 | :rtype: adsk.fusion.Occurrence 154 | """ 155 | transform = adsk.core.Matrix3D.create() 156 | new_occurrence = target_component.occurrences.addNewComponent(transform) 157 | new_occurrence.component.name = name 158 | return new_occurrence 159 | 160 | 161 | # Creates rectangle pattern of bodies based on vectors 162 | def rect_body_pattern(target_component, bodies, x_axis, y_axis, x_qty, x_distance, y_qty, y_distance): 163 | move_feats = target_component.features.moveFeatures 164 | 165 | x_bodies = adsk.core.ObjectCollection.create() 166 | all_bodies = adsk.core.ObjectCollection.create() 167 | 168 | for body in bodies: 169 | x_bodies.add(body) 170 | all_bodies.add(body) 171 | 172 | for i in range(1, x_qty): 173 | 174 | # Create a collection of entities for move 175 | x_source = adsk.core.ObjectCollection.create() 176 | 177 | for body in bodies: 178 | new_body = body.copyToComponent(target_component) 179 | x_source.add(new_body) 180 | x_bodies.add(new_body) 181 | all_bodies.add(new_body) 182 | 183 | x_transform = adsk.core.Matrix3D.create() 184 | x_axis.normalize() 185 | x_axis.scaleBy(x_distance * i) 186 | x_transform.translation = x_axis 187 | 188 | move_input_x = move_feats.createInput(x_source, x_transform) 189 | move_feats.add(move_input_x) 190 | 191 | for j in range(1, y_qty): 192 | # Create a collection of entities for move 193 | y_source = adsk.core.ObjectCollection.create() 194 | 195 | for body in x_bodies: 196 | new_body = body.copyToComponent(target_component) 197 | y_source.add(new_body) 198 | all_bodies.add(new_body) 199 | 200 | y_transform = adsk.core.Matrix3D.create() 201 | y_axis.normalize() 202 | y_axis.scaleBy(y_distance * j) 203 | y_transform.translation = y_axis 204 | 205 | move_input_y = move_feats.createInput(y_source, y_transform) 206 | move_feats.add(move_input_y) 207 | 208 | return all_bodies 209 | 210 | 211 | # Creates Combine Feature in target with all tool bodies as source 212 | # Specify operation as: adsk.fusion.FeatureOperations 213 | # target_body -> single body 214 | # tool_bodies -> list of bodies 215 | def combine_feature(target_body, tool_bodies, operation): 216 | 217 | # Get Combine Features 218 | combine_features = target_body.parentComponent.features.combineFeatures 219 | 220 | # Define a collection and add all tool bodies to it 221 | combine_tools = adsk.core.ObjectCollection.create() 222 | for tool in tool_bodies: 223 | # todo add error checking 224 | combine_tools.add(tool) 225 | 226 | # Create Combine Feature 227 | combine_input = combine_features.createInput(target_body, combine_tools) 228 | combine_input.operation = operation 229 | combine_features.add(combine_input) -------------------------------------------------------------------------------- /Fusion360Utilities/Fusion360CommandBase.py: -------------------------------------------------------------------------------- 1 | import traceback 2 | 3 | import adsk.core 4 | import adsk.fusion 5 | 6 | handlers = [] 7 | 8 | 9 | # Returns a dictionary for all inputs. Very useful for creating quick Fusion 360 Add-ins 10 | def get_inputs(command_inputs): 11 | value_types = [adsk.core.BoolValueCommandInput.classType(), adsk.core.DistanceValueCommandInput.classType(), 12 | adsk.core.FloatSliderCommandInput.classType(), adsk.core.FloatSpinnerCommandInput.classType(), 13 | adsk.core.IntegerSliderCommandInput.classType(), adsk.core.IntegerSpinnerCommandInput.classType(), 14 | adsk.core.ValueCommandInput.classType(), adsk.core.SliderCommandInput.classType(), 15 | adsk.core.StringValueCommandInput.classType()] 16 | 17 | list_types = [adsk.core.ButtonRowCommandInput.classType(), adsk.core.DropDownCommandInput.classType(), 18 | adsk.core.RadioButtonGroupCommandInput.classType()] 19 | 20 | selection_types = [adsk.core.SelectionCommandInput.classType()] 21 | 22 | input_values = {} 23 | input_values.clear() 24 | 25 | for command_input in command_inputs: 26 | 27 | # If the input type is in this list the value of the input is returned 28 | if command_input.objectType in value_types: 29 | input_values[command_input.id] = command_input.value 30 | input_values[command_input.id + '_input'] = command_input 31 | 32 | # If the input type is in this list the name of the selected list item is returned 33 | elif command_input.objectType in list_types: 34 | input_values[command_input.id] = command_input.selectedItem.name 35 | input_values[command_input.id + '_input'] = command_input 36 | 37 | # If the input type is a selection an array of entities is returned 38 | elif command_input.objectType in selection_types: 39 | if command_input.selectionCount > 0: 40 | selections = [] 41 | for i in range(0, command_input.selectionCount): 42 | selections.append(command_input.selection(i).entity) 43 | 44 | input_values[command_input.id] = selections 45 | input_values[command_input.id + '_input'] = command_input 46 | 47 | else: 48 | input_values[command_input.id] = command_input.name 49 | input_values[command_input.id + '_input'] = command_input 50 | 51 | return input_values 52 | 53 | 54 | # Finds command definition in active UI 55 | def command_definition_by_id(cmd_id, ui): 56 | 57 | command_definitions = ui.commandDefinitions 58 | command_definition = command_definitions.itemById(cmd_id) 59 | return command_definition 60 | 61 | 62 | # Find command control by id in nav bar 63 | def cmd_control_in_nav_bar(cmd_id, ui): 64 | 65 | toolbars_ = ui.toolbars 66 | nav_toolbar = toolbars_.itemById('NavToolbar') 67 | nav_toolbar_controls = nav_toolbar.controls 68 | cmd_control = nav_toolbar_controls.itemById(cmd_id) 69 | 70 | if cmd_control is not None: 71 | return cmd_control 72 | 73 | 74 | # Destroys a given object 75 | def destroy_object(obj_to_be_deleted): 76 | app = adsk.core.Application.cast(adsk.core.Application.get()) 77 | ui = app.userInterface 78 | 79 | if ui and obj_to_be_deleted: 80 | if obj_to_be_deleted.isValid: 81 | obj_to_be_deleted.deleteMe() 82 | else: 83 | ui.messageBox(obj_to_be_deleted.id + 'is not a valid object') 84 | 85 | 86 | # Returns the id of a Toolbar Panel in the given Workspace 87 | def toolbar_panel_by_id_in_workspace(workspace_id, toolbar_panel_id): 88 | app = adsk.core.Application.cast(adsk.core.Application.get()) 89 | ui = app.userInterface 90 | 91 | all_workspaces = ui.workspaces 92 | this_workspace = all_workspaces.itemById(workspace_id) 93 | 94 | if this_workspace is None: 95 | ui.messageBox(toolbar_panel_id + 'is not a valid workspace') 96 | raise ValueError 97 | 98 | all_toolbar_panels = this_workspace.toolbarPanels 99 | toolbar_panel = all_toolbar_panels.itemById(toolbar_panel_id) 100 | 101 | if toolbar_panel is not None: 102 | return toolbar_panel 103 | else: 104 | ui.messageBox(toolbar_panel_id + 'is not a valid tool bar') 105 | raise ValueError 106 | 107 | 108 | # Returns the Command Control from the given panel 109 | def command_control_by_id_in_panel(cmd_id, toolbar_panel, ui): 110 | if not cmd_id: 111 | ui.messageBox('Command Control: ' + cmd_id + ' is not specified') 112 | return None 113 | 114 | cmd_control = toolbar_panel.controls.itemById(cmd_id) 115 | 116 | if cmd_control is not None: 117 | return cmd_control 118 | 119 | else: 120 | raise ValueError 121 | 122 | 123 | # Get Controls in workspace panel or nav bar 124 | def get_controls(command_in_nav_bar, workspace, toolbar_panel_id, ui): 125 | 126 | # Add command in nav bar 127 | if command_in_nav_bar: 128 | 129 | toolbars_ = ui.toolbars 130 | nav_bar = toolbars_.itemById('NavToolbar') 131 | controls = nav_bar.controls 132 | 133 | # Get Controls from a workspace panel 134 | else: 135 | toolbar_panel = toolbar_panel_by_id_in_workspace(workspace, toolbar_panel_id) 136 | controls = toolbar_panel.controls 137 | 138 | if controls is not None: 139 | return controls 140 | else: 141 | raise RuntimeError 142 | 143 | 144 | # Base Class for creating Fusion 360 Commands 145 | class Fusion360CommandBase: 146 | def __init__(self, cmd_def, debug): 147 | 148 | self.cmd_name = cmd_def.get('cmd_name', 'Default Command Name') 149 | self.cmd_description = cmd_def.get('cmd_description', 'Default Command Description') 150 | self.cmd_resources = cmd_def.get('cmd_resources', './resources') 151 | self.cmd_id = cmd_def.get('cmd_id', 'Default Command ID') 152 | 153 | self.workspace = cmd_def.get('workspace', 'FusionSolidEnvironment') 154 | self.toolbar_panel_id = cmd_def.get('toolbar_panel_id', 'SolidScriptsAddinsPanel') 155 | 156 | self.add_to_drop_down = cmd_def.get('add_to_drop_down', False) 157 | self.drop_down_cmd_id = cmd_def.get('drop_down_cmd_id', 'Default_DC_CmdId') 158 | self.drop_down_resources = cmd_def.get('drop_down_resources', './resources') 159 | self.drop_down_name = cmd_def.get('drop_down_name', './resources') 160 | 161 | self.command_in_nav_bar = cmd_def.get('command_in_nav_bar', False) 162 | 163 | self.debug = debug 164 | 165 | # global set of event handlers to keep them referenced for the duration of the command 166 | self.handlers = [] 167 | 168 | def on_preview(self, command, inputs, args, input_values): 169 | pass 170 | 171 | def on_destroy(self, command, inputs, reason, input_values): 172 | pass 173 | 174 | def on_input_changed(self, command_, command_inputs, changed_input, input_values): 175 | pass 176 | 177 | def on_execute(self, command, inputs, args, input_values): 178 | pass 179 | 180 | def on_create(self, command, inputs): 181 | pass 182 | 183 | def on_run(self): 184 | global handlers 185 | 186 | app = adsk.core.Application.cast(adsk.core.Application.get()) 187 | ui = app.userInterface 188 | 189 | try: 190 | 191 | cmd_definitions = ui.commandDefinitions 192 | 193 | controls_to_add_to = get_controls(self.command_in_nav_bar, self.workspace, self.toolbar_panel_id, ui) 194 | 195 | # Add to a drop down 196 | if self.add_to_drop_down: 197 | 198 | drop_control = controls_to_add_to.itemById(self.drop_down_cmd_id) 199 | 200 | if not drop_control: 201 | drop_control = controls_to_add_to.addDropDown(self.drop_down_name, self.drop_down_resources, 202 | self.drop_down_cmd_id) 203 | 204 | controls_to_add_to = drop_control.controls 205 | 206 | new_control = controls_to_add_to.itemById(self.cmd_id) 207 | 208 | # If control does not exist, create it 209 | if not new_control: 210 | cmd_definition = cmd_definitions.itemById(self.cmd_id) 211 | if not cmd_definition: 212 | cmd_definition = cmd_definitions.addButtonDefinition(self.cmd_id, 213 | self.cmd_name, 214 | self.cmd_description, 215 | self.cmd_resources) 216 | 217 | on_command_created_handler = CommandCreatedEventHandler(self) 218 | cmd_definition.commandCreated.add(on_command_created_handler) 219 | handlers.append(on_command_created_handler) 220 | 221 | new_control = controls_to_add_to.addCommand(cmd_definition) 222 | new_control.isVisible = True 223 | 224 | except: 225 | if ui: 226 | ui.messageBox('AddIn Start Failed: {}'.format(traceback.format_exc())) 227 | 228 | def on_stop(self): 229 | app = adsk.core.Application.cast(adsk.core.Application.get()) 230 | ui = app.userInterface 231 | 232 | try: 233 | 234 | controls_to_delete_from = get_controls(self.command_in_nav_bar, self.workspace, self.toolbar_panel_id, ui) 235 | 236 | # If it is in a drop down 237 | if self.add_to_drop_down: 238 | drop_down_control = controls_to_delete_from.itemById(self.drop_down_cmd_id) 239 | controls_to_delete_from = drop_down_control.controls 240 | 241 | cmd_control = controls_to_delete_from.itemById(self.cmd_id) 242 | cmd_definition = command_definition_by_id(self.cmd_id, ui) 243 | 244 | destroy_object(cmd_control) 245 | destroy_object(cmd_definition) 246 | 247 | if self.add_to_drop_down: 248 | if drop_down_control.controls.count == 0: 249 | drop_down_definition = command_definition_by_id(self.drop_down_cmd_id, ui) 250 | 251 | destroy_object(drop_down_control) 252 | destroy_object(drop_down_definition) 253 | 254 | except: 255 | if ui: 256 | ui.messageBox('AddIn Stop Failed: {}'.format(traceback.format_exc())) 257 | 258 | 259 | class ExecutePreviewHandler(adsk.core.CommandEventHandler): 260 | def __init__(self, cmd_object): 261 | super().__init__() 262 | self.cmd_object_ = cmd_object 263 | self.args = None 264 | 265 | def notify(self, args): 266 | app = adsk.core.Application.cast(adsk.core.Application.get()) 267 | ui = app.userInterface 268 | 269 | try: 270 | 271 | command_ = args.firingEvent.sender 272 | command_inputs = command_.commandInputs 273 | if self.cmd_object_.debug: 274 | ui.messageBox('***Debug *** Preview: {} execute preview event triggered'. 275 | format(command_.parentCommandDefinition.id)) 276 | input_values = get_inputs(command_inputs) 277 | self.cmd_object_.on_preview(command_, command_inputs, args, input_values) 278 | 279 | except: 280 | if ui: 281 | ui.messageBox('Input changed event failed: {}'.format(traceback.format_exc())) 282 | 283 | 284 | class DestroyHandler(adsk.core.CommandEventHandler): 285 | def __init__(self, cmd_object): 286 | super().__init__() 287 | self.cmd_object_ = cmd_object 288 | 289 | def notify(self, args): 290 | app = adsk.core.Application.cast(adsk.core.Application.get()) 291 | ui = app.userInterface 292 | 293 | try: 294 | command_ = args.firingEvent.sender 295 | command_inputs = command_.commandInputs 296 | reason_ = args.terminationReason 297 | 298 | if self.cmd_object_.debug: 299 | ui.messageBox('***Debug ***Command: {} destroyed'.format(command_.parentCommandDefinition.id)) 300 | ui.messageBox("***Debug ***Reason for termination= " + str(reason_)) 301 | 302 | input_values = get_inputs(command_inputs) 303 | 304 | self.cmd_object_.on_destroy(command_, command_inputs, reason_, input_values) 305 | 306 | except: 307 | if ui: 308 | ui.messageBox('Input changed event failed: {}'.format(traceback.format_exc())) 309 | 310 | 311 | class InputChangedHandler(adsk.core.InputChangedEventHandler): 312 | def __init__(self, cmd_object): 313 | super().__init__() 314 | self.cmd_object_ = cmd_object 315 | 316 | def notify(self, args): 317 | app = adsk.core.Application.cast(adsk.core.Application.get()) 318 | ui = app.userInterface 319 | 320 | try: 321 | command_ = args.firingEvent.sender 322 | command_inputs = command_.commandInputs 323 | changed_input = args.input 324 | 325 | if self.cmd_object_.debug: 326 | ui.messageBox('***Debug Input: {} changed event triggered'.format(command_.parentCommandDefinition.id)) 327 | ui.messageBox('***Debug The Input: {} was the command'.format(changed_input.id)) 328 | 329 | input_values = get_inputs(command_inputs) 330 | 331 | self.cmd_object_.on_input_changed(command_, command_inputs, changed_input, input_values) 332 | 333 | except: 334 | if ui: 335 | ui.messageBox('Input changed event failed: {}'.format(traceback.format_exc())) 336 | 337 | 338 | class CommandExecuteHandler(adsk.core.CommandEventHandler): 339 | def __init__(self, cmd_object): 340 | super().__init__() 341 | self.cmd_object_ = cmd_object 342 | 343 | def notify(self, args): 344 | try: 345 | app = adsk.core.Application.cast(adsk.core.Application.get()) 346 | ui = app.userInterface 347 | command_ = args.firingEvent.sender 348 | command_inputs = command_.commandInputs 349 | 350 | if self.cmd_object_.debug: 351 | ui.messageBox('***Debug command: {} executed successfully'.format(command_.parentCommandDefinition.id)) 352 | 353 | input_values = get_inputs(command_inputs) 354 | 355 | self.cmd_object_.on_execute(command_, command_inputs, args, input_values) 356 | 357 | except: 358 | if ui: 359 | ui.messageBox('command executed failed: {}'.format(traceback.format_exc())) 360 | 361 | 362 | class CommandCreatedEventHandler(adsk.core.CommandCreatedEventHandler): 363 | def __init__(self, cmd_object): 364 | super().__init__() 365 | self.cmd_object_ = cmd_object 366 | 367 | def notify(self, args): 368 | app = adsk.core.Application.cast(adsk.core.Application.get()) 369 | ui = app.userInterface 370 | 371 | try: 372 | global handlers 373 | 374 | command_ = args.command 375 | inputs_ = command_.commandInputs 376 | 377 | on_execute_handler = CommandExecuteHandler(self.cmd_object_) 378 | command_.execute.add(on_execute_handler) 379 | handlers.append(on_execute_handler) 380 | 381 | on_input_changed_handler = InputChangedHandler(self.cmd_object_) 382 | command_.inputChanged.add(on_input_changed_handler) 383 | handlers.append(on_input_changed_handler) 384 | 385 | on_destroy_handler = DestroyHandler(self.cmd_object_) 386 | command_.destroy.add(on_destroy_handler) 387 | handlers.append(on_destroy_handler) 388 | 389 | on_execute_preview_handler = ExecutePreviewHandler(self.cmd_object_) 390 | command_.executePreview.add(on_execute_preview_handler) 391 | handlers.append(on_execute_preview_handler) 392 | 393 | if self.cmd_object_.debug: 394 | ui.messageBox('***Debug ***Panel command created successfully') 395 | 396 | self.cmd_object_.on_create(command_, inputs_) 397 | 398 | except: 399 | if ui: 400 | ui.messageBox('Command created failed: {}'.format(traceback.format_exc())) --------------------------------------------------------------------------------