Skip to content

Commit 76a661d

Browse files
authored
Merge pull request #54 from AustL/popups
Popups
2 parents 617c79f + f6a1f44 commit 76a661d

File tree

5 files changed

+205
-6
lines changed

5 files changed

+205
-6
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ while run:
5353

5454
## Prerequisites
5555

56-
* [Python 3](https://www.python.org/downloads) `>= 3.7`
56+
* [Python 3](https://www.python.org/downloads) `>= 3.10`
5757
* [Pygame](https://www.pygame.org/wiki/GettingStarted) `>= 2.0.0`
5858

5959
## Installation

pygame_widgets/popup.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import pygame
2+
import tkinter as tk
3+
from tkinter import messagebox
4+
from enum import Enum
5+
6+
import pygame_widgets
7+
from pygame_widgets.widget import WidgetBase
8+
9+
tk.Tk().wm_withdraw()
10+
11+
12+
class PopupType(Enum):
13+
INFO = 0
14+
ERROR = 1
15+
WARNING = 2
16+
QUESTION = 3
17+
OK_CANCEL = 4
18+
YES_NO = 5
19+
YES_NO_CANCEL = 6
20+
RETRY_CANCEL = 7
21+
22+
23+
class Popup(WidgetBase):
24+
def __init__(self, win: pygame.Surface, x: int, y: int, width: int, height: int, popupType: PopupType,
25+
title: str, text: str, trigger=lambda *args: None, *buttons, **kwargs):
26+
super().__init__(win, x, y, width, height)
27+
self.popupType = popupType
28+
self.title = title
29+
self.text = text
30+
self.trigger = trigger
31+
self.buttons = buttons
32+
33+
self.margin = kwargs.get('margin', 20)
34+
35+
self.titleColour = kwargs.get('titleColour', (0, 0, 0))
36+
self.titleSize = kwargs.get('titleSize', 40)
37+
self.titleFont = kwargs.get('titleFont', pygame.font.SysFont('calibri', self.titleSize, True))
38+
self.titleRect = self.alignTitleRect()
39+
40+
self.textColour = kwargs.get('textColour', (0, 0, 0))
41+
self.textSize = kwargs.get('textSize', 18)
42+
self.textFont = kwargs.get('textFont', pygame.font.SysFont('calibri', self.textSize))
43+
self.textRect = self.alignTextRect()
44+
45+
self.radius = kwargs.get('radius', 0)
46+
47+
self.colour = kwargs.get('colour', (150, 150, 150))
48+
self.shadowDistance = kwargs.get('shadowDistance', 0)
49+
self.shadowColour = kwargs.get('shadowColour', (210, 210, 180))
50+
51+
self.result = None
52+
53+
self.hide()
54+
55+
def alignTitleRect(self):
56+
return pygame.Rect(self._x + self.margin, self._y + self.margin,
57+
self._width - self.margin * 2, self._height // 3 - self.margin * 2)
58+
59+
def alignTextRect(self):
60+
return pygame.Rect(self._x + self.margin, self._y + self._height // 3,
61+
self._width - self.margin * 2, self._height // 2 - self.margin * 2)
62+
63+
def listen(self, events):
64+
if self.trigger():
65+
self.show()
66+
messagebox.showinfo(self.title, self.text)
67+
68+
def draw(self):
69+
pass
70+
71+
def show(self):
72+
super().show()
73+
match self.popupType:
74+
case PopupType.INFO:
75+
messagebox.showinfo(self.title, self.text)
76+
case PopupType.ERROR:
77+
messagebox.showerror(self.title, self.text)
78+
case PopupType.WARNING:
79+
messagebox.showwarning(self.title, self.text)
80+
case PopupType.QUESTION:
81+
self.result = messagebox.askquestion(self.title, self.text)
82+
case PopupType.OK_CANCEL:
83+
self.result = messagebox.askokcancel(self.title, self.text)
84+
case PopupType.YES_NO:
85+
self.result = messagebox.askyesno(self.title, self.text)
86+
case PopupType.YES_NO_CANCEL:
87+
self.result = messagebox.askyesnocancel(self.title, self.text)
88+
case PopupType.RETRY_CANCEL:
89+
self.result = messagebox.askretrycancel(self.title, self.text)
90+
91+
def getResult(self):
92+
return self.result
93+
94+
95+
if __name__ == '__main__':
96+
from pygame_widgets.button import Button
97+
98+
def setButtonColour():
99+
if popup.getResult():
100+
button.setInactiveColour('green')
101+
elif popup.getResult() == False:
102+
button.setInactiveColour('red')
103+
104+
pygame.init()
105+
win = pygame.display.set_mode((600, 600))
106+
107+
popup = Popup(win, 100, 100, 400, 400, PopupType.YES_NO, 'Popup',
108+
'This is the text in the popup. Would you like to continue? The buttons below can be customised.',
109+
radius=20, textSize=20)
110+
111+
button = Button(win, 100, 100, 400, 400, text='Popup', onClick=popup.show)
112+
113+
run = True
114+
while run:
115+
events = pygame.event.get()
116+
for event in events:
117+
if event.type == pygame.QUIT:
118+
pygame.quit()
119+
run = False
120+
quit()
121+
122+
win.fill((255, 255, 255))
123+
124+
pygame_widgets.update(events)
125+
pygame.display.update()
126+
setButtonColour()

pygame_widgets/util.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import pygame
2+
3+
4+
def drawText(win, text, colour, rect, font, align='centre'):
5+
rect = pygame.Rect(rect)
6+
y = rect.top
7+
lineSpacing = -2
8+
9+
fontHeight = font.size('Tg')[1]
10+
11+
while text:
12+
i = 1
13+
14+
if y + fontHeight > rect.bottom:
15+
break
16+
17+
while font.size(text[:i])[0] < rect.width and i < len(text):
18+
i += 1
19+
20+
if i < len(text):
21+
i = text.rfind(' ', 0, i) + 1
22+
23+
image: pygame.Surface = font.render(text[:i], 1, colour)
24+
25+
imageRect: pygame.Rect = image.get_rect()
26+
27+
imageRect.center = rect.center
28+
29+
if align == 'left':
30+
imageRect.left = rect.left
31+
elif align == 'right':
32+
imageRect.right = rect.right
33+
34+
win.blit(image, (imageRect.left, y))
35+
y += fontHeight + lineSpacing
36+
37+
text = text[i:]
38+
39+
return text

pygame_widgets/widget.py

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,17 @@ def listen(self, events):
4141
def draw(self):
4242
pass
4343

44+
def __repr__(self):
45+
return f'{type(self).__name__}(x = {self._x}, y = {self._y}, width = {self._width}, height = {self._height})'
46+
4447
def contains(self, x, y):
4548
return (self._x < x - self.win.get_abs_offset()[0] < self._x + self._width) and \
4649
(self._y < y - self.win.get_abs_offset()[1] < self._y + self._height)
4750

4851
def hide(self):
4952
self._hidden = True
53+
if not self._isSubWidget:
54+
WidgetHandler.moveToBottom(self)
5055

5156
def show(self):
5257
self._hidden = False
@@ -65,6 +70,9 @@ def isSubWidget(self):
6570
def moveToTop(self):
6671
WidgetHandler.moveToTop(self)
6772

73+
def moveToBottom(self):
74+
WidgetHandler.moveToBottom(self)
75+
6876
def moveX(self, x):
6977
self._x += x
7078

@@ -137,6 +145,13 @@ def setWidth(self, width):
137145
def setHeight(self, height):
138146
self._height = height
139147

148+
def setIsSubWidget(self, isSubWidget):
149+
self._isSubWidget = isSubWidget
150+
if isSubWidget:
151+
WidgetHandler.removeWidget(self)
152+
else:
153+
WidgetHandler.addWidget(self)
154+
140155

141156
class WidgetHandler:
142157
_widgets: [WidgetBase] = []
@@ -158,12 +173,31 @@ def main(events: [Event]) -> None:
158173

159174
@staticmethod
160175
def addWidget(widget: WidgetBase) -> None:
161-
WidgetHandler._widgets.append(widget)
176+
if widget not in WidgetHandler._widgets:
177+
WidgetHandler._widgets.append(widget)
178+
179+
@staticmethod
180+
def removeWidget(widget: WidgetBase) -> None:
181+
try:
182+
WidgetHandler._widgets.remove(widget)
183+
except ValueError:
184+
print(f'Error: Tried to remove {widget} when {widget} not in WidgetHandler.')
162185

163186
@staticmethod
164187
def moveToTop(widget: WidgetBase):
165-
WidgetHandler._widgets.remove(widget)
166-
WidgetHandler.addWidget(widget)
188+
try:
189+
WidgetHandler._widgets.remove(widget)
190+
WidgetHandler.addWidget(widget)
191+
except ValueError:
192+
print(f'Error: Tried to move {widget} to top when {widget} not in WidgetHandler.')
193+
194+
@staticmethod
195+
def moveToBottom(widget: WidgetBase):
196+
try:
197+
WidgetHandler._widgets.remove(widget)
198+
WidgetHandler._widgets.insert(0, widget)
199+
except ValueError:
200+
print(f'Error: Tried to move {widget} to bottom when {widget} not in WidgetHandler.')
167201

168202
@staticmethod
169203
def getWidgets() -> [WidgetBase]:

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setuptools.setup(
77
name='pygame-widgets',
8-
version='1.0.0',
8+
version='1.1.0',
99
author='AustL',
1010
author_email='21chydra@gmail.com',
1111
description='Widgets for use with Pygame',
@@ -18,7 +18,7 @@
1818
'License :: OSI Approved :: MIT License',
1919
'Operating System :: OS Independent'
2020
],
21-
python_requires='>=3.6',
21+
python_requires='>=3.10',
2222
license='MIT',
2323
install_requires=['pygame>=2.0.0']
2424
)

0 commit comments

Comments
 (0)