Dynamically update context_menu_handler

Is it possible to dynamically update an

UI.add_context_menu_handler

depending on the element selected? I wanted to change the name of submenu items with information of selection item. (for example it’s name)

perhaps something like this…

module Dezmo
module Dezmo_test
  extend self
  @@loaded = false unless defined?(@@loaded)
  
  def get_name()
    mod = Sketchup.active_model
    sel = mod.selection
    return unless (sel.single_object? && sel.first.respond_to?(:definition))
    sel.first.definition.name
  end

  def do_somthing()
    # do something
  end
  
  unless @@loaded
    UI.add_context_menu_handler do |context_menu|
      context_menu.add_item("Test.. name: #{get_name} "){
        do_somthing()
      } if get_name
    end
    @@loaded = true
  end
end
end

It works perfectly. If I want to stop the behaviour, what should I do?

Restart SU.

1 Like

Give us an idea on what condition you want to stop the “behavior” ?

My idea of stopping it is in case it consumes a lot of resources because it is always analyzing the selection.

Okay then this is actually easy.

You use an extension variable to decide whether or not to modify the context menu:

At the top of your extension submodule:

  @@feature = true unless defined?(@@feature)

At the bottom of your extension submodule, in the run once at startup block:

  unless @@loaded

    UI.add_context_menu_handler do |context_menu|
      #
      break unless @@feature
      #
      name = get_name()
      if name # nil otherwise
        context_item = "Test.. name: #{name} "
        context_menu.add_item(context_item) { do_somthing() }
      end
    end

    @@loaded = true
  end
  • The method name in the example is missing an “e” … ie … do_somthing()

You decide what the “feature” variable is named and whether it is initially true or false. The reference can be set false or true any number of times during a session. For example a submenu for the extension could have a menu item that allows the user to switch the feature “on” and “off” at will.

The @@feature object can be an instance variable, like @feature (because a module is an instance of class Module,) … or it could be a member of an options hash, like @options[:feature] or OPTIONS[:feature] depending upon how you control extension options. (I find the hash easiest because it is simple to save them out to JSON files and load them from JSON files.)

Again, the word “feature” in the above discussion and snippets is just a placeholder for the name you choose.

1 Like

FYI, it is notalways analyzing the selection” …

The block only executes when the context menu needs to be built after the mouse right-click (or hitting SHIFT+F10.)

1 Like

I thought, you want to stop the test code… but in this case Dan is right, but partly, because:

This will give an error:
Error: #<LocalJumpError: break from proc-closure>

So, perhaps this could be better:

module Dezmo
module Dezmo_test_a
  extend self
  @@loaded = false unless defined?(@@loaded)
  @@show_popup = false unless defined?(@@show_popup)
  
  def get_name()
    mod = Sketchup.active_model
    sel = mod.selection
    return unless (sel.single_object? && sel.first.respond_to?(:definition))
    sel.first.definition.name
  end

  def toggle_popup()
    @@show_popup = !@@show_popup
  end
  
  def do_something()
    # do something
  end
  
  unless @@loaded
    cmd = UI::Command.new("Toggle My 'Test...' Contex menu"){ toggle_popup() }
    cmd.set_validation_proc { 
      @@show_popup ? MF_CHECKED : MF_UNCHECKED 
    }
    UI.menu("PlugIns").add_item(cmd) 
    UI.add_context_menu_handler do |context_menu|
      if @@show_popup
        name = get_name()
        if name
          context_item = "Test.. name: #{name} "
          context_menu.add_item(context_item) { do_something() }
        end
      end
    end
    @@loaded = true
  end
end
end

…at least almost consistently :wink: (Corrected in my new snippet.)

1 Like

It runs like clockwork! Thanks @dezmo

1 Like

Sorry, did not test that. Yes, it can be replaced with an if statement.

1 Like