[GTKUI] Refactor piecesbar code
This commit is contained in:
parent
2f4cb0156c
commit
08192033fb
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
|
|
||||||
import logging
|
|
||||||
from math import pi
|
from math import pi
|
||||||
|
|
||||||
import gtk
|
import gtk
|
||||||
|
@ -18,10 +17,6 @@ import pangocairo
|
||||||
from cairo import FORMAT_ARGB32, Context, ImageSurface
|
from cairo import FORMAT_ARGB32, Context, ImageSurface
|
||||||
|
|
||||||
from deluge.configmanager import ConfigManager
|
from deluge.configmanager import ConfigManager
|
||||||
from deluge.ui.gtkui.tab_data_funcs import fpcnt
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
COLOR_STATES = ["missing", "waiting", "downloading", "completed"]
|
COLOR_STATES = ["missing", "waiting", "downloading", "completed"]
|
||||||
|
|
||||||
|
@ -35,68 +30,63 @@ class PiecesBar(gtk.DrawingArea):
|
||||||
# Get progress bar styles, in order to keep font consistency
|
# Get progress bar styles, in order to keep font consistency
|
||||||
pb = gtk.ProgressBar()
|
pb = gtk.ProgressBar()
|
||||||
pb_style = pb.get_style()
|
pb_style = pb.get_style()
|
||||||
self.__text_font = pb_style.font_desc
|
self.text_font = pb_style.font_desc
|
||||||
self.__text_font.set_weight(pango.WEIGHT_BOLD)
|
self.text_font.set_weight(pango.WEIGHT_BOLD)
|
||||||
# Done with the ProgressBar styles, don't keep refs of it
|
# Done with the ProgressBar styles, don't keep refs of it
|
||||||
del pb, pb_style
|
del pb, pb_style
|
||||||
|
|
||||||
self.set_size_request(-1, 25)
|
self.set_size_request(-1, 25)
|
||||||
self.gtkui_config = ConfigManager("gtkui.conf")
|
self.gtkui_config = ConfigManager("gtkui.conf")
|
||||||
self.__width = self.__old_width = 0
|
|
||||||
self.__height = self.__old_height = 0
|
self.width = self.prev_width = 0
|
||||||
self.__pieces = self.__old_pieces = ()
|
self.height = self.prev_height = 0
|
||||||
self.__num_pieces = self.__old_num_pieces = None
|
self.pieces = self.prev_pieces = ()
|
||||||
self.__text = self.__old_text = ""
|
self.num_pieces = None
|
||||||
self.__message = self.__old_message = ""
|
self.text = self.prev_text = ""
|
||||||
self.__fraction = self.__old_fraction = 0.0
|
self.fraction = self.prev_fraction = 0
|
||||||
self.__state = self.__old_state = None
|
self.progress_overlay = self.text_overlay = self.pieces_overlay = None
|
||||||
self.__progress_overlay = self.__text_overlay = self.__pieces_overlay = None
|
self.cr = None
|
||||||
self.__cr = None
|
|
||||||
|
|
||||||
self.connect('size-allocate', self.do_size_allocate_event)
|
self.connect('size-allocate', self.do_size_allocate_event)
|
||||||
self.set_colormap(gtk.gdk.colormap_get_system())
|
self.set_colormap(gtk.gdk.colormap_get_system())
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
def do_size_allocate_event(self, widget, size):
|
def do_size_allocate_event(self, widget, size):
|
||||||
self.__old_width = self.__width
|
self.prev_width = self.width
|
||||||
self.__width = size.width
|
self.width = size.width
|
||||||
self.__old_height = self.__height
|
self.prev_height = self.height
|
||||||
self.__height = size.height
|
self.height = size.height
|
||||||
|
|
||||||
# Handle the expose-event by drawing
|
# Handle the expose-event by drawing
|
||||||
def do_expose_event(self, event):
|
def do_expose_event(self, event):
|
||||||
# Create cairo context
|
# Create cairo context
|
||||||
self.__cr = self.window.cairo_create()
|
self.cr = self.window.cairo_create()
|
||||||
self.__cr.set_line_width(max(self.__cr.device_to_user_distance(0.5, 0.5)))
|
self.cr.set_line_width(max(self.cr.device_to_user_distance(0.5, 0.5)))
|
||||||
|
|
||||||
# Restrict Cairo to the exposed area; avoid extra work
|
# Restrict Cairo to the exposed area; avoid extra work
|
||||||
self.__roundcorners_clipping()
|
self.roundcorners_clipping()
|
||||||
|
|
||||||
self.__draw_pieces()
|
self.draw_pieces()
|
||||||
self.__draw_progress_overlay()
|
self.draw_progress_overlay()
|
||||||
self.__write_text()
|
self.write_text()
|
||||||
self.__roundcorners_border()
|
self.roundcorners_border()
|
||||||
|
|
||||||
# Drawn once, update width, eight
|
# Drawn once, update width, height
|
||||||
if self.__resized():
|
if self.resized():
|
||||||
self.__old_width = self.__width
|
self.prev_width = self.width
|
||||||
self.__old_height = self.__height
|
self.prev_height = self.height
|
||||||
|
|
||||||
def __roundcorners_clipping(self):
|
def roundcorners_clipping(self):
|
||||||
self.__create_roundcorners_subpath(
|
self.create_roundcorners_subpath(self.cr, 0, 0, self.width, self.height)
|
||||||
self.__cr, 0, 0, self.__width, self.__height
|
self.cr.clip()
|
||||||
)
|
|
||||||
self.__cr.clip()
|
|
||||||
|
|
||||||
def __roundcorners_border(self):
|
def roundcorners_border(self):
|
||||||
self.__create_roundcorners_subpath(
|
self.create_roundcorners_subpath(self.cr, 0.5, 0.5, self.width - 1, self.height - 1)
|
||||||
self.__cr, 0.5, 0.5, self.__width - 1, self.__height - 1
|
self.cr.set_source_rgba(0, 0, 0, 0.9)
|
||||||
)
|
self.cr.stroke()
|
||||||
self.__cr.set_source_rgba(0.0, 0.0, 0.0, 0.9)
|
|
||||||
self.__cr.stroke()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __create_roundcorners_subpath(ctx, x, y, width, height):
|
def create_roundcorners_subpath(ctx, x, y, width, height):
|
||||||
aspect = 1.0
|
aspect = 1.0
|
||||||
corner_radius = height / 10
|
corner_radius = height / 10
|
||||||
radius = corner_radius / aspect
|
radius = corner_radius / aspect
|
||||||
|
@ -109,145 +99,107 @@ class PiecesBar(gtk.DrawingArea):
|
||||||
ctx.close_path()
|
ctx.close_path()
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
def __draw_pieces(self):
|
def draw_pieces(self):
|
||||||
if not self.__pieces and not self.__num_pieces:
|
if not self.num_pieces:
|
||||||
# Nothing to draw.
|
# Nothing to draw.
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.__resized() or self.__pieces != self.__old_pieces or self.__pieces_overlay is None:
|
if self.resized() or self.pieces != self.prev_pieces or self.pieces_overlay is None:
|
||||||
# Need to recreate the cache drawing
|
# Need to recreate the cache drawing
|
||||||
self.__pieces_overlay = ImageSurface(FORMAT_ARGB32, self.__width, self.__height)
|
self.pieces_overlay = ImageSurface(FORMAT_ARGB32, self.width, self.height)
|
||||||
ctx = Context(self.__pieces_overlay)
|
ctx = Context(self.pieces_overlay)
|
||||||
|
|
||||||
start_pos = 0
|
if self.pieces:
|
||||||
if self.__pieces:
|
pieces = self.pieces
|
||||||
pieces = self.__pieces
|
elif self.num_pieces:
|
||||||
elif self.__num_pieces:
|
|
||||||
# Completed torrents do not send any pieces so create list using 'completed' state.
|
# Completed torrents do not send any pieces so create list using 'completed' state.
|
||||||
pieces = [COLOR_STATES.index("completed")] * self.__num_pieces
|
pieces = [COLOR_STATES.index("completed")] * self.num_pieces
|
||||||
piece_width = self.__width / len(pieces)
|
start_pos = 0
|
||||||
|
piece_width = self.width / len(pieces)
|
||||||
|
pieces_colors = [[color / 65535 for color in self.gtkui_config["pieces_color_%s" % state]]
|
||||||
|
for state in COLOR_STATES]
|
||||||
for state in pieces:
|
for state in pieces:
|
||||||
color = self.gtkui_config["pieces_color_%s" % COLOR_STATES[state]]
|
ctx.set_source_rgb(*pieces_colors[state])
|
||||||
ctx.set_source_rgb(color[0] / 65535, color[1] / 65535, color[2] / 65535)
|
ctx.rectangle(start_pos, 0, piece_width, self.height)
|
||||||
ctx.rectangle(start_pos, 0, piece_width, self.__height)
|
|
||||||
ctx.fill()
|
ctx.fill()
|
||||||
start_pos += piece_width
|
start_pos += piece_width
|
||||||
|
|
||||||
self.__cr.set_source_surface(self.__pieces_overlay)
|
self.cr.set_source_surface(self.pieces_overlay)
|
||||||
self.__cr.paint()
|
self.cr.paint()
|
||||||
|
|
||||||
def __draw_progress_overlay(self):
|
def draw_progress_overlay(self):
|
||||||
if not self.__state:
|
if not self.text:
|
||||||
# Nothing useful to draw, return now!
|
# Nothing useful to draw, return now!
|
||||||
return
|
return
|
||||||
if (self.__resized() or self.__fraction != self.__old_fraction) or self.__progress_overlay is None:
|
|
||||||
|
if self.resized() or self.fraction != self.prev_fraction or self.progress_overlay is None:
|
||||||
# Need to recreate the cache drawing
|
# Need to recreate the cache drawing
|
||||||
self.__progress_overlay = ImageSurface(FORMAT_ARGB32, self.__width, self.__height)
|
self.progress_overlay = ImageSurface(FORMAT_ARGB32, self.width, self.height)
|
||||||
ctx = Context(self.__progress_overlay)
|
ctx = Context(self.progress_overlay)
|
||||||
ctx.set_source_rgba(0.1, 0.1, 0.1, 0.3) # Transparent
|
ctx.set_source_rgba(0.1, 0.1, 0.1, 0.3) # Transparent
|
||||||
ctx.rectangle(0.0, 0.0, self.__width * self.__fraction, self.__height)
|
ctx.rectangle(0, 0, self.width * self.fraction, self.height)
|
||||||
ctx.fill()
|
ctx.fill()
|
||||||
self.__cr.set_source_surface(self.__progress_overlay)
|
self.cr.set_source_surface(self.progress_overlay)
|
||||||
self.__cr.paint()
|
self.cr.paint()
|
||||||
|
|
||||||
def __write_text(self):
|
def write_text(self):
|
||||||
if not self.__state:
|
if not self.text:
|
||||||
# Nothing useful to draw, return now!
|
# Nothing useful to draw, return now!
|
||||||
return
|
return
|
||||||
if (self.__resized() or self.__text != self.__old_text or
|
|
||||||
self.__fraction != self.__old_fraction or
|
if self.resized() or self.text != self.prev_text or self.text_overlay is None:
|
||||||
self.__state != self.__old_state or
|
|
||||||
self.__text_overlay is None):
|
|
||||||
# Need to recreate the cache drawing
|
# Need to recreate the cache drawing
|
||||||
self.__text_overlay = ImageSurface(FORMAT_ARGB32, self.__width, self.__height)
|
self.text_overlay = ImageSurface(FORMAT_ARGB32, self.width, self.height)
|
||||||
ctx = Context(self.__text_overlay)
|
ctx = Context(self.text_overlay)
|
||||||
pg = pangocairo.CairoContext(ctx)
|
pg = pangocairo.CairoContext(ctx)
|
||||||
pl = pg.create_layout()
|
pl = pg.create_layout()
|
||||||
pl.set_font_description(self.__text_font)
|
pl.set_font_description(self.text_font)
|
||||||
pl.set_width(-1) # No text wrapping
|
pl.set_width(-1) # No text wrapping
|
||||||
|
pl.set_text(self.text)
|
||||||
if self.__text:
|
|
||||||
text = self.__text
|
|
||||||
else:
|
|
||||||
text = fpcnt(self.__fraction, self.__state, self.__message)
|
|
||||||
|
|
||||||
log.trace("PiecesBar text %r", text)
|
|
||||||
pl.set_text(text)
|
|
||||||
plsize = pl.get_size()
|
plsize = pl.get_size()
|
||||||
text_width = plsize[0] // pango.SCALE
|
text_width = plsize[0] // pango.SCALE
|
||||||
text_height = plsize[1] // pango.SCALE
|
text_height = plsize[1] // pango.SCALE
|
||||||
area_width_without_text = self.__width - text_width
|
area_width_without_text = self.width - text_width
|
||||||
area_height_without_text = self.__height - text_height
|
area_height_without_text = self.height - text_height
|
||||||
ctx.move_to(area_width_without_text // 2, area_height_without_text // 2)
|
ctx.move_to(area_width_without_text // 2, area_height_without_text // 2)
|
||||||
ctx.set_source_rgb(1.0, 1.0, 1.0)
|
ctx.set_source_rgb(1, 1, 1)
|
||||||
pg.update_layout(pl)
|
pg.update_layout(pl)
|
||||||
pg.show_layout(pl)
|
pg.show_layout(pl)
|
||||||
self.__cr.set_source_surface(self.__text_overlay)
|
self.cr.set_source_surface(self.text_overlay)
|
||||||
self.__cr.paint()
|
self.cr.paint()
|
||||||
|
|
||||||
def __resized(self):
|
def resized(self):
|
||||||
return (self.__old_width != self.__width or
|
return self.prev_width != self.width or self.prev_height != self.height
|
||||||
self.__old_height != self.__height)
|
|
||||||
|
|
||||||
def set_fraction(self, fraction):
|
def set_fraction(self, fraction):
|
||||||
self.__old_fraction = self.__fraction
|
self.prev_fraction = self.fraction
|
||||||
self.__fraction = fraction
|
self.fraction = fraction
|
||||||
|
|
||||||
def get_fraction(self):
|
def get_fraction(self):
|
||||||
return self.__fraction
|
return self.fraction
|
||||||
|
|
||||||
def get_text(self):
|
def get_text(self):
|
||||||
return self.__text
|
return self.text
|
||||||
|
|
||||||
def set_text(self, text):
|
def set_text(self, text):
|
||||||
self.__old_text = self.__text
|
self.prev_text = self.text
|
||||||
self.__text = text
|
self.text = text
|
||||||
|
|
||||||
def get_status_message(self):
|
|
||||||
return self.__text
|
|
||||||
|
|
||||||
def set_status_message(self, message):
|
|
||||||
self.__old_message = self.__message
|
|
||||||
self.__message = message
|
|
||||||
|
|
||||||
def set_pieces(self, pieces, num_pieces):
|
def set_pieces(self, pieces, num_pieces):
|
||||||
self.__old_pieces = self.__pieces
|
self.prev_pieces = self.pieces
|
||||||
self.__pieces = pieces
|
self.pieces = pieces
|
||||||
self.__num_pieces = num_pieces
|
self.num_pieces = num_pieces
|
||||||
|
|
||||||
def get_pieces(self):
|
def get_pieces(self):
|
||||||
return self.__pieces
|
return self.pieces
|
||||||
|
|
||||||
def set_state(self, state):
|
|
||||||
self.__old_state = self.__state
|
|
||||||
self.__state = state
|
|
||||||
|
|
||||||
def get_state(self):
|
|
||||||
return self.__state
|
|
||||||
|
|
||||||
def update_from_status(self, status):
|
|
||||||
log.trace("Updating PiecesBar from status")
|
|
||||||
self.set_fraction(status["progress"] / 100)
|
|
||||||
torrent_state = status["state"]
|
|
||||||
self.set_state(torrent_state)
|
|
||||||
if torrent_state == "Checking":
|
|
||||||
self.update()
|
|
||||||
# Skip the pieces assignment
|
|
||||||
return
|
|
||||||
|
|
||||||
self.set_pieces(status['pieces'], status['num_pieces'])
|
|
||||||
self.set_status_message(status['message'])
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
self.__pieces = self.__old_pieces = ()
|
self.pieces = self.prev_pieces = ()
|
||||||
self.__num_pieces = self.__old_num_pieces = None
|
self.num_pieces = None
|
||||||
self.__text = self.__old_text = ""
|
self.text = self.prev_text = ""
|
||||||
self.__fraction = self.__old_fraction = 0.0
|
self.fraction = self.prev_fraction = 0
|
||||||
self.__state = self.__old_state = None
|
self.progress_overlay = self.text_overlay = self.pieces_overlay = None
|
||||||
self.__progress_overlay = self.__text_overlay = self.__pieces_overlay = None
|
self.cr = None
|
||||||
self.__cr = None
|
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
|
|
|
@ -28,13 +28,16 @@ class StatusTab(Tab):
|
||||||
# Get the labels we need to update.
|
# Get the labels we need to update.
|
||||||
# widget name, modifier function, status keys
|
# widget name, modifier function, status keys
|
||||||
self.builder = builder = component.get("MainWindow").get_builder()
|
self.builder = builder = component.get("MainWindow").get_builder()
|
||||||
self.progressbar = builder.get_object("progressbar")
|
|
||||||
|
|
||||||
self._name = "Status"
|
self._name = "Status"
|
||||||
self._child_widget = builder.get_object("status_tab")
|
self._child_widget = builder.get_object("status_tab")
|
||||||
self._tab_label = builder.get_object("status_tab_label")
|
self._tab_label = builder.get_object("status_tab_label")
|
||||||
self.config = ConfigManager("gtkui.conf")
|
self.config = ConfigManager("gtkui.conf")
|
||||||
|
|
||||||
|
self.progressbar = builder.get_object("progressbar")
|
||||||
|
self.piecesbar = None
|
||||||
|
self.piecesbar_label_widget = None
|
||||||
|
|
||||||
self.label_widgets = [
|
self.label_widgets = [
|
||||||
(builder.get_object("summary_availability"), fratio, ("distributed_copies",)),
|
(builder.get_object("summary_availability"), fratio, ("distributed_copies",)),
|
||||||
(builder.get_object("summary_total_downloaded"), ftotal_sized, ("all_time_download",
|
(builder.get_object("summary_total_downloaded"), ftotal_sized, ("all_time_download",
|
||||||
|
@ -56,18 +59,13 @@ class StatusTab(Tab):
|
||||||
]
|
]
|
||||||
|
|
||||||
self.status_keys = [status for widget in self.label_widgets for status in widget[2]]
|
self.status_keys = [status for widget in self.label_widgets for status in widget[2]]
|
||||||
|
|
||||||
self.piecesbar = None
|
|
||||||
self.config.register_set_function("show_piecesbar", self.on_show_piecesbar_config_changed, apply_now=True)
|
self.config.register_set_function("show_piecesbar", self.on_show_piecesbar_config_changed, apply_now=True)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
# Get the first selected torrent
|
# Get the first selected torrent
|
||||||
selected = component.get("TorrentView").get_selected_torrents()
|
selected = component.get("TorrentView").get_selected_torrent()
|
||||||
|
|
||||||
# Only use the first torrent in the list or return if None selected
|
if not selected:
|
||||||
if selected:
|
|
||||||
selected = selected[0]
|
|
||||||
else:
|
|
||||||
# No torrent is selected in the torrentview
|
# No torrent is selected in the torrentview
|
||||||
self.clear()
|
self.clear()
|
||||||
return
|
return
|
||||||
|
@ -75,14 +73,14 @@ class StatusTab(Tab):
|
||||||
# Get the torrent status
|
# Get the torrent status
|
||||||
status_keys = self.status_keys
|
status_keys = self.status_keys
|
||||||
if self.config['show_piecesbar']:
|
if self.config['show_piecesbar']:
|
||||||
status_keys = self.status_keys + ["pieces", "num_pieces"]
|
status_keys.extend(["pieces", "num_pieces"])
|
||||||
|
|
||||||
component.get("SessionProxy").get_torrent_status(
|
component.get("SessionProxy").get_torrent_status(
|
||||||
selected, status_keys).addCallback(self._on_get_torrent_status)
|
selected, status_keys).addCallback(self._on_get_torrent_status)
|
||||||
|
|
||||||
def _on_get_torrent_status(self, status):
|
def _on_get_torrent_status(self, status):
|
||||||
# Check to see if we got valid data from the core
|
# Check to see if we got valid data from the core
|
||||||
if status is None:
|
if not status:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Update all the label widgets
|
# Update all the label widgets
|
||||||
|
@ -91,11 +89,17 @@ class StatusTab(Tab):
|
||||||
if widget[0].get_text() != txt:
|
if widget[0].get_text() != txt:
|
||||||
widget[0].set_text(txt)
|
widget[0].set_text(txt)
|
||||||
|
|
||||||
# Do the progress bar because it's a special case (not a label)
|
# Update progress bar seperately as it's a special case (not a label).
|
||||||
if self.config['show_piecesbar']:
|
|
||||||
self.piecesbar.update_from_status(status)
|
|
||||||
else:
|
|
||||||
fraction = status["progress"] / 100
|
fraction = status["progress"] / 100
|
||||||
|
|
||||||
|
if self.config['show_piecesbar']:
|
||||||
|
if self.piecesbar.get_fraction() != fraction:
|
||||||
|
self.piecesbar.set_fraction(fraction)
|
||||||
|
if status["state"] != "Checking" and self.piecesbar.get_pieces() != status['pieces']:
|
||||||
|
# Skip pieces assignment if checking torrent.
|
||||||
|
self.piecesbar.set_pieces(status['pieces'], status['num_pieces'])
|
||||||
|
self.piecesbar.update()
|
||||||
|
else:
|
||||||
if self.progressbar.get_fraction() != fraction:
|
if self.progressbar.get_fraction() != fraction:
|
||||||
self.progressbar.set_fraction(fraction)
|
self.progressbar.set_fraction(fraction)
|
||||||
|
|
||||||
|
@ -109,6 +113,8 @@ class StatusTab(Tab):
|
||||||
if self.piecesbar is None:
|
if self.piecesbar is None:
|
||||||
self.piecesbar = PiecesBar()
|
self.piecesbar = PiecesBar()
|
||||||
self.builder.get_object("status_progress_vbox").pack_start(self.piecesbar, False, False, 0)
|
self.builder.get_object("status_progress_vbox").pack_start(self.piecesbar, False, False, 0)
|
||||||
|
self.piecesbar_label_widget = (self.piecesbar, fpcnt, ("progress", "state", "message"))
|
||||||
|
self.label_widgets.append(self.piecesbar_label_widget)
|
||||||
self.piecesbar.show()
|
self.piecesbar.show()
|
||||||
self.progressbar.hide()
|
self.progressbar.hide()
|
||||||
|
|
||||||
|
@ -116,7 +122,8 @@ class StatusTab(Tab):
|
||||||
self.progressbar.show()
|
self.progressbar.show()
|
||||||
if self.piecesbar:
|
if self.piecesbar:
|
||||||
self.piecesbar.hide()
|
self.piecesbar.hide()
|
||||||
self.piecesbar = None
|
self.label_widgets.remove(self.piecesbar_label_widget)
|
||||||
|
self.piecesbar = self.piecesbar_label_widget = None
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
for widget in self.label_widgets:
|
for widget in self.label_widgets:
|
||||||
|
@ -125,4 +132,4 @@ class StatusTab(Tab):
|
||||||
if self.config['show_piecesbar']:
|
if self.config['show_piecesbar']:
|
||||||
self.piecesbar.clear()
|
self.piecesbar.clear()
|
||||||
else:
|
else:
|
||||||
self.progressbar.set_fraction(0.0)
|
self.progressbar.set_fraction(0)
|
||||||
|
|
Loading…
Reference in New Issue