From 93489d90ccc812825f14237bc597d2d99a9cf433 Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Wed, 19 Oct 2022 18:51:23 +0300 Subject: [PATCH 01/22] fixed right menu --- packages/map_editor/mainWindow.py | 7 ------- packages/map_editor/windowDesign.py | 17 +++-------------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/packages/map_editor/mainWindow.py b/packages/map_editor/mainWindow.py index 67c856a..8e395ca 100644 --- a/packages/map_editor/mainWindow.py +++ b/packages/map_editor/mainWindow.py @@ -202,7 +202,6 @@ def init_ui(self): # Customize the Map Editor menu default_fill = self.ui.default_fill - delete_fill = self.ui.delete_fill # Fill out the list categories = self.info_json['categories'] @@ -226,14 +225,8 @@ def init_ui(self): if group['id'] in ("road", "block"): default_fill.addItem(QtGui.QIcon(information[elem_id]['icon']), self.get_translation(information[elem_id])['name'], elem_id) - delete_fill.addItem(QtGui.QIcon(information[elem_id]['icon']), - self.get_translation(information[elem_id])['name'], elem_id) default_fill.setCurrentText(self.get_translation(information["grass"])['name']) - delete_fill.setCurrentText(self.get_translation(information["grass"])['name']) - - set_fill = self.ui.set_fill - set_fill.clicked.connect(self.set_default_fill) def change_env(self): pass diff --git a/packages/map_editor/windowDesign.py b/packages/map_editor/windowDesign.py index 25e49e2..b4e243d 100644 --- a/packages/map_editor/windowDesign.py +++ b/packages/map_editor/windowDesign.py @@ -262,7 +262,7 @@ def setupUi(self, MainWindow): sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.map_info_widget.sizePolicy().hasHeightForWidth()) self.map_info_widget.setSizePolicy(sizePolicy) - self.map_info_widget.setMinimumSize(QtCore.QSize(183, 200)) + #self.map_info_widget.setMinimumSize(QtCore.QSize(183, 200)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.SolidPattern) @@ -288,7 +288,7 @@ def setupUi(self, MainWindow): self.map_info_widget.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea|QtCore.Qt.RightDockWidgetArea) self.map_info_widget.setObjectName("map_info_widget") self.dockWidgetContents_3 = QtWidgets.QWidget() - self.dockWidgetContents_3.setMaximumHeight(150) + self.dockWidgetContents_3.setMaximumHeight(90) self.dockWidgetContents_3.setObjectName("dockWidgetContents_3") self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.dockWidgetContents_3) self.verticalLayout_3.setObjectName("verticalLayout_3") @@ -298,15 +298,6 @@ def setupUi(self, MainWindow): self.default_fill = QtWidgets.QComboBox(self.dockWidgetContents_3) self.default_fill.setObjectName("default_fill") self.verticalLayout_3.addWidget(self.default_fill) - self.delete_fill_label = QtWidgets.QLabel(self.dockWidgetContents_3) - self.delete_fill_label.setObjectName("delete_fill_label") - self.verticalLayout_3.addWidget(self.delete_fill_label) - self.delete_fill = QtWidgets.QComboBox(self.dockWidgetContents_3) - self.delete_fill.setObjectName("delete_fill") - self.verticalLayout_3.addWidget(self.delete_fill) - self.set_fill = QtWidgets.QPushButton(self.dockWidgetContents_3) - self.set_fill.setObjectName("set_fill") - self.verticalLayout_3.addWidget(self.set_fill) self.map_info_widget.setWidget(self.dockWidgetContents_3) MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.map_info_widget) self.open_map = QtWidgets.QAction(MainWindow) @@ -412,9 +403,7 @@ def retranslateUi(self, MainWindow): # TODO future functionality #self.layer_info_widget.setWindowTitle(_translate("MainWindow", "Layers")) #self.map_info_widget.setWindowTitle(_translate("MainWindow", "Map editor")) - self.default_fill_label.setText(_translate("MainWindow", "Default fill")) - self.delete_fill_label.setText(_translate("MainWindow", "Fill when deleted")) - self.set_fill.setText(_translate("MainWindow", "Set")) + self.default_fill_label.setText(_translate("MainWindow", "Current fill")) self.open_map.setText(_translate("MainWindow", "Open map")) self.open_map.setToolTip(_translate("MainWindow", "Open *.yaml map")) self.open_map.setShortcut(_translate("MainWindow", "Ctrl+O")) From 6e42de6ddf2bee34190fbeef8c57aff9bd0f2848 Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Wed, 19 Oct 2022 19:10:15 +0300 Subject: [PATCH 02/22] block change tile i j --- packages/map_editor/forms/edit_object.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/map_editor/forms/edit_object.py b/packages/map_editor/forms/edit_object.py index b8ca140..314f07e 100644 --- a/packages/map_editor/forms/edit_object.py +++ b/packages/map_editor/forms/edit_object.py @@ -13,6 +13,7 @@ def __init__(self, layer_name: str, name: str, config: Dict[str, Any], frame: Dict[str, Any], is_draggable: bool): super(EditObject, self).__init__() self.info = {"types": {}} + self.layer_name = layer_name self.info_send = {"name": name, "layer_name": layer_name, "new_config": {}, "is_draggable": is_draggable, "frame": {}, @@ -79,6 +80,9 @@ def create_form(self, config: Dict[str, Any], frame: Dict[str, Any]) -> None: self.info[key] = edit self.info["types"][key] = type(config[key]) edit.setText(str(config[key])) + # tile identifiers must not be changed + if self.layer_name == "tiles" and (key == "i" or key == "j"): + edit.setDisabled(True) layout.addRow(QLabel(key), edit) layout.addWidget(QHLine()) for frame_key in frame: @@ -97,6 +101,7 @@ def create_form(self, config: Dict[str, Any], frame: Dict[str, Any]) -> None: self.info["types"][row_name] = type(val) self.info[row_name] = edit edit.setText(str(val)) + # cannot edit frames of non-draggable objects if not self.is_draggable: edit.setDisabled(True) layout.addRow(QLabel(row_name), edit) From a83e144facf4587a85baf40ba70de88357ccb183 Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Wed, 19 Oct 2022 19:54:56 +0300 Subject: [PATCH 03/22] added button for go to the left high corner of map --- packages/map_editor/mainWindow.py | 12 +++++++++++- packages/map_editor/mapAPI.py | 3 +++ packages/map_editor/mapViewer.py | 10 ++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/map_editor/mainWindow.py b/packages/map_editor/mainWindow.py index 8e395ca..abe41f6 100644 --- a/packages/map_editor/mainWindow.py +++ b/packages/map_editor/mainWindow.py @@ -131,6 +131,10 @@ def init_ui(self): a3 = QtWidgets.QAction(QtGui.QIcon("img/icons/save.png"), _translate("MainWindow", "Save map (Ctrl+S)"), self) a4 = QtWidgets.QAction(QtGui.QIcon("img/icons/save_as.png"), _translate("MainWindow", "Save map as (Ctrl+Alt+S)"), self) a5 = QtWidgets.QAction(QtGui.QIcon("img/icons/png.png"), _translate("MainWindow", "Export to PNG (Ctrl+P)"), self) + a6 = QtWidgets.QAction(QtGui.QIcon("img/icons/leftup.png"), + _translate("MainWindow", + "To the corner of the map (Ctrl+M)"), self) + a6.setShortcut("Ctrl+M") # TODO ''' @@ -147,11 +151,11 @@ def init_ui(self): ''' c1 = QtWidgets.QAction(QtGui.QIcon("img/icons/rotate.png"), _translate("MainWindow", "Rotate (Ctrl+R)"), self) + c1.setShortcut("Ctrl+R") # TODO #c2 = QtWidgets.QAction(QtGui.QIcon("img/icons/trim.png"), # _translate("MainWindow", "Delete extreme empty blocks"), self) - c1.setShortcut("Ctrl+R") #c2.setShortcut("Ctrl+F") self.brush_button.setIcon(QtGui.QIcon("img/icons/brush.png")) @@ -164,6 +168,7 @@ def init_ui(self): a3.triggered.connect(self.save_map_triggered) a4.triggered.connect(self.save_map_as_triggered) a5.triggered.connect(self.save_map_as_png) + a6.triggered.connect(self.to_the_map_corner) # TODO ''' @@ -188,6 +193,7 @@ def init_ui(self): tool_bar.addSeparator() tool_bar.addWidget(self.brush_button) tool_bar.addAction(c1) + tool_bar.addAction(a6) # TODO #tool_bar.addAction(c2) @@ -234,6 +240,10 @@ def change_env(self): def center(self): pass + def to_the_map_corner(self) -> None: + print("press") + self.map_api.to_the_map_corner() + # Create a new map def open_map_triggered(self) -> None: self.map_api.open_map_triggered(self) diff --git a/packages/map_editor/mapAPI.py b/packages/map_editor/mapAPI.py index f9bc184..91ad3d0 100644 --- a/packages/map_editor/mapAPI.py +++ b/packages/map_editor/mapAPI.py @@ -79,6 +79,9 @@ def create_map_triggered(self, info: Dict[str, Any]) -> None: except OSError as err: logging.error(f"Cannot create path {path} for new map. {err.strerror}") + def to_the_map_corner(self): + self._map_viewer.to_the_corner() + def create_region(self): print('create_region') diff --git a/packages/map_editor/mapViewer.py b/packages/map_editor/mapViewer.py index d0dd195..fe039f2 100644 --- a/packages/map_editor/mapViewer.py +++ b/packages/map_editor/mapViewer.py @@ -451,6 +451,7 @@ def wheelEvent(self, event: QtGui.QWheelEvent) -> None: else: self.scale *= sf self.coordinates_transformer.set_scale(self.scale) + self.set_offset() self.change_object_handler(self.scaled_obj, {"scale": self.scale}) self.scene_update() @@ -472,6 +473,15 @@ def move_map(self, x: float, y: float) -> None: self.change_object_handler(self.move_obj, {"delta_coordinates": delta_pos}) + def to_the_corner(self) -> None: + left_upper_tile = self.get_object( + f"{self.tile_map}/tile_0_{self.map_height - 1}") + delta_pos = (-left_upper_tile.pos().x(), + -left_upper_tile.pos().y()) + self.change_object_handler(self.move_obj, + {"delta_coordinates": delta_pos}) + self.set_offset() + def get_event_coordinates(self, event: Union[Tuple[float, float], QtGui.QMouseEvent]) -> \ [float, float, QtGui.QMouseEvent]: if isinstance(event, tuple): From b4cc94b09c04a4a1f81a169e74686ee1c8aabe70 Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Wed, 19 Oct 2022 20:06:52 +0300 Subject: [PATCH 04/22] added 5-accuracy in form --- packages/map_editor/forms/edit_object.py | 11 +++++++++-- packages/map_editor/img/icons/leftup.png | Bin 0 -> 1072 bytes packages/map_editor/mainWindow.py | 1 - 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 packages/map_editor/img/icons/leftup.png diff --git a/packages/map_editor/forms/edit_object.py b/packages/map_editor/forms/edit_object.py index 314f07e..5c623c7 100644 --- a/packages/map_editor/forms/edit_object.py +++ b/packages/map_editor/forms/edit_object.py @@ -12,6 +12,7 @@ class EditObject(QDialog): def __init__(self, layer_name: str, name: str, config: Dict[str, Any], frame: Dict[str, Any], is_draggable: bool): super(EditObject, self).__init__() + self.float_accuracy = 5 self.info = {"types": {}} self.layer_name = layer_name self.info_send = {"name": name, "layer_name": layer_name, @@ -79,7 +80,10 @@ def create_form(self, config: Dict[str, Any], frame: Dict[str, Any]) -> None: edit = QLineEdit(self) self.info[key] = edit self.info["types"][key] = type(config[key]) - edit.setText(str(config[key])) + if not isinstance(config[key], float): + edit.setText(str(config[key])) + else: + edit.setText(f'{config[key]:.{self.float_accuracy}f}') # tile identifiers must not be changed if self.layer_name == "tiles" and (key == "i" or key == "j"): edit.setDisabled(True) @@ -100,7 +104,10 @@ def create_form(self, config: Dict[str, Any], frame: Dict[str, Any]) -> None: val = frame[frame_key][frame_val] self.info["types"][row_name] = type(val) self.info[row_name] = edit - edit.setText(str(val)) + if not isinstance(val, float): + edit.setText(str(val)) + else: + edit.setText(f'{val:.{self.float_accuracy}f}') # cannot edit frames of non-draggable objects if not self.is_draggable: edit.setDisabled(True) diff --git a/packages/map_editor/img/icons/leftup.png b/packages/map_editor/img/icons/leftup.png new file mode 100644 index 0000000000000000000000000000000000000000..b39abf64e9918146b52f62a935a2938e80150d3b GIT binary patch literal 1072 zcmV-01kd}4P)CE4T%dy$W=NNfWEv6ICQDLNQVTsX~awiK1keNANxMBeFA1^@VehA9U3u!Dki(7 z|FCZ2haGq;_1uK(^H4iy2iUI3S%y~>)GBn>NMNsKLKkNx{wAv1cyE*f(75?)X9 zMK{5 None: - print("press") self.map_api.to_the_map_corner() # Create a new map From 0e07e01ea8fcec7d2501ae45f8269e8d143b1fac Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Wed, 19 Oct 2022 20:52:52 +0300 Subject: [PATCH 05/22] dragging by clicking on the mouse wheel --- packages/map_editor/mainWindow.py | 5 ++++- packages/map_editor/mapAPI.py | 9 ++++++++- packages/map_editor/mapViewer.py | 6 ++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/map_editor/mainWindow.py b/packages/map_editor/mainWindow.py index 5e47744..61e7db9 100644 --- a/packages/map_editor/mainWindow.py +++ b/packages/map_editor/mainWindow.py @@ -1,7 +1,7 @@ import functools import json import codecs -from PyQt5.QtGui import QResizeEvent, QKeyEvent +from PyQt5.QtGui import QResizeEvent, QKeyEvent, QMouseEvent from mapAPI import MapAPI from mapViewer import MapViewer from utils.debug import DebugLine @@ -373,6 +373,9 @@ def keyPressEvent(self, event: QKeyEvent) -> None: def keyReleaseEvent(self, event: QKeyEvent) -> None: self.map_api.key_release_event(event) + def mousePressEvent(self, event: QMouseEvent): + self.map_api.mouse_press_event(event) + def rotate_selected_tiles(self) -> None: self.map_api.rotate_selected_tiles() diff --git a/packages/map_editor/mapAPI.py b/packages/map_editor/mapAPI.py index 91ad3d0..9dff95f 100644 --- a/packages/map_editor/mapAPI.py +++ b/packages/map_editor/mapAPI.py @@ -1,5 +1,5 @@ import logging -from PyQt5 import QtWidgets, QtCore +from PyQt5 import QtWidgets, QtCore, QtGui from PyQt5.QtGui import QKeyEvent from PyQt5.QtWidgets import QMessageBox from editorState import EditorState @@ -243,6 +243,13 @@ def key_press_event(self, event: QKeyEvent) -> None: if event.key() == CTRL and not self._editor_state.is_move: self.set_move_mode(True) + def mouse_press_event(self, event: QtGui.QMouseEvent): + if event.buttons() == QtCore.Qt.MiddleButton: + if not self._editor_state.is_move: + self.set_move_mode(True) + else: + self.set_move_mode(False) + def key_release_event(self, event: QKeyEvent) -> None: if event.key() == CTRL: self.set_move_mode(False) diff --git a/packages/map_editor/mapViewer.py b/packages/map_editor/mapViewer.py index fe039f2..f27c6e6 100644 --- a/packages/map_editor/mapViewer.py +++ b/packages/map_editor/mapViewer.py @@ -496,11 +496,12 @@ def mousePressEvent(self, event: Union[Tuple[float, float], QtGui.QMouseEvent]) -> None: # cursor on object x, y, event = self.get_event_coordinates(event) - if event.buttons() == QtCore.Qt.LeftButton: + if event.buttons() == QtCore.Qt.LeftButton or event.buttons() == QtCore.Qt.MiddleButton: self.lmbPressed = True self.set_offset() self.mouse_cur_x = self.mouse_start_x = x self.mouse_cur_y = self.mouse_start_y = y + self.parentWidget().mousePressEvent(event) def mouseMoveEvent(self, event: Union[Tuple[float, float], QtGui.QMouseEvent]) -> None: # cursor on object @@ -517,7 +518,7 @@ def mouseMoveEvent(self, event: Union[Tuple[float, float], QtGui.QMouseEvent]) - self.update_debug_info((self.mouse_cur_x, self.mouse_cur_y)) def mouseReleaseEvent(self, event: QtGui.QMouseEvent) -> None: - if event.button() == QtCore.Qt.LeftButton: + if event.button() == QtCore.Qt.LeftButton or event.buttons() == QtCore.Qt.MiddleButton: self.lmbPressed = False self.set_offset() if not self.is_move_mode(): @@ -525,6 +526,7 @@ def mouseReleaseEvent(self, event: QtGui.QMouseEvent) -> None: self.select_objects() self.parentWidget().parent().selectionUpdate() self.scene_update() + self.parentWidget().mousePressEvent(event) else: self.rmbPressed = False From 19a28d8bca9b078dbe9fbedc3840d7465788a371 Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Wed, 19 Oct 2022 22:46:34 +0300 Subject: [PATCH 06/22] block selecting when moving --- packages/map_editor/mapViewer.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/map_editor/mapViewer.py b/packages/map_editor/mapViewer.py index f27c6e6..65f2288 100644 --- a/packages/map_editor/mapViewer.py +++ b/packages/map_editor/mapViewer.py @@ -392,7 +392,6 @@ def change_obj_from_info(self, conf: Dict[str, Any]) -> None: self.parentWidget().parent().view_info_form("Error", "Invalid values entered!") - def check_layer_config(self, layer_name: str, new_config: Dict[str, Any]): return self.handlers.handle(CheckConfigCommand(layer_name, new_config)) @@ -524,7 +523,7 @@ def mouseReleaseEvent(self, event: QtGui.QMouseEvent) -> None: if not self.is_move_mode(): self.select_tiles() self.select_objects() - self.parentWidget().parent().selectionUpdate() + self.parentWidget().parent().selectionUpdate() self.scene_update() self.parentWidget().mousePressEvent(event) else: From 4e2fa8ea06b3031864b7026f72179cb1747617ab Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Thu, 20 Oct 2022 12:49:01 +0300 Subject: [PATCH 07/22] rotate selected objects on ctrl+r --- packages/map_editor/mainWindow.py | 2 +- packages/map_editor/mapAPI.py | 3 ++- packages/map_editor/mapViewer.py | 9 +++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/map_editor/mainWindow.py b/packages/map_editor/mainWindow.py index 61e7db9..90ede74 100644 --- a/packages/map_editor/mainWindow.py +++ b/packages/map_editor/mainWindow.py @@ -377,7 +377,7 @@ def mousePressEvent(self, event: QMouseEvent): self.map_api.mouse_press_event(event) def rotate_selected_tiles(self) -> None: - self.map_api.rotate_selected_tiles() + self.map_api.rotate_selected_objects() def update_debug_info(self, event: Dict[str, Any]) -> None: self.map_api.update_debug_info(event) diff --git a/packages/map_editor/mapAPI.py b/packages/map_editor/mapAPI.py index 9dff95f..99dc4fb 100644 --- a/packages/map_editor/mapAPI.py +++ b/packages/map_editor/mapAPI.py @@ -254,8 +254,9 @@ def key_release_event(self, event: QKeyEvent) -> None: if event.key() == CTRL: self.set_move_mode(False) - def rotate_selected_tiles(self) -> None: + def rotate_selected_objects(self) -> None: self._map_viewer.rotate_tiles() + self._map_viewer.rotate_objects() def set_debug_mode(self, debug_line: DebugLine) -> None: self._editor_state.debug_mode = True diff --git a/packages/map_editor/mapViewer.py b/packages/map_editor/mapViewer.py index 65f2288..1606832 100644 --- a/packages/map_editor/mapViewer.py +++ b/packages/map_editor/mapViewer.py @@ -424,6 +424,15 @@ def painting_tiles(self, default_fill: str) -> None: def rotate_tiles(self) -> None: self.change_tiles_handler(self.rotate_with_button, {}) + def rotate_object_with_button(self, obj: ImageObject, args: Dict[str, Any]) -> None: + if obj.is_draggable() and obj.is_select: + new_angle = obj.yaw + 90 + self.rotate_obj(obj, new_angle) + self.rotate_obj_on_map(obj.name, new_angle) + + def rotate_objects(self) -> None: + self.change_object_handler(self.rotate_object_with_button, {}) + def highlight_select_tile(self, args: Dict[str, Any]): tile = self.get_object(args["tile_name"]) self.painter.draw_rect((tile.pos().x() - 1, tile.pos().y() - 1), From a08346c4d94b9814cb822322066680b85322a475 Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Sat, 22 Oct 2022 14:32:14 +0300 Subject: [PATCH 08/22] added undo buttons --- packages/map_editor/editorState.py | 8 +-- packages/map_editor/history.py | 53 +++++++++++++++++++ packages/map_editor/img/icons/shift_undo.png | Bin 0 -> 5249 bytes packages/map_editor/mainWindow.py | 35 ++++++------ packages/map_editor/mapViewer.py | 37 +++++++++---- 5 files changed, 97 insertions(+), 36 deletions(-) create mode 100644 packages/map_editor/history.py create mode 100644 packages/map_editor/img/icons/shift_undo.png diff --git a/packages/map_editor/editorState.py b/packages/map_editor/editorState.py index e95ec69..35655bd 100644 --- a/packages/map_editor/editorState.py +++ b/packages/map_editor/editorState.py @@ -2,18 +2,12 @@ DEFAULT_TILE_SIZE = 0.585 - +# TODO is draw state set draw state class EditorState(metaclass=SingletonMeta): drawState = '' - copyBuffer = [[]] debug_mode = False def __init__(self) -> None: - self.distortion_view_one_string_mode = True - self.region_create = False - self.active_items = [] - self.active_group = None - self.name_of_editable_obj = None self.tile_size = DEFAULT_TILE_SIZE self.is_move = False diff --git a/packages/map_editor/history.py b/packages/map_editor/history.py new file mode 100644 index 0000000..f56a8eb --- /dev/null +++ b/packages/map_editor/history.py @@ -0,0 +1,53 @@ +from typing import Optional + +MAX_BUFFER_LENGTH = 100 + + +class Memento: + _state = None + + def __init__(self, state) -> None: + self._state = state + + def get_state(self): + return self._state + + +class EditorHistory: + buffer: [Memento] = [] + current_state_index: int = 0 + + def delete(self, start_index: int) -> None: + """ + Delete objects from current_state_index to max_length. + If buffer is full, delete old states. + """ + del self.buffer[start_index:] + + def push(self, m: Memento) -> None: + """ + Add new state to the end of buffer. + """ + if self.current_state_index < len(self.buffer) - 1: + self.delete(self.current_state_index) + self.buffer.append(m) + self.current_state_index += 1 + + def undo(self) -> Optional[Memento]: + """ + Return state from history at index current_state_index - 1. + """ + if self.current_state_index >= 0 and len(self.buffer) > 0: + self.current_state_index -= 1 + return self.buffer[self.current_state_index] + else: + return None + + def shift_undo(self) -> Memento: + """ + Return state from history at index current_state_index + 1. + """ + if self.current_state_index < MAX_BUFFER_LENGTH and \ + len(self.buffer) > self.current_state_index + 1: + self.current_state_index += 1 + return self.buffer[self.current_state_index] diff --git a/packages/map_editor/img/icons/shift_undo.png b/packages/map_editor/img/icons/shift_undo.png new file mode 100644 index 0000000000000000000000000000000000000000..62d7ea1308f13ca77d924249ed4854593f0a397d GIT binary patch literal 5249 zcmeHLX;>5I77i-1C?Lpov6c{&i(rz;Mo1(qVMjtCA|PJS$z%e7Y$Sn%MXaM-)PmLy%0Iel9EPIsCgqv!C`VXs6b1kVjf=rqveSb7!51= zJQPa#aG;Qt-($OY`*<-YXY-_0+-HkzO2t6)0j-3j<7dyB(JG&2d<|^=(voSJxBkh? z*KIy&RzaD?txnSGiSECYZnw9n*mvx7zC*-gzm)jS$s)#Y%NG}v>=~i_NtptVZtOT| z7yiQ2_Tk-%v?1H1C(Q*dl%4*$N6aRT>pT*X!hk_BLa?{V|b=HL!;)g{|)oJ`%Pe9 zY>=XrH@_R@+1I+Wq>$PSPs$CG-{rXSl(6?4y2P<*cX1NP=GZJc|aX zd*H=!xJNxbJN&`_ z?O!%JeWgdWsoB6W&uFRM7GqzR`=;0?RKu+(XutRO=y{N;X=nsm6Mi~Jt6XZ8r{QXHy3%$C?aF)9x#EP+!lDiu#W^nA{egM!f;Bi& z9&o*D^SbZn?KuukS1)`KNFh)v1tPF9X3xn7(p&rc4u?hjr=TcGVStZxXVznOcza}q zS8L-~_BF~(w%@7mDw#E1e`IM?4PLl$y7n+*=u&g!i-+Y~_BzDYBxZ+%4?H^DJ=I^6 zoEw?M=&uW*kCt0orZxoS(97?pe}Ayv>vLz$t{`!Y**(iwdNJ~#ZqFF~(IShJg9bW# z+cH@^RFkhx!xl_kdhd0?BKBin5%E{u?qKtJ-=dpz76)CXRiT$uzBa{ZU(b};k3AFL zE}IUO@=KEo9(^G?Q#SUB)M{EWVtlJawC&E0DQi3LeJ%+uPe*HW6o2Hlc=ub68ct|$ z`P!M8me*2eX)toRE)8XQwM_d`=OPCbN+X@`?jGpt?*3N(i0F&A>}2@VyMETVXLfw|ULB+|X zZ23;3=|bc1h9t?OT*dh3iXqg&aPHo_4!Y6jg*M#;!oCfL^Ur9P8btKhox8aj3duK$ zrd=BB?EWKSS5%ercwc`=rRn?>%=5)0|03l+rSy)21QYYG-~7P zV{$ZCGq-7L!h#a*WkKQb?A0syF88jwbWE(2uIhP+vTkRu*J>%xKCRCw#}8`0HI$3ohhpUlrIJ#9p-yJ7_tAAMG3Iy5L49B3zvO{Jnz z#-u08CKMJ(qq5*54JnM}Plv=p9LN=OV4PAYK^hhc<>aE2fKV(fM|0pPzKDSts=bUs z^SKO6D1`;EB<^rD-zP~5uS*IDhLU0-8W-c@tm~wtBLG5J4x*Jpfk;MIGB9dfI&!TV z#$(WG6L~BH6UGWeyNjhTnv5gk0Ia8ypFqSo>!O{cTppe6;WZ0^+%YiGa=C<#$14;H zoPvZCOQY}v8jXerhBYhpuhGpV-DFk~a zz#_TzTnH}o&R-HQ6{ySMLU>pJ3lUQp5|!{lNN-mO1RTdla3CJwNaAvdSO+SZizSnI z9IPV==3pTzNB{^Rmq_4p=RkZRU*&C>SphMX6(`2&cOR`Z6#?9PoZ5Pyot#hyw%T z&lklj-%kYdh44B#sA7}g;NU9wL zG+HfNIta}Kk%0;D3ibc8_a0~h~LZ@(q52mg@4zsW;s*Q_z%8j z*Ww?HfIxo=@=^SLqU#e~AH~2&8GlmOC%Qh0fsZo&q^|!PUApfdcwiCoD@cJn&J@@u zq#%z%3ps1OJy6rCcge-01;~hw#AkyHg<4yvIy43w#b{(uOYY0^)aunWU8JvbU&GN9 z`NJpF*TXG1tbU+vZFFm>x#sYuZ-R8#Svb3uxtwEX*msx_(Q8_>G(AscWsA<*9=o^Q zE1F*!cQ97bRVtD%&tsab^4iH+QqlT@#)0Z%x0{ZypKygz7Sz(dw6H0-9_!Fsx4PG5 ze3~&xYp+p!*N~m_G%kyzWeGWpy1|u2%K1l!jlURXn1-C)y6;J~UaiE^rE9>?q}-Bv zJ7d-TZEO0k*6y||(b9Vrxm_-FT&fYPQoD=8(zv^bzN9TOYc!Lfbl zc&{P8b9_mv`=;P&+l>*_hUB%SJ2t+QlMhY%8K?ehvN|UrC6o0M%_$1OG_855nFel5 zhzs+-5>w1N8dYv0yP*eYiw}~Z^H8-p<$g|W=Z_|p&2BCu5+~1dyNn)$Zjejo@m`HZ z_b%WWZ!D)=&-EHu3jP)Mu^9>bo zf+pzM=Qe?Qk-Cg;Y1_bc6lp)n04;C?8u>i_oapE zSchkg#MO^A8oQJ;hB{HF50{LOFs*(%)pT*i#qj1=}aw$<#PT;_(irMl|rAKCgs zo42AYHy~-`)ej9G#*bq=PHx(BgF9~P&kMOVIW;^v-s7_0cUSf_3e%7^)X_#DAgV+8 MdIor$W^Ug07ZNQ49{>OV literal 0 HcmV?d00001 diff --git a/packages/map_editor/mainWindow.py b/packages/map_editor/mainWindow.py index 90ede74..94e6b41 100644 --- a/packages/map_editor/mainWindow.py +++ b/packages/map_editor/mainWindow.py @@ -61,7 +61,6 @@ def get_translation(self, elem): return elem['lang']['en'] def init_ui(self): - self.center() self.show() # Initialize button objects @@ -131,10 +130,13 @@ def init_ui(self): a3 = QtWidgets.QAction(QtGui.QIcon("img/icons/save.png"), _translate("MainWindow", "Save map (Ctrl+S)"), self) a4 = QtWidgets.QAction(QtGui.QIcon("img/icons/save_as.png"), _translate("MainWindow", "Save map as (Ctrl+Alt+S)"), self) a5 = QtWidgets.QAction(QtGui.QIcon("img/icons/png.png"), _translate("MainWindow", "Export to PNG (Ctrl+P)"), self) - a6 = QtWidgets.QAction(QtGui.QIcon("img/icons/leftup.png"), - _translate("MainWindow", - "To the corner of the map (Ctrl+M)"), self) + a6 = QtWidgets.QAction(QtGui.QIcon("img/icons/leftup.png"), _translate("MainWindow", "To the corner of the map (Ctrl+M)"), self) + a7 = QtWidgets.QAction(QtGui.QIcon("img/icons/undo.png"), _translate("MainWindow", "Undo (Ctrl+Z)"), self) + a8 = QtWidgets.QAction(QtGui.QIcon("img/icons/shift_undo.png"), _translate("MainWindow", "Shift undo (Ctrl+Shift+Z)"), self) a6.setShortcut("Ctrl+M") + a7.setShortcut("Ctrl+Z") + a8.setShortcut("Ctrl+Shift+Z") + # TODO ''' @@ -142,12 +144,10 @@ def init_ui(self): b2 = QtWidgets.QAction(QtGui.QIcon("img/icons/cut.png"), _translate("MainWindow", "Cut"), self) b3 = QtWidgets.QAction(QtGui.QIcon("img/icons/insert.png"), _translate("MainWindow", "Paste"), self) b4 = QtWidgets.QAction(QtGui.QIcon("img/icons/delete.png"), _translate("MainWindow", "Delete"), self) - b5 = QtWidgets.QAction(QtGui.QIcon("img/icons/undo.png"), _translate("MainWindow", "Undo"), self) b1.setShortcut("Ctrl+C") b2.setShortcut("Ctrl+X") b3.setShortcut("Ctrl+V") b4.setShortcut("Delete") - b5.setShortcut("Ctrl+Z") ''' c1 = QtWidgets.QAction(QtGui.QIcon("img/icons/rotate.png"), _translate("MainWindow", "Rotate (Ctrl+R)"), self) @@ -169,6 +169,8 @@ def init_ui(self): a4.triggered.connect(self.save_map_as_triggered) a5.triggered.connect(self.save_map_as_png) a6.triggered.connect(self.to_the_map_corner) + a7.triggered.connect(self.undo_button_clicked) + a8.triggered.connect(self.shift_undo_button_clicked) # TODO ''' @@ -191,9 +193,12 @@ def init_ui(self): for act in elem: tool_bar.addAction(act) tool_bar.addSeparator() + tool_bar.addAction(a7) + tool_bar.addAction(a8) tool_bar.addWidget(self.brush_button) tool_bar.addAction(c1) tool_bar.addAction(a6) + # TODO #tool_bar.addAction(c2) @@ -234,12 +239,6 @@ def init_ui(self): default_fill.setCurrentText(self.get_translation(information["grass"])['name']) - def change_env(self): - pass - - def center(self): - pass - def to_the_map_corner(self) -> None: self.map_api.to_the_map_corner() @@ -254,12 +253,6 @@ def import_old_format(self): def create_map_triggered(self) -> None: self.map_api.create_map_form() - def create_region(self): - pass - - def change_distortion_view_triggered(self): - pass - # Save map def save_map_triggered(self): self.map_api.save_map_triggered() @@ -353,8 +346,12 @@ def insert_button_clicked(self): def delete_button_clicked(self): pass - # Undo def undo_button_clicked(self): + print(1) + pass + + def shift_undo_button_clicked(self): + print(2) pass # Brush mode diff --git a/packages/map_editor/mapViewer.py b/packages/map_editor/mapViewer.py index 1606832..07072e4 100644 --- a/packages/map_editor/mapViewer.py +++ b/packages/map_editor/mapViewer.py @@ -18,6 +18,7 @@ from classes.map_objects import DraggableImage, ImageObject from typing import Dict, Any, Optional, Union, Tuple from coordinatesTransformer import CoordinatesTransformer +from history import Memento from painter import Painter from classes.Commands.MoveObjCommand import MoveObjCommand from classes.Commands.RotateObjCommand import RotateCommand @@ -35,21 +36,16 @@ class MapViewer(QtWidgets.QGraphicsView, QtWidgets.QWidget): map = None - tile_sprites: Dict[str, QtGui.QImage] = {'empty': QtGui.QImage()} - tiles = None map_height = 10 objects = {} handlers = None scale = 1 tile_selection = [0] * 4 - rmbPressed = False lmbPressed = False - rmbPrevPos = [0, 0] mouse_start_x, mouse_start_y = 0, 0 mouse_cur_x, mouse_cur_y = 0, 0 offset_x = 0 offset_y = 0 - lmbClicked = QtCore.pyqtSignal(int, int) # click coordinates as an index of the clicked tile is_to_png = False tile_width: float = 0.585 tile_height: float = 0.585 @@ -83,7 +79,7 @@ def init_objects(self) -> None: if layer and layer_name != "frames": for object_name in layer: layer_object = layer[object_name] - if not object_name in frames: + if object_name not in frames: self.add_frame_on_map(object_name) self.add_obj_image(layer_name, object_name, layer_object) @@ -424,7 +420,8 @@ def painting_tiles(self, default_fill: str) -> None: def rotate_tiles(self) -> None: self.change_tiles_handler(self.rotate_with_button, {}) - def rotate_object_with_button(self, obj: ImageObject, args: Dict[str, Any]) -> None: + def rotate_object_with_button(self, obj: ImageObject, + args: Dict[str, Any]) -> None: if obj.is_draggable() and obj.is_select: new_angle = obj.yaw + 90 self.rotate_obj(obj, new_angle) @@ -511,7 +508,8 @@ def mousePressEvent(self, event: Union[Tuple[float, float], self.mouse_cur_y = self.mouse_start_y = y self.parentWidget().mousePressEvent(event) - def mouseMoveEvent(self, event: Union[Tuple[float, float], QtGui.QMouseEvent]) -> None: + def mouseMoveEvent(self, event: Union[ + Tuple[float, float], QtGui.QMouseEvent]) -> None: # cursor on object x, y, event = self.get_event_coordinates(event) if self.lmbPressed: @@ -535,8 +533,6 @@ def mouseReleaseEvent(self, event: QtGui.QMouseEvent) -> None: self.parentWidget().parent().selectionUpdate() self.scene_update() self.parentWidget().mousePressEvent(event) - else: - self.rmbPressed = False def set_offset(self) -> None: left_upper_tile = self.get_object(f"{self.tile_map}/tile_0_{self.map_height - 1}") @@ -665,3 +661,24 @@ def open_map(self, path: Path, map_name: str, is_new_map: bool = False, self.change_object_handler(self.scaled_obj, {"scale": self.scale}) self.set_map_size() self.scene_update() + + def save_state(self) -> Memento: + return Memento({"map": deepcopy(self.map), "map_height": self.map_height, + "objects": deepcopy(self.objects), "handlers": deepcopy(self.handlers), + "tile_width": self.tile_width, "tile_height": self.tile_height, + "grid_scale": self.grid_scale, "grid_height": self.grid_height, + "grid_width": self.grid_width, "tile_map": self.tile_map}) + + def restore_state(self, m: Memento) -> None: + state = m.get_state() + self.map = state["map"] + self.map_height = state["map_height"] + self.objects = state["objects"] + self.handlers = state["handlers"] + self.tile_width = state["tile_width"] + self.tile_height = state["tile_height"] + self.grid_scale = state["grid_scale"] + self.grid_height = state["grid_height"] + self.grid_width = state["grid_width"] + self.tile_map = state["tile_map"] + self.scene_update() From 1d4fd7ab1509b1e59615d0179aacd1485e17e5e0 Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Sun, 23 Oct 2022 00:45:37 +0300 Subject: [PATCH 09/22] problem with dt maps restore --- packages/map_editor/history.py | 11 ++++++++--- packages/map_editor/mainWindow.py | 13 +++++++++---- packages/map_editor/mapAPI.py | 17 +++++++++++++++-- packages/map_editor/mapViewer.py | 25 ++++++++++++++++++++++--- 4 files changed, 54 insertions(+), 12 deletions(-) diff --git a/packages/map_editor/history.py b/packages/map_editor/history.py index f56a8eb..864d082 100644 --- a/packages/map_editor/history.py +++ b/packages/map_editor/history.py @@ -15,7 +15,7 @@ def get_state(self): class EditorHistory: buffer: [Memento] = [] - current_state_index: int = 0 + current_state_index: int = -1 def delete(self, start_index: int) -> None: """ @@ -32,22 +32,27 @@ def push(self, m: Memento) -> None: self.delete(self.current_state_index) self.buffer.append(m) self.current_state_index += 1 + print("push", self.buffer) def undo(self) -> Optional[Memento]: """ Return state from history at index current_state_index - 1. """ + print("undo", self.current_state_index, self.buffer) if self.current_state_index >= 0 and len(self.buffer) > 0: self.current_state_index -= 1 return self.buffer[self.current_state_index] else: return None - def shift_undo(self) -> Memento: + def shift_undo(self) -> Optional[Memento]: """ Return state from history at index current_state_index + 1. """ + print("shift undo", self.current_state_index) if self.current_state_index < MAX_BUFFER_LENGTH and \ len(self.buffer) > self.current_state_index + 1: self.current_state_index += 1 - return self.buffer[self.current_state_index] + return self.buffer[self.current_state_index] + else: + return None diff --git a/packages/map_editor/mainWindow.py b/packages/map_editor/mainWindow.py index 94e6b41..9a97a31 100644 --- a/packages/map_editor/mainWindow.py +++ b/packages/map_editor/mainWindow.py @@ -2,6 +2,8 @@ import json import codecs from PyQt5.QtGui import QResizeEvent, QKeyEvent, QMouseEvent + +from history import Memento from mapAPI import MapAPI from mapViewer import MapViewer from utils.debug import DebugLine @@ -346,13 +348,16 @@ def insert_button_clicked(self): def delete_button_clicked(self): pass - def undo_button_clicked(self): + def undo_button_clicked(self) -> None: print(1) - pass + self.map_api.undo_button_clicked() - def shift_undo_button_clicked(self): + def shift_undo_button_clicked(self) -> None: print(2) - pass + self.map_api.shift_button_clicked() + + def push_state(self, m: Memento) -> None: + self.map_api.push_state(m) # Brush mode def brush_mode(self) -> None: diff --git a/packages/map_editor/mapAPI.py b/packages/map_editor/mapAPI.py index 99dc4fb..eba2d6c 100644 --- a/packages/map_editor/mapAPI.py +++ b/packages/map_editor/mapAPI.py @@ -11,6 +11,7 @@ from utils.qtWindowAPI import QtWindowAPI from mapStorage import MapStorage from mapViewer import MapViewer +from history import Memento, EditorHistory from utils.debug import DebugLine from typing import Dict, Any from pathlib import Path @@ -30,6 +31,7 @@ class MapAPI: _map_viewer: MapViewer = None _editor_state: EditorState = None _debug_line: DebugLine = None + _history: EditorHistory = None def __init__(self, info_json: dict, map_viewer: MapViewer, args) -> None: self._map_storage = MapStorage() @@ -37,6 +39,7 @@ def __init__(self, info_json: dict, map_viewer: MapViewer, args) -> None: self.info_json = info_json self._map_viewer = map_viewer self._editor_state = EditorState() + self._history = EditorHistory() self.change_obj_info_form = None self.init_info_form = NewMapInfoForm(args.wkdir) self.init_info_form.send_info.connect(self.create_map_triggered) @@ -222,8 +225,18 @@ def delete_button_clicked(self): pass # Undo - def undo_button_clicked(self): - pass + def undo_button_clicked(self) -> None: + m = self._history.undo() + if m: + self._map_viewer.restore_state(m) + + def shift_button_clicked(self) -> None: + m = self._history.shift_undo() + if m: + self._map_viewer.restore_state(m) + + def push_state(self, m: Memento) -> None: + self._history.push(m) # Brush mode def brush_mode(self, brush_button_is_checked: bool) -> None: diff --git a/packages/map_editor/mapViewer.py b/packages/map_editor/mapViewer.py index 07072e4..9842531 100644 --- a/packages/map_editor/mapViewer.py +++ b/packages/map_editor/mapViewer.py @@ -34,6 +34,15 @@ from dt_maps.Map import REGISTER +def need_save_state(func): + def save(*args, **kwargs): + self = args[0] + m = self.save_state() + self.parentWidget().parent().push_state(m) + return func(*args, **kwargs) + return save + + class MapViewer(QtWidgets.QGraphicsView, QtWidgets.QWidget): map = None map_height = 10 @@ -146,7 +155,9 @@ def set_relative_to(self, object_name: str, value: str): self.handlers.handle( command=AddRelativeToObj(object_name, value)) + @need_save_state def add_obj(self, type_of_element: str, item_name: str = None) -> None: + print(self.map.map.layers) i = 1 layer_name = f"{type_of_element}s" while True: @@ -159,6 +170,8 @@ def add_obj(self, type_of_element: str, item_name: str = None) -> None: {'scale': self.scale}) break i += 1 + print(self.get_layer("tiles")["map_1/tile_0_0"]) + print(deepcopy(self.get_layer("tiles")["map_1/tile_0_0"])) def add_obj_image(self, layer_name: str, object_name: str, layer_object=None, item_name: str = None) -> None: @@ -337,6 +350,7 @@ def change_obj_info(self, layer_name: str, obj_name: str) -> None: self.get_object_conf(layer_name, obj_name), self.get_object_conf(FRAMES, obj.name), obj.is_draggable()) + #@need_save_state def change_obj_from_info(self, conf: Dict[str, Any]) -> None: print(conf) obj = self.get_object(conf["name"]) @@ -396,6 +410,7 @@ def change_obj_from_config(self, layer_name: str, obj_name: str, self.handlers.handle(ChangeObjCommand(layer_name, obj_name, new_config)) + @need_save_state def delete_object(self, obj: ImageObject) -> None: self.delete_obj_on_map(obj) self.objects.__delitem__(obj.name) @@ -404,6 +419,7 @@ def change_tiles_handler(self, handler_func, args: Dict[str, Any]) -> None: tiles = self.get_layer(TILES) for tile_name in tiles: tile = tiles[tile_name] + print(tile.__dict__, tile.__str__(), dir(tile)) if self.is_selected_tile(tile): args["tile_name"] = tile_name args["tile"] = tile @@ -663,15 +679,18 @@ def open_map(self, path: Path, map_name: str, is_new_map: bool = False, self.scene_update() def save_state(self) -> Memento: - return Memento({"map": deepcopy(self.map), "map_height": self.map_height, - "objects": deepcopy(self.objects), "handlers": deepcopy(self.handlers), + return Memento({"map": deepcopy(self.map.map), "map_height": self.map_height, + "objects": self.objects.copy(), "handlers": deepcopy(self.handlers), "tile_width": self.tile_width, "tile_height": self.tile_height, "grid_scale": self.grid_scale, "grid_height": self.grid_height, "grid_width": self.grid_width, "tile_map": self.tile_map}) def restore_state(self, m: Memento) -> None: + print("ok") state = m.get_state() - self.map = state["map"] + + self.map.map = state["map"] + print(self.map.map.layers) self.map_height = state["map_height"] self.objects = state["objects"] self.handlers = state["handlers"] From f7fee593a6f280ee9d881d6ed23a6fd92e955b9d Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Tue, 15 Nov 2022 18:41:30 +0300 Subject: [PATCH 10/22] simple undo started working --- packages/map_editor/mapViewer.py | 36 ++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/packages/map_editor/mapViewer.py b/packages/map_editor/mapViewer.py index 9842531..6c88af8 100644 --- a/packages/map_editor/mapViewer.py +++ b/packages/map_editor/mapViewer.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import time from copy import deepcopy from importlib import import_module from PyQt5 import QtWidgets, QtGui, QtCore @@ -157,7 +158,6 @@ def set_relative_to(self, object_name: str, value: str): @need_save_state def add_obj(self, type_of_element: str, item_name: str = None) -> None: - print(self.map.map.layers) i = 1 layer_name = f"{type_of_element}s" while True: @@ -170,8 +170,6 @@ def add_obj(self, type_of_element: str, item_name: str = None) -> None: {'scale': self.scale}) break i += 1 - print(self.get_layer("tiles")["map_1/tile_0_0"]) - print(deepcopy(self.get_layer("tiles")["map_1/tile_0_0"])) def add_obj_image(self, layer_name: str, object_name: str, layer_object=None, item_name: str = None) -> None: @@ -419,7 +417,7 @@ def change_tiles_handler(self, handler_func, args: Dict[str, Any]) -> None: tiles = self.get_layer(TILES) for tile_name in tiles: tile = tiles[tile_name] - print(tile.__dict__, tile.__str__(), dir(tile)) + #print(tile.__dict__, tile.__str__(), dir(tile)) if self.is_selected_tile(tile): args["tile_name"] = tile_name args["tile"] = tile @@ -664,6 +662,7 @@ def create_default_map_content(self, size: Tuple[int, int], def open_map(self, path: Path, map_name: str, is_new_map: bool = False, size: Tuple[int, int] = (0, 0), tile_size: Tuple[float, float] = (0, 0)) -> None: + t = time.time() self.delete_objects() self.map.load_map(MapDescription(path, map_name)) self.set_tile_map() @@ -677,23 +676,34 @@ def open_map(self, path: Path, map_name: str, is_new_map: bool = False, self.change_object_handler(self.scaled_obj, {"scale": self.scale}) self.set_map_size() self.scene_update() + print(time.time() - t) def save_state(self) -> Memento: - return Memento({"map": deepcopy(self.map.map), "map_height": self.map_height, - "objects": self.objects.copy(), "handlers": deepcopy(self.handlers), + # скопировали слои + layers = {name: layer.copy() for name, layer in self.map.map.layers.items()} + return Memento({"layers": layers, "map_height": self.map_height, "tile_width": self.tile_width, "tile_height": self.tile_height, "grid_scale": self.grid_scale, "grid_height": self.grid_height, "grid_width": self.grid_width, "tile_map": self.tile_map}) def restore_state(self, m: Memento) -> None: - print("ok") state = m.get_state() - - self.map.map = state["map"] - print(self.map.map.layers) - self.map_height = state["map_height"] - self.objects = state["objects"] - self.handlers = state["handlers"] + layers = state["layers"] + self.delete_objects() + # removing all elements from the original layers + for layer in self.map.map.layers: + items = [item for item in self.map.map.layers[layer]] + for item in items: + del self.map.map.layers[layer][item] + # fill the original now empty layers with the copied data + for layer_name in layers: + layer = layers[layer_name] + items = [item for item in layer] + for item in items: + self.map.map.layers[layer_name][item] = layer[item] + # initialize map objects from layers + self.init_objects() + # restore other settings self.tile_width = state["tile_width"] self.tile_height = state["tile_height"] self.grid_scale = state["grid_scale"] From 3bdcc5b0d5e4102e5c932fb51e2e80572e731929 Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Tue, 15 Nov 2022 21:16:49 +0300 Subject: [PATCH 11/22] fixed ctrl+z --- packages/map_editor/history.py | 24 +++++++++------ packages/map_editor/mapViewer.py | 52 ++++++++++++++++---------------- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/packages/map_editor/history.py b/packages/map_editor/history.py index 864d082..6743c41 100644 --- a/packages/map_editor/history.py +++ b/packages/map_editor/history.py @@ -24,24 +24,27 @@ def delete(self, start_index: int) -> None: """ del self.buffer[start_index:] + def push(self, m: Memento) -> None: """ Add new state to the end of buffer. """ - if self.current_state_index < len(self.buffer) - 1: - self.delete(self.current_state_index) - self.buffer.append(m) - self.current_state_index += 1 - print("push", self.buffer) + + if self.current_state_index + 1 < MAX_BUFFER_LENGTH: + self.buffer.append(m) + self.current_state_index = len(self.buffer) - 1 + def undo(self) -> Optional[Memento]: """ Return state from history at index current_state_index - 1. """ - print("undo", self.current_state_index, self.buffer) - if self.current_state_index >= 0 and len(self.buffer) > 0: + + if self.current_state_index - 1 >= 0: self.current_state_index -= 1 return self.buffer[self.current_state_index] + elif self.current_state_index == 0: + return self.buffer[0] else: return None @@ -49,9 +52,10 @@ def shift_undo(self) -> Optional[Memento]: """ Return state from history at index current_state_index + 1. """ - print("shift undo", self.current_state_index) - if self.current_state_index < MAX_BUFFER_LENGTH and \ - len(self.buffer) > self.current_state_index + 1: + + if self.current_state_index == len(self.buffer) - 1: + return self.buffer[self.current_state_index] + elif self.current_state_index + 1 < len(self.buffer): self.current_state_index += 1 return self.buffer[self.current_state_index] else: diff --git a/packages/map_editor/mapViewer.py b/packages/map_editor/mapViewer.py index 6c88af8..f5c0f64 100644 --- a/packages/map_editor/mapViewer.py +++ b/packages/map_editor/mapViewer.py @@ -37,10 +37,11 @@ def need_save_state(func): def save(*args, **kwargs): + func(*args, **kwargs) self = args[0] m = self.save_state() self.parentWidget().parent().push_state(m) - return func(*args, **kwargs) + #return func(*args, **kwargs) return save @@ -662,7 +663,6 @@ def create_default_map_content(self, size: Tuple[int, int], def open_map(self, path: Path, map_name: str, is_new_map: bool = False, size: Tuple[int, int] = (0, 0), tile_size: Tuple[float, float] = (0, 0)) -> None: - t = time.time() self.delete_objects() self.map.load_map(MapDescription(path, map_name)) self.set_tile_map() @@ -676,7 +676,6 @@ def open_map(self, path: Path, map_name: str, is_new_map: bool = False, self.change_object_handler(self.scaled_obj, {"scale": self.scale}) self.set_map_size() self.scene_update() - print(time.time() - t) def save_state(self) -> Memento: # скопировали слои @@ -688,26 +687,27 @@ def save_state(self) -> Memento: def restore_state(self, m: Memento) -> None: state = m.get_state() - layers = state["layers"] - self.delete_objects() - # removing all elements from the original layers - for layer in self.map.map.layers: - items = [item for item in self.map.map.layers[layer]] - for item in items: - del self.map.map.layers[layer][item] - # fill the original now empty layers with the copied data - for layer_name in layers: - layer = layers[layer_name] - items = [item for item in layer] - for item in items: - self.map.map.layers[layer_name][item] = layer[item] - # initialize map objects from layers - self.init_objects() - # restore other settings - self.tile_width = state["tile_width"] - self.tile_height = state["tile_height"] - self.grid_scale = state["grid_scale"] - self.grid_height = state["grid_height"] - self.grid_width = state["grid_width"] - self.tile_map = state["tile_map"] - self.scene_update() + if state: + layers = state["layers"] + self.delete_objects() + # removing all elements from the original layers + for layer in self.map.map.layers: + items = [item for item in self.map.map.layers[layer]] + for item in items: + del self.map.map.layers[layer][item] + # fill the original now empty layers with the copied data + for layer_name in layers: + layer = layers[layer_name] + items = [item for item in layer] + for item in items: + self.map.map.layers[layer_name][item] = layer[item] + # initialize map objects from layers + self.init_objects() + # restore other settings + self.tile_width = state["tile_width"] + self.tile_height = state["tile_height"] + self.grid_scale = state["grid_scale"] + self.grid_height = state["grid_height"] + self.grid_width = state["grid_width"] + self.tile_map = state["tile_map"] + self.scene_update() From 77d85956ab712316ecf65b4a9063a91173e223c0 Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Thu, 17 Nov 2022 02:25:24 +0300 Subject: [PATCH 12/22] managed to copy tiles, but there is a problem with moving through history --- .../classes/Commands/DeepCopyLayerCommand.py | 15 +++++ packages/map_editor/classes/layers.py | 14 ++-- packages/map_editor/layers.py | 64 ++++++++++++++++++- packages/map_editor/mapViewer.py | 17 ++++- 4 files changed, 101 insertions(+), 9 deletions(-) create mode 100644 packages/map_editor/classes/Commands/DeepCopyLayerCommand.py diff --git a/packages/map_editor/classes/Commands/DeepCopyLayerCommand.py b/packages/map_editor/classes/Commands/DeepCopyLayerCommand.py new file mode 100644 index 0000000..1a756ba --- /dev/null +++ b/packages/map_editor/classes/Commands/DeepCopyLayerCommand.py @@ -0,0 +1,15 @@ +from dt_maps import MapLayer +from classes.basic.command import Command + + +class DeepCopyLayerCommand(Command): + _layer_name: str + + def __init__(self, layer_name: str): + self._layer_name = layer_name + + def execute(self, layer: MapLayer, layer_name: str, *args, + **kwargs) -> None: + if layer_name == self._layer_name: + get_deepcopy = kwargs["get_deepcopy"] + return get_deepcopy(layer) diff --git a/packages/map_editor/classes/layers.py b/packages/map_editor/classes/layers.py index a907523..5ef556f 100644 --- a/packages/map_editor/classes/layers.py +++ b/packages/map_editor/classes/layers.py @@ -8,8 +8,8 @@ from mapStorage import MapStorage from utils.constants import LAYER_NAME from utils.maps import create_layer -from typing import Dict, Any -from copy import deepcopy +from typing import Dict, Any, Optional +from copy import deepcopy, copy class AbstractLayer(ABC): @@ -44,6 +44,11 @@ def check_config(self, config: Dict[str, Any]) -> bool: def set_layer_handler(self, handler: EntityHelper) -> None: self._layer_handler = handler + def get_layer_deepcopy(self, layer: MapLayer) -> Dict[str, Any]: + if not len(layer): + return {} + return layer.copy() + class BasicLayerHandler(AbstractHandler, AbstractLayer): def __init__(self, **kwargs) -> None: @@ -52,7 +57,8 @@ def __init__(self, **kwargs) -> None: def handle(self, command: Command) -> Any: response = command.execute(self._data, self._layer_name, deepcopy(self._default_conf), - check_config=self.check_config) + check_config=self.check_config, + get_deepcopy=self.get_layer_deepcopy) if response: return response return super().handle(command) @@ -62,7 +68,7 @@ class DynamicLayer(EntityHelper): _fields: Dict[str, Any] = {} _layer_name: str = "" - def __init__(self, **kwargs): + def __init__(self, **kwargs) -> None: super(DynamicLayer, self).__init__(kwargs["map"], kwargs[LAYER_NAME]) self._layer_name = kwargs[LAYER_NAME] for field_name, field_val in kwargs["conf"].items(): diff --git a/packages/map_editor/layers.py b/packages/map_editor/layers.py index 57894b9..cb16bc8 100644 --- a/packages/map_editor/layers.py +++ b/packages/map_editor/layers.py @@ -1,6 +1,7 @@ -from __future__ import annotations +from copy import copy from pathlib import Path -from typing import Any, Dict +from typing import Any, Dict, Optional +from dt_maps import MapLayer from utils.constants import TILE_SIZE from mapStorage import MapStorage from classes.layers import BasicLayerHandler @@ -22,6 +23,13 @@ def check_config(self, config: Dict[str, Any]) -> bool: return super().check_config(config) and config.get("type") \ in [t.value for t in TileType] + def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: + copied_layer = {} + for name, value in layer.items(): + copied_layer[name] = {'i': value["i"], 'j': value["j"], + 'type': value["type"]} + return copied_layer + class WatchtowersLayerHandler(BasicLayerHandler): def __init__(self, **kwargs) -> None: @@ -32,6 +40,13 @@ def check_config(self, config: Dict[str, Any]) -> bool: return super().check_config(config) and config.get("configuration") \ in [t.value for t in WatchtowerType] + def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: + copied_layer = {} + for name, value in layer.items(): + copied_layer[name] = {'configuration': value["configuration"], + 'id': value["id"]} + return copied_layer + class FramesLayerHandler(BasicLayerHandler): def __init__(self, **kwargs) -> None: @@ -40,12 +55,29 @@ def __init__(self, **kwargs) -> None: 'pitch': 0.0}, 'relative_to': ""} super(FramesLayerHandler, self).__init__(**kwargs) + def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: + copied_layer = {} + for name, value in layer.items(): + pose = value["pose"] + copied_layer[name] = { + 'pose': {'x': pose["x"], 'y': pose["y"], 'z': pose["z"], + 'yaw': pose["yaw"], 'roll': pose["roll"], + 'pitch': pose["pitch"]}, + 'relative_to': value["relative_to"]} + return copied_layer + class TileMapsLayerHandler(BasicLayerHandler): def __init__(self, **kwargs) -> None: kwargs["default_conf"] = {TILE_SIZE: {'x': 0.585, 'y': 0.585}} super(TileMapsLayerHandler, self).__init__(**kwargs) + def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: + copied_layer = {} + for name, value in layer.items(): + copied_layer[name] = {TILE_SIZE: {'x': value["x"], 'y': value["y"]}} + return copied_layer + class TrafficSignsLayerHandler(BasicLayerHandler): def __init__(self, **kwargs) -> None: @@ -56,12 +88,26 @@ def check_config(self, config: Dict[str, Any]) -> bool: return super().check_config(config) and \ config.get("type") in [t.value for t in TrafficSignType] + def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: + copied_layer = {} + for name, value in layer.items(): + copied_layer[name] = {"type": value["type"], "id": value["id"], + "family": value["family"]} + return copied_layer + class GroundTagsLayerHandler(BasicLayerHandler): def __init__(self, **kwargs) -> None: kwargs["default_conf"] = {"size": 0.15, "id": 0, "family": "36h11"} super(GroundTagsLayerHandler, self).__init__(**kwargs) + def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: + copied_layer = {} + for name, value in layer.items(): + copied_layer[name] = {"size": value["size"], "id": value["id"], + "family": value["family"]} + return copied_layer + class CitizensLayerHandler(BasicLayerHandler): def __init__(self, **kwargs) -> None: @@ -72,6 +118,12 @@ def check_config(self, config: Dict[str, Any]) -> bool: return super().check_config(config) and \ config.get("color") in [t.value for t in CitizenType] + def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: + copied_layer = {} + for name, value in layer.items(): + copied_layer[name] = {"color": value["color"]} + return copied_layer + class VehiclesLayerHandler(BasicLayerHandler): def __init__(self, **kwargs) -> None: @@ -84,6 +136,14 @@ def check_config(self, config: Dict[str, Any]) -> bool: config.get("configuration") in [t.value for t in VehicleType] and \ config.get("color") in [t.value for t in ColorType] + def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: + copied_layer = {} + for name, value in layer.items(): + copied_layer[name] = {"color": value["color"], + "configuration": value["configuration"], + "id": value["id"]} + return copied_layer + if __name__ == '__main__': MapStorage(MapDescription(Path("./maps/tm1"), "map_1")) diff --git a/packages/map_editor/mapViewer.py b/packages/map_editor/mapViewer.py index f5c0f64..7a87d52 100644 --- a/packages/map_editor/mapViewer.py +++ b/packages/map_editor/mapViewer.py @@ -9,6 +9,7 @@ from dt_maps import MapLayer from classes.Commands.AddObjCommand import AddObjCommand from classes.Commands.AddRelativeToObj import AddRelativeToObj +from classes.Commands.DeepCopyLayerCommand import DeepCopyLayerCommand from classes.Commands.DeleteObjCommand import DeleteObjCommand from classes.Commands.GetLayerCommand import GetLayerCommand from classes.Commands.SetTileSizeCommand import SetTileSizeCommand @@ -84,6 +85,7 @@ def __init__(self, work_dir: str): self.setMouseTracking(True) def init_objects(self) -> None: + print("init objects") frames = self.get_layer("frames") for layer_name in REGISTER: layer = self.get_layer(layer_name) @@ -262,6 +264,9 @@ def move_obj_command(self, frame_name: str, new_coord: Tuple[float, float]) -> None: self.handlers.handle(command=MoveObjCommand(frame_name, new_coord)) + def get_layer_deepcopy(self, layer_name: str) -> Dict[str, Any]: + return self.handlers.handle(command=DeepCopyLayerCommand(layer_name)) + def rotate_obj(self, obj: ImageObject, new_angle: float) -> None: obj.rotate_object(new_angle) self.scene_update() @@ -349,7 +354,7 @@ def change_obj_info(self, layer_name: str, obj_name: str) -> None: self.get_object_conf(layer_name, obj_name), self.get_object_conf(FRAMES, obj.name), obj.is_draggable()) - #@need_save_state + @need_save_state def change_obj_from_info(self, conf: Dict[str, Any]) -> None: print(conf) obj = self.get_object(conf["name"]) @@ -428,10 +433,12 @@ def change_object_handler(self, handler_func, args: Dict[str, Any]) -> None: for obj_name in self.objects: handler_func(self.get_object(obj_name), args) + @need_save_state def painting_tiles(self, default_fill: str) -> None: self.change_tiles_handler(self.change_tile_type, {"default_fill": default_fill}) + #@need_save_state def rotate_tiles(self) -> None: self.change_tiles_handler(self.rotate_with_button, {}) @@ -442,6 +449,7 @@ def rotate_object_with_button(self, obj: ImageObject, self.rotate_obj(obj, new_angle) self.rotate_obj_on_map(obj.name, new_angle) + #@need_save_state def rotate_objects(self) -> None: self.change_object_handler(self.rotate_object_with_button, {}) @@ -678,8 +686,8 @@ def open_map(self, path: Path, map_name: str, is_new_map: bool = False, self.scene_update() def save_state(self) -> Memento: - # скопировали слои - layers = {name: layer.copy() for name, layer in self.map.map.layers.items()} + # custom deepcopy + layers = {name: self.get_layer_deepcopy(name) for name in self.map.map.layers} return Memento({"layers": layers, "map_height": self.map_height, "tile_width": self.tile_width, "tile_height": self.tile_height, "grid_scale": self.grid_scale, "grid_height": self.grid_height, @@ -689,6 +697,7 @@ def restore_state(self, m: Memento) -> None: state = m.get_state() if state: layers = state["layers"] + print(layers) self.delete_objects() # removing all elements from the original layers for layer in self.map.map.layers: @@ -698,6 +707,8 @@ def restore_state(self, m: Memento) -> None: # fill the original now empty layers with the copied data for layer_name in layers: layer = layers[layer_name] + if not layer: + layer = {} items = [item for item in layer] for item in items: self.map.map.layers[layer_name][item] = layer[item] From 3016a7c9de8fe02a9b8a3d0cf4137b917856f7fc Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Thu, 17 Nov 2022 02:27:50 +0300 Subject: [PATCH 13/22] fixed minibug --- packages/map_editor/layers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/map_editor/layers.py b/packages/map_editor/layers.py index cb16bc8..e375a8a 100644 --- a/packages/map_editor/layers.py +++ b/packages/map_editor/layers.py @@ -75,7 +75,8 @@ def __init__(self, **kwargs) -> None: def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: copied_layer = {} for name, value in layer.items(): - copied_layer[name] = {TILE_SIZE: {'x': value["x"], 'y': value["y"]}} + copied_layer[name] = {TILE_SIZE: {'x': value[TILE_SIZE]["x"], + 'y': value[TILE_SIZE]["y"]}} return copied_layer From da0939d2fbfed4dff3308504d0cfa8981a058560 Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Thu, 17 Nov 2022 17:29:10 +0300 Subject: [PATCH 14/22] fixed states --- packages/map_editor/mapAPI.py | 3 ++- packages/map_editor/mapViewer.py | 15 +++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/map_editor/mapAPI.py b/packages/map_editor/mapAPI.py index eba2d6c..7be86c3 100644 --- a/packages/map_editor/mapAPI.py +++ b/packages/map_editor/mapAPI.py @@ -249,7 +249,8 @@ def trimClicked(self): pass def selection_update(self, default_fill: str) -> None: - if self._editor_state.drawState == 'brush': + if self._editor_state.drawState == 'brush' and \ + self._map_viewer.have_selected_tiles(): self._map_viewer.painting_tiles(default_fill) def key_press_event(self, event: QKeyEvent) -> None: diff --git a/packages/map_editor/mapViewer.py b/packages/map_editor/mapViewer.py index 7a87d52..9563da2 100644 --- a/packages/map_editor/mapViewer.py +++ b/packages/map_editor/mapViewer.py @@ -85,7 +85,6 @@ def __init__(self, work_dir: str): self.setMouseTracking(True) def init_objects(self) -> None: - print("init objects") frames = self.get_layer("frames") for layer_name in REGISTER: layer = self.get_layer(layer_name) @@ -248,6 +247,7 @@ def set_obj_map_pos(self, obj: ImageObject, new_pos: Tuple[float, float]) -> None: obj.set_obj_map_pos(new_pos) + @need_save_state def move_obj_on_map(self, frame_name: str, new_pos: Tuple[float, float], obj_width: float = 0, @@ -423,7 +423,6 @@ def change_tiles_handler(self, handler_func, args: Dict[str, Any]) -> None: tiles = self.get_layer(TILES) for tile_name in tiles: tile = tiles[tile_name] - #print(tile.__dict__, tile.__str__(), dir(tile)) if self.is_selected_tile(tile): args["tile_name"] = tile_name args["tile"] = tile @@ -599,6 +598,14 @@ def select_tiles(self) -> None: for i, v in enumerate(raw_selection) ] + def have_selected_tiles(self) -> bool: + tiles = self.get_layer(TILES) + for tile_name in tiles: + tile = tiles[tile_name] + if self.is_selected_tile(tile): + return True + return False + def select_objects(self) -> None: raw_selection = [ min(self.mouse_start_x, self.mouse_cur_x), @@ -697,7 +704,7 @@ def restore_state(self, m: Memento) -> None: state = m.get_state() if state: layers = state["layers"] - print(layers) + #print(layers) self.delete_objects() # removing all elements from the original layers for layer in self.map.map.layers: @@ -706,7 +713,7 @@ def restore_state(self, m: Memento) -> None: del self.map.map.layers[layer][item] # fill the original now empty layers with the copied data for layer_name in layers: - layer = layers[layer_name] + layer = deepcopy(layers[layer_name]) if not layer: layer = {} items = [item for item in layer] From 934a3cd2a908c91f30b7624b4be484b6eb71bb82 Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Thu, 17 Nov 2022 17:48:17 +0300 Subject: [PATCH 15/22] deleting excessed states --- packages/map_editor/history.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/map_editor/history.py b/packages/map_editor/history.py index 6743c41..31edf7e 100644 --- a/packages/map_editor/history.py +++ b/packages/map_editor/history.py @@ -24,22 +24,22 @@ def delete(self, start_index: int) -> None: """ del self.buffer[start_index:] - def push(self, m: Memento) -> None: """ Add new state to the end of buffer. """ + if self.current_state_index + 1 == MAX_BUFFER_LENGTH: + self.buffer.pop(0) + self.current_state_index -= 1 if self.current_state_index + 1 < MAX_BUFFER_LENGTH: self.buffer.append(m) self.current_state_index = len(self.buffer) - 1 - def undo(self) -> Optional[Memento]: """ Return state from history at index current_state_index - 1. """ - if self.current_state_index - 1 >= 0: self.current_state_index -= 1 return self.buffer[self.current_state_index] @@ -52,7 +52,6 @@ def shift_undo(self) -> Optional[Memento]: """ Return state from history at index current_state_index + 1. """ - if self.current_state_index == len(self.buffer) - 1: return self.buffer[self.current_state_index] elif self.current_state_index + 1 < len(self.buffer): From bea98ccce0d434aa328f8f75c23195fb760f88b4 Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Tue, 22 Nov 2022 17:28:12 +0300 Subject: [PATCH 16/22] convert maplayer to dict --- packages/map_editor/classes/layers.py | 10 ++++- packages/map_editor/layers.py | 64 +-------------------------- 2 files changed, 9 insertions(+), 65 deletions(-) diff --git a/packages/map_editor/classes/layers.py b/packages/map_editor/classes/layers.py index 5ef556f..6739639 100644 --- a/packages/map_editor/classes/layers.py +++ b/packages/map_editor/classes/layers.py @@ -44,10 +44,16 @@ def check_config(self, config: Dict[str, Any]) -> bool: def set_layer_handler(self, handler: EntityHelper) -> None: self._layer_handler = handler - def get_layer_deepcopy(self, layer: MapLayer) -> Dict[str, Any]: + def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: if not len(layer): return {} - return layer.copy() + new_layer = {} + for name, item in layer.items(): + new_item = {} + for item_filed in self._default_conf: + new_item[item_filed] = deepcopy(layer[name][item_filed]) + new_layer[name] = new_item + return new_layer class BasicLayerHandler(AbstractHandler, AbstractLayer): diff --git a/packages/map_editor/layers.py b/packages/map_editor/layers.py index e375a8a..eba5483 100644 --- a/packages/map_editor/layers.py +++ b/packages/map_editor/layers.py @@ -1,7 +1,5 @@ -from copy import copy from pathlib import Path -from typing import Any, Dict, Optional -from dt_maps import MapLayer +from typing import Any, Dict from utils.constants import TILE_SIZE from mapStorage import MapStorage from classes.layers import BasicLayerHandler @@ -23,13 +21,6 @@ def check_config(self, config: Dict[str, Any]) -> bool: return super().check_config(config) and config.get("type") \ in [t.value for t in TileType] - def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: - copied_layer = {} - for name, value in layer.items(): - copied_layer[name] = {'i': value["i"], 'j': value["j"], - 'type': value["type"]} - return copied_layer - class WatchtowersLayerHandler(BasicLayerHandler): def __init__(self, **kwargs) -> None: @@ -40,13 +31,6 @@ def check_config(self, config: Dict[str, Any]) -> bool: return super().check_config(config) and config.get("configuration") \ in [t.value for t in WatchtowerType] - def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: - copied_layer = {} - for name, value in layer.items(): - copied_layer[name] = {'configuration': value["configuration"], - 'id': value["id"]} - return copied_layer - class FramesLayerHandler(BasicLayerHandler): def __init__(self, **kwargs) -> None: @@ -55,30 +39,12 @@ def __init__(self, **kwargs) -> None: 'pitch': 0.0}, 'relative_to': ""} super(FramesLayerHandler, self).__init__(**kwargs) - def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: - copied_layer = {} - for name, value in layer.items(): - pose = value["pose"] - copied_layer[name] = { - 'pose': {'x': pose["x"], 'y': pose["y"], 'z': pose["z"], - 'yaw': pose["yaw"], 'roll': pose["roll"], - 'pitch': pose["pitch"]}, - 'relative_to': value["relative_to"]} - return copied_layer - class TileMapsLayerHandler(BasicLayerHandler): def __init__(self, **kwargs) -> None: kwargs["default_conf"] = {TILE_SIZE: {'x': 0.585, 'y': 0.585}} super(TileMapsLayerHandler, self).__init__(**kwargs) - def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: - copied_layer = {} - for name, value in layer.items(): - copied_layer[name] = {TILE_SIZE: {'x': value[TILE_SIZE]["x"], - 'y': value[TILE_SIZE]["y"]}} - return copied_layer - class TrafficSignsLayerHandler(BasicLayerHandler): def __init__(self, **kwargs) -> None: @@ -89,26 +55,12 @@ def check_config(self, config: Dict[str, Any]) -> bool: return super().check_config(config) and \ config.get("type") in [t.value for t in TrafficSignType] - def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: - copied_layer = {} - for name, value in layer.items(): - copied_layer[name] = {"type": value["type"], "id": value["id"], - "family": value["family"]} - return copied_layer - class GroundTagsLayerHandler(BasicLayerHandler): def __init__(self, **kwargs) -> None: kwargs["default_conf"] = {"size": 0.15, "id": 0, "family": "36h11"} super(GroundTagsLayerHandler, self).__init__(**kwargs) - def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: - copied_layer = {} - for name, value in layer.items(): - copied_layer[name] = {"size": value["size"], "id": value["id"], - "family": value["family"]} - return copied_layer - class CitizensLayerHandler(BasicLayerHandler): def __init__(self, **kwargs) -> None: @@ -119,12 +71,6 @@ def check_config(self, config: Dict[str, Any]) -> bool: return super().check_config(config) and \ config.get("color") in [t.value for t in CitizenType] - def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: - copied_layer = {} - for name, value in layer.items(): - copied_layer[name] = {"color": value["color"]} - return copied_layer - class VehiclesLayerHandler(BasicLayerHandler): def __init__(self, **kwargs) -> None: @@ -137,14 +83,6 @@ def check_config(self, config: Dict[str, Any]) -> bool: config.get("configuration") in [t.value for t in VehicleType] and \ config.get("color") in [t.value for t in ColorType] - def get_layer_deepcopy(self, layer: MapLayer) -> Optional[Dict[str, Any]]: - copied_layer = {} - for name, value in layer.items(): - copied_layer[name] = {"color": value["color"], - "configuration": value["configuration"], - "id": value["id"]} - return copied_layer - if __name__ == '__main__': MapStorage(MapDescription(Path("./maps/tm1"), "map_1")) From 0b3460d5ef080374d93be18853a2fe0c4b0a0902 Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Tue, 22 Nov 2022 21:38:44 +0300 Subject: [PATCH 17/22] fixed first state bug --- packages/map_editor/main.py | 1 + packages/map_editor/mapViewer.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/map_editor/main.py b/packages/map_editor/main.py index 61b41c3..2bbc0c5 100644 --- a/packages/map_editor/main.py +++ b/packages/map_editor/main.py @@ -28,6 +28,7 @@ def main(args): # Create main window window = DuckWindow(args) + window.map_viewer.save_first_viewer_state() window.show() app.exec_() diff --git a/packages/map_editor/mapViewer.py b/packages/map_editor/mapViewer.py index 9563da2..40382dd 100644 --- a/packages/map_editor/mapViewer.py +++ b/packages/map_editor/mapViewer.py @@ -42,7 +42,6 @@ def save(*args, **kwargs): self = args[0] m = self.save_state() self.parentWidget().parent().push_state(m) - #return func(*args, **kwargs) return save @@ -136,6 +135,10 @@ def init_handlers(self) -> None: handlers_list[i].set_next(handlers_list[i + 1]) self.handlers = handlers_list[0] + @need_save_state + def save_first_viewer_state(self) -> None: + pass + def set_map_viewer_sizes(self, tile_width: float = 0, tile_height: float = 0) -> None: if not (tile_width and tile_height): From f07907a5e6bda813975a954e622ebca2e8cba49c Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Tue, 22 Nov 2022 22:15:16 +0300 Subject: [PATCH 18/22] clear history when open/create map --- packages/map_editor/history.py | 3 +++ packages/map_editor/mainWindow.py | 3 +++ packages/map_editor/mapAPI.py | 3 +++ packages/map_editor/mapViewer.py | 10 ++-------- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/map_editor/history.py b/packages/map_editor/history.py index 31edf7e..4d9410b 100644 --- a/packages/map_editor/history.py +++ b/packages/map_editor/history.py @@ -24,6 +24,9 @@ def delete(self, start_index: int) -> None: """ del self.buffer[start_index:] + def clear_history(self) -> None: + self.delete(0) + def push(self, m: Memento) -> None: """ Add new state to the end of buffer. diff --git a/packages/map_editor/mainWindow.py b/packages/map_editor/mainWindow.py index 9a97a31..cab8b13 100644 --- a/packages/map_editor/mainWindow.py +++ b/packages/map_editor/mainWindow.py @@ -359,6 +359,9 @@ def shift_undo_button_clicked(self) -> None: def push_state(self, m: Memento) -> None: self.map_api.push_state(m) + def clear_editor_history(self) -> None: + self.map_api.clear_editor_history() + # Brush mode def brush_mode(self) -> None: self.map_api.brush_mode(self.brush_button.isChecked()) diff --git a/packages/map_editor/mapAPI.py b/packages/map_editor/mapAPI.py index 7be86c3..f89b7c1 100644 --- a/packages/map_editor/mapAPI.py +++ b/packages/map_editor/mapAPI.py @@ -238,6 +238,9 @@ def shift_button_clicked(self) -> None: def push_state(self, m: Memento) -> None: self._history.push(m) + def clear_editor_history(self) -> None: + self._history.clear_history() + # Brush mode def brush_mode(self, brush_button_is_checked: bool) -> None: if brush_button_is_checked: diff --git a/packages/map_editor/mapViewer.py b/packages/map_editor/mapViewer.py index 40382dd..6604b29 100644 --- a/packages/map_editor/mapViewer.py +++ b/packages/map_editor/mapViewer.py @@ -682,6 +682,7 @@ def open_map(self, path: Path, map_name: str, is_new_map: bool = False, size: Tuple[int, int] = (0, 0), tile_size: Tuple[float, float] = (0, 0)) -> None: self.delete_objects() + self.parentWidget().parent().clear_editor_history() self.map.load_map(MapDescription(path, map_name)) self.set_tile_map() self.init_handlers() @@ -693,6 +694,7 @@ def open_map(self, path: Path, map_name: str, is_new_map: bool = False, self.init_objects() self.change_object_handler(self.scaled_obj, {"scale": self.scale}) self.set_map_size() + self.save_first_viewer_state() self.scene_update() def save_state(self) -> Memento: @@ -707,7 +709,6 @@ def restore_state(self, m: Memento) -> None: state = m.get_state() if state: layers = state["layers"] - #print(layers) self.delete_objects() # removing all elements from the original layers for layer in self.map.map.layers: @@ -724,11 +725,4 @@ def restore_state(self, m: Memento) -> None: self.map.map.layers[layer_name][item] = layer[item] # initialize map objects from layers self.init_objects() - # restore other settings - self.tile_width = state["tile_width"] - self.tile_height = state["tile_height"] - self.grid_scale = state["grid_scale"] - self.grid_height = state["grid_height"] - self.grid_width = state["grid_width"] - self.tile_map = state["tile_map"] self.scene_update() From 586eef29a7720056ce93f07f82b3a50c73b9142d Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Fri, 25 Nov 2022 15:40:45 +0300 Subject: [PATCH 19/22] all states are saved except rotation --- packages/map_editor/mapViewer.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/packages/map_editor/mapViewer.py b/packages/map_editor/mapViewer.py index 6604b29..7793484 100644 --- a/packages/map_editor/mapViewer.py +++ b/packages/map_editor/mapViewer.py @@ -36,7 +36,7 @@ from dt_maps.Map import REGISTER -def need_save_state(func): +def needsavestate(func): def save(*args, **kwargs): func(*args, **kwargs) self = args[0] @@ -135,7 +135,7 @@ def init_handlers(self) -> None: handlers_list[i].set_next(handlers_list[i + 1]) self.handlers = handlers_list[0] - @need_save_state + @needsavestate def save_first_viewer_state(self) -> None: pass @@ -161,7 +161,7 @@ def set_relative_to(self, object_name: str, value: str): self.handlers.handle( command=AddRelativeToObj(object_name, value)) - @need_save_state + @needsavestate def add_obj(self, type_of_element: str, item_name: str = None) -> None: i = 1 layer_name = f"{type_of_element}s" @@ -250,7 +250,7 @@ def set_obj_map_pos(self, obj: ImageObject, new_pos: Tuple[float, float]) -> None: obj.set_obj_map_pos(new_pos) - @need_save_state + @needsavestate def move_obj_on_map(self, frame_name: str, new_pos: Tuple[float, float], obj_width: float = 0, @@ -274,6 +274,7 @@ def rotate_obj(self, obj: ImageObject, new_angle: float) -> None: obj.rotate_object(new_angle) self.scene_update() + #@needsavestate def rotate_obj_on_map(self, frame_name: str, new_angle: float) -> None: self.handlers.handle(command=RotateCommand(frame_name, new_angle)) @@ -357,13 +358,14 @@ def change_obj_info(self, layer_name: str, obj_name: str) -> None: self.get_object_conf(layer_name, obj_name), self.get_object_conf(FRAMES, obj.name), obj.is_draggable()) - @need_save_state + @needsavestate def change_obj_from_info(self, conf: Dict[str, Any]) -> None: print(conf) obj = self.get_object(conf["name"]) if conf["is_valid"]: if conf["remove"]: - self.delete_object(obj) + self.delete_obj_on_map(obj) + self.objects.__delitem__(obj.name) obj.delete_object() else: if self.check_layer_config(FRAMES, @@ -386,9 +388,16 @@ def change_obj_from_info(self, conf: Dict[str, Any]) -> None: conf[FRAME]["pose"]["y"], obj.height()) + self.offset_y self.move_obj(obj, {"new_coordinates": (pos_x, pos_y)}) - self.move_obj_on_map(obj.name, (pos_x, pos_y), - obj_width=obj.width(), - obj_height=obj.height()) + # move obj on map + map_x = self.get_x_from_view((pos_x, pos_y)[0], + obj_width=obj.width(), + offset=self.offset_x) + map_y = self.get_y_from_view((pos_x, pos_y)[1], + obj_height=obj.height(), + offset=self.offset_y) + obj = self.get_object(obj.name) + self.set_obj_map_pos(obj, (map_x, map_y)) + self.move_obj_command(obj.name, (map_x, map_y)) else: self.parentWidget().parent().view_info_form("Error", "Invalid object frame values entered!") @@ -417,7 +426,7 @@ def change_obj_from_config(self, layer_name: str, obj_name: str, self.handlers.handle(ChangeObjCommand(layer_name, obj_name, new_config)) - @need_save_state + @needsavestate def delete_object(self, obj: ImageObject) -> None: self.delete_obj_on_map(obj) self.objects.__delitem__(obj.name) @@ -435,7 +444,7 @@ def change_object_handler(self, handler_func, args: Dict[str, Any]) -> None: for obj_name in self.objects: handler_func(self.get_object(obj_name), args) - @need_save_state + @needsavestate def painting_tiles(self, default_fill: str) -> None: self.change_tiles_handler(self.change_tile_type, {"default_fill": default_fill}) From 8db08c67efa1fa7291844ba220ec7d2f94aab0b9 Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Sat, 26 Nov 2022 00:19:15 +0300 Subject: [PATCH 20/22] fixed rotation --- packages/map_editor/main.py | 2 +- packages/map_editor/mapAPI.py | 1 + packages/map_editor/mapViewer.py | 7 ++----- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/map_editor/main.py b/packages/map_editor/main.py index 2bbc0c5..910cb2e 100644 --- a/packages/map_editor/main.py +++ b/packages/map_editor/main.py @@ -28,7 +28,7 @@ def main(args): # Create main window window = DuckWindow(args) - window.map_viewer.save_first_viewer_state() + window.map_viewer.save_viewer_state() window.show() app.exec_() diff --git a/packages/map_editor/mapAPI.py b/packages/map_editor/mapAPI.py index f89b7c1..7a5c68a 100644 --- a/packages/map_editor/mapAPI.py +++ b/packages/map_editor/mapAPI.py @@ -274,6 +274,7 @@ def key_release_event(self, event: QKeyEvent) -> None: def rotate_selected_objects(self) -> None: self._map_viewer.rotate_tiles() self._map_viewer.rotate_objects() + self._map_viewer.save_viewer_state() def set_debug_mode(self, debug_line: DebugLine) -> None: self._editor_state.debug_mode = True diff --git a/packages/map_editor/mapViewer.py b/packages/map_editor/mapViewer.py index 7793484..a046e5a 100644 --- a/packages/map_editor/mapViewer.py +++ b/packages/map_editor/mapViewer.py @@ -136,7 +136,7 @@ def init_handlers(self) -> None: self.handlers = handlers_list[0] @needsavestate - def save_first_viewer_state(self) -> None: + def save_viewer_state(self) -> None: pass def set_map_viewer_sizes(self, tile_width: float = 0, @@ -274,7 +274,6 @@ def rotate_obj(self, obj: ImageObject, new_angle: float) -> None: obj.rotate_object(new_angle) self.scene_update() - #@needsavestate def rotate_obj_on_map(self, frame_name: str, new_angle: float) -> None: self.handlers.handle(command=RotateCommand(frame_name, new_angle)) @@ -449,7 +448,6 @@ def painting_tiles(self, default_fill: str) -> None: self.change_tiles_handler(self.change_tile_type, {"default_fill": default_fill}) - #@need_save_state def rotate_tiles(self) -> None: self.change_tiles_handler(self.rotate_with_button, {}) @@ -460,7 +458,6 @@ def rotate_object_with_button(self, obj: ImageObject, self.rotate_obj(obj, new_angle) self.rotate_obj_on_map(obj.name, new_angle) - #@need_save_state def rotate_objects(self) -> None: self.change_object_handler(self.rotate_object_with_button, {}) @@ -703,7 +700,7 @@ def open_map(self, path: Path, map_name: str, is_new_map: bool = False, self.init_objects() self.change_object_handler(self.scaled_obj, {"scale": self.scale}) self.set_map_size() - self.save_first_viewer_state() + self.save_viewer_state() self.scene_update() def save_state(self) -> Memento: From 8d9de55d0cb2fe889d91fa94e7aa9161680adf78 Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Sat, 26 Nov 2022 00:30:00 +0300 Subject: [PATCH 21/22] some names fixes --- packages/map_editor/mainWindow.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/map_editor/mainWindow.py b/packages/map_editor/mainWindow.py index cab8b13..24781cf 100644 --- a/packages/map_editor/mainWindow.py +++ b/packages/map_editor/mainWindow.py @@ -183,7 +183,7 @@ def init_ui(self): b5.triggered.connect(self.undo_button_clicked) ''' - c1.triggered.connect(self.rotate_selected_tiles) + c1.triggered.connect(self.rotate_selected_objects) # TODO #c2.triggered.connect(self.trimClicked) @@ -349,11 +349,9 @@ def delete_button_clicked(self): pass def undo_button_clicked(self) -> None: - print(1) self.map_api.undo_button_clicked() def shift_undo_button_clicked(self) -> None: - print(2) self.map_api.shift_button_clicked() def push_state(self, m: Memento) -> None: @@ -381,7 +379,7 @@ def keyReleaseEvent(self, event: QKeyEvent) -> None: def mousePressEvent(self, event: QMouseEvent): self.map_api.mouse_press_event(event) - def rotate_selected_tiles(self) -> None: + def rotate_selected_objects(self) -> None: self.map_api.rotate_selected_objects() def update_debug_info(self, event: Dict[str, Any]) -> None: From 9fbe5746337fffd4ac4b1b98c79798e6a7a657e8 Mon Sep 17 00:00:00 2001 From: Valentina-Gol Date: Tue, 6 Dec 2022 13:32:43 +0300 Subject: [PATCH 22/22] fixed deleting --- packages/map_editor/mainWindow.py | 9 ++++++--- packages/map_editor/mapViewer.py | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/map_editor/mainWindow.py b/packages/map_editor/mainWindow.py index 038dd1f..aff4327 100644 --- a/packages/map_editor/mainWindow.py +++ b/packages/map_editor/mainWindow.py @@ -99,6 +99,10 @@ def init_ui(self): a6 = QtWidgets.QAction(QtGui.QIcon("img/icons/leftup.png"), _translate("MainWindow", "To the corner of the map (Ctrl+M)"), self) a7 = QtWidgets.QAction(QtGui.QIcon("img/icons/undo.png"), _translate("MainWindow", "Undo (Ctrl+Z)"), self) a8 = QtWidgets.QAction(QtGui.QIcon("img/icons/shift_undo.png"), _translate("MainWindow", "Shift undo (Ctrl+Shift+Z)"), self) + a9 = QtWidgets.QAction(QtGui.QIcon("img/icons/delete.png"), + _translate("MainWindow", + "Delete (Ctrl+D or Delete)"), self) + a9.setShortcuts(["Ctrl+D", "Delete"]) a6.setShortcut("Ctrl+M") a7.setShortcut("Ctrl+Z") a8.setShortcut("Ctrl+Shift+Z") @@ -137,6 +141,7 @@ def init_ui(self): a6.triggered.connect(self.to_the_map_corner) a7.triggered.connect(self.undo_button_clicked) a8.triggered.connect(self.shift_undo_button_clicked) + a9.triggered.connect(self.delete_selected_objects) # TODO ''' @@ -157,6 +162,7 @@ def init_ui(self): for act in elem: tool_bar.addAction(act) tool_bar.addSeparator() + tool_bar.addAction(a9) tool_bar.addAction(a7) tool_bar.addAction(a8) tool_bar.addWidget(self.brush_button) @@ -206,9 +212,6 @@ def init_ui(self): def to_the_map_corner(self) -> None: self.map_api.to_the_map_corner() - def to_the_map_corner(self) -> None: - self.map_api.to_the_map_corner() - # Create a new map def open_map_triggered(self) -> None: self.map_api.open_map_triggered(self) diff --git a/packages/map_editor/mapViewer.py b/packages/map_editor/mapViewer.py index a7dde65..438d6aa 100644 --- a/packages/map_editor/mapViewer.py +++ b/packages/map_editor/mapViewer.py @@ -429,7 +429,6 @@ def change_obj_from_config(self, layer_name: str, obj_name: str, self.handlers.handle(ChangeObjCommand(layer_name, obj_name, new_config)) - @needsavestate def delete_object(self, obj: ImageObject) -> None: self.delete_obj_on_map(obj) self.objects.__delitem__(obj.name) @@ -635,6 +634,7 @@ def select_objects(self) -> None: raw_selection[1] <= map_object.y() <= raw_selection[3]: map_object.is_select = True + @needsavestate def delete_selected_objects(self) -> None: delete_list = [] for map_object in self.objects: