use std::cell::RefCell;
use std::convert::TryFrom;
use std::iter::FromIterator;
use log;
use bitflags::bitflags;
use key_vec::KeyVec;
use smallvec::SmallVec;
use strum::EnumCount;
use crate::prelude::*;
pub mod controls;
pub use self::controls::Controls;
pub mod bindings;
pub use self::bindings::Bindings;
pub mod component;
pub use self::component::Component;
pub mod alignment;
pub mod offset;
pub mod size;
pub use self::alignment::Alignment;
pub use self::offset::Offset;
pub use self::size::Size;
#[derive(Clone, Debug, Default)]
pub struct Controller {
pub component : Component,
pub state : State,
pub appearances : Appearances,
pub focus_top : bool,
pub bubble_trap : InputMask,
pub(crate) input_map : InputMap
}
#[derive(Clone, Debug, Default, Eq, PartialEq, EnumCount)]
pub enum State {
#[default]
Enabled,
Focused,
Disabled
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub enum Area {
#[default]
Interior,
Exterior
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum Orientation {
#[default]
Horizontal,
Vertical
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Appearances (pub [Appearance; State::COUNT]);
#[derive(Default)]
pub struct AppearancesBuilder ([Appearance; State::COUNT]);
bitflags! {
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
pub struct InputMask : u8 {
const AXIS = 0b0000_0001;
const BUTTON = 0b0000_0010;
const MOTION = 0b0000_0100;
const POINTER = 0b0000_1000;
const SYSTEM = 0b0001_0000;
const TEXT = 0b0010_0000;
const WHEEL = 0b0100_0000;
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub(crate) struct InputMap {
pub button_any : Option <controls::Button>,
pub buttons : KeyVec <input::Button, controls::Button>,
pub release_buttons : KeyVec <input::Button, controls::Button>,
pub axes : KeyVec <u32, controls::Axis>,
pub motion : Option <controls::Motion>,
pub pointer : Option <controls::Pointer>,
pub system : Option <controls::System>,
pub text : Option <controls::Text>,
pub wheel : Option <controls::Wheel>
}
#[derive(Debug)]
pub (crate) enum ButtonRelease {
Insert (input::Button, SmallVec <[(controls::Button, NodeId); 1]>),
Remove (input::Button, NodeId)
}
pub (crate) fn refocus (node_id : &NodeId, elements : &Tree <Element>)
-> Option <NodeId>
{
let node = elements.get (node_id).unwrap();
let element = node.data();
if element.controller.state != State::Focused {
log::warn!("refocus state not focused: {:?}", element.controller.state);
debug_assert!(false);
}
let mut refocus_id = None;
if Frame::try_from (element).is_ok() {
let mut children_ids = node.children().iter();
if let Some (child_id) = children_ids.next() {
let child = elements.get_element (child_id);
if Field::try_from (child).is_ok() || Numbox::try_from (child).is_ok() {
refocus_id = Some (child_id.clone());
} else if let Ok (Widget (selection, _, _)) = Menu::try_from (child) {
refocus_id = selection.current.clone()
.or_else (|| menu::find_first_item (elements, children_ids));
}
}
}
refocus_id
}
impl Controller {
#[inline]
pub fn with_bindings <A : Application> (bindings : &Bindings <A>) -> Self {
Controller { input_map: bindings.into(), .. Controller::default() }
}
#[inline]
pub fn get_appearance (&self) -> &Appearance {
self.appearances.get (self.state.clone())
}
#[inline]
pub fn get_bindings <A : Application> (&self) -> Bindings <A> {
self.input_map.to_bindings()
}
#[inline]
pub fn set_bindings <A : Application> (&mut self, bindings : &Bindings <A>) {
self.clear_bindings();
self.add_bindings (bindings);
}
#[inline]
pub fn add_bindings <A : Application> (&mut self, bindings : &Bindings <A>) {
self.input_map.add_bindings (bindings)
}
#[inline]
pub fn insert_bindings <A : Application> (&mut self, bindings : &Bindings <A>) {
self.input_map.insert_bindings (bindings)
}
#[inline]
pub fn remove_bindings (&mut self, controls : &Controls) {
self.input_map.remove_bindings (controls)
}
#[inline]
pub fn clear_buttons (&mut self) {
self.input_map.buttons.clear()
}
#[inline]
pub const fn remove_any_button (&mut self) {
self.input_map.button_any = None
}
#[inline]
pub const fn remove_system (&mut self) {
self.input_map.system = None
}
#[inline]
pub const fn remove_text (&mut self) {
self.input_map.text = None
}
#[inline]
pub const fn remove_motion (&mut self) {
self.input_map.motion = None
}
#[inline]
pub const fn remove_pointer (&mut self) {
self.input_map.pointer = None
}
#[inline]
pub fn clear_bindings (&mut self) {
self.input_map.clear()
}
pub (crate) fn handle_input <A : Application> (&self,
input : Input,
elements : &Tree <Element>,
node_id : &NodeId,
action_buffer : &mut Vec <(NodeId, Action)>
) -> Result <Option <ButtonRelease>, Input> {
use controls::Control;
log::trace!("handle_input...");
let mut button_release = None;
match &input {
Input::Button (button, state) => {
if let Component::Cursor (cursor) = &self.component &&
let input::button::Variant::Keycode (keycode) = button.variant &&
!button.modifiers.intersects (
input::Modifiers::ALT | input::Modifiers::CTRL | input::Modifiers::SUPER)
{
if cursor.ignore.contains (&keycode) {
return Err (input)
} else if keycode.is_printable() {
return Ok (None)
}
}
match state {
input::button::State::Pressed => {
let mut any = false;
if self.input_map.release_buttons
.binary_search_by_key (&button, |(b, _)| b).is_ok()
{
return Ok (None)
}
let control = if let Some (control) = self.input_map.button_any.as_ref() {
any = true;
Some (control)
} else if let Ok (index) = self.input_map.buttons
.binary_search_by_key (&button, |(b, _)| b)
{
let (b, control) = &self.input_map.buttons[index];
if b.modifiers.contains (input::Modifiers::ANY) {
any = true;
}
Some (control)
} else {
None
};
#[expect(clippy::unnecessary_literal_unwrap)]
if let Some (control) = control {
let release = Some (RefCell::new (SmallVec::new()));
control.fun::<A::ButtonControls>().0
(&release, elements, node_id, action_buffer);
let controls = release.unwrap().into_inner();
if !controls.is_empty() {
let mut button = *button;
if any {
button.modifiers.set (input::Modifiers::ANY, true);
}
button_release = Some (ButtonRelease::Insert (button, controls));
}
}
}
input::button::State::Released => {
let control = if let Ok (index) = self.input_map.release_buttons
.binary_search_by_key (&button, |(b, _)| b)
{
let (_, control) = &self.input_map.release_buttons[index];
Some (control)
} else {
None
};
if let Some (control) = control {
control.fun::<A::ButtonControls>().0
(&None, elements, node_id, action_buffer);
button_release =
Some (ButtonRelease::Remove (*button, node_id.clone()));
}
}
}
}
Input::Axis (axis) => {
if let Ok (index) = self.input_map.axes
.binary_search_by_key (&axis.axis, |(a, _)| *a)
{
let (_, control) = &self.input_map.axes[index];
control.fun::<A::AxisControls>().0
(&axis.value, elements, node_id, action_buffer)
}
}
Input::Motion (motion) => {
if let Some (control) = self.input_map.motion.as_ref() {
control.fun::<A::MotionControls>().0
(motion, elements, node_id, action_buffer)
}
}
Input::Pointer (pointer) => {
if let Some (control) = self.input_map.pointer.as_ref() {
control.fun::<A::PointerControls>().0
(pointer, elements, node_id, action_buffer)
}
}
Input::System (system) => {
if let Some (control) = self.input_map.system.as_ref() {
control.fun::<A::SystemControls>().0
(system, elements, node_id, action_buffer)
}
}
Input::Text (text) => {
if let Some (control) = self.input_map.text.as_ref() {
control.fun::<A::TextControls>().0
(text, elements, node_id, action_buffer)
}
}
Input::Wheel (wheel) => {
if let Some (control) = self.input_map.wheel.as_ref() {
control.fun::<A::WheelControls>().0
(wheel, elements, node_id, action_buffer)
}
}
}
log::trace!("...handle_input");
if action_buffer.is_empty() && button_release.is_none() {
Err (input)
} else {
Ok (button_release)
}
}
pub (crate) fn release_buttons (&mut self) -> Vec <controls::Button> {
self.input_map.release_buttons.drain (..).map (|(_, control)| control)
.collect()
}
pub (crate) fn release_button_insert (&mut self,
input : input::Button, control : controls::Button
) {
if self.input_map.release_buttons.insert (input, control).is_some() {
log::debug!("button release control already exists: {:?}", (input, control));
}
}
pub (crate) fn release_button_remove (&mut self, input : input::Button) {
match self.input_map.release_buttons
.binary_search_by_key (&&input, |(b, _)| b)
{
Ok (index) => {
let _ = self.input_map.release_buttons.remove_index (index);
}
Err (_) => {
log::warn!("remove release button not present: {input:?}");
debug_assert!(false);
}
}
}
pub (crate) fn update_view_focus (&self, view : &mut View) {
view.appearance = self.get_appearance().clone();
if let view::Component::Body (body) = &mut view.component &&
let Component::Cursor (cursor) = &self.component
{
match self.state {
State::Focused => {
let caret = char::try_from (cursor.caret).unwrap();
body.0.push (caret);
}
State::Enabled => {
let _ = body.0.pop().unwrap();
}
State::Disabled => {}
}
}
}
}
impl From <Component> for Controller {
fn from (component : Component) -> Self {
Controller { component, .. Controller::default() }
}
}
impl From<&Input> for InputMask {
fn from (input : &Input) -> Self {
match input {
Input::Axis (_) => InputMask::AXIS,
Input::Button (_, _) => InputMask::BUTTON,
Input::Motion (_) => InputMask::MOTION,
Input::Pointer(_) => InputMask::POINTER,
Input::System (_) => InputMask::SYSTEM,
Input::Text (_) => InputMask::TEXT,
Input::Wheel (_) => InputMask::WHEEL
}
}
}
impl InputMap {
pub(crate) fn to_bindings <A : Application> (&self) -> Bindings <A> {
let buttons = self.buttons.iter().copied()
.map (|(button, control)| controls::button::Binding::new (control.into(), button))
.collect();
let any_button = self.button_any.map (Into::into);
let system = self.system.map (Into::into);
let text = self.text.map (Into::into);
let motion = self.motion.map (Into::into);
let pointer = self.pointer.map (Into::into);
Bindings { buttons, any_button, system, text, motion, pointer }
}
pub(crate) fn add_bindings <A : Application> (&mut self, bindings : &Bindings <A>) {
let Bindings { buttons, any_button, system, text, motion, pointer } = bindings;
let buttons_len = self.buttons.len();
let bindings_len = buttons.len();
self.buttons.extend (buttons.iter().map (|binding| (binding.1, binding.0.0)));
assert_eq!(self.buttons.len(), buttons_len + bindings_len);
any_button.clone().map (|button| {
assert!(self.button_any.is_none());
self.button_any = Some (button.into());
});
system.clone().map (|system| {
assert!(self.system.is_none());
self.system = Some (system.into());
});
text.clone().map (|text| {
assert!(self.text.is_none());
self.text = Some (text.into());
});
motion.clone().map (|motion| {
assert!(self.motion.is_none());
self.motion = Some (motion.into());
});
pointer.clone().map (|pointer| {
assert!(self.pointer.is_none());
self.pointer = Some (pointer.into());
});
}
pub(crate) fn insert_bindings <A : Application> (&mut self, bindings : &Bindings <A>) {
let Bindings { buttons, any_button, system, text, motion, pointer } = bindings;
self.buttons.extend (buttons.iter().map (|binding| (binding.1, binding.0.0)));
any_button.clone().map (|button| self.button_any = Some (button.into()));
system.clone().map (|system| self.system = Some (system.into()));
text.clone().map (|text| self.text = Some (text.into()));
motion.clone().map (|motion| self.motion = Some (motion.into()));
pointer.clone().map (|pointer| self.pointer = Some (pointer.into()));
}
pub(crate) fn remove_bindings (&mut self, controls : &Controls) {
let Controls { buttons, any_button, system, text, motion, pointer } = controls;
self.buttons.retain (|(_, button)| !buttons.contains (button));
if &self.button_any == any_button {
self.button_any = None;
}
if &self.system == system {
self.system = None;
}
if &self.text == text {
self.text = None;
}
if &self.motion == motion {
self.motion = None;
}
if &self.pointer == pointer {
self.pointer = None;
}
}
#[inline]
pub(crate) fn clear (&mut self) {
*self = InputMap::default()
}
}
impl <A : Application> From <&Bindings <A>> for InputMap {
fn from (bindings : &Bindings <A>) -> Self {
let Bindings { buttons, any_button, system, text, motion, pointer } = bindings;
let buttons = KeyVec::from_iter (buttons.iter()
.map (|binding| (binding.1, binding.0.0)));
let button_any = any_button.clone().map (Into::into);
let system = system.clone().map (Into::into);
let text = text.clone().map (Into::into);
let motion = motion.clone().map (Into::into);
let pointer = pointer.clone().map (Into::into);
InputMap {
buttons, button_any, system, text, motion, pointer, .. InputMap::default()
}
}
}
impl State {
#[inline]
pub fn focus (&mut self) {
if self != &State::Enabled {
log::warn!("focus state not enabled: {self:?}");
}
debug_assert_eq!(self, &State::Enabled);
*self = State::Focused;
}
#[inline]
pub fn defocus (&mut self) {
if self != &State::Focused {
log::warn!("defocus state not focused: {self:?}");
}
debug_assert_eq!(self, &State::Focused);
*self = State::Enabled;
}
#[inline]
pub fn enable (&mut self) {
if self != &State::Disabled {
log::warn!("enable state not disabled: {self:?}");
}
debug_assert_eq!(self, &State::Disabled);
*self = State::Enabled;
}
#[inline]
pub fn disable (&mut self) {
if self != &State::Enabled {
log::warn!("disable state not enabled: {self:?}");
}
debug_assert_eq!(self, &State::Enabled);
*self = State::Disabled;
}
}
impl Appearances {
#[inline]
pub const fn get (&self, state : State) -> &Appearance {
&self.0[state as usize]
}
#[inline]
pub const fn get_mut (&mut self, state : State) -> &mut Appearance {
&mut self.0[state as usize]
}
}
impl AppearancesBuilder {
pub fn transparent() -> Self {
AppearancesBuilder::default()
.style_fg (State::Focused, Color::TRANSPARENT)
.style_bg (State::Focused, Color::TRANSPARENT)
.style_fg (State::Enabled, Color::TRANSPARENT)
.style_bg (State::Enabled, Color::TRANSPARENT)
.style_fg (State::Disabled, Color::TRANSPARENT)
.style_bg (State::Disabled, Color::TRANSPARENT)
}
#[inline]
pub const fn state (mut self, state : State, appearance : Appearance) -> Self {
self.0[state as usize] = appearance;
self
}
#[inline]
pub const fn style (mut self, state : State, style : Style) -> Self {
self.0[state as usize].style = Some (style);
self
}
#[inline]
pub fn style_default (mut self, state : State) -> Self {
self.0[state as usize].style = Some (Style::default());
self
}
#[inline]
pub const fn sound (mut self, state : State, sound : Sound) -> Self {
self.0[state as usize].sound = Some (sound);
self
}
#[inline]
pub const fn pointer (mut self, state : State, pointer : Pointer) -> Self {
self.0[state as usize].pointer = Some (pointer);
self
}
#[inline]
pub fn style_fg (mut self, state : State, color : Color) -> Self {
let state = state as usize;
let mut style = self.0[state].style.take().unwrap_or_default();
style.fg = color;
self.0[state].style = Some (style);
self
}
#[inline]
pub fn style_bg (mut self, state : State, color : Color) -> Self {
let state = state as usize;
let mut style = self.0[state].style.take().unwrap_or_default();
style.bg = color;
self.0[state].style = Some (style);
self
}
#[inline]
pub fn style_lo (mut self, state : State, color : Color) -> Self {
let state = state as usize;
let mut style = self.0[state].style.take().unwrap_or_default();
style.lo = color;
self.0[state].style = Some (style);
self
}
#[inline]
pub fn style_hi (mut self, state : State, color : Color) -> Self {
let state = state as usize;
let mut style = self.0[state].style.take().unwrap_or_default();
style.hi = color;
self.0[state].style = Some (style);
self
}
#[inline]
pub const fn build (self) -> Appearances {
Appearances (self.0)
}
}
impl Orientation {
pub const fn toggle (self) -> Self {
match self {
Orientation::Horizontal => Orientation::Vertical,
Orientation::Vertical => Orientation::Horizontal
}
}
}