Close Component Option & Component Attribute windows using ruby script

Apologies, I am not a programmer but wondered if someone knew a way to close the Component Option and Component Attribute windows using a ruby script. It will be added to another piece of script where the resulting function falls over with these windows open. It would prevent this happening in the case where the windows are left open accidentally.

Many thanks

This is not possible. But you can use the SketchUp Ruby API to open the components inspector and the preferences window (which I think you meant by ā€œoptionsā€). But they neither toggle, nor can you hide them programmatically.

UI.show_inspector('Components')

UI.show_preferences

This sounds rather the other piece of script tries to solve a problem the wrong (unsafe) way, or it tries to achieve something that is not possible to do.

Why not explain what you want to achieve on a higher abstract level to get several suggested solutions, than asking for implementation steps of your specific approach?

thanks for the reply. I mean the ā€˜Component Optionā€™ and ā€˜Component Attributeā€™ windows. Apologies for the confusion. Is this also the case for these windows?

No, they are not part of the API.

In general, you cannot easily interact with or use/modify other tools/windows if they are not your own. The API is more focussed on automating geometry creation or building new tools, than a macro language for automating the user interface.

Got you. Many thanks

All true, ā€¦ however there are some public instance methods can can be used with disclaimer.

DISCLAIMER: Use at own risk. The Dynamic Components extension is a Trimble internal extension (that is almost part of the core.) Itā€™s internal functionality and method names could change at any time without warning. This could cause your code ā€œin the wildā€ to fail, resulting in you needing to patch your code and re-release it.

module AuthorNamespace
  module ThisPlugin # defined only if DC extension is pre-loaded !

    extend self

    DC ||= $dc_observers.get_latest_class


    # Test whether the DC Component Attributes dialog is open.
    def component_attributes_dialog_open?
      DC.manager_dialog_is_visible()
    end

    # Test whether the DC Component Options dialog is open.
    def component_options_dialog_open?
      DC.configure_dialog_is_visible()
    end

    # Closes the DC Component Attributes dialog.
    def close_component_attributes_dialog
      DC.close_manager_dialog()
    end

    # Closes the DC Component Options dialog.
    def close_component_options_dialog
      DC.close_configure_dialog()
    end

    # Refreshes the DC Component Attributes dialog.
    def refresh_component_attributes_dialog
      DC.refresh_manager_dialog()
    end

    # Refreshes the DC Component Options dialog.
    def refresh_component_options_dialog
      DC.refresh_configure_dialog()
    end

    # Refreshes both dialogs, clearing the highlight if arg is true.
    def refresh_dynamic_component_dialogs(clear_highlight = false)
      DC.refresh_dialogs(clear_highlight)
    end

    # Opens the DC Component Attributes dialog.
    def show_component_attributes_dialog
      model  = Sketchup.active_model
      entity = model.selection.empty? ? model : model.selection[0]
      DC.show_manager_dialog(entity)
    end

    # Opens the DC Component Options dialog.
    def show_component_options_dialog
      DC.show_configure_dialog()
    end

    # --------------------

    # A block form method that closes the DC dialog windows,
    # evaluates the given block (passing in any arguments,)
    # then restores the dialogs if they were previously open.
    def do_with_DC_dialogs_closed(*args)
      return nil unless block_given?
      atts_was_open = component_attributes_dialog_open?
      opts_was_open = component_options_dialog_open?
      close_component_attributes_dialog() if atts_was_open
      close_component_options_dialog() if opts_was_open
      #
      result = yield *args # eval the block
      #
      show_component_attributes_dialog() if atts_was_open
      show_component_options_dialog() if opts_was_open
      return result
    end

  end if defined?($dc_observers)
end

Using local method wrappers would allow adapting the DC method calls if they change in future releases, using conditional statements that ā€œduck-typeā€ the DC observer instance using #respond_to?().

1 Like

Thanks DanRathbun. Iā€™m not writing a plugin, Iā€™m using a script that Eneroth3 posted to select all child instances. Itā€™s a work around for an issue discussed here:

Aerillus, I agree the script is not strictly safe but it solves my problem until Trimble rectify the issue. If the component option and component attribute windows are accidentally left open it throws up an alert ā€œMerging multiple items might be slow. Do you want to continueā€. This requires each instance to be either OKā€™d or cancelled, in the case of my drawings too many times. I tend to force quit at this point.

