enthought / envisage

Envisage is a Python-based framework for building applications whose functionalities can be extended by adding "plug-ins".
http://docs.enthought.com/envisage/
Other
81 stars 26 forks source link

Experiment: Add a GUI-providing plugin #507

Closed corranwebster closed 1 year ago

corranwebster commented 1 year ago

This is a proof-of-concept which follows from some discussions about disentangling the GUI and SplashScreen objects: when using the SplashScreen support in a GUI object it requires very early creation of the GUI object, when it is really only needed at during the run method.

This shows how once this separation is done, the GUI object can be supplied by a plugin, and demonstrates use with the GUIApplication and TasksApplication classes and corresponding examples.

This attempts to be backwards compatible with existing code that (a) supplies a GUI directly and/or SplashScreen directly, or (b) relies on a default GUI and also doesn't know about GUIPlugin.

No tests right now, although existing tests might pass (it would be good if they did).

mdickinson commented 1 year ago

@corranwebster and I have discussed this a bit offline. I'm summarising some of that discussion here (so the below isn't for @corranwebster, but for other readers, and possibly also for future me and Corran).

mdickinson commented 1 year ago
  • This would look quite a lot like a subset of IGUI

In particular, this would allow initial "cheap" solutions where an existing GUI subclass could simply be declared as implementing IEventLoop, or where we have an event loop that just delegates to a GUI instance.

corranwebster commented 1 year ago

Thanks for the feedback.

I guess to keep consistency if we had IEventLoop as a new superinterface of IGUI it might look something like:

class IEventLoop(Interface):

    def create(self):
         # after calling create, can start and stop and register things to be invoked

    def destroy(self):
        # after calling destroy, can no longer start, stop or invoke

    def start_event_loop(self):
        ...

    def stop_event_loop(self):
        ...

    def invoke_later(self, callback, ...):
        ...

    def invoke_after(self, delay, callback, ...):
        ...

etc.

I think we either have to have invoke_after, a common timer API, or some sort of "stop event loop after x seconds" timeout function, because it's basic functionality needed for timeouts in tests (ie. you need to be able to do something like invoke_after(10, event_loop.stop_event_loop). It might not need to be part of the core API and instead in a test assistant, though.

mdickinson commented 1 year ago

it might look something like [...]

Yep, that's pretty much what I was imagining. Agreed about needing something that does timing.

There's also things like set_trait_later and set_trait_after; those could possibly be provided by some kind of MEventLoop mixin, since they're only really special cases of invoke_later and invoke_after.

mdickinson commented 1 year ago

@corranwebster I've recreated this PR as #562, since the style fixes in main made a direct merge of main into this branch very messy. If you prefer, I can do a force push on this branch instead. Preferences?

corranwebster commented 1 year ago

Let's close this one.