Move all interface Windows to their own modules in interface.window

This commit is contained in:
Eryn Wells 2023-03-07 21:44:01 -08:00
parent 1e678ff47d
commit a8bbc47668
5 changed files with 160 additions and 133 deletions

View file

@ -10,14 +10,12 @@ from tcod import event as tev
from tcod.console import Console
from tcod.context import Context
from .color import HealthBar
from .events import InterfaceEventHandler
from .percentage_bar import PercentageBar
from .window import Window, MapWindow
from .window.info import InfoWindow
from .window.map import MapWindow
from .window.message_log import MessageLogWindow
from ..engine import Engine
from ..geometry import Point, Rect, Size
from ..messages import MessageLog
from ..object import Entity, Hero
from ..geometry import Rect, Size
class Interface:
@ -76,49 +74,3 @@ class Interface:
continue
self.engine.process_input_action(action)
class InfoWindow(Window):
'''A window that displays information about the player'''
def __init__(self, bounds: Rect):
super().__init__(bounds, framed=True)
self.turn_count: int = 0
drawable_area = self.drawable_bounds
self.hit_points_bar = PercentageBar(
position=Point(drawable_area.min_x + 6, drawable_area.min_y),
width=20,
colors=list(HealthBar.bar_colors()))
def update_hero(self, hero: Hero):
'''Update internal state for the hero'''
assert hero.fighter
fighter = hero.fighter
hp, max_hp = fighter.hit_points, fighter.maximum_hit_points
self.hit_points_bar.percent_filled = hp / max_hp
def draw(self, console):
super().draw(console)
drawable_bounds = self.drawable_bounds
console.print(x=drawable_bounds.min_x + 2, y=drawable_bounds.min_y, string='HP:')
self.hit_points_bar.render_to_console(console)
if self.turn_count:
console.print(x=drawable_bounds.min_x, y=drawable_bounds.min_y + 1, string=f'Turn: {self.turn_count}')
class MessageLogWindow(Window):
'''A window that displays a list of messages'''
def __init__(self, bounds: Rect, message_log: MessageLog):
super().__init__(bounds, framed=True)
self.message_log = message_log
def draw(self, console):
super().draw(console)
self.message_log.render_to_console(console, self.drawable_bounds)

View file

@ -0,0 +1,83 @@
# Eryn Wells <eryn@erynwells.me>
from typing import Optional
from tcod import event as tev
from tcod.console import Console
from ...geometry import Point, Rect, Vector
class Window:
'''A user interface window. It can be framed and it can handle events.'''
class EventHandler(tev.EventDispatch[bool]):
'''
Handles events for a Window. Event dispatch methods return True if the event
was handled and no further action is needed.
'''
def __init__(self, window: 'Window'):
super().__init__()
self.window = window
def mouse_point_for_event(self, event: tev.MouseState) -> Point:
'''
Return the mouse point in tiles for a window event. Raises a ValueError
if the event is not a mouse event.
'''
if not isinstance(event, tev.MouseState):
raise ValueError("Can't get mouse point for non-mouse event")
return Point(event.tile.x, event.tile.y)
def ev_keydown(self, event: tev.KeyDown) -> bool:
return False
def ev_keyup(self, event: tev.KeyUp) -> bool:
return False
def ev_mousemotion(self, event: tev.MouseMotion) -> bool:
mouse_point = self.mouse_point_for_event(event)
if mouse_point not in self.window.bounds:
return False
return False
def __init__(self, bounds: Rect, *, framed: bool = True, event_handler: Optional['EventHandler'] = None):
self.bounds = bounds
self.is_framed = framed
self.event_handler = event_handler or self.__class__.EventHandler(self)
@property
def drawable_bounds(self) -> Rect:
'''
The bounds of the window that is drawable, inset by its frame if
`is_framed` is `True`.
'''
if self.is_framed:
return self.bounds.inset_rect(1, 1, 1, 1)
return self.bounds
def convert_console_point(self, point: Point) -> Optional[Point]:
'''
Converts a point in console coordinates to window-relative coordinates.
If the point is out of bounds of the window, return None.
'''
converted_point = point - Vector.from_point(self.bounds.origin)
return converted_point if converted_point in self.bounds else None
def draw(self, console: Console):
'''Draw the window to the conole'''
if self.is_framed:
console.draw_frame(
self.bounds.origin.x,
self.bounds.origin.y,
self.bounds.size.width,
self.bounds.size.height)
drawable_bounds = self.drawable_bounds
console.draw_rect(drawable_bounds.min_x, drawable_bounds.min_y,
drawable_bounds.width, drawable_bounds.height,
ord(' '), (255, 255, 255), (0, 0, 0))

View file

@ -0,0 +1,45 @@
# Eryn Wells <eryn@erynwells.me>
'''
Declares the InfoWindow.
'''
from . import Window
from ..color import HealthBar
from ..percentage_bar import PercentageBar
from ...geometry import Point, Rect
from ...object import Hero
class InfoWindow(Window):
'''A window that displays information about the player'''
def __init__(self, bounds: Rect):
super().__init__(bounds, framed=True)
self.turn_count: int = 0
drawable_area = self.drawable_bounds
self.hit_points_bar = PercentageBar(
position=Point(drawable_area.min_x + 6, drawable_area.min_y),
width=20,
colors=list(HealthBar.bar_colors()))
def update_hero(self, hero: Hero):
'''Update internal state for the hero'''
assert hero.fighter
fighter = hero.fighter
hp, max_hp = fighter.hit_points, fighter.maximum_hit_points
self.hit_points_bar.percent_filled = hp / max_hp
def draw(self, console):
super().draw(console)
drawable_bounds = self.drawable_bounds
console.print(x=drawable_bounds.min_x + 2, y=drawable_bounds.min_y, string='HP:')
self.hit_points_bar.render_to_console(console)
if self.turn_count:
console.print(x=drawable_bounds.min_x, y=drawable_bounds.min_y + 1, string=f'Turn: {self.turn_count}')

View file

@ -1,90 +1,16 @@
# Eryn Wells <eryn@erynwells.me>
from typing import List, Optional
from typing import List
import numpy as np
from tcod import event as tev
import tcod.event as tev
from tcod.console import Console
from .. import log
from ..geometry import Point, Rect, Size, Vector
from ..map import Map
from ..object import Entity, Hero
class Window:
'''A user interface window. It can be framed and it can handle events.'''
class EventHandler(tev.EventDispatch[bool]):
'''
Handles events for a Window. Event dispatch methods return True if the event
was handled and no further action is needed.
'''
def __init__(self, window: 'Window'):
super().__init__()
self.window = window
def mouse_point_for_event(self, event: tev.MouseState) -> Point:
'''
Return the mouse point in tiles for a window event. Raises a ValueError
if the event is not a mouse event.
'''
if not isinstance(event, tev.MouseState):
raise ValueError("Can't get mouse point for non-mouse event")
return Point(event.tile.x, event.tile.y)
def ev_keydown(self, event: tev.KeyDown) -> bool:
return False
def ev_keyup(self, event: tev.KeyUp) -> bool:
return False
def ev_mousemotion(self, event: tev.MouseMotion) -> bool:
mouse_point = self.mouse_point_for_event(event)
if mouse_point not in self.window.bounds:
return False
return False
def __init__(self, bounds: Rect, *, framed: bool = True, event_handler: Optional['EventHandler'] = None):
self.bounds = bounds
self.is_framed = framed
self.event_handler = event_handler or self.__class__.EventHandler(self)
@property
def drawable_bounds(self) -> Rect:
'''
The bounds of the window that is drawable, inset by its frame if
`is_framed` is `True`.
'''
if self.is_framed:
return self.bounds.inset_rect(1, 1, 1, 1)
return self.bounds
def convert_console_point(self, point: Point) -> Optional[Point]:
'''
Converts a point in console coordinates to window-relative coordinates.
If the point is out of bounds of the window, return None.
'''
converted_point = point - Vector.from_point(self.bounds.origin)
return converted_point if converted_point in self.bounds else None
def draw(self, console: Console):
'''Draw the window to the conole'''
if self.is_framed:
console.draw_frame(
self.bounds.origin.x,
self.bounds.origin.y,
self.bounds.size.width,
self.bounds.size.height)
drawable_bounds = self.drawable_bounds
console.draw_rect(drawable_bounds.min_x, drawable_bounds.min_y,
drawable_bounds.width, drawable_bounds.height,
ord(' '), (255, 255, 255), (0, 0, 0))
from . import Window
from ... import log
from ...geometry import Point, Rect, Size, Vector
from ...map import Map
from ...object import Entity, Hero
class MapWindow(Window):

View file

@ -0,0 +1,21 @@
# Eryn Wells <eryn@erynwells.me>
'''
Declares the MessageLogWindow.
'''
from . import Window
from ...geometry import Rect
from ...messages import MessageLog
class MessageLogWindow(Window):
'''A window that displays a list of messages'''
def __init__(self, bounds: Rect, message_log: MessageLog):
super().__init__(bounds, framed=True)
self.message_log = message_log
def draw(self, console):
super().draw(console)
self.message_log.render_to_console(console, self.drawable_bounds)