I was hoping to add a few lines to the script to force these windows shut if they are left open. Iā€™m not sure if this is possible with what you have very kindly posted DanRathbun but that is the aim.

Many thanks

Can I ask for the reason behind this request?

He explained above ā€¦

ā€¦ I wasnā€™t entirely aware that he was using someone elseā€™s code.

Well all of what I posted is needed. Itā€™s not ā€œa few linesā€.

BUT ā€¦ I also added near the end, a block form method that will do what you wish (provided all the dialog control methods are added.) The method name is ā€œdo_with_DC_dialogs_closedā€ and youā€™d use it to wrap calls to Enerothā€™s code.

    # within the plugin module ...
    do_with_DC_dialogs_closed {
      # call the code / methods to perform whilst DC dialogs are closed
    }

Of course, in the example, youā€™d either add the methods I defined into Enerothā€™s module, or rename the two nested moduleā€™s to something of your own unique names. Ie "AuthorNamespace" and "ThisPlugin" are just place holder names.


If adding all the wrapper methods are too confusing, you can ā€œliftā€ some code from the ā€œdo_with_DC_dialogs_closedā€ method, and replace calls to the ā€œwrapperā€ methods with direct calls to the DC object ā€¦

      DC ||= $dc_observers.get_latest_class

      atts_was_open = DC.manager_dialog_is_visible()
      opts_was_open = DC.configure_dialog_is_visible()
      DC.close_manager_dialog() if atts_was_open
      DC.close_configure_dialog() if opts_was_open
      #
      # call Eneroth's code HERE
      #
      model  = Sketchup.active_model
      entity = model.selection.empty? ? model : model.selection[0]
      DC.show_manager_dialog(entity) if atts_was_open
      DC.show_configure_dialog() if opts_was_open

ā€¦ but again, if these DC method names or functionality change, your ā€œworkaroundā€ will break and need to be updated.

ā€¦more to follow

Thank you @DanRathbun and @eneroth3. This combined code worked for me. I removed the re-opening as this was causing an issue for drawings with many components. Thanks again

DC ||= $dc_observers.get_latest_class

          atts_was_open = DC.manager_dialog_is_visible()
          opts_was_open = DC.configure_dialog_is_visible()
          DC.close_manager_dialog() if atts_was_open
          DC.close_configure_dialog() if opts_was_open
          
          def select_children(instance)
      children = instance.definition.entities.select { |e| e.respond_to?(:definition) }
      instance.model.selection.add(children)
      children.each { |c| select_children(c) }
    end

    select_children(Sketchup.active_model.selection.first)
          
          model  = Sketchup.active_model
          entity = model.selection.empty? ? model : model.selection[0]

Just in summary for anyone that might stumble across this. The code solves an issue where generate report does not see copied components. It allows you to select all child components within a component including copies. Selecting ā€˜current selectionā€™ in the report window will now include copied components.

This will be cleaner for you, and will not create constants nor methods globally ā€¦

module SBJ
  module SelectAllCopiedDynamicSubComponents

    extend self

    DC ||= $dc_observers.get_latest_class

    @@loaded = false unless defined?(@@loaded)

    def select_children(instance) # recursive method
      children = instance.definition.entities.select { |e| e.respond_to?(:definition) }
      instance.model.selection.add(children)
      children.each { |c| select_children(c) }
    end

    def select_DC_children_command(instance)
      return if instance.nil? # selection was empty
      atts_was_open = DC.manager_dialog_is_visible()
      opts_was_open = DC.configure_dialog_is_visible()
      DC.close_manager_dialog() if atts_was_open
      DC.close_configure_dialog() if opts_was_open
      select_children(instance)
    end

    if not @@loaded

      # Create a menu item so a shortcut keychord can be used ...
      topmenu = UI.menu('Plugins')
      item = topmenu.add_item("Select DC Children") {
        select_DC_children_command(Sketchup.active_model.selection.first)
      }
      topmenu.set_validation_proc(item) {
        Sketchup.active_model.selection.empty? ? MF_DISABLED : MF_ENABLED
      }

      @@loaded = true
    end

  end
end

Allows setting a shortcut keychord once the menu item is created.

Works perfectly, thank you!

1 Like