use pelican_ui::events::{OnEvent, Event};
use pelican_ui::drawable::{Color, Drawable, Component, Image};
use pelican_ui::layout::{Area, SizeRequest, Layout};
use pelican_ui::{Context, Component};
use crate::components::{Rectangle, AspectRatioImage};
use crate::components::button::{Button, ButtonState, IconButton};
use crate::events::{NavigatorSelect, NavigateEvent, NavigatorEvent};
use crate::layout::{Column, Stack, Bin, Row, Padding, Offset, Size};
use crate::utils::ElementID;
use crate::pages::AppPage;
use crate::pages::Error;
use std::fmt::Debug;
use crate::components::interface::general::{NavigationButton, NavigateInfo, PageBuilder};
#[derive(Component)]
pub struct WebInterface(Column, Option<WebNavigator>, Option<Box<dyn AppPage>>, Option<WebFooter>, #[skip] PageBuilder);
impl WebInterface {
pub fn new(
ctx: &mut Context,
start_page: Box<dyn AppPage>,
mut navigation: Option<(usize, Vec<NavigateInfo>, Vec<NavigateInfo>)>,
socials: Option<Vec<(&'static str, String)>>
) -> Self {
let pages = navigation.as_mut().map(|navi| navi.1.iter_mut().chain(navi.2.iter_mut()).map(|t| t.3.take().unwrap()).collect::<Vec<_>>());
let navigator = navigation.map(|n| WebNavigator::new(ctx, n));
let footer = socials.map(|s| WebFooter::new(ctx, s));
WebInterface(
Column::new(0.0, Offset::Start, Size::fill(), Padding::default()),
navigator,
Some(start_page),
footer,
pages,
)
}
pub fn page(&mut self) -> &mut Option<Box<dyn AppPage>> { &mut self.2 }
pub fn navigator(&mut self) -> &mut Option<WebNavigator> { &mut self.1 }
}
impl OnEvent for WebInterface {
fn on_event(&mut self, ctx: &mut Context, event: &mut dyn Event) -> bool {
if let Some(NavigateEvent(index)) = event.downcast_mut::<NavigateEvent>() {
self.2 = match self.2.take().unwrap().navigate(ctx, *index) {
Ok(p) => Some(p),
Err(e) => Some(Box::new(Error::new(ctx, "404 Page Not Found", e)))
};
} else if let Some(NavigatorEvent(index)) = event.downcast_mut::<NavigatorEvent>() {
if let Some(nav) = self.4.as_mut() { self.2 = Some(nav[*index](ctx)); }
}
true
}
}
impl std::fmt::Debug for WebInterface {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Desktop")
}
}
#[derive(Debug, Component)]
pub struct WebNavigator(Row, Image, Bin<Stack, Rectangle>, ButtonRow);
impl WebNavigator {
pub fn new(
ctx: &mut Context,
navigation: (usize, Vec<NavigateInfo>, Vec<NavigateInfo>),
) -> Self {
let mut buttons = Vec::new();
let mut index = 0;
navigation.1.into_iter().chain(navigation.2).for_each(|(icon, name, _, _)| {
let id = ElementID::new();
let closure = move |ctx: &mut Context| {
ctx.trigger_event(NavigatorSelect(id));
ctx.trigger_event(NavigatorEvent(index));
};
let button = Button::navigation(ctx, icon, &name, navigation.0 == index, closure);
buttons.push(NavigationButton::new(id, Some(button), None));
index += 1;
});
let wordmark = ctx.theme.brand.wordmark.clone();
WebNavigator(
Row::new(32.0, Offset::Center, Size::Fit, Padding::new(48.0)),
AspectRatioImage::new(wordmark, (150.0, 35.0)),
Bin (
Stack(Offset::Center, Offset::Center, Size::fill(), Size::Static(5.0), Padding::default()),
Rectangle::new(Color::TRANSPARENT, 0.0, None)
),
ButtonRow::new(buttons)
)
}
pub fn buttons(&mut self) -> Vec<&mut Button> {
self.3.buttons().iter_mut().flat_map(|nb| nb.button()).collect::<Vec<_>>()
}
}
impl OnEvent for WebNavigator {
fn on_event(&mut self, ctx: &mut Context, event: &mut dyn Event) -> bool {
if let Some(NavigatorSelect(id)) = event.downcast_ref::<NavigatorSelect>() {
let mut buttons: Vec<&mut NavigationButton> = self.3.buttons().iter_mut().collect();
buttons.iter_mut().for_each(|button| {
*button.button().as_mut().unwrap().status() = if button.id() == *id {ButtonState::Selected} else {ButtonState::Default};
button.button().as_mut().unwrap().color(ctx);
});
}
true
}
}
#[derive(Debug, Component)]
struct ButtonRow(Row, Vec<NavigationButton>);
impl OnEvent for ButtonRow {}
impl ButtonRow {
fn new(buttons: Vec<NavigationButton>) -> Self {
ButtonRow(Row::center(8.0), buttons)
}
fn buttons(&mut self) -> &mut Vec<NavigationButton> {&mut self.1}
}
#[derive(Debug, Component)]
struct WebFooter(Row, Bin<Stack, Rectangle>, ButtonRow);
impl OnEvent for WebFooter {}
impl WebFooter {
fn new(
ctx: &mut Context,
socials: Vec<(&'static str, String)>
) -> Self {
let buttons = socials.into_iter().map(|(i, _)| {
let button = IconButton::ghost(ctx, i, Box::new(move |_ctx: &mut Context| {}));
let id = ElementID::new();
NavigationButton::new(id, None, Some(button))
}).collect();
WebFooter(
Row::new(32.0, Offset::Center, Size::Fit, Padding::new(48.0)),
Bin (
Stack(Offset::Center, Offset::Center, Size::fill(), Size::Static(5.0), Padding::default()),
Rectangle::new(Color::TRANSPARENT, 0.0, None)
),
ButtonRow::new(buttons)
)
}
}