Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Select track UI implemented #19

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added resources/graphics/track1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/graphics/track2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/graphics/track3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/graphics/track4.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 22 additions & 4 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from view.menu import Menu
from view.track_view import TrackView
from view.window import Window
from view.options_menu import OptionsMenu

WINDOW_NAME = "CarsML"
WINDOW_SIZE = (1280, 800)
Expand Down Expand Up @@ -68,8 +69,7 @@ def main() -> None:
window = Window(WINDOW_NAME, WINDOW_SIZE, resizable=True, min_size=WINDOW_MIN_SIZE)

menu_options = {
"Track": Action(ActionType.CHANGE_VIEW, 1),
"Testing segment": Action(ActionType.CHANGE_VIEW, 2),
"Train": Action(ActionType.CHANGE_VIEW, 1),
"Exit": Action(ActionType.SYS_EXIT),
}
menu = Menu(menu_options)
Expand All @@ -78,10 +78,28 @@ def main() -> None:

tv1 = TrackView(Track.from_points(tracks[1]["points"]))
tv2 = TrackView(Track.from_points(tracks[3]["points"]))
tv3 = TrackView(Track.from_points(tracks[4]["points"]))

track_options = {
"Track1": Action(ActionType.CHANGE_VIEW, 2),
"Track2": Action(ActionType.CHANGE_VIEW, 3),
"Track3": Action(ActionType.CHANGE_VIEW, 4),
}
track_images = [
pygame.image.load("resources/graphics/track1.jpg"),
pygame.image.load("resources/graphics/track2.jpg"),
pygame.image.load("resources/graphics/track3.jpg"),
]
options_menu = OptionsMenu(tracks=track_options, tracks_thumbnails=track_images)
options_menu.background_image = pygame.image.load(
"resources/graphics/menu-background.png"
)

window.add_view(menu, 0, True)
window.add_view(tv1, 1)
window.add_view(tv2, 2)
window.add_view(tv1, 2)
window.add_view(tv2, 3)
window.add_view(tv3, 4)
window.add_view(options_menu, 1)

window.run()

Expand Down
3 changes: 3 additions & 0 deletions src/view/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import pygame

pygame.init()
2 changes: 2 additions & 0 deletions src/view/colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
LIGHTBLUE = (120, 140, 170)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
ORANGE = (255, 176, 21)
BIZARRE_MASKING_PURPLE = (240, 0, 240)
LIME = (50, 205, 50)
42 changes: 24 additions & 18 deletions src/view/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@


class Menu(View):
FONT_COLOR = colors.ORANGE
SELECTED_FONT_COLOR = colors.WHITE
BUTTON_COLOR = colors.WHITE
SELECTED_BUTTON_COLOR = colors.ORANGE
FONT = pygame.font.SysFont("Verdana", 24)

def __init__(self, menu_options: Dict[str, Action]):
super().__init__()
pygame.font.init()
self.font = pygame.font.SysFont("Verdana", 24)
self.selected_item = 0
self._options = OrderedDict(menu_options)
self.font_color = colors.WHITE
self.button_highlight = colors.GRAY
self.button_color = colors.LIGHTGRAY
self._background: Optional[Tuple[Surface, Tuple[int, int]]] = None
self._logo: Optional[Tuple[Surface, Tuple[int, int]]] = None
self.background_image: Surface = Surface((1, 1))
Expand All @@ -31,7 +32,6 @@ def __init__(self, menu_options: Dict[str, Action]):
def draw(
self, destination: Surface, events: List[EventType], delta_time: float
) -> Optional[Action]:
# TODO add activation check for consistency
size = destination.get_size()
self._update_geometry(size)

