Add action button component for rendering the search options

This commit is contained in:
Mikayla 2023-08-17 15:30:40 -07:00
parent f451e3423d
commit 8630557ece
No known key found for this signature in database
11 changed files with 223 additions and 35 deletions

View file

@ -3313,11 +3313,20 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
&mut self,
element_id: usize,
initial: T,
) -> ElementStateHandle<T> {
self.element_state_dynamic(TypeTag::new::<Tag>(), element_id, initial)
}
pub fn element_state_dynamic<T: 'static>(
&mut self,
tag: TypeTag,
element_id: usize,
initial: T,
) -> ElementStateHandle<T> {
let id = ElementStateId {
view_id: self.view_id(),
element_id,
tag: TypeId::of::<Tag>(),
tag,
};
self.element_states
.entry(id)
@ -3331,11 +3340,20 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
) -> ElementStateHandle<T> {
self.element_state::<Tag, T>(element_id, T::default())
}
pub fn default_element_state_dynamic<T: 'static + Default>(
&mut self,
tag: TypeTag,
element_id: usize,
) -> ElementStateHandle<T> {
self.element_state_dynamic::<T>(tag, element_id, T::default())
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct TypeTag {
tag: TypeId,
composed: Option<TypeId>,
#[cfg(debug_assertions)]
tag_type_name: &'static str,
}
@ -3344,6 +3362,7 @@ impl TypeTag {
pub fn new<Tag: 'static>() -> Self {
Self {
tag: TypeId::of::<Tag>(),
composed: None,
#[cfg(debug_assertions)]
tag_type_name: std::any::type_name::<Tag>(),
}
@ -3352,11 +3371,17 @@ impl TypeTag {
pub fn dynamic(tag: TypeId, #[cfg(debug_assertions)] type_name: &'static str) -> Self {
Self {
tag,
composed: None,
#[cfg(debug_assertions)]
tag_type_name: type_name,
}
}
pub fn compose(mut self, other: TypeTag) -> Self {
self.composed = Some(other.tag);
self
}
#[cfg(debug_assertions)]
pub(crate) fn type_name(&self) -> &'static str {
self.tag_type_name
@ -4751,7 +4776,7 @@ impl Hash for AnyWeakViewHandle {
pub struct ElementStateId {
view_id: usize,
element_id: usize,
tag: TypeId,
tag: TypeTag,
}
pub struct ElementStateHandle<T> {

View file

@ -1,10 +1,13 @@
use std::any::{Any, TypeId};
use crate::TypeTag;
pub trait Action: 'static {
fn id(&self) -> TypeId;
fn namespace(&self) -> &'static str;
fn name(&self) -> &'static str;
fn as_any(&self) -> &dyn Any;
fn type_tag(&self) -> TypeTag;
fn boxed_clone(&self) -> Box<dyn Action>;
fn eq(&self, other: &dyn Action) -> bool;
@ -107,6 +110,10 @@ macro_rules! __impl_action {
}
}
fn type_tag(&self) -> $crate::TypeTag {
$crate::TypeTag::new::<Self>()
}
$from_json_fn
}
};

View file

@ -34,8 +34,8 @@ use crate::{
rect::RectF,
vector::{vec2f, Vector2F},
},
json, Action, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View, ViewContext,
WeakViewHandle, WindowContext,
json, Action, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, TypeTag, View,
ViewContext, WeakViewHandle, WindowContext,
};
use anyhow::{anyhow, Result};
use collections::HashMap;
@ -172,6 +172,20 @@ pub trait Element<V: View>: 'static {
FlexItem::new(self.into_any()).float()
}
fn with_dynamic_tooltip(
self,
tag: TypeTag,
id: usize,
text: impl Into<Cow<'static, str>>,
action: Option<Box<dyn Action>>,
style: TooltipStyle,
cx: &mut ViewContext<V>,
) -> Tooltip<V>
where
Self: 'static + Sized,
{
Tooltip::new_dynamic(tag, id, text, action, style, self.into_any(), cx)
}
fn with_tooltip<Tag: 'static>(
self,
id: usize,

View file

@ -7,6 +7,34 @@ use crate::{
ViewContext,
};
use super::Empty;
pub trait GeneralComponent {
fn render<V: View>(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V>;
}
pub trait StyleableComponent {
type Style: Clone;
type Output: GeneralComponent;
fn with_style(self, style: Self::Style) -> Self::Output;
}
impl GeneralComponent for () {
fn render<V: View>(self, _: &mut V, _: &mut ViewContext<V>) -> AnyElement<V> {
Empty::new().into_any()
}
}
impl StyleableComponent for () {
type Style = ();
type Output = ();
fn with_style(self, _: Self::Style) -> Self::Output {
()
}
}
pub trait Component<V: View> {
fn render(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V>;
@ -18,6 +46,12 @@ pub trait Component<V: View> {
}
}
impl<V: View, C: GeneralComponent> Component<V> for C {
fn render(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V> {
self.render(v, cx)
}
}
pub struct ComponentAdapter<V, E> {
component: Option<E>,
phantom: PhantomData<V>,

View file

@ -7,7 +7,7 @@ use crate::{
geometry::{rect::RectF, vector::Vector2F},
json::json,
Action, Axis, ElementStateHandle, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
Task, View, ViewContext,
Task, TypeTag, View, ViewContext,
};
use schemars::JsonSchema;
use serde::Deserialize;
@ -61,11 +61,23 @@ impl<V: View> Tooltip<V> {
child: AnyElement<V>,
cx: &mut ViewContext<V>,
) -> Self {
struct ElementState<Tag>(Tag);
struct MouseEventHandlerState<Tag>(Tag);
Self::new_dynamic(TypeTag::new::<Tag>(), id, text, action, style, child, cx)
}
pub fn new_dynamic(
mut tag: TypeTag,
id: usize,
text: impl Into<Cow<'static, str>>,
action: Option<Box<dyn Action>>,
style: TooltipStyle,
child: AnyElement<V>,
cx: &mut ViewContext<V>,
) -> Self {
tag = tag.compose(TypeTag::new::<Self>());
let focused_view_id = cx.focused_view_id();
let state_handle = cx.default_element_state::<ElementState<Tag>, Rc<TooltipState>>(id);
let state_handle = cx.default_element_state_dynamic::<Rc<TooltipState>>(tag, id);
let state = state_handle.read(cx).clone();
let text = text.into();
@ -95,7 +107,7 @@ impl<V: View> Tooltip<V> {
} else {
None
};
let child = MouseEventHandler::new::<MouseEventHandlerState<Tag>, _>(id, cx, |_, _| child)
let child = MouseEventHandler::new_dynamic(tag, id, cx, |_, _| child)
.on_hover(move |e, _, cx| {
let position = e.position;
if e.started {