Prepping editor more...
This commit is contained in:
3
tools/editortool/map/.editor
Normal file
3
tools/editortool/map/.editor
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"lastFile": "/home/yourwishes/htdocs/dusk/assets/map/map.json"
|
||||
}
|
||||
@@ -1,36 +1,54 @@
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QPushButton, QGridLayout
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QPushButton, QGridLayout, QTreeWidget, QTreeWidgetItem
|
||||
from editortool.map.map import map
|
||||
|
||||
class ChunkPanel(QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
layout = QVBoxLayout(self)
|
||||
self.chunk_info_label = QLabel("Tile Information")
|
||||
layout.addWidget(self.chunk_info_label)
|
||||
self.move_label = QLabel("Move Selection")
|
||||
layout.addWidget(self.move_label)
|
||||
self.chunkInfoLabel = QLabel("Tile Information")
|
||||
layout.addWidget(self.chunkInfoLabel)
|
||||
|
||||
grid = QGridLayout()
|
||||
self.btn_up = QPushButton("U")
|
||||
self.btn_n = QPushButton("N")
|
||||
self.btn_down = QPushButton("D")
|
||||
self.btn_w = QPushButton("W")
|
||||
self.btn_s = QPushButton("S")
|
||||
self.btn_e = QPushButton("E")
|
||||
self.btnUp = QPushButton("U")
|
||||
self.btnN = QPushButton("N")
|
||||
self.btnDown = QPushButton("D")
|
||||
self.btnW = QPushButton("W")
|
||||
self.btnS = QPushButton("S")
|
||||
self.btnE = QPushButton("E")
|
||||
|
||||
# Arrange buttons: U N D on top row, W S E on bottom row
|
||||
grid.addWidget(self.btn_up, 0, 0)
|
||||
grid.addWidget(self.btn_n, 0, 1)
|
||||
grid.addWidget(self.btn_down, 0, 2)
|
||||
grid.addWidget(self.btn_w, 1, 0)
|
||||
grid.addWidget(self.btn_s, 1, 1)
|
||||
grid.addWidget(self.btn_e, 1, 2)
|
||||
grid.addWidget(self.btnUp, 0, 0)
|
||||
grid.addWidget(self.btnN, 0, 1)
|
||||
grid.addWidget(self.btnDown, 0, 2)
|
||||
grid.addWidget(self.btnW, 1, 0)
|
||||
grid.addWidget(self.btnS, 1, 1)
|
||||
grid.addWidget(self.btnE, 1, 2)
|
||||
layout.addLayout(grid)
|
||||
layout.addStretch()
|
||||
|
||||
self.btn_n.clicked.connect(lambda: map.moveRelative(0, 1, 0))
|
||||
self.btn_s.clicked.connect(lambda: map.moveRelative(0, -1, 0))
|
||||
self.btn_e.clicked.connect(lambda: map.moveRelative(1, 0, 0))
|
||||
self.btn_w.clicked.connect(lambda: map.moveRelative(-1, 0, 0))
|
||||
self.btn_up.clicked.connect(lambda: map.moveRelative(0, 0, 1))
|
||||
self.btn_down.clicked.connect(lambda: map.moveRelative(0, 0, -1))
|
||||
# Add expandable tree list
|
||||
self.tree = QTreeWidget()
|
||||
self.tree.setHeaderLabel("Chunks")
|
||||
# Example tree items
|
||||
parentItem = QTreeWidgetItem(self.tree, ["Chunk 1"])
|
||||
childItem1 = QTreeWidgetItem(parentItem, ["Tile A"])
|
||||
childItem2 = QTreeWidgetItem(parentItem, ["Tile B"])
|
||||
parentItem2 = QTreeWidgetItem(self.tree, ["Chunk 2"])
|
||||
QTreeWidgetItem(parentItem2, ["Tile C"])
|
||||
QTreeWidgetItem(parentItem2, ["Tile D"])
|
||||
self.tree.expandAll() # Expand by default, remove if you want collapsed
|
||||
layout.addWidget(self.tree, 1) # Give tree stretch factor so it expands
|
||||
|
||||
self.btnN.clicked.connect(lambda: map.moveRelative(0, 1, 0))
|
||||
self.btnS.clicked.connect(lambda: map.moveRelative(0, -1, 0))
|
||||
self.btnE.clicked.connect(lambda: map.moveRelative(1, 0, 0))
|
||||
self.btnW.clicked.connect(lambda: map.moveRelative(-1, 0, 0))
|
||||
self.btnUp.clicked.connect(lambda: map.moveRelative(0, 0, 1))
|
||||
self.btnDown.clicked.connect(lambda: map.moveRelative(0, 0, -1))
|
||||
|
||||
# Subscribe to parent's fileSaving event
|
||||
if parent is not None and hasattr(parent, 'fileSaving'):
|
||||
parent.fileSaving.subscribe(self.onFileSaving)
|
||||
|
||||
def onFileSaving(self, objOut):
|
||||
# Inject 'name' into the object
|
||||
objOut['name'] = 'ChunkPanel'
|
||||
@@ -1,36 +1,24 @@
|
||||
from dusk.event import Event
|
||||
|
||||
MAP_WIDTH = 5
|
||||
MAP_HEIGHT = 5
|
||||
MAP_DEPTH = 3
|
||||
|
||||
class Map:
|
||||
def __init__(self):
|
||||
self._position = [0, 0, 0] # x, y, z
|
||||
self.listeners = []
|
||||
self.position = [0, 0, 0] # x, y, z
|
||||
self.positionEvent = Event()
|
||||
self.chunks = []
|
||||
self.width = 5
|
||||
self.height = 5
|
||||
self.depth = 3
|
||||
|
||||
@property
|
||||
def position(self):
|
||||
return self._position
|
||||
|
||||
@position.setter
|
||||
def position(self, value):
|
||||
self._position = value
|
||||
self.notifyPositionListeners()
|
||||
|
||||
def addPositionListener(self, listener):
|
||||
self.listeners.append(listener)
|
||||
|
||||
def notifyPositionListeners(self):
|
||||
for listener in self.listeners:
|
||||
listener(self._position)
|
||||
|
||||
def moveTo(self, x, y, z):
|
||||
self.position = [x, y, z]
|
||||
self.positionEvent.invoke(self.position)
|
||||
|
||||
def moveRelative(self, x, y, z):
|
||||
self.moveTo(
|
||||
self._position[0] + x,
|
||||
self._position[1] + y,
|
||||
self._position[2] + z
|
||||
self.position[0] + x,
|
||||
self.position[1] + y,
|
||||
self.position[2] + z
|
||||
)
|
||||
|
||||
# Singleton instance
|
||||
|
||||
78
tools/editortool/map/mapdata.py
Normal file
78
tools/editortool/map/mapdata.py
Normal file
@@ -0,0 +1,78 @@
|
||||
import json
|
||||
from dusk.event import Event
|
||||
from PyQt5.QtWidgets import QFileDialog, QMessageBox
|
||||
from PyQt5.QtCore import QTimer
|
||||
import os
|
||||
|
||||
MAP_DEFAULT_PATH = os.path.join(os.path.dirname(__file__), '../../../assets/map/')
|
||||
EDITOR_CONFIG_PATH = os.path.join(os.path.dirname(__file__), '.editor')
|
||||
|
||||
class MapData:
|
||||
def __init__(self):
|
||||
self.data = {}
|
||||
self.dataOriginal = {}
|
||||
self.onMapData = Event()
|
||||
self.mapFileName = None
|
||||
|
||||
QTimer.singleShot(16, self.loadLastFile)
|
||||
|
||||
def loadLastFile(self):
|
||||
if os.path.exists(EDITOR_CONFIG_PATH):
|
||||
try:
|
||||
with open(EDITOR_CONFIG_PATH, 'r') as f:
|
||||
config = json.load(f)
|
||||
lastFile = config.get('lastFile')
|
||||
if lastFile and os.path.exists(lastFile):
|
||||
self.load(lastFile)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def updateEditorConfig(self):
|
||||
try:
|
||||
config = {'lastFile': self.mapFileName if self.mapFileName else ""}
|
||||
with open(EDITOR_CONFIG_PATH, 'w') as f:
|
||||
json.dump(config, f, indent=2)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def newFile(self):
|
||||
self.data = {}
|
||||
self.dataOriginal = {}
|
||||
self.mapFileName = None
|
||||
self.onMapData.invoke(self.data)
|
||||
self.updateEditorConfig()
|
||||
|
||||
def save(self, fname=None):
|
||||
if not self.mapFileName and fname is None:
|
||||
filePath, _ = QFileDialog.getSaveFileName(None, "Save Map File", MAP_DEFAULT_PATH, "Map Files (*.json)")
|
||||
if not filePath:
|
||||
return
|
||||
self.mapFileName = filePath
|
||||
if fname:
|
||||
self.mapFileName = fname
|
||||
if not self.isMapFileDirty():
|
||||
return
|
||||
try:
|
||||
with open(self.mapFileName, 'w') as f:
|
||||
json.dump(self.data, f, indent=2)
|
||||
self.dataOriginal = json.loads(json.dumps(self.data)) # Deep copy
|
||||
self.updateEditorConfig()
|
||||
except Exception as e:
|
||||
QMessageBox.critical(None, "Save Error", f"Failed to save map file:\n{e}")
|
||||
|
||||
def load(self, fileName):
|
||||
try:
|
||||
with open(fileName, 'r') as f:
|
||||
self.data = json.load(f)
|
||||
self.mapFileName = fileName
|
||||
self.dataOriginal = json.loads(json.dumps(self.data)) # Deep copy
|
||||
self.onMapData.invoke(self.data)
|
||||
self.updateEditorConfig()
|
||||
except Exception as e:
|
||||
QMessageBox.critical(None, "Load Error", f"Failed to load map file:\n{e}")
|
||||
|
||||
def isMapFileDirty(self):
|
||||
return json.dumps(self.data, sort_keys=True) != json.dumps(self.dataOriginal, sort_keys=True)
|
||||
|
||||
def isDirty(self):
|
||||
return self.isMapFileDirty()
|
||||
@@ -2,22 +2,23 @@ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QLineEdit, QPushButton
|
||||
from editortool.map.map import map
|
||||
from dusk.defs import defs
|
||||
|
||||
CHUNK_WIDTH = int(defs.get('CHUNK_WIDTH'))
|
||||
CHUNK_HEIGHT = int(defs.get('CHUNK_HEIGHT'))
|
||||
CHUNK_DEPTH = int(defs.get('CHUNK_DEPTH'))
|
||||
chunkWidth = int(defs.get('CHUNK_WIDTH'))
|
||||
chunkHeight = int(defs.get('CHUNK_HEIGHT'))
|
||||
chunkDepth = int(defs.get('CHUNK_DEPTH'))
|
||||
|
||||
class MapInfoPanel(QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
layout = QVBoxLayout()
|
||||
map_info_label = QLabel("Map Information")
|
||||
layout.addWidget(map_info_label)
|
||||
self.parent = parent
|
||||
|
||||
map_title_label = QLabel("Map Title")
|
||||
self.map_title_input = QLineEdit()
|
||||
layout.addWidget(map_title_label)
|
||||
layout.addWidget(self.map_title_input)
|
||||
# Components
|
||||
layout = QVBoxLayout()
|
||||
|
||||
mapTitleLabel = QLabel("Map Title")
|
||||
self.mapTitleInput = QLineEdit()
|
||||
layout.addWidget(mapTitleLabel)
|
||||
layout.addWidget(self.mapTitleInput)
|
||||
|
||||
tilePositionLabel = QLabel("Tile Position")
|
||||
layout.addWidget(tilePositionLabel)
|
||||
@@ -43,13 +44,18 @@ class MapInfoPanel(QWidget):
|
||||
layout.addStretch()
|
||||
self.setLayout(layout)
|
||||
|
||||
# Events
|
||||
self.tileGo.clicked.connect(self.goToPosition)
|
||||
self.tileXInput.returnPressed.connect(self.goToPosition)
|
||||
self.tileYInput.returnPressed.connect(self.goToPosition)
|
||||
self.tileZInput.returnPressed.connect(self.goToPosition)
|
||||
map.positionEvent.sub(self.updatePositionLabels)
|
||||
parent.mapData.onMapData.sub(self.onMapData)
|
||||
|
||||
self.mapTitleInput.textChanged.connect(self.onMapNameChange)
|
||||
|
||||
# Initial label setting
|
||||
self.updatePositionLabels(map.position)
|
||||
map.addPositionListener(self.updatePositionLabels)
|
||||
|
||||
def goToPosition(self):
|
||||
try:
|
||||
@@ -64,5 +70,12 @@ class MapInfoPanel(QWidget):
|
||||
self.tileXInput.setText(str(pos[0]))
|
||||
self.tileYInput.setText(str(pos[1]))
|
||||
self.tileZInput.setText(str(pos[2]))
|
||||
self.chunkPosLabel.setText(f"Chunk Position: {pos[0] % CHUNK_WIDTH}, {pos[1] % CHUNK_HEIGHT}, {pos[2] % CHUNK_DEPTH}")
|
||||
self.chunkLabel.setText(f"Chunk: {pos[0] // CHUNK_WIDTH}, {pos[1] // CHUNK_HEIGHT}, {pos[2] // CHUNK_DEPTH}")
|
||||
self.chunkPosLabel.setText(f"Chunk Position: {pos[0] % chunkWidth}, {pos[1] % chunkHeight}, {pos[2] % chunkDepth}")
|
||||
self.chunkLabel.setText(f"Chunk: {pos[0] // chunkWidth}, {pos[1] // chunkHeight}, {pos[2] // chunkDepth}")
|
||||
|
||||
def onMapData(self, data):
|
||||
self.updatePositionLabels(map.position)
|
||||
self.mapTitleInput.setText(data.get("mapName", ""))
|
||||
|
||||
def onMapNameChange(self, text):
|
||||
self.parent.mapData.data['mapName'] = text
|
||||
39
tools/editortool/map/toolbar.py
Normal file
39
tools/editortool/map/toolbar.py
Normal file
@@ -0,0 +1,39 @@
|
||||
import os
|
||||
from PyQt5.QtWidgets import QAction, QMenuBar, QFileDialog
|
||||
from editortool.map.mapdata import MAP_DEFAULT_PATH
|
||||
|
||||
class MapToolbar:
|
||||
def __init__(self, parent):
|
||||
self.parent = parent
|
||||
self.menubar = parent.menuBar()
|
||||
self.fileMenu = self.menubar.addMenu("File")
|
||||
|
||||
self.actionNew = QAction("New", parent)
|
||||
self.actionOpen = QAction("Open", parent)
|
||||
self.actionSave = QAction("Save", parent)
|
||||
self.actionSaveAs = QAction("Save As", parent)
|
||||
|
||||
self.actionNew.triggered.connect(self.newFile)
|
||||
self.actionOpen.triggered.connect(self.openFile)
|
||||
self.actionSave.triggered.connect(self.saveFile)
|
||||
self.actionSaveAs.triggered.connect(self.saveAsFile)
|
||||
self.fileMenu.addAction(self.actionNew)
|
||||
self.fileMenu.addAction(self.actionOpen)
|
||||
self.fileMenu.addAction(self.actionSave)
|
||||
self.fileMenu.addAction(self.actionSaveAs)
|
||||
|
||||
def newFile(self):
|
||||
self.parent.mapData.newFile()
|
||||
|
||||
def openFile(self):
|
||||
filePath, _ = QFileDialog.getOpenFileName(self.menubar, "Open Map File", MAP_DEFAULT_PATH, "Map Files (*.json)")
|
||||
if filePath:
|
||||
self.parent.mapData.load(filePath)
|
||||
|
||||
def saveFile(self):
|
||||
self.parent.mapData.save()
|
||||
|
||||
def saveAsFile(self):
|
||||
filePath, _ = QFileDialog.getSaveFileName(self.menubar, "Save Map File As", MAP_DEFAULT_PATH, "Map Files (*.json)")
|
||||
if filePath:
|
||||
self.parent.mapData.save(filePath)
|
||||
Reference in New Issue
Block a user