use std::fmt;
use std::sync::{mpsc, Arc, Mutex};
use crate::apps::{ControlMessage, FullscreenSetter, FullscreenState};
use crate::vui::options::{graphics_options_widgets, pause_toggle_button};
use crate::vui::widgets::{self, Crosshair, TooltipState};
use crate::vui::{CueNotifier, LayoutTree, UiBlocks, VuiMessage, VuiPageState, Widget, WidgetTree};
use all_is_cubes::block::Block;
use all_is_cubes::camera::GraphicsOptions;
use all_is_cubes::character::Character;
use all_is_cubes::content::palette;
use all_is_cubes::drawing::VoxelBrush;
use all_is_cubes::inv::Icons;
use all_is_cubes::linking::BlockProvider;
use all_is_cubes::listen::ListenableSource;
use all_is_cubes::math::Face6;
use all_is_cubes::universe::{URef, Universe};
use all_is_cubes::util::YieldProgress;
pub(crate) use all_is_cubes::drawing::embedded_graphics::mono_font::iso_8859_1::FONT_8X13_BOLD as HudFont;
pub(crate) const TOOLBAR_POSITIONS: usize = 10;
pub(crate) struct HudInputs {
pub hud_blocks: Arc<HudBlocks>,
pub cue_channel: CueNotifier,
pub vui_control_channel: mpsc::SyncSender<VuiMessage>,
pub app_control_channel: mpsc::SyncSender<ControlMessage>,
pub graphics_options: ListenableSource<GraphicsOptions>,
pub paused: ListenableSource<bool>,
pub page_state: ListenableSource<VuiPageState>,
pub mouselook_mode: ListenableSource<bool>,
pub fullscreen_mode: ListenableSource<FullscreenState>,
pub set_fullscreen: FullscreenSetter,
}
impl fmt::Debug for HudInputs {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("HudInputs").finish_non_exhaustive()
}
}
#[allow(clippy::redundant_clone)]
pub(super) fn new_hud_widget_tree(
character_source: ListenableSource<Option<URef<Character>>>,
hud_inputs: &HudInputs,
universe: &mut Universe,
tooltip_state: Arc<Mutex<TooltipState>>,
) -> WidgetTree {
let toolbar: Arc<dyn Widget> = widgets::Toolbar::new(
character_source,
Arc::clone(&hud_inputs.hud_blocks),
TOOLBAR_POSITIONS,
universe,
hud_inputs.cue_channel.clone(),
);
let tooltip: Arc<dyn Widget> = widgets::Tooltip::new(
Arc::clone(&tooltip_state),
hud_inputs.hud_blocks.clone(),
universe,
);
let hud_widget_tree: WidgetTree = Arc::new(LayoutTree::Hud {
crosshair: LayoutTree::leaf(Crosshair::new(
hud_inputs.hud_blocks.blocks[UiBlocks::Crosshair].clone(),
hud_inputs.mouselook_mode.clone(),
)),
toolbar: Arc::new(LayoutTree::Stack {
direction: Face6::PY,
children: vec![LayoutTree::leaf(toolbar), LayoutTree::leaf(tooltip)],
}),
control_bar: control_bar(hud_inputs),
});
hud_widget_tree
}
pub(crate) fn control_bar(hud_inputs: &HudInputs) -> WidgetTree {
let control_bar_widgets: WidgetTree = Arc::new(LayoutTree::Stack {
direction: Face6::NX,
children: vec![
Arc::new(LayoutTree::Stack {
direction: Face6::NX,
children: graphics_options_widgets(hud_inputs),
}),
LayoutTree::leaf(widgets::ToggleButton::new(
hud_inputs.page_state.clone(),
|page_state| matches!(page_state, VuiPageState::AboutText),
|state| hud_inputs.hud_blocks.blocks[UiBlocks::AboutButton(state)].clone(),
{
let cc = hud_inputs.vui_control_channel.clone();
move || {
let _ignore_errors = cc.send(VuiMessage::About);
}
},
)),
LayoutTree::leaf(pause_toggle_button(hud_inputs)),
LayoutTree::leaf(widgets::ToggleButton::new(
hud_inputs.mouselook_mode.clone(),
|&value| value,
|state| hud_inputs.hud_blocks.blocks[UiBlocks::MouselookButton(state)].clone(),
{
let cc = hud_inputs.app_control_channel.clone();
move || {
let _ignore_errors = cc.send(ControlMessage::ToggleMouselook);
}
},
)),
],
});
if false {
Arc::new(LayoutTree::Stack {
direction: Face6::PZ,
children: vec![
LayoutTree::leaf(widgets::Frame::for_menu()),
control_bar_widgets,
],
})
} else {
control_bar_widgets
}
}
#[derive(Debug, Clone)]
pub(crate) struct HudBlocks {
pub(crate) blocks: BlockProvider<UiBlocks>,
pub(crate) icons: BlockProvider<Icons>,
pub(crate) text: VoxelBrush<'static>,
}
impl HudBlocks {
pub(crate) async fn new(universe: &mut Universe, p: YieldProgress) -> Self {
let [p1, p2] = p.split(0.5);
let ui_blocks = UiBlocks::new(universe, p1).await.install(universe).unwrap();
let icons = Icons::new(universe, p2).await.install(universe).unwrap();
let text_brush = VoxelBrush::new::<_, Block>([
([0, 0, 1], palette::HUD_TEXT_FILL.into()),
([1, 0, 0], palette::HUD_TEXT_STROKE.into()),
([-1, 0, 0], palette::HUD_TEXT_STROKE.into()),
([0, 1, 0], palette::HUD_TEXT_STROKE.into()),
([0, -1, 0], palette::HUD_TEXT_STROKE.into()),
]);
Self {
blocks: ui_blocks,
icons,
text: text_brush,
}
}
}