Text and code blocks implemented
This commit is contained in:
parent
fff62bea5a
commit
d19debe614
|
@ -1 +1,2 @@
|
||||||
__pycache__
|
__pycache__
|
||||||
|
.idea
|
||||||
|
|
|
@ -21,6 +21,8 @@ class Statement:
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
ui = gui.UI('Dariuino IDE', gui.Dimensions(1920, 1080))
|
||||||
|
|
||||||
resources = gui.ResourceContainer.from_json_file('res/resources.json')
|
resources = gui.ResourceContainer.from_json_file('res/resources.json')
|
||||||
|
|
||||||
container = gui.Container(gui.Position(0, 0), gui.Dimensions(600, 600))
|
container = gui.Container(gui.Position(0, 0), gui.Dimensions(600, 600))
|
||||||
|
@ -29,11 +31,23 @@ def main():
|
||||||
c.on_click = lambda: print('Hello world')
|
c.on_click = lambda: print('Hello world')
|
||||||
|
|
||||||
a = gui.Dragable(resources.get_image('icon-while-32'), gui.Position(150, 350))
|
a = gui.Dragable(resources.get_image('icon-while-32'), gui.Position(150, 350))
|
||||||
|
a.on_drag = lambda: a.set_transparency(0.5)
|
||||||
|
a.on_drop = lambda dropable: a.set_transparency(0.0)
|
||||||
|
a.on_fail = lambda drag : a.set_transparency(0.0)
|
||||||
|
|
||||||
|
d = gui.Dropable(gui.Position(0, 0), gui.Dimensions(50, 100))
|
||||||
|
d.background_color = gui.Color(255, 0, 0)
|
||||||
|
d.on_drop = lambda dragable: print(dragable)
|
||||||
|
|
||||||
|
container.add_dropable(d)
|
||||||
container.add_clickable(c)
|
container.add_clickable(c)
|
||||||
container.add_clickable(a)
|
container.add_clickable(a)
|
||||||
|
|
||||||
ui = gui.UI('Dariuino IDE', gui.Dimensions(1920, 1080))
|
block = CodeBlock(BlockColor.VIOLET, resources.get_image('icon-for-32'))
|
||||||
|
block.add_text('Hallo liebe rosa Welt mit Regenbögen und Einhörnern.')
|
||||||
|
|
||||||
|
container.add_clickable(block)
|
||||||
|
|
||||||
ui.add_container(container)
|
ui.add_container(container)
|
||||||
ui.init()
|
ui.init()
|
||||||
ui.update()
|
ui.update()
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import pygame.draw
|
||||||
|
|
||||||
import src.gui as gui
|
import src.gui as gui
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,8 +11,71 @@ class BlockColor:
|
||||||
YELLOW = gui.Color(255, 255, 0)
|
YELLOW = gui.Color(255, 255, 0)
|
||||||
|
|
||||||
|
|
||||||
class CodeBlock(gui.Clickable):
|
class CodeBlock(gui.ListItem):
|
||||||
def __init__(self, color: gui.Color, on_click_callback: callable):
|
TEXT_SIZE = 24
|
||||||
Clickable.__init__(self, gui.Canvas(500, 200), gui.Position(0, 0))
|
TEXT_COLOR = gui.Color(255, 255, 255)
|
||||||
self.on_click = on_click_callable
|
TEXT_FONT = 'freesansbold.ttf'
|
||||||
|
RADIUS_CORNERS = 30
|
||||||
|
PADDING = 20
|
||||||
|
SPACE = 10
|
||||||
|
|
||||||
|
def __init__(self, color: gui.Color, icon: gui.Image):
|
||||||
|
gui.ListItem.__init__(self, gui.Canvas(gui.Dimensions(500, 100)))
|
||||||
|
self.icon = icon
|
||||||
|
self.color = color
|
||||||
|
self.content = []
|
||||||
|
|
||||||
|
def add_text(self, text: str) -> None:
|
||||||
|
for word in text.split(' '):
|
||||||
|
self.add_visualization(
|
||||||
|
gui.Text(word, size = self.TEXT_SIZE, font_family = self.TEXT_FONT, color = self.TEXT_COLOR)
|
||||||
|
)
|
||||||
|
|
||||||
|
def add_visualization(self, visualization: gui.Visualization) -> None:
|
||||||
|
self.content.append(visualization)
|
||||||
|
|
||||||
|
def draw(self, canvas: gui.Canvas) -> None:
|
||||||
|
self.canvas.clear()
|
||||||
|
|
||||||
|
self._render_background()
|
||||||
|
|
||||||
|
self.canvas.draw_inside(self.icon, gui.Position(self.PADDING, self.PADDING))
|
||||||
|
|
||||||
|
line_dimensions = gui.Dimensions(self.icon.get_dimensions().width, self.PADDING)
|
||||||
|
line_dimensions.width += self.PADDING
|
||||||
|
|
||||||
|
max_height = self.icon.get_dimensions().height
|
||||||
|
|
||||||
|
for drawable in self.content:
|
||||||
|
line_dimensions.width += self.SPACE
|
||||||
|
max_height = max(max_height, drawable.get_dimensions().height)
|
||||||
|
|
||||||
|
if line_dimensions.width + drawable.get_dimensions().width > self.canvas.get_dimensions().width:
|
||||||
|
line_dimensions.width = self.PADDING + self.icon.get_dimensions().width + self.SPACE
|
||||||
|
line_dimensions.height += max_height
|
||||||
|
max_height = drawable.get_dimensions().height
|
||||||
|
|
||||||
|
self.canvas.draw_inside(drawable, gui.Position(line_dimensions.width, line_dimensions.height))
|
||||||
|
|
||||||
|
line_dimensions.width += drawable.get_dimensions().width
|
||||||
|
|
||||||
|
gui.Visualization.draw(self, canvas)
|
||||||
|
|
||||||
|
def _render_background(self):
|
||||||
|
self.canvas.clear(None)
|
||||||
|
|
||||||
|
pygame.draw.rect(
|
||||||
|
self.canvas.surface,
|
||||||
|
self.color.as_tuple(),
|
||||||
|
(0, 0, self.canvas.get_dimensions().width, self.canvas.get_dimensions().height),
|
||||||
|
0,
|
||||||
|
self.RADIUS_CORNERS
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Code(gui.ItemList):
|
||||||
|
def __init__(self, position: gui.Position):
|
||||||
|
gui.ItemList.__init__(self, position, gui.Dimensions(500, 250))
|
||||||
|
|
||||||
|
def add_code_block(self, code_block: CodeBlock):
|
||||||
|
self.add_item(code_block)
|
||||||
|
|
137
src/gui.py
137
src/gui.py
|
@ -53,11 +53,14 @@ class Dimensions:
|
||||||
self.width = width
|
self.width = width
|
||||||
self.height = height
|
self.height = height
|
||||||
|
|
||||||
|
def __add__(self, dimensions: Self):
|
||||||
|
return Dimensions(self.width + dimensions.width, self.height + dimensions.height)
|
||||||
|
|
||||||
def as_tuple(self):
|
def as_tuple(self):
|
||||||
return (self.width, self.height)
|
return self.width, self.height
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_tuple(tuple):
|
def from_tuple(tuple: Tuple):
|
||||||
return Dimensions(tuple[0], tuple[1])
|
return Dimensions(tuple[0], tuple[1])
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,6 +72,10 @@ class Drawable:
|
||||||
self.surface.blit(drawable.surface, position.as_tuple())
|
self.surface.blit(drawable.surface, position.as_tuple())
|
||||||
|
|
||||||
def clear(self, color = Color(0, 0, 0)):
|
def clear(self, color = Color(0, 0, 0)):
|
||||||
|
if color is None:
|
||||||
|
self.surface.fill(pygame.Color(0, 0, 0, 0))
|
||||||
|
return
|
||||||
|
|
||||||
self.surface.fill(color.as_tuple())
|
self.surface.fill(color.as_tuple())
|
||||||
|
|
||||||
def get_image(self):
|
def get_image(self):
|
||||||
|
@ -80,6 +87,9 @@ class Drawable:
|
||||||
def get_dimensions(self) -> Dimensions:
|
def get_dimensions(self) -> Dimensions:
|
||||||
return Dimensions.from_tuple(self.surface.get_size())
|
return Dimensions.from_tuple(self.surface.get_size())
|
||||||
|
|
||||||
|
def set_transparency(self, transparency: float):
|
||||||
|
self.surface.set_alpha(255 - 255 * transparency)
|
||||||
|
|
||||||
|
|
||||||
class Image(Drawable):
|
class Image(Drawable):
|
||||||
def __init__(self, path = None):
|
def __init__(self, path = None):
|
||||||
|
@ -98,6 +108,7 @@ class Screen:
|
||||||
def __init__(self, title: str, resolution: Dimensions):
|
def __init__(self, title: str, resolution: Dimensions):
|
||||||
self.resolution = resolution
|
self.resolution = resolution
|
||||||
self.screen = pygame.display.set_mode(resolution.as_tuple(), pygame.NOFRAME | pygame.FULLSCREEN | pygame.DOUBLEBUF)
|
self.screen = pygame.display.set_mode(resolution.as_tuple(), pygame.NOFRAME | pygame.FULLSCREEN | pygame.DOUBLEBUF)
|
||||||
|
|
||||||
pygame.display.set_caption(title)
|
pygame.display.set_caption(title)
|
||||||
|
|
||||||
def get_canvas(self):
|
def get_canvas(self):
|
||||||
|
@ -106,9 +117,6 @@ class Screen:
|
||||||
|
|
||||||
return canvas
|
return canvas
|
||||||
|
|
||||||
def get_image(self):
|
|
||||||
image = Image()
|
|
||||||
|
|
||||||
def update(self) -> None:
|
def update(self) -> None:
|
||||||
pygame.dispay.flip()
|
pygame.dispay.flip()
|
||||||
|
|
||||||
|
@ -122,14 +130,20 @@ class Screen:
|
||||||
return resolutions
|
return resolutions
|
||||||
|
|
||||||
|
|
||||||
class Visualization():
|
class Visualization:
|
||||||
def __init__(self, surface: Canvas, position: Position):
|
def __init__(self, canvas: Canvas, position: Position):
|
||||||
self.surface = surface
|
self.canvas = canvas
|
||||||
self.position = position
|
self.position = position
|
||||||
self.on_hover = lambda : None
|
self.on_hover = lambda : None
|
||||||
|
|
||||||
def draw(self, canvas: Canvas) -> None:
|
def draw(self, canvas: Canvas) -> None:
|
||||||
canvas.draw_inside(self.surface, self.position)
|
canvas.draw_inside(self.canvas, self.position)
|
||||||
|
|
||||||
|
def set_transparency(self, transparency: float):
|
||||||
|
self.canvas.set_transparency(transparency)
|
||||||
|
|
||||||
|
def get_dimensions(self) -> Dimensions:
|
||||||
|
return self.canvas.get_dimensions()
|
||||||
|
|
||||||
def is_inside(self, position: Position) -> bool:
|
def is_inside(self, position: Position) -> bool:
|
||||||
if position.x < self.position.x:
|
if position.x < self.position.x:
|
||||||
|
@ -138,7 +152,7 @@ class Visualization():
|
||||||
if position.y < self.position.y:
|
if position.y < self.position.y:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
dimensions = self.surface.get_dimensions()
|
dimensions = self.canvas.get_dimensions()
|
||||||
|
|
||||||
if position.x > self.position.x + dimensions.width:
|
if position.x > self.position.x + dimensions.width:
|
||||||
return False
|
return False
|
||||||
|
@ -162,32 +176,20 @@ class Dragable(Clickable):
|
||||||
def __init__(self, canvas: Canvas, position: Position):
|
def __init__(self, canvas: Canvas, position: Position):
|
||||||
Clickable.__init__(self, canvas, position)
|
Clickable.__init__(self, canvas, position)
|
||||||
self.on_drag = lambda: None
|
self.on_drag = lambda: None
|
||||||
self.on_drop = lambda : None
|
self.on_drop = lambda dropable: None
|
||||||
self.on_fail = lambda drag: None
|
self.on_fail = lambda drag: None
|
||||||
|
|
||||||
def drag(self) -> None:
|
def drag(self) -> None:
|
||||||
self.on_drag()
|
self.on_drag()
|
||||||
|
|
||||||
def drop(self) -> None:
|
def drop(self, dropable: 'Dropable') -> None:
|
||||||
self.on_drop()
|
self.on_drop(dropable)
|
||||||
|
|
||||||
def fail(self, drag: 'Drag'):
|
def fail(self, drag: 'Drag'):
|
||||||
self.on_fail(drag)
|
self.on_fail(drag)
|
||||||
|
|
||||||
|
|
||||||
class Dropable(Visualization):
|
|
||||||
def __init__(self, canvas: Canvas, position: Position):
|
|
||||||
Visualization.__init__(self, canvas, position)
|
|
||||||
self.on_drop = lambda dragable: None
|
|
||||||
|
|
||||||
def drop(self, dragable: Dragable) -> None:
|
|
||||||
self.on_drop(dragable)
|
|
||||||
|
|
||||||
|
|
||||||
class Container(Visualization):
|
class Container(Visualization):
|
||||||
ROWS = 0
|
|
||||||
COLUMNS = 1
|
|
||||||
|
|
||||||
def __init__(self, position: Position, dimensions: Dimensions):
|
def __init__(self, position: Position, dimensions: Dimensions):
|
||||||
Visualization.__init__(self, Canvas(dimensions), position)
|
Visualization.__init__(self, Canvas(dimensions), position)
|
||||||
|
|
||||||
|
@ -195,18 +197,19 @@ class Container(Visualization):
|
||||||
self.background_color = Color(0, 0, 0)
|
self.background_color = Color(0, 0, 0)
|
||||||
self.visualizations = []
|
self.visualizations = []
|
||||||
self.clickables = []
|
self.clickables = []
|
||||||
|
self.dropables = []
|
||||||
|
|
||||||
def set_background_image(self, image: Image) -> None:
|
def set_background_image(self, image: Image) -> None:
|
||||||
self.background_image = image
|
self.background_image = image
|
||||||
|
|
||||||
def render(self) -> None:
|
def render(self) -> None:
|
||||||
self.surface.clear(self.background_color)
|
self.canvas.clear(self.background_color)
|
||||||
|
|
||||||
if self.background_image is not None:
|
if self.background_image is not None:
|
||||||
self.surface.draw_inside(self.background_image, Dimensions(0, 0))
|
self.canvas.draw_inside(self.background_image, Dimensions(0, 0))
|
||||||
|
|
||||||
for visualization in self.visualizations:
|
for visualization in self.visualizations:
|
||||||
visualization.draw(self.surface)
|
visualization.draw(self.canvas)
|
||||||
|
|
||||||
def add_visualization(self, visualization: Visualization) -> None:
|
def add_visualization(self, visualization: Visualization) -> None:
|
||||||
self.visualizations.append(visualization)
|
self.visualizations.append(visualization)
|
||||||
|
@ -215,6 +218,33 @@ class Container(Visualization):
|
||||||
self.add_visualization(clickable)
|
self.add_visualization(clickable)
|
||||||
self.clickables.append(clickable)
|
self.clickables.append(clickable)
|
||||||
|
|
||||||
|
def add_dropable(self, dropable: 'Dropable'):
|
||||||
|
self.add_visualization(dropable)
|
||||||
|
self.dropables.append(dropable)
|
||||||
|
|
||||||
|
|
||||||
|
class Dropable(Container):
|
||||||
|
def __init__(self, position: Position, dimensions: Dimensions):
|
||||||
|
Container.__init__(self, position, dimensions)
|
||||||
|
self.on_drop = lambda dragable: None
|
||||||
|
|
||||||
|
def drop(self, dragable: Dragable) -> None:
|
||||||
|
self.on_drop(dragable)
|
||||||
|
|
||||||
|
|
||||||
|
class Text(Visualization, Drawable):
|
||||||
|
def __init__(self, text: str, size: int = 12, font_family: str = 'freesansbold.ttf', color: Color = Color(255, 255, 255)):
|
||||||
|
font = pygame.font.Font(font_family, size)
|
||||||
|
self.surface = font.render(text, True, color.as_tuple())
|
||||||
|
|
||||||
|
Visualization.__init__(
|
||||||
|
self,
|
||||||
|
Canvas(Dimensions.from_tuple(self.surface.get_size())),
|
||||||
|
Position(0, 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.canvas.surface = self.surface
|
||||||
|
|
||||||
|
|
||||||
class Drag:
|
class Drag:
|
||||||
def __init__(self, dragable: Dragable, cursor_offset: Position):
|
def __init__(self, dragable: Dragable, cursor_offset: Position):
|
||||||
|
@ -234,10 +264,10 @@ class UI:
|
||||||
self.drag = None
|
self.drag = None
|
||||||
self.containers = []
|
self.containers = []
|
||||||
|
|
||||||
def init(self):
|
def init(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def update(self):
|
def update(self) -> None:
|
||||||
self.canvas.clear()
|
self.canvas.clear()
|
||||||
|
|
||||||
for container in self.containers:
|
for container in self.containers:
|
||||||
|
@ -246,13 +276,13 @@ class UI:
|
||||||
|
|
||||||
pygame.display.update()
|
pygame.display.update()
|
||||||
|
|
||||||
def add_container(self, container: Container):
|
def add_container(self, container: Container) -> None:
|
||||||
self.containers.append(container)
|
self.containers.append(container)
|
||||||
|
|
||||||
def exit(self):
|
def exit(self) -> None:
|
||||||
self.is_running = False
|
self.is_running = False
|
||||||
|
|
||||||
def main(self):
|
def main(self) -> None:
|
||||||
while self.is_running:
|
while self.is_running:
|
||||||
event = pygame.event.wait()
|
event = pygame.event.wait()
|
||||||
|
|
||||||
|
@ -284,7 +314,7 @@ class UI:
|
||||||
|
|
||||||
clickable = clickables_clicked[-1]
|
clickable = clickables_clicked[-1]
|
||||||
|
|
||||||
if type(clickable) is Dragable:
|
if self._is_in_filter(clickable, [Dragable]):
|
||||||
self.drag = Drag(
|
self.drag = Drag(
|
||||||
clickable,
|
clickable,
|
||||||
Position.from_tuple(event.pos) - clickable.position
|
Position.from_tuple(event.pos) - clickable.position
|
||||||
|
@ -292,7 +322,7 @@ class UI:
|
||||||
|
|
||||||
clickable.click()
|
clickable.click()
|
||||||
|
|
||||||
def _handle_drag(self, event: pygame.event.Event):
|
def _handle_drag(self, event: pygame.event.Event) -> None:
|
||||||
position_cursor = Position.from_tuple(event.pos)
|
position_cursor = Position.from_tuple(event.pos)
|
||||||
|
|
||||||
position = position_cursor - self.drag.cursor_offset
|
position = position_cursor - self.drag.cursor_offset
|
||||||
|
@ -300,7 +330,7 @@ class UI:
|
||||||
self.drag.dragable.position = position
|
self.drag.dragable.position = position
|
||||||
self.drag.dragable.drag()
|
self.drag.dragable.drag()
|
||||||
|
|
||||||
def _handle_drop(self, event: pygame.event.Event):
|
def _handle_drop(self, event: pygame.event.Event) -> None:
|
||||||
if self.drag is None:
|
if self.drag is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -317,11 +347,11 @@ class UI:
|
||||||
|
|
||||||
self.drag = None
|
self.drag = None
|
||||||
|
|
||||||
def _handle_mouse_motion(self, event: pygame.event.Event):
|
def _handle_mouse_motion(self, event: pygame.event.Event) -> None:
|
||||||
if type(self.drag) is Drag:
|
if type(self.drag) is Drag:
|
||||||
self._handle_drag(event)
|
self._handle_drag(event)
|
||||||
|
|
||||||
def _get_visualizations_hovered(self, cursor_position: Position, filter: list = []):
|
def _get_visualizations_hovered(self, cursor_position: Position, filter: list = []) -> list[Visualization]:
|
||||||
containers_hovered = []
|
containers_hovered = []
|
||||||
visualizations_hovered = []
|
visualizations_hovered = []
|
||||||
|
|
||||||
|
@ -341,13 +371,17 @@ class UI:
|
||||||
|
|
||||||
return visualizations_hovered
|
return visualizations_hovered
|
||||||
|
|
||||||
def _get_clickables_clicked(self, event: pygame.event.Event):
|
def _get_clickables_clicked(self, event: pygame.event.Event) -> list[Clickable]:
|
||||||
return self._get_visualizations_hovered(
|
clickables = self._get_visualizations_hovered(
|
||||||
Position.from_tuple(event.pos),
|
Position.from_tuple(event.pos),
|
||||||
[Clickable, Dragable]
|
[Clickable, Dragable]
|
||||||
)
|
)
|
||||||
|
|
||||||
def _is_in_filter(self, visualization: Visualization, filter: list = []) -> bool:
|
print(clickables)
|
||||||
|
|
||||||
|
return clickables
|
||||||
|
|
||||||
|
def _is_in_filter(self, visualization: Visualization, filter: list[Visualization] = []) -> bool:
|
||||||
if len(filter) == 0:
|
if len(filter) == 0:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -359,20 +393,27 @@ class UI:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class IconButton(Clickable):
|
class ListItem(Dragable):
|
||||||
def __init__(self, icon: Image, icon_hover = None):
|
def __init__(self, canvas: Canvas):
|
||||||
self.icon = icon
|
Dragable.__init__(self, canvas, Position(0, 0))
|
||||||
self.icon_hover = icon_hover
|
|
||||||
|
|
||||||
|
class ItemList(Dropable):
|
||||||
|
def __init__(self, position: Position, dimensions: Dimensions):
|
||||||
|
Dropable.__init__(self, position, dimensions)
|
||||||
|
|
||||||
|
def add_item(self, item: ListItem) -> None:
|
||||||
|
self.add_dropable(item)
|
||||||
|
|
||||||
|
|
||||||
class ResourceContainer:
|
class ResourceContainer:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.images = {}
|
self.images = {}
|
||||||
|
|
||||||
def add_image(self, name, url):
|
def add_image(self, name, url) -> None:
|
||||||
self.images[name] = Image(url)
|
self.images[name] = Image(url)
|
||||||
|
|
||||||
def get_image(self, name):
|
def get_image(self, name) -> Image:
|
||||||
return self._get_resource(self.images, name)
|
return self._get_resource(self.images, name)
|
||||||
|
|
||||||
def _get_resource(self, resources: list, name: str):
|
def _get_resource(self, resources: list, name: str):
|
||||||
|
@ -382,7 +423,7 @@ class ResourceContainer:
|
||||||
raise Exception('Resource "%s" not found!' % (name))
|
raise Exception('Resource "%s" not found!' % (name))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_json_file(json_file):
|
def from_json_file(json_file) -> Self:
|
||||||
with open(json_file, 'r') as file:
|
with open(json_file, 'r') as file:
|
||||||
data = json.loads(file.read())
|
data = json.loads(file.read())
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue