How to get in Ruby the list of templates

I am creating my own template manager.
One reasons is; I want to separated al the templates in groups, like a group for site plans, concept e.t.c, a group for 3D-printer modelling, one for the default SU templates.

Second ; If I open SU I get the start window then I can choose from a cluttered table of templates. After I choose one or open a recent document, and close that I have to go to the preference window to open a new template. Who did put it there!!! Has nothing to do with preferences. I just want to open a new document build from a template. So, or ‘New’ should be 'New…" and open a dialog with templates or I have to make one bij myself, where they are ordered by group.

It does because that function is setting the default template for SketchUp’s “New” command.

No New should remain New (as it is for quickly starting a new model from a user’s or company’s normal [default] template. Ie, some companies will enforce a certain template that employees must use.)

But (as I said above) we should have long ago had a “New from template…” command that opened a template manager like all the office suites have.

Pro users usually uncheck the box so that the Welcome dialog does not show on startup.

This must be a Mac only thing. This will not happen on Windows. But then again Windows always has a model open, and only 1 model open.

Actually there is a standard procedure. You enable AppObserver functionality for your plugin submodule.
Observers do not need to be a class object, nor even a subclass as the examples show.
Observers are abstract so any Ruby object can be an observer if it has the correctly named - publicly accessible callback methods.

# encoding: UTF-8

module RvAmerongen
  module TemplateSetManager

    extend self

    NEW_FROM_TEMPLATE ||= "New ..."

    @@menu_loaded = false unless defined?(@@menu_loaded)
    @@manager_open = false unless defined?(@@manager_open)
    @@manager_menu ||= MF_ENABLED

    #{# AppObserver callbacks
    #
      def expectsStartupModelNotifications
        return true
      end

      def onNewModel(model)
        build_menu_item()
      end

      def onOpenModel(model)
        build_menu_item()
      end
    #
    #}#

    def build_menu_item
      unless @@menu_loaded
        menu = UI.menu("File")
        mItem = menu.add_item(NEW_FROM_TEMPLATE,1) { open_manager() }
        menu.set_validation_proc(mItem) { @@manager_menu }
        # Don't load the menu item again ...
        @@menu_loaded = true
        # We are now done with the AppObserver ...
        Sketchup.remove_observer(self)
      end
    end

    def get_templates
      # build list of templates
    end

    def open_manager
      @@manager_menu = MF_GRAYED
      # create the WebDialog here...
      @@manager_open = true
    end

    def on_close_manager
      @@manager_open = false
      @@manager_menu = MF_ENABLED
    end

    unless @@menu_loaded
      # Always enable menu item, How ???
      # By using an AppObserver object, this module will do.
      Sketchup.add_observer(self) # (self is this module)
    end

  end
end

ADD: I discourage becoming hooked on any of the global methods in the "sketchup.rb" file.
Most are slowly being deprecated anyway. You might just as well use your own internal functions.
This is why I use and promote a internal reference to hold whether menu commands have been loaded, etc.

1 Like

Yeah, it’s a Mac thing, part of its app-centric design. Since OS X is willing to keep an app alive when the app has no document open, the system disables document-targeted menu items unless there is a document open. In SketchUp the only ones that are active are on the SketchUp menu (e.g. Preferences) and the ones on the File menu that will open a new or existing file. I don’t know whether an app can choose this behavior or if it is mandatory, but for the purpose here that’s academic because the SketchUp app would have to be programmed to provide it; a Ruby extension has no control.

But also, wouldn’t your extension have to somehow insert itself into the file opening process before SketchUp creates a model? On SketchUp Mac I don’t think this is currently possible because SketchUp opens the first blank model window before it loads Ruby extensions. Once upon a time SketchUp did it in the opposite order, loading extensions before opening the first model window. But this caused issues with initializing many extensions (for example anything that tries to access Sketchup.active_model for any reason), so it was reversed.

Purely as a matter of information, the behavior of staying alive when no document is open is voluntary, not mandatory. There is a simple delegation method that, if implemented, can tell OS X that the app wants to quit when its last document is closed. But there is a tradition of not implementing this method.

1 Like

Haha, Sorry but that makes no sense. So a user that makes every day or week a different kind of project and need a different template to start from but leave the check box marked are no Pro’s??

