Notifications
Clear all

[Closed] Tape tool as floater UI (Script Wish)

macroScript Popup_Tape
	category:"Tools"
	tooltip:"Popup Tape Params"
	buttontext:"POPUP TAPE"
(
	global PopupTapeRollout = if PopupTapeRollout != undefined do PopupTapeRollout

	--local dialog_width = 220 
	
	rollout PopupTapeRollout "Popup Tape Params" width:220
	(
		local opened = off
		local placed = if placed != undefined do placed
		
		local use_units = on
		
		local dialog_width = 220
		
		local w_sh = 54
		local w_st = dialog_width - w_sh - 10
		local w_tx = w_st/3
		local w_sp = 2*w_tx - 12
		local w_bx = 3*w_tx
		
		local w_im = w_sh + 4
		local h_im = 18
		
		fn isValidTape node = (iskindof node Tape and not isdeleted node and isvalidnode node.target)
		local tape_node = if tape_node != undefined do tape_node
			
		group "Current Tape: "
		(
			label length_lb "Length:" align:#right offset:[-w_st,4]
			spinner length_sp pos:[w_sh,length_lb.pos.y] fieldwidth:w_sp type:(if use_units then #worldunits else #float) range:[0.0001,1e9,0] --scale:(universeScale 1)
			--checkbox units_ch "Units" checked:use_units pos:([w_sh + w_sp + 18,length_lb.pos.y]) enabled:off -- built-in mxs doesn't support changing spinner type after creation 

			label tape_lb "Name:" align:#right offset:[-w_st,6]
			edittext tape_name_tx pos:[w_sh,tape_lb.pos.y-1] width:w_bx
		)
		
		local null = "0.0"
		group "World Space Angles: "
		(
			label axis_lb "Axis:" align:#right offset:[-w_st,4]
			edittext angle_xx_ed text:null pos:[w_sh + 0*w_tx,axis_lb.pos.y-1] width:w_tx readonly:on
			edittext angle_yy_ed text:null pos:[w_sh + 1*w_tx,axis_lb.pos.y-1] width:w_tx readonly:on
			edittext angle_zz_ed text:null pos:[w_sh + 2*w_tx,axis_lb.pos.y-1] width:w_tx readonly:on
			imgtag axis_im pos:[0,axis_lb.pos.y-2] width:w_im height:h_im transparent:black tooltip:"Axis X Y Z"

			label plane_lb "Plane:" align:#right offset:[-w_st,4]
			edittext angle_xy_ed text:null pos:[w_sh + 0*w_tx,plane_lb.pos.y-1] width:w_tx readonly:on
			edittext angle_yz_ed text:null pos:[w_sh + 1*w_tx,plane_lb.pos.y-1] width:w_tx readonly:on
			edittext angle_zx_ed text:null pos:[w_sh + 2*w_tx,plane_lb.pos.y-1] width:w_tx readonly:on
			imgtag plane_im pos:[0,plane_lb.pos.y-2] width:w_im height:h_im transparent:black tooltip:"Plane XY YZ ZX"
		)
				
		fn roundFloat d pre:0.01 =
		(
			d = (d as float)/pre
			v = if (d - (v1 = floor d)) > ((v2 = ceil d) - d) then v2 else v1 
			v*pre
		)
		fn axisAngle dir axis func: control: =
		(
			local ang = roundFloat (abs (func (dot dir axis)))
			if iskindof control RolloutControl then
			(
				if control.text as float != ang do control.text = (ang as string)
				ok
			)
			else ang
		)

		fn updateNameUI = if isValidTape tape_node do
		(
			tape_name_tx.text = tape_node.name
			--tape_name_tx.text = tape_node.name + " (" + tape_node.target.name + ")" -- if you want to show tape's target name 
		)
		fn updateDataUI = if isValidTape tape_node do
		(
			--notifydependents tape_node.target partid:#tm -- DON'T uncomment! it just proves problems with processPostedMessages
			
			length_sp.value = distance tape_node tape_node.target 

			local dir = tape_node.dir
			
			axisAngle dir x_axis func:acos control:angle_xx_ed
			axisAngle dir y_axis func:acos control:angle_yy_ed
			axisAngle dir z_axis func:acos control:angle_zz_ed
			
			axisAngle dir z_axis func:asin control:angle_xy_ed
			axisAngle dir x_axis func:asin control:angle_yz_ed
			axisAngle dir y_axis func:asin control:angle_zx_ed

			windows.processPostedMessages()
		)
		fn updateLength value: =
		(
			if value == unsupplied do value = length_sp.value
			if tape_node.isselected then
			(
				pos = tape_node.pos - tape_node.dir * value
				tape_node.target.pos = pos 
			)
			else
			(
				pos = tape_node.target.pos + tape_node.dir * value
				tape_node.pos = pos
			)
		)
		
		on length_sp buttondown do if isValidTape tape_node do
		(
			theHold.Begin()
			updateLength()
		)
		on length_sp entered spin can do if isValidTape tape_node do
		(
			if spin and theHold.Holding() do 
			(
				if can then theHold.Cancel() else theHold.Accept "Set Length"
			)
		)
		on length_sp changed val do if isValidTape tape_node do
		(
			local hold = theHold.Holding()
			undo "Enter Length" (not hold) updateLength()
		)
		
		fn deleteHandlers = (deleteallchangehandlers id:#popup_tape)
		fn setupHandlers node = 
		(
			deleteHandlers()
			
			tape_node = node	
			
			when transform tape_node changes id:#popup_tape handleAt:#redrawViews do updateDataUI()
			when transform tape_node.target changes id:#popup_tape handleAt:#redrawViews do updateDataUI()
			when name tape_node change id:#popup_tape do updateNameUI()
			--when name tape_node.target change id:#popup_tape do updateNameUI() -- if you want to show tape's target name 
		)
		
		fn getTapeNode = if isvalidnode (node = selection[1]) do
		(
			if iskindof node Targetobject do node = refs.dependentnodes node firstonly:on
			
			if isValidTape node do
			(
				setupHandlers node

				updateDataUI()
				updateNameUI()
			)
		)
		
		on PopupTapeRollout close do
		(
			opened = off
			placed = getdialogpos PopupTapeRollout
			
			callbacks.removescripts id:#popup_tape
			deleteHandlers()
			updateToolbarButtons()
		)

		on PopupTapeRollout open do
		(
			opened = on
			placed = getdialogpos PopupTapeRollout
			
			callbacks.removescripts id:#popup_tape
			callbacks.addscript #selectionSetChanged "::PopupTapeRollout.getTapeNode()" id:#popup_tape
			
			getTapeNode()
			updateToolbarButtons()
		)
	)
	
	
	fn isOpened = (iskindof ::PopupTapeRollout RolloutClass and ::PopupTapeRollout.opened)
	on isChecked do isOpened()

	on execute do
	(
		if isOpened() then
		(
			try (::PopupTapeRollout.placed = getdialogpos ::PopupTapeRollout) catch()
			try (destroydialog ::PopupTapeRollout) catch()
		)
		else
		(
			pos = if iskindof PopupTapeRollout RolloutClass do PopupTapeRollout.placed
			pos = if iskindof pos Point2 then pos else unsupplied
			createdialog PopupTapeRollout style:#(#style_titlebar, #style_toolwindow, #style_sysmenu) pos:pos
		)
		updateToolbarButtons()
	)
)
try (destroydialog ::PopupTapeRollout) catch()

this is new version… i’ve cleaned up node monitoring, and add editable tape length.
the code about ‘undoable editing’ of tape length might be interesting for mxs developing beginners.

the logic of ‘length editing’:
– change the length spinner’s value using arrows or by typing
– if tape node (or both tape and target) is selected the target moves
– if tape target node (or nothing) is selected the tape node moves

PS. if you would find a bug, please, tell me about and let me fix it

Page 3 / 3