How to save positions of toolbars?

Is there some way how to save toolbars positions? That’s because I do viewport resize - during the action toolbars positions changes. So I would like to restore the toolbars when finished.

No. Not in SU8. They went to a different toolbar manager in later versions so that wouldn’t be a problem.

You can try Preferences>Reset Workspace but it doesn’t always work.

No doesn’t. But never mind.

It’s been a long time so my memory of that disaster is foggy but look for a Reset Toolbars button.

Instead of saving positions of toolbars I could turn them off so they will not be affected when I resize the SU window. And them turn them back. The only thing I will need to do it to save the statuses of toolbars

#hide ⇒ Object

The hide method is used to hide the toolbar on the user interface.

#show ⇒ Object

The show method is used to display the toolbar in the user interface.

#visible? ⇒ Object

The visible? method is used to find out if a toolbar is currently visible.

Examples:
toolbar.show
UI.messagebox “Toolbar Showing”
toolbar.hide
UI.messagebox “Toolbar Hidden”
visible = toolbar.visible?

Yet I need to find out how to load or access the toolbars array

There is no such collection, so make your own:

# Custom Ruby toolbars:
customToolbarSet = {}
ObjectSpace.each_object(UI::Toolbar) {|o|
  customToolbarSet[o]= o.visible?
  o.hide if o.visible? 
}

# Native application toolbars:
nativeToolbarSet = {}
UI.toolbar_names.each {|name|
  nativeToolbarSet[name]= UI.toolbar_visible?(name)
  UI.set_toolbar_visible(name, false) if UI.toolbar_visible?(name)
}

# Later on iterate the sets and reset visibility:
customToolbarSet.each {|tb,was_visible| tb.show if was_visible }
nativeToolbarSet.each {|name,was_visible|
  UI.set_toolbar_visible(name, true) if was_visible
}

You may wish to reshow them in reverse order.

1 Like

Thank you very much for this code! It help a lot. This adds a lot of space to SU when I hide the toolbars. Simple tool. I just edited the code like this

# Save toolbars:
ObjectSpace.each_object(UI::Toolbar) {|o| @customToolbarSet[o]= o.visible? }
UI.toolbar_names.each {|n| @nativeToolbarSet[n]= UI.toolbar_visible?(n) }

def self.hideToolbars
  ObjectSpace.each_object(UI::Toolbar) { |o| o.hide if o.visible? }
  UI.toolbar_names.each {|n| UI.set_toolbar_visible(n, false) if UI.toolbar_visible?(n) }
end;
# Reset visibility of toolbars
def self.unhideToolbars  
  @customToolbarSet.each {|tb,was_visible| tb.show if was_visible }
  @nativeToolbarSet.each {|name,was_visible| UI.set_toolbar_visible(name, true) if was_visible }
end;

Yet I think it would be good to create alias for the function unhideToolbars, as showToolbars. How do you create alias, not coping the code?

One more idea - is there some plugin to do this thing but save the statuses to file? In case of the closing of SU the toolbar list is in the file, so on the start it could reload. Also from menu Plugins it would be possible to show/hide all toolbars. It was just idea, that there already could be such plugin.

@DanRathbun

For some reason when I check the statuses, Selection toys are not present in the list of custom toolbars. Why? They are turned on.

ObjectSpace.each_object(UI::Toolbar) { |o| puts o.name; puts o.visible?;   }
BZ__Toolbar
false
Construction Line Tool
true
Perpendicular Face Tools
false
Projections
false
LSS Toolbar
false
Round Corner
false
Fredo6_JointPushPull
false
Fredo6_Animator
false
Edge Tools˛
false
TIG-TextureTools
false
Soap Bubble
false
QuadFace Tools
false
ImageAnimator
false
Pen Tools +
false
Solar North
false
Shadow Strings Fix
false
Sandbox
false
Dynamic Components
false
TGI3D
false
19

any that aren’t showing are possibly sub-classing UI::Toolbar

if the code isn’t scrambled you can see how those toolbars are constructed…

for example @thomthom may use TT::Toolbar in his tools…

BTW:

being ruby, there is of course a completely different way of extracting and cropping your images using a WebDialog that covers the main window while it runs…

when making toolbar icons in the past, I would create the square outline model, then

zoom_extents and zoom 1.045 to fill the viewport height

create a temp image

create a WebDialog using the tmp image height to set it’s height and width

use the tmp image as the html’s content entered in the window

then save the that as an image…

I never used jpeg as it will loose quality each step…

