View Issue Details

IDProjectCategoryView StatusLast Update
0002217gnunet-gtkgnunet-fs-gtkpublic2012-11-05 18:32
ReporterLRN Assigned ToChristian Grothoff  
PrioritynormalSeverityfeatureReproducibilityN/A
Status closedResolutionfixed 
Product VersionGit master 
Target Version0.9.4Fixed in Version0.9.4 
Summary0002217: Animated status icons for downloads/publications/searches
DescriptionAs was mentioned in 0002009, GNUnet-FS-GTK will look better with status icons.

We've obtained a few images in gnunet-fs-gtk/contrib/ - that's a start.
TagsNo tags attached.
Attached Files

Activities

LRN

2012-03-13 09:05

developer   ~0005605

Uploaded gtk-treeview-animated-image.tar.xz
It's a simple GTK+ application that shows animated images in a treeview.
How to use:
1) Run
2) Press the filechooser button
3) Choose an image (animated or not; must be supported by GtkPixbuf)
4) Press the "Add" button
5) Repeat 2-4 until you have enough items.
6) Change the value in the spinner
7) Press "Set" to change the animation tick delay
8) Repeat 6-7 to discover the correlation between CPU usage and tick delay

LRN

2012-03-13 09:21

developer   ~0005606

IME it consumes very little CPU on 100ms, and 100ms is certainly enough for anything GNUnet is going to display.
However, it means that it has a single timer that updates all images that had their frames expired. Because the advancement function skips frames to reach the given timestamp, tick delay must be sufficiently small - otherwise some frames will be skipped, making a jumpy animation. If that is undesirable, then we have to:
2) Get next frame delay after advancing to a new frame
3) At every tick calculate a new timestamp = last update timestamp + new frame delay
4) Advance to a new frame
5) Remember new timestamp as the last update timestamp
This way animation will play in its own bogus timeline, and its speed will only depend on the tick delay (as a side-effect, image's built-in inter-frame delay or fps value will be ignored).

Christian Grothoff

2012-03-13 19:28

manager   ~0005608

Yes, this looks about right in terms of how we should do it.

LRN

2012-03-14 19:28

developer   ~0005610

Uploaded gtk-treeview-animated-image-002.tar.xz
It's a quick hack on top of the first example program (so, for example, it crashes if you remove items), but it does illustrate the point - you can give a copy of the same GdkPixbuf to multiple cell renderers, update it destructively and invalidate treeview's GdkWindow to force it to redraw itself with new images.

(also added a license, in case anyone finds this code later)

LRN

2012-03-16 04:57

developer   ~0005615

gtk-treeview-animated-image-003.tar.xz was a bit premature, i've removed it.
gtk-treeview-animated-image-004.tar.xz is the correct version. The difference between 002 and 004 is that 004 only invalidates the column with images. As a result, if it isn't visible (i've added scrollbars and made columns resizable to help to illustrate this), nothing is drawn, and CPU consumption stays at zero.

LRN

2012-03-16 06:56

developer   ~0005616

OK, now we have to decide whether this mechnism is the right one.

As commented in https://ng.gnunet.org/bugs/view.php?id=2217#c5606 , it skips frames, which means that setting high delay (will be possible in config file; users might opt for higher delay to reduce resource usage - Azureus does that kind of thing), such as 1000ms, will produce weird-looking animation. OTOH, with low delay it draws animations the way they were created. On low delays it will not increase CPU usage significantly, since most animations won't request a redraw every tick (depends on animations themselves).
Also, i observed that settings delay < 10ms causes massive CPU usage increase. That is likely a GLib scheduler bug/feature. So there will be a restriction on this value, not allowing user to set it lower than 10ms.

The alternative approach only displays one frame per tick, making animation go slower on high delays, and faster on low delays. No frames will be skipped, but speed will change. Lower delays will guarantee higher CPU usage. Animations might get a different look, since their internal timing will be completely ignored.

Now, about formats:
As i've said on the IRC, i've managed to write some code for composing and de-composing .ani files. It's commandline and a bit crude, but it works. Git repo is here - https://gitorious.org/libgriff/libgriff
To create an .ani file with it:
Save every animation frame as uncompressed 32bpp .ico, with transparency (GIMP can do that).
Create a file with the following contents:
size:<uint>
icons:<uint>
steps:<uint>
width:<uint>
height:<uint>
bits:<uint>
planes:<uint>
jiffs:<uint>
flags:<hex>

Followed by <steps> lines consisting of
<int> <int>

