update events
This commit is contained in:
@@ -77,6 +77,10 @@ class Front:
|
||||
self._avatar_display_states: Dict[str, Dict[str, float]] = {}
|
||||
self._init_avatar_display_states()
|
||||
|
||||
# 侧栏筛选状态:None 表示所有人;否则为 avatar_id
|
||||
self._sidebar_filter_avatar_id: Optional[str] = None
|
||||
self._sidebar_filter_open: bool = False
|
||||
|
||||
def add_events(self, new_events: List[Event]):
|
||||
self.events.extend(new_events)
|
||||
if len(self.events) > 1000:
|
||||
@@ -108,6 +112,8 @@ class Front:
|
||||
elif event.key == pygame.K_SPACE:
|
||||
if current_step_task is None or current_step_task.done():
|
||||
current_step_task = asyncio.create_task(self._step_once_async())
|
||||
elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
|
||||
self._handle_mouse_click()
|
||||
if self._auto_step and self._last_step_ms >= self.step_interval_ms:
|
||||
if current_step_task is None or current_step_task.done():
|
||||
current_step_task = asyncio.create_task(self._step_once_async())
|
||||
@@ -162,10 +168,33 @@ class Front:
|
||||
)
|
||||
# 先绘制状态栏和侧边栏,再绘制 tooltip 保证 tooltip 在最上层
|
||||
draw_status_bar(pygame, self.screen, self.colors, self.status_font, self.margin, self.world, self._auto_step)
|
||||
draw_sidebar(
|
||||
pygame, self.screen, self.colors, self.sidebar_font, self.events,
|
||||
|
||||
# 计算筛选后的事件
|
||||
if self._sidebar_filter_avatar_id is None:
|
||||
events_to_draw: List[Event] = self.events
|
||||
else:
|
||||
aid = self._sidebar_filter_avatar_id
|
||||
events_to_draw = [e for e in self.events if getattr(e, "related_avatars", None) and (aid in e.related_avatars)]
|
||||
|
||||
# 构造下拉选项(第一个是所有人;其余为当前世界中的角色)
|
||||
options: List[tuple[str, Optional[str]]] = [("所有人", None)]
|
||||
for avatar_id, avatar in self.world.avatar_manager.avatars.items():
|
||||
options.append((avatar.name, avatar_id))
|
||||
sel_label = "所有人"
|
||||
if self._sidebar_filter_avatar_id is not None:
|
||||
sel_avatar = self.world.avatar_manager.avatars.get(self._sidebar_filter_avatar_id)
|
||||
if sel_avatar is not None:
|
||||
sel_label = sel_avatar.name
|
||||
|
||||
sidebar_ui = draw_sidebar(
|
||||
pygame, self.screen, self.colors, self.sidebar_font, events_to_draw,
|
||||
self.world.map, self.tile_size, self.margin, self.sidebar_width,
|
||||
filter_selected_label=sel_label,
|
||||
filter_is_open=self._sidebar_filter_open,
|
||||
filter_options=options,
|
||||
)
|
||||
# 保存供点击检测
|
||||
self._sidebar_ui = sidebar_ui
|
||||
if hovered_avatar is not None:
|
||||
draw_tooltip_for_avatar(pygame, self.screen, self.colors, self.tooltip_font, hovered_avatar)
|
||||
elif hovered_region is not None:
|
||||
@@ -173,6 +202,23 @@ class Front:
|
||||
draw_tooltip_for_region(pygame, self.screen, self.colors, self.tooltip_font, hovered_region, mouse_x, mouse_y)
|
||||
pygame.display.flip()
|
||||
|
||||
def _handle_mouse_click(self) -> None:
|
||||
# 仅处理侧栏筛选点击
|
||||
pygame = self.pygame
|
||||
mouse_pos = pygame.mouse.get_pos()
|
||||
ui = getattr(self, "_sidebar_ui", {}) or {}
|
||||
toggle_rect = ui.get("filter_toggle_rect")
|
||||
option_rects = ui.get("filter_option_rects") or []
|
||||
if toggle_rect and toggle_rect.collidepoint(mouse_pos):
|
||||
self._sidebar_filter_open = not self._sidebar_filter_open
|
||||
return
|
||||
if self._sidebar_filter_open:
|
||||
for oid, rect in option_rects:
|
||||
if rect.collidepoint(mouse_pos):
|
||||
self._sidebar_filter_avatar_id = oid if oid is not None else None
|
||||
self._sidebar_filter_open = False
|
||||
return
|
||||
|
||||
def _get_region_font(self, size: int):
|
||||
return _get_region_font_cached(self.pygame, self._region_font_cache, size, self.font_path)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import List
|
||||
from typing import List, Optional, Tuple, Dict
|
||||
from .rendering import STATUS_BAR_HEIGHT
|
||||
|
||||
|
||||
@@ -25,8 +25,21 @@ def _wrap_text_by_pixels(font, text: str, max_width_px: int) -> List[str]:
|
||||
return lines
|
||||
|
||||
|
||||
def draw_sidebar(pygame_mod, screen, colors, font, events: List[object],
|
||||
world_map, tile_size: int, margin: int, sidebar_width: int):
|
||||
def draw_sidebar(
|
||||
pygame_mod,
|
||||
screen,
|
||||
colors,
|
||||
font,
|
||||
events: List[object],
|
||||
world_map,
|
||||
tile_size: int,
|
||||
margin: int,
|
||||
sidebar_width: int,
|
||||
*,
|
||||
filter_selected_label: str,
|
||||
filter_is_open: bool,
|
||||
filter_options: List[Tuple[str, Optional[str]]],
|
||||
) -> Dict[str, object]:
|
||||
sidebar_x = world_map.width * tile_size + margin * 2
|
||||
sidebar_y = margin + STATUS_BAR_HEIGHT
|
||||
|
||||
@@ -39,13 +52,54 @@ def draw_sidebar(pygame_mod, screen, colors, font, events: List[object],
|
||||
pygame_mod.draw.rect(screen, colors["sidebar_bg"], sidebar_rect)
|
||||
pygame_mod.draw.rect(screen, colors["sidebar_border"], sidebar_rect, 2)
|
||||
|
||||
# 下拉选择器:显示“所有人/某人”,放在最上方
|
||||
dropdown_margin_x = 10
|
||||
dropdown_width = sidebar_width - 20
|
||||
# 先用一个基准高度,确保点击区域更易操作
|
||||
dropdown_height = 24
|
||||
dropdown_x = sidebar_x + dropdown_margin_x
|
||||
dropdown_y = sidebar_y + 10
|
||||
dropdown_rect = pygame_mod.Rect(dropdown_x, dropdown_y, dropdown_width, dropdown_height)
|
||||
# 填充底色并描边
|
||||
pygame_mod.draw.rect(screen, colors["sidebar_bg"], dropdown_rect)
|
||||
pygame_mod.draw.rect(screen, colors["sidebar_border"], dropdown_rect, 1)
|
||||
# 选中项文本
|
||||
sel_text = filter_selected_label or "所有人"
|
||||
sel_surf = font.render(f"筛选:{sel_text}", True, colors["event_text"])
|
||||
screen.blit(sel_surf, (dropdown_x + 6, dropdown_y + (dropdown_height - sel_surf.get_height()) // 2))
|
||||
# 右侧箭头
|
||||
arrow_char = "▲" if filter_is_open else "▼"
|
||||
arrow_surf = font.render(arrow_char, True, colors["event_text"])
|
||||
screen.blit(arrow_surf, (dropdown_x + dropdown_width - arrow_surf.get_width() - 6, dropdown_y + (dropdown_height - arrow_surf.get_height()) // 2))
|
||||
|
||||
option_rects: List[Tuple[Optional[str], object]] = []
|
||||
options_total_h = 0
|
||||
if filter_is_open and filter_options:
|
||||
# 整体下拉区域背景,避免与事件文字混在一起
|
||||
options_total_h = dropdown_height * len(filter_options)
|
||||
options_area_rect = pygame_mod.Rect(dropdown_x, dropdown_y + dropdown_height, dropdown_width, options_total_h)
|
||||
pygame_mod.draw.rect(screen, colors["sidebar_bg"], options_area_rect)
|
||||
pygame_mod.draw.rect(screen, colors["sidebar_border"], options_area_rect, 1)
|
||||
# 逐项绘制
|
||||
opt_y = dropdown_y + dropdown_height
|
||||
for label, oid in filter_options:
|
||||
opt_rect = pygame_mod.Rect(dropdown_x, opt_y, dropdown_width, dropdown_height)
|
||||
pygame_mod.draw.rect(screen, colors["sidebar_bg"], opt_rect)
|
||||
pygame_mod.draw.rect(screen, colors["sidebar_border"], opt_rect, 1)
|
||||
opt_surf = font.render(label, True, colors["event_text"])
|
||||
screen.blit(opt_surf, (dropdown_x + 6, opt_y + (dropdown_height - opt_surf.get_height()) // 2))
|
||||
option_rects.append((oid, opt_rect))
|
||||
opt_y += dropdown_height
|
||||
|
||||
# 标题“事件历史”位于筛选下拉之下
|
||||
title_text = "事件历史"
|
||||
title_surf = font.render(title_text, True, colors["text"])
|
||||
title_x = sidebar_x + 10
|
||||
title_y = sidebar_y + 10
|
||||
title_y = dropdown_y + dropdown_height + (options_total_h if filter_is_open else 0) + 10
|
||||
screen.blit(title_surf, (title_x, title_y))
|
||||
|
||||
line_y = title_y + title_surf.get_height() + 10
|
||||
# 事件列表起始位置位于标题之后
|
||||
line_y = title_y + title_surf.get_height() + 6
|
||||
pygame_mod.draw.line(screen, colors["sidebar_border"],
|
||||
(sidebar_x + 10, line_y),
|
||||
(sidebar_x + sidebar_width - 10, line_y), 1)
|
||||
@@ -70,6 +124,10 @@ def draw_sidebar(pygame_mod, screen, colors, font, events: List[object],
|
||||
no_event_text = "暂无事件"
|
||||
no_event_surf = font.render(no_event_text, True, colors["event_text"])
|
||||
screen.blit(no_event_surf, (title_x, event_y))
|
||||
return {
|
||||
"filter_toggle_rect": dropdown_rect,
|
||||
"filter_option_rects": option_rects,
|
||||
}
|
||||
|
||||
|
||||
__all__ = ["draw_sidebar"]
|
||||
|
||||
Reference in New Issue
Block a user