import sys import os import json from PyQt5.QtCore import Qt, QTimer from PyQt5.QtWidgets import ( QApplication, QMainWindow, QWidget, QHBoxLayout, QVBoxLayout, QPushButton, QLabel, QSlider, QDialog, QRadioButton, QDialogButtonBox, QAction, QFileDialog, QLineEdit, QMessageBox ) from editortool.map.glwidget import GLWidget from editortool.map.chunkpanel import ChunkPanel from editortool.map.mapinfopanel import MapInfoPanel class MapWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Dusk Map Editor") self.resize(1280, 720) # File menu setup menubar = self.menuBar() file_menu = menubar.addMenu("File") action_new = QAction("New", self) action_open = QAction("Open", self) action_save = QAction("Save", self) action_save_as = QAction("Save As", self) file_menu.addAction(action_new) file_menu.addAction(action_open) file_menu.addAction(action_save) file_menu.addAction(action_save_as) action_new.triggered.connect(self.newFile) action_open.triggered.connect(self.openFile) action_save.triggered.connect(self.saveFile) action_save_as.triggered.connect(self.saveFileAs) self.current_file = None self.dirty = False self.highlighted_pos = [0, 0, 0] # x, y, z central = QWidget() self.setCentralWidget(central) main_layout = QHBoxLayout(central) # Left panel (ChunkPanel) self.chunk_panel = ChunkPanel() left_widget = QWidget() left_widget.setLayout(self.chunk_panel.layout()) left_widget.setFixedWidth(200) main_layout.addWidget(left_widget) # Center panel (GLWidget + controls) self.gl_widget = GLWidget(self) main_layout.addWidget(self.gl_widget, stretch=3) # Right panel (MapInfoPanel) self.map_info_panel = MapInfoPanel() right_widget = self.map_info_panel right_widget.setFixedWidth(250) main_layout.addWidget(right_widget) self.map_title_input = self.map_info_panel.map_title_input self.map_title_input.textChanged.connect(self._on_map_title_changed) def _on_map_title_changed(self): self.dirty = True def newFile(self): self.current_file = None self.map_title_input.setText("") self.dirty = False def openFile(self): default_dir = os.path.join(os.path.dirname(__file__), '../../assets/map/') fname, _ = QFileDialog.getOpenFileName(self, "Open JSON File", default_dir, "JSON Files (*.json)") if fname: self.current_file = fname try: with open(fname, "r", encoding="utf-8") as f: data = json.load(f) self.map_title_input.setText(data.get("mapName", "")) self.dirty = False except Exception as e: self.map_title_input.setText("") QMessageBox.critical(self, "Error", f"Failed to load file:\n{e}") def saveFile(self): if self.current_file: self._save_to_file(self.current_file) else: self.saveFileAs() def saveFileAs(self): default_dir = os.path.join(os.path.dirname(__file__), '../../assets/map/') fname, _ = QFileDialog.getSaveFileName(self, "Save JSON File As", default_dir, "JSON Files (*.json)") if fname: self.current_file = fname self._save_to_file(fname) def _save_to_file(self, fname): data = { "mapName": self.map_title_input.text() } try: with open(fname, "w", encoding="utf-8") as f: json.dump(data, f, indent=2) self.dirty = False except Exception as e: QMessageBox.critical(self, "Error", f"Failed to save file:\n{e}") def closeEvent(self, event): if self.dirty: reply = QMessageBox.question( self, "Unsaved Changes", "You have unsaved changes. Do you want to save before closing?", QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel, QMessageBox.Save ) if reply == QMessageBox.Save: self.saveFile() if self.dirty: event.ignore() return elif reply == QMessageBox.Cancel: event.ignore() return # Discard: continue closing event.accept()