diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 21:38:38 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 21:38:38 +0000 |
commit | 2e2851dc13d73352530dd4495c7e05603b2e520d (patch) | |
tree | 622b9cd8e5d32091c9aa9e4937b533975a40356c /deluge/plugins/Scheduler/deluge_scheduler/gtkui.py | |
parent | Initial commit. (diff) | |
download | deluge-upstream/2.1.2_dev0+20240219.tar.xz deluge-upstream/2.1.2_dev0+20240219.zip |
Adding upstream version 2.1.2~dev0+20240219.upstream/2.1.2_dev0+20240219upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'deluge/plugins/Scheduler/deluge_scheduler/gtkui.py')
-rw-r--r-- | deluge/plugins/Scheduler/deluge_scheduler/gtkui.py | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/deluge/plugins/Scheduler/deluge_scheduler/gtkui.py b/deluge/plugins/Scheduler/deluge_scheduler/gtkui.py new file mode 100644 index 0000000..16222c8 --- /dev/null +++ b/deluge/plugins/Scheduler/deluge_scheduler/gtkui.py @@ -0,0 +1,356 @@ +# +# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com> +# +# Basic plugin template created by: +# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com> +# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com> +# +# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with +# the additional special exception to link portions of this program with the OpenSSL library. +# See LICENSE for more details. +# + +import logging + +from gi.repository import Gdk, Gtk + +import deluge.component as component +from deluge.plugins.pluginbase import Gtk3PluginBase +from deluge.ui.client import client + +from .common import get_resource + +log = logging.getLogger(__name__) + +DAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] + + +class SchedulerSelectWidget(Gtk.DrawingArea): + def __init__(self, hover): + super().__init__() + self.set_events( + Gdk.EventMask.BUTTON_PRESS_MASK + | Gdk.EventMask.BUTTON_RELEASE_MASK + | Gdk.EventMask.POINTER_MOTION_MASK + | Gdk.EventMask.LEAVE_NOTIFY_MASK + ) + + self.connect('draw', self.draw) + self.connect('button_press_event', self.mouse_down) + self.connect('button_release_event', self.mouse_up) + self.connect('motion_notify_event', self.mouse_hover) + self.connect('leave_notify_event', self.mouse_leave) + + self.colors = [ + [115 / 255, 210 / 255, 22 / 255], + [237 / 255, 212 / 255, 0 / 255], + [204 / 255, 0 / 255, 0 / 255], + ] + self.button_state = [[0] * 7 for dummy in range(24)] + + self.start_point = [0, 0] + self.hover_point = [-1, -1] + self.hover_label = hover + self.hover_days = DAYS + self.mouse_press = False + self.set_size_request(350, 150) + + def set_button_state(self, state): + self.button_state = [] + for s in state: + self.button_state.append(list(s)) + log.debug(self.button_state) + + # redraw the whole thing + def draw(self, widget, context): + width = widget.get_allocated_width() + height = widget.get_allocated_height() + context.rectangle(0, 0, width, height) + context.clip() + + for y in range(7): + for x in range(24): + context.set_source_rgba( + self.colors[self.button_state[x][y]][0], + self.colors[self.button_state[x][y]][1], + self.colors[self.button_state[x][y]][2], + 0.5, + ) + context.rectangle( + width * (6 * x / 145 + 1 / 145), + height * (6 * y / 43 + 1 / 43), + 6 * width / 145, + 5 * height / 43, + ) + context.fill_preserve() + context.set_source_rgba(0, 0, 0, 0.7) + context.set_line_width(1) + context.stroke() + + # coordinates --> which box + def get_point(self, event): + width = self.get_allocated_width() + height = self.get_allocated_height() + x = int((event.x - width * 0.5 / 145) / (6 * width / 145)) + y = int((event.y - height * 0.5 / 43) / (6 * height / 43)) + + if x > 23: + x = 23 + elif x < 0: + x = 0 + if y > 6: + y = 6 + elif y < 0: + y = 0 + + return [x, y] + + # mouse down + def mouse_down(self, widget, event): + self.mouse_press = True + self.start_point = self.get_point(event) + + # if the same box -> change it + def mouse_up(self, widget, event): + self.mouse_press = False + end_point = self.get_point(event) + + # change color on mouseclick depending on the button + if end_point[0] is self.start_point[0] and end_point[1] is self.start_point[1]: + if event.button == 1: + self.button_state[end_point[0]][end_point[1]] += 1 + if self.button_state[end_point[0]][end_point[1]] > 2: + self.button_state[end_point[0]][end_point[1]] = 0 + elif event.button == 3: + self.button_state[end_point[0]][end_point[1]] -= 1 + if self.button_state[end_point[0]][end_point[1]] < 0: + self.button_state[end_point[0]][end_point[1]] = 2 + self.queue_draw() + + # if box changed and mouse is pressed draw all boxes from start point to end point + # set hover text etc.. + def mouse_hover(self, widget, event): + if self.get_point(event) != self.hover_point: + self.hover_point = self.get_point(event) + + self.hover_label.set_text( + self.hover_days[self.hover_point[1]] + + ' ' + + str(self.hover_point[0]) + + ':00 - ' + + str(self.hover_point[0]) + + ':59' + ) + + if self.mouse_press: + points = [ + [self.hover_point[0], self.start_point[0]], + [self.hover_point[1], self.start_point[1]], + ] + + for x in range(min(points[0]), max(points[0]) + 1): + for y in range(min(points[1]), max(points[1]) + 1): + self.button_state[x][y] = self.button_state[ + self.start_point[0] + ][self.start_point[1]] + + self.queue_draw() + + # clear hover text on mouse leave + def mouse_leave(self, widget, event): + self.hover_label.set_text('') + self.hover_point = [-1, -1] + + +class GtkUI(Gtk3PluginBase): + def enable(self): + self.create_prefs_page() + + component.get('PluginManager').register_hook( + 'on_apply_prefs', self.on_apply_prefs + ) + component.get('PluginManager').register_hook( + 'on_show_prefs', self.on_show_prefs + ) + self.statusbar = component.get('StatusBar') + self.status_item = self.statusbar.add_item( + image=get_resource('green.svg'), + text='', + callback=self.on_status_item_clicked, + tooltip='Scheduler', + ) + + def on_state_deferred(state): + self.state = state + self.on_scheduler_event(state) + + self.on_show_prefs() + + client.scheduler.get_state().addCallback(on_state_deferred) + client.register_event_handler('SchedulerEvent', self.on_scheduler_event) + + def disable(self): + component.get('Preferences').remove_page(_('Scheduler')) + # Reset statusbar dict. + self.statusbar.config_value_changed_dict[ + 'max_download_speed' + ] = self.statusbar._on_max_download_speed + self.statusbar.config_value_changed_dict[ + 'max_upload_speed' + ] = self.statusbar._on_max_upload_speed + # Remove statusbar item. + self.statusbar.remove_item(self.status_item) + del self.status_item + + component.get('PluginManager').deregister_hook( + 'on_apply_prefs', self.on_apply_prefs + ) + component.get('PluginManager').deregister_hook( + 'on_show_prefs', self.on_show_prefs + ) + + def on_apply_prefs(self): + log.debug('applying prefs for Scheduler') + config = {} + config['low_down'] = self.spin_download.get_value() + config['low_up'] = self.spin_upload.get_value() + config['low_active'] = self.spin_active.get_value_as_int() + config['low_active_down'] = self.spin_active_down.get_value_as_int() + config['low_active_up'] = self.spin_active_up.get_value_as_int() + config['button_state'] = self.scheduler_select.button_state + client.scheduler.set_config(config) + + def on_show_prefs(self): + def on_get_config(config): + log.debug('config: %s', config) + self.scheduler_select.set_button_state(config['button_state']) + self.spin_download.set_value(config['low_down']) + self.spin_upload.set_value(config['low_up']) + self.spin_active.set_value(config['low_active']) + self.spin_active_down.set_value(config['low_active_down']) + self.spin_active_up.set_value(config['low_active_up']) + + client.scheduler.get_config().addCallback(on_get_config) + + def on_scheduler_event(self, state): + self.state = state + self.status_item.set_image_from_file(get_resource(self.state.lower() + '.svg')) + if self.state == 'Yellow': + # Prevent func calls in Statusbar if the config changes. + self.statusbar.config_value_changed_dict.pop('max_download_speed', None) + self.statusbar.config_value_changed_dict.pop('max_upload_speed', None) + try: + self.statusbar._on_max_download_speed(self.spin_download.get_value()) + self.statusbar._on_max_upload_speed(self.spin_upload.get_value()) + except AttributeError: + # Skip error due to Plugin being enabled before statusbar items created on startup. + pass + else: + self.statusbar.config_value_changed_dict[ + 'max_download_speed' + ] = self.statusbar._on_max_download_speed + self.statusbar.config_value_changed_dict[ + 'max_upload_speed' + ] = self.statusbar._on_max_upload_speed + + def update_config_values(config): + try: + self.statusbar._on_max_download_speed(config['max_download_speed']) + self.statusbar._on_max_upload_speed(config['max_upload_speed']) + except AttributeError: + # Skip error due to Plugin being enabled before statusbar items created on startup. + pass + + client.core.get_config_values( + ['max_download_speed', 'max_upload_speed'] + ).addCallback(update_config_values) + + def on_status_item_clicked(self, widget, event): + component.get('Preferences').show('Scheduler') + + # Configuration dialog + def create_prefs_page(self): + # Select Widget + hover = Gtk.Label() + self.scheduler_select = SchedulerSelectWidget(hover) + + vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, spacing=5) + hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, spacing=5) + vbox_days = Gtk.Box.new(Gtk.Orientation.VERTICAL, spacing=0) + for day in DAYS: + vbox_days.pack_start(Gtk.Label(day, xalign=0), True, False, 0) + hbox.pack_start(vbox_days, False, False, 15) + hbox.pack_start(self.scheduler_select, True, True, 0) + frame = Gtk.Frame() + label = Gtk.Label() + label.set_markup(_('<b>Schedule</b>')) + frame.set_label_widget(label) + frame.set_shadow_type(Gtk.ShadowType.NONE) + frame.set_margin_left(15) + frame.add(hbox) + + vbox.pack_start(frame, False, False, 0) + vbox.pack_start(hover, False, False, 0) + + table = Gtk.Table(5, 2) + table.set_margin_left(15) + + label = Gtk.Label(_('Download Limit:')) + label.set_alignment(0.0, 0.6) + table.attach_defaults(label, 0, 1, 0, 1) + self.spin_download = Gtk.SpinButton() + self.spin_download.set_numeric(True) + self.spin_download.set_range(-1.0, 99999.0) + self.spin_download.set_increments(1, 10) + table.attach_defaults(self.spin_download, 1, 2, 0, 1) + + label = Gtk.Label(_('Upload Limit:')) + label.set_alignment(0.0, 0.6) + table.attach_defaults(label, 0, 1, 1, 2) + self.spin_upload = Gtk.SpinButton() + self.spin_upload.set_numeric(True) + self.spin_upload.set_range(-1.0, 99999.0) + self.spin_upload.set_increments(1, 10) + table.attach_defaults(self.spin_upload, 1, 2, 1, 2) + + label = Gtk.Label(_('Active Torrents:')) + label.set_alignment(0.0, 0.6) + table.attach_defaults(label, 0, 1, 2, 3) + self.spin_active = Gtk.SpinButton() + self.spin_active.set_numeric(True) + self.spin_active.set_range(-1, 9999) + self.spin_active.set_increments(1, 10) + table.attach_defaults(self.spin_active, 1, 2, 2, 3) + + label = Gtk.Label(_('Active Downloading:')) + label.set_alignment(0.0, 0.6) + table.attach_defaults(label, 0, 1, 3, 4) + self.spin_active_down = Gtk.SpinButton() + self.spin_active_down.set_numeric(True) + self.spin_active_down.set_range(-1, 9999) + self.spin_active_down.set_increments(1, 10) + table.attach_defaults(self.spin_active_down, 1, 2, 3, 4) + + label = Gtk.Label(_('Active Seeding:')) + label.set_alignment(0.0, 0.6) + table.attach_defaults(label, 0, 1, 4, 5) + self.spin_active_up = Gtk.SpinButton() + self.spin_active_up.set_numeric(True) + self.spin_active_up.set_range(-1, 9999) + self.spin_active_up.set_increments(1, 10) + table.attach_defaults(self.spin_active_up, 1, 2, 4, 5) + + eventbox = Gtk.EventBox() + eventbox.add(table) + frame = Gtk.Frame() + label = Gtk.Label() + label.set_markup(_('<b>Slow Settings</b>')) + label.modify_bg(Gtk.StateFlags.NORMAL, Gdk.color_parse('#EDD400')) + frame.set_label_widget(label) + frame.set_margin_left(15) + frame.set_border_width(2) + frame.add(eventbox) + vbox.pack_start(frame, False, False, 0) + + vbox.show_all() + component.get('Preferences').add_page(_('Scheduler'), vbox) |