Opened 16 years ago

Last modified 7 years ago

#378 assigned feature-request

Advanced (pieces) progress bar

Reported by: andar Owned by:
Priority: major Milestone: 2.x
Component: Web UI Version:
Keywords: Cc: ufs@ufsoft.org, kernja@earlham.edu

Description


Attachments (15)

pieces_bar.patch (9.8 KB ) - added by James_Kern 15 years ago.
patch for adding pieces bar to status tab, against 1.2.1
pieces_bar_2.patch (96.3 KB ) - added by James_Kern 15 years ago.
piecesbar_gtk_js.patch (35.1 KB ) - added by James_Kern 14 years ago.
progress.png (2.1 KB ) - added by s0undt3ch 13 years ago.
Progress bar screenshot
progress-new.png (9.4 KB ) - added by s0undt3ch 13 years ago.
New approach using cairo
pieces_test.py (6.1 KB ) - added by s0undt3ch 13 years ago.
Small test which muliplies the data available by 100, like show on the previsous screenshot attachment
with-progress-bar.png (3.0 KB ) - added by s0undt3ch 13 years ago.
With an overal progress bar
with-progress-bar1.png (8.0 KB ) - added by s0undt3ch 13 years ago.
with-progress-bar2.png (4.6 KB ) - added by s0undt3ch 13 years ago.
with-progress-bar3.png (4.7 KB ) - added by s0undt3ch 13 years ago.
with-progress-bar4.png (4.3 KB ) - added by s0undt3ch 13 years ago.
final-progress-bar.png (10.7 KB ) - added by s0undt3ch 13 years ago.
final-progress-bar1.png (4.9 KB ) - added by s0undt3ch 13 years ago.
final-progress-bar2.png (26.6 KB ) - added by s0undt3ch 13 years ago.
C olors config
piecesbar_webui.patch (6.9 KB ) - added by James_Kern 13 years ago.
canvas based piecesbar for web ui

Download all attachments as: .zip

Change History (57)

comment:1 by mvoncken, 16 years ago

Milestone: 1.1.01.2.0

comment:2 by anonymous, 15 years ago

This would be really nice, especially for the individual files view

comment:3 by s0undt3ch, 15 years ago

Cc: ufs@ufsoft.org added

comment:4 by andar, 15 years ago

Milestone: 1.2.0Future
Version: 1.1.0_dev

comment:5 by James_Kern, 15 years ago

Cc: kernja@earlham.edu added

To get a feel for the code base, I've swapped out the progress bar in the status tab with a bar that shows you the status of each piece in the torrent. Not sure on how to go about getting this merged back in though.

comment:6 by Damien Churchill, 15 years ago

Attach a patch so we can have a look at it?

by James_Kern, 15 years ago

Attachment: pieces_bar.patch added

patch for adding pieces bar to status tab, against 1.2.1

comment:7 by James_Kern, 15 years ago

Yea I should've guessed that :)

comment:8 by Damien Churchill, 15 years ago

Looks good, although I would change it to return None rather than an empty list, and merge line 486 and 487 so you end up with:

def get_pieces_status(self):
    if not self.handle.has_metadata():
        return None
    return self.handle.status().pieces

Returning None rather than an empty list is less expensive.

andar do you have any thoughts?

comment:9 by James_Kern, 15 years ago

bleck, noticed a couple problems. The bar expands to fill the vertical space when the panel is expanded, which looks ugly. Also when a torrent has more pieces than there are pixels wide, the bar shows up as empty. The first shouldn't be too bad, but not sure how easy the second one will be to fix.

comment:10 by Damien Churchill, 15 years ago

The first issue can be solved with a gtk setting, can't remember which one it is off the top of my head but widgets can be set to not auto-expand.

As for the second, the only solution I can think of would be to start dropping pieces, or merge pieces together and average, so

if piece_count > bar_width:
    _pieces = pieces[:]
    pieces = []
    while _pieces:
        one = _pieces.pop(0)
        two = _pieces.pop(0)
        # do calc
        pieces.append(one + two / 2)

That is of course pseudo code just to give a general idea of what I was saying.

comment:11 by andar, 15 years ago

You could also change the progress bar to a progress grid if you do not have enough space. This would basically split up the vertical space so you can gain some additional rows without losing any piece information by dropping or merging pieces.