I agree that there should be a second New… must be, but if they want only one ‘new’ then they should change that. There are other options to create to lock users from unwanted behaviour, but to use a kind of lock for ‘some’ companies against the many Single users? Not very client friendly.
About requests. I understand that they cleaning up some mess from the early years, but there are enough one or two day jobs/bug to solve, but not seen or having any update since nov last year??? Like your request(s), some should be done in no time.

Its logical that items are disabled/greyed out when there nothing to do for the menu item command.
Ha funny, at the Mac you can open or new with the alt key to get a second tab with a second model, or thirth.

I will try your sample code, thank you for that.

1 Like

… and was why the expectsStartupModelNotifications AppObsever callback was created, to fix this loading issue.

I put this into the example above. Did either of you try it on the Mac ?

This is not what I meant. I meant that the majority start the same kind of project and use the same template the majority of the time.

I also …

(shrug) I quit wondering after 10 years.

1 Like

So there is some property that the application has to set to make certain menu items enabled when there is a blank workspace.

Hmm. But all is dandy if there is a model open, such as when SketchUp is started by clicking a SKP file ?

I did notice that, I guess that the original developers did drove them selfs in a kind of deadlock; continue with blisters and bandage or rewrite a massive piece of code. Happens often, also with Lotus Notes and Formula, they also did have to rewrite that. Maybe SU has to rewrite the events for the model engine.

Anyway, I did try this to get your idea working, but it crashes.

I did put some messageboxes in there to look at the call order. I notice that when I wait to dismiss the messagebox with “build_menu_item - menu not loaded yet exit” it crashes directly after, but if I am quick I get also the to see the " build_menu_item - exit" message. But then it crashed direclty after that. My guess is that it happens because of removing the observer. If I remove that line, then it so far works, but if that is the purpose…
( BTW, is there a kind of keyword like LINE or FILE but for a def or module to shoe in what for def the code is executed? )

module RvAmerongen
  module TemplateSetManager

    extend self

    NEW_FROM_TEMPLATE ||= "New ..."

    @@menu_loaded = false unless defined?(@@menu_loaded)
    @@manager_open = false unless defined?(@@manager_open)
    @@manager_menu ||= MF_ENABLED

    #{# AppObserver callbacks
    #
      def expectsStartupModelNotifications
      UI.messagebox(__FILE__ + " expectsStartupModelNotifications")
        return true
      end

      def onNewModel(model)
      UI.messagebox(__FILE__ + " onNewModel")
        build_menu_item()
      end

      def onOpenModel(model)
      UI.messagebox(__FILE__ + " onOpenModel")
        build_menu_item()
      end
    #
    #}#

    def build_menu_item
    UI.messagebox(__FILE__ + " build_menu_item")
      unless @@menu_loaded
      	UI.messagebox(__FILE__ + " build_menu_item - menu not loaded yet")
        menu = UI.menu("File")
        mItem = menu.add_item(NEW_FROM_TEMPLATE,1) { open_manager() }
        menu.set_validation_proc(mItem) { @@manager_menu }
        # Don't load the menu item again ...
        @@menu_loaded = true
        # We are now done with the AppObserver ...
        Sketchup.remove_observer(self)
        UI.messagebox(__FILE__ + "  build_menu_item - menu not loaded yet exit")
      end  #### IT CRASHES AROUND HERE
      UI.messagebox(__FILE__ + " build_menu_item - exit")
    end

    def get_templates
      # build list of templates
      # Get them ...
      UI.messagebox(__FILE__ + " get_templates")
				tdir = Sketchup.get_resource_path("Templates")
				file_list = Dir.chdir(tdir) { Dir["*.skp"] }

				# List them ...
				UI.messagebox(file_list.join("\n"), MB_MULTILINE, "Templates")

				# Current one ( full path )...
				previous = File.basename(Sketchup.template)

				# Pick one ...
				result = UI.inputbox(
  					['Choose template file '],
  					[ File.basename(previous) ],
  					[file_list.join('|')],
  					'Pick one ...'
				)
    end

    def open_manager
      @@manager_menu = MF_GRAYED
      UI.messagebox(__FILE__ + " open_manager")
      # create the WebDialog here...
      get_templates()
      @@manager_open = true
    end

    def on_close_manager
    UI.messagebox(__FILE__ + " on_close_manager")
      @@manager_open = false
      @@manager_menu = MF_ENABLED
    end

    unless @@menu_loaded
    UI.messagebox(__FILE__ + " menu_loaded not yet")
      # Always enable menu item, How ???
      # By using an AppObserver object, this module will do.
      Sketchup.add_observer(self) # (self is this module)
    end

  end
