Initial commit
This commit is contained in:
commit
565b6ba903
12 changed files with 2284 additions and 0 deletions
439
gamegui.py
Normal file
439
gamegui.py
Normal file
|
@ -0,0 +1,439 @@
|
|||
# gamegui.py
|
||||
|
||||
from tkinter import *
|
||||
from tkinter import ttk
|
||||
from tkinter import filedialog
|
||||
from tkinter import messagebox
|
||||
from tile import Tile
|
||||
from gamebase import GameBase
|
||||
import io
|
||||
|
||||
class App(ttk.Frame):
|
||||
|
||||
def __init__(self, master, gameBase):
|
||||
#print('Initializing...')
|
||||
super(App, self).__init__(master)
|
||||
self.gameBase = gameBase
|
||||
self.gameBase.outstream = io.StringIO()
|
||||
self.gameBase.requestInput = self.requestInput
|
||||
self.gameBase.onLevelLoad = self.getGraphics
|
||||
self.selected = (-1, -1)
|
||||
self.parent = master
|
||||
self.mapSize = (800, 450)
|
||||
self.hasChanged = False
|
||||
self.fileName = 'Untitled'
|
||||
self.invTuple = tuple(self.gameBase.playerInv.keys())
|
||||
self.invNames = StringVar(value=self.invTuple)
|
||||
#self.project = Project()
|
||||
self.tool = StringVar()
|
||||
self.brush = StringVar()
|
||||
self.history = []
|
||||
self.redos = []
|
||||
#self.selectedArea = (0, 0, self.project.x-1, self.project.y-1)
|
||||
self.parent.clipboard_clear()
|
||||
self.parent.clipboard_append('')
|
||||
self.grid()
|
||||
self.createWidgets()
|
||||
self.makeTheDisplayWork()
|
||||
self.bindKeys()
|
||||
|
||||
#print('Done.')
|
||||
|
||||
def createWidgets(self):
|
||||
#print('Creating Widgets...')
|
||||
self.initWidth, self.initHeight = 0, 0
|
||||
|
||||
# create menu bar
|
||||
self.createMenuBar()
|
||||
|
||||
# create map
|
||||
self.createMapView()
|
||||
|
||||
# create text out
|
||||
self.createTextOut()
|
||||
|
||||
# create inventory list
|
||||
self.createInventoryView()
|
||||
|
||||
#self.tool.set('setone')
|
||||
#brushes = ttk.Combobox(self, textvariable = self.brush, values = tuple(sorted(Project.tileID.keys())))
|
||||
#brushes.grid(column = 0, row = 6, sticky = (E, W))
|
||||
#brushes.state(['readonly'])
|
||||
#brushes.set('Dirt')
|
||||
#ttk.Separator(self, orient = VERTICAL).grid(column = 1, row = 0, rowspan = 9, sticky = (N, S))
|
||||
|
||||
ttk.Sizegrip(self).grid(column = 1, row = 1, sticky = (S, E))
|
||||
self.columnconfigure(0, weight = 1)
|
||||
self.rowconfigure(0, weight = 1)
|
||||
#print('Done.')
|
||||
|
||||
def createMenuBar(self):
|
||||
#print('Creating the menubar...')
|
||||
menubar = Menu(self.parent)
|
||||
menuFile = Menu(menubar)
|
||||
#menuEdit = Menu(menubar)
|
||||
menuHelp = Menu(menubar)
|
||||
|
||||
menubar.add_cascade(menu = menuFile, label = 'File')
|
||||
menuFile.add_command(label = 'New', command = lambda: self.loadLevel('maps/apartment.xml'), accelerator = 'Ctrl+N')
|
||||
menuFile.add_command(label = 'Open...', command = self.fileOpen, accelerator = 'Ctrl+O')
|
||||
menuFile.add_command(label = 'Save', command = self.fileSave, accelerator = 'Ctrl+S')
|
||||
menuFile.add_command(label = 'Save As...', command = self.fileSaveAs)
|
||||
menuFile.add_separator()
|
||||
menuFile.add_command(label = 'Exit', command = self.onQuit, accelerator = 'Ctrl+Q')
|
||||
|
||||
#menubar.add_cascade(menu = menuEdit, label = 'Edit')
|
||||
#menuEdit.add_command(label = 'Undo', command = self.undo, accelerator = 'Ctrl+Z')
|
||||
#menuEdit.add_command(label = 'Redo', command = self.redo, accelerator = 'Ctrl+Y')
|
||||
#menuEdit.add_separator()
|
||||
#menuEdit.add_command(label = 'Cut', command = self.cut, accelerator = 'Ctrl+X')
|
||||
#menuEdit.add_command(label = 'Copy', command = self.copy, accelerator = 'Ctrl+C')
|
||||
#menuEdit.add_command(label = 'Paste', command = self.paste, accelerator = 'Ctrl+V')
|
||||
|
||||
menubar.add_cascade(menu = menuHelp, label = 'Help')
|
||||
menuHelp.add_command(label = 'About', command = self.about)
|
||||
menuHelp.add_separator()
|
||||
menuHelp.add_command(label = 'Read Me', command = self.readme)
|
||||
self.parent.configure(menu = menubar)
|
||||
#print('Done.')
|
||||
|
||||
def createMapView(self):
|
||||
mapFrame = ttk.LabelFrame(self, text = "map")
|
||||
mapFrame.grid(column = 0, row = 0)
|
||||
self.levelDisplay = Canvas(mapFrame, width = self.mapSize[0], height = self.mapSize[1], scrollregion = '0 0 2048 2048')
|
||||
self.levelDisplay.grid(column = 0, row = 0)
|
||||
vbar = ttk.Scrollbar(mapFrame, orient = VERTICAL, command = self.levelDisplay.yview)
|
||||
self.levelDisplay.configure(yscrollcommand = vbar.set)
|
||||
vbar.grid(column = 1, row = 0, sticky = (N, S))
|
||||
hbar = ttk.Scrollbar(mapFrame, orient = HORIZONTAL, command = self.levelDisplay.xview)
|
||||
self.levelDisplay.configure(xscrollcommand = hbar.set)
|
||||
hbar.grid(column = 0, row = 1, sticky = (E, W))
|
||||
self.bind('<Configure>', self.onResize)
|
||||
|
||||
def createTextOut(self):
|
||||
textFrame = ttk.LabelFrame(self, text = "Info")
|
||||
textFrame.grid(column = 0, row = 1)
|
||||
self.infoDisplay = Text(textFrame, width = 80, height = 8, state = 'disabled')
|
||||
self.infoDisplay.grid(column = 0, row = 0)
|
||||
vbar = ttk.Scrollbar(textFrame, orient = VERTICAL, command = self.infoDisplay.yview)
|
||||
self.infoDisplay.configure(yscrollcommand = vbar.set)
|
||||
vbar.grid(column = 1, row = 0, sticky = (N, S))
|
||||
self.infoCursor = 0
|
||||
|
||||
def createInventoryView(self):
|
||||
invFrame = ttk.LabelFrame(self, text = "Inventory")
|
||||
invFrame.grid(column = 1, row = 0)
|
||||
self.invDisplay = Listbox(invFrame, height = 24, listvariable = self.invNames)
|
||||
self.invDisplay.grid(column = 0, row = 0)
|
||||
vbar = ttk.Scrollbar(invFrame, orient = VERTICAL, command = self.invDisplay.yview)
|
||||
self.invDisplay.configure(yscrollcommand = vbar.set)
|
||||
vbar.grid(column = 1, row = 0, sticky = (N, S))
|
||||
|
||||
def getGraphics(self):
|
||||
self.tiles = {}
|
||||
for i in range(len(self.gameBase.level.floorColors)):
|
||||
self.tiles['e{0}'.format(i)] = Tile(self.gameBase.level.floorColors[i])
|
||||
for i in range(len(self.gameBase.level.wallColors)):
|
||||
self.tiles['w{0}'.format(i)] = Tile(self.gameBase.level.wallColors[i])
|
||||
self.tiles['player'] = Tile('clear', 'blue', 'o')
|
||||
for thing in self.gameBase.level.thingNames:
|
||||
graphic = self.gameBase.level.thingNames[thing].graphic
|
||||
self.tiles[thing] = Tile(graphic[0], graphic[1], graphic[2])
|
||||
|
||||
def makeTheDisplayWork(self):
|
||||
#print('Making the display work...')
|
||||
# level display
|
||||
self.context = Menu(self.levelDisplay)
|
||||
self.context.add_command(label = 'Load Map', command = lambda: self.loadLevel('maps/apartment.xml'))
|
||||
self.context.add_command(label = 'Go', command = lambda: self.go(self.selected[0], self.selected[1]))
|
||||
self.context.add_command(label = 'Run', command = lambda: self.go(self.selected[0], self.selected[1], True))
|
||||
self.context.add_command(label = 'Look', command = lambda: self.look(self.selected[0], self.selected[1]))
|
||||
self.context.add_command(label = 'Use', command = lambda: self.use(self.selected[0], self.selected[1]))
|
||||
self.context.add_command(label = 'Take', command = lambda: self.take(self.selected[0], self.selected[1]))
|
||||
#self.context.add_command(label = 'Cut', command = self.cut, accelerator = 'Ctrl+X')
|
||||
#self.context.add_command(label = 'Goblin...')
|
||||
#self.context.entryconfigure('Goblin...', command = self.configureGoblin, state = DISABLED)
|
||||
#self.refreshDisplay()
|
||||
self.levelDisplay.bind('<1>', self.handleClick)
|
||||
self.levelDisplay.bind('<Double-1>', self.handleDoubleClick)
|
||||
#self.levelDisplay.bind('<B1-Motion>', self.handleDragEvent)
|
||||
#self.levelDisplay.bind('<ButtonRelease-1>', self.handleReleaseEvent)
|
||||
self.levelDisplay.bind('<3>', self.handleRightClick)
|
||||
|
||||
# inventory list
|
||||
self.invContext = Menu(self.invDisplay)
|
||||
self.invContext.add_command(label = 'Look', command = lambda: self.look(self.invTuple[self.invDisplay.curselection()[0]]))
|
||||
self.invContext.add_command(label = 'Use', command = lambda: self.use(self.invTuple[self.invDisplay.curselection()[0]]))
|
||||
self.invContext.add_command(label = 'Drop', command = lambda: self.drop(self.invTuple[self.invDisplay.curselection()[0]]))
|
||||
self.invDisplay.bind('<<ListboxSelect>>', lambda e: self.look(self.invTuple[self.invDisplay.curselection()[0]]))
|
||||
self.invDisplay.bind('<3>', lambda e: self.invContext.post(e.x_root, e.y_root))
|
||||
#print('Done.')
|
||||
pass
|
||||
|
||||
def bindKeys(self):
|
||||
self.parent.bind('<Control-n>', lambda e: self.fileNew())
|
||||
self.parent.bind('<Control-o>', lambda e: self.fileOpen())
|
||||
self.parent.bind('<Control-s>', lambda e: self.fileSave())
|
||||
#self.parent.bind('<Control-z>', lambda e: self.undo())
|
||||
#self.parent.bind('<Control-y>', lambda e: self.redo())
|
||||
#self.parent.bind('<Control-x>', lambda e: self.cut())
|
||||
#self.parent.bind('<Control-c>', lambda e: self.copy())
|
||||
#self.parent.bind('<Control-v>', lambda e: self.paste())
|
||||
self.parent.bind('<Control-q>', lambda e: self.onQuit())
|
||||
|
||||
def refreshDisplay(self):
|
||||
#print('Refreshing the display...')
|
||||
# refresh the map
|
||||
self.levelDisplay.delete('all')
|
||||
for y in range(self.gameBase.level.dimensions[1]):
|
||||
for x in range(self.gameBase.level.dimensions[0]):
|
||||
pos = self.gameBase.level.mapMatrix[y][x]
|
||||
if pos[0] == 'w':
|
||||
self.tiles['w{0}'.format(pos[1])].paint(self.levelDisplay, x, y)
|
||||
else:
|
||||
self.tiles['e{0}'.format(pos[1])].paint(self.levelDisplay, x, y)
|
||||
for name in self.gameBase.level.thingNames:
|
||||
thing = self.gameBase.level.getThingByName(name)
|
||||
self.tiles[name].paint(self.levelDisplay, thing.x, thing.y)
|
||||
self.tiles['player'].paint(self.levelDisplay, self.gameBase.playerx, self.gameBase.playery)
|
||||
# refresh the info box
|
||||
self.gameBase.outstream.seek(self.infoCursor)
|
||||
#print(self.gameBase.outstream.tell())
|
||||
#print(self.gameBase.outstream.read())
|
||||
self.infoDisplay['state'] = 'normal'
|
||||
self.infoDisplay.insert('end', self.gameBase.outstream.read())
|
||||
self.infoDisplay.see('end -1 chars')
|
||||
self.infoDisplay['state'] = 'disabled'
|
||||
self.infoCursor = self.gameBase.outstream.tell()
|
||||
#print(self.infoCursor)
|
||||
#print('Done.')
|
||||
|
||||
def handleClick(self, event):
|
||||
x = int(self.levelDisplay.canvasx(event.x) / 32)
|
||||
y = int(self.levelDisplay.canvasy(event.y) / 32)
|
||||
if (x, y) != self.selected:
|
||||
self.selected = (x, y)
|
||||
self.look(x, y)
|
||||
|
||||
def handleDoubleClick(self, event):
|
||||
x = int(self.levelDisplay.canvasx(event.x) / 32)
|
||||
y = int(self.levelDisplay.canvasy(event.y) / 32)
|
||||
thing = self.gameBase.level.getThingAtCoords(x, y)
|
||||
if thing != None and thing.useable:
|
||||
self.use(x, y)
|
||||
else:
|
||||
self.go(x, y)
|
||||
|
||||
def handleRightClick(self, event):
|
||||
x = int(self.levelDisplay.canvasx(event.x) / 32)
|
||||
y = int(self.levelDisplay.canvasy(event.y) / 32)
|
||||
self.selected = (x, y)
|
||||
self.context.post(event.x_root, event.y_root)
|
||||
|
||||
#def openInvContext(self, event):
|
||||
# self.invContext.post(event.x_root, event.y_root)
|
||||
|
||||
def handleDragEvent(self, event):
|
||||
x = min(int(self.levelDisplay.canvasx(event.x) / 32), self.project.x-1)
|
||||
y = min(int(self.levelDisplay.canvasy(event.y) / 32), self.project.y-1)
|
||||
|
||||
if self.tool.get() == 'select':
|
||||
rect = self.levelDisplay.find_withtag('selectArea')
|
||||
self.selectedArea = (min(x, self.firstX), min(y, self.firstY),
|
||||
max(x, self.firstX), max(y, self.firstY))
|
||||
self.levelDisplay.coords(rect,
|
||||
(self.selectedArea[0]*32, self.selectedArea[1]*32,
|
||||
self.selectedArea[2]*32+31, self.selectedArea[3]*32+31))
|
||||
|
||||
def handleReleaseEvent(self, event):
|
||||
x = int(self.levelDisplay.canvasx(event.x) / 32)
|
||||
y = int(self.levelDisplay.canvasy(event.y) / 32)
|
||||
|
||||
if self.tool.get() == 'select':
|
||||
rect = self.levelDisplay.find_withtag('selectArea')
|
||||
self.selectedArea = (min(x, self.firstX), min(y, self.firstY),
|
||||
max(x, self.firstX), max(y, self.firstY))
|
||||
self.levelDisplay.coords(rect,
|
||||
(self.selectedArea[0]*32, self.selectedArea[1]*32,
|
||||
self.selectedArea[2]*32+31, self.selectedArea[3]*32+31))
|
||||
tiles = self.project.getTiles(self.selectedArea)
|
||||
for y in range(len(tiles)):
|
||||
for x in range(len(tiles[0])):
|
||||
if type(tiles[y][x]) == Project.GoblinSettings:
|
||||
self.context.entryconfigure('Goblin...', state = NORMAL)
|
||||
break
|
||||
break
|
||||
else: pass
|
||||
|
||||
def loadLevel(self, fileName):
|
||||
self.gameBase.loadMap([fileName])
|
||||
#self.getGraphics()
|
||||
self.refreshDisplay()
|
||||
|
||||
def go(self, x, y, running = False):
|
||||
#print("go called")
|
||||
#print(x, y)
|
||||
if running:
|
||||
self.gameBase.go(['-r', str(x), str(y)])
|
||||
else:
|
||||
self.gameBase.go([str(x), str(y)])
|
||||
self.gameBase.gameEventLoop()
|
||||
self.refreshDisplay() #inefficient, but will work for now.
|
||||
|
||||
def look(self, x, y = 1):
|
||||
#print("look called")
|
||||
#if x == self.gameBase.playerx and y == self.gameBase.playery:
|
||||
# self.gameBase.look([
|
||||
if isinstance(x, int):
|
||||
thing = self.gameBase.level.getThingAtCoords(x, y)
|
||||
if thing != None:
|
||||
self.gameBase.look([thing.name])
|
||||
else:
|
||||
self.gameBase.look([])
|
||||
else:
|
||||
self.gameBase.look([x])
|
||||
self.gameBase.gameEventLoop()
|
||||
self.refreshDisplay() #inefficient, but will work for now.
|
||||
|
||||
def use(self, x, y = 1):
|
||||
if isinstance(x, int):
|
||||
self.gameBase.use([str(x), str(y)])
|
||||
else:
|
||||
self.gameBase.use([x])
|
||||
self.gameBase.gameEventLoop()
|
||||
self.refreshDisplay() #inefficient, but will work for now.
|
||||
|
||||
def take(self, x, y):
|
||||
self.gameBase.take([str(x), str(y)])
|
||||
self.gameBase.gameEventLoop()
|
||||
self.refreshDisplay() #inefficient, but will work for now.
|
||||
self.invTuple = tuple(self.gameBase.playerInv.keys())
|
||||
self.invNames.set(self.invTuple)
|
||||
|
||||
def drop(self, item):
|
||||
self.gameBase.drop([item])
|
||||
self.gameBase.gameEventLoop()
|
||||
self.refreshDisplay()
|
||||
self.invTuple = tuple(self.gameBase.playerInv.keys())
|
||||
self.invNames.set(self.invTuple)
|
||||
|
||||
def requestInput(self, prompt = ''):
|
||||
answer = messagebox.askyesno(message=prompt, icon='question', title='Prompt')
|
||||
if answer:
|
||||
return 'y'
|
||||
else:
|
||||
return 'n'
|
||||
|
||||
def fileNew(self):
|
||||
#print('Creating a new project...')
|
||||
if self.askToSave():
|
||||
self.newDialog = Toplevel(self.parent)
|
||||
self.newDialog.title('New Project')
|
||||
newFrame = Frame(self.newDialog)
|
||||
newFrame.grid()
|
||||
self.hei = StringVar()
|
||||
self.wid = StringVar()
|
||||
ttk.Label(newFrame, text = 'Width:').grid(column = 0, row = 0, sticky = W)
|
||||
ttk.Label(newFrame, text = 'Height:').grid(column = 0, row = 1, sticky = W)
|
||||
Spinbox(newFrame, from_ = 16, to = 255, increment = 1, textvariable = self.wid
|
||||
).grid(column = 1, row = 0, sticky = W)
|
||||
Spinbox(newFrame, from_ = 16, to = 255, increment = 1, textvariable = self.hei
|
||||
).grid(column = 1, row = 1, sticky = W)
|
||||
ttk.Button(newFrame, text = 'Create', command = self.__confirmNewDimensions,
|
||||
default = 'active').grid(column = 0, row = 2)
|
||||
ttk.Button(newFrame, text = 'Cancel', command = self.newDialog.destroy
|
||||
).grid(column = 1, row = 2)
|
||||
|
||||
#print('Done.')
|
||||
|
||||
def fileOpen(self):
|
||||
#print('Opening a project...')
|
||||
if self.askToSave():
|
||||
newName = filedialog.askopenfilename(defaultextension = '.dat', initialdir = 'saves')
|
||||
if newName != '':
|
||||
self.fileName = newName
|
||||
self.gameBase.loadGame((self.fileName,))
|
||||
self.gameBase.gameEventLoop()
|
||||
self.refreshDisplay()
|
||||
self.invTuple = tuple(self.gameBase.playerInv.keys())
|
||||
self.invNames.set(self.invTuple)
|
||||
#print('Done.')
|
||||
|
||||
def fileSave(self):
|
||||
#print('Saving a project...')
|
||||
newName = self.fileName
|
||||
if self.fileName == 'Untitled':
|
||||
self.fileSaveAs()
|
||||
elif newName != '':
|
||||
self.fileName = newName
|
||||
self.gameBase.saveGame((self.fileName,))
|
||||
self.hasChanged = False
|
||||
#print('Done.')
|
||||
|
||||
def fileSaveAs(self):
|
||||
newName = filedialog.asksaveasfilename(defaultextension = '.dat', initialdir = 'saves')
|
||||
if newName != '':
|
||||
self.fileName = newName
|
||||
self.gameBase.saveGame((self.fileName,))
|
||||
self.hasChanged = False
|
||||
|
||||
def onQuit(self):
|
||||
if self.askToSave():
|
||||
exit()
|
||||
|
||||
def askToSave(self):
|
||||
if self.hasChanged:
|
||||
insecure = messagebox.askyesnocancel(
|
||||
message = 'Do you want to save ' + self.fileName + ' before continuing?',
|
||||
icon = 'warning', title = 'New File')
|
||||
print(type(insecure))
|
||||
if insecure == None: return False
|
||||
elif insecure == True:
|
||||
self.fileSave()
|
||||
return True
|
||||
else: return True
|
||||
else: return True
|
||||
|
||||
def about(self):
|
||||
self.newDialog = Toplevel(self.parent)
|
||||
self.newDialog.title('About')
|
||||
newFrame = Frame(self.newDialog)
|
||||
newFrame.grid()
|
||||
ttk.Label(newFrame, text = 'I Am Gnome Level Editor v.0.9.0013').grid()
|
||||
ttk.Button(newFrame, text = 'Okay', command = self.newDialog.destroy).grid()
|
||||
|
||||
def readme(self):
|
||||
self.newDialog = Toplevel(self.parent)
|
||||
self.newDialog.title('About')
|
||||
newFrame = Frame(self.newDialog)
|
||||
newFrame.grid()
|
||||
text = Text(newFrame, width=80, height=40, wrap = 'word')
|
||||
text.grid(column = 0, row = 0)
|
||||
sbar = ttk.Scrollbar(newFrame, orient = VERTICAL, command = text.yview)
|
||||
sbar.grid(column = 1, row = 0, sticky = (N, S, W))
|
||||
text.configure(yscrollcommand = sbar.set)
|
||||
text.state(['disabled'])
|
||||
file = open('iag_readme.txt', 'r')
|
||||
text.insert('1.0', file.read())
|
||||
|
||||
def onResize(self, event):
|
||||
if self.initWidth == 0 and self.initHeight == 0:
|
||||
self.initWidth = event.width
|
||||
self.initHeight = event.height
|
||||
else:
|
||||
wDelta = event.width - int(self.initWidth)
|
||||
hDelta = event.height - int(self.initHeight)
|
||||
self.levelDisplay.configure(width = self.mapSize[0] + wDelta, height = self.mapSize[1] + hDelta)
|
||||
|
||||
# main
|
||||
if __name__ == '__main__':
|
||||
root = Tk()
|
||||
root.title('Game Gui (debug)')
|
||||
#root.geometry("1024x768")
|
||||
#root.resizable(FALSE, FALSE)
|
||||
root.option_add('*tearOff', FALSE)
|
||||
root.columnconfigure(0, weight = 1)
|
||||
root.rowconfigure(0, weight = 1)
|
||||
newApp = App(root, GameBase())
|
||||
newApp.grid(sticky = (N, S, E, W))
|
||||
root.mainloop()
|
Loading…
Add table
Add a link
Reference in a new issue