1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License in the LICENSE-APACHE file or at:
// https://www.apache.org/licenses/LICENSE-2.0
//! Configuration context
use super::Pending;
use crate::draw::DrawShared;
use crate::event::EventState;
use crate::geom::{Rect, Size};
use crate::layout::AlignPair;
use crate::shell::Platform;
use crate::text::TextApi;
use crate::theme::{Feature, SizeCx, TextClass, ThemeSize};
use crate::{Action, Node, WidgetId};
use std::ops::{Deref, DerefMut};
#[allow(unused)] use crate::{event::Event, Events, Layout};
/// Widget configuration and update context
///
/// This type supports easy access to [`EventState`] (via [`Deref`],
/// [`DerefMut`] and [`Self::ev_state`]) as well as [`SizeCx`]
/// ([`Self::size_cx`]) and [`DrawShared`] ([`Self::draw_shared`]).
#[must_use]
pub struct ConfigCx<'a> {
sh: &'a dyn ThemeSize,
ds: &'a mut dyn DrawShared,
pub(crate) ev: &'a mut EventState,
}
impl<'a> ConfigCx<'a> {
/// Construct
#[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 {
ConfigCx { sh, ds, ev }
}
/// Get the platform
pub fn platform(&self) -> Platform {
self.ds.platform()
}
/// Access a [`SizeCx`]
#[inline]
pub fn size_cx(&self) -> SizeCx<'a> {
SizeCx::new(self.sh)
}
/// Access [`DrawShared`]
#[inline]
pub fn draw_shared(&mut self) -> &mut dyn DrawShared {
self.ds
}
/// Access [`EventState`]
#[inline]
pub fn ev_state(&mut self) -> &mut EventState {
self.ev
}
/// Disable or enable navigation focus
///
/// When nav focus is disabled, [`EventState::nav_focus`] always returns
/// `None`. Any existing focus is immediately cleared. Both
/// [`EventState::set_nav_focus`] and [`EventState::next_nav_focus`] will fail to
/// do anything. Input such as the <kbd>Tab</kbd> key and mouse click
/// will not set navigation focus.
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::Send(id, Event::LostNavFocus));
}
}
}
/// Configure a widget
///
/// All widgets must be configured after construction (see
/// [widget lifecycle](Layout#widget-lifecycle)).
/// This method performs complete configuration of the widget by calling
/// [`Events::configure`], [`Events::update`], [`Events::configure_recurse`].
///
/// Pass the `id` to assign to the widget. This is usually constructed with
/// [`Events::make_child_id`].
#[inline]
pub fn configure(&mut self, mut widget: Node<'_>, id: WidgetId) {
widget._configure(self, id);
}
/// Update a widget
///
/// All widgets must be updated after input data changes.
/// This method recursively updates the widget by calling
/// [`Events::update`] and [`Events::update_recurse`].
#[inline]
pub fn update(&mut self, mut widget: Node<'_>) {
widget._update(self);
}
/// Align a feature's rect
///
/// In case the input `rect` is larger than desired on either axis, it is
/// reduced in size and offset within the original `rect` as is preferred.
#[inline]
pub fn align_feature(&self, feature: Feature, rect: Rect, align: AlignPair) -> Rect {
self.sh.align_feature(feature, rect, align)
}
/// Prepare a text object
///
/// This sets the text's font, font size, wrapping and optionally alignment,
/// then performs the text preparation necessary before display.
///
/// Note: setting alignment here is not necessary when the default alignment
/// is desired or when [`SizeCx::text_rules`] is used.
#[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)
}
}
impl<'a> std::ops::BitOrAssign<Action> for ConfigCx<'a> {
#[inline]
fn bitor_assign(&mut self, action: Action) {
self.ev.send_action(action);
}
}
impl<'a> Deref for ConfigCx<'a> {
type Target = EventState;
fn deref(&self) -> &EventState {
self.ev
}
}
impl<'a> DerefMut for ConfigCx<'a> {
fn deref_mut(&mut self) -> &mut EventState {
self.ev
}
}