by James_Kern, 15 years ago

Attachment: pieces_bar_2.patch added

comment:12 by James_Kern, 15 years ago

Ok, fixed the expansion issue at the cost of the height being fixed now. For the other issue I went with grouping the pieces like damoxc suggested. It does lose a little bit of information versus using a grid where you can fit more pieces, but I think it still gives a close enough approximation. Also you could still potentially run into the same issue using the grid if a torrent had more pieces then pixels in the bar (unlikely as that may be).

comment:13 by James_Kern, 14 years ago

Do you guys have any thoughts on how to do this in the web ui? Looked through the ExtJS docs and didn't see anything promising on first glance. Next thought is to generate an image server-side using cairo.

comment:14 by Damien Churchill, 14 years ago

Nah should do this client side, less load you can place on the web server the better.

Could build something along the lines of:

<div class="x-piecesbar-wrapper">
        <div class="x-piecesbar-piece x-piece-complete"></div>
        <div class="x-piecesbar-piece"></div>
        <div class="x-piecesbar-piece"></div>
        <div class="x-piecesbar-piece"></div>
        <div class="x-piecesbar-piece x-piece-complete"></div>
        <div class="x-piecesbar-piece x-piece-complete"></div>
        <div class="x-piecesbar-piece x-piece-complete"></div>
        <div class="x-piecesbar-piece x-piece-complete"></div>
        <div class="x-piecesbar-piece x-piece-complete"></div>
        <div class="x-piecesbar-piece"></div>
        <div class="x-piecesbar-piece"></div>
        <div class="x-piecesbar-piece x-piece-complete"></div>
        <div class="x-piecesbar-piece"></div>
        ...
</div>

This should be built up via a class named Deluge.Piecesbar that extends from Ext.BoxComponent.

comment:15 by Damien Churchill, 14 years ago

Oh and the css would be something like:

.x-piecesbar-piece {
    display: inline; /* or float: left; */
    color: #fff;
    width: 1px;
}

.x-piece-complete {
    color: #000;
}

comment:16 by James_Kern, 14 years ago

Been a little while, but was bored over the weekend so finally took a stab at implementing this for the WebUI as well. Attached a patch against git trunk.

Only concern right now is that it's a little slow on torrents with lots of pieces (i.e. more than 1000). Doesn't seem to be much of a problem on chrome, but firefox is a little laggy when switching between torrents. I think the problem is clearing all the <div>'s, but not sure of any more efficient way of doing that.

by James_Kern, 14 years ago

Attachment: piecesbar_gtk_js.patch added

comment:17 by Calum, 14 years ago

Type: feature-requestpatch

in reply to:  16 comment:18 by s0undt3ch, 14 years ago

Replying to James_Kern:

Been a little while, but was bored over the weekend so finally took a stab at implementing this for the WebUI as well. Attached a patch against git trunk.

Only concern right now is that it's a little slow on torrents with lots of pieces (i.e. more than 1000). Doesn't seem to be much of a problem on chrome, but firefox is a little laggy when switching between torrents. I think the problem is clearing all the <div>'s, but not sure of any more efficient way of doing that.

How about drawing on a canvas?

comment:19 by s0undt3ch, 13 years ago

So, should this be done for 1.4?

comment:20 by s0undt3ch, 13 years ago

Ppl, I'm trying to extend the pieces information. Ie, each piece should have 4 states:

  • 0 - Missing
  • 1 - Present but not downloaded
  • 2 - Downloading
  • 3 - Downloaded

So far I've managed to build this information, but, I'm at the end of my night shift and my head is getting too tired. How can I adapt the reduce function to this?

Here's an example list:

[3, 2, 1, 1, 1, 0, 0, 2, 0, 1, 0, 2, 0, 2, 1, 0, 2, 0, 0, 0, 2,
0, 0, 0, 2, 0, 0, 2, 2, 1, 0, 2, 1, 0, 1, 1, 0, 0, 2, 0, 0, 0,
0, 0, 0, 3, 3, 0, 0, 2, 0, 2, 2, 2, 0, 2, 2, 1]

comment:21 by s0undt3ch, 13 years ago

