from rio import Component, Text, Icon, TextStyle, Rectangle, Spacer, Color, PointerEventListener, Row, PointerEvent, Tooltip from typing import Optional, Literal from rio.event import on_populate from elm.types import Seat, UserSession, User class SeatPixel(Component): seat_id: str seat_orientation: Literal["top", "bottom"] seat: Optional[Seat] = None associated_user: Optional[User] = None @on_populate async def on_populate(self) -> None: if self.seat is None: self.seat = await Seat.find_one(Seat.seat_id == self.seat_id.replace("\n", ""), fetch_links=True) if self.seat and self.seat.user is not None: self.associated_user = await self.seat.user.fetch() async def on_press(self, _: PointerEvent) -> None: seat_id = self.seat_id.replace("\n", "") self.session.navigate_to(f"./seat-info?seat_id={seat_id}") def determine_color(self) -> Color: if self.seat is not None: try: user_name = self.session[UserSession].user_name except KeyError: user_name = None if self.seat.user is not None and self.associated_user and self.associated_user.user_name == user_name: return Color.from_hex("800080") elif self.seat.is_blocked or self.seat.user is not None: return self.session.theme.danger_color return self.session.theme.success_color return self.session.theme.success_color def build(self) -> Component: if self.seat is None: return Spacer() text = Text(f"{self.seat_id}", style=TextStyle(fill=Color.BLACK, font_size=0.9), align_x=0.5, selectable=False) rec = Rectangle( content=Row(text), min_width=1, min_height=1, fill=self.determine_color(), stroke_width=0.1, hover_stroke_width=0.1, stroke_color=Color.BLACK, grow_x=True, grow_y=True, hover_fill=self.session.theme.hud_color, transition_time=0.4, ripple=True ) if self.associated_user or self.seat.is_blocked: return PointerEventListener( content=Tooltip( anchor=rec, tip=self.associated_user.user_name if self.associated_user else "Gesperrt", position=self.seat_orientation, ), on_press=self.on_press, ) else: return PointerEventListener( content=rec, on_press=self.on_press, ) class TextPixel(Component): text: Optional[str] = None icon_name: Optional[str] = None no_outline: bool = False def build(self) -> Component: if self.text is not None: content = Text(self.text, style=TextStyle(fill=self.session.theme.text_color, font_size=1), align_x=0.5, selectable=False) elif self.icon_name is not None: content = Icon(self.icon_name, fill=self.session.theme.text_color) else: content = None return Rectangle( content=content, min_width=1, min_height=1, fill=self.session.theme.background_color, stroke_width=0.0 if self.no_outline else 0.1, stroke_color=self.session.theme.neutral_color, hover_stroke_width=None if self.no_outline else 0.1, grow_x=True, grow_y=True, hover_fill=None, ripple=True ) class WallPixel(Component): def build(self) -> Component: return Rectangle( min_width=1, min_height=1, fill=Color.from_hex("434343"), grow_x=True, grow_y=True, ) class DebugPixel(Component): def build(self) -> Component: return Rectangle( content=Spacer(), min_width=1, min_height=1, fill=self.session.theme.success_color, hover_stroke_color=self.session.theme.hud_color, hover_stroke_width=0.1, grow_x=True, grow_y=True, hover_fill=self.session.theme.secondary_color, transition_time=0.1 ) class InvisiblePixel(Component): def build(self) -> Component: return Rectangle( content=Spacer(), min_width=1, min_height=1, fill=Color.TRANSPARENT, hover_stroke_width=0.0, grow_x=True, grow_y=True )