Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Switch the cursor to a busy cursor while redrawing. #6603

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 29, 2017

Conversation

anntzer
Copy link
Contributor

@anntzer anntzer commented Jun 18, 2016

To test, plot e.g. plot(rand(100000)) and zoom in manually (the
redraw should take some time). The cursor should switch to a "busy"
cursor (e.g. spinwheel). The switch doesn't seem to happen under the
Tk and WX backends, probably due to some event loop intricacies I don't
understand.

@anntzer anntzer force-pushed the waitcursor-while-redrawing branch from 6c8450c to 1a816ae Compare June 18, 2016 08:44
@anntzer
Copy link
Contributor Author

anntzer commented Jun 18, 2016

On an vaguely related note, I noticed the methods Axes.{get,set}_cursor_props, which seem to have no effect and have never been used (according to git log -S). Would it be OK to just get rid of them or should we go through a deprecation cycle as usual?

@WeatherGod
Copy link
Member

... or we make it actually do something. It is fully functional and
documented... it's state just doesn't seem to get accessed anywhere else,
though.

On Sat, Jun 18, 2016 at 4:48 AM, Antony Lee [email protected]
wrote:

On an vaguely related note, I noticed the methods
Axes.{get,set}_cursor_props, which seem to have no effect and have never
been used (according to git log -S). Would it be OK to just get rid of
them or should we go through a deprecation cycle as usual?


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
#6603 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AARy-KQywk9bptlSbK-_WNfGswv8aOfBks5qM7DHgaJpZM4I45VE
.

@tacaswell tacaswell added this to the 2.0 (style change major release) milestone Jun 18, 2016
@tacaswell
Copy link
Member

I am curious of the history when those methods were added and why. There are a surprising number if bread crumb trails in the codebase.

@tacaswell
Copy link
Member

Also, this is a huge UX improvement this should be backported to 2.0

@anntzer
Copy link
Contributor Author

anntzer commented Jun 18, 2016

Perhaps you're better than me at git log -{G,S} but at least I didn't find anything :-( Just seems like a completely unused attribute.
Who are the Tk and WX specialists there? The feature doesn't work with these backends (nothing's broken but the cursor doesn't change) so it'd be nice but not obligatory to fix that first.

@QuLogic
Copy link
Member

QuLogic commented Jun 18, 2016

Are the Cairo backends also handled here?

@anntzer
Copy link
Contributor Author

anntzer commented Jun 18, 2016

Good catch. A quick look seems to indicate that the Cairo backend does not override draw; where should the cursor change go?

@tacaswell
Copy link
Member

Maybe on the on_draw_event in gtk3cairo and expose_event in gtk_cairo?

@anntzer
Copy link
Contributor Author

anntzer commented Jun 20, 2016

Done. The cursor switches to a spinwheel, but is not animated, for a reason I don't understand.

Side notes:

  • The GTK3Cairo backend prints the warning "(-c:14995): Gtk-WARNING **: Allocating size to GtkToolItem 0x5564c90a5490 without calling gtk_widget_get_preferred_width/height(). How does the code know the size to allocate?" when picking the zoom tool.
  • It would probably be worth upping the minimum PyGTK version requirement to something like 2.12 (2009) to get rid of conditional branches that support old APIs.

@tacaswell
Copy link
Member

@OceanWolf @fariza can you address the gtk questions?

try:
if toolbar:
toolbar.set_cursor(cursors.WAIT)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is going to fail with new tool manager, toolbar doesn't have a set_cursor method anymore.
I have to think in a clean way of doing it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a completely different note... you are doing this to the AGG backend, a non-interactive backend. How does this code interact with the combined backends like GtkAgg and such? Would this code get called twice?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I never got an answer about why this is being done for the AGG backend.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aye, but from what I gather set_cursor will move from the toolbar to the canvas.

I'm +1 on doing this now so that we get a clean PR, but @tacaswell disagrees.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@OceanWolf, was that a response to my question? I am not sure how your response applies, since the AGG backend has a canvas, too. Why is there any cursor-handling code for the agg backend?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, It applies only in the sense that the code here has already been slated for removal. Only a partial answer to your question.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, missed the comments.
The reason to put this here is the same reason why canvas.toolbar exists on all canvases (possibly None) rather than only on interactive ones: because there is no InteractiveCanvas class in the hierarchy :-) (Note that this is orthogonal with the toolmanager question)