end

Yes, it is __FILE__ and __LINE__.

And from the Kernel module, the global method __method__.
You should also understand caller, and caller_locations and the Thread::Backtrace::Location class.

Do not use modal messageboxes to debug code. Open the Console and use puts calls.

Try a timer then …

UI.start_timer(1.0,false) { Sketchup.remove_observer(self) }

… this would allow the observer callback to return before the observer itself is removed from the application’s observer queue.

About puts, I knew, but then the only way I (know) can use the console is to disable MyPlugin open the console and then enable MyPlugin, but then the load order with other plugin’s are different. So the ui.message is easy when directly from the start with the plugiin always enabled.

Also because of the pause, by not quickly dismissing the dialog, I notice the time needed by the observer.

Hmm, maybe there is SU.command to open the console. Bu that is for tomorrow.

The timer works, perfect thank you.

Good night

@eneroth3 has a auto console opener plugin somewhere.

Aha, this becomes bed reading :wink:

I found this from @DanRathbun (and others):

https://groups.google.com/forum/#!topic/sketchupruby/kplzdNOyclM

Yes, that is 8 years old, but it still works for all SketchUp versions …

Sketchup.send_action("showRubyPanel:")

… whereas …

SKETCHUP_CONSOLE.show

… will only work for SketchUp 2014 and later.

So you could use …

SKETCHUP_CONSOLE.show rescue Sketchup.send_action("showRubyPanel:")

… to cover all possibilities.

:wink:

1 Like

Great tip, merci beaucoup. Gives extra info.

Is there a serious book about the in’s and out’s of Skechtup and Layout ( with development in mind )? Not about ruby but specific SU. I did see happily that Layout can accept plugins, but very less information or samples?

Not “live” plugins yet. LayOut does not have a Ruby subprocess (yet.)

We can only read and write to .layout files from within SketchUp’s Ruby, … or from 3rd party C applications.

See the Books list and it’s “SketchUp Specific” section of my WikiLists thread …

… also see the official SketchUp book list …

I want to do the same for Layout. So far as I can see I can load the template names bij using a hardcoded path.

Anyway, when I do have a path to a LO template, it doesn’t load.
If I save a template.layout I can’t, read it won’t, load in Layout.

This is the simplest code and copied from the docs.

doc2 = Layout::Document.new("/Users/dev/Library/Application Support/SketchUp 2018/LayOut/Templates/A1 Landscape.layout")
# doesn't work, I do get a ref pointer in the console	    

tfile = "/Users/anubis/Desktop/Untitled.layout"

puts("#{__method__} - Layout start loading")
doc = Layout::Document.open(tfile) 
# nothing get opened. I do get a ref pointer in the console
     
definitions = doc.auto_text_definitions
definitions.each { |auto_text|
puts("tag : #{auto_text.name}")
puts("name : #{auto_text.tag}")

#definitions.remove(auto_text) unless auto_text.mandatory?
}
puts("#{__method__} - Layout loading done??")

What do I wrong? I can’t find a doc.show command.

BTW In the mean time I use

system( "open '/Users/anubis/Desktop/Untitled.layout'")

Since I don’t have your files, I can’t say why your attempts to open it in the API don’t work. They work for me with my files. Maybe the problem is with what you expect from the methods #new and #open? These create a Layout::Document object instance within the current SketchUp Ruby session and provide access to it for manipulation. It is somewhat like the external SketchUp C SDK except embedded in the SketchUp Ruby API. They do not launch LayOut or open the file in LayOut itself. There is not (yet) any API method to launch LayOut and tell it to open a Document.

Just as an aside.

The following method call works on Windows to get a working path to the user’s LayOut templates folder.
Does it also work on Mac ?

Sketchup.find_support_file "../LayOut/Templates"
#=> C:/Users/Dan/AppData/Roaming/SketchUp/SketchUp 2016/SketchUp/../LayOut/Templates

This alos gives a working path to a Program Data distro templates folder …

Sketchup.find_support_file "../LayOut/templates/Paper"

Does it also work on Mac ?


doc2 = Layout::Document.new(
"/Users/dev/Library/Application Support/SketchUp 2018/LayOut/Templates/A1 Landscape.layout"
)

I don’t have a template named "A1 Landscape.layout", … is this a custom template of yours ?


(Please use ```ruby tagline to start your code blocks.)

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.