>>> x = [3, 2, 1, 1, 1, 0, 0, 2, 0, 1, 0, 2, 0, 2, 1, 0, 2, 0, 0, 0,
2, 0, 0, 0, 2, 0, 0, 2, 2, 1, 0, 2, 1, 0, 1, 1, 0, 0, 2, 0, 0, 0, 0,
0, 0, 3, 3, 0, 0, 2, 0, 2, 2, 2, 0, 2, 2, 1]
>>> t = len(x)*1.0 
>>> xx = [] 
>>> v = x.pop(0) 
>>> n = 1 
>>> while True: 
...     if not x: 
...         break 
...     vv = x.pop(0) 
...     if vv == v: 
...         n += 1 
...     else: 
...         xx.append(n/t) 
...         n = 1 
...  
>>> xx 
[0.017241379310344827, 0.017241379310344827, 0.017241379310344827, 0.017241379310344827,
0.017241379310344827, 0.017241379310344827, 0.017241379310344827, 0.017241379310344827,
0.017241379310344827, 0.017241379310344827, 0.017241379310344827, 0.017241379310344827,
0.017241379310344827, 0.017241379310344827, 0.017241379310344827, 0.017241379310344827,
0.017241379310344827, 0.017241379310344827, 0.017241379310344827, 0.017241379310344827,
0.017241379310344827, 0.017241379310344827, 0.017241379310344827, 0.017241379310344827,
0.017241379310344827, 0.017241379310344827, 0.017241379310344827, 0.017241379310344827,
0.017241379310344827, 0.017241379310344827, 0.017241379310344827, 0.017241379310344827,
0.017241379310344827, 0.017241379310344827, 0.017241379310344827, 0.017241379310344827,
0.017241379310344827, 0.017241379310344827, 0.017241379310344827, 0.017241379310344827,
0.017241379310344827, 0.017241379310344827, 0.017241379310344827, 0.017241379310344827,
0.051724137931034482, 0.017241379310344827, 0.017241379310344827, 0.017241379310344827,
0.017241379310344827, 0.017241379310344827, 0.017241379310344827, 0.017241379310344827,
0.017241379310344827, 0.017241379310344827, 0.017241379310344827]
>>> len(xx) 
55 
>>> t 
58.0 
>>>

Didn't reduce that much, but the data was not helping much too ;)

Is this the way to go?

The final values and width percentages, considering 58 is 100%

comment:22 by s0undt3ch, 13 years ago

Actually:

>>> x = [3, 2, 1, 1, 1, 0, 0, 2, 0, 1, 0, 2, 0, 2, 1, 0, 2, 0, 0, 0, 2, 0, 0, 0,
...      2, 0, 0, 2, 2, 1, 0, 2, 1, 0, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 3, 0,
...      0, 2, 0, 2, 2, 2, 0, 2, 2, 1]
>>> t = len(x)*1.0
>>> xx = []
>>> v = None
>>> n = None
>>> 
>>> while True:
...     if not x:
...         break
...     if v is None:
...         v = x.pop(0)
...         n = 1
...     else:
...         vv = x.pop(0)
...         if v == vv:
...             n += 1
...         else:
...             xx.append((v, n/t))
...             v = vv
...             n = 1
... 
>>> 
>>> 
>>> print xx
[(3, 0.017241379310344827), (2, 0.017241379310344827),
(1, 0.051724137931034482), (0, 0.034482758620689655),
(2, 0.017241379310344827), (0, 0.017241379310344827),
(1, 0.017241379310344827), (0, 0.017241379310344827),
(2, 0.017241379310344827), (0, 0.017241379310344827),
(2, 0.017241379310344827), (1, 0.017241379310344827),
(0, 0.017241379310344827), (2, 0.017241379310344827),
(0, 0.051724137931034482), (2, 0.017241379310344827),
(0, 0.051724137931034482), (2, 0.017241379310344827),
(0, 0.034482758620689655), (2, 0.034482758620689655),
(1, 0.017241379310344827), (0, 0.017241379310344827),
(2, 0.017241379310344827), (1, 0.017241379310344827),
(0, 0.017241379310344827), (1, 0.034482758620689655),
(0, 0.034482758620689655), (2, 0.017241379310344827),
(0, 0.10344827586206896), (3, 0.034482758620689655),
(0, 0.034482758620689655), (2, 0.017241379310344827),
(0, 0.017241379310344827), (2, 0.051724137931034482),
(0, 0.017241379310344827), (2, 0.034482758620689655)]
>>> print len(xx)
36
>>>

