[Closed] Scripted Plugin Clone Event, detect type?
I have a scripted plugin where when it’s cloned from a user shift-drag action I would like to run a function but if I’m cloning the object with maxops.cloneNodes instead I don’t want it to run. Trying to figure out if there’s a way to detect the user mode as we have many scripts which use cloneNodes()
Isn’t it easier and safer to provide your own cloning tool that will work alongside your scripted plugin?
Another way is to catch all cloning events, but update scripted data just by user’s request.
Do SHIFT clone > Update script plugin…
You could check whether Clone Options dialog was actually opened before #postNodesCloned event.
btw. It works for shift-drag copying but not for Ctrl + V (for that you can use ActionItem Notifications, not sure when it was first added to callbacks)
global n =
(
try ( n.Destroy() ) catch()
local owner
struct NodeShiftCloneHandler
(
selectionChanged = false,
deleted = false,
shift_clone_active = false,
cancelled = false,
fn OnEvent ev nodes =
(
if ev == #callbackBegin or ev == #callbackEnd do return true
case ev of
(
#controllerOtherEvent :
(
-- !!! there could be more than one instance of max with Clone Options dialog open, so you need to find them all. Moreover some max instances could be localized so it is better to find another method to check if the dialog is indeed Clone Options dialog.
local data = windows.getChildHWND 0 "Clone Options"
owner.shift_clone_active = if data != undefined then (windows.getMAXHWND()) == data[6] else false
format "Clone dialog is open: %\n" owner.shift_clone_active
)
#selectionChanged : if owner.shift_clone_active do owner.selectionChanged = true
#deleted : if owner.shift_clone_active do owner.deleted = true
)
if owner.selectionChanged and owner.deleted do owner.cancelled = true
if owner.cancelled do
(
format "CANCELLED\n"
owner.NodeEvents.enabled = false
)
),
NodeEvents = NodeEventCallback enabled:false all:OnEvent,
fn OnPreNodesCloned =
(
format "preNodesCloned\n"
selectionChanged = false
deleted = false
shift_clone_active = false
cancelled = false
NodeEvents.enabled = true
),
fn OnPostNodesCloned =
(
format "postNodesCloned\n"
NodeEvents.enabled = false
if not cancelled and shift_clone_active do
(
format "SHIFT-CLONED\n"
)
),
fn Destroy =
(
NodeEvents = undefined
callbacks.removeScripts id:#test42
gc light:true
),
on create do
(
callbacks.removeScripts id:#test42
callbacks.addScript #preNodesCloned "n.OnPreNodesCloned()" id:#test42
callbacks.addScript #postNodesCloned "n.OnPostNodesCloned()" id:#test42
owner = this
)
)
NodeShiftCloneHandler()
)
maxOps.CloneNodes objects[1]
Another idea, not fully tested. It can fail if there are other scripts modifying the selection.
(
global PreNodesCloned, PostNodesCloned
SHIFT_PRESSED = false
CLONED_NODES = #{}
fn PreNodesCloned =
(
SHIFT_PRESSED = keyboard.shiftPressed
CLONED_NODES = (for j in selection collect j.inode.handle) as bitarray
)
fn PostNodesCloned =
(
for j in selection do CLONED_NODES[j.inode.handle] = false
if CLONED_NODES.isempty then
(
format "CLONED using \"maxOps.CloneNodes()\"\n"
)
else
(
if SHIFT_PRESSED == true then
(
selection.wirecolor = green
format "CLONED using \"SHIFT\"\n"
)
else
(
selection.wirecolor = yellow
format "CLONED using \"CRTL+V\"\n"
)
)
)
callbacks.removescripts id:#ID_0X4AE4797C
callbacks.addscript #preNodesCloned "PreNodesCloned()" id:#ID_0X4AE4797C
callbacks.addscript #postNodesCloned "PostNodesCloned()" id:#ID_0X4AE4797C
)
I would fear that some script may use modifier keys to change script behavior
smth like this
try (destroydialog X ) catch ()
rollout X ""
(
button clone_node "clone node" width:100 tooltip:"Hold Shift to clone as instance, Hold Ctrl to clone as reference"
on clone_node pressed do if selection[1] != undefined do
(
local type = #copy
case of
(
( keyboard.shiftPressed ) : type = #instance
( keyboard.controlPressed ) : type = #reference
)
maxOps.CloneNodes selection[1] cloneType:type offset:[100,0,0]
)
)
createDialog X pos:[100,100]
Nice catch. I’ve modified the script, but there might be other situations where it doesn’t work properly.
Here is another way to catch “custom” (from UI) cloned nodes. I try to monitor “Clone Options” dialog and check if it finishes with #nodecloned general event.
it should catch both SHIFT and CTRL+V cases… but not maxops.clone or any 3-rd party
DialogMonitorOPS.unRegisterNotification id:#clone_monitor
callbacks.removescripts id:#clone_monitor
global cloned_nodes = #()
global callbackContainer
try
(
callbackContainer.enabled = off
callbackContainer = undefined
)
catch()
fn CloneAccept =
(
if isvalidnode (node = callbacks.notificationParam()) do append cloned_nodes node
)
fn CloneEnd e h =
(
callbacks.removescripts id:#clone_monitor
format "cloned >> %\n" cloned_nodes
callbackContainer.enabled = off
callbackContainer = undefined
)
fn CloneMonitor =
(
hwnd = DialogMonitorOPS.GetWindowHandle()
if (UIAccessor.isWindow hwnd) and (UIAccessor.GetWindowText hwnd) == "Clone Options" do
(
cloned_nodes = #()
callbackContainer = NodeEventCallback callbackEnd:CloneEnd enabled:on
callbacks.removescripts id:#clone_monitor
callbacks.addscript #nodeCloned "CloneAccept()" id:#clone_monitor
)
true
)
DialogMonitorOPS.RegisterNotification CloneMonitor id:#clone_monitor
if not DialogMonitorOPS.enabled do DialogMonitorOPS.enabled = on
(of course, we can put everything in one global structure, but this is not the point of this task)