Combine multiple operation into one

When manipulating an entity, I may perform a similar operation on it multiple times, such as rotating it by a random angle up to 120 times. After completing these operations, if I want to return to the initial state, I would need to undo the operation 120 times, but in practice, I can only undo a maximum of 100 times.

How can I merge these 120 operations into one? I know that the last parameter of the start_operation function can merge operations, but it still only allows for a maximum of 100 operations to be merged.

Have you tried just wrapping the 120 intermediate edits into a single operation ?

You can define a block form method within your extension submodule to simplify wrapping operations:

def wrap_as(op_name)
  model = Sketchup.active_model
  model.start_operation(op_name, true)
    yield model model.active_entities model.selection
rescue => error
  puts error.inspect

@DanRathbun’s snippet shows a neat way of wrapping a series of steps as one operation. But be aware that wrapping all the edits in a single operation does not preserve them as individual “undoable” steps. SketchUp has no support for both kinds of undo on the same series of steps. If all you need is the bulk undo, there’s the answer: don’t make each step an operation in the first place.

1 Like

Regarding the maximum number of undo steps.

This describes a likely obsolete feature. (... click to expand ...)

The default setting is 100.

  • NOTE: The "MaxUndo" setting described below no longer exists in v2023.

On Windows prior to v18, the "MaxUndo" attribute was within the registry dB using the "Preferences" key, for the user SketchUp settings. (ex: HKCU\Software\SketchUp\SketchUp 2017\Preferences)

Since v18, it is now within the "SharedPreferences.json" file ie:
"Shared for All Computers" > "Preferences" > "MaxUndo"

Where xx is the current year edition

On Windows this file is in the Roaming %AppData% path for the current SketchUp version.
%AppData%/SketchUp/SketchUp 20xx/SketchUp/SharedPreferences.json

On Mac, this file is in the user App Support path:
~/Library/Application Support/SketchUp 20xx/SketchUp/SharedPreferences.json

These files must be edited with SketchUp closed otherwise any changes will be overwritten by SketchUp when it closes. The files are read by SketchUp when it loads.

No guarantee that SketchUp still accepts the value of this attribute although it has been in the preference settings for years (since v2016 at least.)

Always make a backup copy of these files before attempting manual edits.

Strange. I just checked, and on my Mac that setting is present in SharedPreferences.json for all versions from 2018 through 2022, but is missing in 2023! I never manually edited it into any of them (all are at the default 100), so why does 2023 omit the setting? Was there a change to the handling of the undo stack?

Yes. Same on Windows, the setting is no longer there for v2023.

Perhaps it has been orphaned for a while and was finally removed as not working ?

Thanks for your solution.

But what I’m doing is developing a custom tool, like the rotation tool, every time the mouse moves, the selected entities will rotate to the new angle. These rotation steps are executed in onMouseMove method, so they can’t be wrapped into a single operation. After the user clicks the mouse button, the rotation is completed, and if the user wants to recover to the original state, they will press Ctrl + Z.

The original Sketchup rotation tool can press Ctrl + Z once to recover, but I don’t know what magic it has.

One workable approach is to use Sketchup.undo(). On the first mouse move after activation there is an initial start_operation()/commit_operation(). Then with each mouse move you perform an undo() which resets the target geometry to its initial position and then another start_operation()/commit_operation() with a new transformation in between. The result of all of this jerking about of the undo stack is that there is only ever one operation to undo no matter how many times the geometry is transformed…

At one point a while back I found that I needed a way to drag screen text around the screen with a Ruby Extension (which is sort of the same repeated transformation problem). Here’s the code and a short screen capture of the tool in action. sw_Screen_Text_Mover.rbz (13.3 KB)

Edit: Removed animated GIF

1 Like

Thanks, this solution works! But it also makes the program much more complicated if we create some entities between two rotations or movings.

It’s the best solution for now anyway, thanks again.

Perhaps you can follow this logic:

module Dezmo
module DezmoTest

class DezmoTestTool

  def initialize
    @in_transform = false
    @myselection = nil
  def onCancel(reason, view)
    view.model.abort_operation if @in_transform
    @in_transform = false
  def onLButtonDown( flags, x, y, view )
    if @in_transform
      if @myselection
        start_transform( view, "My Rotation" )
        # code for select the entities to rotate
        #   and set @myselection
  def onMouseMove(flags, x, y, view)
    if @in_transform && @myselection
      # code for trasnform (rotate) the entities (@myselection)
      # code for select the entities to rotate
      #   and set @myselection

  def start_transform( view, undo_text )
    @in_transform = true
    #view.model.start_operation(undo_text, true)
    # edited:
  def commit_transform( view )
    @in_transform = false

end #tool

end #extension
end #namespace

If you are starting a long operation in a tool, then you don’t want to disable the UI (second argument), that would prevent any visual feedback while the tool updates the model.


This is what I exactly want. I made a mistake that I thought the start_operation and commit_operation should match in one method, just like def and end :slight_smile:

The separate operation control methods allow multiple paradigm coding.

The all-in-one method pattern as I’ve shown above is the simplest paradigm.
But as you’ve found is usually not suitable for complex event driven tool codeflows.