Overlay – Do Something when Definition / Instance Is Closed

In my custom select tool the method that gets the tag name and draws it is called whenever I enter or close a group/component - otherwise I have to move the mouse a little for onMouseMove to call this method.

I have been able to replicate the behaviour of this custom select tool with the native select tool and an Overlay except the getting of and drawing the tag name when opening and closing a group/component because only onMouseMove is available.

Generally, I’ve looked at some Observers and the ModelObserver / onActivePathChange fires whenever a group/component is opened or closed but how to call the methods in the Overlay class that get the tag name and draw it ?

I could of course have a separate extension and duplicate the methods in the ModelObserver…?

I’ve gone down a number of routes, including looking into Dan’s Author_MultiClassPlugin example but I’m stumped because of my lack on knowledge !

Any pointers or wise words would be gratefully received…

The answer is likely to be that you use an observer similar to any other extension that you might have that watches the model for edit path changes.

The slight difference with Overlays is that your model observer should honor the toggle state of your extension’s overlay(s). To do this, when your extension instantiates the overlay for a model, pass a reference of the model into the overlay’s constructor and keep an @model reference inside it.

  • Sidenote: I’ve asked for the API to set an internal model reference automatically when the overlay is attached to the model via OverlaysManager#add, but it did not make it into the release. (Hoping for in the future.)

Now, I want to remind (or inform) here that generally the API’s various #add_observer methods do not do any class checking and so do not enforce any particular coding pattern, ie subclassing versus singleton callbacks on a unique object, etc. All that is required is that any observer have publicly accessible observer callback methods.

This is why I most always use the extension submodule itself as the extension’s AppObserver since there is only 1 application and therefore I don’t need multiple observer instance objects.

Likewise, I will often use a hybrid ModelObserver that combines the callbacks for all the model’s collection observers as well. It makes it much easier. Ie, it is cumbersome to share data and state between separate model level observers.

The point I am getting at is that any object can serve as an observer without needing to be any particular subclass of any specific superclass. (This is because API observer superclasses are abstract and have no functionality, ie methods, to pass down to descendants.)

But the new Overlay class is different because it does have necessary methods and functionality so the subclass paradigm is enforced.

So how to have an overlay and an observer that play well together ?

There is only 1 choice since the overlay pattern must be a subclass of Sketchup::Overlay.

And that choice is to have your Overlay also be a ModelObserver that has an onActivePathChanged callback defined.

Then to honor the overlay toggle, you should attach the overly to the model as an observer in the overlay’s start callback and detach it from the model in the overlay’s stop callback.

# Overlay instantiated and added to OverlaysManager by AppObserver.
class ExampleOverlay < Sketchup::Overlay

  def initialize(model = Sketchup.active_model)
    @model = model
    description = "A short sentence describing the overlay."
    super('example_inc.my_overlay', 'Example Overlay', description: description)
  end

  def onActivePathChanged(model)
    draw(model.view)
  end

  #
  ### other overlay callbacks: draw(), onMouseMove(), etc ...
  #

  def start(*)
    @model.add_observer(self)
  end

  def stop(*)
    @model.remove_observer(self)
  end

end # overlay class
2 Likes

Thanks Dan !

I’ve managed to get it to work.

2 Likes