Dynamic tooltips and status text

I wanted to make some toolbar button tooltips and status text more dynamic:
In this simplified example I try to change the tooltip to reflect a resulting change in default angle, and the status text to report the results of the command:

module MainMod

	def self.buttoncmd
		#200 lines of code here not shown
		@@cmd.tooltip= "rotate 60 degrees"
		@@cmd.status_bar_text= "Rotated 3 objects by 60 degrees"
	tb = UI::Toolbar.new("testtooltip")
	@@cmd = UI::Command.new("testtooltip") { Sketchup::active_model.select_tool self.buttoncmd }
	@@cmd.tooltip= "rotate 45 degrees"
	@@cmd.status_bar_text= ""

If you run the above then click on the new button:

  1. the tooltip does not change.??
  2. the status text does change but does not behave in the same way that status text for native Sketchup commands does: For them the status text persists in the lower left of the screen as long as the button remains depressed. For this new button the status text appears only while the mouse hovers over the button, and switches to “ready” when mouse moves, even though the button remains depressed. This may be because this button doesn’t involve a tool class object.

Overall, the “status text” works more an extended tooltip rather than a place to report actual “status”.(?)

Any further advice or suggestions on these matters would be appreciated.

Perhaps try defining it as @cmd rather than @@cmd ?
I think a cmd’s tooltip is frozen at the cmd’s creation.
The cmd’s status_bar_text should be able to be be changed dynamically…
Test it…

@cmd gives same result as @@cmd

No it is not. I change both all the time.

@barry_milliken_droid I see several issues.

You use of select_tool is incorrect. It expects a Tool class instance, but Ruby methods return the result of the last expression. In your example it would return the text string you used for the setter call.

Normally an API method would do type-checking on the argument, but the Tool class is abstract, meaning is is just a subclass of Object, that has certain expected callback methods.

This means that internally the select_tool method should instead do “duck-typing” (test it, and if it talks like a duck then it can pass as a duck.) Since all tools should have an activate callback, this should be made a requirement, and then the object tested if it responds to one.

raise(TypeError,"not a Tool class instance") unless arg.nil? || arg.respond_to?(:activate)

More specifically, what is happening. Ruby evaluates the expression you are passing to the select_tool, before it calls the select_tool method.

So the buttoncmd method is getting called, but the call to select_tool is simply ignored (*) , so it serves no actually use in your example.

(*) It may actually setup a bad situation where an instance of String is pushed onto the model’s toolstack. This is a recipe for a BugSplat!

All use of class/module variables should declare (or define them,) near the top of the code.
If you reference them, or ruby encounters them before they have been initialized, a Runtime error occurs.

I do this even when I will later set them to a command or a string, etc.
It is a good place (at the top of the code) to put a comment explaining what the variables will be used for.

@@rotate_cmd = nil # UI::Command instance for rotator tool

FYI, definition of class/module variables cannot use the ||= syntax because that expands to

@@var = @@var || value

… which would be referencing @@var just to the right of the assignment operator, before it is initailized.

BTW,… did we just abandon the previous topic ?
Editing toolbar tooltips on the fly

1 Like

The API documentation and examples of UI::Command.new are so weak that I never grasped that a toolbar tool could call a method that wasn’t a “tool class” tool directly. (Tool is an ambiguous term.)
But now I’m back to square one. If I use:
@cmd = UI::Command.new(“testtooltip”) { self.buttoncmd }
and try again, it works the same: only status text changes but not tooltip (except that the button does not remain depressed).
Are you saying that tooltips can only be changed within a tool class tool?

(Yes I forgot we already had a similar topic)

No. Your code needs to change the tooltips WHEN the time is right.
When the user clicks the button, the proc is evaluated.

Think of buttomcmd method as a toggling method.

It would need to invert (boolean-wise) the check/pressed state of the variable that is evaluated in the command’s validation proc, (I usually use module vars that have “_check_state” suffix on their names.) and a variable to hold the toggle boolean value.

@@option_setting = true
@@option_setting_check_state = MF_CHECKED

COMMANDS[:option_setting].set_validation_proc {
def option_toggle()
  @@option_setting = !@@option_setting
  if @@option_setting
    @@option_setting_check_state = MF_CHECKED
    COMMANDS[:option_setting].tooltip= "Click to toggle Option off"
    @@option_setting_check_state = MF_UNCHECKED
    COMMANDS[:option_setting].tooltip= "Click to toggle Option on"
  opts = Sketchup.active_model.options['SomeOptionsProvider']
  opts['SomeOptionEnabled']= @@option_setting

That’s way over my head. I’m not toggling between 2 possible tooltips for the given command.
Here’s my example again showing that the tooltip is dynamic. Maybe you can show me how what you are recommending can be integrated with this:

module MainMod

	def self.buttoncmd
		#200 lines of code here not shown
		newdefangle = 66 # resulting from above code
		@cmd.tooltip= "rotate " + newdefangle.to_s + " degrees"
		@cmd.tooltip= "rotate 60 degrees"
		@cmd.status_bar_text= "Rotated 3 objects 60 degrees"
		puts "rotate 60 degrees"
	tb = UI::Toolbar.new("testtooltip")
	@cmd = UI::Command.new("testtooltip") { self.buttoncmd }
	startdefangle = 45
	@cmd.tooltip= "rotate " + startdefangle.to_s + " degrees"
	@cmd.status_bar_text= "status 45"

Sorry, I must modify what I said. I USED TO change them all the time.

The tooltips used to be plain-Jane popup tip strings, up through SketchUp 8, and could be dynamically changed.

THEN, with the release of SketchUp 2013, they overhauled the toolbar “look and feel”, and started using an expanded popup tooltip window that uses the tooltip text as a bold title, beneath it an underline, and then the status text as a description.
The tooltip text became static, (and there is a bug in 2013 where mouse-over Ruby buttons do not display status text in the statusbar while other tools are active.)

But I will wish and request that they be made dynamic again, because I have alot of code that changes the tooltip. If they won’t change this, I’ll have to modify alot of code to use the “title/description” protocol instead.

ADD: These changes were not accompanied with updates to the API docs.