Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions scrutiny/gui/assets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ class Icons(enum.Enum):
HMILine = "hmi_line"
HMIColorIndicator = "hmi_color_indicator"
HMIButton = "hmi_button"
HMISlider = "hmi_slider"


_filename_cache: Dict[Tuple[Icons, IconFormat, IconSet], Path] = {}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added scrutiny/gui/assets/icons/dark/hmi_slider_8x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added scrutiny/gui/assets/icons/light/hmi_slider_8x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 10 additions & 9 deletions scrutiny/gui/components/locals/hmi/hmi_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,25 +208,26 @@ def load_state(self, state: Dict[Any, Any]) -> bool:
validation.assert_dict_key(state_cast, 'hmi_widgets', list)
validation.assert_dict_key(state_cast, 'workzone_size', (list, tuple))

def read_pair(d: Any, key: str) -> Tuple[int, int]:
def read_posint_pair(d: Any, key: str) -> Tuple[int, int]:
validation.assert_dict_key(d, key, (tuple, list))
v = d[key]
assert len(v) == 2, "Invalid size"
assert isinstance(v[0], int), "Invalid size"
assert isinstance(v[1], int), "Invalid size"
assert len(v) == 2, f"Invalid {key}"
assert isinstance(v[0], int), f"Invalid {key}"
assert isinstance(v[1], int), f"Invalid {key}"
if v[0] < 0 or v[1] < 0:
raise ValueError("Invalid Size")
raise ValueError(f"Invalid {key}")
return tuple(v)

def read_size(d: Any, key: str) -> QSize:
pair = read_pair(d, key)
pair = read_posint_pair(d, key)
return QSize(pair[0], pair[1])

def read_pos(d: Any, key: str) -> QPoint:
pair = read_pair(d, key)
pair = read_posint_pair(d, key)
return QPoint(pair[0], pair[1])

workszone_size = read_size(state_cast, 'workzone_size')
self._workzone.setSceneRect(QRect(QPoint(0, 0), workszone_size))
self._workzone.resize(workszone_size)

fully_loaded_ok = True
Expand Down Expand Up @@ -337,7 +338,7 @@ def delete_hmi_widget(self, widget: BaseHMIWidget) -> None:
self._awaiting_delete_set.add(widget.instance_id)
widget.add_del_callback(functools.partial(self._hmi_widget_del_callback, widget.instance_id))

fn = functools.partial(self.check_is_deleted, widget.instance_id, widget.get_display_name())
fn = functools.partial(self._check_is_deleted, widget.instance_id, widget.get_display_name())
invoke_later(fn)
gc.collect()

Expand Down Expand Up @@ -518,7 +519,7 @@ def _hmi_widget_del_callback(self, instance_id: int) -> None:
if instance_id in self._awaiting_delete_set:
self._awaiting_delete_set.remove(instance_id)

def check_is_deleted(self, instance_id: int, name: str) -> None:
def _check_is_deleted(self, instance_id: int, name: str) -> None:
if instance_id in self._awaiting_delete_set:
self.logger.warning(f"Dangling reference to widget {name} after deletion")

Expand Down
15 changes: 10 additions & 5 deletions scrutiny/gui/components/locals/hmi/hmi_widgets/base_hmi_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ class ValueOverride:
"""A unique ID used to subscribe to value update"""
last_value_received: WatchableValueType
"""Last value received"""
last_value_drawn: WatchableValueType
"""Last value drawn. Used to avoid unnecessary redraw"""
require_redraw: bool
"""A flag that indicate if a redraw of the HMI widget is required when the value of this slot changes"""
value_update_callback: Optional[HMIWidgetValueUpdateCallback]
Expand All @@ -106,6 +108,7 @@ def __init__(self,
self.watchable_line_edit = WatchableLineEdit()
self.watcher_id = f'{name}{global_i64_counter()}'
self.last_value_received = None
self.last_value_drawn = None
self.value_update_callback = value_update_callback
self.require_redraw = require_redraw
self.value_override = None
Expand Down Expand Up @@ -307,6 +310,7 @@ class _Signals(QObject):
_del_callback: List[Callable[[], None]]
"""A list of callbacks to call when this object is garbage collected."""
_hit_zone: Optional[BaseHitZone]
"""Object used for knowing if a position is on a visible section of the drawing. Like QT Shape(), but owned but used by the Workzone"""

def __init__(self, app: AbstractComponentAppInterface) -> None:
super().__init__()
Expand Down Expand Up @@ -627,9 +631,9 @@ def _get_vslot_by_name_or_raise(self, name: str) -> ValueSlot:

def _slot_value_update_callback(self, vslot: ValueSlot, val: WatchableValueType) -> None:
"""The callback invoked when a ValueSlot value changes"""
value_changed = (vslot.last_value_received != val)
value_changed = (vslot.last_value_drawn != val)

if value_changed: # Avoid redrawing when not necessary
if value_changed:
if vslot.value_update_callback is not None:
vslot.value_update_callback(val)

Expand Down Expand Up @@ -690,7 +694,7 @@ def get_vslot_val_by_name(self, name: str) -> WatchableValueType:
vslot = self._get_vslot_by_name_or_raise(name)
return vslot.get_val()

def _get_vslot_vals(self) -> Dict[str, Optional[WatchableValueType]]:
def _get_vslot_vals_for_draw(self) -> Dict[str, Optional[WatchableValueType]]:
"""Read and returns the actual values of each ValueSlot"""

def compute_single(vslot: ValueSlot) -> Optional[WatchableValueType]:
Expand All @@ -705,7 +709,8 @@ def compute_single(vslot: ValueSlot) -> Optional[WatchableValueType]:
if node is None:
return None

return vslot.get_val()
vslot.last_value_drawn = vslot.get_val()
return vslot.last_value_drawn

return {vslot.name: compute_single(vslot) for vslot in self._vslots}

Expand Down Expand Up @@ -742,7 +747,7 @@ def paint(self, painter: QPainter, option: QStyleOptionGraphicsItem, widget: Opt
self._pending_redraw = False
self._need_redraw = False

values = self._get_vslot_vals()
values = self._get_vslot_vals_for_draw()
painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)

self.draw(values, self._edit_mode, painter)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import enum
import math

from PySide6.QtGui import QPainter, QPainterPath, QPen, QBrush
from PySide6.QtGui import QPainter, QPen, QBrush
from PySide6.QtCore import QSize, Qt, QPointF, QRectF, QSizeF
from PySide6.QtWidgets import QGraphicsSceneMouseEvent, QVBoxLayout, QWidget, QGroupBox, QComboBox, QFormLayout, QLineEdit

Expand Down Expand Up @@ -183,10 +183,6 @@ def min_width(self) -> int:
def get_config_widget(self) -> QWidget:
return self._config_widget

def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent) -> None:
print("move")
return super().mouseMoveEvent(event)

def draw(self,
values: Dict[str, Optional[WatchableValueType]],
edit_mode: bool,
Expand Down
Loading
Loading