Events are queued by the button and popped in main where they are handled. Eventually this can be moved to the Game class or whatever. Could create something where other classes can subscribe to certain events or something.
Can specify position, font, text, colour, and the event to emit on click in the JSON.
Re worked fonts in Texture.py to support multiple fonts at multiple sizes.
Changes to InputHandler to support mouse events.
screenshots for writeup.
{
"widgets": [
{
- "type" : "ImageWidget",
+ "type" : "BasicButton",
+ "props" : {
+ "x" : 1000,
+ "y" : 600,
+ "w" : 256,
+ "h" : 64,
+ "event" : "quit game",
+ "text" : "Exit",
+ "font" : "m12",
+ "fontSize" : "medium",
+ "colour" : "255, 255, 255"
+ }
+ },
+ {
+ "type" : "BasicButton",
+ "props" : {
+ "x" : 1000,
+ "y" : 664,
+ "w" : 256,
+ "h" : 64,
+ "event" : "",
+ "text" : "Test",
+ "font" : "m12",
+ "fontSize" : "medium",
+ "colour" : "255, 255, 255"
+ }
+ },
+ {
+ "type" : "Image",
"props" : {
"source" : "smile.png",
- "x" : 100,
- "y" : 100,
- "w" : 400,
- "h" : 500,
+ "x" : 30,
+ "y" : 60,
+ "w" : 128,
+ "h" : 128,
"fit" : true
}
},
{
- "type": "ImageWidget",
+ "type": "Image",
"props" : {
- "w" : 250,
- "h" : 250,
- "x" : 1200,
- "y" : 600,
+ "w" : 200,
+ "h" : 200,
+ "x" : 1700,
+ "y" : 800,
"source" : "test.png",
"fit" : true
}
--- /dev/null
+import GUI.Widget as Widget
+import Texture
+from enum import Enum
+import pygame
+import os
+
+BUTTONSTATE_IDLE = 0
+BUTTONSTATE_HOVER = 1
+BUTTONSTATE_CLICK = 2
+
+class BasicButtonWidget(Widget.Widget):
+ def __init__(self, gui, x, y, w, h, event, text, font, fontSize, colour) -> None:
+ super().__init__(gui)
+
+ self.event = event
+
+ self.screenX = x
+ self.screenY = y
+ self.screenW = w
+ self.screenH = h
+
+ self.text = text
+ self.font = font
+ self.fontSize = fontSize
+ self.colour = colour
+
+ self.surface = pygame.Surface((self.screenW, self.screenH))
+ self.buttonImage = pygame.image.load(os.path.join('Assets', 'basicButton.png'))
+ self.buttonImage = pygame.transform.scale(self.buttonImage, (self.screenW * 3, self.screenH))
+ self.setSurface(BUTTONSTATE_IDLE)
+
+ def setHover(self, hover) -> None:
+ if not hover == self.hover:
+ self.hover = hover
+ if self.hover:
+ self.setSurface(BUTTONSTATE_HOVER)
+ else:
+ self.setSurface(BUTTONSTATE_IDLE)
+
+ def setClicked(self, click) -> None:
+ if not click == self.click:
+ self.click = click
+ self.hover = False
+ if self.click:
+ self.setSurface(BUTTONSTATE_CLICK)
+ self._onClicked()
+ else:
+ self.setSurface(BUTTONSTATE_IDLE)
+
+ def setSurface(self, buttonState) -> None:
+ sourceRect = (buttonState * self.screenW, 0, self.screenW, self.screenH)
+ self.surface.blit(self.buttonImage, (0,0), sourceRect)
+ text = Texture.fontDict[self.textSize].render(self.text, False, self.textCol)
+ textRect = text.get_rect()
+ textOriginX = (self.screenW / 2) - (textRect.w / 2)
+ textOriginY = (self.screenH / 2) - (textRect.h / 2)
+ self.surface.blit(text, (textOriginX, textOriginY))
+
+ def _onClicked(self) -> None:
+ self._emit(self.event)
+ pass
\ No newline at end of file
import json
from dataclasses import dataclass
import GUI.ImageWidget as ImageWidget
+import GUI.BasicButtonWidget as BasicButtonWidget
@dataclass
class Event:
class GuiManager:
def __init__(self) -> None:
+ # maybe make this a dictionary so they can have ids :)
self.widgetList = []
self.eventList = []
with open(path, "r") as file:
data = json.loads(file.read())
for widget in data["widgets"]:
- if widget["type"] == "ImageWidget" :
+ if widget["type"] == "Image" :
props = widget["props"]
self.createImageWidget(
props["x"],
props["source"],
props["fit"]
)
+ elif widget["type"] == "BasicButton" :
+ props = widget["props"]
+ self.createBasicButtonWidget(
+ props["x"],
+ props["y"],
+ props["w"],
+ props["h"],
+ props["event"],
+ props["text"],
+ props["font"],
+ props["fontSize"],
+ tuple(map(int, props["colour"].split(', ')))
+ )
+
def createImageWidget(self, x, y, w, h, path, fit) -> None:
self.widgetList.append(ImageWidget.ImageWidget(self, x, y, w, h, path, fit))
- def mouseClicked(self, mouseX, mouseY) -> None:
- # look through all widgets and see if the mouse hit it, if so call it's
- # onClicked function
- pass
+ def createBasicButtonWidget(self, x, y, w, h, event, text, font, fontSize, colour) -> None:
+ self.widgetList.append(BasicButtonWidget.BasicButtonWidget(self, x, y, w, h, event, text, font, fontSize, colour))
+
+ def handleMouseEvent(self, mouseX, mouseY, mouseDown) -> None:
+ for widget in self.widgetList:
+ if (mouseX > widget.screenX
+ and mouseX < widget.screenX + widget.screenW
+ and mouseY > widget.screenY
+ and mouseY < widget.screenY + widget.screenH):
+ if (mouseDown):
+ widget.setClicked(True)
+ else:
+ widget.setClicked(False)
+ widget.setHover(True)
+ else:
+ widget.setHover(False)
+
def registerEvent(self, event) -> None:
self.eventList.append(event)
\ No newline at end of file
self.screenY = 0
self.width = 0
self.height = 0
+ self.hover = False
+ self.click = False
- def onClicked(self) -> None:
+ def setClicked(self, click) -> None:
pass
- def emit(self, emitString) -> None:
- self.guiManager.registerEvent(GuiManager.Event(emitString))
\ No newline at end of file
+ def setHover(self, hover) -> None:
+ pass
+
+ def _emit(self, emitString) -> None:
+ self.guiManager.registerEvent(GuiManager.Event(emitString))
+
+ def _onClicked(self) -> None:
+ pass
\ No newline at end of file
debugLevel: int = 0
inputMade: bool = False
debugRegenWorld: bool = False
+ mousePos: Tuple = (0, 0)
+ lmbDown: bool = False
maxZoom = 3.0
minZoom = 0.125
else: newInputState.debugLevel = 0
elif event.key == pygame.K_F4:
newInputState.debugRegenWorld = True
+ elif event.type == pygame.MOUSEBUTTONDOWN:
+ newInputState.lmbDown = True
+ elif event.type == pygame.MOUSEBUTTONUP:
+ newInputState.lmbDown = False
+ newInputState.mousePos = pygame.mouse.get_pos()
+
newInputState.inputMade = not newInputState == globalInputState
# now replace the global one with our new one
# mutex lock if I move to thread
player = Player.Player(World.worldWidth / 2, World.worldHeight / 2)
+ running = True
+
# begin game loop
getTicksLastFrame = 0
t = 0
deltaTime = 0
- while not InputHandler.globalInputState.quit:
+ while running:
# Compute delta time
t = pygame.time.get_ticks()
deltaTime = (t - getTicksLastFrame) / 1000.0
Debug.debugRects.clear()
InputHandler.handleInputs()
+ running = not InputHandler.globalInputState.quit
+
+ guiManager.handleMouseEvent(*InputHandler.globalInputState.mousePos, InputHandler.globalInputState.lmbDown)
+
+ # handle event queue
+ while guiManager.eventList:
+ event = guiManager.eventList.pop()
+ if event.event == "quit game":
+ running = False
player.update()
animationSheet = pygame.image.load(os.path.join('Assets', 'animation.png'))
font = pygame.font.Font(os.path.join('Assets','m12.ttf'), 28)
+#smallFont = pygame.font.Font(os.path.join('Assets', 'm12.ttf'), 12)
+# = pygame.font.Font(os.path.join('Assets', 'm12.ttf'), 12)
+
+m12FontDict = {
+ "small" : pygame.font.Font(os.path.join('Assets', 'm12.ttf'), 12),
+ "medium" : pygame.font.Font(os.path.join('Assets', 'm12.ttf'), 20),
+ "large" : pygame.font.Font(os.path.join('Assets', 'm12.ttf'), 28),
+ "veryLarge" : pygame.font.Font(os.path.join('Assets', 'm12.ttf'), 32)
+}
+
+fontDictDict = {
+ "m12" : m12FontDict
+}
+
sheetWidth = spriteSheet.get_width()
sheetHeight = spriteSheet.get_height()
# multiply coords by sprite size :)