use std::ops::{Deref, DerefMut};
use std::time::Instant;
use log;
use crate::core::{BaseState, CommandQueue, FocusChange};
use crate::piet::Piet;
use crate::piet::RenderContext;
use crate::{
Affine, Command, Cursor, Insets, Rect, Size, Target, Text, TimerToken, WidgetId, WindowHandle,
WindowId,
};
pub struct EventCtx<'a> {
pub(crate) cursor: &'a mut Option<Cursor>,
pub(crate) command_queue: &'a mut CommandQueue,
pub(crate) window_id: WindowId,
pub(crate) window: &'a WindowHandle,
pub(crate) base_state: &'a mut BaseState,
pub(crate) focus_widget: Option<WidgetId>,
pub(crate) had_active: bool,
pub(crate) is_handled: bool,
pub(crate) is_root: bool,
}
pub struct LifeCycleCtx<'a> {
pub(crate) command_queue: &'a mut CommandQueue,
pub(crate) base_state: &'a mut BaseState,
pub(crate) window_id: WindowId,
}
pub struct UpdateCtx<'a> {
pub(crate) window: &'a WindowHandle,
pub(crate) window_id: WindowId,
pub(crate) base_state: &'a mut BaseState,
}
pub struct LayoutCtx<'a, 'b: 'a> {
pub(crate) text_factory: &'a mut Text<'b>,
pub(crate) paint_insets: Insets,
pub(crate) window_id: WindowId,
}
pub(crate) struct ZOrderPaintOp {
pub z_index: u32,
pub paint_func: Box<dyn FnOnce(&mut PaintCtx) + 'static>,
pub transform: Affine,
}
pub struct PaintCtx<'a, 'b: 'a> {
pub render_ctx: &'a mut Piet<'b>,
pub window_id: WindowId,
pub(crate) z_ops: Vec<ZOrderPaintOp>,
pub(crate) region: Region,
pub(crate) base_state: &'a BaseState,
pub(crate) focus_widget: Option<WidgetId>,
}
#[derive(Debug, Clone)]
pub struct Region(Rect);
impl<'a> EventCtx<'a> {
#[deprecated(since = "0.5.0", note = "use request_paint instead")]
pub fn invalidate(&mut self) {
self.base_state.needs_inval = true;
}
pub fn request_paint(&mut self) {
self.base_state.needs_inval = true;
}
pub fn request_layout(&mut self) {
self.base_state.needs_layout = true;
self.base_state.needs_inval = true;
}
pub fn children_changed(&mut self) {
self.base_state.children_changed = true;
}
pub fn text(&mut self) -> Text {
self.window.text()
}
pub fn set_cursor(&mut self, cursor: &Cursor) {
*self.cursor = Some(cursor.clone());
}
pub fn set_active(&mut self, active: bool) {
self.base_state.is_active = active;
}
pub fn is_hot(&self) -> bool {
self.base_state.is_hot
}
pub fn is_active(&self) -> bool {
self.base_state.is_active
}
pub fn window(&self) -> &WindowHandle {
&self.window
}
pub fn set_handled(&mut self) {
self.is_handled = true;
}
pub fn is_handled(&self) -> bool {
self.is_handled
}
pub fn has_focus(&self) -> bool {
let is_child = self
.focus_widget
.map(|id| self.base_state.children.contains(&id))
.unwrap_or(false);
is_child || self.focus_widget == Some(self.widget_id())
}
pub fn is_focused(&self) -> bool {
self.focus_widget == Some(self.widget_id())
}
pub fn request_focus(&mut self) {
self.base_state.request_focus = Some(FocusChange::Focus(self.widget_id()));
}
pub fn focus_next(&mut self) {
if self.focus_widget == Some(self.widget_id()) {
self.base_state.request_focus = Some(FocusChange::Next);
} else {
log::warn!("focus_next can only be called by the currently focused widget");
}
}
pub fn focus_prev(&mut self) {
if self.focus_widget == Some(self.widget_id()) {
self.base_state.request_focus = Some(FocusChange::Previous);
} else {
log::warn!("focus_prev can only be called by the currently focused widget");
}
}
pub fn resign_focus(&mut self) {
if self.focus_widget == Some(self.widget_id()) {
self.base_state.request_focus = Some(FocusChange::Resign);
} else {
log::warn!("resign_focus can only be called by the currently focused widget");
}
}
pub fn request_anim_frame(&mut self) {
self.base_state.request_anim = true;
self.base_state.needs_inval = true;
}
pub fn request_timer(&mut self, deadline: Instant) -> TimerToken {
self.base_state.request_timer = true;
self.window.request_timer(deadline)
}
pub fn size(&self) -> Size {
self.base_state.size()
}
pub fn submit_command(
&mut self,
command: impl Into<Command>,
target: impl Into<Option<Target>>,
) {
let target = target.into().unwrap_or_else(|| self.window_id.into());
self.command_queue.push_back((target, command.into()))
}
pub fn window_id(&self) -> WindowId {
self.window_id
}
pub fn widget_id(&self) -> WidgetId {
self.base_state.id
}
pub(crate) fn make_lifecycle_ctx(&mut self) -> LifeCycleCtx {
LifeCycleCtx {
command_queue: self.command_queue,
base_state: self.base_state,
window_id: self.window_id,
}
}
}
impl<'a> LifeCycleCtx<'a> {
#[deprecated(since = "0.5.0", note = "use request_paint instead")]
pub fn invalidate(&mut self) {
self.base_state.needs_inval = true;
}
pub fn request_paint(&mut self) {
self.base_state.needs_inval = true;
}
pub fn request_layout(&mut self) {
self.base_state.needs_layout = true;
self.base_state.needs_inval = true;
}
pub fn widget_id(&self) -> WidgetId {
self.base_state.id
}
pub fn register_child(&mut self, child_id: WidgetId) {
self.base_state.children.add(&child_id);
}
pub fn register_for_focus(&mut self) {
self.base_state.focus_chain.push(self.widget_id());
}
pub fn children_changed(&mut self) {
self.base_state.children_changed = true;
}
pub fn request_anim_frame(&mut self) {
self.base_state.request_anim = true;
}
pub fn submit_command(
&mut self,
command: impl Into<Command>,
target: impl Into<Option<Target>>,
) {
let target = target.into().unwrap_or_else(|| self.window_id.into());
self.command_queue.push_back((target, command.into()))
}
}
impl<'a> UpdateCtx<'a> {
#[deprecated(since = "0.5.0", note = "use request_paint instead")]
pub fn invalidate(&mut self) {
self.base_state.needs_inval = true;
}
pub fn request_paint(&mut self) {
self.base_state.needs_inval = true;
}
pub fn request_layout(&mut self) {
self.base_state.needs_layout = true;
self.base_state.needs_inval = true;
}
pub fn children_changed(&mut self) {
self.base_state.children_changed = true;
}
pub fn text(&mut self) -> Text {
self.window.text()
}
pub fn window(&self) -> &WindowHandle {
&self.window
}
pub fn window_id(&self) -> WindowId {
self.window_id
}
pub fn widget_id(&self) -> WidgetId {
self.base_state.id
}
}
impl<'a, 'b> LayoutCtx<'a, 'b> {
pub fn text(&mut self) -> &mut Text<'b> {
&mut self.text_factory
}
pub fn window_id(&self) -> WindowId {
self.window_id
}
pub fn set_paint_insets(&mut self, insets: impl Into<Insets>) {
self.paint_insets = insets.into().nonnegative();
}
}
impl<'a, 'b: 'a> PaintCtx<'a, 'b> {
pub fn widget_id(&self) -> WidgetId {
self.base_state.id
}
pub fn is_hot(&self) -> bool {
self.base_state.is_hot
}
pub fn is_active(&self) -> bool {
self.base_state.is_active
}
pub fn size(&self) -> Size {
self.base_state.size()
}
pub fn is_focused(&self) -> bool {
self.focus_widget == Some(self.widget_id())
}
pub fn has_focus(&self) -> bool {
let is_child = self
.focus_widget
.map(|id| self.base_state.children.contains(&id))
.unwrap_or(false);
is_child || self.focus_widget == Some(self.widget_id())
}
#[inline]
pub fn region(&self) -> &Region {
&self.region
}
pub fn with_child_ctx(&mut self, region: impl Into<Region>, f: impl FnOnce(&mut PaintCtx)) {
let mut child_ctx = PaintCtx {
render_ctx: self.render_ctx,
base_state: self.base_state,
z_ops: Vec::new(),
window_id: self.window_id,
focus_widget: self.focus_widget,
region: region.into(),
};
f(&mut child_ctx);
self.z_ops.append(&mut child_ctx.z_ops);
}
pub fn with_save(&mut self, f: impl FnOnce(&mut PaintCtx)) {
if let Err(e) = self.render_ctx.save() {
log::error!("Failed to save RenderContext: '{}'", e);
return;
}
f(self);
if let Err(e) = self.render_ctx.restore() {
log::error!("Failed to restore RenderContext: '{}'", e);
}
}
pub fn paint_with_z_index(
&mut self,
z_index: u32,
paint_func: impl FnOnce(&mut PaintCtx) + 'static,
) {
let current_transform = self.render_ctx.current_transform();
self.z_ops.push(ZOrderPaintOp {
z_index,
paint_func: Box::new(paint_func),
transform: current_transform,
})
}
}
impl Region {
pub fn to_rect(&self) -> Rect {
self.0
}
#[inline]
pub fn intersects(&self, other: Rect) -> bool {
self.0.intersect(other).area() > 0.
}
}
impl From<Rect> for Region {
fn from(src: Rect) -> Region {
Region(src)
}
}
impl<'a, 'b: 'a> Deref for PaintCtx<'a, 'b> {
type Target = Piet<'b>;
fn deref(&self) -> &Self::Target {
self.render_ctx
}
}
impl<'a, 'b: 'a> DerefMut for PaintCtx<'a, 'b> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.render_ctx
}
}