comment:23 by s0undt3ch, 13 years ago

Here's a GTK example, nevermind the colors used ;)

import pygtk
pygtk.require('2.0')
import gtk

class PiecesBar(gtk.DrawingArea):
    def __init__(self):
        gtk.DrawingArea.__init__(self)
        self.width = 0
        self.height = 0
        self.pieces = []

        self.connect('size-allocate', self.on_size_allocate)
        self.connect('expose-event', self.update)
        self.connect('realize', self.on_realize)

        self.show()

    def on_realize(self, widget):
        map = widget.get_colormap()
        done_color = map.alloc_color("#325891")
        down_color = map.alloc_color("#67DB63")
        wait_color = map.alloc_color("#EBF57A")
        miss_color = map.alloc_color("#FF4D36")
        outline_color = map.alloc_color("#888888")

        self.colors = {
            0: widget.window.new_gc(foreground=miss_color),
            1: widget.window.new_gc(foreground=wait_color),
            2: widget.window.new_gc(foreground=down_color),
            3: widget.window.new_gc(foreground=done_color)
        }
        self.gc_done = widget.window.new_gc(foreground=done_color)
        self.gc_down = widget.window.new_gc(foreground=down_color)
        self.gc_wait = widget.window.new_gc(foreground=wait_color)
        self.gc_miss = widget.window.new_gc(foreground=miss_color)
        self.gc_outline = widget.window.new_gc(foreground=outline_color)

    def on_size_allocate(self, widget, size):
        self.width = size.width
        self.height = size.height

    def update(self, widget=None, event=None):
        num_pieces = len(self.pieces)

        if num_pieces < 1:
            self.clear()
            return None

        self.window.draw_rectangle(self.gc_outline, False, 0, 0,
                                   self.width - 1, self.height - 1)

        width = self.width - 2
        pieces = self.collapse_pieces()

        start_pos = 1

        for state, wpercent in pieces:
            print state, wpercent
            pwidth = width*wpercent
            print 1, pwidth
            self.draw_piece(state, start_pos, 1, pwidth, self.height - 2)
            start_pos += pwidth

    def collapse_pieces(self):
        num_pieces = len(self.pieces)*1.0
        opieces = self.pieces[:]
        npieces = []
        v = None
        n = None
        while True:
            if not opieces:
                break
            if v is None:
                v = opieces.pop(0)
                n = 1
            else:
                vv = opieces.pop(0)
                if v == vv:
                    n += 1
                else:
                    npieces.append((v, n/num_pieces))
                    v = vv
                    n = 1
        return npieces

    def draw_piece(self, piece, start_x, start_y, width, height):
        self.window.draw_rectangle(
            self.colors[piece], True, start_x, start_y, width, height
        )

    def clear(self):
        self.pieces = [0]
        self.update()

    def get_text(self):
        return ""

    def set_text(self, text):
        pass

pieces = PiecesBar()
pieces.pieces = [3, 2, 1, 1, 1, 0, 0, 2, 0, 1, 0, 2, 2, 2, 1, 2, 2, 0, 0, 0, 2,
                 1, 1, 1, 2, 0, 0, 2, 2, 1, 0, 2, 1, 0, 1, 1, 0, 0, 2, 3, 3, 3,
                 3, 3, 0, 3, 3, 0, 0, 2, 0, 2, 2, 2, 0, 2, 2, 1]

window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.add(pieces)
window.show_all()
gtk.main()

How about this?

comment:24 by s0undt3ch, 13 years ago

Still needs a percent complete label added, like the progressbar has.

by s0undt3ch, 13 years ago

Attachment: progress.png added

Progress bar screenshot

by s0undt3ch, 13 years ago

Attachment: progress-new.png added

New approach using cairo

by s0undt3ch, 13 years ago

Attachment: pieces_test.py added

Small test which muliplies the data available by 100, like show on the previsous screenshot attachment

comment:25 by s0undt3ch, 13 years ago

Using cairo, like shown on the attached pieces_test.py, not data is lost, and event if there's huge amount of pieces for a really small space, all data will be shown. The pieces are only collapsed to reduce the number of rectangle draws. I like this approach much better. How about it? I'll take up the GTK part of the task of this is accepted.

comment:26 by s0undt3ch, 13 years ago

