diff --git a/src/lifeblood_viewer/create_task_dialog.py b/src/lifeblood_viewer/create_task_dialog.py index 154a4073..650a7c03 100644 --- a/src/lifeblood_viewer/create_task_dialog.py +++ b/src/lifeblood_viewer/create_task_dialog.py @@ -2,7 +2,7 @@ from PySide2.QtWidgets import QWidget, QDialog, QVBoxLayout, QHBoxLayout, QLineEdit, QLabel, QMessageBox, QSpinBox, QPushButton from PySide2.QtCore import Slot, QSize -from typing import TYPE_CHECKING, Optional, Tuple, List, Set +from typing import TYPE_CHECKING, Optional, Tuple, List if TYPE_CHECKING: from .graphics_items import Task diff --git a/src/lifeblood_viewer/editor_scene_integration.py b/src/lifeblood_viewer/editor_scene_integration.py index b670b15c..a6bba4f1 100644 --- a/src/lifeblood_viewer/editor_scene_integration.py +++ b/src/lifeblood_viewer/editor_scene_integration.py @@ -1,22 +1,21 @@ from PySide2.QtCore import Qt, QTimer from PySide2.QtWidgets import QWidget from .code_editor.editor import StringParameterEditor +from .scene_data_controller import SceneDataController from lifeblood.enums import InvocationState from lifeblood.ui_protocol_data import InvocationLogData -from typing import Optional, TYPE_CHECKING -if TYPE_CHECKING: - from .graphics_scene_with_data_controller import QGraphicsImguiSceneWithDataController +from typing import Optional, Tuple -def fetch_and_open_log_viewer(scene: "QGraphicsImguiSceneWithDataController", invoc_id: int, parent_widget: QWidget, *, update_interval: Optional[float] = None): +def fetch_and_open_log_viewer(scene_data_controller: SceneDataController, invoc_id: int, parent_widget: QWidget, *, update_interval: Optional[float] = None): if update_interval is None: - scene.fetch_log_run_callback(invoc_id, _open_log_viewer, parent_widget) + scene_data_controller.fetch_log_run_callback(invoc_id, _open_log_viewer, parent_widget) else: - scene.fetch_log_run_callback(invoc_id, _open_log_viewer_with_update, (parent_widget, update_interval, invoc_id, scene)) + scene_data_controller.fetch_log_run_callback(invoc_id, _open_log_viewer_with_update, (parent_widget, update_interval, invoc_id, scene_data_controller)) -def _open_log_viewer(log, parent): +def _open_log_viewer(log: InvocationLogData, parent: QWidget): hl = StringParameterEditor.SyntaxHighlight.LOG wgt = StringParameterEditor(syntax_highlight=hl, parent=parent) wgt.setAttribute(Qt.WA_DeleteOnClose, True) @@ -26,8 +25,8 @@ def _open_log_viewer(log, parent): wgt.show() -def _open_log_viewer_with_update(log, callback_data): - parent, update_interval, invoc_id, scene = callback_data +def _open_log_viewer_with_update(log, callback_data: Tuple[QWidget, float, int, SceneDataController]): + parent, update_interval, invoc_id, scene_data_controller = callback_data hl = StringParameterEditor.SyntaxHighlight.LOG wgt = StringParameterEditor(syntax_highlight=hl, parent=parent) @@ -50,7 +49,7 @@ def _on_log_fetched(new_log: InvocationLogData, _): update_timer.start() # restart timer update_timer.timeout.connect( - lambda: scene.fetch_log_run_callback( + lambda: scene_data_controller.fetch_log_run_callback( invoc_id, _on_log_fetched ) diff --git a/src/lifeblood_viewer/graphics_items/graphics_items.py b/src/lifeblood_viewer/graphics_items/graphics_items.py index b7179aa9..fe0a26af 100644 --- a/src/lifeblood_viewer/graphics_items/graphics_items.py +++ b/src/lifeblood_viewer/graphics_items/graphics_items.py @@ -35,7 +35,7 @@ class TaskSortOrder(Enum): class PseudoNode(BaseNode): def __init__(self, my_node: "Node"): - super(Node.PseudoNode, self).__init__('_noname_') + super().__init__('_noname_') self.__my_node = my_node def _ui_changed(self, definition_changed=False): @@ -108,10 +108,10 @@ def output_connections(self, outname) -> Set["NodeConnection"]: raise RuntimeError(f'nodetype {self.__node_type} does not have output {outname}') return {x for x in self.__connections if x.output() == (self, outname)} - def input_names(self) -> Tuple[str]: + def input_names(self) -> Tuple[str, ...]: return tuple(self.__inputs) if self.__inputs else () - def output_names(self) -> tuple[str]: + def output_names(self) -> Tuple[str, ...]: return tuple(self.__outputs) if self.__outputs else () def input_nodes(self, inname: Optional[str] = None) -> Set["Node"]: diff --git a/src/lifeblood_viewer/graphics_items/graphics_scene_container.py b/src/lifeblood_viewer/graphics_items/graphics_scene_container.py index 61409a71..0341edd3 100644 --- a/src/lifeblood_viewer/graphics_items/graphics_scene_container.py +++ b/src/lifeblood_viewer/graphics_items/graphics_scene_container.py @@ -1,9 +1,10 @@ from lifeblood import logging from .graphics_scene_base import GraphicsSceneBase from .graphics_items import Node, Task, NodeConnection +from PySide2.QtCore import QPointF from types import MappingProxyType -from typing import Dict, Tuple, Mapping, Optional +from typing import Dict, Tuple, Mapping, Optional, Sequence logger = logging.get_logger('viewer') @@ -87,6 +88,15 @@ def clear(self): self.__node_dict = {} logger.debug('scene cleared') + # + + def move_nodes(self, nodes_datas: Sequence[Tuple[Node, QPointF]]): + """ + move nodes + """ + for node, pos in nodes_datas: + node.setPos(pos) + # settings # TODO: move to a dedicated settings provider def node_snapping_enabled(self): diff --git a/src/lifeblood_viewer/graphics_items/pretty_items/decorated_node.py b/src/lifeblood_viewer/graphics_items/pretty_items/decorated_node.py index fd29321e..59eedaa0 100644 --- a/src/lifeblood_viewer/graphics_items/pretty_items/decorated_node.py +++ b/src/lifeblood_viewer/graphics_items/pretty_items/decorated_node.py @@ -1,12 +1,12 @@ from .node_decorator_base import NodeDecorator, NodeDecoratorFactoryBase -from .drawable_node import DrawableNode +from .drawable_node_with_snap_points import DrawableNodeWithSnapPoints from ..graphics_scene_base import GraphicsSceneBase -from typing import Iterable, List, Optional, Tuple +from typing import Iterable, List -class DecoratedNode(DrawableNode): +class DecoratedNode(DrawableNodeWithSnapPoints): def __init__(self, scene: GraphicsSceneBase, id: int, type: str, name: str, node_decorator_factories: Iterable[NodeDecoratorFactoryBase] = ()): super().__init__(scene, id, type, name) diff --git a/src/lifeblood_viewer/graphics_items/pretty_items/drawable_node.py b/src/lifeblood_viewer/graphics_items/pretty_items/drawable_node.py index a9b711af..e27b5f45 100644 --- a/src/lifeblood_viewer/graphics_items/pretty_items/drawable_node.py +++ b/src/lifeblood_viewer/graphics_items/pretty_items/drawable_node.py @@ -2,7 +2,6 @@ from lifeblood.enums import TaskState from ..graphics_items import Node, Task from ..graphics_scene_base import GraphicsSceneBase -from ..node_connection_snap_point import NodeConnSnapPoint from .drawable_task import DrawableTask @@ -23,7 +22,7 @@ class DrawableNode(Node): def __init__(self, scene: GraphicsSceneBase, id: int, type: str, name: str): super().__init__(scene, id, type, name) - self.__visual_tasks: List[Task] = [] + self.__visual_tasks: List[DrawableTask] = [] # display self.__hoverover_pos: Optional[QPointF] = None @@ -98,7 +97,7 @@ def set_expanded(self, expanded: bool): self.__pivot_y = 0 # self.setPos(self.pos() - QPointF(0, 225 * 0.5)) # TODO: modify painterpath getters to avoid moving nodes on expand - for i, task in enumerate(self.tasks()): + for i, task in enumerate(self.drawable_tasks()): self.__make_task_child_with_position(task, *self.get_task_pos(task, i), animate=True) self.item_updated() @@ -138,27 +137,9 @@ def get_output_position(self, name: str = 'main', *, local: bool = False) -> QPo local ) - def input_snap_points(self) -> List[NodeConnSnapPoint]: - # TODO: cache snap points, don't recalc them every time - if self.get_nodeui() is None: - return [] - inputs = [] - for input_name in self.get_nodeui().inputs_names(): - inputs.append(NodeConnSnapPoint(self, input_name, True)) - return inputs - - def output_snap_points(self) -> List[NodeConnSnapPoint]: - # TODO: cache snap points, don't recalc them every time - if self.get_nodeui() is None: - return [] - outputs = [] - for output_name in self.get_nodeui().outputs_names(): - outputs.append(NodeConnSnapPoint(self, output_name, False)) - return outputs - # move animation - def get_task_pos(self, task: "Task", pos_id: int) -> Tuple[QPointF, int]: + def get_task_pos(self, task: DrawableTask, pos_id: int) -> Tuple[QPointF, int]: rect = self._get_bodyshape().boundingRect() x, y = rect.topLeft().toTuple() w, h = rect.size().toTuple() @@ -184,6 +165,12 @@ def __make_task_child_with_position(self, task: DrawableTask, pos: QPointF, laye else: task.set_task_position(self, pos, layer) + def drawable_tasks(self) -> Iterable[DrawableTask]: + for task in self.tasks(): + if not isinstance(task, DrawableTask): + continue + yield task + def add_task(self, task: Task): if not isinstance(task, DrawableTask): return super().add_task(task) @@ -215,7 +202,7 @@ def remove_tasks(self, tasks_to_remove: Iterable["Task"]): tasks_to_remove = set(tasks_to_remove) super().remove_tasks(tasks_to_remove) - self.__visual_tasks: List["Task"] = [None if x in tasks_to_remove else x for x in self.__visual_tasks] + self.__visual_tasks = [None if x in tasks_to_remove else x for x in self.__visual_tasks] off = 0 for i, task in enumerate(self.__visual_tasks): if task is None: @@ -229,6 +216,7 @@ def remove_tasks(self, tasks_to_remove: Iterable["Task"]): def remove_task(self, task_to_remove: "Task"): super().remove_task(task_to_remove) + assert isinstance(task_to_remove, DrawableTask) # TODO: see TODO in add_task task_pid = self.__visual_tasks.index(task_to_remove) for i in range(task_pid, len(self.__visual_tasks) - 1): diff --git a/src/lifeblood_viewer/graphics_items/pretty_items/drawable_node_with_snap_points.py b/src/lifeblood_viewer/graphics_items/pretty_items/drawable_node_with_snap_points.py index e69de29b..c813df78 100644 --- a/src/lifeblood_viewer/graphics_items/pretty_items/drawable_node_with_snap_points.py +++ b/src/lifeblood_viewer/graphics_items/pretty_items/drawable_node_with_snap_points.py @@ -0,0 +1,28 @@ +from .drawable_node import DrawableNode +from .node_connection_snap_point import NodeConnSnapPoint +from ..graphics_scene_base import GraphicsSceneBase + +from typing import List + + +class DrawableNodeWithSnapPoints(DrawableNode): + def __init__(self, scene: GraphicsSceneBase, id: int, type: str, name: str): + super().__init__(scene, id, type, name) + + def input_snap_points(self) -> List[NodeConnSnapPoint]: + # TODO: cache snap points, don't recalc them every time + if self.get_nodeui() is None: + return [] + inputs = [] + for input_name in self.get_nodeui().inputs_names(): + inputs.append(NodeConnSnapPoint(self, input_name, True)) + return inputs + + def output_snap_points(self) -> List[NodeConnSnapPoint]: + # TODO: cache snap points, don't recalc them every time + if self.get_nodeui() is None: + return [] + outputs = [] + for output_name in self.get_nodeui().outputs_names(): + outputs.append(NodeConnSnapPoint(self, output_name, False)) + return outputs diff --git a/src/lifeblood_viewer/graphics_items/pretty_items/drawable_task.py b/src/lifeblood_viewer/graphics_items/pretty_items/drawable_task.py index 2eb3184b..038ade5e 100644 --- a/src/lifeblood_viewer/graphics_items/pretty_items/drawable_task.py +++ b/src/lifeblood_viewer/graphics_items/pretty_items/drawable_task.py @@ -6,7 +6,6 @@ from ..graphics_items import Node, Task from ..graphics_scene_container import GraphicsSceneWithNodesAndTasks - from PySide2.QtCore import QAbstractAnimation, Slot, QPointF, QRectF, QSizeF, QSequentialAnimationGroup from PySide2.QtGui import QBrush, QColor, QPainter, QPainterPath, QPen from PySide2.QtWidgets import QGraphicsItem, QStyleOptionGraphicsItem, QWidget @@ -255,4 +254,4 @@ def hoverMoveEvent(self, event): def hoverLeaveEvent(self, event): self.__hoverover_pos = None - self.update() \ No newline at end of file + self.update() diff --git a/src/lifeblood_viewer/graphics_items/pretty_items/fancy_items/implicit_split_visualizer.py b/src/lifeblood_viewer/graphics_items/pretty_items/fancy_items/implicit_split_visualizer.py index 662675db..a290fcf9 100644 --- a/src/lifeblood_viewer/graphics_items/pretty_items/fancy_items/implicit_split_visualizer.py +++ b/src/lifeblood_viewer/graphics_items/pretty_items/fancy_items/implicit_split_visualizer.py @@ -1,5 +1,5 @@ from PySide2.QtWidgets import QWidget, QStyleOptionGraphicsItem -from PySide2.QtCore import Qt, Slot, QRectF, QPointF +from PySide2.QtCore import Qt, QRectF, QPointF from PySide2.QtGui import QPainterPath, QPainter, QBrush, QPen, QColor from typing import Optional diff --git a/src/lifeblood_viewer/graphics_items/pretty_items/fancy_items/scene_node.py b/src/lifeblood_viewer/graphics_items/pretty_items/fancy_items/scene_node.py index 0ed260be..ae763541 100644 --- a/src/lifeblood_viewer/graphics_items/pretty_items/fancy_items/scene_node.py +++ b/src/lifeblood_viewer/graphics_items/pretty_items/fancy_items/scene_node.py @@ -6,9 +6,10 @@ from lifeblood_viewer.graphics_items import Node from ...utils import call_later from ..decorated_node import DecoratedNode +from ..drawable_node_with_snap_points import DrawableNodeWithSnapPoints from ..node_connection_create_preview import NodeConnectionCreatePreview +from ..node_connection_snap_point import NodeConnSnapPoint from ...graphics_scene_container import GraphicsSceneWithNodesAndTasks -from ...node_connection_snap_point import NodeConnSnapPoint from lifeblood_viewer.scene_data_controller import SceneDataController from lifeblood_viewer.code_editor.editor import StringParameterEditor @@ -292,7 +293,7 @@ def mousePressEvent(self, event: QGraphicsSceneMouseEvent): for input in self.input_names(): inpos = self.get_input_position(input) if QPointF.dotProduct(inpos - pos, inpos - pos) <= r2 and wgt.request_ui_focus(self): - snap_points = [y for x in self.__scene_container.nodes() if x != self for y in x.output_snap_points()] + snap_points = [y for x in self.__scene_container.nodes() if x != self and isinstance(x, DrawableNodeWithSnapPoints) for y in x.output_snap_points()] displayer = NodeConnectionCreatePreview(None, self, '', input, snap_points, 15, self._ui_interactor_finished) self.scene().addItem(displayer) self.__ui_interactor = displayer @@ -305,7 +306,7 @@ def mousePressEvent(self, event: QGraphicsSceneMouseEvent): for output in self.output_names(): outpos = self.get_output_position(output) if QPointF.dotProduct(outpos - pos, outpos - pos) <= r2 and wgt.request_ui_focus(self): - snap_points = [y for x in self.__scene_container.nodes() if x != self for y in x.input_snap_points()] + snap_points = [y for x in self.__scene_container.nodes() if x != self and isinstance(x, DrawableNodeWithSnapPoints) for y in x.input_snap_points()] displayer = NodeConnectionCreatePreview(self, None, output, '', snap_points, 15, self._ui_interactor_finished) self.scene().addItem(displayer) self.__ui_interactor = displayer @@ -370,14 +371,21 @@ def mouseReleaseEvent(self, event: QGraphicsSceneMouseEvent): # return super().mouseReleaseEvent(event) if self.__move_start_position is not None: - if self.__scene_container.node_snapping_enabled(): - for node in self.__move_start_selection: - pos = node.pos() + # calc final pos if snapping is involved, + # then reset nodes to orig position and call scene's move_nodes so that proper op is generated + nodes_final_positions = [] + for node in self.__move_start_selection: + pos = node.pos() + if self.__scene_container.node_snapping_enabled(): snapx = node.base_width / 4 snapy = node.base_height / 4 - node.setPos(round(pos.x() / snapx) * snapx, - round(pos.y() / snapy) * snapy) - self.scene()._nodes_were_moved([(node, node.__move_start_position) for node in self.__move_start_selection]) + pos = QPointF(round(pos.x() / snapx) * snapx, + round(pos.y() / snapy) * snapy) + nodes_final_positions.append((node, pos)) + node.setPos(node.__move_start_position) + + self.__scene_container.move_nodes(nodes_final_positions) + #self.scene()._nodes_were_moved([(node, node.__move_start_position) for node in self.__move_start_selection]) for node in self.__move_start_selection: node.__move_start_position = None diff --git a/src/lifeblood_viewer/graphics_items/pretty_items/fancy_items/scene_node_connection.py b/src/lifeblood_viewer/graphics_items/pretty_items/fancy_items/scene_node_connection.py index a790d852..87b860c0 100644 --- a/src/lifeblood_viewer/graphics_items/pretty_items/fancy_items/scene_node_connection.py +++ b/src/lifeblood_viewer/graphics_items/pretty_items/fancy_items/scene_node_connection.py @@ -1,10 +1,11 @@ from math import sqrt from lifeblood import logging -from ...graphics_items import Node, NodeConnection +from ...graphics_items import NodeConnection from ...utils import call_later, length2 from ..node_connection_create_preview import NodeConnectionCreatePreview +from ..node_connection_snap_point import NodeConnSnapPoint +from ..drawable_node_with_snap_points import DrawableNodeWithSnapPoints from ...graphics_scene_container import GraphicsSceneWithNodesAndTasks -from ...node_connection_snap_point import NodeConnSnapPoint from lifeblood_viewer.scene_data_controller import SceneDataController from lifeblood_viewer.graphics_scene_viewing_widget import GraphicsSceneViewingWidgetBase @@ -13,14 +14,13 @@ from PySide2.QtGui import QColor, QPainter, QPainterPath, QPainterPathStroker, QPen from PySide2.QtWidgets import QGraphicsItem, QStyleOptionGraphicsItem, QGraphicsSceneMouseEvent, QWidget -from typing import Optional - +from typing import Optional, Tuple logger = logging.get_logger('viewer') class SceneNodeConnection(NodeConnection): - def __init__(self, scene: GraphicsSceneWithNodesAndTasks, id: int, nodeout: Node, nodein: Node, outname: str, inname: str, data_controller: SceneDataController): + def __init__(self, scene: GraphicsSceneWithNodesAndTasks, id: int, nodeout: DrawableNodeWithSnapPoints, nodein: DrawableNodeWithSnapPoints, outname: str, inname: str, data_controller: SceneDataController): super().__init__(scene, id, nodeout, nodein, outname, inname) self.__scene_container = scene self.__data_controller: SceneDataController = data_controller @@ -57,6 +57,16 @@ def __init__(self, scene: GraphicsSceneWithNodesAndTasks, id: int, nodeout: Node # to ensure correct interaction self.__ui_widget: Optional[GraphicsSceneViewingWidgetBase] = None + def output(self) -> Tuple[DrawableNodeWithSnapPoints, str]: + node, name = super().output() + assert isinstance(node, DrawableNodeWithSnapPoints) + return node, name + + def input(self) -> Tuple[DrawableNodeWithSnapPoints, str]: + node, name = super().input() + assert isinstance(node, DrawableNodeWithSnapPoints) + return node, name + def distance_to_point(self, pos: QPointF): """ returns approx distance to a given point @@ -202,9 +212,9 @@ def post_mousePressEvent(self, event: QGraphicsSceneMouseEvent): output_picked = d02 < d12 if output_picked: - snap_points = [y for x in self.__scene_container.nodes() if x != innode for y in x.output_snap_points()] + snap_points = [y for x in self.__scene_container.nodes() if x != innode and isinstance(x, DrawableNodeWithSnapPoints) for y in x.output_snap_points()] else: - snap_points = [y for x in self.__scene_container.nodes() if x != outnode for y in x.input_snap_points()] + snap_points = [y for x in self.__scene_container.nodes() if x != outnode and isinstance(x, DrawableNodeWithSnapPoints) for y in x.input_snap_points()] self.__ui_interactor = NodeConnectionCreatePreview(None if output_picked else outnode, innode if output_picked else None, outname, inname, diff --git a/src/lifeblood_viewer/graphics_items/pretty_items/fancy_items/scene_task.py b/src/lifeblood_viewer/graphics_items/pretty_items/fancy_items/scene_task.py index 00fe357f..f50b0c39 100644 --- a/src/lifeblood_viewer/graphics_items/pretty_items/fancy_items/scene_task.py +++ b/src/lifeblood_viewer/graphics_items/pretty_items/fancy_items/scene_task.py @@ -54,7 +54,7 @@ def set_groups(self, groups: Set[str]): def refresh_ui(self): """ unlike update - this method actually queries new task ui status - if task is not selected or not watched- does nothing + if task is not selected or not watched - does nothing :return: """ if not self.isSelected() and len(self.item_watchers()) == 0: @@ -184,7 +184,7 @@ def draw_imgui_elements(self, drawing_widget): else: if invoc_log.stdout: if imgui.button(f'open in viewer##{invoc_id}'): - fetch_and_open_log_viewer(self.scene(), invoc_id, drawing_widget, update_interval=None if invoc_log.invocation_state == InvocationState.FINISHED else 5) + fetch_and_open_log_viewer(self.__data_controller, invoc_id, drawing_widget, update_interval=None if invoc_log.invocation_state == InvocationState.FINISHED else 5) imgui.text_unformatted(invoc_log.stdout or '...nothing here...') if invoc_log.invocation_state == InvocationState.IN_PROGRESS: diff --git a/src/lifeblood_viewer/graphics_items/pretty_items/node_connection_create_preview.py b/src/lifeblood_viewer/graphics_items/pretty_items/node_connection_create_preview.py index e200810a..b24c5619 100644 --- a/src/lifeblood_viewer/graphics_items/pretty_items/node_connection_create_preview.py +++ b/src/lifeblood_viewer/graphics_items/pretty_items/node_connection_create_preview.py @@ -1,6 +1,6 @@ -from ..graphics_items import Node from ..utils import length2 -from ..node_connection_snap_point import NodeConnSnapPoint +from .drawable_node import DrawableNode +from .node_connection_snap_point import NodeConnSnapPoint from PySide2.QtCore import Qt, QPointF, QRectF from PySide2.QtGui import QColor, QPainter, QPainterPath, QPen @@ -10,7 +10,7 @@ class NodeConnectionCreatePreview(QGraphicsItem): - def __init__(self, nodeout: Optional[Node], nodein: Optional[Node], outname: str, inname: str, snap_points: List[NodeConnSnapPoint], snap_radius: float, report_done_here: Callable, do_cutting: bool = False): + def __init__(self, nodeout: Optional[DrawableNode], nodein: Optional[DrawableNode], outname: str, inname: str, snap_points: List[NodeConnSnapPoint], snap_radius: float, report_done_here: Callable, do_cutting: bool = False): super().__init__() assert nodeout is None and nodein is not None or \ nodeout is not None and nodein is None diff --git a/src/lifeblood_viewer/graphics_items/pretty_items/node_connection_snap_point.py b/src/lifeblood_viewer/graphics_items/pretty_items/node_connection_snap_point.py index 4dd4d582..5519de48 100644 --- a/src/lifeblood_viewer/graphics_items/pretty_items/node_connection_snap_point.py +++ b/src/lifeblood_viewer/graphics_items/pretty_items/node_connection_snap_point.py @@ -1,4 +1,4 @@ -from .graphics_items import Node +from .drawable_node import DrawableNode from PySide2.QtCore import QPointF @@ -8,13 +8,13 @@ def pos(self) -> QPointF: class NodeConnSnapPoint(SnapPoint): - def __init__(self, node: Node, connection_name: str, connection_is_input: bool): + def __init__(self, node: DrawableNode, connection_name: str, connection_is_input: bool): super().__init__() self.__node = node self.__conn_name = connection_name self.__isinput = connection_is_input - def node(self) -> Node: + def node(self) -> DrawableNode: return self.__node def connection_name(self) -> str: diff --git a/src/lifeblood_viewer/graphics_items/pretty_items/task_animation.py b/src/lifeblood_viewer/graphics_items/pretty_items/task_animation.py index 5121232c..ea1ac81f 100644 --- a/src/lifeblood_viewer/graphics_items/pretty_items/task_animation.py +++ b/src/lifeblood_viewer/graphics_items/pretty_items/task_animation.py @@ -4,7 +4,7 @@ class TaskAnimation(QAbstractAnimation): - def __init__(self, task: "Task", node1: "Node", pos1: "QPointF", node2: "Node", pos2: "QPointF", duration: int, parent): + def __init__(self, task: Task, node1: Node, pos1: QPointF, node2: Node, pos2: QPointF, duration: int, parent): super().__init__(parent) self.__task = task diff --git a/src/lifeblood_viewer/graphics_scene.py b/src/lifeblood_viewer/graphics_scene.py index cc4ee93c..eac2992a 100644 --- a/src/lifeblood_viewer/graphics_scene.py +++ b/src/lifeblood_viewer/graphics_scene.py @@ -3,7 +3,7 @@ from .graphics_items.graphics_scene_container import GraphicsSceneWithNodesAndTasks from .long_op import LongOperation, LongOperationData, LongOperationProcessor from .undo_stack import UndoStack, UndoableOperation -from PySide2.QtCore import Slot +from PySide2.QtCore import Signal, Slot from typing import Callable, Dict, Generator, List, Optional, Tuple @@ -11,6 +11,10 @@ class GraphicsScene(GraphicsSceneWithNodesAndTasks, LongOperationProcessor): + operation_started = Signal(int) # operation id + operation_progress_updated = Signal(int, str, float) # operation id, name, progress 0.0 - 1.0 + operation_finished = Signal(int) # operation id + def __init__(self, parent=None): super().__init__(parent=parent) self.__config = get_config('viewer') diff --git a/src/lifeblood_viewer/graphics_scene_with_data_controller.py b/src/lifeblood_viewer/graphics_scene_with_data_controller.py index 83f90bc5..36901cdd 100644 --- a/src/lifeblood_viewer/graphics_scene_with_data_controller.py +++ b/src/lifeblood_viewer/graphics_scene_with_data_controller.py @@ -94,11 +94,6 @@ class QGraphicsImguiSceneWithDataController(GraphicsScene, SceneDataController): task_invocation_job_fetched = Signal(int, InvocationJob) unhandled_error_happened = Signal(str) - # - operation_started = Signal(int) # operation id - operation_progress_updated = Signal(int, str, float) # operation id, name, progress 0.0 - 1.0 - operation_finished = Signal(int) # operation id - def __init__(self, scene_item_factory: SceneItemFactoryBase, db_path: str = None, worker: Optional["SchedulerConnectionWorker"] = None, parent=None): super(QGraphicsImguiSceneWithDataController, self).__init__(parent=parent) # to debug fuching bsp # self.setItemIndexMethod(QGraphicsScene.NoIndex) @@ -374,14 +369,13 @@ def skip_archived_groups(self) -> bool: # - def _nodes_were_moved(self, nodes_datas: Sequence[Tuple[Node, QPointF]]): + def move_nodes(self, nodes_datas: Sequence[Tuple[Node, QPointF]]): """ - item needs to notify the scene that move operation has happened, + on top of actual moving - scene needs to create an undo entry for that """ - op = MoveNodesOp(self, - ((node, node.pos(), old_pos) for node, old_pos in nodes_datas) + ((node, new_pos, node.pos()) for node, new_pos in nodes_datas) ) op.do() @@ -515,11 +509,6 @@ def rename_node(self, node_id: int, new_name: str, *, callback: Optional[Callabl # def fetch_log_run_callback(self, invocation_id, callback: Callable[[InvocationLogData, Any], None], callback_data: Any = None): - """ - fetch log for given invocation and run callback - - callback is run only in case of success - """ def _fetch_open_log_longop(longop: LongOperation): longop.set_op_status(None, f"fetching log for {invocation_id}") self.request_log(invocation_id, LongOperationData(longop)) @@ -655,7 +644,6 @@ def tasks_process_events(self, events: List[TaskEvent]): """ :param events: - :param first_time_getting_events: True if it's a first event batch since filter change :return: """ for event in events: @@ -733,7 +721,6 @@ def tasks_update(self, tasks_data: TaskBatchData): unlike tasks_full_update - this ONLY applies updates, does not delete anything :param tasks_data: - :param existing_tasks: optional already computed dict of existing tasks. if none - it will be computed :return: """ @@ -1025,7 +1012,7 @@ def get_node_by_session_id(self, node_session_id) -> Optional[Node]: node_id = self.session_node_id_to_id(node_session_id) if node_id is None: return None - return self.get_node(node_id, None) + return self.get_node(node_id) def find_nodes_by_name(self, name: str, match_partly=False) -> Set[Node]: if match_partly: diff --git a/src/lifeblood_viewer/models/multiple_sort_model.py b/src/lifeblood_viewer/models/multiple_sort_model.py index d8f98697..efdd72fd 100644 --- a/src/lifeblood_viewer/models/multiple_sort_model.py +++ b/src/lifeblood_viewer/models/multiple_sort_model.py @@ -1,6 +1,6 @@ from PySide2.QtCore import QAbstractItemModel, QObject, QSortFilterProxyModel -from typing import Any, Dict, Iterable, List, Optional +from typing import Dict, Iterable, List class MultipleFilterSortProxyModel(QSortFilterProxyModel): diff --git a/src/lifeblood_viewer/nodeeditor.py b/src/lifeblood_viewer/nodeeditor.py index 80d7e4e2..71c4f203 100644 --- a/src/lifeblood_viewer/nodeeditor.py +++ b/src/lifeblood_viewer/nodeeditor.py @@ -28,7 +28,7 @@ import PySide2.QtCore import PySide2.QtGui -from PySide2.QtWidgets import * +from PySide2.QtWidgets import QApplication, QDialog, QGraphicsView, QInputDialog, QLineEdit, QMenu, QMessageBox, QOpenGLWidget, QShortcut, QTextEdit, QVBoxLayout from PySide2.QtCore import QObject, Qt, Slot, QRectF, QPoint, QPointF, QEvent, QSize from PySide2.QtGui import QSurfaceFormat, QPainter, QTransform, QKeySequence, QCursor, QPen, QColor, QClipboard diff --git a/src/lifeblood_viewer/nodeeditor_overlays/overlay_base.py b/src/lifeblood_viewer/nodeeditor_overlays/overlay_base.py index 85208057..74332b4c 100644 --- a/src/lifeblood_viewer/nodeeditor_overlays/overlay_base.py +++ b/src/lifeblood_viewer/nodeeditor_overlays/overlay_base.py @@ -1,7 +1,7 @@ import re from lifeblood_viewer.graphics_scene_with_data_controller import QGraphicsImguiSceneWithDataController -from PySide2.QtCore import Qt, Slot, Signal, QRectF, QPointF -from PySide2.QtWidgets import QWidget, QGraphicsView +from PySide2.QtCore import QRectF +from PySide2.QtWidgets import QGraphicsView from PySide2.QtGui import QPainter, QMouseEvent diff --git a/src/lifeblood_viewer/nodeeditor_overlays/task_history_overlay.py b/src/lifeblood_viewer/nodeeditor_overlays/task_history_overlay.py index 2cfdfe0f..09882876 100644 --- a/src/lifeblood_viewer/nodeeditor_overlays/task_history_overlay.py +++ b/src/lifeblood_viewer/nodeeditor_overlays/task_history_overlay.py @@ -1,15 +1,12 @@ from datetime import timedelta from lifeblood.logging import get_logger -from lifeblood.ui_protocol_data import InvocationLogData -from lifeblood_viewer.code_editor.editor import StringParameterEditor -from lifeblood_viewer.long_op import LongOperation, LongOperationData from lifeblood_viewer.graphics_scene_with_data_controller import QGraphicsImguiSceneWithDataController from lifeblood_viewer.graphics_items import Task from lifeblood.enums import InvocationState -from PySide2.QtCore import Qt, Slot, Signal, QRectF, QPointF -from PySide2.QtWidgets import QWidget, QGraphicsView -from PySide2.QtGui import QPainter, QPainterPath, QPen, QColor, QMouseEvent +from PySide2.QtCore import Qt, QRectF, QPointF +from PySide2.QtWidgets import QGraphicsView +from PySide2.QtGui import QPainter, QPainterPath, QPen, QColor import imgui from ..editor_scene_integration import fetch_and_open_log_viewer diff --git a/src/lifeblood_viewer/nodeeditor_windows/ui_task_list_window.py b/src/lifeblood_viewer/nodeeditor_windows/ui_task_list_window.py index 7377714f..96f080ca 100644 --- a/src/lifeblood_viewer/nodeeditor_windows/ui_task_list_window.py +++ b/src/lifeblood_viewer/nodeeditor_windows/ui_task_list_window.py @@ -4,8 +4,7 @@ from lifeblood.enums import TaskState from lifeblood_viewer.nodeeditor import NodeEditor from lifeblood_viewer.ui_scene_elements import ImguiViewWindow -from ..graphics_items import Node, Task, NetworkItemWatcher -from PySide2.QtCore import QPoint +from ..graphics_items import Node, NetworkItemWatcher from PySide2.QtGui import QCursor from typing import Optional diff --git a/src/lifeblood_viewer/save_node_settings_dialog.py b/src/lifeblood_viewer/save_node_settings_dialog.py index 19169aae..17b5522a 100644 --- a/src/lifeblood_viewer/save_node_settings_dialog.py +++ b/src/lifeblood_viewer/save_node_settings_dialog.py @@ -1,5 +1,4 @@ from PySide2.QtWidgets import QDialog, QVBoxLayout, QCheckBox, QHBoxLayout, QPushButton, QLineEdit -from PySide2.QtCore import Slot, QSize from typing import Iterable diff --git a/src/lifeblood_viewer/scene_data_controller.py b/src/lifeblood_viewer/scene_data_controller.py index 93a3c44e..6ee0ac7f 100644 --- a/src/lifeblood_viewer/scene_data_controller.py +++ b/src/lifeblood_viewer/scene_data_controller.py @@ -2,6 +2,7 @@ from .long_op import LongOperation, LongOperationData from .ui_snippets import NodeSnippetData from lifeblood.uidata import Parameter +from lifeblood.ui_protocol_data import InvocationLogData from lifeblood.node_type_metadata import NodeTypeMetadata from lifeblood.enums import TaskState, TaskGroupArchivedState from lifeblood.taskspawn import NewTask @@ -177,5 +178,13 @@ def change_node_parameter(self, node_id: int, item: Parameter, value: Any = ..., """ raise NotImplementedError() + def fetch_log_run_callback(self, invocation_id, callback: Callable[[InvocationLogData, Any], None], callback_data: Any = None): + """ + fetch log for given invocation and run callback + + callback is run only in case of success + """ + raise NotImplementedError() + def node_types(self) -> MappingProxyType[str, NodeTypeMetadata]: raise NotImplementedError() diff --git a/src/lifeblood_viewer/ui_scene_elements.py b/src/lifeblood_viewer/ui_scene_elements.py index 13fc7a34..40e030ee 100644 --- a/src/lifeblood_viewer/ui_scene_elements.py +++ b/src/lifeblood_viewer/ui_scene_elements.py @@ -3,7 +3,7 @@ from .nodeeditor import NodeEditor from .graphics_scene_with_data_controller import QGraphicsImguiSceneWithDataController -from typing import Optional, Tuple +from typing import Tuple class ImguiViewWindow(ImguiWindow): diff --git a/src/lifeblood_viewer/widgets/flashy_label.py b/src/lifeblood_viewer/widgets/flashy_label.py index 13fe9f00..43ba6cdb 100644 --- a/src/lifeblood_viewer/widgets/flashy_label.py +++ b/src/lifeblood_viewer/widgets/flashy_label.py @@ -1,5 +1,5 @@ from PySide2.QtWidgets import QLabel -from PySide2.QtGui import QPalette, QColor, QFont, QFontMetrics +from PySide2.QtGui import QFont, QFontMetrics from PySide2.QtCore import QTimer, Qt from typing import Tuple diff --git a/src/lifeblood_viewer/widgets/worker_list.py b/src/lifeblood_viewer/widgets/worker_list.py index cc4b9bac..90c85220 100644 --- a/src/lifeblood_viewer/widgets/worker_list.py +++ b/src/lifeblood_viewer/widgets/worker_list.py @@ -1,18 +1,18 @@ from datetime import datetime from dataclasses import dataclass -from lifeblood.ui_protocol_data import UiData, WorkerData, WorkerBatchData, WorkerResources, WorkerMetadata +from lifeblood.ui_protocol_data import WorkerData, WorkerBatchData, WorkerResources, WorkerMetadata from lifeblood.enums import WorkerType, WorkerState from lifeblood.text import nice_memory_formatting from lifeblood.logging import get_logger -from lifeblood.misc import timeit, performance_measurer +from lifeblood.misc import performance_measurer from lifeblood_viewer.connection_worker import SchedulerConnectionWorker from lifeblood_viewer.models.multiple_sort_model import MultipleFilterSortProxyModel -from PySide2.QtWidgets import QWidget, QTableView, QTreeView, QHBoxLayout, QVBoxLayout, QHeaderView, QMenu, QLineEdit -from PySide2.QtCore import Slot, Signal, Qt, QAbstractItemModel, QAbstractTableModel, QModelIndex, QSortFilterProxyModel, QAbstractProxyModel, QPoint, QObject +from PySide2.QtWidgets import QWidget, QTreeView, QHBoxLayout, QVBoxLayout, QMenu, QLineEdit +from PySide2.QtCore import Slot, Signal, Qt, QAbstractItemModel, QModelIndex, QPoint from PySide2.QtGui import QColor -from typing import Any, Dict, Iterable, List, Optional, Set, Tuple, Union +from typing import Any, Dict, List, Optional, Set, Tuple, Union _init_column_order_prototype = ('id', 'state', 'progress', 'task_id', 'metadata.hostname', 'last_address', 'last_seen', '__resources__', 'devices', 'groups', 'worker_type')