How to access existing toolbars and call existing commands?

Hello Everyone!

I am trying to build a better toolbar interface as a plugin. It should work like this:

  1. Access all existing toolbars. Gather information about all commands (icon & tooltip) in each toolbar.
  2. Hide all existing toolbars.
  3. Show all commands in my plugin’s own window (a webview window), so the user can easily arrange and use them.
  4. When the user clicks on a command in my plugin’s own window, call that command. So it should look exactly like the user clicked the original command in the toolbar.

I know how to do step 2 and 3 with Ruby API. But how can I get all existing commands? And call any one of them? I did not see such API in the document. Am I missing something due to not being familiar with Ruby language itself?

You can check out Sketchup#send_action for performing the actions themselves, but you can’t fetch the names or descriptions. Those have to be redefined.

fetching all the names…

puts
ObjectSpace.each_object(UI::Toolbar) { |tb| p tb.name }
puts
UI.toolbar_names.map { |n| p n }
nil

john

1 Like

There are Ruby objects for native toolbars? :open_mouth:

No there are not, AFAIK. The 2nd module method (of the UI module) that John shows simply return names (String) of the native toolbars. As it’s documentation says …

The toolbar_names method is used to return the name of all the available native toolbars (this differs between PC and Mac). These toolbar names do not include Ruby toolbars.

So this is the reason for John showing the first iterator filtering the ObjectSpace for the Ruby toolbar objects.

Have you looked at Aerilius’ Toolbar Editor extension ?
Yours would have to do similar things as his, and they might not be compatible with one another.

This is a challenge. When menu items or UI::Command objects are created they get assigned an integer ID number. Sketchup.send_action can take these ID integers, but only on the MS Windows platform.

The API does not expose an ID getter, nor getters for the command proc, or validation proc.

This means you would have to do a “no no” which is to “tap” into (and modify) the UI::Command class’ methods to “grab” references to the Proc objects as they are passed into the methods.

You could iterate the ObjectSpace and get a listing for all Proc objects defined, but it is very difficult to pair up the procs knowing only the source file and line number with the UI::Command objects that “own” them.

For the native commands, you’d have to create the UI::Command objects (or simply methods that duplicate the native commands functionality.) The images (SVG for Windows and PDF for Mac) are in the SketchUp application’s “Images” subfolder.
On Windows …

Sketchup.find_support_file("Images")
#=> C:/Program Files/SketchUp/SketchUp 2020/Images

This would be a different path on Mac platform.

Thank you! Your reply helps a lot.
So what I understand is, that I only need to “tap” into UI::Command to get all I want (icon, tooltip, proc objects…), and Aerilius’ Toolbar Editor already did this, so I can learn from reading its source code. Am I right?
P.S. Although unrelated to SketchUp, could you please give me some hint about how to tap into a Ruby class? I am quite familiar with this kind of meta-programming with other languages like Python, but some examples or links with Ruby would be very helpful!

It may not be that simple. Ie, there are other things you may need to do and know.

Normally, you need to be very experienced with Ruby in order to do the modifying correctly without causing issues for other extensions. The SketchUp Extension Warehouse regulations do not allow extensions posted that modify any API or Core Ruby modules or classes. (Such extensions will be rejected.)

I looked at his code and Aerilius so far I do not see that he actually “tapped” into or modified the UI::Command class. He didn’t need to as his extension only creates custom native toolbars, which the user will fire by clicking buttons.
So his extension is only a helper to create custom toolbars (using buttons from other toolbars and new buttons with custom code snippets.)

So he did not actually need to fire the command procs from code. But if you will be creating HTML buttons and needing to fire the Ruby commands of other coder’s extensions, you’ll need to be able to do this.
Your choice is either to modify an API class and risk having your extension shunned, …
…or …
Perhaps publish a guideline on allowing other coders to “register” their extension’s command methods with YOUR extension. (This also requires the other coders to use good coding practice and have their UI::Command procs do nothing more than call a command method. This is good coding practice because the method can be redefined “on the fly” during development and testing, but UI::Command procs cannot. Ie, Proc objects are a snapshot of the calling environment. See the Ruby Core docs for more information.)

If you only intend to use your extension in house, then it’s up to you not to interfere with any other extensions you will be using. And the prohibition on API and Core modifications doesn’t apply.
(However if you cause issues for other extensions, especially commercial extensions, those extension companies will not be pleased to spend support efforts debugging such situations. If you were to release such an extension via your own retail portal, you could incur legal troubles if your product interferes with one of the big commercial extensions.)

I will not specifically publicly post an example of modifying an API class. I’m sure you will understand such an example (given your Python experience.) I can send you an example via a PM if you like. But you will assume all legal liability.

He has not encrypted his source code, but the extension registrar script states that it is copyright.

Please discuss with him any code sharing. At one time I think he was asking if anyone wished to help maintain the code. (The version posted in the SketchUp Extension Warehouse is newer than that posted at SketchUcation.)

Perhaps your extension could be an add-on to his. (Ie, his extension already creates a singleton UI::Command index that your code could query.) But then again, creating an index isn’t that difficult and if you do “tap” into the UI::Command class, your code might as well push the proc reference into an index at the same time.


I recall many years ago, discussing doing this (perhaps as an open source Community Library extension) that all or any extension could use. It would eliminate situations as we are discussing here and now.


All this aside, ... there is another hurdle to overcome ...

All this aside, … there is another hurdle to overcome in trying to use Web Dialog command buttons.

(You are not the first to attempt this.) And this challenge is one of window focus. You need to give the main SketchUp application window the focus just after the user clicks the command button in your Html Dialog.

Although long requested, such an API feature has not yet been implemented. So coders have to employ “hacky” workarounds which might differ with platform.

Please search this forum category and perhaps the Dev forum over at SketchUcation for discussions on focus. (As it’d diverge away from this topic.)

Thanks for your great answer! Now that I know all these options and difficulties, I am going to reconsider my requirements.