use crate::action::ActionEnvelope;
use crate::internal::InternalLowerer;
use crate::ui::node::InternalRenderNode;
use crate::ui::Widget;
use fission_ir::op::PaintOp;
use fission_ir::{AnyRenderObject, WidgetId};
use fission_layout::{LayoutPoint, LayoutRect};
use std::fmt::Debug;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct CustomHitResult {
pub hit: bool,
pub byte_offset: Option<usize>,
}
impl CustomHitResult {
pub fn inside(byte_offset: Option<usize>) -> Self {
Self {
hit: true,
byte_offset,
}
}
pub fn miss() -> Self {
Self {
hit: false,
byte_offset: None,
}
}
}
#[derive(Debug, Clone)]
pub struct CustomEventResult {
pub handled: bool,
pub actions: Vec<(WidgetId, ActionEnvelope)>,
}
impl CustomEventResult {
pub fn ignored() -> Self {
Self {
handled: false,
actions: Vec::new(),
}
}
pub fn consumed() -> Self {
Self {
handled: true,
actions: Vec::new(),
}
}
pub fn consumed_with(actions: Vec<(WidgetId, ActionEnvelope)>) -> Self {
Self {
handled: true,
actions,
}
}
}
pub trait CustomRenderObject: Send + Sync + Debug {
fn is_runtime_dynamic(&self) -> bool {
false
}
fn accepts_text_input(&self) -> bool {
false
}
fn hit_test(&self, local_point: LayoutPoint, node_rect: LayoutRect) -> CustomHitResult {
let _ = local_point;
let _ = node_rect;
CustomHitResult::inside(None)
}
fn handle_event(
&self,
node_id: WidgetId,
event: &crate::event::InputEvent,
node_rect: LayoutRect,
) -> CustomEventResult {
let _ = (node_id, event, node_rect);
CustomEventResult::ignored()
}
fn ime_cursor_area(&self, _node_rect: LayoutRect) -> Option<LayoutRect> {
None
}
fn blur_actions(&self, _node_id: WidgetId) -> Vec<(WidgetId, ActionEnvelope)> {
Vec::new()
}
fn paint(&self, node_rect: LayoutRect) -> Vec<PaintOp> {
let _ = node_rect;
Vec::new()
}
}
#[derive(Debug, Clone)]
pub struct RenderObjectHolder(pub Arc<dyn CustomRenderObject>);
pub fn downcast_render_object(any: &AnyRenderObject) -> Option<&Arc<dyn CustomRenderObject>> {
any.downcast_ref::<RenderObjectHolder>()
.map(|holder| &holder.0)
}
#[derive(Clone)]
pub struct CustomRender {
debug_tag: String,
lowerer: Arc<dyn InternalLowerer>,
render_object: Option<Arc<dyn CustomRenderObject>>,
}
impl CustomRender {
pub fn new(debug_tag: impl Into<String>, lowerer: Arc<dyn InternalLowerer>) -> Self {
Self {
debug_tag: debug_tag.into(),
lowerer,
render_object: None,
}
}
pub fn with_render_object(mut self, render_object: Arc<dyn CustomRenderObject>) -> Self {
self.render_object = Some(render_object);
self
}
}
impl From<CustomRender> for Widget {
fn from(widget: CustomRender) -> Self {
Widget::custom(InternalRenderNode {
debug_tag: widget.debug_tag,
lowerer: Some(widget.lowerer),
render_object: widget.render_object,
})
}
}