Tape tool as floater UI (Script Wish)


#1

I use the tape quite often, but infortunately, the default UI is really narrow and I cant read the values.

I would like to see a floater UI for the tape tool.


#2
Updated code below.

#3

It has great potential. The UI is larger, so I can see more.

Is it possible to keep the focus on the tape object, so that you can read the values all the time without the need to first select the tape object?
We would need to keep focus both when the tape is been created (eg if I just drag and then right click to cancel the tape) or when I select the target.


#4
Updated code below.

#5

Can the pin feature be automatically called when the UI is there and I press the tape-tool?
Even better: when I execute the code, the UI is built, followed by running the tape-tool for me. Then I could create a button out of your script.


#6

Regarding the idea of automatically creating a Tape when you run the script, although a Tape can be created from a script, I’ve seen issues when trying to select it. The best would be to create a custom Tape plugin.

Updated code below.

#7

This time, nothing happens.
The UI is there, but everything is grayed out.
I tried both creating UI first, tape after, and tape first and UI after, with same result


#8

Don’t know what it could be. Tested it in different Max versions and it works. Just have the UI opened and then manually create a Tape and it should update the values.

EDIT 1: I’ve updated the code, it should now work with any amount of Tapes and keep the values of the latest selected one.
EDIT 2: Improved it a bit. Should have better response and work better when changing selections.
EDIT 3: Fixed bugs and converted to MacroScript.

macroScript Floater_Tape
category:"Tools"
tooltip:"Floater Tape"
buttontext:"Tape"
icon:#("Helpers",5)
(
	global RO_TAPE_FLOATER
	
	on execute do
	(
		rollout RO_TAPE_FLOATER "Tape Floater" width:140 height:194
		(
			label   lbl      "Length:" pos:[12, 4]
			spinner spn1     ""        pos:[ 8,20] fieldwidth:112 range:[0,1e9,0] type:#worldunits enabled:false
			label   lbl_node ""        pos:[12,40] width:104
			
			label lbl1 "To X Axis:"   pos:[20, 64]
			label lbl2 "To Y Axis:"   pos:[20, 84]
			label lbl3 "To Z Axis:"   pos:[20,104]
			label lbl4 "To XY Plane:" pos:[ 8,134]
			label lbl5 "To YZ Plane:" pos:[ 8,154]
			label lbl6 "To ZX Plane:" pos:[ 8,174]
			
			label edt1 "" pos:[74, 64] width:104
			label edt2 "" pos:[74, 84] width:104
			label edt3 "" pos:[74,104] width:104
			label edt4 "" pos:[74,134] width:104
			label edt5 "" pos:[74,154] width:104
			label edt6 "" pos:[74,174] width:104
			
			local plane_xy = [0,0,1]
			local plane_yz = [1,0,0]
			local plane_zx = [0,1,0]
			local node     = undefined
			local ctrl     = float_script()
			
			fn DeleteHandlers =
			(
				deleteallchangehandlers id:#ID_0X5D5F4A2C
				gc light:on
			)
				
			fn UpdateUI =
			(
				if node == undefined or isdeleted node or node.target == undefined or isdeleted node.target then
				(
					spn1.value = 0
					lbl_node.text = edt1.text = edt2.text = edt3.text = edt4.text = edt5.text = edt6.text = ""
					DeleteHandlers()
				)else(
					p1 = node.pos
					p2 = node.target.pos
					
					dir = normalize (p1-p2)
					
					angleToAxis_X = acos dir.x
					angleToAxis_Y = acos dir.y
					angleToAxis_Z = acos dir.z
					
					angleToPlane_XY = abs ((acos (dot dir plane_xy))-90)
					angleToPlane_YZ = abs ((acos (dot dir plane_yz))-90)
					angleToPlane_ZX = abs ((acos (dot dir plane_zx))-90)
					
					spn1.value = distance p1 p2
					
					edt1.text = angleToAxis_X as string
					edt2.text = angleToAxis_Y as string
					edt3.text = angleToAxis_Z as string
					
					edt4.text = angleToPlane_XY as string
					edt5.text = angleToPlane_YZ as string
					edt6.text = angleToPlane_ZX as string
				)
			)
			
			fn GetSelection =
			(
				sel = selection[1]
				
				if sel == undefined do return()
				
				if iskindof sel tape then
				(
					node = sel
				)else if iskindof (refs.dependentnodes sel)[1] tape then
				(
					node = (refs.dependentnodes sel)[1]
				)else(
					node = undefined
				)
				
				if node != undefined and node.target != undefined do
				(
					DeleteHandlers()
					if ctrl.VariableExists "TAPE" then ctrl.SetObject "TAPE" node.controller else ctrl.AddObject "TAPE" node.controller
					
					when parameters ctrl changes id:#ID_0X5D5F4A2C do UpdateUI()
					when node deleted id:#ID_0X5D5F4A2C do
					(
						node = undefined
						UpdateUI()
					)
					
					lbl_node.text = node.name
					
					ctrl.update()
				)
			)
			
			on RO_TAPE_FLOATER open do
			(
				callbacks.removescripts id:#ID_0X350B32A9
				callbacks.addscript #selectionSetChanged "::RO_TAPE_FLOATER.GetSelection()" id:#ID_0X350B32A9
				GetSelection()
			)
			
			on RO_TAPE_FLOATER close do
			(
				callbacks.removescripts id:#ID_0X350B32A9
				DeleteHandlers()
			)
		)
		
		createdialog RO_TAPE_FLOATER style:#(#style_titlebar, #style_toolwindow, #style_sysmenu)

		startobjectcreation Tape
	
	) -- End Excecute
  
	on isChecked return (mcrUtils.IsCreating Tape)
  
)

Here is a modified version, as suggested by Denis, with TextBox controls so you can copy the values.

macroScript Floater_Tape
category:"Tools"
tooltip:"Floater Tape"
buttontext:"Tape"
icon:#("Helpers",5)
(
	global RO_TAPE_FLOATER
	
	on execute do
	(
		rollout RO_TAPE_FLOATER "Tape Floater" width:140 height:194
		(
			label   lbl      "Length:" pos:[12, 4]
			spinner spn1     ""        pos:[ 8,20] fieldwidth:112 range:[0,1e9,0] type:#worldunits enabled:false
			label   lbl_node ""        pos:[12,40] width:104
			
			label lbl1 "To X Axis:"   pos:[20, 64]
			label lbl2 "To Y Axis:"   pos:[20, 84]
			label lbl3 "To Z Axis:"   pos:[20,104]
			label lbl4 "To XY Plane:" pos:[ 8,134]
			label lbl5 "To YZ Plane:" pos:[ 8,154]
			label lbl6 "To ZX Plane:" pos:[ 8,174]
			
			dotnetcontrol edt1 "TextBox" pos:[70, 60] width:62
			dotnetcontrol edt2 "TextBox" pos:[70, 80] width:62
			dotnetcontrol edt3 "TextBox" pos:[70,100] width:62
			dotnetcontrol edt4 "TextBox" pos:[70,130] width:62
			dotnetcontrol edt5 "TextBox" pos:[70,150] width:62
			dotnetcontrol edt6 "TextBox" pos:[70,170] width:62
			
			local plane_xy = [0,0,1]
			local plane_yz = [1,0,0]
			local plane_zx = [0,1,0]
			local node     = undefined
			local ctrl     = float_script()
			
			fn DeleteHandlers =
			(
				deleteallchangehandlers id:#ID_0X5D5F4A2C
				gc light:on
			)
				
			fn UpdateUI =
			(
				if node == undefined or isdeleted node or node.target == undefined or isdeleted node.target then
				(
					spn1.value = 0
					lbl_node.text = edt1.text = edt2.text = edt3.text = edt4.text = edt5.text = edt6.text = ""
					DeleteHandlers()
				)else(
					p1 = node.pos
					p2 = node.target.pos
					
					dir = normalize (p1-p2)
					
					angleToAxis_X = acos dir.x
					angleToAxis_Y = acos dir.y
					angleToAxis_Z = acos dir.z
					
					angleToPlane_XY = abs ((acos (dot dir plane_xy))-90)
					angleToPlane_YZ = abs ((acos (dot dir plane_yz))-90)
					angleToPlane_ZX = abs ((acos (dot dir plane_zx))-90)
					
					spn1.value = distance p1 p2
					
					edt1.text = angleToAxis_X as string
					edt2.text = angleToAxis_Y as string
					edt3.text = angleToAxis_Z as string
					
					edt4.text = angleToPlane_XY as string
					edt5.text = angleToPlane_YZ as string
					edt6.text = angleToPlane_ZX as string

					edt1.update()
					edt2.update()
					edt3.update()
					edt4.update()
					edt5.update()
					edt6.update()
				)
			)
			
			fn GetSelection =
			(
				sel = selection[1]
				
				if sel == undefined do return()
				
				if iskindof sel tape then
				(
					node = sel
				)else if iskindof (refs.dependentnodes sel)[1] tape then
				(
					node = (refs.dependentnodes sel)[1]
				)else(
					node = undefined
				)
				
				if node != undefined and node.target != undefined do
				(
					DeleteHandlers()
					if ctrl.VariableExists "TAPE" then ctrl.SetObject "TAPE" node.controller else ctrl.AddObject "TAPE" node.controller
					
					when parameters ctrl changes id:#ID_0X5D5F4A2C do UpdateUI()
					when node deleted id:#ID_0X5D5F4A2C do
					(
						node = undefined
						UpdateUI()
					)
					
					lbl_node.text = node.name
					
					ctrl.update()
				)
			)
			
			fn SetUpControls =
			(
				for j in RO_TAPE_FLOATER.controls where iskindof j dotNetControl do j.ReadOnly = true
			)
			
			on RO_TAPE_FLOATER open do
			(
				SetUpControls()
				callbacks.removescripts id:#ID_0X350B32A9
				callbacks.addscript #selectionSetChanged "::RO_TAPE_FLOATER.GetSelection()" id:#ID_0X350B32A9
				GetSelection()
			)
			
			on RO_TAPE_FLOATER close do
			(
				callbacks.removescripts id:#ID_0X350B32A9
				DeleteHandlers()
			)
			
		)
		createdialog RO_TAPE_FLOATER style:#(#style_titlebar, #style_toolwindow, #style_sysmenu)
		
		startobjectcreation Tape
		
	) -- End Excecute
  
	on isChecked return (mcrUtils.IsCreating Tape)
	
)

A last version with buttons for copying the values. A bit cluttered UI but does the job.
Three flavors, for all tastes.

macroScript Floater_Tape
category:"Tools"
tooltip:"Floater Tape"
buttontext:"Tape"
icon:#("Helpers",5)
(
	global RO_TAPE_FLOATER
	
	on execute do
	(
		rollout RO_TAPE_FLOATER "Tape Floater" width:156 height:194
		(
			label   lbl      "Length:" pos:[12, 4]
			spinner spn1     ""        pos:[ 8,20] fieldwidth:108 range:[0,1e9,0] type:#worldunits enabled:false
			label   lbl_node ""        pos:[12,40] width:104
			
			label lbl1 "To X Axis:"   pos:[20, 64]
			label lbl2 "To Y Axis:"   pos:[20, 84]
			label lbl3 "To Z Axis:"   pos:[20,104]
			label lbl4 "To XY Plane:" pos:[ 8,134]
			label lbl5 "To YZ Plane:" pos:[ 8,154]
			label lbl6 "To ZX Plane:" pos:[ 8,174]
			
			label edt1 "0.0" pos:[74, 64] width:58
			label edt2 "0.0" pos:[74, 84] width:58
			label edt3 "0.0" pos:[74,104] width:58
			label edt4 "0.0" pos:[74,134] width:58
			label edt5 "0.0" pos:[74,154] width:58
			label edt6 "0.0" pos:[74,174] width:58
			
			button bt0 "C" pos:[132, 18] width:18 height:18 tooltip:"Copy Value"
			button bt1 "C" pos:[132, 62] width:18 height:18 tooltip:"Copy Value"
			button bt2 "C" pos:[132, 82] width:18 height:18 tooltip:"Copy Value"
			button bt3 "C" pos:[132,102] width:18 height:18 tooltip:"Copy Value"
			button bt4 "C" pos:[132,132] width:18 height:18 tooltip:"Copy Value"
			button bt5 "C" pos:[132,152] width:18 height:18 tooltip:"Copy Value"
			button bt6 "C" pos:[132,172] width:18 height:18 tooltip:"Copy Value"
			
			local plane_xy = [0,0,1]
			local plane_yz = [1,0,0]
			local plane_zx = [0,1,0]
			local node     = undefined
			local ctrl     = float_script()
			
			fn DeleteHandlers =
			(
				deleteallchangehandlers id:#ID_0X5D5F4A2C
				gc light:on
			)
				
			fn UpdateUI =
			(
				if node == undefined or isdeleted node or node.target == undefined or isdeleted node.target then
				(
					spn1.value    = 0
					lbl_node.text = ""
					edt1.text     = edt2.text = edt3.text = edt4.text = edt5.text = edt6.text = "0.0"
					DeleteHandlers()
				)else(
					p1 = node.pos
					p2 = node.target.pos
					
					dir = normalize (p1-p2)
					
					angleToAxis_X = acos dir.x
					angleToAxis_Y = acos dir.y
					angleToAxis_Z = acos dir.z
					
					angleToPlane_XY = abs ((acos (dot dir plane_xy))-90)
					angleToPlane_YZ = abs ((acos (dot dir plane_yz))-90)
					angleToPlane_ZX = abs ((acos (dot dir plane_zx))-90)
					
					spn1.value = distance p1 p2
					
					edt1.text = angleToAxis_X as string
					edt2.text = angleToAxis_Y as string
					edt3.text = angleToAxis_Z as string
					
					edt4.text = angleToPlane_XY as string
					edt5.text = angleToPlane_YZ as string
					edt6.text = angleToPlane_ZX as string
				)
			)
			
			fn GetSelection =
			(
				sel = selection[1]
				
				if sel == undefined do return()
				
				if iskindof sel tape then
				(
					node = sel
				)else if iskindof (refs.dependentnodes sel)[1] tape then
				(
					node = (refs.dependentnodes sel)[1]
				)else(
					node = undefined
				)
				
				if node != undefined and node.target != undefined do
				(
					DeleteHandlers()
					if ctrl.VariableExists "TAPE" then ctrl.SetObject "TAPE" node.controller else ctrl.AddObject "TAPE" node.controller
					
					when parameters ctrl changes id:#ID_0X5D5F4A2C do UpdateUI()
					when node deleted id:#ID_0X5D5F4A2C do
					(
						node = undefined
						UpdateUI()
					)
					
					lbl_node.text = node.name
					
					ctrl.update()
				)
			)
			
			fn SetUpControls =
			(
				for j in RO_TAPE_FLOATER.controls where iskindof j dotNetControl do j.ReadOnly = true
			)
			
			on RO_TAPE_FLOATER open do
			(
				SetUpControls()
				callbacks.removescripts id:#ID_0X350B32A9
				callbacks.addscript #selectionSetChanged "::RO_TAPE_FLOATER.GetSelection()" id:#ID_0X350B32A9
				GetSelection()
			)
			
			on RO_TAPE_FLOATER close do
			(
				callbacks.removescripts id:#ID_0X350B32A9
				DeleteHandlers()
			)
			
			on bt0 pressed do setclipboardtext (spn1.value as string)
			on bt1 pressed do setclipboardtext edt1.text
			on bt2 pressed do setclipboardtext edt2.text
			on bt3 pressed do setclipboardtext edt3.text
			on bt4 pressed do setclipboardtext edt4.text
			on bt5 pressed do setclipboardtext edt5.text
			on bt6 pressed do setclipboardtext edt6.text
			
		)
		createdialog RO_TAPE_FLOATER style:#(#style_titlebar, #style_toolwindow, #style_sysmenu)
		
		startobjectcreation Tape
		
	) -- End Excecute
  
	on isChecked return (mcrUtils.IsCreating Tape)
	
)

