Skip to content

Commit 7b197d9

Browse files
committed
pygameui v2
1 parent 807efb0 commit 7b197d9

File tree

1 file changed

+303
-5
lines changed

1 file changed

+303
-5
lines changed

pygameui.py

Lines changed: 303 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ def __init__(self,
5151
# Framerate
5252
self.framerate = 60
5353

54+
# Clicked
55+
self.clicked = False
56+
5457

5558
"""
5659
Setters
@@ -249,10 +252,22 @@ def is_clicked(self):
249252
# Check mouse over and clicked conditions
250253
if self.rect.collidepoint(mouse_pos):
251254
if pygame.mouse.get_pressed()[0] == 1: # == 1 is left click
255+
self.clicked = True
252256
return True
253257

254258
return False
255259

260+
def was_clicked(self):
261+
"""
262+
Returnes true if the element was clicked and then released
263+
"""
264+
if self.is_clicked():
265+
return
266+
267+
if self.clicked:
268+
self.clicked = False
269+
return True
270+
256271
"""
257272
Basic functions
258273
"""
@@ -303,14 +318,15 @@ def __init__(self,
303318
self.content = content
304319
self.font_size = font_size
305320
self.font_family = font_family
321+
self.font = pygame.font.SysFont(self.font_family, self.font_size)
306322

307323
# Get the dimensions of the text
308324
if width != 0 and height != 0:
309325
text_dimensions = (width, height)
310326
else:
311327
text_dimensions = self.get_text_rect_dimensions()
312328

313-
super().__init__(position, text_dimensions[0], text_dimensions[1], color, centered)
329+
super().__init__(position, width=text_dimensions[0], height=text_dimensions[1], color=color, centered=centered)
314330

315331
# Render text
316332
self.text_surface = self.render_text()
@@ -336,6 +352,24 @@ def render_text(self) -> pygame.Surface:
336352
text_surface = font.render(self.content, True, self.color)
337353
return text_surface
338354

355+
def change_text(self, new_text: str) -> None:
356+
"""
357+
Change the text of the element
358+
:param new_text: str with the new text
359+
:return: None
360+
"""
361+
self.content = new_text
362+
self.text_surface = self.render_text()
363+
364+
def change_text_color(self, new_color: tuple[int, int, int]) -> None:
365+
"""
366+
Change the color of the text
367+
:param new_color: tuple[int, int, int] with the new color
368+
:return: None
369+
"""
370+
self.color = new_color
371+
self.text_surface = self.render_text()
372+
339373
def draw(self, surface: pygame.Surface) -> None:
340374
"""
341375
Draw the text in the surface
@@ -346,7 +380,13 @@ def draw(self, surface: pygame.Surface) -> None:
346380
if not self.display:
347381
return
348382

349-
surface.blit(self.text_surface, self.rect)
383+
rect = self.text_surface.get_rect()
384+
if self.centered:
385+
rect.center = self.rect.center
386+
else:
387+
rect.topleft = self.rect.topleft
388+
389+
surface.blit(self.text_surface, rect)
350390

351391
class Image(Element):
352392
"""
@@ -392,6 +432,9 @@ def draw(self, surface: pygame.Surface) -> None:
392432
surface.blit(self.image, self.rect)
393433

394434
class Input(Text):
435+
"""
436+
Input element that can be displayed
437+
"""
395438
def __init__(self,
396439
position: tuple [int, int],
397440
width: int = 200,
@@ -406,8 +449,30 @@ def __init__(self,
406449
font_family: str = "Arial",
407450
hint: str = "",
408451
centered: bool = False):
409-
410-
super().__init__(position, content=hint, color=passive_text_color, font_size=font_size, font_family=font_family, width=width, height=height, centered=centered)
452+
"""
453+
Create an input element
454+
:param position: Where the input will be positioned
455+
:param width: Width of the input
456+
:param height: Height of the input
457+
:param passive_text_color: Color of the text when the input is not active
458+
:param active_text_color: Color of the text when the input is active
459+
:param passive_border_color: Color of the border when the input is not active
460+
:param active_border_color: Color of the border when the input is active
461+
:param border_radius: Radius of the border
462+
:param border_width: Width of the border
463+
:param font_size: Size of the font
464+
:param font_family: Font family of the text
465+
:param hint: Hint of the input
466+
"""
467+
468+
super().__init__(position,
469+
content=hint,
470+
color=passive_text_color,
471+
font_size=font_size,
472+
font_family=font_family,
473+
width=width,
474+
height=height,
475+
centered=centered)
411476

412477
# Visual attributes
413478
self.passive_text_color = passive_text_color
@@ -417,13 +482,246 @@ def __init__(self,
417482
self.border_radius = border_radius
418483
self.border_width = border_width
419484

485+
# Text attributes
486+
self.hint = hint
487+
self.text = ""
488+
420489
# States
421490
self.active = False
422491

492+
# Filer
493+
self.filter = None
494+
self.filter_mode_exclude = True
495+
496+
# Keys
497+
self.exclude_keys = [pygame.KMOD_SHIFT, pygame.KMOD_CAPS, pygame.K_CAPSLOCK, pygame.K_LSHIFT, pygame.K_RSHIFT]
498+
self.exit_keys = [pygame.K_RETURN, pygame.K_KP_ENTER, pygame.K_TAB, pygame.K_ESCAPE]
499+
500+
# Cursor
501+
self.cursor = False
502+
self.cursor_index = 0
503+
504+
"""
505+
Getters
506+
"""
507+
508+
def get_text(self):
509+
"""
510+
Get the text of the input
511+
"""
512+
return self.text
513+
514+
"""
515+
Filter
516+
"""
517+
518+
def set_filter(self, new_filter: str, exclude_mode: bool = True) -> None:
519+
"""
520+
Set the filter of the input
521+
:param new_filter: str with the new filter
522+
:param exclude_mode: If the true, the filter will exclude the characters in the filter, if false, the filter will only allow characters in the filter
523+
"""
524+
self.filter = new_filter
525+
self.filter_mode_exclude = exclude_mode
526+
527+
def allow_key(self, key: str):
528+
"""
529+
Check if the key is allowed by the filter
530+
:param key: str with the key to be checked
531+
"""
532+
if not self.filter:
533+
return True
534+
535+
if self.filter_mode_exclude:
536+
if key not in self.filter:
537+
return True
538+
else:
539+
if key in self.filter:
540+
return True
541+
542+
return False
543+
544+
"""
545+
Typing
546+
"""
547+
def handle_keys(self, events: list) -> None:
548+
"""
549+
Handle the typing of the input
550+
:param events: list with the events
551+
"""
552+
for event in events:
553+
if event.type != pygame.KEYDOWN:
554+
continue
555+
elif event.key in self.exit_keys:
556+
self.active = False
557+
elif event.key in self.exclude_keys:
558+
continue
559+
elif event.key == pygame.K_RIGHT:
560+
if self.cursor_index >= len(self.text):
561+
continue
562+
self.cursor_index += 1
563+
elif event.key == pygame.K_LEFT:
564+
if self.cursor_index <= 0:
565+
continue
566+
self.cursor_index -= 1
567+
elif event.key == pygame.K_BACKSPACE:
568+
if self.cursor_index == 0:
569+
continue
570+
571+
self.text = self.text[:self.cursor_index-1] + self.text[self.cursor_index:]
572+
self.cursor_index -= 1
573+
elif event.key == pygame.K_DELETE:
574+
if self.cursor_index == len(self.text):
575+
continue
576+
577+
self.text = self.text[:self.cursor_index] + self.text[self.cursor_index+1:]
578+
else:
579+
if not self.allow_key(event.unicode):
580+
continue
581+
582+
self.text = self.text[:self.cursor_index] + event.unicode + self.text[self.cursor_index:]
583+
self.cursor_index += 1
584+
585+
self.change_text(self.text)
586+
587+
def draw_cursor(self, surface: pygame.Surface):
588+
"""
589+
Draw the cursor
590+
:param surface: pygame.Surface where the cursor will be drawn
591+
"""
592+
if not self.cursor:
593+
return
594+
595+
font = pygame.font.SysFont(self.font_family, self.font_size)
596+
cursor_surface = font.render("|", True, self.active_text_color)
597+
598+
text_to_cursor = Text(self.get_position(), self.text[:self.cursor_index], self.active_text_color,
599+
self.font_size, self.font_family, self.centered)
600+
601+
cursor_position = (self.rect.x + text_to_cursor.rect.width, self.rect.y)
602+
603+
if self.centered:
604+
print((self.rect.width - self.get_text_rect_dimensions()[0])//2)
605+
cursor_position = (self.rect.x + (self.rect.width - self.get_text_rect_dimensions()[0]), self.rect.centery - text_to_cursor.rect.height//2)
606+
607+
surface.blit(cursor_surface, cursor_position)
608+
609+
"""
610+
Basic functions
611+
"""
612+
423613
def draw(self, surface: pygame.surface):
614+
"""
615+
Draw the input and the cursor
616+
:param surface: pygame.Surface where the input will be drawn
617+
"""
424618
super().draw(surface)
425619

426620
if self.active:
621+
self.draw_cursor(surface)
427622
pygame.draw.rect(surface, self.active_border_color, self.rect, self.border_width, border_radius=self.border_radius)
428623
else:
429-
pygame.draw.rect(surface, self.passive_border_color, self.rect, self.border_width, border_radius=self.border_radius)
624+
pygame.draw.rect(surface, self.passive_border_color, self.rect, self.border_width, border_radius=self.border_radius)
625+
626+
def update(self, events: list) -> None:
627+
"""
628+
Update the input
629+
:param events: list with the events
630+
"""
631+
super().update()
632+
633+
# Check if the input was clicked
634+
if self.was_clicked():
635+
self.active = True
636+
# Check if the input was clicked outside, if so, deactivate it
637+
elif self.active:
638+
self.handle_keys(events)
639+
if pygame.mouse.get_pressed()[0] == 1 and not self.is_clicked():
640+
self.active = False
641+
if self.text != "":
642+
self.change_text(self.text)
643+
else:
644+
self.change_text(self.hint)
645+
646+
class Button(Element):
647+
"""
648+
Button element that can be displayed
649+
"""
650+
def __init__(self,
651+
position: tuple[int, int],
652+
width: int = 200,
653+
height: int = 50,
654+
border_radius: int = 10,
655+
content: str = "Click me.",
656+
color: tuple[int, int, int] = (255, 255, 255),
657+
hover_color: tuple[int, int, int] = (200, 200, 200),
658+
click_color: tuple[int, int, int] = (150, 150, 150),
659+
text_color: tuple[int, int, int] = (100, 100, 100),
660+
text_hover_color: tuple[int, int, int] = (0, 0, 0),
661+
text_click_color: tuple[int, int, int] = (0, 0, 0),
662+
font_size: int = 20,
663+
font_family: str = "Arial",
664+
centered: bool = False):
665+
"""
666+
Create a button element
667+
:param position: Where the button will be positioned
668+
:param width: Width of the button
669+
:param height: Height of the button
670+
:param content: Text of the button
671+
:param color: Color of the button
672+
:param hover_color: Color of the button when hovered
673+
:param click_color: Color of the button when clicked
674+
:param font_size: Size of the font
675+
:param font_family: Font family of the text
676+
:param centered: If the button will be centered in the position
677+
"""
678+
679+
super().__init__(position, width, height, color, border_radius, centered)
680+
681+
self.text_object = Text(position, content, text_color, font_size, font_family, width, height, centered)
682+
683+
# Button attributes
684+
self.text = content
685+
self.color = color
686+
self.hover_color = hover_color
687+
self.click_color = click_color
688+
self.border_radius = border_radius
689+
690+
# Text attributes
691+
self.text_color = text_color
692+
self.text_hover_color = text_hover_color
693+
self.text_click_color = text_click_color
694+
695+
# States
696+
self.hovered = False
697+
self.clicked = False
698+
699+
def draw(self, surface: pygame.Surface) -> None:
700+
"""
701+
Draw the button
702+
:param surface: pygame.Surface where the button will be drawn
703+
"""
704+
if not self.display:
705+
return
706+
707+
if self.clicked:
708+
pygame.draw.rect(surface, self.click_color, self.rect, border_radius=self.border_radius)
709+
self.text_object.change_text_color(self.text_click_color)
710+
elif self.hovered:
711+
pygame.draw.rect(surface, self.hover_color, self.rect, border_radius=self.border_radius)
712+
self.text_object.change_text_color(self.text_hover_color)
713+
else:
714+
pygame.draw.rect(surface, self.color, self.rect, border_radius=self.border_radius)
715+
self.text_object.change_text_color(self.text_color)
716+
717+
self.text_object.draw(surface)
718+
719+
def update(self) -> None:
720+
"""
721+
Update the button,
722+
Collects the events and updates the button
723+
"""
724+
self.text_object.update()
725+
726+
# Check if the button is hovered
727+
self.hovered = self.is_hovered()

0 commit comments

Comments
 (0)