john

I have a personal extension to select, save, and load Toolbar “Sets”. I’ve never published it but can send you the code if interested.

Ok, please send. I can compare what is wrong with my code. When I tested it, all toolbars has been turned on whilst some natural parts of SU was not visible.

In TT plugins there is no TT::Toolbar;but TT is defined. Where should I look?

look in the code where it makes the menu and toolbar items, it may point to code in TT_Lib…

might be…

TT::GUI::Toolbar

john

TT_lib/toolbars.rb

You repeatedly ask questions on how to do basic Ruby programming.
It would be better if you just downloaded any of the numerous free Ruby books and read them.

Go to the Books section of the Learning Resources thread. (If I were to be answering such basic questions, then I would have wasted my time creating the Learning Resources list! Please use it!)

1 Like

@barracuda After taking a look, I’m not doing anything in my code that hasn’t already been shown in this thread so there’s little point in posting it.

Not sub-classing, but the Toolbars may be being created inside one of Thom’s namespaces and so it doesn’t appear at top-level in ObjectSpace. To get all the Toolbars, you would need to search for UI::Toolbar in all the namespaces returned by ObjectSpace recursively.

When I type to console:
UI.toolbar(“Selection Toys”)
#UI::Toolbar:0xdce42b4
But when I type
ObjectSpace.each_object(UI::Toolbar) {|o| @customToolbarSet[o]= o.visible? }
puts @customToolbarSet
So the “Selection Toys” are not on the list.
This is correct:
ObjectSpace.each_object(UI::Toolbar) {|o| @customToolbarSet[o.name]= o.visible? }
So the problem found and solved. Now it should works safely, gonna test

Edit:
One more problem found. Whilst hiding of the toolbars works fine, showing makes problems. I can Display the Selection Toys only.

Error: #NoMethodError: undefined method `show' for "Round Corner":String
/Plugins/shadows.rb:166:in `showToolbars'
/Plugins/shadows.rb:166:in `each'
/Plugins/shadows.rb:166:in `showToolbars'
/Plugins/shadows.rb:254

My code:

@customToolbarSet = {}
@nativeToolbarSet = {}
@toolbarsHidden = false;
# Save toolbars:
ObjectSpace.each_object(UI::Toolbar) {|o| @customToolbarSet[o.name]= o.visible? }
UI.toolbar_names.each {|n| @nativeToolbarSet[n]= UI.toolbar_visible?(n) }

...
def self.hideToolbars
  ObjectSpace.each_object(UI::Toolbar) { |o| o.hide if o.visible? }
  UI.toolbar_names.each {|n| UI.set_toolbar_visible(n, false) if UI.toolbar_visible?(n) }
  @toolbarsHidden = true;
end;
# Reset visibility of toolbars
def self.showToolbars  
  @customToolbarSet.each {|tb,was_visible| tb.show if was_visible }
  @nativeToolbarSet.each {|name,was_visible| UI.set_toolbar_visible(name, true) if was_visible }
  @toolbarsHidden = false;
end;

...

	UI.menu("Plugins").add_item("Show/Hide Toolbars") { 
    if @toolbarsHidden == true
      ShadowsModifier.showToolbars;
    else
      ShadowsModifier.hideToolbars;
    end;
    }

Ruby does not use semi-colons at the end of statements. Using them just makes more work, and your code is less “readable”.


Because you did not use the exact code I gave you above.

My example uses the custom toolbar object reference as the Hash key. Not the name of the custom toolbar ! You must do this in order to then call the show method when re-showing the toolbars.

@customToolbarSet.each {|tb,was_visible| tb.show if was_visible }

ALSO, you should have a call to a method that saves the toolbar visibility states, at the beginning of your hideToolbars() method.


Danger Will Robinson ! :robot:

The API docs say: UI::toolbar()

The toolbar method is used to get a Ruby toolbar by name.
If the toolbar doesn’t exist a new one will be created.

So, you cannot use that method to test for an existing custom Ruby toolbar !

IF you correctly use the toolbar object reference as the hash key, then:

found = @customToolbarSet.find {|tb| tb.name == "Selection Toys" }
if found
  # It exists! Do something ... 
  # found will be an array of [ toolbar_reference, was_visible ]
end

Here is an example module:

module SomeAuthor::TB

  @customToolbarSet ||= {}
  @nativeToolbarSet ||= {}
  @toolbarsHidden   ||= false

  # Save toolbars:
  def self.saveToolbars
    ObjectSpace.each_object(UI::Toolbar) {|o|
      @customToolbarSet[o]= o.visible?
    }
    puts @customToolbarSet.keys.map{|o|o.name}.sort.inspect
    UI.toolbar_names.each {|n|
      @nativeToolbarSet[n]= UI.toolbar_visible?(n)
    }
  end

  def self.hideToolbars
    self.saveToolbars
    ObjectSpace.each_object(UI::Toolbar) {|o| o.hide if o.visible? }
    UI.toolbar_names.each {|n|
      UI.set_toolbar_visible(n, false) if UI.toolbar_visible?(n)
    }
    @toolbarsHidden = true
  end

  # Reset visibility of toolbars
  def self.showToolbars  
    @customToolbarSet.each {|tb,was_visible| tb.show if was_visible }
    @nativeToolbarSet.each {|name,was_visible|
      UI.set_toolbar_visible(name, true) if was_visible 
    }
    @toolbarsHidden = false
  end
  
  def self.get_custom_toolbar(name)
    found = @customToolbarSet.find {|tb,was_visible|
      # Boolean hash values "was_visible" are not used in search.
      # We use the hash key which are the toolbar obejct references.
      # As soon as the block returns a TRUE result, the "find"
      # method breaks and returns [key,value] or nil if no match.
      tb.name == name
    }
    puts "TB::get_custom_toolbar(\"#{name}\") = #{found.inspect}"
    found ? found : nil
  end

  def self.toolbar_exist?(name)
    found = self.get_custom_toolbar(name)
    # If found, it will be an array: [ toolbar_oject, was_visible ]
    # otherwise it will be nil if the toolbar was not found.
    puts "TB::toolbar_exist?(\"#{name}\") = #{found.nil? ? 'false' : 'true'}"
    found.nil? ? false : true
  end

end

For example with "Selection Toys not loaded:

TB.toolbar_exist?("Selection Toys")
#=> TB::get_custom_toolbar("Selection Toys") = nil
#=> TB::toolbar_exist?("Selection Toys") = false

TB.toolbar_exist?("Dynamic Components")
#=> TB::get_custom_toolbar("Dynamic Components") = [#<UI::Toolbar:0x0000000b6a4310>, true]
#=> TB::toolbar_exist?("Dynamic Components") = true

In fact I used your code originally, I have confirmed that it worked, but not for Selection toys. When I have renamed it to access o.name so all toolbars were successfully hidden. When I restore the changes so again the Selection toys toolbar stays visible. It would be even “solution” to keep the o.name and to restore the toolbars from View/Toolbars/Restore Toolbars Positions. That would work perfectly. I am using the restoring function when the toolbars are not visible, instead of turning on every toolbar manually.

Yet to use the hash I have never seen; it’s just crazy ruby, I consider this a bit a lot strange.

I give up, do what you will. :frowning2:

And I just confirmed it does work. But after I had disabled Selection Toys, and restarted SketchUp with it off, and then reenabled Selection Toys.

There is an intermittent bug in SU8, that does not seem to happen in SU2013 and later.

It is not because the hash key is (or is not) string, or the object reference, or because the object class is something other than UI::Toolbar ( … because it is a UI::Toolbar, I have checked the code, and Thomas is not using a subclass nor a wrapper class. This would not matter anyway as an instance of UI::Toolbar must be created for SketchUp to display the toolbar.)


Nor is this true at all. ObjectSpace.each_object() does not work this way, Jim.
It will find all instances, of the class passed and subclasses, that exist period, in all scopes at the time of call. It is a process-wide module function and there is no way to call it “recursively” or within namespaces (modules, etc.)

Looking for instances of a deep nested class definition, from the toplevel works quite well:

ObjectSpace.each_object(TT::Plugins::SelectionToys::UI_Manager) {|o| puts o }
#<TT::Plugins::SelectionToys::UI_Manager:0xa3667d0>
#<TT::Plugins::SelectionToys::UI_Manager:0xa402f68>
2

Attempting to find nested UI::Toolbar in a submodule fails:

ObjectSpace.each_object(TT::Plugins::SelectionToys::UI::Toolbar) {|o| puts o }
#Error: #<NameError: (eval):34: uninitialized constant TT::Plugins::SelectionToys::UI>
#(eval):34

Again, there is an intermittent bug in SU8 that causes some Ruby toolbars not to be enumerated by Ruby. Switching the extension off via Window > Preferences > Extensions, restarting SketchUp, then switching the extension back on seems to solve the issue (at least temporarily.)