Where first <int> is the icon index, second <int> is the number of jiffs this icon should be displayed for
Followed by <icons> lines consisting of file names (absolute or relative)
Followed by a newline.
Example:
size:36
icons:7
steps:0
width:0
height:0
bits:32
planes:1
jiffs:3
flags:1
blackspot_0000000000.ico
blackspot_0000000001.ico
blackspot_0000000002.ico
blackspot_0000000003.ico
blackspot_0000000004.ico
blackspot_0000000005.ico
blackspot_0000000006.ico

size is the size of the header, in bytes. At the moment only 36-byte headers are supported.
icons is the number of unique icons (number of .ico files)
steps is the number of animation steps. If 0, means that frames are played sequentially, and every frame is displayed for jiffs jiffs
width is the width of icons. Used when icons in the file are in raw bitmap format. When icons are .ico files (with headers), width is usually set to 0
height analogous to width
bits bits-per-pixel. Used for the same purposes as width and height - to decode raw data, but might be set to non-0 even if normal .ico files are used. I advice to keep it set to the true bit depth value (32, in our case)
planes number of color planes. Usually 1.
jiffs is the number of jiffs each frame is displayed for. 60 jiffs == 1 second. This number is used when steps == 0, and no timing data is included (see below).
flags is a hexademical (without 0x prefix) number. Flag 0x1 is set when .ani file contains .ico or .cur files (our case); otherwise it contains raw bitmap data. Flag 0x2 is set if .ani file contains a sequence chunk (see below); otherwise it contains no sequence chunk. Obviously, it is possible to work around the lack of flag 0x2 (robust RIFF applications should be able to handle that). There was a bug in gdk-pixbuf (now fixed in git master) that made it unable to open files without flag 0x2.
Next comes a number of lines (defined by steps) consisting of two signed integers.
First integers are icon indices, they from a sequence chunk in the .ani file. All icons are given implicit indices (in the order of storage, starting at 0) - these are the indices used by the sequence chunk. This allows the animation to display frames in any order, not just in the order they are stored. Frames may be displayed more than once in a single animation loop.
Second integers are per-frame delays, in jiffs. They form a rate chunk in .ani file.
These integers may be -1, if the respective chunk is not present in the file. Most likely the flag 0x2 was intended to allow .ani files to have a rate chunk, but not a sequence chunk (both chunks' have the same length; if steps is not 0, it's not obvious whether the file has both chunks or only rate; flag 0x2 states clearly that sequence chunk is present). That is how i see this, not sure what Windows thinks.
In practice you either have steps==0, in which case you have no sequence-rate lines in the text decription file, or you have steps!=0, and flag 0x2 set, so you have both chunks, and seqnuence-rate lines with non-negative integers. My program does support cases when one of the chunks is missing, in that case sequence or rate will be -1 for every frame; that's hardly useful.
And the last lines are for filenames.
The program will read the description file and assemble an .ani file.
Another program will do the reverse - create a number of .ico files from an .ani file, and fill out a text description file.

Not very convenient, but i doubt that suddenly lots of people will start making animated icons for GNUnet.

Since right now we're updating frames manually and invalidating the column manually, we're not tied to ANY format at all. As long as we have a convenient wrapper that serves us frames (i'm using GdkPixbufAnimation in the example code, but that is not mandatory - could be anything), and we have a way to make frames into GdkPixbufs - we're good. Thus possible alternatives are:
a) zip-compressed .ani files (same as .ani files, but smaller)
b) directories with .png files for frames and a single text description file for metadata
c) simple animation custom file format (combines png files and metadata; this means practically re-inventing .ani, .ang or .mng).

Now, about animated icons we currently have:
1) Obviously, GIF is not going to cut it. IMO. Having GIF icons as a backup is acceptable, having only GIF icons is not. Namely, icons should have 8-bit alpha channel.
2) Icons such as downloading.gif have disturbing animations. In downloading.gif the green arrow moves from top to bottom for a few frames, then animation loops and the arrow jumps to the top. The animation looks jumpy. Now, it's fixable by providing the right sequence information, which would make the arrow move down, then backtrack its movement back to the top, or make its movement smooth in some other way. But maybe we should have something different altogether? Variants:
  a) Make the arrow move down and "leave the visible area", then gradually "come into the visible area" from the top.
  b) Don't use an arrow at all. Use, for example, a picture of a drive (the on on downloaded.gif looks OK), and show pieces of files (green ones, i guess) dropping into the drive like raindrops (or maybe like these glyphs on the famous Matrix screensaver). "Downloaded" state will then look like a drive with all pieces present and combined into a file. Or maybe there won't be enough space in 24x24 pixels for that... But it's unclear how "downloading-not-receiving-new-pieces" counterpart would look in that case (same thing, with grey translucent pieces falling down and not hitting the drive?)
3) Do we need animation for everything? downloaded.gif is animated, but should it be?
4) "Publishing" and "Published" are a bit misleading, if they are going to be used for items in "Publications" tab in gnunet-fs-gtk; "Indexing" and "indexed" or "Inserting" and "inserted" would be more appropriate, with matching icons.

