222 lines
8.7 KiB
Python
222 lines
8.7 KiB
Python
|
import pygame
|
||
|
from math import floor
|
||
|
|
||
|
|
||
|
class Button:
|
||
|
# constructor that can be used to set parameters of Button instance
|
||
|
def __init__(
|
||
|
self,
|
||
|
position,
|
||
|
dimensions,
|
||
|
text="",
|
||
|
box_color=(195, 195, 195),
|
||
|
font=pygame.font.get_default_font(),
|
||
|
font_color=(50, 50, 50),
|
||
|
font_size=None,
|
||
|
is_visible=True,
|
||
|
is_active=True,
|
||
|
fit_text=True,
|
||
|
outline=True,
|
||
|
outline_thickness=None,
|
||
|
outline_color=(50, 50, 50),
|
||
|
box_transform_hover=1.16,
|
||
|
box_transform_inactive=0.9,
|
||
|
font_transform_hover=1.24,
|
||
|
font_transform_inactive=0.85
|
||
|
):
|
||
|
# extracting and setting values
|
||
|
smaller_dimension = min(dimensions)
|
||
|
width, height = dimensions
|
||
|
|
||
|
# counting default outline thickness
|
||
|
default_outline_thickness = (smaller_dimension + (width + height) / 4) / 50
|
||
|
|
||
|
# setting attributes
|
||
|
self.position = position
|
||
|
self.dimensions = dimensions
|
||
|
self.text = text
|
||
|
self.box_color = _get_proper_rgb(box_color)
|
||
|
self.font_color = _get_proper_rgb(font_color)
|
||
|
self.font_size = _return_value_or_default(font_size, floor(smaller_dimension / 2))
|
||
|
self.font = pygame.font.SysFont(font, self.font_size)
|
||
|
self.is_visible = is_visible
|
||
|
self.is_active = is_active
|
||
|
self.fit_text = fit_text
|
||
|
self.outline = outline
|
||
|
self.outline_thickness = _return_value_or_default(outline_thickness, default_outline_thickness)
|
||
|
self.outline_color = _get_proper_rgb(outline_color)
|
||
|
self.box_transform_hover = box_transform_hover
|
||
|
self.box_transform_inactive = box_transform_inactive
|
||
|
self.font_transform_hover = font_transform_hover
|
||
|
self.font_transform_inactive = font_transform_inactive
|
||
|
|
||
|
# rendering text to get it's width and height
|
||
|
rendered_text = self.font.render(text, True, (0, 0, 0))
|
||
|
|
||
|
# if text is out of bounds and fit_text=True - resizing text to fit the box
|
||
|
if self.fit_text and rendered_text.get_width() > self.dimensions[0]:
|
||
|
self.font_size = floor(self.font_size / (rendered_text.get_width() / width + 0.1))
|
||
|
self.font = pygame.font.SysFont(font, self.font_size)
|
||
|
|
||
|
# counting colors on: hover, inactive
|
||
|
self.box_hover_color = _get_proper_rgb(tuple(_transform(self.box_color, self.box_transform_hover)))
|
||
|
self.box_inactive_color = _get_proper_rgb(tuple(_transform(self.box_color, self.box_transform_inactive)))
|
||
|
self.font_hover_color = _get_proper_rgb(tuple(_transform(self.font_color, self.font_transform_hover)))
|
||
|
self.font_inactive_color = _get_proper_rgb(tuple(_transform(self.font_color, self.font_transform_inactive)))
|
||
|
|
||
|
# draws the Button instance
|
||
|
def draw(self, window, mouse_position):
|
||
|
# if is_visible=True - drawing Button
|
||
|
if self.is_visible:
|
||
|
# extracting and setting values from attributes
|
||
|
box_x, box_y = self.position
|
||
|
width, height = self.dimensions
|
||
|
|
||
|
# if outline=True - drawing an outline
|
||
|
if self.outline:
|
||
|
padding = self.outline_thickness
|
||
|
outline_coordinates = (box_x - padding, box_y - padding, width + 2 * padding, height + 2 * padding)
|
||
|
pygame.draw.rect(window, self.outline_color, outline_coordinates)
|
||
|
|
||
|
# setting values accordingly to InputBox'es state
|
||
|
# is active and mouse is not over
|
||
|
if not self.is_over(mouse_position) and self.is_active:
|
||
|
pygame.draw.rect(window, self.box_color, (box_x, box_y, width, height))
|
||
|
text_color = self.font_color
|
||
|
|
||
|
# is active and mouse is over
|
||
|
elif self.is_active:
|
||
|
pygame.draw.rect(window, self.box_hover_color, (box_x, box_y, width, height))
|
||
|
text_color = self.font_hover_color
|
||
|
|
||
|
# is not active
|
||
|
else:
|
||
|
pygame.draw.rect(window, self.box_inactive_color, (box_x, box_y, width, height))
|
||
|
text_color = self.font_inactive_color
|
||
|
|
||
|
# rendering text and counting its coordinates
|
||
|
rendered_text = self.font.render(self.text, True, text_color)
|
||
|
rendered_text_x = box_x + width / 2 - rendered_text.get_width() / 2
|
||
|
rendered_text_y = box_y + height / 2 - rendered_text.get_height() / 2
|
||
|
|
||
|
# drawing the text on the coordinates
|
||
|
window.blit(rendered_text, (rendered_text_x, rendered_text_y))
|
||
|
|
||
|
# returns True if the Button is clicked, or False otherwise
|
||
|
def is_clicked(self, mouse_position, events):
|
||
|
# if is_active=True and mouse is over the Button - checking if mouse is clicked
|
||
|
if self.is_active and self.is_over(mouse_position):
|
||
|
|
||
|
# if mouse is clicked returning True, otherwise False
|
||
|
for event in events:
|
||
|
if event.type == pygame.MOUSEBUTTONUP:
|
||
|
return True
|
||
|
|
||
|
return False
|
||
|
|
||
|
# checks if a position is over the InputBox and returns True or False
|
||
|
def is_over(self, position):
|
||
|
mouse_x, mouse_y = position
|
||
|
button_x, button_y = self.position
|
||
|
width, height = self.dimensions
|
||
|
|
||
|
return button_x <= mouse_x <= (button_x + width) and button_y <= mouse_y <= (button_y + height)
|
||
|
|
||
|
# returns text value
|
||
|
def get_text(self):
|
||
|
return self.text
|
||
|
|
||
|
# sets chosen coordinates
|
||
|
def set_coordinates(self, position=None, dimensions=None, outline_thickness=None):
|
||
|
if position is not None:
|
||
|
self.position = position
|
||
|
|
||
|
if dimensions is not None:
|
||
|
self.dimensions = dimensions
|
||
|
|
||
|
if outline_thickness is not None:
|
||
|
self.outline_thickness = outline_thickness
|
||
|
|
||
|
# sets text attribute
|
||
|
def set_text(self, text):
|
||
|
self.text = text
|
||
|
|
||
|
# sets chosen font attributes
|
||
|
def set_font(self, font=None, font_size=None):
|
||
|
if font_size is not None:
|
||
|
self.font_size = font_size
|
||
|
|
||
|
# rendering text to get it's width and height
|
||
|
rendered_text = self.font.render(self.text, True, (0, 0, 0))
|
||
|
|
||
|
# if text is out of bounds and fit_text=True - resizing text to fit the box
|
||
|
if self.fit_text and rendered_text.get_width() > self.dimensions[0]:
|
||
|
self.font_size = floor(self.font_size / (rendered_text.get_width() / self.dimensions[0] + 0.1))
|
||
|
self.font = pygame.font.SysFont(font, self.font_size)
|
||
|
|
||
|
if font is not None:
|
||
|
self.font = pygame.font.SysFont(font, self.font_size)
|
||
|
|
||
|
# sets chosen color attributes
|
||
|
def set_colors(
|
||
|
self,
|
||
|
box_color=None,
|
||
|
font_color=None,
|
||
|
outline_color=None,
|
||
|
box_transform_hover=None,
|
||
|
box_transform_inactive=None,
|
||
|
font_transform_hover=None,
|
||
|
font_transform_inactive=None
|
||
|
):
|
||
|
if box_color is not None:
|
||
|
self.box_color = _get_proper_rgb(box_color)
|
||
|
|
||
|
if font_color is not None:
|
||
|
self.font_color = _get_proper_rgb(font_color)
|
||
|
|
||
|
if outline_color is not None:
|
||
|
self.outline_color = _get_proper_rgb(outline_color)
|
||
|
|
||
|
if box_transform_hover is not None:
|
||
|
self.box_transform_hover = box_transform_hover
|
||
|
|
||
|
if box_transform_inactive is not None:
|
||
|
self.box_transform_inactive = box_transform_inactive
|
||
|
|
||
|
if font_transform_hover is not None:
|
||
|
self.font_transform_hover = font_transform_hover
|
||
|
|
||
|
if font_transform_inactive is not None:
|
||
|
self.font_transform_inactive = font_transform_inactive
|
||
|
|
||
|
self.box_hover_color = _get_proper_rgb(tuple(_transform(self.box_color, self.box_transform_hover)))
|
||
|
self.box_inactive_color = _get_proper_rgb(tuple(_transform(self.box_color, self.box_transform_inactive)))
|
||
|
self.font_hover_color = _get_proper_rgb(tuple(_transform(self.font_color, self.font_transform_hover)))
|
||
|
self.font_inactive_color = _get_proper_rgb(tuple(_transform(self.font_color, self.font_transform_inactive)))
|
||
|
|
||
|
# sets chosen flags
|
||
|
def set_flags(self, is_visible=None, is_active=None, outline=None):
|
||
|
if is_visible is not None:
|
||
|
self.is_visible = is_visible
|
||
|
|
||
|
if is_active is not None:
|
||
|
self.is_active = is_active
|
||
|
|
||
|
if outline is not None:
|
||
|
self.outline = outline
|
||
|
|
||
|
|
||
|
def _get_proper_rgb(x):
|
||
|
r, g, b = x
|
||
|
r, g, b = max(0, min(255, floor(r))), max(0, min(255, floor(g))), max(0, min(255, floor(b)))
|
||
|
|
||
|
return tuple((r, g, b))
|
||
|
|
||
|
|
||
|
def _transform(iterable, transform_value):
|
||
|
return [x * transform_value for x in iterable]
|
||
|
|
||
|
|
||
|
def _return_value_or_default(value, default):
|
||
|
return default if value is None else value
|