#9

Works wonderful now! Fantastic work :smiley:

The only tiny bug, nothing critical, is when you drag a tape and right-click to cancel on the fly. I get an error message
"No ""isDeleted"" function for undefined"

Beside than that, works great. Finally a Tape Floater :smiley:

edit: I tried to add this so that the tool works as one:
on execute do StartObjectCreation Tape
on isChecked return mcrUtils.IsCreating Tape

I tried to put it in the beginning and in the end. It worked once, and then it broke. I think it might be because of the right-click -error message I mentioned above.


#10

Glad it worked.

Regarding the error you get, same as the previous error, I don’t get any error when the script is used as is and you create the Tape from the Max UI (not even if I start the tool from the listener), but haven’t tried to put it in a Macro.

What Max version are you using?

What would be best for you, to create a Macro out of the script or to add a button to the script to create a new Tape?

EDIT: Got the error when running from a Macro :slight_smile:. Well, let me know what would you like to do from my previous question and I’ll see if I can finish it.


#11

Code updated. I think everything works fine now as a MacroScript.


#12

i suggest to replace all value outputs with readonly textbox controls to be able copy values in the clipboard.


#13

Thanks Denis.

The fields where previously Edittext controls, but changed them to labels because they perform a lot better. There is a lag in other controls while moving the tape fast. The other native control that performs well are the spinners. Tried some .Net control but they all have a little lag. Perhaps they redraw or update when the system is idle, I don’t know.

Do you know how to make the TextBox control perform better, with no redrawing lag?


#14

it’s not really ‘lagging’… it’s not updating UI controls during some other scripts running.

the way to update ui controls is to use windows.processPostedMessages after setting ui controls values

the SDK enough solution is MAXScript_interface->CheckMAXMessages()


#15

I think the word “lag” isn’t completly wrong, we use it often in programming to describe some sort of delay between events, you know what I mean.

“Lag: A period of time between one event and another.”

As you said, windows.processPostedMessages() should dispatch all the messages, although it may not always ensures a UI redraw or update. If I am not wrong, it would also dispatch other messages, which may cause troubles, wouldn’t it?

In this case it updates the UI, but due to the amount of calls the controller makes, I am unsure of whether or not it is good to put it there.

If someone would like to test its stability you can just add the following line to the code below the “edt6.text = angleToPlane_ZX as string” line:

windows.processPostedMessages()

Just needed for the version that uses the .Net controls.


#16

windows.processPostedMessages() is about window messages. it doesn’t effect any system messages (like system notifications or events).

in your case it’s safe to use… slowing down is possible, but very little

.net controls will meet the same problem with update. or might be worth.


#17

Thank you very much !

The new code works way better than the original tape :smiley:
I love the copy-button

I suggest you publish it on Scriptspot as well :+1:


#18
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 = if use_units != undefined then use_units else off
		
		local w_dl = 220
		
		local w_sh = 54
		local w_st = w_dl - w_sh - 10
		local w_tx = w_st/3
		local w_sp = 2*w_tx
		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]
			edittext length_ed pos:[w_sh,length_lb.pos.y-1] width:w_sp
			checkbox units_ch "Units" checked:use_units pos:([w_sh + w_sp + 6,length_lb.pos.y])

			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
		)
		
		group "World Space Angles: "
		(
			label axis_lb "Axis:" align:#right offset:[-w_st,4]
			edittext angle_xx_ed pos:[w_sh + 0*w_tx,axis_lb.pos.y-1] width:w_tx readonly:on
			edittext angle_yy_ed pos:[w_sh + 1*w_tx,axis_lb.pos.y-1] width:w_tx readonly:on
			edittext angle_zz_ed 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 pos:[w_sh + 0*w_tx,plane_lb.pos.y-1] width:w_tx readonly:on
			edittext angle_yz_ed pos:[w_sh + 1*w_tx,plane_lb.pos.y-1] width:w_tx readonly:on
			edittext angle_zx_ed 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 updateNameUI = if isValidTape tape_node do
		(
			tape_name_tx.text = tape_node.name
		)
		
		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 calc: control: =
		(
			a = roundFloat (abs (calc (dot dir axis)))
			if control != unsupplied then
			(
				if control.text as float != a do 
				(
					control.text = (a as string)
				)
				ok
			)
			else a
		)
		fn updateDataUI = if isValidTape tape_node do
		(			
			d = distance tape_node tape_node.target
			length_ed.text = if not use_units then d as string else units.formatValue d 

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

			windows.processPostedMessages()
		)
		
		on units_ch changed state do 
		(
			use_units = state
			updateDataUI()
		)
		
		fn deleteHandlers =
		(
			deleteallchangehandlers id:#popup_tape
			gc light:on
		)
		fn setupHandlers =
		(
			deleteHandlers()
			
			when transform tape_node changes id:#popup_tape do updateDataUI()
			when name tape_node change id:#popup_tape do updateNameUI()
		)
		
		fn getTapeNode = if isvalidnode (node = selection[1]) do
		(
			if iskindof node Targetobject do node = refs.dependentnodes node firstonly:on
			
			if isValidTape node do
			(
				tape_node = node	
				setupHandlers() 

				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
			callbacks.addscript #unitsChange "::PopupTapeRollout.updateDataUI()" 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 my version… i changed a little callbacks logic, and UI. the UI might look OFF in normal display because i tested it for 4K only (what i have at home)

also couple features added (tape name update, units option, etc.)


#19

Thanks Denis,

Personally, I appreciate different approaches, because it reveals different possibilities.
Here is my feedback

  • I like the UI, it offers many feature. Interresting that once you click and move the target, it sticks to the mouse pointer - what was your motivation for that feature?
  • I like that the toolbar button toggles the UI, however, it does not turn on the tape for me. The toggle could include the tape tool as well. But then we would need a tape-button in the UI as well, because in Jorge’s approach, pressing the toolbar button toggles the tape alone (like in the native tape tool). The way I use the tape tool is mostly creating it and RMB click to cancel it on the fly once I got what I needed, which is measuring. After cancelling the tool, I might need it again - so pressing the toolbar button would in this case turn off the UI instead of giving me a new tape. Optionally, RMB-cancelling the tool could simply turn of the UI as well, so that I would need to press the toolbar button again to get the tool plus UI. This could work :slight_smile:
  • Issues: I get two MAXScript Change Handler Exception: Unable to convert: undefined to type: <node> when I click the Tape Tool

#20

Issues: I get two MAXScript Change Handler Exception: Unable to convert: undefined to type: when I click the Tape Tool

that was a bug. fixed.

about combining the pop-up tape params dialog and tape creation tool… i don’t want to combine it one tool.
the dialog binds to any newly created tape object or to any selected tape or its target.