use std::any::Any;
use std::fmt;
use super::Boxed;
use crate::draw::{DrawHandle, InputState, SizeHandle};
use crate::event::{self, ConfigureManager, Manager, ManagerState};
use crate::geom::{Coord, Rect};
use crate::layout::{AxisInfo, SizeRules};
use crate::{AlignHints, CoreData, TkAction, WidgetId};
impl dyn WidgetCore {
#[inline]
pub fn is<T: Any>(&self) -> bool {
Any::is::<T>(self.as_any())
}
#[inline]
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
Any::downcast_ref::<T>(self.as_any())
}
#[inline]
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
Any::downcast_mut::<T>(self.as_any_mut())
}
}
pub trait WidgetCore: Any + fmt::Debug {
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
fn core_data(&self) -> &CoreData;
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
fn core_data_mut(&mut self) -> &mut CoreData;
#[inline]
fn id(&self) -> WidgetId {
self.core_data().id
}
#[inline]
fn is_disabled(&self) -> bool {
self.core_data().disabled
}
#[inline]
fn set_disabled(&mut self, disabled: bool) -> TkAction {
self.core_data_mut().disabled = disabled;
TkAction::Redraw
}
#[inline]
fn rect(&self) -> Rect {
self.core_data().rect
}
fn widget_name(&self) -> &'static str;
fn as_widget(&self) -> &dyn WidgetConfig;
fn as_widget_mut(&mut self) -> &mut dyn WidgetConfig;
fn input_state(&self, mgr: &ManagerState, disabled: bool) -> InputState {
let id = self.core_data().id;
InputState {
disabled: self.core_data().disabled || disabled,
error: false,
hover: mgr.is_hovered(id),
depress: mgr.is_depressed(id),
nav_focus: mgr.nav_focus(id),
char_focus: mgr.char_focus(id),
}
}
}
pub trait WidgetChildren: WidgetCore {
fn len(&self) -> usize;
fn get(&self, index: usize) -> Option<&dyn WidgetConfig>;
fn get_mut(&mut self, index: usize) -> Option<&mut dyn WidgetConfig>;
#[inline]
fn is_ancestor_of(&self, id: WidgetId) -> bool {
self.find(id).is_some()
}
fn find(&self, id: WidgetId) -> Option<&dyn WidgetConfig> {
if id == self.id() {
return Some(self.as_widget());
} else if id > self.id() {
return None;
}
for i in 0..self.len() {
if let Some(w) = self.get(i) {
if id > w.id() {
continue;
}
return w.find(id);
}
break;
}
None
}
fn find_mut(&mut self, id: WidgetId) -> Option<&mut dyn WidgetConfig> {
if id == self.id() {
return Some(self.as_widget_mut());
} else if id > self.id() {
return None;
}
for i in 0..self.len() {
if self.get(i).map(|w| id > w.id()).unwrap_or(true) {
continue;
}
if let Some(w) = self.get_mut(i) {
return w.find_mut(id);
}
break;
}
None
}
fn walk(&self, f: &mut dyn FnMut(&dyn WidgetConfig)) {
for i in 0..self.len() {
if let Some(w) = self.get(i) {
w.walk(f);
}
}
f(self.as_widget());
}
fn walk_mut(&mut self, f: &mut dyn FnMut(&mut dyn WidgetConfig)) {
for i in 0..self.len() {
if let Some(w) = self.get_mut(i) {
w.walk_mut(f);
}
}
f(self.as_widget_mut());
}
}
pub trait WidgetConfig: Layout {
fn configure(&mut self, _: &mut Manager) {}
fn configure_recurse<'a, 'b>(&mut self, mut cmgr: ConfigureManager<'a, 'b>) {
for i in 0..self.len() {
if let Some(w) = self.get_mut(i) {
w.configure_recurse(cmgr.child());
}
}
self.core_data_mut().id = cmgr.next_id(self.id());
self.configure(cmgr.mgr());
}
fn key_nav(&self) -> bool {
false
}
fn cursor_icon(&self) -> event::CursorIcon {
event::CursorIcon::Default
}
}
pub trait Layout: WidgetChildren {
fn size_rules(&mut self, size_handle: &mut dyn SizeHandle, axis: AxisInfo) -> SizeRules;
#[inline]
fn set_rect(&mut self, rect: Rect, _align: AlignHints) {
self.core_data_mut().rect = rect;
}
#[inline]
fn translation(&self, _child_index: usize) -> Coord {
Coord::ZERO
}
fn spatial_range(&self) -> (usize, usize) {
(0, WidgetChildren::len(self).wrapping_sub(1))
}
#[inline]
fn find_id(&self, coord: Coord) -> Option<WidgetId> {
if !self.rect().contains(coord) {
return None;
}
Some(self.id())
}
fn draw(&self, draw_handle: &mut dyn DrawHandle, mgr: &ManagerState, disabled: bool);
}
pub trait Widget: event::SendEvent {}
impl<W: Widget + Sized> Boxed<dyn Widget<Msg = W::Msg>> for W {
fn boxed(self) -> Box<dyn Widget<Msg = W::Msg>> {
Box::new(self)
}
}