Prepping editor more...
All checks were successful
Build Dusk / build-linux (push) Successful in 39s
Build Dusk / build-psp (push) Successful in 1m6s

This commit is contained in:
2025-11-16 14:43:29 -06:00
parent cf59989167
commit 750e8840f0
10 changed files with 285 additions and 167 deletions

View File

@@ -0,0 +1,3 @@
{
"lastFile": "/home/yourwishes/htdocs/dusk/assets/map/map.json"
}

View File

@@ -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'

View File

@@ -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

View 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()

View File

@@ -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

View 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)