Move all interface Windows to their own modules in interface.window
This commit is contained in:
parent
1e678ff47d
commit
a8bbc47668
5 changed files with 160 additions and 133 deletions
|
@ -10,14 +10,12 @@ from tcod import event as tev
|
||||||
from tcod.console import Console
|
from tcod.console import Console
|
||||||
from tcod.context import Context
|
from tcod.context import Context
|
||||||
|
|
||||||
from .color import HealthBar
|
|
||||||
from .events import InterfaceEventHandler
|
from .events import InterfaceEventHandler
|
||||||
from .percentage_bar import PercentageBar
|
from .window.info import InfoWindow
|
||||||
from .window import Window, MapWindow
|
from .window.map import MapWindow
|
||||||
|
from .window.message_log import MessageLogWindow
|
||||||
from ..engine import Engine
|
from ..engine import Engine
|
||||||
from ..geometry import Point, Rect, Size
|
from ..geometry import Rect, Size
|
||||||
from ..messages import MessageLog
|
|
||||||
from ..object import Entity, Hero
|
|
||||||
|
|
||||||
|
|
||||||
class Interface:
|
class Interface:
|
||||||
|
@ -76,49 +74,3 @@ class Interface:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self.engine.process_input_action(action)
|
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)
|
|
||||||
|
|
83
erynrl/interface/window/__init__.py
Normal file
83
erynrl/interface/window/__init__.py
Normal 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))
|
45
erynrl/interface/window/info.py
Normal file
45
erynrl/interface/window/info.py
Normal 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}')
|
|
@ -1,90 +1,16 @@
|
||||||
# Eryn Wells <eryn@erynwells.me>
|
# Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
from typing import List, Optional
|
from typing import List
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from tcod import event as tev
|
import tcod.event as tev
|
||||||
from tcod.console import Console
|
from tcod.console import Console
|
||||||
|
|
||||||
from .. import log
|
from . import Window
|
||||||
from ..geometry import Point, Rect, Size, Vector
|
from ... import log
|
||||||
from ..map import Map
|
from ...geometry import Point, Rect, Size, Vector
|
||||||
from ..object import Entity, Hero
|
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))
|
|
||||||
|
|
||||||
|
|
||||||
class MapWindow(Window):
|
class MapWindow(Window):
|
21
erynrl/interface/window/message_log.py
Normal file
21
erynrl/interface/window/message_log.py
Normal 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)
|
Loading…
Add table
Add a link
Reference in a new issue