By the way, this is partially done on a local branch. I'll upload it to deluge's git if there's interest.

comment:27 by James_Kern, 13 years ago

The cairo approach is nice! For the web side of this we'd have to change to using canvas, since I think that's the only way to support using floats for width. I took a first pass at it and it didn't seem too hard to switch to. If there's actual interest in getting this in I'll commit to doing that part.

by s0undt3ch, 13 years ago

Attachment: with-progress-bar.png added

With an overal progress bar

comment:28 by s0undt3ch, 13 years ago

How about also including an overall progress bar on the bottom? Screenshot attached.

comment:29 by James_Kern, 13 years ago

I don't think the progress bar is really necessary, since there's one shown above in the main torrent list. The bar is already a pretty busy area visually so I'd prefer not add something else to it too.

in reply to:  29 comment:30 by s0undt3ch, 13 years ago

Replying to James_Kern:

I don't think the progress bar is really necessary, since there's one shown above in the main torrent list. The bar is already a pretty busy area visually so I'd prefer not add something else to it too.

My idea for this pieces bar is to either show the progress bar in the torrent list, or, show the pieces bar. Not both. In the torrent details, I'm open for discussion, same behavior?

comment:31 by s0undt3ch, 13 years ago

Now, I see. The original patch was just for the status tab :) Well, what I'm after is to replace the dull progress bar with the pieces bar.

comment:32 by shnurapet, 13 years ago

Keep it nice and simple, please.

by s0undt3ch, 13 years ago

Attachment: with-progress-bar1.png added

by s0undt3ch, 13 years ago

Attachment: with-progress-bar2.png added

by s0undt3ch, 13 years ago

Attachment: with-progress-bar3.png added

by s0undt3ch, 13 years ago

Attachment: with-progress-bar4.png added

comment:33 by s0undt3ch, 13 years ago

The last 4 screenshots attached, with-progress-barX.png, show the current status of the implementation, and removes the need to have the regular progress bar above the pieces bar.

comment:34 by s0undt3ch, 13 years ago

There's a testing branch now for every one to try and report bugs before merging to master:

by s0undt3ch, 13 years ago

Attachment: final-progress-bar.png added

by s0undt3ch, 13 years ago

Attachment: final-progress-bar1.png added

comment:35 by s0undt3ch, 13 years ago

Final pieces bar screenshots(2)

by s0undt3ch, 13 years ago

Attachment: final-progress-bar2.png added

C olors config

comment:36 by Calum, 13 years ago

Milestone: Future1.4.0
Owner: changed from andar to s0undt3ch
Status: newassigned
Type: patchfeature-request

comment:37 by James_Kern, 13 years ago

I've mostly ported the new implementation to the web ui (haven't looked into hooking it into the preferences) on the pieces-progress-bar branch. Don't know how to push changes back up using git (or if I should even) so I'm attaching a patch here instead

by James_Kern, 13 years ago

Attachment: piecesbar_webui.patch added

canvas based piecesbar for web ui

comment:38 by Damien Churchill, 13 years ago

Excellent thanks, I'm currently in the progress of migrating master to extjs4 (extjs4-port on git) so once I've done that I will integrate your patch!

I might modify it a little bit to change it into a widget so it can be used else where if anyone wants to in a plugin or something if that's okay?

in reply to:  37 comment:39 by s0undt3ch, 13 years ago

Replying to James_Kern:

I've mostly ported the new implementation to the web ui (haven't looked into hooking it into the preferences) on the pieces-progress-bar branch. Don't know how to push changes back up using git (or if I should even) so I'm attaching a patch here instead

Great Stuff!

in reply to:  38 comment:40 by James_Kern, 13 years ago

Replying to damoxc:

Excellent thanks, I'm currently in the progress of migrating master to extjs4 (extjs4-port on git) so once I've done that I will integrate your patch!

I might modify it a little bit to change it into a widget so it can be used else where if anyone wants to in a plugin or something if that's okay?

Yea, absolutely. If you need any help with the extjs4 port I'd be happy to lend a hand

comment:41 by Calum, 10 years ago

Component: GTK-UIWeb-UI
Owner: s0undt3ch removed

comment:42 by Calum, 7 years ago

Milestone: 2.0.x2.x

Milestone renamed

Note: See TracTickets for help on using tickets.