Notifications
Clear all

[Closed] Help with spinner using "with undo"

Just putting together a little script that manipulates various properties of a selected camera and want to be able to undo changes made by the spinners.

Sample code:


  on spn_TargetDist buttondown do with undo "Target distance" on
  		(
  			If currentcam.type == #target then Currentcam.targetdistance = spn_TargetDist.value
  			else Currentcam.target_distance = spn_TargetDist.value
  		)
  
  	On spn_TargetDist changed val do
  	(
  			If currentcam.type == #target then Currentcam.targetdistance = val
  			else Currentcam.target_distance = val
  	)
  

This works as expected if the value of spinner “spn_TargetDist” is changed by “Spinning” the spinner, however manually entering a value does not generate any undo blocks.

My next logical step was to put with undo into the changed val event.


  on spn_TargetDist buttondown do with undo "Target distance" on
  		(
  			If currentcam.type == #target then Currentcam.targetdistance = spn_TargetDist.value
  			else Currentcam.target_distance = spn_TargetDist.value
  		)
 
  	On spn_TargetDist changed val do with undo "Target distance" on
  	(
  			If currentcam.type == #target then Currentcam.targetdistance = val
  			else Currentcam.target_distance = val
  	)
  

This fixed the manually entered values, however “spinning” the spinner will generate hundreds of undo blocks due to obviously the On changed event constantly updating while dragging the mouse.

I have tried using an on entered event but this only generates an undo block once the value has been inputted and user pressed enter.

Is there a simple workaround to this problem ? Many thanks in advance.

D.

6 Replies

Hi David,

Take a look into using theHold

You can call

if not thehold.holding() then thehold.begin()

in the spinner button down event,

and then in the spinner buttonup event –

TheHold.accept <Undo List string>

with this you can capture a block of code operations into one Undo entry.


 try(destroydialog dialog) catch()
 rollout dialog "" width:200
 (
 	spinner sp "Target Distance: " fieldwidth:56 range:[0.0001,1e9,0]
 	
 	local cam
 	fn setDistance value:sp.value = if iskindof cam Camera do (cam.targetdistance = value)
 
 	on sp buttondown do undo "Set Value" on setDistance value:cam.targetdistance
 	on sp changed v do setDistance()
 	on dialog open do
 	(
 		delete objects
 		cam = targetcamera target:(targetObject())
 		sp.value = cam.targetdistance = 100
 		gc() -- start new undo session 
 	)
 )
 createdialog dialog
 

is it what you are looking for?

PS. using theHold is a good idea!

Thanks for all your suggestions, I wasn’t aware of the thehold feature so I am sure I can make good use of that in the future. I tried thehold in the buttondown/up events and this worked as a nice alternative for “spinning” the spinners however still hasn’t resolved manually entered values.

The source of the problem I can see is that clicking in the spinners dialog, to manually enter a value, doesn’t seem to constitute a buttondown event? Is there an event that can recognise when the user clicks in the spinners dialog pre entering a new value?

you do have an entered event, you could use the undo context for that event, and thehold to capture the multiple spinner ‘twiddle’, for want of a better word.


 try(destroydialog dialog) catch()
 rollout dialog "" width:200
 (
 	spinner sp "Target Distance: " fieldwidth:56 range:[0.0001,1e9,0]
 	
 	local cam
 	fn setDistance value:sp.value = if iskindof cam Camera do (cam.targetdistance = value)
 
 	on sp buttondown do undo "Set Value(spin)" on setDistance value:cam.targetdistance
 	on sp changed v do setDistance()
 	on sp entered spin cancel do undo "Set Value(enter)" on if not spin and not cancel do setDistance()
 
 	on dialog open do
 	(
 		delete objects
 		cam = targetcamera target:(targetObject())
 		sp.value = cam.targetdistance = 100
 		gc() -- start new undo session 
 	)
 )
 createdialog dialog
 

does it solve the problem now?

Thanks Denis this seems to resolve the problem.