Extension web interface

My extension gets a bug splat when using Windows SketchUp Pro 2022. I am using web page interface. Was something deprecated? My link is using “skp:selection@”. Any ideas where to begin.

Without seeing your code snippets … it is difficult.

However you should be using the newer UI::HtmlDialog class.

This is the old skp: protocol used with the old deprecated class. The new class does not need to use this protocol as there is a sketchup JavaScript object defined in the new class’ Chromium environment.

2 Likes

UI::WebDialog is deprecated, but no functionality removed. Even if something was removed it should not be allowed to crash SketchUp.

A reproduction code snippet would be useful.

AllanBlock_3DModelingTools.rb (24.5 KB)

AllanBlock_3DModelingTools.rb (24.5 KB)

Here is my code that gives the bug splat.

Several issues with your Ruby coding.

1. Ruby uses 2 space indents.

2. An extension should only create it’s commands and toolbar once.
You have the creation code inside a menu item block. This means that each time the menu item is clicked, that extra duplicate commands and toolbar will be created.

3. Your “Load” menu item is attempting (poorly) to create a similar load on demand that is built into SketchUp if a proper SketchupExtension object is created in a registrar script and the extension code is placed in an extension subfolder.
This allows the user to switch the extension on and off via the Extension Manager interface.

4. Commands and menu items cannot be dynamically redefined. For this reason it is better to wrap command code within a Ruby method and have only that method call within the menu item or command block.
Then during development, the coder can reload their extension code (or a certain part if it’s separated into multiple files,) … without having to close and restart SketchUp.

5. Try to leverage the global __dir__ and File.join methods, as well as temporary references to reduce the use of long literal path strings:

      # Before all the command definitions ...
      icons = File.join(__dir__,'icons')

      # later below when defining command objects ...
      cmdf.small_icon = File.join(icons, 'btnFavorites-16.png')
      cmdf.large_icon = File.join(icons, 'btnFavorites-24.png')

The above assumes you setup an extension properly with the code files within a subfolder. (Only the registrar file goes in the “Plugins” folder.)

6. It is not necessary to set the toolbar reference multiple times. IE …

      toolbar = toolbar.add_item cmds

… etc. It is already set when you called the class constructor ::new method.

7. Honor the user’s toolbar and interface settings …

toolbar.get_last_state == TB_NEVER_SHOWN ? toolbar.show : toolbar.restore

8. If you must use file_loaded? then the call to file_loaded( __FILE__ ) should go within the file_loaded? conditional block.
We’ve long advocated that instead of using these methods to compare very long path strings (which is slow) in a very large global array, that coders should use a module variable within their extension submodule to wrap conditional code such as GUI object creation. Ex:

      unless defined?(@gui_loaded)
        #
        # ... menu and toolbar creation here ...
        #
        @gui_loaded = true
      end

9. Normally callbacks are attached to the dialog object before the window is shown. Also you should define the callbacks in a method. If the user closes the dialog window, the object still exists but the callbacks are disconnected. Having the callback definitions within a method allows them to be reconnected by calling the method again if the dialog is reshown.

10. As noted (in 5.) above about using __dir__, if you have resources in subfolders of your extension subfolder, you can use …

more = File.join(__dir__, 'Textures', 'More')

… and use this reference to load files.
The reason is that Sketchup.find_support_file() looks in multiple (hardcoded) places (that can vary between Mac and Windows) and could return false or an empty string which you do not want passed as an argument to the global require method.
The places where it searches has not been made a part of the API contract. (The doc says “within installation directory” but this may not be 100% true anymore.)
So, anyway, you know where they are so there is no need to search for them.

11. Code defensively when loading external files or doing other IO.
Verify that files exist before calling require or load, and verify the return values from require or load. Don’t assume everything went okay.
BTW, require will only load a file once and return true, otherwise it does not and returns false.
Same goes for any use of Sketchup.find_support_file(), it’s return needs to be checked for “truth”.

12. With the new UI::HtmlDialog class, you no longer have to pass everything as a string and split it up afterward.
Instead you can pass JavaScript arrays and objects to the Ruby callbacks, and they will convert them to Ruby Arrays and Ruby Hashes, respectively.

That’s unfortunately not a complete example that can be run in isolation. It’s not possible to just look at the code and determine what might crash on your system. Can you produce a complete minimal example that we can run on our machine please?

1 Like