use super::{Menu, SubItems};
use crate::{AccessLabel, CheckBox};
use kas::theme::{FrameStyle, TextClass};
use kas::{layout, prelude::*};
use std::fmt::Debug;
impl_scope! {
#[derive(Clone, Debug, Default)]
#[widget {
layout = self.label;
navigable = true;
}]
pub struct MenuEntry<M: Clone + Debug + 'static> {
core: widget_core!(),
#[widget]
label: AccessLabel,
msg: M,
}
impl Layout for Self {
fn find_id(&mut self, coord: Coord) -> Option<WidgetId> {
self.rect().contains(coord).then(|| self.id())
}
fn draw(&mut self, mut draw: DrawCx) {
draw.frame(self.rect(), FrameStyle::MenuEntry, Default::default());
self.label.draw(draw);
}
}
impl Self {
pub fn new_msg<S: Into<AccessString>>(label: S, msg: M) -> Self {
MenuEntry {
core: Default::default(),
label: AccessLabel::new(label).with_class(TextClass::MenuLabel),
msg,
}
}
pub fn set_msg(&mut self, msg: M) {
self.msg = msg;
}
}
impl HasStr for Self {
fn get_str(&self) -> &str {
self.label.get_str()
}
}
impl Events for Self {
type Data = ();
fn handle_event(&mut self, cx: &mut EventCx, _: &Self::Data, event: Event) -> IsUsed {
match event {
Event::Command(cmd, code) if cmd.is_activate() => {
cx.push(self.msg.clone());
if let Some(code) = code {
cx.depress_with_key(self.id(), code);
}
Used
}
_ => Unused,
}
}
fn handle_messages(&mut self, cx: &mut EventCx, _: &Self::Data) {
if let Some(kas::message::Activate(code)) = cx.try_pop() {
cx.push(self.msg.clone());
if let Some(code) = code {
cx.depress_with_key(self.id(), code);
}
}
}
}
impl Menu for Self {
fn sub_items(&mut self) -> Option<SubItems> {
Some(SubItems {
label: Some(&mut self.label),
..Default::default()
})
}
}
impl PartialEq<M> for Self where M: PartialEq {
#[inline]
fn eq(&self, rhs: &M) -> bool {
self.msg == *rhs
}
}
}
impl_scope! {
#[widget {
layout = row! [self.checkbox, self.label];
}]
pub struct MenuToggle<A> {
core: widget_core!(),
#[widget]
checkbox: CheckBox<A>,
#[widget(&())]
label: AccessLabel,
}
impl Layout for Self {
fn find_id(&mut self, coord: Coord) -> Option<WidgetId> {
self.rect().contains(coord).then(|| self.checkbox.id())
}
fn draw(&mut self, mut draw: DrawCx) {
let mut draw = draw.re_id(self.checkbox.id());
draw.frame(self.rect(), FrameStyle::MenuEntry, Default::default());
<Self as layout::AutoLayout>::draw(self, draw);
}
}
impl Events for Self {
type Data = A;
fn handle_messages(&mut self, cx: &mut EventCx, data: &Self::Data) {
if let Some(kas::message::Activate(code)) = cx.try_pop() {
self.checkbox.toggle(cx, data);
if let Some(code) = code {
cx.depress_with_key(self.id(), code);
}
}
}
}
impl Menu for Self {
fn sub_items(&mut self) -> Option<SubItems> {
Some(SubItems {
label: Some(&mut self.label),
toggle: Some(&mut self.checkbox),
..Default::default()
})
}
}
impl Self {
#[inline]
pub fn new(
label: impl Into<AccessString>,
state_fn: impl Fn(&ConfigCx, &A) -> bool + 'static,
) -> Self {
MenuToggle {
core: Default::default(),
checkbox: CheckBox::new(state_fn),
label: AccessLabel::new(label).with_class(TextClass::MenuLabel),
}
}
#[inline]
#[must_use]
pub fn with<F>(self, f: F) -> Self
where
F: Fn(&mut EventCx, &A, bool) + 'static,
{
MenuToggle {
core: self.core,
checkbox: self.checkbox.with(f),
label: self.label,
}
}
#[inline]
#[must_use]
pub fn with_msg<M>(self, f: impl Fn(bool) -> M + 'static) -> Self
where
M: std::fmt::Debug + 'static,
{
self.with(move |cx, _, state| cx.push(f(state)))
}
#[inline]
pub fn new_msg<M: Debug + 'static>(
label: impl Into<AccessString>,
state_fn: impl Fn(&ConfigCx, &A) -> bool + 'static,
msg_fn: impl Fn(bool) -> M + 'static,
) -> Self {
MenuToggle::new(label, state_fn).with_msg(msg_fn)
}
}
}