Bug 296945

Summary: Busy indicator for undetermined duration busy state
Product: [openSUSE] openSUSE 10.3 Reporter: Michael Meeks <mmeeks>
Component: InstallationAssignee: Stefan Hundhammer <shundhammer>
Status: RESOLVED FIXED QA Contact: Jiri Srain <jsrain>
Severity: Enhancement    
Priority: P5 - None CC: coolo, dmacvicar, forgotten_h13THG8RK1, francis, lslezak
Version: Alpha 7   
Target Milestone: ---   
Hardware: Other   
OS: Other   
Whiteboard:
Found By: --- Services Priority:
Business Priority: Blocker: ---
Marketing QA Status: --- IT Deployment: ---
Attachments: Screen Shot of the problem
Simple MNG animation example
Screenshot of prototype
Prototype patch #1 (to yast2-packager)
Icon used for the prototype ( must go in /usr/share/YaST2/theme/current/animations )
New patch #2, with timeout
New image, with only 3 loops (/usr/share/YaST2/theme/current/animations/ticks.mng)
opensuse 10.2 boot spinner. (with reflection)
10.3 plain spinner (no reflection).
generic spinner at 22x22px
generic spinner at 32x32px
generic spinner at 48x48px
suse styled animation posted above.
testing script

Description Michael Meeks 2007-08-02 16:50:39 UTC
After I selected 'No' in the 'Additional Repositories' dialog (and some time before this) I got a number of short-lived (perhaps ~1 second) dialogs:

these contained merely a '/' 1/2 way across them, and an 'Abort' button: what gives there ? :-)
Comment 1 Stefan Hundhammer 2007-08-03 09:27:44 UTC
I understand that's some kind of animated "busy" dialog. But I agree that we could come up with something more sophisticated here (after 10.3).

For example, Qt supports a progress dialog that pops up only after a certain timeout -- only if an operation takes long enough for such a dialog to make sense. That's something, however, that has to be done on the UI level.

In addition to that, from what I heard we can't use a 0-100% progress dialog since the number of operations to perform is unknown at the start, so it has to be some generic animation, not a progress bar that fills until 100% are reached.
Comment 2 Yavor Ivelinov Ivanov 2007-08-05 14:47:03 UTC
Created attachment 155633 [details]
Screen Shot of the problem

I assume this is the problem you are talking about.
Comment 3 Katarina Machalkova 2007-08-06 07:53:25 UTC
Package callbacks issue? (Lado, please check)
Comment 4 Michael Meeks 2007-08-06 07:58:11 UTC
Yavor - yes, like that, but I could have sworn mine had a single '/' instead ;-)

Stefan - clearly implementing the timeout show itself is more than trivial, like falling of the proverbial log ;-)

I suspect though that we havn't got the information on which dialogs we want this to happen on in the toolkit-backend ? [ any chance we can propagate that there & add a suitable hint ? ;-]
Comment 5 Ladislav Slezák 2007-08-06 14:32:45 UTC
The problem with empty dialog has been fixed, there is a title describing the current action now.

Concept of delayed popups looks quite interesting, I think it's a good solution how to prevent flashing on a fast machine and still display some feedback on a slow machine.

Qt (and also other toolkits) support "busy indicator" instead of the real progress (it's a progress bar with indicator which moves forth and back).

Comment 6 Ladislav Slezák 2007-08-15 09:45:44 UTC
Stefan, Michael, would it be possible to add a new option for `Progress widget to have just a busy indicator instead of real progress? (In the ncurses UI it should stay as it is now, the rotating character fits there well.)

Excerpt from the Qt documentation: "If the total is given as 0 the progress bar shows a busy indicator instead of a percentage of steps." So it should be quite easy I think. I suppose the same is valid also in Gtk...

Is it doable for 10.3?
Comment 7 Michael Meeks 2007-08-15 11:32:01 UTC
The hacking is trivial - we need to call a different function though 'gtk_progress_bar_pulse' every now/ then to update the sliding progress thing. Very happy to do the yast2-gtk bits if someone else can add the core API.

Failing that, if the convention will simply be that if maxprogress == 0 then we go into pulse mode on 'setProgress' - then that's fine too.

Lets do it :-) anything to kill that awful evilness of -/|\-/| etc. ;-)

[ incidentally, it'd be nice to get more feedback in the dialog title (eg.) or in a label as to what exactly is going on during all of these potentially endless waits ;-].

Oh - and I guess, in the 'pulse' case we could defer showing the dialog on a timeout quite nicely and solve 2 problems with one stoned bird ? ;-)
Comment 8 Ladislav Slezák 2007-08-22 08:52:08 UTC
We need to change the core UI API (and Qt) to accept maxprogres == 0 (and use busy indicator in that case) or create a new widget.

Stefan, reassign it back to me when it's ready, I'll fix the yast script.
Comment 9 Michael Meeks 2007-08-22 16:53:02 UTC
implemented in yast2-gtk HEAD.
Comment 10 Ladislav Slezák 2007-08-27 11:41:55 UTC
*** Bug 304700 has been marked as a duplicate of this bug. ***
Comment 11 Stefan Hundhammer 2007-08-29 17:42:43 UTC
I don't think it's a good idea to use an otherwise invalid value as a flag that changes the whole semantics of the widget. I'd call that a blatant misuse.

We have simpler things (and well-documented, too) that application developers can't remember. Things like this drift into oblivion the moment they were once used for one very special case. Even more so when (like in this case) it's really non-obvious.

If we need a mechanism to display a busy state of undetermined duration, we will have to introduce something. Something dedicated, something obvious, something easy to use, something that preferably works in ALL UIs.

In the course of migrating to the mod-ui I found many corpses in the basement like this. Most of them started as quick hacks to get something going quickly. And now some code depends on it, meaning that it will hurt a lot to fix it. It's a neverending fight against windmills to get rid of such stuff. I really don't see why we should want to introduce more of it.

For busy animations, we have MNG movie support. Did anybody ever give that a try? Or is that also just another feature that was once requested and forgotten right away with an implementation that never got used beyond the UI examples (which double as the UI test suite)?

Please let's do this properly and not misuse something that works today under certain circumstances, but which may break with any future code change.
Comment 12 Stanislav Visnovsky 2007-08-30 10:52:51 UTC
MNG is useless, as the callback is the code that tries to move the indicator to the next step. Otherwise a busy cursor would be enough.
Comment 13 Duncan Mac-Vicar 2007-08-30 11:37:21 UTC
We could use http://build.opensuse.org/images/rotating-tail.gif
Play, and have a timeout, if the callback don't tick inside this timeout, we stop. If it ticks, we play.

For ncurses, this can be done with a rotating /. The trick of just go to the next rotation every x seconds, and stop if no tick inside a x2 timeout happens could work as well as just going to the next state everytime the callback ticks (like zypper).

The code of the rotating / is in zypper: AliveCursor.h

Or?
Comment 14 Stefan Hundhammer 2007-08-30 12:22:24 UTC
I didn't try it with a zypp callback, but AFAICS we shouldn't even need a callback to play MNG movies. The UI should be able to handle this on its own in its UI thread. But of course this needs to be tested to be really sure.
Comment 15 Stefan Hundhammer 2007-08-30 12:46:09 UTC
Created attachment 160958 [details]
Simple MNG animation example
Comment 16 Stanislav Visnovsky 2007-08-30 12:52:25 UTC
MNG does not work in yast2-gtk-2.15.9-1
Comment 17 Duncan Mac-Vicar 2007-08-30 12:55:42 UTC
Comment #14: You want the "alive" cursor to reflect reality. If the pacient dies, you want to stop the animation at some point to reflect it.
Comment 18 Duncan Mac-Vicar 2007-08-30 15:23:51 UTC
MNG will stay with the ugly "/" then.

Can we do this for 10.3 already? I was already surprised that pkg-bindings implemented the ASCII cursor for the UI.

Where is that code and behavior defined? Should be as easy as setup the mng file in play and make sure it plays again when the callback ticks and stop if timeout without tick.
Comment 19 Michael Meeks 2007-08-30 15:42:20 UTC
Stefan - you choose how to do it :-) it is interesting to hear you to
compare the Qt interface choice here with a corpse in a basement ;-)

OTOH, I tend to agree that this could be a lot more elegant; let me
know when you add whatever new method is necessary here. Wrt. animated
images (or whatever), I'm not sure we implemented this in yast2-gtk,
and it sounds a rather odd way to do it [ and as you say, perhaps
something to deprecate ] - presumably that would not work for the
ncurses front-end.
Comment 20 Stefan Hundhammer 2007-08-30 15:52:13 UTC
(In reply to comment #19 from Michael Meeks)
> Stefan - you choose how to do it :-) it is interesting to hear you to
> compare the Qt interface choice here with a corpse in a basement ;-)

As a matter of fact, I was referring to the whole UI that has grown (at some point even festered) for 8+ years... ;-)

yast2-gtk is too young to have developed that amount of dead bodies. Just wait for a couple of years, then let's talk again. ;-)

Comment 23 Duncan Mac-Vicar 2007-08-31 10:22:03 UTC
Michael, probably fixing the dialog in the package manager would fix the issue, using a fake animation would not be that bad.

Would you be able to implement mng support?
Comment 24 Duncan Mac-Vicar 2007-08-31 10:52:31 UTC
Created attachment 161201 [details]
Screenshot of prototype
Comment 25 Duncan Mac-Vicar 2007-08-31 10:53:14 UTC
Created attachment 161202 [details]
Prototype patch #1 (to yast2-packager)
Comment 26 Duncan Mac-Vicar 2007-08-31 10:53:53 UTC
Created attachment 161204 [details]
Icon used for the prototype ( must go in /usr/share/YaST2/theme/current/animations )
Comment 27 Duncan Mac-Vicar 2007-08-31 10:55:51 UTC
The remaining issue I have to solve with Stefan is the fact that if the process  freezes, the animation still play. We could solve that with a timer, but they don't exist at ycp level.

Stefan is investigating if mng supports that in the metadata itself so perhaps we can force the animation to play 1 loop and reactivate it in the tick() callback.
Comment 28 Duncan Mac-Vicar 2007-08-31 11:06:02 UTC
We should be safe I guess:

identify -verbose /usr/share/YaST2/theme/current/animations/ticks.mng | grep Iter
  Iterations: 0

So I only need to Replace the widget in the tick callback and it should work?
Comment 29 Duncan Mac-Vicar 2007-08-31 11:41:57 UTC
Created attachment 161220 [details]
New patch #2, with timeout
Comment 30 Duncan Mac-Vicar 2007-08-31 11:42:55 UTC
Created attachment 161221 [details]
New image, with only 3 loops (/usr/share/YaST2/theme/current/animations/ticks.mng)
Comment 31 Duncan Mac-Vicar 2007-08-31 11:46:02 UTC
Last version of the patch works differently.

Stefan created another mng wich loops 3 times only.

I changed the patch so in each tick I change the widget, so it starts from the beggining. The effect is not that bad, and we make sure if there is no tick, after 3 loops it will stop.

Ladislav, can you integrate it in package (and/or) give a look at the patch)
Michael, mng support in gtk, is it possible (the patch fallsback to the old method anyway)
Everyone else. If you don't like the image, go to http://www.ajaxload.info/, create another one and propose it.
Comment 32 Stefan Hundhammer 2007-08-31 12:02:38 UTC
How to convert an andless-looping MNG to one that loops only a limited number of times:

- Disassemble the MNG:

    convert myanim.mng myanim.png

(will create a separate PNG for each frame, myanim0.png ... myanim999.mng)

- Reassemble the MNG with a number of loop iterations (here: 3) specified:

    convert -loop 3 myanim*.png myanim-new.png

- Test with

    animate myanim-new.png
Comment 33 Jakub Steiner 2007-08-31 12:44:12 UTC
Created attachment 161245 [details]
opensuse 10.2 boot spinner. (with reflection)
Comment 34 Jakub Steiner 2007-08-31 12:49:18 UTC
Created attachment 161246 [details]
10.3 plain spinner (no reflection).
Comment 35 Jakub Steiner 2007-08-31 12:50:52 UTC
Created attachment 161247 [details]
generic spinner at 22x22px
Comment 36 Jakub Steiner 2007-08-31 12:52:15 UTC
Created attachment 161248 [details]
generic spinner at 32x32px
Comment 37 Jakub Steiner 2007-08-31 12:53:03 UTC
Created attachment 161249 [details]
generic spinner at 48x48px
Comment 38 Jakub Steiner 2007-08-31 13:12:35 UTC
Created attachment 161255 [details]
suse styled animation posted above.
Comment 39 Forgotten User h13THG8RK1 2007-08-31 23:34:09 UTC
Sorry, but I never tested a MNG movie... yast-gtk does support the animation flag, but is restricted to GIF animations (and at least some other obscure format). A GIF sounds good enough for what you want though.
I remember yast-qt also supported GIF fine, just didn't honor the tile and scale flags.

The restriction is at the library level, GdkPixbuf. I have no idea how much work it would be to extend its PNG support for that... And I doubt we can find an external library for movie playback that won't bring a bunch of dependencies, like for sound...

Anyway, unless there are some schedule restrictions, I would rather we'd use a progress bar. But I'm sure Jakub's animations would make me think twice, if I could open them. ;)
Comment 40 Duncan Mac-Vicar 2007-09-02 16:38:47 UTC
Comment #39: We would use a progress bar too, if we had the progress information. This is a tick progress. We get keep-alives.
Comment 41 Ladislav Slezák 2007-09-03 08:38:43 UTC
It seems to be quite complicated, how should we solve it in 10.3?

AFAIK there are these possibilities:

1) The current solution (rotating slash) - works in all UIs
2) Use the proposed solution (an animated PNG) - not supported in GTK UI, ncurses would still use the rotating slash, it's supported only in Qt currently. If yast is able to distinguish between Gtk and Qt UI we could use the rotating slash or use the solution from comment #7 for Gtk.

After 10.3 we should introduce a new widget for busy indicator, each UI would handle it internally and we should drop the hack from YCP script...
Comment 42 Stephan Kulow 2007-09-03 09:16:04 UTC
Duncan, your stance?
Comment 43 Duncan Mac-Vicar 2007-09-03 09:53:17 UTC
The patch I sent, checks if there are animation capabilities in the display, and fallback to the rotating slash if not.

If gtk does not support mng, but gif. Then the only needed change is to convert the animation to animated gif, and then gtk and qt will have the animation and ncurses the slash.

In the long term of course YUI developers have to provide a built-in solution.
Comment 44 Stephan Kulow 2007-09-03 10:01:40 UTC
Stefan, anything else you need?
Comment 45 Stefan Hundhammer 2007-09-03 10:19:05 UTC
It's now up to the YCP part -> lszezak
Comment 46 Stefan Hundhammer 2007-09-03 11:50:53 UTC
I just submitted yast2-theme-2.15.12.tar.bz2 which now includes:

/usr/share/YaST2/theme/current/animations/
    ticks-endless.mng
    ticks-loop3.mng

For this purpose, use ticks-loop3.mng which will iterate 3 times, then finish.
Comment 47 Ladislav Slezák 2007-09-03 11:52:39 UTC
Thanks Stefan!
Comment 48 Ladislav Slezák 2007-09-03 12:26:17 UTC
Fixed in yast2-packager-2.15.73 (Duncan, thanks for the original patch!)
Comment 49 Duncan Mac-Vicar 2007-09-03 13:27:03 UTC
Uhm shouldn't those files go as gif so gtk can play them?
Comment 50 Ladislav Slezák 2007-09-03 13:37:49 UTC
Uh, you are right. Stefan, please, convert the animations to gif and then reassign it back to me, I'll fix the YCP code...
Comment 51 Stefan Hundhammer 2007-09-03 13:57:37 UTC
Submitted y2-theme once more (3rd time today)
Comment 52 Ladislav Slezák 2007-09-03 14:48:06 UTC
Fixed in yast2-packager-2.15.74 (also the 3rd submit today)

Stefan, the animation doesn't look nice in Qt UI, it looks as if it's restarting too early, but 'animate' shows it correctly. Could you check that? Looks like a Qt bug...
Comment 53 Stefan Hundhammer 2007-09-03 15:23:47 UTC
I really wouldn't know what to do about that. Does the MNG work better? I never tried with animated GIFs before.
Comment 54 Ladislav Slezák 2007-09-03 15:35:01 UTC
Created attachment 161537 [details]
testing script

Yes, MNG looks better (at least in Beta2).

The attachment contains a test code for the tick callback.