Detect scene activation

Hi all,

Is there a way to detect when a scene has been activated? I’m working on some improved Advanced Camera Tools and need to know when the user clicks a scene tab (or use the scene manager to activate a scene).

I can’t find any observer firing on scene activation. I guess I could listen to view changes and compare the active scene with that of the last frame, but if there is a more direct way to detect scene activation that’d be better. If possible I’d also like to know when the already active scene is activated anew, and this workaround wouldn’t handle that.

Thanks

Observers are at best able to detect modifications, but less for activation, or even selection in the GUI (note that you can select something without activating it).

I had the same problem with Attribute Inspector and found a work-around for styles. Pages is also an Entity, but I doubt the EntityObserver#onChangeEntity triggers on change of the selected (active) page. I could imagine you could use any observer that is triggered when the view is refreshed, and then check the status of the view.model.pages.selected_page.

Could you not just “look up” (if nobody watches you) how advanced camera tools does it?

There is a call back that you can set

observer_frame = Sketchup::Pages.add_frame_change_observer()

The callback method to be implemented in your class is
frameChange(from_scene, to_scene, percent_done)

PS: what is missing in the API is the event when you Update a scene. No observer, no callback!

1 Like

Yes I had implemented an abstract class page in the docs for this several years ago …


API FR filed (Jan 2018 Issue #26): … add any thoughts to issue please.

https://github.com/SketchUp/api-issue-tracker/issues/26

1 Like

the original camera.rb carries this copyright message…


# This software is provided as an example of using the Ruby interface
# to SketchUp.

# Permission to use, copy, modify, and distribute this software for 
# any purpose and without fee is hereby granted, provided that the above
# copyright notice appear in all copies.

# THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

you can grab it from the SU v5 page on the wayback machine or PM me for a copy…

john

1 Like

I must have had some connectivity issues. I found the FrameChangeObserver minutes after posting, realized I could get what I wanted from it and tried to post again, but today my new post was just a draft.

Thanks anyway for the help! I’ll make sure to look into the old Advanced Camera Tools source too.

1 Like

Class: Sketchup::PagesObserver

The #onContentsModified method is invoked whenever the pages change.

Oh wait… maybe I read that wrong… that might just trigger when a page property changes… hm… are we really missing this event?

What does “this” refer to ?

It seems so :open_mouth: . Can be worked around though with a FrameChangeObserver but I didn’t find it first as the name didn’t correspond to what I was locking for.

SceneTransitionObserver might have been a better name.

Perhaps a note on the Sketchup::Pages and Sketchup::Page class docs mentioning the FrameChangeObserver ?
(EDIT - Actually is it already mentioned on the Sketchup::Pages class doc for the observer class methods.)


Also be aware that the Sketchup::ViewObserver#onViewChanged() callback fires on each frame of the transistion as well as the FrameChangeObserver#frameChange() callback. (ADD - However it also fires on any camera change caused by manual orbit, pan, etc.)

class MyViewObserver < Sketchup::ViewObserver

  def initialize()
    super
    @frame = 0
  end

  def onViewChanged(view)
    @frame += 1
    puts "onViewChanged: frame #{@frame}"
  end
end

# Attach the observer.
Sketchup.active_model.active_view.add_observer(MyViewObserver.new)

This one is a strange one - because we don’t have a superclass for it. But neither does the “Tool” interface. I think it would make sense to add a separate page for this interface to make it discoverable.

We also should have an observer to detect active scene changes.

1 Like

I did some digging in the source and found that there is actually events being fired. But there is a lot of noise there that makes it less than ideal for an API.

Sketchup::PagesObserver#onContentsModified is triggered when:

  • kPageMoved
  • kSelectedPageChanged
  • kNameChanged
  • kRemoveAll
  • kPageActivate

“changed” vs “active” you ask? Good question - that’s some internal implementation noise leaking through.

When the active page is changed you get two calls to onContentsModified. The first one is before the Sketchup::Pages#selected_page getter will reflect the new page. The second once it’s all set.

For instance, given three scenes, toggle from Scene 1 to Scene 2 you get this result:

class MyPagesObserver < Sketchup::PagesObserver
  def onContentsModified(pages)
    puts "onContentsModified: #{pages.selected_page.name}"
  end
end

# Attach the observer.
Sketchup.active_model.pages.add_observer(MyPagesObserver.new)

2019-03-29_12h21_01

So there is an event - but you can’t easily tell exactly what changed. But there’ll be a lot less noise than using the view or framechange observers.

2 Likes

You must have missed my post above where I said that I already authored an abstract observer class page in the API docs … years ago. (You and Jim Foltz inspected it at that time and you pulled it into the stubs repo.)

It is there in the API docs, right now …

… you can close your issue in the tracker.

I was mentioning that perhaps a cross-reference link might be needed to point readers TO the existing abstract class page. But then I edited my post to acknowledge that there is already a See Also link as well as a parameter link in the Sketchup::Pages::add_frame_change_observer class method documentation … which points at the Sketchup::FrameChangeObserver class doc page.

With this “hidden” information a coder can cache the active page object reference in a model specific instance variable and compare each time the Sketchup::PagesObserver#onContentsModified callback fires.

If @selected_page != pages.selected_page then a page transition has completed.
The code does it’s thing and then sets @selected_page = pages.selected_page.

No way to detect currently that this has happened without using an abstract Sketchup::FrameChangeObserver object. (An even then, if scene transitions are switched off a frame change observer may only fire after complettion.)

I agree with your issue (Add observer event to detect active scene change · Issue #237 · SketchUp/api-issue-tracker · GitHub) to add an observer event (with a both a start and complete callback.)

Having 2 separate callbacks (then the old bulk handler) I think’d work best.


Ie … this situation is a good example showing how bulk callbacks are often not in the API’s best interest.

Adding events that fire a bulk callback, change that bulk callback’s implementation and effects all extensions using it. The parameters of the old bulk callback may not have envisioned the workflow of the new event when the bulk handling callback was first implemented. (This might be called “shoehorning”.)