diff --git a/.gitignore b/.gitignore
index e43b0f9..c120690 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
.DS_Store
+.vscode/*
\ No newline at end of file
diff --git a/f360-script/External controls/.env b/f360-script/External controls/.env
new file mode 100644
index 0000000..e28bd05
--- /dev/null
+++ b/f360-script/External controls/.env
@@ -0,0 +1 @@
+PYTHONPATH=C:/Users/gena0/AppData/Local/Autodesk/webdeploy/production/525fe9b2ece26c4d179982b11ecdfb713cb5058f/Api/Python/packages
diff --git a/f360-script/External controls/.vscode/launch.json b/f360-script/External controls/.vscode/launch.json
new file mode 100644
index 0000000..1c69300
--- /dev/null
+++ b/f360-script/External controls/.vscode/launch.json
@@ -0,0 +1,20 @@
+{
+ "version": "0.2.0",
+ "configurations": [{
+ "name": "Python: Attach",
+ "type": "python",
+ "request": "attach",
+ "pathMappings": [{
+ "localRoot": "${workspaceRoot}",
+ "remoteRoot": "${workspaceRoot}"
+ }],
+ "osx": {
+ "filePath": "${file}"
+ },
+ "windows": {
+ "filePath": "${file}"
+ },
+ "port": 9000,
+ "host": "localhost"
+ }]
+}
\ No newline at end of file
diff --git a/f360-script/External controls/.vscode/settings.json b/f360-script/External controls/.vscode/settings.json
new file mode 100644
index 0000000..bb38fc9
--- /dev/null
+++ b/f360-script/External controls/.vscode/settings.json
@@ -0,0 +1,12 @@
+{
+ "python.autoComplete.extraPaths": [
+ "C:\\Users\\gena0\\AppData\\Roaming\\Autodesk\\Autodesk Fusion 360\\API\\Python\\defs"
+ ],
+ "python.analysis.extraPaths": ["C:/Users/gena0/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Python/defs"],
+ "python.pythonPath": "C:/Users/gena0/AppData/Local/Autodesk/webdeploy/production/525fe9b2ece26c4d179982b11ecdfb713cb5058f/Python/python.exe",
+ "fusion-360-helper.enabled": true,
+ "fusion-360-helper.python.pythonPath": "C:\\Users\\gena0\\AppData\\Local\\Autodesk\\webdeploy\\production\\eb2a69395707b2ba8a2af9d915b9a52ace64d385\\Python\\python.exe",
+ "fusion-360-helper.python.extraLibs": [
+ "C:\\Users\\gena0\\AppData\\Roaming\\Autodesk\\Autodesk Fusion 360\\API\\Python\\defs"
+ ]
+}
\ No newline at end of file
diff --git a/f360-script/External controls/External controls.manifest b/f360-script/External controls/External controls.manifest
new file mode 100644
index 0000000..377ab05
--- /dev/null
+++ b/f360-script/External controls/External controls.manifest
@@ -0,0 +1,13 @@
+{
+ "autodeskProduct": "Fusion360",
+ "type": "addin",
+ "id": "0afdf698-8eed-4eaa-ac5c-d6ae17db8147",
+ "author": "InTostor",
+ "description": {
+ "": ""
+ },
+ "version": "0.1",
+ "runOnStartup": true,
+ "supportedOS": "windows|mac",
+ "editEnabled": true
+}
\ No newline at end of file
diff --git a/f360-script/External controls/External controls.py b/f360-script/External controls/External controls.py
new file mode 100644
index 0000000..3a8e22c
--- /dev/null
+++ b/f360-script/External controls/External controls.py
@@ -0,0 +1,161 @@
+# started experiments with f360 driver-script
+
+
+# There is a lot of code copied from stackoverflow, autodesk forums, etc.
+# windows only yet
+
+import adsk.fusion, adsk.core, traceback
+import math
+
+from .lib import joystickapi
+from .lib.mathExt import *
+from .lib.Joystick import *
+from .lib.logger import *
+
+from .lib import fusion360utils as futil
+from .config import *
+from . import commands
+
+
+import msvcrt
+import time
+import inspect, os, sys
+
+logger=Logger()
+
+
+def greeting():
+ logger.print("------Starting------")
+ logger.print("f360 joystick driver")
+ logger.print(f"version, {VERSION}. By {AUTHOR}.")
+
+
+
+def transformCameraByMatrix(camera: adsk.core.Camera, matrix: adsk.core.Matrix3D):
+ eye: adsk.core.Point3D = camera.eye
+ eye.transformBy(matrix)
+ camera.eye = eye
+
+def transformCameraByVector(camera: adsk.core.Camera, vector: adsk.core.Vector3D):
+ eye: adsk.core.Point3D = camera.eye
+ eye.translateBy(vector)
+ camera.eye = eye
+
+
+
+def changeCameraZoom(camera: adsk.core.Camera,zoom):
+ zoomOld = camera.viewExtents
+ if zoom<0:
+ zoom=0.001
+ camera.viewExtents = zoom
+
+numOfJoysticks = joystickapi.joyGetNumDevs()
+
+
+joy = None
+
+def run(context):
+
+ try:
+ # This will run the start function in each of your commands as defined in commands/__init__.py
+ commands.start()
+
+ except:
+ futil.handle_error('run')
+
+# This section executes once on script start
+ ui = None
+ app: adsk.core.Application = adsk.core.Application.get()
+ ui = app.userInterface
+ greeting()
+
+ if numOfJoysticks==0:
+ raise Exception("No joystick")
+ else:
+ joy = Joystick()
+
+ # this found there https://github.com/Rabbid76/python_windows_joystickapi
+
+
+ ret, caps, startinfo = False, None, None
+ for id in range(numOfJoysticks):
+ ret, caps = joystickapi.joyGetDevCaps(id)
+ if ret:
+ ui.messageBox(str("Using gamepad: " + caps.szPname))
+ ret, startinfo = joystickapi.joyGetPosEx(id)
+ break
+ else:
+ ui.messageBox(str("no gamepad detected"))
+
+ first=True
+# This section executes once on script start
+
+
+# Loop starts
+
+ while True:
+ # viewport
+ vp: adsk.core.Viewport = app.activeViewport
+ cam: adsk.core.Camera = vp.camera
+ vecUp: adsk.core.Vector3D = cam.upVector
+ target: adsk.core.Point3D = cam.target
+ eye: adsk.core.Point3D = cam.eye
+
+
+
+ eTvector=eye.vectorTo(target)
+ angle1 = eTvector.angleTo(vecUp)
+ dx,dy,dz = getPerpendicularVector(vecUp.x, vecUp.y, vecUp.z)
+ perpendicular = adsk.core.Point3D.create(dx,dy,dz)
+ perpendicular=perpendicular.asVector()
+
+ angle2=vecUp.angleTo(perpendicular)
+
+
+ if numOfJoysticks==0:
+ raise Exception("No joystick")
+
+
+ deg = (joy.getAxes()[6]/262144)
+ deg=deg*deg*deg
+
+ zoom = cam.viewExtents
+ if cam.cameraType==0:
+ zoom = zoom-joy.getAxes()[1]/2621*zoom/5000
+ else:
+ zoom = zoom-joy.getAxes()[1]/26214400
+
+
+ changeCameraZoom(cam,zoom)
+
+ # futil.log( str(str(joy.getAxes()) +"|"+ str(cam.viewExtents))) # all axes output
+ logger.print(
+ "vecUp - target angle: "+str(math.degrees(angle1))+ "\n"+
+ "vecUp - calcul angle: "+str(math.degrees(angle2))+ "\n"+
+ str(perpendicular.x)+"|"+str(perpendicular.y)+"|"+str(perpendicular.z)
+ )
+
+
+ # matrix3d
+ mat: adsk.core.Matrix3D = adsk.core.Matrix3D.create()
+
+ mat.setToRotation(math.radians(deg), vecUp, target)
+ # update camera
+ cam.isSmoothTransition = False
+
+ transformCameraByMatrix(cam,mat)
+
+ transformCameraByVector(cam,perpendicular)
+
+
+
+
+
+
+
+ #futil.log(str(axisXYZRUV[0])+"|||||"+str(cam.viewExtents))
+ # cam.viewExtents = zoom
+ vp.camera = cam
+ vp.refresh()
+
+ adsk.doEvents()
diff --git a/f360-script/External controls/__pycache__/config.cpython-39.pyc b/f360-script/External controls/__pycache__/config.cpython-39.pyc
new file mode 100644
index 0000000..a4c6765
Binary files /dev/null and b/f360-script/External controls/__pycache__/config.cpython-39.pyc differ
diff --git a/f360-script/External controls/commands/__init__.py b/f360-script/External controls/commands/__init__.py
new file mode 100644
index 0000000..0499301
--- /dev/null
+++ b/f360-script/External controls/commands/__init__.py
@@ -0,0 +1,30 @@
+# Here you define the commands that will be added to your add-in.
+
+# TODO Import the modules corresponding to the commands you created.
+# If you want to add an additional command, duplicate one of the existing directories and import it here.
+# You need to use aliases (import "entry" as "my_module") assuming you have the default module named "entry".
+from .commandDialog import entry as commandDialog
+from .paletteShow import entry as paletteShow
+from .paletteSend import entry as paletteSend
+
+# TODO add your imported modules to this list.
+# Fusion will automatically call the start() and stop() functions.
+commands = [
+ commandDialog,
+ paletteShow,
+ paletteSend
+]
+
+
+# Assumes you defined a "start" function in each of your modules.
+# The start function will be run when the add-in is started.
+def start():
+ for command in commands:
+ command.start()
+
+
+# Assumes you defined a "stop" function in each of your modules.
+# The stop function will be run when the add-in is stopped.
+def stop():
+ for command in commands:
+ command.stop()
\ No newline at end of file
diff --git a/f360-script/External controls/commands/__pycache__/__init__.cpython-39.pyc b/f360-script/External controls/commands/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000..923bc4d
Binary files /dev/null and b/f360-script/External controls/commands/__pycache__/__init__.cpython-39.pyc differ
diff --git a/f360-script/External controls/commands/commandDialog/__init__.py b/f360-script/External controls/commands/commandDialog/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/f360-script/External controls/commands/commandDialog/__pycache__/__init__.cpython-39.pyc b/f360-script/External controls/commands/commandDialog/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000..c69504c
Binary files /dev/null and b/f360-script/External controls/commands/commandDialog/__pycache__/__init__.cpython-39.pyc differ
diff --git a/f360-script/External controls/commands/commandDialog/__pycache__/entry.cpython-39.pyc b/f360-script/External controls/commands/commandDialog/__pycache__/entry.cpython-39.pyc
new file mode 100644
index 0000000..cd81118
Binary files /dev/null and b/f360-script/External controls/commands/commandDialog/__pycache__/entry.cpython-39.pyc differ
diff --git a/f360-script/External controls/commands/commandDialog/entry.py b/f360-script/External controls/commands/commandDialog/entry.py
new file mode 100644
index 0000000..e00314c
--- /dev/null
+++ b/f360-script/External controls/commands/commandDialog/entry.py
@@ -0,0 +1,158 @@
+import adsk.core
+import os
+from ...lib import fusion360utils as futil
+from ... import config
+app = adsk.core.Application.get()
+ui = app.userInterface
+
+
+# TODO *** Specify the command identity information. ***
+CMD_ID = f'{config.COMPANY_NAME}_{config.ADDIN_NAME}_cmdDialog'
+CMD_NAME = 'Command Dialog Sample'
+CMD_Description = 'A Fusion 360 Add-in Command with a dialog'
+
+# Specify that the command will be promoted to the panel.
+IS_PROMOTED = True
+
+# TODO *** Define the location where the command button will be created. ***
+# This is done by specifying the workspace, the tab, and the panel, and the
+# command it will be inserted beside. Not providing the command to position it
+# will insert it at the end.
+WORKSPACE_ID = 'FusionSolidEnvironment'
+PANEL_ID = 'SolidScriptsAddinsPanel'
+COMMAND_BESIDE_ID = 'ScriptsManagerCommand'
+
+# Resource location for command icons, here we assume a sub folder in this directory named "resources".
+ICON_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'resources', '')
+
+# Local list of event handlers used to maintain a reference so
+# they are not released and garbage collected.
+local_handlers = []
+
+
+# Executed when add-in is run.
+def start():
+ # Create a command Definition.
+ cmd_def = ui.commandDefinitions.addButtonDefinition(CMD_ID, CMD_NAME, CMD_Description, ICON_FOLDER)
+
+ # Define an event handler for the command created event. It will be called when the button is clicked.
+ futil.add_handler(cmd_def.commandCreated, command_created)
+
+ # ******** Add a button into the UI so the user can run the command. ********
+ # Get the target workspace the button will be created in.
+ workspace = ui.workspaces.itemById(WORKSPACE_ID)
+
+ # Get the panel the button will be created in.
+ panel = workspace.toolbarPanels.itemById(PANEL_ID)
+
+ # Create the button command control in the UI after the specified existing command.
+ control = panel.controls.addCommand(cmd_def, COMMAND_BESIDE_ID, False)
+
+ # Specify if the command is promoted to the main toolbar.
+ control.isPromoted = IS_PROMOTED
+
+
+# Executed when add-in is stopped.
+def stop():
+ # Get the various UI elements for this command
+ workspace = ui.workspaces.itemById(WORKSPACE_ID)
+ panel = workspace.toolbarPanels.itemById(PANEL_ID)
+ command_control = panel.controls.itemById(CMD_ID)
+ command_definition = ui.commandDefinitions.itemById(CMD_ID)
+
+ # Delete the button command control
+ if command_control:
+ command_control.deleteMe()
+
+ # Delete the command definition
+ if command_definition:
+ command_definition.deleteMe()
+
+
+# Function that is called when a user clicks the corresponding button in the UI.
+# This defines the contents of the command dialog and connects to the command related events.
+def command_created(args: adsk.core.CommandCreatedEventArgs):
+ # General logging for debug.
+ futil.log(f'{CMD_NAME} Command Created Event')
+
+ # https://help.autodesk.com/view/fusion360/ENU/?contextId=CommandInputs
+ inputs = args.command.commandInputs
+
+ # TODO Define the dialog for your command by adding different inputs to the command.
+
+ # Create a simple text box input.
+ inputs.addTextBoxCommandInput('text_box', 'Some Text', 'Enter some text.', 1, False)
+
+ # Create a value input field and set the default using 1 unit of the default length unit.
+ defaultLengthUnits = app.activeProduct.unitsManager.defaultLengthUnits
+ default_value = adsk.core.ValueInput.createByString('1')
+ inputs.addValueInput('value_input', 'Some Value', defaultLengthUnits, default_value)
+
+ # TODO Connect to the events that are needed by this command.
+ futil.add_handler(args.command.execute, command_execute, local_handlers=local_handlers)
+ futil.add_handler(args.command.inputChanged, command_input_changed, local_handlers=local_handlers)
+ futil.add_handler(args.command.executePreview, command_preview, local_handlers=local_handlers)
+ futil.add_handler(args.command.validateInputs, command_validate_input, local_handlers=local_handlers)
+ futil.add_handler(args.command.destroy, command_destroy, local_handlers=local_handlers)
+
+
+# This event handler is called when the user clicks the OK button in the command dialog or
+# is immediately called after the created event not command inputs were created for the dialog.
+def command_execute(args: adsk.core.CommandEventArgs):
+ # General logging for debug.
+ futil.log(f'{CMD_NAME} Command Execute Event')
+
+ # TODO ******************************** Your code here ********************************
+
+ # Get a reference to your command's inputs.
+ inputs = args.command.commandInputs
+ text_box: adsk.core.TextBoxCommandInput = inputs.itemById('text_box')
+ value_input: adsk.core.ValueCommandInput = inputs.itemById('value_input')
+
+ # Do something interesting
+ text = text_box.text
+ expression = value_input.expression
+ msg = f'Your text: {text}
Your value: {expression}'
+ ui.messageBox(msg)
+
+
+# This event handler is called when the command needs to compute a new preview in the graphics window.
+def command_preview(args: adsk.core.CommandEventArgs):
+ # General logging for debug.
+ futil.log(f'{CMD_NAME} Command Preview Event')
+ inputs = args.command.commandInputs
+
+
+# This event handler is called when the user changes anything in the command dialog
+# allowing you to modify values of other inputs based on that change.
+def command_input_changed(args: adsk.core.InputChangedEventArgs):
+ changed_input = args.input
+ inputs = args.inputs
+
+ # General logging for debug.
+ futil.log(f'{CMD_NAME} Input Changed Event fired from a change to {changed_input.id}')
+
+
+# This event handler is called when the user interacts with any of the inputs in the dialog
+# which allows you to verify that all of the inputs are valid and enables the OK button.
+def command_validate_input(args: adsk.core.ValidateInputsEventArgs):
+ # General logging for debug.
+ futil.log(f'{CMD_NAME} Validate Input Event')
+
+ inputs = args.inputs
+
+ # Verify the validity of the input values. This controls if the OK button is enabled or not.
+ valueInput = inputs.itemById('value_input')
+ if valueInput.value >= 0:
+ inputs.areInputsValid = True
+ else:
+ inputs.areInputsValid = False
+
+
+# This event handler is called when the command terminates.
+def command_destroy(args: adsk.core.CommandEventArgs):
+ # General logging for debug.
+ futil.log(f'{CMD_NAME} Command Destroy Event')
+
+ global local_handlers
+ local_handlers = []
diff --git a/f360-script/External controls/commands/commandDialog/resources/16x16.png b/f360-script/External controls/commands/commandDialog/resources/16x16.png
new file mode 100644
index 0000000..03babdc
Binary files /dev/null and b/f360-script/External controls/commands/commandDialog/resources/16x16.png differ
diff --git a/f360-script/External controls/commands/commandDialog/resources/32x32.png b/f360-script/External controls/commands/commandDialog/resources/32x32.png
new file mode 100644
index 0000000..863b2e3
Binary files /dev/null and b/f360-script/External controls/commands/commandDialog/resources/32x32.png differ
diff --git a/f360-script/External controls/commands/commandDialog/resources/64x64.png b/f360-script/External controls/commands/commandDialog/resources/64x64.png
new file mode 100644
index 0000000..dd285fd
Binary files /dev/null and b/f360-script/External controls/commands/commandDialog/resources/64x64.png differ
diff --git a/f360-script/External controls/commands/paletteSend/__init__.py b/f360-script/External controls/commands/paletteSend/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/f360-script/External controls/commands/paletteSend/__pycache__/__init__.cpython-39.pyc b/f360-script/External controls/commands/paletteSend/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000..01a3254
Binary files /dev/null and b/f360-script/External controls/commands/paletteSend/__pycache__/__init__.cpython-39.pyc differ
diff --git a/f360-script/External controls/commands/paletteSend/__pycache__/entry.cpython-39.pyc b/f360-script/External controls/commands/paletteSend/__pycache__/entry.cpython-39.pyc
new file mode 100644
index 0000000..f5ab94a
Binary files /dev/null and b/f360-script/External controls/commands/paletteSend/__pycache__/entry.cpython-39.pyc differ
diff --git a/f360-script/External controls/commands/paletteSend/entry.py b/f360-script/External controls/commands/paletteSend/entry.py
new file mode 100644
index 0000000..0878e66
--- /dev/null
+++ b/f360-script/External controls/commands/paletteSend/entry.py
@@ -0,0 +1,149 @@
+import json
+import adsk.core
+import os
+from ...lib import fusion360utils as futil
+from ... import config
+
+app = adsk.core.Application.get()
+ui = app.userInterface
+
+# TODO ********************* Change these names *********************
+CMD_ID = f'{config.COMPANY_NAME}_{config.ADDIN_NAME}_palette_send'
+CMD_NAME = 'Send to Palette'
+CMD_Description = 'Send some information to the palette'
+IS_PROMOTED = False
+
+# Using "global" variables by referencing values from /config.py
+PALETTE_ID = config.sample_palette_id
+
+# TODO *** Define the location where the command button will be created. ***
+# This is done by specifying the workspace, the tab, and the panel, and the
+# command it will be inserted beside. Not providing the command to position it
+# will insert it at the end.
+WORKSPACE_ID = 'FusionSolidEnvironment'
+PANEL_ID = 'SolidScriptsAddinsPanel'
+COMMAND_BESIDE_ID = 'ScriptsManagerCommand'
+
+# Resource location for command icons, here we assume a sub folder in this directory named "resources".
+ICON_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'resources', '')
+
+# Local list of event handlers used to maintain a reference so
+# they are not released and garbage collected.
+local_handlers = []
+
+
+# Executed when add-in is run.
+def start():
+ # Create a command Definition.
+ cmd_def = ui.commandDefinitions.addButtonDefinition(CMD_ID, CMD_NAME, CMD_Description, ICON_FOLDER)
+
+ # Add command created handler. The function passed here will be executed when the command is executed.
+ futil.add_handler(cmd_def.commandCreated, command_created)
+
+ # ******** Add a button into the UI so the user can run the command. ********
+ # Get the target workspace the button will be created in.
+ workspace = ui.workspaces.itemById(WORKSPACE_ID)
+
+ # Get the panel the button will be created in.
+ panel = workspace.toolbarPanels.itemById(PANEL_ID)
+
+ # Create the button command control in the UI after the specified existing command.
+ control = panel.controls.addCommand(cmd_def, COMMAND_BESIDE_ID, False)
+
+ # Specify if the command is promoted to the main toolbar.
+ control.isPromoted = IS_PROMOTED
+
+
+# Executed when add-in is stopped.
+def stop():
+ # Get the various UI elements for this command
+ workspace = ui.workspaces.itemById(WORKSPACE_ID)
+ panel = workspace.toolbarPanels.itemById(PANEL_ID)
+ command_control = panel.controls.itemById(CMD_ID)
+ command_definition = ui.commandDefinitions.itemById(CMD_ID)
+
+ # Delete the button command control
+ if command_control:
+ command_control.deleteMe()
+
+ # Delete the command definition
+ if command_definition:
+ command_definition.deleteMe()
+
+
+# Event handler that is called when the user clicks the command button in the UI.
+# To have a dialog, you create the desired command inputs here. If you don't need
+# a dialog, don't create any inputs and the execute event will be immediately fired.
+# You also need to connect to any command related events here.
+def command_created(args: adsk.core.CommandCreatedEventArgs):
+ # General logging for debug.
+ futil.log(f'{CMD_NAME} Command Created Event')
+
+ # TODO Create the event handlers you will need for this instance of the command
+ futil.add_handler(args.command.execute, command_execute, local_handlers=local_handlers)
+ futil.add_handler(args.command.inputChanged, command_input_changed, local_handlers=local_handlers)
+ futil.add_handler(args.command.executePreview, command_preview, local_handlers=local_handlers)
+ futil.add_handler(args.command.destroy, command_destroy, local_handlers=local_handlers)
+
+ # Create the user interface for your command by adding different inputs to the CommandInputs object
+ # https://help.autodesk.com/view/fusion360/ENU/?contextId=CommandInputs
+ inputs = args.command.commandInputs
+
+ # TODO ******************************** Define your UI Here ********************************
+
+ # Simple text input box
+ inputs.addTextBoxCommandInput('text_input', 'Text Message', 'Enter some text', 1, False)
+
+ # To create a numerical input with units, we need to get the current units and create a "ValueInput"
+ # https://help.autodesk.com/view/fusion360/ENU/?contextId=ValueInput
+ users_current_units = app.activeProduct.unitsManager.defaultLengthUnits
+ default_value = adsk.core.ValueInput.createByString(f'1 {users_current_units}')
+ inputs.addValueInput('value_input', 'Value Message', users_current_units, default_value)
+
+
+# This function will be called when the user hits the OK button in the command dialog
+def command_execute(args: adsk.core.CommandEventArgs):
+ # General logging for debug
+ futil.log(f'{CMD_NAME} Command Execute Event')
+
+ inputs = args.command.commandInputs
+
+ # TODO ******************************** Your code here ********************************
+
+ # Get a reference to your command's inputs
+ text_input: adsk.core.TextBoxCommandInput = inputs.itemById('text_input')
+ value_input: adsk.core.ValueCommandInput = inputs.itemById('value_input')
+
+ # Construct a message
+ message_action = 'updateMessage'
+ message_data = {
+ 'myValue': f'{value_input.value} cm',
+ 'myExpression': value_input.expression,
+ 'myText': text_input.formattedText
+ }
+ # JSON strings are a useful way to translate between javascript objects and python dictionaries
+ message_json = json.dumps(message_data)
+
+ # Get a reference to the palette and send the message to the palette javascript
+ palette = ui.palettes.itemById(PALETTE_ID)
+ palette.sendInfoToHTML(message_action, message_json)
+
+
+# This function will be called when the command needs to compute a new preview in the graphics window
+def command_preview(args: adsk.core.CommandEventArgs):
+ inputs = args.command.commandInputs
+ futil.log(f'{CMD_NAME} Command Preview Event')
+
+
+# This function will be called when the user changes anything in the command dialog
+def command_input_changed(args: adsk.core.InputChangedEventArgs):
+ changed_input = args.input
+ inputs = args.inputs
+ futil.log(f'{CMD_NAME} Input Changed Event fired from a change to {changed_input.id}')
+
+
+# This event handler is called when the command terminates.
+def command_destroy(args: adsk.core.CommandEventArgs):
+ global local_handlers
+ local_handlers = []
+ futil.log(f'{CMD_NAME} Command Destroy Event')
diff --git a/f360-script/External controls/commands/paletteSend/resources/16x16.png b/f360-script/External controls/commands/paletteSend/resources/16x16.png
new file mode 100644
index 0000000..c18250a
Binary files /dev/null and b/f360-script/External controls/commands/paletteSend/resources/16x16.png differ
diff --git a/f360-script/External controls/commands/paletteSend/resources/32x32.png b/f360-script/External controls/commands/paletteSend/resources/32x32.png
new file mode 100644
index 0000000..f6b4c18
Binary files /dev/null and b/f360-script/External controls/commands/paletteSend/resources/32x32.png differ
diff --git a/f360-script/External controls/commands/paletteSend/resources/64x64.png b/f360-script/External controls/commands/paletteSend/resources/64x64.png
new file mode 100644
index 0000000..ed1ae27
Binary files /dev/null and b/f360-script/External controls/commands/paletteSend/resources/64x64.png differ
diff --git a/f360-script/External controls/commands/paletteShow/__init__.py b/f360-script/External controls/commands/paletteShow/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/f360-script/External controls/commands/paletteShow/__pycache__/__init__.cpython-39.pyc b/f360-script/External controls/commands/paletteShow/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000..1b93fad
Binary files /dev/null and b/f360-script/External controls/commands/paletteShow/__pycache__/__init__.cpython-39.pyc differ
diff --git a/f360-script/External controls/commands/paletteShow/__pycache__/entry.cpython-39.pyc b/f360-script/External controls/commands/paletteShow/__pycache__/entry.cpython-39.pyc
new file mode 100644
index 0000000..c6e754a
Binary files /dev/null and b/f360-script/External controls/commands/paletteShow/__pycache__/entry.cpython-39.pyc differ
diff --git a/f360-script/External controls/commands/paletteShow/entry.py b/f360-script/External controls/commands/paletteShow/entry.py
new file mode 100644
index 0000000..f48c1c4
--- /dev/null
+++ b/f360-script/External controls/commands/paletteShow/entry.py
@@ -0,0 +1,193 @@
+import json
+import adsk.core
+import os
+from ...lib import fusion360utils as futil
+from ... import config
+from datetime import datetime
+
+app = adsk.core.Application.get()
+ui = app.userInterface
+
+# TODO ********************* Change these names *********************
+CMD_ID = f'{config.COMPANY_NAME}_{config.ADDIN_NAME}_PalleteShow'
+CMD_NAME = 'Show My Palette'
+CMD_Description = 'A Fusion 360 Add-in Palette'
+PALETTE_NAME = 'My Palette Sample'
+IS_PROMOTED = False
+
+# Using "global" variables by referencing values from /config.py
+PALETTE_ID = config.sample_palette_id
+
+# Specify the full path to the local html. You can also use a web URL
+# such as 'https://www.autodesk.com/'
+PALETTE_URL = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'resources', 'html', 'index.html')
+
+# The path function builds a valid OS path. This fixes it to be a valid local URL.
+PALETTE_URL = PALETTE_URL.replace('\\', '/')
+
+# Set a default docking behavior for the palette
+PALETTE_DOCKING = adsk.core.PaletteDockingStates.PaletteDockStateRight
+
+# TODO *** Define the location where the command button will be created. ***
+# This is done by specifying the workspace, the tab, and the panel, and the
+# command it will be inserted beside. Not providing the command to position it
+# will insert it at the end.
+WORKSPACE_ID = 'FusionSolidEnvironment'
+PANEL_ID = 'SolidScriptsAddinsPanel'
+COMMAND_BESIDE_ID = 'ScriptsManagerCommand'
+
+# Resource location for command icons, here we assume a sub folder in this directory named "resources".
+ICON_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'resources', '')
+
+# Local list of event handlers used to maintain a reference so
+# they are not released and garbage collected.
+local_handlers = []
+
+
+# Executed when add-in is run.
+def start():
+ # Create a command Definition.
+ cmd_def = ui.commandDefinitions.addButtonDefinition(CMD_ID, CMD_NAME, CMD_Description, ICON_FOLDER)
+
+ # Add command created handler. The function passed here will be executed when the command is executed.
+ futil.add_handler(cmd_def.commandCreated, command_created)
+
+ # ******** Add a button into the UI so the user can run the command. ********
+ # Get the target workspace the button will be created in.
+ workspace = ui.workspaces.itemById(WORKSPACE_ID)
+
+ # Get the panel the button will be created in.
+ panel = workspace.toolbarPanels.itemById(PANEL_ID)
+
+ # Create the button command control in the UI after the specified existing command.
+ control = panel.controls.addCommand(cmd_def, COMMAND_BESIDE_ID, False)
+
+ # Specify if the command is promoted to the main toolbar.
+ control.isPromoted = IS_PROMOTED
+
+
+# Executed when add-in is stopped.
+def stop():
+ # Get the various UI elements for this command
+ workspace = ui.workspaces.itemById(WORKSPACE_ID)
+ panel = workspace.toolbarPanels.itemById(PANEL_ID)
+ command_control = panel.controls.itemById(CMD_ID)
+ command_definition = ui.commandDefinitions.itemById(CMD_ID)
+ palette = ui.palettes.itemById(PALETTE_ID)
+
+ # Delete the button command control
+ if command_control:
+ command_control.deleteMe()
+
+ # Delete the command definition
+ if command_definition:
+ command_definition.deleteMe()
+
+ # Delete the Palette
+ if palette:
+ palette.deleteMe()
+
+
+# Event handler that is called when the user clicks the command button in the UI.
+# To have a dialog, you create the desired command inputs here. If you don't need
+# a dialog, don't create any inputs and the execute event will be immediately fired.
+# You also need to connect to any command related events here.
+def command_created(args: adsk.core.CommandCreatedEventArgs):
+ # General logging for debug.
+ futil.log(f'{CMD_NAME}: Command created event.')
+
+ # Create the event handlers you will need for this instance of the command
+ futil.add_handler(args.command.execute, command_execute, local_handlers=local_handlers)
+ futil.add_handler(args.command.destroy, command_destroy, local_handlers=local_handlers)
+
+
+# Because no command inputs are being added in the command created event, the execute
+# event is immediately fired.
+def command_execute(args: adsk.core.CommandEventArgs):
+ # General logging for debug.
+ futil.log(f'{CMD_NAME}: Command execute event.')
+
+ palettes = ui.palettes
+ palette = palettes.itemById(PALETTE_ID)
+ if palette is None:
+ palette = palettes.add(
+ id=PALETTE_ID,
+ name=PALETTE_NAME,
+ htmlFileURL=PALETTE_URL,
+ isVisible=True,
+ showCloseButton=True,
+ isResizable=True,
+ width=650,
+ height=600,
+ useNewWebBrowser=True
+ )
+ futil.add_handler(palette.closed, palette_closed)
+ futil.add_handler(palette.navigatingURL, palette_navigating)
+ futil.add_handler(palette.incomingFromHTML, palette_incoming)
+ futil.log(f'{CMD_NAME}: Created a new palette: ID = {palette.id}, Name = {palette.name}')
+
+ if palette.dockingState == adsk.core.PaletteDockingStates.PaletteDockStateFloating:
+ palette.dockingState = PALETTE_DOCKING
+
+ palette.isVisible = True
+
+
+# Use this to handle a user closing your palette.
+def palette_closed(args: adsk.core.UserInterfaceGeneralEventArgs):
+ # General logging for debug.
+ futil.log(f'{CMD_NAME}: Palette was closed.')
+
+
+# Use this to handle a user navigating to a new page in your palette.
+def palette_navigating(args: adsk.core.NavigationEventArgs):
+ # General logging for debug.
+ futil.log(f'{CMD_NAME}: Palette navigating event.')
+
+ # Get the URL the user is navigating to:
+ url = args.navigationURL
+
+ log_msg = f"User is attempting to navigate to {url}\n"
+ futil.log(log_msg, adsk.core.LogLevels.InfoLogLevel)
+
+ # Check if url is an external site and open in user's default browser.
+ if url.startswith("http"):
+ args.launchExternally = True
+
+
+# Use this to handle events sent from javascript in your palette.
+def palette_incoming(html_args: adsk.core.HTMLEventArgs):
+ # General logging for debug.
+ futil.log(f'{CMD_NAME}: Palette incoming event.')
+
+ message_data: dict = json.loads(html_args.data)
+ message_action = html_args.action
+
+ log_msg = f"Event received from {html_args.firingEvent.sender.name}\n"
+ log_msg += f"Action: {message_action}\n"
+ log_msg += f"Data: {message_data}"
+ futil.log(log_msg, adsk.core.LogLevels.InfoLogLevel)
+
+ # TODO ******** Your palette reaction code here ********
+
+ # Read message sent from palette javascript and react appropriately.
+ if message_action == 'messageFromPalette':
+ arg1 = message_data.get('arg1', 'arg1 not sent')
+ arg2 = message_data.get('arg2', 'arg2 not sent')
+
+ msg = 'An event has been fired from the html to Fusion with the following data:
'
+ msg += f'Action: {message_action}
arg1: {arg1}
arg2: {arg2}'
+ ui.messageBox(msg)
+
+ # Return value.
+ now = datetime.now()
+ currentTime = now.strftime('%H:%M:%S')
+ html_args.returnData = f'OK - {currentTime}'
+
+
+# This event handler is called when the command terminates.
+def command_destroy(args: adsk.core.CommandEventArgs):
+ # General logging for debug.
+ futil.log(f'{CMD_NAME}: Command destroy event.')
+
+ global local_handlers
+ local_handlers = []
diff --git a/f360-script/External controls/commands/paletteShow/resources/16x16.png b/f360-script/External controls/commands/paletteShow/resources/16x16.png
new file mode 100644
index 0000000..f1b8e57
Binary files /dev/null and b/f360-script/External controls/commands/paletteShow/resources/16x16.png differ
diff --git a/f360-script/External controls/commands/paletteShow/resources/32x32.png b/f360-script/External controls/commands/paletteShow/resources/32x32.png
new file mode 100644
index 0000000..a61a47e
Binary files /dev/null and b/f360-script/External controls/commands/paletteShow/resources/32x32.png differ
diff --git a/f360-script/External controls/commands/paletteShow/resources/64x64.png b/f360-script/External controls/commands/paletteShow/resources/64x64.png
new file mode 100644
index 0000000..4dd5dfc
Binary files /dev/null and b/f360-script/External controls/commands/paletteShow/resources/64x64.png differ
diff --git a/f360-script/External controls/commands/paletteShow/resources/html/index.html b/f360-script/External controls/commands/paletteShow/resources/html/index.html
new file mode 100644
index 0000000..2a6176e
--- /dev/null
+++ b/f360-script/External controls/commands/paletteShow/resources/html/index.html
@@ -0,0 +1,39 @@
+
+
+
Message from Fusion
+