deluge/deluge/ui/gtkui/piecesbar.py
Pedro Algarvio 28def22625 PiecesBar enhancement.
The pieces bar will now draw status text, like a regular progress bar does, and for the overall progress, a semi-transparent overlay is also drawn.
2011-05-18 05:01:30 +01:00

233 lines
7.3 KiB
Python

# -*- coding: utf-8 -*-
#
# listview.py
#
# Copyright (C) 2011 Pedro Algarvio <pedro@algarvio.me>
#
# Deluge is free software.
#
# You may redistribute it and/or modify it under the terms of the
# GNU General Public License, as published by the Free Software
# Foundation; either version 3 of the License, or (at your option)
# any later version.
#
# deluge is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with deluge. If not, write to:
# The Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
# In addition, as a special exception, the copyright holders give
# permission to link the code of portions of this program with the OpenSSL
# library.
# You must obey the GNU General Public License in all respects for all of
# the code used other than OpenSSL. If you modify file(s) with this
# exception, you may extend this exception to your version of the file(s),
# but you are not obligated to do so. If you do not wish to do so, delete
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here.
#
#
import gtk
import pango
import pangocairo
import logging
from deluge.configmanager import ConfigManager
log = logging.getLogger(__name__)
COLOR_STATES = {
0: "missing",
1: "waiting",
2: "downloading",
3: "completed"
}
class PiecesBar(gtk.DrawingArea):
# Draw in response to an expose-event
__gsignals__ = {"expose-event": "override"}
def __init__(self):
gtk.DrawingArea.__init__(self)
# Get progress bar styles, in order to keep font consistency
pb = gtk.ProgressBar()
pb_style = pb.get_style()
self.text_font = pb_style.font_desc
self.text_font.set_weight(pango.WEIGHT_BOLD)
# Done with the ProgressBar styles, don't keep refs of it
del pb, pb_style
self.set_size_request(-1, 25)
self.gtkui_config = ConfigManager("gtkui.conf")
self.width = 0
self.height = 0
self.pieces = ()
self.num_pieces = None
self.text = ""
self.fraction = 0.0
self.torrent_state = None
self.connect('size-allocate', self.do_size_allocate_event)
self.set_colormap(self.get_screen().get_rgba_colormap())
self.show()
def do_size_allocate_event(self, widget, size):
self.width = size.width
self.height = size.height
# Handle the expose-event by drawing
def do_expose_event(self, event=None):
# Create the cairo context
cr = self.window.cairo_create()
# Restrict Cairo to the exposed area; avoid extra work
cr.rectangle(event.area.x, event.area.y,
event.area.width, event.area.height)
cr.clip()
cr.set_line_width(max(cr.device_to_user_distance(0.5, 0.5)))
cr.set_source_rgb(0.1, 0.1, 0.1)
cr.rectangle(0.0, 0.0, event.area.width, event.area.height)
cr.stroke()
if not self.pieces and self.num_pieces is not None:
# Complete Torrent
piece_height = self.height - 2
piece_width = self.width*1.0/self.num_pieces
start = 1
for _ in range(self.num_pieces):
# Like this to keep same aspect ratio
color = self.gtkui_config["pieces_color_%s" % COLOR_STATES[3]]
cr.set_source_rgb(
color[0]/65535.0,
color[1]/65535.0,
color[2]/65535.0,
)
cr.rectangle(start, 1, piece_width, piece_height)
cr.fill()
start += piece_width
self.__write_text(cr, event)
return
if not self.pieces:
self.__write_text(cr, event)
return
# Create the cairo context
start_pos = 1
num_pieces = self.num_pieces and self.num_pieces or len(self.pieces)
piece_width = self.width*1.0/num_pieces
piece_height = self.height - 2
for state in self.pieces:
color = self.gtkui_config["pieces_color_%s" % COLOR_STATES[state]]
cr.set_source_rgb(
color[0]/65535.0,
color[1]/65535.0,
color[2]/65535.0,
)
cr.rectangle(start_pos, 1, piece_width, piece_height)
cr.fill()
start_pos += piece_width
self.__write_text(cr, event)
def __draw_progress_overlay(self, cr):
cr.set_source_rgba(0.1, 0.1, 0.1, 0.2) # Transparent
cr.rectangle(0.0, 0.0, self.width*self.fraction, self.height)
cr.fill()
def __write_text(self, cr, event):
if not self.torrent_state:
# Nothing useful to draw, return now!
return
self.__draw_progress_overlay(cr)
pg = pangocairo.CairoContext(cr)
pl = pg.create_layout()
pl.set_font_description(self.text_font)
pl.set_width(-1) # No text wrapping
text = ""
if self.text:
text += self.text
else:
if self.torrent_state:
text += self.torrent_state + " "
if self.fraction == 1.0:
format = "%d%%"
else:
format = "%.2f%%"
text += format % (self.fraction*100)
log.debug("PiecesBar text %r", text)
pl.set_text(text)
plsize = pl.get_size()
text_width = plsize[0]/pango.SCALE
text_height = plsize[1]/pango.SCALE
area_width_without_text = event.area.width - text_width
area_height_without_text = event.area.height - text_height
cr.move_to(area_width_without_text/2, area_height_without_text/2)
cr.set_source_rgb(1.0, 1.0, 1.0)
pg.update_layout(pl)
pg.show_layout(pl)
def set_fraction(self, fraction):
self.fraction = fraction
self.update()
def set_pieces(self, pieces, num_pieces):
if pieces != self.pieces:
self.pieces = pieces
self.num_pieces = num_pieces
self.update()
def update_from_status(self, status):
update = False
fraction = status["progress"]/100
if fraction != self.fraction:
self.fraction = fraction
update = True
torrent_state = status["state"]
if torrent_state != self.torrent_state:
self.torrent_state = torrent_state
update = True
if torrent_state == "Checking":
self.update()
# Skip the pieces assignment
return
if status['pieces'] != self.pieces:
self.pieces = status['pieces']
self.num_pieces = status['num_pieces']
update = True
if update:
self.update()
def clear(self):
self.pieces = []
self.num_pieces = None
self.fraction = 0.0
self.update()
def update(self):
self.queue_draw()
def get_text(self):
return self.text
def set_text(self, text):
self.text = text
self.update()