anntzer added a commit to anntzer/matplotlib that referenced this pull request Jul 21, 2016
Apparently unused ever since they were added.  See original discussion
in matplotlib#6603.
anntzer added a commit to anntzer/matplotlib that referenced this pull request Jul 21, 2016
Apparently unused and with no effect ever since they were added.  See original
discussion in matplotlib#6603.
@tacaswell tacaswell modified the milestones: 2.0.1 (next bug fix release), 2.0 (style change major release) Sep 5, 2016
@anntzer
Copy link
Contributor Author

anntzer commented Jan 26, 2017

Right now it looks like Qt4Agg Qt5Agg GtkCairo and Gtk3Cairo all work (I don't see the warning mentioned in #6603 (comment) anymore). In theory Tk and WX "should" be supported too but don't actually work. Could we push this forward with just support for these backends?

@dstansby dstansby modified the milestones: 2.1 (next point release), 2.0.1 (next bug fix release) Feb 8, 2017
@QuLogic
Copy link
Member

QuLogic commented May 31, 2017

Ping @fariza @anntzer; what should we do about this? Seems useful...

@anntzer anntzer force-pushed the waitcursor-while-redrawing branch 2 times, most recently from f2f72f6 to 5d06137 Compare June 1, 2017 01:17
@anntzer
Copy link
Contributor Author

anntzer commented Jun 1, 2017

Rebased. Now works on py3: qt4 qt5 tk gtk3 and py2: wx gtk (haven't tested other combos). See the latest commit for the reason (we needed to trigger the event loop on some backends).

@tacaswell
Copy link
Member

@fariza What owns the cursor in the new tool model? It does make a certain amount of sense for the toolbar to do so (as it holds the other things that change the state of the cursor. The other logical option is for the manager to own it.

Not sure I like putting this all the way down in Agg, seems like it should be fully owned by the GUI layer.

A decorator like:

def wating_cursor(meth):
      @contextlib.contextmanager
      def spin_cursor(manager):
          manager and manager.set_cursor(cursor.WAIT)
          try:
              yield
         finally:
            manager and manager.set_cursor(cursor.POINTER)
   

     @functools.wraps(meth)
     def inner(self, *args, **kwargs):
        mager = getattr(self, 'manager', None)
        with spin_cursor(manager):
            return meth(self, *args, **kwarg)

would make this easy and safe to apply.

@fariza
Copy link
Member

fariza commented Jun 3, 2017

@anntzer is the problem of returning to previously selected cursor solved?

@tacaswell the cursors doesn't belong to the toolbar, right now there is a tool that sets the cursor when in axes backend_tools.SetCursorBase._set_cursor_cbk.

We can just trigger an event to inform the tool that we are waiting. But this seems a little bit overkill and maybe too much resources?

@anntzer
Copy link
Contributor Author

anntzer commented Jun 3, 2017

Now it is :) see latest commit

@anntzer
Copy link
Contributor Author

anntzer commented Jun 3, 2017

@tacaswell I'm not convinced that adding a contextmanager around each and every call to draw() from an interactive backend is the solution (e.g. people sometimes call figure.canvas.draw() themselves)... or I guess interactive backends could derive from a common InteractiveCanvas class (earlier than FigureCanvasAgg in the MRO) which defines draw() as

def draw(...):
    <sets cursor>
    super().draw(...)
    <unsets cursor>

but then you're actually relying on multiple inheritance to do your job correctly (which I am actually totally fine with).

@@ -538,7 +539,7 @@ def set_message(self, s):

def set_cursor(self, cursor):
self.canvas.get_property("window").set_cursor(cursord[cursor])
#self.canvas.set_cursor(cursord[cursor])
Gtk.main_iteration()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are you adding this cal to Gtk.main_iteration?

Copy link
Contributor Author

@anntzer anntzer Jun 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because otherwise the cursor is actually not set on the GUI (see docstring changed in CanvasBase.set_cursor). Basically, what happens is

Notification that a redraw is necessary.
Redraw starts and cursor is set.
[possibly long computation]
Return to GUI thread.

Note that the GUI event loop doesn't get to run between [cursor is set] and [possibly long computation], so depending on the details of the toolkit, the cursor change may not actually appear to the user before the end of the computation. Letting the GUI event loop run once allows it to change the cursor. (And upon testing, I see that Qt does not need this, probably because its version of setCursor triggers(?) the event loop.)

@fariza
Copy link
Member

fariza commented Jun 5, 2017

For the toolmanager, I think it can be done using the trigger method of the ToolSetCursor, we can use that method to override the active cursor... I will try to find some time this week to give it a try.

@fariza
Copy link
Member

fariza commented Jun 11, 2017

@tacaswell what would be the problem moving set_cursor from the toolbar to the firgurecanvas? it seems a more logical place for it to be, and more useful.

@anntzer
Copy link
Contributor Author

anntzer commented Jun 11, 2017

(fwiw I agree that it may make sense to allow ourselves to change the cursor even if there is no toolbar (ie in some embedding cases))

@tacaswell
Copy link
Member

The canvas class makes more sense than the manager class so that direct embeddings can take advantage of it, but we will have to be careful to not mess with anything end-user may already be doing with the cursor.

@anntzer
Copy link
Contributor Author

anntzer commented Jun 12, 2017 via email

@tacaswell
Copy link
Member

Fair enough.

@anntzer anntzer force-pushed the waitcursor-while-redrawing branch from 7ab48cd to 6c6cab4 Compare August 1, 2017 00:36
@anntzer
Copy link
Contributor Author

anntzer commented Aug 1, 2017

Rebased.

@fariza
Copy link
Member

fariza commented Aug 11, 2017

So we are not moving the set_cursor to the canvas? I think this is the right time and place to do it

@tacaswell
Copy link
Member

We can do that later, I think it is worth getting the busy-spinner in now.

@choldgraf
Copy link
Contributor

is this ready to go? looks like features are there...time to merge this 1-year-old PR? :-)

@anntzer
Copy link
Contributor Author

anntzer commented Aug 17, 2017

(I think this is good to go.)

To test, plot e.g. `plot(rand(100000))` and zoom in manually (the
redraw should take some time).  The cursor should switch to a "busy"
cursor (e.g. spinwheel).  The switch doesn't seem to happen under the
Tk and WX backends, probably due to some event loop intricacies I don't
understand.
The wait cursor is not animated, though.
@anntzer anntzer force-pushed the waitcursor-while-redrawing branch from 6c6cab4 to d1516e6 Compare August 23, 2017 16:27
@anntzer
Copy link
Contributor Author

anntzer commented Aug 23, 2017

rebased

@anntzer
Copy link
Contributor Author

anntzer commented Aug 29, 2017

Allowing myself to mark this as release critical as it's been around for very long, it's been approved, and @tacaswell says it's "a huge UX improvement" :-)

@anntzer anntzer added the Release critical For bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions. label Aug 29, 2017
Copy link
Contributor

@dopplershift dopplershift left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having the feature itself is a great improvement. Refactoring to put this in a more logical place, while nice, is not a reason to hold up this PR.

@dopplershift dopplershift merged commit fe0095e into matplotlib:master Aug 29, 2017
@anntzer anntzer deleted the waitcursor-while-redrawing branch August 29, 2017 17:05
@tacaswell
Copy link
Member

I am happy this went in 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Release critical For bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants