Push_tool and pop_tool?

I can’t seem to come up with any use-case for these methods. What are they for?

Tools#push_tool seams to be the same as model.select_tool so maybe it’s just a matter of preference which one you use.

Tool#pop_tool is more difficult to understand. I was thinking you maybe could use it in a custom camera tool to re-activate the previous tool once the camera has been moved. However it doesn’t re-activate the previous tool but the “default tool” (aka select tool). I just can’t figure out what this is for.

Btw, I think it’s really interesting to discuss use cases for the´more obscure API methods. Often the docs doesn’t provide much help so these discussions are really useful.

‘pop_tool’ only works if you ‘push’ your tool first and not if it uses ‘select_tool’…

so if the current tool is ‘rectangle tool’, you start your tool by ‘pushing’ it Sketchup.active_model.tools.push_tool MyRubyTool.new

when you end it using Sketchup.active_model.tools.pop_tool the ‘rectangle tool’ will be active…

if you start it with Sketchup.active_model.select_tool MyRubyTool.new, then pop_tool fails silently and you get select_tool = nil

it’s prime use case is to behave like when you use ‘orbit tool’ which only suspends the users current tool, rather than force them too use the selection tool on completion…

it’s tricky to implement because you need to start your tool with the ‘push’ and end your tool with the ‘pop’…

@AdamB made a test tool found here



… another little priceless nugget of info missing from the docs.

In a (half-hearted) defense of the omission: Is there ANY programming environment where a “pop” operation is expected to guess what hasn’t been “pushed”? My impression that “pops” need to be paired with a preceding “push” is so ingrained in the concept of FIFO stacks that it doesn’t need to be documented.

Except that the model’s toolstack is initiated and maintained by SketchUp. Any normal person would think that popping off the tool on the top of the stack, should re-activate that tool underneath.

It seems after having trouble and reading threads like this, that there are two (or more) toolstacks. (who knows?)

It doesn’t really make sense that model.select_tool(tool) would push references onto some “secret” toolstack. Also that we cannot pop native tools, to reactivate the previous one (ruby nor native.)

I know it always been like this, but it still has been a peeve of mine for a long time, as I had to throw at least one of my plugin projects in the “wait till the API is fixed” folder years ago (along with a whole bunch of others.)


I gather this issue has been fixed? E.g.:

    model.tools.push_tool(nil)  # Refresh VCB

is my workaround to get active tools to update the VCB. And it happily re-selects native tools.

@tt_su Why would #push_tool allow this as nil is not an abstract Tool class object ?
It results in an invalid object on the toolstack (and it’s return ID from #active_tool_id may be invalid.)

@JDTS What your “hack” actually does is momentarily activate another “tool” (which is actually not a tool,) which first deactivates your tool, then afterward reactivates it. This seems like this would not result in a normal suspend then resume cycle.

Is this true ? Which does your “workaround” fire … your tool’s #deactivate() / #activate() OR #suspend() / #resume() method pair ?

Mine isn’t a custom tool. Rather it is a custom options-setting command that should work with any tool (see this post for the code). For example, while sketching, measuring, drawing a circle, etc.

Since view.refresh does not invalidate the content of the VCB, my hack activates “no tool”, then reactivates the formerly active tool, which presumably causes that tool to repopulate the VCB with fresh content, and also update the tooltip. I don’t know internally whether it’s suspend/resume-ing or activate/deactivate-ing. But the fact that it works with a built-in tool selected through the UI indicates to me that they are now (SU2018) utilizing the tool stack for user selection as well as direct tool_push. I haven’t tested it with every tool, but it works with everything I’ve tried, including sketch tool, circle, rectangle, tape-measure, etc.

When is the VCB not updating as it should?

When I change the units format programmatically. You then have to move the cursor to get VCB information in the new units framework. This hack works around that.

1 Like

That was new to me. I would consider that a bug.

Are you using view.refresh outside of a tool?

That raises an interesting question about how #push_tool should test its argument. Arguably nil is never acceptable because it can’t possibly be a legitimate Tool. But Tool is a protocol, not a class, so for example #is_a? and the like can’t be used to check! Furthermore, the Ruby API doesn’t specify any minimal set of methods from the Tool protocol that an object must implement to be considered a Tool, quite the opposite it says “You do not have to implement methods for every possible event that a Tool can respond to.” Perhaps the Ruby API needs an added mandatory method along the lines of #is_tool?

Yes. No tool, generic extension while using any tool.

One could say nil is an instance of NilClass which decided not to implement any Tool methods. That way it is just as legitimate as any other class that SketchUp accepts as tool.

Since all methods in the Tool interface are currently free to implement depending on whether the developer has something to do in a specific hook or not, there is no common denominator. Except requiring to inherit or include Sketchup::Tool, or adding required metadata like Sketchup::Tool#name which would make a lot of sense regarding active_tool_name. But nothing of all that could be made required because of backwards-compatibility.

1 Like

All valid points.

Of course, for that to work Sketchup::Tool would actually have to exist. Contrary to the Ruby API docs, there is currently no such object defined!

> class TestTool < Sketchup::Tool
Error: #<NameError: uninitialized constant Sketchup::Tool>
<main>:in `<main>'
SketchUp:1:in `eval'

@slbaumgartner. Sketchup::Tools is defined…

Sketchup.active_model.tools.class  # => Sketchup::Tools
# so...
class TestTool < Sketchup.active_model.tools.class
# gives no error...


That is the Tools collection class, not the class of an individual Tool!