use super::Pending;
use crate::draw::DrawShared;
use crate::event::EventState;
use crate::geom::{Rect, Size};
use crate::layout::AlignPair;
use crate::text::TextApi;
use crate::theme::{Feature, SizeMgr, TextClass, ThemeSize};
use crate::{TkAction, Widget, WidgetExt, WidgetId};
use std::ops::{Deref, DerefMut};
#[allow(unused)] use crate::{event::Event, Layout};
#[must_use]
pub struct ConfigMgr<'a> {
sh: &'a dyn ThemeSize,
ds: &'a mut dyn DrawShared,
pub(crate) ev: &'a mut EventState,
}
impl<'a> ConfigMgr<'a> {
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(doc_cfg, doc(cfg(internal_doc)))]
pub fn new(sh: &'a dyn ThemeSize, ds: &'a mut dyn DrawShared, ev: &'a mut EventState) -> Self {
ConfigMgr { sh, ds, ev }
}
#[inline]
pub fn size_mgr(&self) -> SizeMgr<'a> {
SizeMgr::new(self.sh)
}
#[inline]
pub fn draw_shared(&mut self) -> &mut dyn DrawShared {
self.ds
}
#[inline]
pub fn ev_state(&mut self) -> &mut EventState {
self.ev
}
pub fn disable_nav_focus(&mut self, disabled: bool) {
self.ev.config.nav_focus = !disabled;
if disabled {
if let Some(id) = self.ev.nav_focus.take() {
self.pending.push_back(Pending::LostNavFocus(id));
}
}
}
pub fn configure(&mut self, id: WidgetId, widget: &mut dyn Widget) {
widget.pre_configure(self, id);
for index in 0..widget.num_children() {
let id = widget.make_child_id(index);
if let Some(widget) = widget.get_child_mut(index) {
self.configure(id, widget);
}
}
widget.configure(self);
}
#[inline]
pub fn align_feature(&self, feature: Feature, rect: Rect, align: AlignPair) -> Rect {
self.sh.align_feature(feature, rect, align)
}
#[inline]
pub fn text_set_size(
&self,
text: &mut dyn TextApi,
class: TextClass,
size: Size,
align: Option<AlignPair>,
) {
self.sh.text_set_size(text, class, size, align)
}
pub fn next_nav_focus(
&mut self,
mut widget: &mut dyn Widget,
reverse: bool,
key_focus: bool,
) -> bool {
if !self.config.nav_focus {
return false;
}
if let Some(id) = self.popups.last().map(|(_, p, _)| p.id.clone()) {
if id.is_ancestor_of(widget.id_ref()) {
} else if let Some(w) = widget.find_widget_mut(&id) {
widget = w;
} else {
log::warn!(
target: "kas_core::event::config_mgr",
"next_nav_focus: have open pop-up which is not a child of widget",
);
return false;
}
}
self.send_action(TkAction::REDRAW);
let old_nav_focus = self.nav_focus.take();
fn nav(
mgr: &mut ConfigMgr,
widget: &mut dyn Widget,
focus: Option<&WidgetId>,
rev: bool,
) -> Option<WidgetId> {
if mgr.ev_state().is_disabled(widget.id_ref()) {
return None;
}
let mut child = focus.and_then(|id| widget.find_child_index(id));
if !rev {
if let Some(index) = child {
if let Some(id) = widget
.get_child_mut(index)
.and_then(|w| nav(mgr, w, focus, rev))
{
return Some(id);
}
} else if !widget.eq_id(focus) && widget.navigable() {
return Some(widget.id());
}
loop {
if let Some(index) = widget.nav_next(mgr, rev, child) {
if let Some(id) = widget
.get_child_mut(index)
.and_then(|w| nav(mgr, w, focus, rev))
{
return Some(id);
}
child = Some(index);
} else {
return None;
}
}
} else {
if let Some(index) = child {
if let Some(id) = widget
.get_child_mut(index)
.and_then(|w| nav(mgr, w, focus, rev))
{
return Some(id);
}
}
loop {
if let Some(index) = widget.nav_next(mgr, rev, child) {
if let Some(id) = widget
.get_child_mut(index)
.and_then(|w| nav(mgr, w, focus, rev))
{
return Some(id);
}
child = Some(index);
} else {
return if !widget.eq_id(focus) && widget.navigable() {
Some(widget.id())
} else {
None
};
}
}
}
}
let restart = old_nav_focus.is_some();
let mut opt_id = nav(self, widget, old_nav_focus.as_ref(), reverse);
if restart && opt_id.is_none() {
opt_id = nav(self, widget, None, reverse);
}
log::trace!(
target: "kas_core::event::config_mgr",
"next_nav_focus: nav_focus={opt_id:?}",
);
self.nav_focus = opt_id.clone();
if opt_id == old_nav_focus {
return opt_id.is_some();
}
if let Some(id) = old_nav_focus {
self.pending.push_back(Pending::LostNavFocus(id));
}
if let Some(id) = opt_id {
if id != self.sel_focus {
self.clear_char_focus();
}
self.pending.push_back(Pending::SetNavFocus(id, key_focus));
true
} else {
self.clear_char_focus();
false
}
}
#[inline]
pub fn next_nav_focus_from(
&mut self,
widget: &mut dyn Widget,
id: WidgetId,
key_focus: bool,
) -> bool {
if id == self.nav_focus {
return true;
} else if !self.config.nav_focus {
return false;
}
self.send_action(TkAction::REDRAW);
if let Some(old_id) = self.nav_focus.take() {
self.pending.push_back(Pending::LostNavFocus(old_id));
}
self.clear_char_focus();
if widget
.find_widget(&id)
.map(|w| w.navigable())
.unwrap_or(false)
{
log::trace!(target: "kas_core::event::manager", "set_nav_focus: {id}");
self.nav_focus = Some(id.clone());
self.pending.push_back(Pending::SetNavFocus(id, key_focus));
true
} else {
self.nav_focus = Some(id);
self.next_nav_focus(widget, false, key_focus)
}
}
}
impl<'a> std::ops::BitOrAssign<TkAction> for ConfigMgr<'a> {
#[inline]
fn bitor_assign(&mut self, action: TkAction) {
self.ev.send_action(action);
}
}
impl<'a> Deref for ConfigMgr<'a> {
type Target = EventState;
fn deref(&self) -> &EventState {
self.ev
}
}
impl<'a> DerefMut for ConfigMgr<'a> {
fn deref_mut(&mut self) -> &mut EventState {
self.ev
}
}