forked from thomasa88/NoComponentDrag
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
NoComponentDrag.py
153 lines (128 loc) · 8.07 KB
/
NoComponentDrag.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#Author-Thomas Axelsson, ZXYNINE
#Description-Blocks Component Dragging in parametric mode
#
# Copyright (c) 2021 Thomas Axelsson, ZXYNINE
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# This file is part of NoComponentDrag, a Fusion 360 add-in for blocking
# component dragging.
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import adsk.core, adsk.fusion, adsk.cam
import os
# Import relative path to avoid namespace pollution
from .thomasa88lib import utils, events, manifest, error
utils.ReImport_List(events, manifest, error, utils)
NAME = 'NoComponentDrag'
VERSION = str(manifest.read()["version"])
FILE_DIR = os.path.dirname(os.path.realpath(__file__))
VERSION_INFO = f'({NAME} v {VERSION})'
CMD_DESCRIPTION = 'Enables or disables the movement of components by dragging in the canvas.'
COMMAND_DATA = CMD_DESCRIPTION + '\n\n' + VERSION_INFO + '\n'
ENABLE_CMD_ID = 'thomasa88_NoComponentDrag_Enable'
FUSION_CMD_ID = 'FusionDragComponentsCommand'
FUSION_CTRL_ID = 'FusionDragCompControlsCmd'
ui_:adsk.core.UserInterface = None
app_:adsk.core.Application = None
error_catcher_ = error.ErrorCatcher()
events_manager_ = events.EventsManager(error_catcher_)
enable_ctrl_def_ : adsk.core.CheckBoxControlDefinition = None
select_panel_controls : adsk.core.ToolbarControls = None
parametric_environment_ = True
addin_updating_checkbox_ = False
fusion_drag_controls_def_ : adsk.core.CheckBoxControlDefinition = None
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# This will fire at the start of fusion but not until the workspace is ready which fixes the other problem
#This event removes itself on its first call to prevent useles events being queued
def workspace_activated_handler(args: adsk.core.WorkspaceEventArgs):
events_manager_.remove_handler_by_event(ui_.workspaceActivated)
check_environment()
#This is fired whenever any command is starting up and checks if that command should be blocked
def command_starting_handler(args: adsk.core.ApplicationCommandEventArgs): # Should we block?
if parametric_environment_ and args.commandId == FUSION_CMD_ID and not get_drag_enabled():
args.isCanceled = True
#This is fired any time the command gets disabled
def command_terminated_handler(args: adsk.core.ApplicationCommandEventArgs):
# Detect if user toggles Direct Edit or enters/leaves a Base Feature
# Undo/Redo triggers the ActivateEnvironmentCommand instead.
if (args.commandId in ('ActivateEnvironmentCommand') or
(args.terminationReason == adsk.core.CommandTerminationReason.CompletedTerminationReason and
args.commandId in ('Undo', 'Redo','ConvertToPMDesignCommand', 'ConvertToDMDesignCommand',
'BaseFeatureActivate', 'BaseFeatureStop', 'BaseFeatureCreationCommand'))):
check_environment()
#This is fired when the checkbox changes value
def enable_cmd_created_handler(args: adsk.core.CommandCreatedEventArgs):
# Check if we are updating the checkbox programmatically, to avoid infinite event recursion
if not addin_updating_checkbox_: set_drag_enabled(enable_ctrl_def_.isChecked)
#This is fired whenever the active document is switched
def document_activated_handler(args: adsk.core.WorkspaceEventArgs):
check_environment()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Gets the value of Fusion's "Component Drag" checkbox
def get_drag_enabled(): return fusion_drag_controls_def_.isChecked
#Sets the Fusion's "Component Drag" checkbox to the given value
def set_drag_enabled(value:bool): fusion_drag_controls_def_.isChecked = value
def update_checkbox():
# Only set the checkbox value (triggering a command creation), if the
# direct edit value has actually changed
global addin_updating_checkbox_
direct_edit_drag_ = get_drag_enabled()
if enable_ctrl_def_.isChecked != direct_edit_drag_:
addin_updating_checkbox_ = True
enable_ctrl_def_.isChecked = direct_edit_drag_
addin_updating_checkbox_ = False
def check_environment():
global enable_ctrl_def_, parametric_environment_
# Checking workspace type in DocumentActivated handler fails since Fusion 360 v2.0.10032
# UserInterface.ActiveWorkspace throws when it is called from DocumentActivatedHandler
# during Fusion 360 start-up(?). Checking for app_.isStartupComplete does not help.
is_parametric = bool(utils.is_parametric_mode())
if parametric_environment_ == is_parametric: return # Environment did not change
# Hide/show our menu command to avoid showing to Component Drag menu items in direct edit mode (Our command + Fusion's command).
enable_ctrl_def_.isVisible = parametric_environment_ = is_parametric
# We only need to update checkbox in parametric mode, as it will not be seen in direct edit mode.
# Fusion crashes if we change isChecked from (one of?) the event handlers, so we put the update at the end of the event queue.
if is_parametric and enable_ctrl_def_.isChecked != get_drag_enabled():
events_manager_.delay(update_checkbox)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def run(context):
#Expose global variables inside of function
global app_, ui_, enable_ctrl_def_, select_panel_controls, fusion_drag_controls_def_
with error_catcher_:
app_, ui_ = utils.AppObjects()
fusion_drag_controls_def_ = ui_.commandDefinitions.itemById(FUSION_CTRL_ID).controlDefinition
# There are multiple select panels. Pick the right one
select_panel_controls = ui_.toolbarPanelsByProductType('DesignProductType').itemById('SelectPanel').controls
# Clearing any previous enable_cmd_def # Removing the old control
utils.clear_ui_items(ui_.commandDefinitions.itemById(ENABLE_CMD_ID), select_panel_controls.itemById(ENABLE_CMD_ID))
# Use a Command to get a transaction when renaming
enable_cmd_def_ = ui_.commandDefinitions.addCheckBoxDefinition(ENABLE_CMD_ID, 'Component Drag', COMMAND_DATA, get_drag_enabled())
select_panel_controls.addCommand(enable_cmd_def_, FUSION_CTRL_ID, False) #Adding in the fresh control
enable_ctrl_def_ = enable_cmd_def_.controlDefinition
#Adds all needed handlers to the event manager
events_manager_.add_handler(enable_cmd_def_.commandCreated, callback=enable_cmd_created_handler)
events_manager_.add_handler(ui_.commandStarting, callback=command_starting_handler)
events_manager_.add_handler(ui_.commandTerminated, callback=command_terminated_handler)
events_manager_.add_handler(app_.documentActivated, callback=document_activated_handler)
# Workspace is not ready when starting (?)
# Create a workspace activated handler to wait untill it is ready.
if not bool(context['IsApplicationStartup']): check_environment()
else: events_manager_.add_handler(ui_.workspaceActivated, callback=workspace_activated_handler)
def stop(context):
with error_catcher_: events_manager_.clean_up(select_panel_controls.itemById(ENABLE_CMD_ID))
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~