Expand All @@ -44,15 +44,21 @@ def draw(
destination.blit(*self._logo)

for pos, button in enumerate(self._options):
ofset_y = int(pos * 1.5 * self.button_dims[1])
shifted_button_rect = self._button_rect.move(0, ofset_y)
color = (
self.button_highlight
if pos == self.selected_item
else self.button_color
)
offset_y = int(pos * 1.5 * self.button_dims[1])
shifted_button_rect = self._button_rect.move(0, offset_y)

if pos == self.selected_item:
shifted_button_rect = shifted_button_rect.inflate(20, 20)
color = Menu.SELECTED_BUTTON_COLOR
font_color = Menu.SELECTED_FONT_COLOR
else:
pygame.draw.rect(destination, colors.ORANGE, shifted_button_rect, 4)
color = Menu.BUTTON_COLOR
font_color = Menu.FONT_COLOR

pygame.draw.rect(destination, color, shifted_button_rect)
label = self.font.render(button, True, self.font_color)

label = Menu.FONT.render(button, True, font_color)
destination.blit(
label,
(
Expand All @@ -63,20 +69,20 @@ def draw(
return None

def _update_geometry(self, size: Tuple[int, int]) -> None:
ofset_y = int(self.divider * size[1])
ofset_x = (size[0] - self.button_dims[0]) // 2
offset_y = int(self.divider * size[1])
offset_x = (size[0] - self.button_dims[0]) // 2

background_shape = Rect((0, 0), size)
background_image = pygame.transform.scale(self.background_image, size)
self._background = (background_image, background_shape)
self._button_rect = Rect((ofset_x, ofset_y), self.button_dims)
self._button_rect = Rect((offset_x, offset_y), self.button_dims)

if not self.logo_image:
return

logo_dims = self.logo_image.get_size()
logo_shape = Rect(
((size[0] - logo_dims[0]) // 2, (ofset_y - logo_dims[1]) // 2), logo_dims
((size[0] - logo_dims[0]) // 2, (offset_y - logo_dims[1]) // 2), logo_dims
)
self._logo = (self.logo_image, logo_shape)

Expand Down
124 changes: 118 additions & 6 deletions src/view/options_menu.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,131 @@
from typing import List, Optional, Any, Dict
from typing import List, Optional, Dict, Tuple, Any
from collections import OrderedDict

import pygame

from pygame.event import EventType
from pygame.surface import Surface
from pygame.rect import Rect

from view.action import Action
from view.action import Action, ActionType
from view.view import View
from view import colors


class OptionsMenu(View):
def __init__(
self, available: Any, output_dataset: Dict[str, Any], next: Optional[int] = None
) -> None:
ARROW_COLOR = colors.ORANGE
FONT_COLOR = colors.WHITE
LOGO_IMAGE = pygame.image.load("resources/graphics/logo.png")
DIVIDER = 0.4
FONT = pygame.font.SysFont("Verdana", 30)
MAIN_FONT = pygame.font.SysFont("comicsansms", 60)

def __init__(self, tracks: Dict[str, Action], tracks_thumbnails: List[Any]) -> None:
super().__init__()
self.selected_item = 0
self._options = OrderedDict(tracks)
self._background: Optional[Tuple[Surface, Tuple[int, int]]] = None
self.background_image: Optional[Surface] = None
self.selected_action: Optional[Action] = None
self.thumbnails = tracks_thumbnails

def draw(
self, destination: Surface, events: List[EventType], delta_time: float
) -> Optional[Action]:
pass
size = destination.get_size()
self._update_geometry(size)

if self._process_events(events):
return self.selected_action

if self._background:
destination.blit(*self._background)
if self._logo:
destination.blit(*self._logo)

mini_track = self._button_rect
thumbnail_image = pygame.transform.scale(
self.thumbnails[self.selected_item], (mini_track.w, mini_track.h)
)
thumbnail = (thumbnail_image, mini_track)
destination.blit(*thumbnail)
pygame.draw.rect(destination, colors.WHITE, mini_track, 4)

main_label = OptionsMenu.MAIN_FONT.render(
"Select track", True, OptionsMenu.FONT_COLOR
)
destination.blit(main_label, (size[0] // 2 - 185, size[1] // 10))

track_label = OptionsMenu.FONT.render(
list(self._options.keys())[self.selected_item], True, OptionsMenu.FONT_COLOR
)
destination.blit(
track_label,
(
mini_track.centerx - (track_label.get_height() // 2) - 28,
mini_track.centery - (mini_track.size[1] // 2) - 68,
),
)

left_arrow_points = (
(self.offset_x - size[0] // 20, self.offset_y + mini_track.h // 2),
(self.offset_x - 10, self.offset_y + mini_track.h // 2 - size[0] // 40),
(self.offset_x - 10, self.offset_y + mini_track.h // 2 + size[0] // 40),
)
right_arrow_points = (
(3 * self.offset_x + size[0] // 20, self.offset_y + mini_track.h // 2),
(3 * self.offset_x + 10, self.offset_y + mini_track.h // 2 - size[0] // 40),
(3 * self.offset_x + 10, self.offset_y + mini_track.h // 2 + size[0] // 40),
)

if self.selected_item != 0:
pygame.draw.polygon(destination, OptionsMenu.ARROW_COLOR, left_arrow_points)
if self.selected_item != len(self._options) - 1:
pygame.draw.polygon(
destination, OptionsMenu.ARROW_COLOR, right_arrow_points
)
return None

def _update_geometry(self, size: Tuple[int, int]) -> None:
self.offset_y = int(OptionsMenu.DIVIDER * size[1])
self.offset_x = size[0] // 4

self.button_dims = size[0] // 2, size[1] // 2

background_shape = Rect((0, 0), size)
background_image = pygame.transform.scale(self.background_image, size)
self._background = (background_image, background_shape)
self._button_rect = Rect((self.offset_x, self.offset_y), self.button_dims)

logo_image = pygame.transform.scale(
OptionsMenu.LOGO_IMAGE, (size[1] // 3, size[1] // 12)
)
logo_shape = Rect((10, 10), (size[0] // 8, size[1] // 8))
self._logo = (logo_image, logo_shape)

def _process_events(self, events: List[EventType]) -> bool:
for event in events:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT and self.selected_item != 0:
self.selected_item = self.selected_item - 1
elif (
event.key == pygame.K_RIGHT
and self.selected_item != len(self._options) - 1
):
self.selected_item = self.selected_item + 1
elif event.key == pygame.K_a and self.selected_item != 0:
self.selected_item = self.selected_item - 1
elif (
event.key == pygame.K_d
and self.selected_item != len(self._options) - 1
):
self.selected_item = self.selected_item + 1
elif event.key == pygame.K_RETURN:
self.selected_action = list(self._options.values())[
self.selected_item
]
return True
elif event.key == pygame.K_ESCAPE:
self.selected_action = Action(ActionType.CHANGE_VIEW, 0)
return True
ErykKrupa marked this conversation as resolved.
Show resolved Hide resolved
return False
2 changes: 1 addition & 1 deletion src/view/track_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def _process_events(self, events: List[EventType]) -> Optional[Action]:
elif event.key == pygame.K_KP_MINUS:
self.scale *= 0.625
self._prepare_board()
elif event.key == pygame.K_RETURN or event.key == pygame.K_KP_ENTER:
elif event.key == pygame.K_SPACE:
self._paused = not self._paused
# TODO change to previous view
return None
Expand Down
1 change: 0 additions & 1 deletion src/view/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ def __init__(
resizable: bool = False,
min_size: Optional[Tuple[int, int]] = None,
):
pygame.init()
pygame.display.set_caption(name)
self._mode = pygame.HWSURFACE | pygame.DOUBLEBUF
if fullscreen:
Expand Down