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
31 changes: 31 additions & 0 deletions pySimBlocks/gui/graphics/block_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ def __init__(self,
self._resize_start_pos: QPointF | None = None
self._resize_start_width = self.WIDTH
self._resize_start_height = self.HEIGHT
self._interaction_start_pos: QPointF | None = None
self._interaction_start_rect: QRectF | None = None

self.setPos(pos)
self.setFlag(QGraphicsRectItem.ItemIsMovable)
Expand Down Expand Up @@ -143,6 +145,14 @@ def toggle_orientation(self):
self.view.on_block_moved(self)
self.update()

def set_orientation(self, orientation: str) -> None:
if orientation not in {"normal", "flipped"}:
return
self.orientation = orientation
self._layout_ports()
self.view.on_block_moved(self)
self.update()

def boundingRect(self) -> QRectF:
"""Return the item bounds including resize-handle hit areas.

Expand Down Expand Up @@ -225,6 +235,8 @@ def mousePressEvent(self, event):
Args:
event: Qt mouse-press event.
"""
self._interaction_start_pos = QPointF(self.pos())
self._interaction_start_rect = QRectF(self.rect())
if self.isSelected():
handle = self._handle_at(event.pos())
if handle is not None:
Expand Down Expand Up @@ -284,11 +296,30 @@ def mouseReleaseEvent(self, event):
Args:
event: Qt mouse-release event.
"""
start_pos = self._interaction_start_pos
start_rect = self._interaction_start_rect
end_pos = QPointF(self.pos())
end_rect = QRectF(self.rect())

self._resize_handle = None
self._resize_start_mouse = None
self._resize_start_pos = None
self._interaction_start_pos = None
self._interaction_start_rect = None
super().mouseReleaseEvent(event)

if start_pos is None or start_rect is None:
return

if start_pos != end_pos or start_rect != end_rect:
self.view.project_controller.execute_move_resize_block(
self.instance,
start_pos,
start_rect,
end_pos,
end_rect,
)

def mouseDoubleClickEvent(self, event):
"""Open the block configuration dialog on double click.

Expand Down
32 changes: 30 additions & 2 deletions pySimBlocks/gui/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from pySimBlocks.gui.services.project_saver import ProjectSaverYaml
from pySimBlocks.gui.services.simulation_runner import SimulationRunner
from pySimBlocks.gui.services.yaml_tools import cleanup_runtime_project_yaml
from pySimBlocks.gui.undo_redo.undo_redo_manager import UndoManager
from pySimBlocks.gui.widgets.block_list import BlockList
from pySimBlocks.gui.widgets.diagram_view import DiagramView
from pySimBlocks.gui.widgets.toolbar_view import ToolBarView
Expand Down Expand Up @@ -73,10 +74,13 @@ def __init__(self, project_path: Path):
self.runner = SimulationRunner()

self.block_registry = load_block_registry()
self.undo_manager = UndoManager()

self.project_state = ProjectState(project_path)
self.view = DiagramView()
self.project_controller = ProjectController(self.project_state, self.view, self.resolve_block_meta)
self.project_controller = ProjectController(
self.project_state, self.view, self.resolve_block_meta, self.undo_manager
)
self.view.project_controller = self.project_controller
self.blocks = BlockList(self.get_categories, self.get_blocks, self.resolve_block_meta)
self.toolbar = ToolBarView(self.saver, self.runner, self.project_controller)
Expand All @@ -94,6 +98,7 @@ def __init__(self, project_path: Path):
self.project_controller.load_project(self.loader)

self.project_controller.dirty_changed.connect(self.update_window_title)
self.undo_manager.stack.cleanChanged.connect(self._on_clean_changed)
self.update_window_title()

self.save_action = QAction("Save", self)
Expand All @@ -106,6 +111,16 @@ def __init__(self, project_path: Path):
self.quit_action.triggered.connect(self.close)
self.addAction(self.quit_action)

self.undo_action = self.undo_manager.create_undo_action(self)
self.undo_action.setShortcut(QKeySequence.Undo)
self.undo_action.setShortcutContext(Qt.ApplicationShortcut)
self.addAction(self.undo_action)

self.redo_action = self.undo_manager.create_redo_action(self)
self.redo_action.setShortcuts([QKeySequence("Ctrl+Y"), QKeySequence("Ctrl+Shift+Z")])
self.redo_action.setShortcutContext(Qt.ApplicationShortcut)
self.addAction(self.redo_action)

QTimer.singleShot(0, self.view.setFocus)


Expand Down Expand Up @@ -200,6 +215,10 @@ def closeEvent(self, event) -> None:
event: Qt close event.
"""
if self.confirm_discard_or_save("closing"):
try:
self.undo_manager.stack.cleanChanged.disconnect(self._on_clean_changed)
except (TypeError, RuntimeError):
pass
self.cleanup()
event.accept()
else:
Expand Down Expand Up @@ -235,4 +254,13 @@ def _on_save(self) -> None:
if not self.project_controller.is_dirty:
return
self.saver.save(self.project_controller.project_state, self.project_controller.view.block_items)
self.project_controller.clear_dirty()
self.undo_manager.set_clean()

def _on_clean_changed(self, is_clean: bool) -> None:
try:
if is_clean:
self.project_controller.clear_dirty()
else:
self.project_controller.make_dirty()
except RuntimeError:
return
Loading
Loading