Christian Grothoff

2012-03-16 14:57

manager   ~0005619

You make many reasonable points (8-bit alpha, etc.). I also like the idea of having the download arrow disappear completely and reappear from the top. Anything else is likely too complicated to be seen in 24x24.

As for publishing vs. indexing/inserting, the naming style we use is that publishing is either indexing or inserting (hence gnunet-publish!). So as long as we don't have different icons for inserting and indexing, publishing is the correct name as it covers both. Now, I also don't think that the tiny difference (a checkbox!) gives a good justification for even using a different icon, so I'm fine with publishing and I think we should keep it that way.

In terms of performance, my idea was always that we'd specify the same frame rate for all animations (i.e. 3 jiffs or so) and thus would do all updates to all animations in one shot (and then have one redraw operation). That should reduce resource consumption. Then, we can have an option for the user to specify an alternative frame rate (i.e. 1 jiffs = 5s) which would be useful for very slow systems. And of course we might also want to have a dedicated image to use if the user says "no animation". But supporting such options is secondary; I'd rather like to see a first implementation using any of the proposed image-loading methods.

Having a fixed global animation rate is really the only major design decision I see here.

Christian Grothoff

2012-06-16 16:11

manager   ~0006074

Started with generic animations library code in SVN 22040. Needs to be documented (and integrated...).

Christian Grothoff

2012-06-16 21:38

manager   ~0006075

Animations are now working for publishing, downloading, publish completed, download completed and download stalled (only if the download is 'stalled' because we're downloading other files right now, not because the download is too slow).

What is not working (because availability probes seem to be creating trouble) are the 'checkmark' icons for availability checking. However, for this we'd also need some actual events for "availability check starting" and "availability check ending", so that's ok. For download/publishing errors, we don't have icons yet (once we do, all we need to do is change NULL's to the respetive icons).

Christian Grothoff

2012-06-16 21:40

manager   ~0006076

Little note: I'm not sure the orphan tab is working nicely; at least I think that because of a download operation being moved to orphan tab, I got gnunet-fs-gtk hanging on exit (which can be explained if the orphan tab's animation handle is not cleaned up on exit).

Christian Grothoff

2012-06-17 08:50

manager   ~0006077

Shutdown with orphan tab is now fixed in SVN 22054.

Christian Grothoff

2012-06-17 10:36

manager   ~0006078

Added error icons in SVN 22055, so this should be all for now (until FS API is changed to provide more events, or of course we might eventually get even nicer animations, but that's not essential).

Issue History

Date Modified Username Field Change
2012-03-13 09:01 LRN New Issue
2012-03-13 09:02 LRN File Added: gtk-treeview-animated-image.tar.xz
2012-03-13 09:05 LRN Note Added: 0005605
2012-03-13 09:21 LRN Note Added: 0005606
2012-03-13 19:28 Christian Grothoff Note Added: 0005608
2012-03-14 19:25 LRN File Added: gtk-treeview-animated-image-002.tar.xz
2012-03-14 19:28 LRN Note Added: 0005610
2012-03-16 04:37 LRN File Added: gtk-treeview-animated-image-003.tar.xz
2012-03-16 04:40 LRN File Deleted: gtk-treeview-animated-image-003.tar.xz
2012-03-16 04:56 LRN File Added: gtk-treeview-animated-image-004.tar.xz
2012-03-16 04:57 LRN Note Added: 0005615
2012-03-16 06:56 LRN Note Added: 0005616
2012-03-16 14:57 Christian Grothoff Note Added: 0005619
2012-03-16 22:16 Christian Grothoff Priority low => normal
2012-03-16 22:16 Christian Grothoff Status new => confirmed
2012-05-03 01:16 Christian Grothoff Assigned To => Christian Grothoff
2012-05-03 01:16 Christian Grothoff Status confirmed => assigned
2012-05-03 01:21 Christian Grothoff Product Version => Git master
2012-05-03 01:21 Christian Grothoff Target Version => 0.9.4
2012-06-16 16:11 Christian Grothoff Note Added: 0006074
2012-06-16 21:38 Christian Grothoff Note Added: 0006075
2012-06-16 21:40 Christian Grothoff Note Added: 0006076
2012-06-17 08:50 Christian Grothoff Note Added: 0006077
2012-06-17 10:36 Christian Grothoff Note Added: 0006078
2012-06-17 10:36 Christian Grothoff Status assigned => resolved
2012-06-17 10:36 Christian Grothoff Fixed in Version => 0.9.4
2012-06-17 10:36 Christian Grothoff Resolution open => fixed
2012-11-05 18:32 Christian Grothoff Status resolved => closed