use std::time::Duration;
use super::{Menu, SubMenu};
use kas::event::{GrabMode, NavKey};
use kas::prelude::*;
use kas::widget::List;
const DELAY: Duration = Duration::from_millis(200);
#[handler(noauto)]
#[derive(Clone, Debug, Widget)]
pub struct MenuBar<D: Directional, W: Menu> {
#[widget_core]
core: CoreData,
#[widget]
pub bar: List<D, SubMenu<D::Flipped, W>>,
opening: bool,
delayed_open: Option<WidgetId>,
}
impl<D: Directional + Default, W: Menu> MenuBar<D, W> {
pub fn new(menus: Vec<SubMenu<D::Flipped, W>>) -> Self {
MenuBar::new_with_direction(D::default(), menus)
}
}
impl<D: Directional, W: Menu> MenuBar<D, W> {
pub fn new_with_direction(direction: D, menus: Vec<SubMenu<D::Flipped, W>>) -> Self {
MenuBar {
core: Default::default(),
bar: List::new_with_direction(direction, menus),
opening: false,
delayed_open: None,
}
}
}
impl<D: Directional, W: Menu> Layout for MenuBar<D, W> {
fn size_rules(&mut self, size_handle: &mut dyn SizeHandle, axis: AxisInfo) -> SizeRules {
self.bar.size_rules(size_handle, axis)
}
fn set_rect(&mut self, rect: Rect, _: AlignHints) {
self.core_data_mut().rect = rect;
let align = AlignHints::new(Some(Align::Begin), Some(Align::Begin));
self.bar.set_rect(rect, align);
}
#[inline]
fn find_id(&self, coord: Coord) -> Option<WidgetId> {
if !self.rect().contains(coord) {
return None;
}
if let Some(id) = self.bar.find_id(coord) {
return Some(id);
}
Some(self.id())
}
fn draw(&self, draw_handle: &mut dyn DrawHandle, mgr: &event::ManagerState, disabled: bool) {
self.bar.draw(draw_handle, mgr, disabled);
}
}
impl<D: Directional, W: Menu<Msg = M>, M> event::Handler for MenuBar<D, W> {
type Msg = M;
fn handle(&mut self, mgr: &mut Manager, event: Event) -> Response<Self::Msg> {
match event {
Event::TimerUpdate => {
if let Some(id) = self.delayed_open {
self.delayed_open = None;
self.menu_path(mgr, Some(id));
}
}
Event::PressStart {
source,
start_id,
coord,
} => {
if self.is_ancestor_of(start_id) {
if source.is_primary()
&& mgr.request_grab(self.id(), source, coord, GrabMode::Grab, None)
{
mgr.set_grab_depress(source, Some(start_id));
self.find(start_id).map(|w| mgr.next_nav_focus(w, false));
self.opening = false;
if self.rect().contains(coord) {
for i in 0..self.bar.len() {
let w = &mut self.bar[i];
let id = w.id();
if id == start_id {
if !w.menu_is_open() {
self.opening = true;
self.delayed_open = Some(id);
mgr.update_on_timer(DELAY, self.id());
}
break;
}
}
} else {
self.delayed_open = Some(start_id);
mgr.update_on_timer(DELAY, self.id());
}
}
} else {
self.delayed_open = None;
return Response::Unhandled(Event::None);
}
}
Event::PressMove { source, cur_id, .. } => {
if let Some(w) = cur_id.and_then(|id| self.find(id)) {
if w.key_nav() {
let id = cur_id.unwrap();
mgr.set_grab_depress(source, Some(id));
mgr.set_nav_focus(id);
self.delayed_open = Some(id);
mgr.update_on_timer(DELAY, self.id());
}
} else {
mgr.set_grab_depress(source, None);
}
}
Event::PressEnd { coord, end_id, .. } => {
if end_id.map(|id| self.is_ancestor_of(id)).unwrap_or(false) {
let id = end_id.unwrap();
if self.rect().contains(coord) {
if !self.opening {
self.delayed_open = None;
for i in 0..self.bar.len() {
if self.bar[i].id() == id {
self.bar[i].menu_path(mgr, None);
}
}
}
} else {
self.delayed_open = None;
return self.send(mgr, id, Event::Activate);
}
} else {
self.delayed_open = None;
self.menu_path(mgr, None);
}
}
Event::NavKey(key) => {
let is_vert = self.bar.direction().is_vertical();
let reverse = self.bar.direction().is_reversed()
^ match key {
NavKey::Left if !is_vert => true,
NavKey::Right if !is_vert => false,
NavKey::Up if is_vert => true,
NavKey::Down if is_vert => false,
key => return Response::Unhandled(Event::NavKey(key)),
};
for i in 0..self.bar.len() {
if self.bar[i].menu_is_open() {
let index = if reverse { i.wrapping_sub(1) } else { i + 1 };
if index < self.bar.len() {
self.delayed_open = None;
self.bar[i].menu_path(mgr, None);
let w = &mut self.bar[index];
w.menu_path(mgr, Some(w.id()));
}
break;
}
}
}
e => return Response::Unhandled(e),
}
Response::None
}
}
impl<D: Directional, W: Menu> event::SendEvent for MenuBar<D, W> {
fn send(&mut self, mgr: &mut Manager, id: WidgetId, event: Event) -> Response<Self::Msg> {
if self.is_disabled() {
return Response::Unhandled(event);
}
if id <= self.bar.id() {
return match self.bar.send(mgr, id, event) {
Response::Unhandled(event) => self.handle(mgr, event),
r => r,
};
}
self.handle(mgr, event)
}
}
impl<D: Directional, W: Menu> Menu for MenuBar<D, W> {
fn menu_path(&mut self, mgr: &mut Manager, target: Option<WidgetId>) {
if let Some(id) = target {
let mut child = None;
for i in 0..self.bar.len() {
if self.bar[i].is_ancestor_of(id) {
child = Some(i);
} else {
self.bar[i].menu_path(mgr, None);
}
}
if let Some(i) = child {
self.bar[i].menu_path(mgr, target);
}
} else {
for i in 0..self.bar.len() {
self.bar[i].menu_path(mgr, None);
}
}
}
}