Commit ae16a549 authored by Roman Alifanov's avatar Roman Alifanov

widgets: add info_graph widget

parent cc631d3b
from gi.repository import Adw, Gtk
from .BaseWidget import BaseWidget
class InfoGraphWidget(BaseWidget):
def __init__(self, setting):
super().__init__(setting)
self.history = []
self.max_points = setting.map.get('points', 60) if setting.map else 60
self.min_value = setting.map.get('min', 0) if setting.map else 0
self.max_value = setting.map.get('max', 100) if setting.map else 100
self.color = setting.map.get('color', '#3584e4') if setting.map else '#3584e4'
self.suffix = setting.map.get('suffix', '%') if setting.map else '%'
def create_row(self):
self.row = Adw.ActionRow(
title=self.setting.name,
subtitle=self.setting.help
)
box = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL,
spacing=12,
valign=Gtk.Align.CENTER
)
self.value_label = Gtk.Label(
label="--",
width_chars=6,
xalign=1.0
)
self.value_label.add_css_class("title-4")
self.drawing_area = Gtk.DrawingArea()
self.drawing_area.set_size_request(120, 32)
self.drawing_area.set_draw_func(self._draw_graph)
box.append(self.value_label)
box.append(self.drawing_area)
self.row.add_suffix(box)
return self.row
def _parse_color(self, color_str):
if color_str.startswith('#'):
color_str = color_str[1:]
r = int(color_str[0:2], 16) / 255.0
g = int(color_str[2:4], 16) / 255.0
b = int(color_str[4:6], 16) / 255.0
return r, g, b
def _draw_graph(self, area, cr, width, height):
if not self.history:
return
r, g, b = self._parse_color(self.color)
cr.set_source_rgba(r, g, b, 0.1)
cr.rectangle(0, 0, width, height)
cr.fill()
cr.set_source_rgba(r, g, b, 0.3)
cr.set_line_width(1)
cr.rectangle(0.5, 0.5, width - 1, height - 1)
cr.stroke()
if len(self.history) < 2:
return
cr.set_source_rgba(r, g, b, 0.2)
value_range = self.max_value - self.min_value
if value_range == 0:
value_range = 1
points = []
step = width / (self.max_points - 1)
start_x = width - (len(self.history) - 1) * step
for i, value in enumerate(self.history):
x = start_x + i * step
normalized = (value - self.min_value) / value_range
y = height - (normalized * (height - 4)) - 2
points.append((x, y))
cr.move_to(points[0][0], height)
cr.line_to(points[0][0], points[0][1])
for x, y in points[1:]:
cr.line_to(x, y)
cr.line_to(points[-1][0], height)
cr.close_path()
cr.fill()
cr.set_source_rgb(r, g, b)
cr.set_line_width(1.5)
cr.move_to(points[0][0], points[0][1])
for x, y in points[1:]:
cr.line_to(x, y)
cr.stroke()
def update_display(self):
value = self.setting._current_value
if value is not None:
try:
value = float(value)
self.history.append(value)
if len(self.history) > self.max_points:
self.history.pop(0)
self.value_label.set_label(f"{value:.1f}{self.suffix}")
self.drawing_area.queue_draw()
except (ValueError, TypeError):
pass
......@@ -9,6 +9,7 @@ from .FileChooser import FileChooser
from .ButtonWidget import ButtonWidget
from .InfoLabelWidget import InfoLabelWidget
from .InfoDictWidget import InfoDictWidget
from .InfoGraphWidget import InfoGraphWidget
from .DualListWidget import DualListWidget
from .ImageChooserWidget import ImageChooserWidget
from .DualImageChooserWidget import DualImageChooserWidget
......@@ -31,6 +32,7 @@ class WidgetFactory:
'button': ButtonWidget,
'info_label': InfoLabelWidget,
'info_dict': InfoDictWidget,
'info_graph': InfoGraphWidget,
'list_dual': DualListWidget,
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment