Skip to content

Commit

Permalink
Click and release behaviour
Browse files Browse the repository at this point in the history
A button needs to be pressed first, and then on release, it triggers on_click
  • Loading branch information
soerface committed Oct 27, 2024
1 parent 2dc51d1 commit cbd4a46
Show file tree
Hide file tree
Showing 15 changed files with 167 additions and 121 deletions.
49 changes: 45 additions & 4 deletions drinks_touch/elements/base_elm.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
class BaseElm(object):
def __init__(
self,
children: list["BaseElm"] | None = None,
pos=None,
height=None,
width=None,
Expand All @@ -13,8 +14,6 @@ def __init__(
padding: (
int | tuple[int, int] | tuple[int, int, int] | tuple[int, int, int, int]
) = 0,
*args,
**kwargs
):
if pos is None:
pos = (0, 0)
Expand All @@ -24,6 +23,10 @@ def __init__(
self.is_visible = True
self.align_right = align_right
self.align_bottom = align_bottom
self.focus = False
if children is None:
children = []
self.children = children
if not isinstance(padding, tuple):
self.padding_top = padding
self.padding_right = padding
Expand Down Expand Up @@ -74,14 +77,52 @@ def screen_pos(self):
def box(self):
return self.screen_pos + (self.width, self.height)

def events(self, events):
pass
def events(self, events, pos=None):
for event in events:
consumed = "consumed" in event.dict and event.consumed
if pos is None and hasattr(event, "pos"):
pos = event.pos
if pos is None:
continue
collides = self.collides_with(pos)
if collides:
transformed_pos = (
pos[0] - self.screen_pos[0],
pos[1] - self.screen_pos[1],
)
else:
transformed_pos = None

for child in self.children:
child.events(events, transformed_pos)

if event.type == pygame.MOUSEBUTTONDOWN:
if collides:
self.focus = True
else:
self.focus = False

elif event.type == pygame.MOUSEBUTTONUP:
if not hasattr(self, "on_click"):
continue

if not consumed and self.focus and collides:
self.on_click(*transformed_pos)
event.consumed = True
self.focus = False

@property
def visible(self):
# TODO get rid of is_visible
return self.is_visible

def collides_with(self, pos: tuple[int, int]) -> bool:
return (
self.box is not None
and self.visible
and pygame.Rect(self.box).collidepoint(pos[0], pos[1])
)

def render(self, *args, **kwargs) -> Surface:
surface = pygame.font.SysFont("monospace", 25).render(
"Return surface in render()", 1, (255, 0, 255)
Expand Down
19 changes: 4 additions & 15 deletions drinks_touch/elements/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
class Button(BaseElm):
def __init__(
self,
children: list["BaseElm"] | None = None,
font=FONTS["monospace"],
size=30,
text=None,
Expand All @@ -27,7 +28,7 @@ def __init__(
):
from . import Label

super().__init__(pos, size, size, *args, padding=padding, **kwargs)
super().__init__(children, pos, size, size, *args, padding=padding, **kwargs)

self.size = size
self.color = color
Expand All @@ -44,14 +45,6 @@ def __init__(
)
self.inner = inner

self.clicking = False

def pre_click(self):
self.clicking = True

def post_click(self):
self.clicking = False

def render(self, *args, **kwargs) -> pygame.Surface:
inner = self.inner.render(*args, **kwargs)

Expand All @@ -64,7 +57,7 @@ def render(self, *args, **kwargs) -> pygame.Surface:
self.height = size[1]

surface = pygame.Surface(size, pygame.SRCALPHA)
if self.clicking:
if self.focus:
surface.fill(tuple(c * 0.7 for c in self.color), (0, 0, *size))

if inner is not None:
Expand All @@ -75,8 +68,4 @@ def render(self, *args, **kwargs) -> pygame.Surface:
def on_click(self, x, y):
if self.on_click_handler is None:
raise NotImplementedError("No on_click handler defined")
self.pre_click()
try:
self.on_click_handler()
finally:
self.post_click()
self.on_click_handler()
11 changes: 9 additions & 2 deletions drinks_touch/elements/elm_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@


class ElmList(BaseElm):
def __init__(self, height, width, pos=(0, 0), **kwargs):
super().__init__(pos, height, width)
def __init__(
self,
children: list["BaseElm"] | None = None,
height=None,
width=None,
pos=(0, 0),
**kwargs
):
super().__init__(children, pos, height, width)
self.pos = pos
self.elm_margin = kwargs.get("elm_margin", 5)
self.max_elm_count = kwargs.get("max_elm_count", 10)
Expand Down
27 changes: 13 additions & 14 deletions drinks_touch/elements/hbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,20 @@ class HBox(BaseElm):

def __init__(
self,
elements: list[BaseElm],
children: list["BaseElm"] | None = None,
gap=5,
pos=(0, 0),
*args,
**kwargs,
):
super().__init__(pos, 0, 0, *args, **kwargs)
super().__init__(children, pos, 0, 0, *args, **kwargs)
self.pos = pos
self.elements = elements
self.gap = gap

def render(self, *args, **kwargs) -> pygame.Surface:
surface = pygame.Surface((self.width, self.height), pygame.SRCALPHA)
x = self.padding_left
for element in self.elements:
for element in self.children:
element.pos = (x, self.padding_top)
element_surface = element.render(*args, **kwargs)
surface.blit(element_surface, element.pos)
Expand All @@ -31,31 +30,31 @@ def render(self, *args, **kwargs) -> pygame.Surface:
@property
def width(self):
return (
sum([element.width for element in self.elements])
+ (len(self.elements) - 1) * self.gap
sum([element.width for element in self.children])
+ (len(self.children) - 1) * self.gap
+ self.padding_left
+ self.padding_right
)

@property
def height(self):
return (
max([element.height for element in self.elements])
max([element.height for element in self.children])
+ self.padding_top
+ self.padding_bottom
)

def on_click(self, x, y):
for obj in self.elements:
if pygame.Rect(obj.box).collidepoint(x, y):
if hasattr(obj, "on_click"):
obj.on_click(x - obj.pos[0], y - obj.pos[1])
break
# def on_click(self, x, y):
# for obj in self.elements:
# if pygame.Rect(obj.box).collidepoint(x, y):
# if hasattr(obj, "on_click"):
# obj.on_click(x - obj.pos[0], y - obj.pos[1])
# break

def render_debug(self) -> pygame.Surface:
surface = pygame.Surface((self.width, self.height), pygame.SRCALPHA)
surface.fill((0, 0, 255, 100))
for element in self.elements:
for element in self.children:
element_surface = element.render_debug()
surface.blit(element_surface, element.pos)
pygame.draw.rect(surface, (255, 0, 0), (0, 0, self.width, self.height), 1)
Expand Down
12 changes: 7 additions & 5 deletions drinks_touch/elements/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@


class Image(BaseElm):
def __init__(self, *args, **kwargs):
self.src = kwargs.get("src", "drinks_touch/resources/images/test.jpg")
self.size = kwargs.get("size", None)
def __init__(
self, src="drinks_touch/resources/images/test.jpg", size=None, *args, **kwargs
):
self.src = src
self.size = size
self.img = pygame.image.load(self.src).convert_alpha()

if self.size:
self.img = pygame.transform.smoothscale(self.img, self.size)
if size:
self.img = pygame.transform.smoothscale(self.img, size)
super(Image, self).__init__(*args, **kwargs)

@property
Expand Down
43 changes: 26 additions & 17 deletions drinks_touch/elements/label.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from config import COLORS
import config
from .base_elm import BaseElm

import contextlib
Expand All @@ -12,25 +12,34 @@
class Label(BaseElm):
_font_cache = {}

def __init__(self, *args, **kwargs):
self.font_face = kwargs.get("font", "sans serif")
self.size = kwargs.get("size", 50)
self.max_width = kwargs.get("max_width", None)
# if True, pos marks top-right instead of top-left corner
self.align_right = kwargs.get("align_right", False)
self.text = kwargs.get("text", "<Label>")
self.color = kwargs.get("color", COLORS["infragelb"])
self.bg_color = kwargs.get("bg_color", None)
self.border_color = kwargs.get("border_color", None)
self.border_width = kwargs.get("border_width", 0)
self.padding = kwargs.get("padding", 0)
self.blink_frequency = kwargs.get("blink_frequency", 0)
def __init__(
self,
children: list["BaseElm"] | None = None,
text="<Label>",
font=config.FONTS["sans serif"],
size=35,
color=config.COLORS["infragelb"],
bg_color=None,
border_color=None,
border_width=0,
blink_frequency=0,
max_width=None,
*args,
**kwargs,
):
self.size = size
self.max_width = max_width
self.text = text
self.color = color
self.bg_color = bg_color
self.border_color = border_color
self.border_width = border_width
self.blink_frequency = blink_frequency

self.frame_counter = 0
pos = kwargs.pop("pos", (0, 0))
super().__init__(pos, self.size, self.size, *args, **kwargs)
super().__init__(children, height=self.size, width=self.size, *args, **kwargs)

self.font = Label.get_font(self.font_face, self.size)
self.font = Label.get_font(font, self.size)

@classmethod
def get_font(cls, font_face, size):
Expand Down
31 changes: 23 additions & 8 deletions drinks_touch/elements/progress.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import math

from config import COLORS
import config
from .base_elm import BaseElm

import contextlib
Expand All @@ -10,16 +10,31 @@


class Progress(BaseElm):
def __init__(self, pos=None, *args, **kwargs):
self.size = kwargs.get("size", 50)
self.color = kwargs.get("color", COLORS["infragelb"])
self.tick = kwargs.get("tick", self.__default_tick)
self.speed = kwargs.get("speed", 1 / 4.0) # 4 secs
self.on_elapsed = kwargs.get("on_elapsed", None)
def __init__(
self,
children: list["BaseElm"] | None = None,
pos=None,
size=50,
color=config.COLORS["infragelb"],
tick=None,
speed=1 / 4.0, # 4 secs
on_elapsed=None,
*args,
**kwargs,
):
self.size = size
self.color = color
if tick is None:
tick = self.__default_tick
self.tick = tick
self.speed = speed
self.on_elapsed = on_elapsed
self.value = 0
self.is_running = False

super(Progress, self).__init__(pos, self.size, self.size, *args, **kwargs)
super(Progress, self).__init__(
children, pos, self.size, self.size, *args, **kwargs
)
self.start()

def start(self):
Expand Down
Loading

0 comments on commit cbd4a46

Please sign in to comment.