mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-19 10:29:35 +03:00
wip: picker
co-authored-by: nathan <nathan@zed.dev> co-authored-by: max <max@zed.dev>
This commit is contained in:
parent
3c93b585ab
commit
85000eba81
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -4970,7 +4970,8 @@ dependencies = [
|
|||||||
name = "menu2"
|
name = "menu2"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gpui2",
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -8542,6 +8543,7 @@ dependencies = [
|
|||||||
"gpui2",
|
"gpui2",
|
||||||
"itertools 0.11.0",
|
"itertools 0.11.0",
|
||||||
"log",
|
"log",
|
||||||
|
"menu2",
|
||||||
"picker2",
|
"picker2",
|
||||||
"rust-embed",
|
"rust-embed",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -194,6 +194,15 @@ pub fn red() -> Hsla {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn blue() -> Hsla {
|
||||||
|
Hsla {
|
||||||
|
h: 0.6,
|
||||||
|
s: 1.,
|
||||||
|
l: 0.5,
|
||||||
|
a: 1.,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Hsla {
|
impl Hsla {
|
||||||
/// Returns true if the HSLA color is fully transparent, false otherwise.
|
/// Returns true if the HSLA color is fully transparent, false otherwise.
|
||||||
pub fn is_transparent(&self) -> bool {
|
pub fn is_transparent(&self) -> bool {
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
point, AnyElement, BorrowWindow, Bounds, Component, Element, ElementFocus, ElementId,
|
point, AnyElement, BorrowWindow, Bounds, Component, Element, ElementFocus, ElementId,
|
||||||
ElementInteraction, FocusDisabled, FocusEnabled, FocusHandle, FocusListeners, Focusable,
|
ElementInteractivity, FocusDisabled, FocusEnabled, FocusHandle, FocusListeners, Focusable,
|
||||||
GlobalElementId, GroupBounds, InteractiveElementState, LayoutId, Overflow, ParentElement,
|
GlobalElementId, GroupBounds, InteractiveElementState, LayoutId, Overflow, ParentElement,
|
||||||
Pixels, Point, SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction,
|
Pixels, Point, SharedString, StatefulInteractive, StatefulInteractivity, StatelessInteractive,
|
||||||
StatelessInteractive, Style, StyleRefinement, Styled, ViewContext, Visibility,
|
StatelessInteractivity, Style, StyleRefinement, Styled, ViewContext, Visibility,
|
||||||
};
|
};
|
||||||
use refineable::Refineable;
|
use refineable::Refineable;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
pub struct Div<
|
pub struct Div<
|
||||||
V: 'static,
|
V: 'static,
|
||||||
I: ElementInteraction<V> = StatelessInteraction<V>,
|
I: ElementInteractivity<V> = StatelessInteractivity<V>,
|
||||||
F: ElementFocus<V> = FocusDisabled,
|
F: ElementFocus<V> = FocusDisabled,
|
||||||
> {
|
> {
|
||||||
interaction: I,
|
interactivity: I,
|
||||||
focus: F,
|
focus: F,
|
||||||
children: SmallVec<[AnyElement<V>; 2]>,
|
children: SmallVec<[AnyElement<V>; 2]>,
|
||||||
group: Option<SharedString>,
|
group: Option<SharedString>,
|
||||||
base_style: StyleRefinement,
|
base_style: StyleRefinement,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn div<V: 'static>() -> Div<V, StatelessInteraction<V>, FocusDisabled> {
|
pub fn div<V: 'static>() -> Div<V, StatelessInteractivity<V>, FocusDisabled> {
|
||||||
Div {
|
Div {
|
||||||
interaction: StatelessInteraction::default(),
|
interactivity: StatelessInteractivity::default(),
|
||||||
focus: FocusDisabled,
|
focus: FocusDisabled,
|
||||||
children: SmallVec::new(),
|
children: SmallVec::new(),
|
||||||
group: None,
|
group: None,
|
||||||
@ -30,14 +30,14 @@ pub fn div<V: 'static>() -> Div<V, StatelessInteraction<V>, FocusDisabled> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> Div<V, StatelessInteraction<V>, F>
|
impl<V, F> Div<V, StatelessInteractivity<V>, F>
|
||||||
where
|
where
|
||||||
V: 'static,
|
V: 'static,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
pub fn id(self, id: impl Into<ElementId>) -> Div<V, StatefulInteraction<V>, F> {
|
pub fn id(self, id: impl Into<ElementId>) -> Div<V, StatefulInteractivity<V>, F> {
|
||||||
Div {
|
Div {
|
||||||
interaction: id.into().into(),
|
interactivity: id.into().into(),
|
||||||
focus: self.focus,
|
focus: self.focus,
|
||||||
children: self.children,
|
children: self.children,
|
||||||
group: self.group,
|
group: self.group,
|
||||||
@ -48,7 +48,7 @@ where
|
|||||||
|
|
||||||
impl<V, I, F> Div<V, I, F>
|
impl<V, I, F> Div<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
pub fn group(mut self, group: impl Into<SharedString>) -> Self {
|
pub fn group(mut self, group: impl Into<SharedString>) -> Self {
|
||||||
@ -98,16 +98,20 @@ where
|
|||||||
let mut computed_style = Style::default();
|
let mut computed_style = Style::default();
|
||||||
computed_style.refine(&self.base_style);
|
computed_style.refine(&self.base_style);
|
||||||
self.focus.refine_style(&mut computed_style, cx);
|
self.focus.refine_style(&mut computed_style, cx);
|
||||||
self.interaction
|
self.interactivity.refine_style(
|
||||||
.refine_style(&mut computed_style, bounds, &element_state.interactive, cx);
|
&mut computed_style,
|
||||||
|
bounds,
|
||||||
|
&element_state.interactive,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
computed_style
|
computed_style
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static> Div<V, StatefulInteraction<V>, FocusDisabled> {
|
impl<V: 'static> Div<V, StatefulInteractivity<V>, FocusDisabled> {
|
||||||
pub fn focusable(self) -> Div<V, StatefulInteraction<V>, FocusEnabled<V>> {
|
pub fn focusable(self) -> Div<V, StatefulInteractivity<V>, FocusEnabled<V>> {
|
||||||
Div {
|
Div {
|
||||||
interaction: self.interaction,
|
interactivity: self.interactivity,
|
||||||
focus: FocusEnabled::new(),
|
focus: FocusEnabled::new(),
|
||||||
children: self.children,
|
children: self.children,
|
||||||
group: self.group,
|
group: self.group,
|
||||||
@ -118,9 +122,9 @@ impl<V: 'static> Div<V, StatefulInteraction<V>, FocusDisabled> {
|
|||||||
pub fn track_focus(
|
pub fn track_focus(
|
||||||
self,
|
self,
|
||||||
handle: &FocusHandle,
|
handle: &FocusHandle,
|
||||||
) -> Div<V, StatefulInteraction<V>, FocusEnabled<V>> {
|
) -> Div<V, StatefulInteractivity<V>, FocusEnabled<V>> {
|
||||||
Div {
|
Div {
|
||||||
interaction: self.interaction,
|
interactivity: self.interactivity,
|
||||||
focus: FocusEnabled::tracked(handle),
|
focus: FocusEnabled::tracked(handle),
|
||||||
children: self.children,
|
children: self.children,
|
||||||
group: self.group,
|
group: self.group,
|
||||||
@ -145,13 +149,13 @@ impl<V: 'static> Div<V, StatefulInteraction<V>, FocusDisabled> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static> Div<V, StatelessInteraction<V>, FocusDisabled> {
|
impl<V: 'static> Div<V, StatelessInteractivity<V>, FocusDisabled> {
|
||||||
pub fn track_focus(
|
pub fn track_focus(
|
||||||
self,
|
self,
|
||||||
handle: &FocusHandle,
|
handle: &FocusHandle,
|
||||||
) -> Div<V, StatefulInteraction<V>, FocusEnabled<V>> {
|
) -> Div<V, StatefulInteractivity<V>, FocusEnabled<V>> {
|
||||||
Div {
|
Div {
|
||||||
interaction: self.interaction.into_stateful(handle),
|
interactivity: self.interactivity.into_stateful(handle),
|
||||||
focus: handle.clone().into(),
|
focus: handle.clone().into(),
|
||||||
children: self.children,
|
children: self.children,
|
||||||
group: self.group,
|
group: self.group,
|
||||||
@ -163,7 +167,7 @@ impl<V: 'static> Div<V, StatelessInteraction<V>, FocusDisabled> {
|
|||||||
impl<V, I> Focusable<V> for Div<V, I, FocusEnabled<V>>
|
impl<V, I> Focusable<V> for Div<V, I, FocusEnabled<V>>
|
||||||
where
|
where
|
||||||
V: 'static,
|
V: 'static,
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
{
|
{
|
||||||
fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
|
fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
|
||||||
&mut self.focus.focus_listeners
|
&mut self.focus.focus_listeners
|
||||||
@ -191,13 +195,13 @@ pub struct DivState {
|
|||||||
|
|
||||||
impl<V, I, F> Element<V> for Div<V, I, F>
|
impl<V, I, F> Element<V> for Div<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
type ElementState = DivState;
|
type ElementState = DivState;
|
||||||
|
|
||||||
fn id(&self) -> Option<ElementId> {
|
fn id(&self) -> Option<ElementId> {
|
||||||
self.interaction
|
self.interactivity
|
||||||
.as_stateful()
|
.as_stateful()
|
||||||
.map(|identified| identified.id.clone())
|
.map(|identified| identified.id.clone())
|
||||||
}
|
}
|
||||||
@ -212,7 +216,7 @@ where
|
|||||||
self.focus
|
self.focus
|
||||||
.initialize(element_state.focus_handle.take(), cx, |focus_handle, cx| {
|
.initialize(element_state.focus_handle.take(), cx, |focus_handle, cx| {
|
||||||
element_state.focus_handle = focus_handle;
|
element_state.focus_handle = focus_handle;
|
||||||
self.interaction.initialize(cx, |cx| {
|
self.interactivity.initialize(cx, |cx| {
|
||||||
for child in &mut self.children {
|
for child in &mut self.children {
|
||||||
child.initialize(view_state, cx);
|
child.initialize(view_state, cx);
|
||||||
}
|
}
|
||||||
@ -281,11 +285,11 @@ where
|
|||||||
(child_max - child_min).into()
|
(child_max - child_min).into()
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.stack(z_index, |cx| {
|
cx.with_z_index(z_index, |cx| {
|
||||||
cx.stack(0, |cx| {
|
cx.with_z_index(0, |cx| {
|
||||||
style.paint(bounds, cx);
|
style.paint(bounds, cx);
|
||||||
this.focus.paint(bounds, cx);
|
this.focus.paint(bounds, cx);
|
||||||
this.interaction.paint(
|
this.interactivity.paint(
|
||||||
bounds,
|
bounds,
|
||||||
content_size,
|
content_size,
|
||||||
style.overflow,
|
style.overflow,
|
||||||
@ -293,7 +297,7 @@ where
|
|||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
cx.stack(1, |cx| {
|
cx.with_z_index(1, |cx| {
|
||||||
style.apply_text_style(cx, |cx| {
|
style.apply_text_style(cx, |cx| {
|
||||||
style.apply_overflow(bounds, cx, |cx| {
|
style.apply_overflow(bounds, cx, |cx| {
|
||||||
let scroll_offset = element_state.interactive.scroll_offset();
|
let scroll_offset = element_state.interactive.scroll_offset();
|
||||||
@ -316,7 +320,7 @@ where
|
|||||||
|
|
||||||
impl<V, I, F> Component<V> for Div<V, I, F>
|
impl<V, I, F> Component<V> for Div<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
fn render(self) -> AnyElement<V> {
|
fn render(self) -> AnyElement<V> {
|
||||||
@ -326,7 +330,7 @@ where
|
|||||||
|
|
||||||
impl<V, I, F> ParentElement<V> for Div<V, I, F>
|
impl<V, I, F> ParentElement<V> for Div<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
||||||
@ -336,7 +340,7 @@ where
|
|||||||
|
|
||||||
impl<V, I, F> Styled for Div<V, I, F>
|
impl<V, I, F> Styled for Div<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
fn style(&mut self) -> &mut StyleRefinement {
|
fn style(&mut self) -> &mut StyleRefinement {
|
||||||
@ -346,19 +350,19 @@ where
|
|||||||
|
|
||||||
impl<V, I, F> StatelessInteractive<V> for Div<V, I, F>
|
impl<V, I, F> StatelessInteractive<V> for Div<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
fn stateless_interaction(&mut self) -> &mut StatelessInteraction<V> {
|
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
|
||||||
self.interaction.as_stateless_mut()
|
self.interactivity.as_stateless_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> StatefulInteractive<V> for Div<V, StatefulInteraction<V>, F>
|
impl<V, F> StatefulInteractive<V> for Div<V, StatefulInteractivity<V>, F>
|
||||||
where
|
where
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
fn stateful_interaction(&mut self) -> &mut StatefulInteraction<V> {
|
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<V> {
|
||||||
&mut self.interaction
|
&mut self.interactivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
div, AnyElement, BorrowWindow, Bounds, Component, Div, DivState, Element, ElementFocus,
|
div, AnyElement, BorrowWindow, Bounds, Component, Div, DivState, Element, ElementFocus,
|
||||||
ElementId, ElementInteraction, FocusDisabled, FocusEnabled, FocusListeners, Focusable,
|
ElementId, ElementInteractivity, FocusDisabled, FocusEnabled, FocusListeners, Focusable,
|
||||||
LayoutId, Pixels, SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction,
|
LayoutId, Pixels, SharedString, StatefulInteractive, StatefulInteractivity,
|
||||||
StatelessInteractive, StyleRefinement, Styled, ViewContext,
|
StatelessInteractive, StatelessInteractivity, StyleRefinement, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
|
||||||
pub struct Img<
|
pub struct Img<
|
||||||
V: 'static,
|
V: 'static,
|
||||||
I: ElementInteraction<V> = StatelessInteraction<V>,
|
I: ElementInteractivity<V> = StatelessInteractivity<V>,
|
||||||
F: ElementFocus<V> = FocusDisabled,
|
F: ElementFocus<V> = FocusDisabled,
|
||||||
> {
|
> {
|
||||||
base: Div<V, I, F>,
|
base: Div<V, I, F>,
|
||||||
@ -19,7 +17,7 @@ pub struct Img<
|
|||||||
grayscale: bool,
|
grayscale: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn img<V: 'static>() -> Img<V, StatelessInteraction<V>, FocusDisabled> {
|
pub fn img<V: 'static>() -> Img<V, StatelessInteractivity<V>, FocusDisabled> {
|
||||||
Img {
|
Img {
|
||||||
base: div(),
|
base: div(),
|
||||||
uri: None,
|
uri: None,
|
||||||
@ -30,7 +28,7 @@ pub fn img<V: 'static>() -> Img<V, StatelessInteraction<V>, FocusDisabled> {
|
|||||||
impl<V, I, F> Img<V, I, F>
|
impl<V, I, F> Img<V, I, F>
|
||||||
where
|
where
|
||||||
V: 'static,
|
V: 'static,
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
|
pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
|
||||||
@ -44,11 +42,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> Img<V, StatelessInteraction<V>, F>
|
impl<V, F> Img<V, StatelessInteractivity<V>, F>
|
||||||
where
|
where
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
pub fn id(self, id: impl Into<ElementId>) -> Img<V, StatefulInteraction<V>, F> {
|
pub fn id(self, id: impl Into<ElementId>) -> Img<V, StatefulInteractivity<V>, F> {
|
||||||
Img {
|
Img {
|
||||||
base: self.base.id(id),
|
base: self.base.id(id),
|
||||||
uri: self.uri,
|
uri: self.uri,
|
||||||
@ -59,7 +57,7 @@ where
|
|||||||
|
|
||||||
impl<V, I, F> Component<V> for Img<V, I, F>
|
impl<V, I, F> Component<V> for Img<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
fn render(self) -> AnyElement<V> {
|
fn render(self) -> AnyElement<V> {
|
||||||
@ -69,7 +67,7 @@ where
|
|||||||
|
|
||||||
impl<V, I, F> Element<V> for Img<V, I, F>
|
impl<V, I, F> Element<V> for Img<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
type ElementState = DivState;
|
type ElementState = DivState;
|
||||||
@ -103,7 +101,7 @@ where
|
|||||||
element_state: &mut Self::ElementState,
|
element_state: &mut Self::ElementState,
|
||||||
cx: &mut ViewContext<V>,
|
cx: &mut ViewContext<V>,
|
||||||
) {
|
) {
|
||||||
cx.stack(0, |cx| {
|
cx.with_z_index(0, |cx| {
|
||||||
self.base.paint(bounds, view, element_state, cx);
|
self.base.paint(bounds, view, element_state, cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -120,7 +118,7 @@ where
|
|||||||
.and_then(ResultExt::log_err)
|
.and_then(ResultExt::log_err)
|
||||||
{
|
{
|
||||||
let corner_radii = corner_radii.to_pixels(bounds.size, cx.rem_size());
|
let corner_radii = corner_radii.to_pixels(bounds.size, cx.rem_size());
|
||||||
cx.stack(1, |cx| {
|
cx.with_z_index(1, |cx| {
|
||||||
cx.paint_image(bounds, corner_radii, data, self.grayscale)
|
cx.paint_image(bounds, corner_radii, data, self.grayscale)
|
||||||
.log_err()
|
.log_err()
|
||||||
});
|
});
|
||||||
@ -138,7 +136,7 @@ where
|
|||||||
|
|
||||||
impl<V, I, F> Styled for Img<V, I, F>
|
impl<V, I, F> Styled for Img<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
fn style(&mut self) -> &mut StyleRefinement {
|
fn style(&mut self) -> &mut StyleRefinement {
|
||||||
@ -148,27 +146,27 @@ where
|
|||||||
|
|
||||||
impl<V, I, F> StatelessInteractive<V> for Img<V, I, F>
|
impl<V, I, F> StatelessInteractive<V> for Img<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
fn stateless_interaction(&mut self) -> &mut StatelessInteraction<V> {
|
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
|
||||||
self.base.stateless_interaction()
|
self.base.stateless_interactivity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> StatefulInteractive<V> for Img<V, StatefulInteraction<V>, F>
|
impl<V, F> StatefulInteractive<V> for Img<V, StatefulInteractivity<V>, F>
|
||||||
where
|
where
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
fn stateful_interaction(&mut self) -> &mut StatefulInteraction<V> {
|
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<V> {
|
||||||
self.base.stateful_interaction()
|
self.base.stateful_interactivity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, I> Focusable<V> for Img<V, I, FocusEnabled<V>>
|
impl<V, I> Focusable<V> for Img<V, I, FocusEnabled<V>>
|
||||||
where
|
where
|
||||||
V: 'static,
|
V: 'static,
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
{
|
{
|
||||||
fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
|
fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
|
||||||
self.base.focus_listeners()
|
self.base.focus_listeners()
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
use std::{cmp, ops::Range};
|
|
||||||
|
|
||||||
use smallvec::SmallVec;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
point, px, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element, ElementId,
|
point, px, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element, ElementId,
|
||||||
LayoutId, Pixels, Size, StyleRefinement, Styled, ViewContext,
|
ElementInteractivity, InteractiveElementState, LayoutId, Pixels, Size, StatefulInteractive,
|
||||||
|
StatefulInteractivity, StatelessInteractive, StatelessInteractivity, StyleRefinement, Styled,
|
||||||
|
ViewContext,
|
||||||
};
|
};
|
||||||
|
use smallvec::SmallVec;
|
||||||
// We want to support uniform and non-uniform height
|
use std::{cmp, ops::Range};
|
||||||
// We need to make the ID mandatory, to replace the 'state' field
|
use taffy::style::Overflow;
|
||||||
// Previous implementation measured the first element as early as possible
|
|
||||||
|
|
||||||
pub fn list<Id, V, C>(
|
pub fn list<Id, V, C>(
|
||||||
id: Id,
|
id: Id,
|
||||||
@ -21,8 +18,9 @@ where
|
|||||||
V: 'static,
|
V: 'static,
|
||||||
C: Component<V>,
|
C: Component<V>,
|
||||||
{
|
{
|
||||||
|
let id = id.into();
|
||||||
List {
|
List {
|
||||||
id: id.into(),
|
id: id.clone(),
|
||||||
style: Default::default(),
|
style: Default::default(),
|
||||||
item_count,
|
item_count,
|
||||||
render_items: Box::new(move |view, visible_range, cx| {
|
render_items: Box::new(move |view, visible_range, cx| {
|
||||||
@ -31,10 +29,11 @@ where
|
|||||||
.map(|component| component.render())
|
.map(|component| component.render())
|
||||||
.collect()
|
.collect()
|
||||||
}),
|
}),
|
||||||
|
interactivity: id.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct List<V> {
|
pub struct List<V: 'static> {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
style: StyleRefinement,
|
style: StyleRefinement,
|
||||||
item_count: usize,
|
item_count: usize,
|
||||||
@ -45,19 +44,12 @@ pub struct List<V> {
|
|||||||
&'a mut ViewContext<V>,
|
&'a mut ViewContext<V>,
|
||||||
) -> SmallVec<[AnyElement<V>; 64]>,
|
) -> SmallVec<[AnyElement<V>; 64]>,
|
||||||
>,
|
>,
|
||||||
|
interactivity: StatefulInteractivity<V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[derive(Debug)]
|
|
||||||
// pub enum ScrollTarget {
|
|
||||||
// Show(usize),
|
|
||||||
// Center(usize),
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ListState {
|
pub struct ListState {
|
||||||
scroll_top: f32,
|
interactive: InteractiveElementState,
|
||||||
// todo
|
|
||||||
// scroll_to: Option<ScrollTarget>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static> Styled for List<V> {
|
impl<V: 'static> Styled for List<V> {
|
||||||
@ -111,30 +103,66 @@ impl<V: 'static> Element<V> for List<V> {
|
|||||||
- point(border.right + padding.right, border.bottom + padding.bottom),
|
- point(border.right + padding.right, border.bottom + padding.bottom),
|
||||||
);
|
);
|
||||||
|
|
||||||
if self.item_count > 0 {
|
cx.with_z_index(style.z_index.unwrap_or(0), |cx| {
|
||||||
let item_height = self.measure_item_height(view_state, padded_bounds, cx);
|
let content_size;
|
||||||
let visible_item_count = (padded_bounds.size.height / item_height).ceil() as usize;
|
if self.item_count > 0 {
|
||||||
let visible_range = 0..cmp::min(visible_item_count, self.item_count);
|
let item_height = self.measure_item_height(view_state, padded_bounds, cx);
|
||||||
|
let visible_item_count =
|
||||||
|
(padded_bounds.size.height / item_height).ceil() as usize + 1;
|
||||||
|
let scroll_offset = element_state
|
||||||
|
.interactive
|
||||||
|
.scroll_offset()
|
||||||
|
.map_or((0.0).into(), |offset| offset.y);
|
||||||
|
let first_visible_element_ix = (-scroll_offset / item_height).floor() as usize;
|
||||||
|
let visible_range = first_visible_element_ix
|
||||||
|
..cmp::min(
|
||||||
|
first_visible_element_ix + visible_item_count,
|
||||||
|
self.item_count,
|
||||||
|
);
|
||||||
|
|
||||||
let mut items = (self.render_items)(view_state, visible_range, cx);
|
let mut items = (self.render_items)(view_state, visible_range.clone(), cx);
|
||||||
|
|
||||||
dbg!(items.len(), self.item_count, visible_item_count);
|
content_size = Size {
|
||||||
|
width: padded_bounds.size.width,
|
||||||
|
height: item_height * self.item_count,
|
||||||
|
};
|
||||||
|
|
||||||
for (ix, item) in items.iter_mut().enumerate() {
|
cx.with_z_index(1, |cx| {
|
||||||
item.initialize(view_state, cx);
|
for (item, ix) in items.iter_mut().zip(visible_range) {
|
||||||
|
item.initialize(view_state, cx);
|
||||||
|
|
||||||
let layout_id = item.layout(view_state, cx);
|
let layout_id = item.layout(view_state, cx);
|
||||||
cx.compute_layout(
|
cx.compute_layout(
|
||||||
layout_id,
|
layout_id,
|
||||||
Size {
|
Size {
|
||||||
width: AvailableSpace::Definite(bounds.size.width),
|
width: AvailableSpace::Definite(bounds.size.width),
|
||||||
height: AvailableSpace::Definite(item_height),
|
height: AvailableSpace::Definite(item_height),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let offset = padded_bounds.origin + point(px(0.), item_height * ix);
|
let offset =
|
||||||
cx.with_element_offset(Some(offset), |cx| item.paint(view_state, cx))
|
padded_bounds.origin + point(px(0.), item_height * ix + scroll_offset);
|
||||||
|
cx.with_element_offset(Some(offset), |cx| item.paint(view_state, cx))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
content_size = Size {
|
||||||
|
width: bounds.size.width,
|
||||||
|
height: px(0.),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
let overflow = point(style.overflow.x, Overflow::Scroll);
|
||||||
|
|
||||||
|
cx.with_z_index(0, |cx| {
|
||||||
|
self.interactivity.paint(
|
||||||
|
bounds,
|
||||||
|
content_size,
|
||||||
|
overflow,
|
||||||
|
&mut element_state.interactive,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,6 +189,18 @@ impl<V> List<V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<V: 'static> StatelessInteractive<V> for List<V> {
|
||||||
|
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
|
||||||
|
self.interactivity.as_stateless_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: 'static> StatefulInteractive<V> for List<V> {
|
||||||
|
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<V> {
|
||||||
|
&mut self.interactivity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<V: 'static> Component<V> for List<V> {
|
impl<V: 'static> Component<V> for List<V> {
|
||||||
fn render(self) -> AnyElement<V> {
|
fn render(self) -> AnyElement<V> {
|
||||||
AnyElement::new(self)
|
AnyElement::new(self)
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
div, AnyElement, Bounds, Component, Div, DivState, Element, ElementFocus, ElementId,
|
div, AnyElement, Bounds, Component, Div, DivState, Element, ElementFocus, ElementId,
|
||||||
ElementInteraction, FocusDisabled, FocusEnabled, FocusListeners, Focusable, LayoutId, Pixels,
|
ElementInteractivity, FocusDisabled, FocusEnabled, FocusListeners, Focusable, LayoutId, Pixels,
|
||||||
SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction,
|
SharedString, StatefulInteractive, StatefulInteractivity, StatelessInteractive,
|
||||||
StatelessInteractive, StyleRefinement, Styled, ViewContext,
|
StatelessInteractivity, StyleRefinement, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
|
||||||
pub struct Svg<
|
pub struct Svg<
|
||||||
V: 'static,
|
V: 'static,
|
||||||
I: ElementInteraction<V> = StatelessInteraction<V>,
|
I: ElementInteractivity<V> = StatelessInteractivity<V>,
|
||||||
F: ElementFocus<V> = FocusDisabled,
|
F: ElementFocus<V> = FocusDisabled,
|
||||||
> {
|
> {
|
||||||
base: Div<V, I, F>,
|
base: Div<V, I, F>,
|
||||||
path: Option<SharedString>,
|
path: Option<SharedString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn svg<V: 'static>() -> Svg<V, StatelessInteraction<V>, FocusDisabled> {
|
pub fn svg<V: 'static>() -> Svg<V, StatelessInteractivity<V>, FocusDisabled> {
|
||||||
Svg {
|
Svg {
|
||||||
base: div(),
|
base: div(),
|
||||||
path: None,
|
path: None,
|
||||||
@ -24,7 +24,7 @@ pub fn svg<V: 'static>() -> Svg<V, StatelessInteraction<V>, FocusDisabled> {
|
|||||||
|
|
||||||
impl<V, I, F> Svg<V, I, F>
|
impl<V, I, F> Svg<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
pub fn path(mut self, path: impl Into<SharedString>) -> Self {
|
pub fn path(mut self, path: impl Into<SharedString>) -> Self {
|
||||||
@ -33,11 +33,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> Svg<V, StatelessInteraction<V>, F>
|
impl<V, F> Svg<V, StatelessInteractivity<V>, F>
|
||||||
where
|
where
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
pub fn id(self, id: impl Into<ElementId>) -> Svg<V, StatefulInteraction<V>, F> {
|
pub fn id(self, id: impl Into<ElementId>) -> Svg<V, StatefulInteractivity<V>, F> {
|
||||||
Svg {
|
Svg {
|
||||||
base: self.base.id(id),
|
base: self.base.id(id),
|
||||||
path: self.path,
|
path: self.path,
|
||||||
@ -47,7 +47,7 @@ where
|
|||||||
|
|
||||||
impl<V, I, F> Component<V> for Svg<V, I, F>
|
impl<V, I, F> Component<V> for Svg<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
fn render(self) -> AnyElement<V> {
|
fn render(self) -> AnyElement<V> {
|
||||||
@ -57,7 +57,7 @@ where
|
|||||||
|
|
||||||
impl<V, I, F> Element<V> for Svg<V, I, F>
|
impl<V, I, F> Element<V> for Svg<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
type ElementState = DivState;
|
type ElementState = DivState;
|
||||||
@ -107,7 +107,7 @@ where
|
|||||||
|
|
||||||
impl<V, I, F> Styled for Svg<V, I, F>
|
impl<V, I, F> Styled for Svg<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
fn style(&mut self) -> &mut StyleRefinement {
|
fn style(&mut self) -> &mut StyleRefinement {
|
||||||
@ -117,27 +117,27 @@ where
|
|||||||
|
|
||||||
impl<V, I, F> StatelessInteractive<V> for Svg<V, I, F>
|
impl<V, I, F> StatelessInteractive<V> for Svg<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
fn stateless_interaction(&mut self) -> &mut StatelessInteraction<V> {
|
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
|
||||||
self.base.stateless_interaction()
|
self.base.stateless_interactivity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> StatefulInteractive<V> for Svg<V, StatefulInteraction<V>, F>
|
impl<V, F> StatefulInteractive<V> for Svg<V, StatefulInteractivity<V>, F>
|
||||||
where
|
where
|
||||||
V: 'static,
|
V: 'static,
|
||||||
F: ElementFocus<V>,
|
F: ElementFocus<V>,
|
||||||
{
|
{
|
||||||
fn stateful_interaction(&mut self) -> &mut StatefulInteraction<V> {
|
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<V> {
|
||||||
self.base.stateful_interaction()
|
self.base.stateful_interactivity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static, I> Focusable<V> for Svg<V, I, FocusEnabled<V>>
|
impl<V: 'static, I> Focusable<V> for Svg<V, I, FocusEnabled<V>>
|
||||||
where
|
where
|
||||||
I: ElementInteraction<V>,
|
I: ElementInteractivity<V>,
|
||||||
{
|
{
|
||||||
fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
|
fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
|
||||||
self.base.focus_listeners()
|
self.base.focus_listeners()
|
||||||
|
@ -25,13 +25,13 @@ const TOOLTIP_DELAY: Duration = Duration::from_millis(500);
|
|||||||
const TOOLTIP_OFFSET: Point<Pixels> = Point::new(px(10.0), px(8.0));
|
const TOOLTIP_OFFSET: Point<Pixels> = Point::new(px(10.0), px(8.0));
|
||||||
|
|
||||||
pub trait StatelessInteractive<V: 'static>: Element<V> {
|
pub trait StatelessInteractive<V: 'static>: Element<V> {
|
||||||
fn stateless_interaction(&mut self) -> &mut StatelessInteraction<V>;
|
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V>;
|
||||||
|
|
||||||
fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
|
fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateless_interaction().hover_style = f(StyleRefinement::default());
|
self.stateless_interactivity().hover_style = f(StyleRefinement::default());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateless_interaction().group_hover_style = Some(GroupStyle {
|
self.stateless_interactivity().group_hover_style = Some(GroupStyle {
|
||||||
group: group_name.into(),
|
group: group_name.into(),
|
||||||
style: f(StyleRefinement::default()),
|
style: f(StyleRefinement::default()),
|
||||||
});
|
});
|
||||||
@ -58,7 +58,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateless_interaction()
|
self.stateless_interactivity()
|
||||||
.mouse_down_listeners
|
.mouse_down_listeners
|
||||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||||
if phase == DispatchPhase::Bubble
|
if phase == DispatchPhase::Bubble
|
||||||
@ -79,7 +79,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateless_interaction()
|
self.stateless_interactivity()
|
||||||
.mouse_up_listeners
|
.mouse_up_listeners
|
||||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||||
if phase == DispatchPhase::Bubble
|
if phase == DispatchPhase::Bubble
|
||||||
@ -100,7 +100,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateless_interaction()
|
self.stateless_interactivity()
|
||||||
.mouse_down_listeners
|
.mouse_down_listeners
|
||||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||||
if phase == DispatchPhase::Capture
|
if phase == DispatchPhase::Capture
|
||||||
@ -121,7 +121,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateless_interaction()
|
self.stateless_interactivity()
|
||||||
.mouse_up_listeners
|
.mouse_up_listeners
|
||||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||||
if phase == DispatchPhase::Capture
|
if phase == DispatchPhase::Capture
|
||||||
@ -141,7 +141,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateless_interaction()
|
self.stateless_interactivity()
|
||||||
.mouse_move_listeners
|
.mouse_move_listeners
|
||||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||||
@ -158,7 +158,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateless_interaction()
|
self.stateless_interactivity()
|
||||||
.scroll_wheel_listeners
|
.scroll_wheel_listeners
|
||||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||||
@ -174,23 +174,48 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||||||
C: TryInto<DispatchContext>,
|
C: TryInto<DispatchContext>,
|
||||||
C::Error: Debug,
|
C::Error: Debug,
|
||||||
{
|
{
|
||||||
self.stateless_interaction().dispatch_context =
|
self.stateless_interactivity().dispatch_context =
|
||||||
context.try_into().expect("invalid dispatch context");
|
context.try_into().expect("invalid dispatch context");
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_action<A: 'static>(
|
/// Capture the given action, fires during the capture phase
|
||||||
|
fn capture_action<A: 'static>(
|
||||||
mut self,
|
mut self,
|
||||||
listener: impl Fn(&mut V, &A, DispatchPhase, &mut ViewContext<V>) + 'static,
|
listener: impl Fn(&mut V, &A, &mut ViewContext<V>) + 'static,
|
||||||
) -> Self
|
) -> Self
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateless_interaction().key_listeners.push((
|
self.stateless_interactivity().key_listeners.push((
|
||||||
TypeId::of::<A>(),
|
TypeId::of::<A>(),
|
||||||
Box::new(move |view, event, _, phase, cx| {
|
Box::new(move |view, event, _, phase, cx| {
|
||||||
let event = event.downcast_ref().unwrap();
|
let event = event.downcast_ref().unwrap();
|
||||||
listener(view, event, phase, cx);
|
if phase == DispatchPhase::Capture {
|
||||||
|
listener(view, event, cx)
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a listener for the given action, fires during the bubble event phase
|
||||||
|
fn on_action<A: 'static>(
|
||||||
|
mut self,
|
||||||
|
listener: impl Fn(&mut V, &A, &mut ViewContext<V>) + 'static,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.stateless_interactivity().key_listeners.push((
|
||||||
|
TypeId::of::<A>(),
|
||||||
|
Box::new(move |view, event, _, phase, cx| {
|
||||||
|
let event = event.downcast_ref().unwrap();
|
||||||
|
if phase == DispatchPhase::Bubble {
|
||||||
|
listener(view, event, cx)
|
||||||
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
@ -204,7 +229,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateless_interaction().key_listeners.push((
|
self.stateless_interactivity().key_listeners.push((
|
||||||
TypeId::of::<KeyDownEvent>(),
|
TypeId::of::<KeyDownEvent>(),
|
||||||
Box::new(move |view, event, _, phase, cx| {
|
Box::new(move |view, event, _, phase, cx| {
|
||||||
let event = event.downcast_ref().unwrap();
|
let event = event.downcast_ref().unwrap();
|
||||||
@ -222,7 +247,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateless_interaction().key_listeners.push((
|
self.stateless_interactivity().key_listeners.push((
|
||||||
TypeId::of::<KeyUpEvent>(),
|
TypeId::of::<KeyUpEvent>(),
|
||||||
Box::new(move |view, event, _, phase, cx| {
|
Box::new(move |view, event, _, phase, cx| {
|
||||||
let event = event.downcast_ref().unwrap();
|
let event = event.downcast_ref().unwrap();
|
||||||
@ -237,7 +262,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateless_interaction()
|
self.stateless_interactivity()
|
||||||
.drag_over_styles
|
.drag_over_styles
|
||||||
.push((TypeId::of::<S>(), f(StyleRefinement::default())));
|
.push((TypeId::of::<S>(), f(StyleRefinement::default())));
|
||||||
self
|
self
|
||||||
@ -251,7 +276,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateless_interaction().group_drag_over_styles.push((
|
self.stateless_interactivity().group_drag_over_styles.push((
|
||||||
TypeId::of::<S>(),
|
TypeId::of::<S>(),
|
||||||
GroupStyle {
|
GroupStyle {
|
||||||
group: group_name.into(),
|
group: group_name.into(),
|
||||||
@ -268,7 +293,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateless_interaction().drop_listeners.push((
|
self.stateless_interactivity().drop_listeners.push((
|
||||||
TypeId::of::<W>(),
|
TypeId::of::<W>(),
|
||||||
Box::new(move |view, dragged_view, cx| {
|
Box::new(move |view, dragged_view, cx| {
|
||||||
listener(view, dragged_view.downcast().unwrap(), cx);
|
listener(view, dragged_view.downcast().unwrap(), cx);
|
||||||
@ -279,13 +304,13 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
||||||
fn stateful_interaction(&mut self) -> &mut StatefulInteraction<V>;
|
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<V>;
|
||||||
|
|
||||||
fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
|
fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateful_interaction().active_style = f(StyleRefinement::default());
|
self.stateful_interactivity().active_style = f(StyleRefinement::default());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,7 +322,7 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
|||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateful_interaction().group_active_style = Some(GroupStyle {
|
self.stateful_interactivity().group_active_style = Some(GroupStyle {
|
||||||
group: group_name.into(),
|
group: group_name.into(),
|
||||||
style: f(StyleRefinement::default()),
|
style: f(StyleRefinement::default()),
|
||||||
});
|
});
|
||||||
@ -311,7 +336,7 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
|||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.stateful_interaction()
|
self.stateful_interactivity()
|
||||||
.click_listeners
|
.click_listeners
|
||||||
.push(Box::new(move |view, event, cx| listener(view, event, cx)));
|
.push(Box::new(move |view, event, cx| listener(view, event, cx)));
|
||||||
self
|
self
|
||||||
@ -326,10 +351,10 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
|||||||
W: 'static + Render,
|
W: 'static + Render,
|
||||||
{
|
{
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
self.stateful_interaction().drag_listener.is_none(),
|
self.stateful_interactivity().drag_listener.is_none(),
|
||||||
"calling on_drag more than once on the same element is not supported"
|
"calling on_drag more than once on the same element is not supported"
|
||||||
);
|
);
|
||||||
self.stateful_interaction().drag_listener =
|
self.stateful_interactivity().drag_listener =
|
||||||
Some(Box::new(move |view_state, cursor_offset, cx| AnyDrag {
|
Some(Box::new(move |view_state, cursor_offset, cx| AnyDrag {
|
||||||
view: listener(view_state, cx).into(),
|
view: listener(view_state, cx).into(),
|
||||||
cursor_offset,
|
cursor_offset,
|
||||||
@ -342,10 +367,10 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
|||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
self.stateful_interaction().hover_listener.is_none(),
|
self.stateful_interactivity().hover_listener.is_none(),
|
||||||
"calling on_hover more than once on the same element is not supported"
|
"calling on_hover more than once on the same element is not supported"
|
||||||
);
|
);
|
||||||
self.stateful_interaction().hover_listener = Some(Box::new(listener));
|
self.stateful_interactivity().hover_listener = Some(Box::new(listener));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,10 +383,10 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
|||||||
W: 'static + Render,
|
W: 'static + Render,
|
||||||
{
|
{
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
self.stateful_interaction().tooltip_builder.is_none(),
|
self.stateful_interactivity().tooltip_builder.is_none(),
|
||||||
"calling tooltip more than once on the same element is not supported"
|
"calling tooltip more than once on the same element is not supported"
|
||||||
);
|
);
|
||||||
self.stateful_interaction().tooltip_builder = Some(Arc::new(move |view_state, cx| {
|
self.stateful_interactivity().tooltip_builder = Some(Arc::new(move |view_state, cx| {
|
||||||
build_tooltip(view_state, cx).into()
|
build_tooltip(view_state, cx).into()
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -369,11 +394,11 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ElementInteraction<V: 'static>: 'static {
|
pub trait ElementInteractivity<V: 'static>: 'static {
|
||||||
fn as_stateless(&self) -> &StatelessInteraction<V>;
|
fn as_stateless(&self) -> &StatelessInteractivity<V>;
|
||||||
fn as_stateless_mut(&mut self) -> &mut StatelessInteraction<V>;
|
fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V>;
|
||||||
fn as_stateful(&self) -> Option<&StatefulInteraction<V>>;
|
fn as_stateful(&self) -> Option<&StatefulInteractivity<V>>;
|
||||||
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteraction<V>>;
|
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>>;
|
||||||
|
|
||||||
fn initialize<R>(
|
fn initialize<R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -735,11 +760,11 @@ pub trait ElementInteraction<V: 'static>: 'static {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deref, DerefMut)]
|
#[derive(Deref, DerefMut)]
|
||||||
pub struct StatefulInteraction<V> {
|
pub struct StatefulInteractivity<V> {
|
||||||
pub id: ElementId,
|
pub id: ElementId,
|
||||||
#[deref]
|
#[deref]
|
||||||
#[deref_mut]
|
#[deref_mut]
|
||||||
stateless: StatelessInteraction<V>,
|
stateless: StatelessInteractivity<V>,
|
||||||
click_listeners: SmallVec<[ClickListener<V>; 2]>,
|
click_listeners: SmallVec<[ClickListener<V>; 2]>,
|
||||||
active_style: StyleRefinement,
|
active_style: StyleRefinement,
|
||||||
group_active_style: Option<GroupStyle>,
|
group_active_style: Option<GroupStyle>,
|
||||||
@ -748,29 +773,29 @@ pub struct StatefulInteraction<V> {
|
|||||||
tooltip_builder: Option<TooltipBuilder<V>>,
|
tooltip_builder: Option<TooltipBuilder<V>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static> ElementInteraction<V> for StatefulInteraction<V> {
|
impl<V: 'static> ElementInteractivity<V> for StatefulInteractivity<V> {
|
||||||
fn as_stateful(&self) -> Option<&StatefulInteraction<V>> {
|
fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
|
||||||
Some(self)
|
Some(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteraction<V>> {
|
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>> {
|
||||||
Some(self)
|
Some(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_stateless(&self) -> &StatelessInteraction<V> {
|
fn as_stateless(&self) -> &StatelessInteractivity<V> {
|
||||||
&self.stateless
|
&self.stateless
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_stateless_mut(&mut self) -> &mut StatelessInteraction<V> {
|
fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V> {
|
||||||
&mut self.stateless
|
&mut self.stateless
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> From<ElementId> for StatefulInteraction<V> {
|
impl<V> From<ElementId> for StatefulInteractivity<V> {
|
||||||
fn from(id: ElementId) -> Self {
|
fn from(id: ElementId) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
stateless: StatelessInteraction::default(),
|
stateless: StatelessInteractivity::default(),
|
||||||
click_listeners: SmallVec::new(),
|
click_listeners: SmallVec::new(),
|
||||||
drag_listener: None,
|
drag_listener: None,
|
||||||
hover_listener: None,
|
hover_listener: None,
|
||||||
@ -783,7 +808,7 @@ impl<V> From<ElementId> for StatefulInteraction<V> {
|
|||||||
|
|
||||||
type DropListener<V> = dyn Fn(&mut V, AnyView, &mut ViewContext<V>) + 'static;
|
type DropListener<V> = dyn Fn(&mut V, AnyView, &mut ViewContext<V>) + 'static;
|
||||||
|
|
||||||
pub struct StatelessInteraction<V> {
|
pub struct StatelessInteractivity<V> {
|
||||||
pub dispatch_context: DispatchContext,
|
pub dispatch_context: DispatchContext,
|
||||||
pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
|
pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
|
||||||
pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
|
pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
|
||||||
@ -797,9 +822,9 @@ pub struct StatelessInteraction<V> {
|
|||||||
drop_listeners: SmallVec<[(TypeId, Box<DropListener<V>>); 2]>,
|
drop_listeners: SmallVec<[(TypeId, Box<DropListener<V>>); 2]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> StatelessInteraction<V> {
|
impl<V> StatelessInteractivity<V> {
|
||||||
pub fn into_stateful(self, id: impl Into<ElementId>) -> StatefulInteraction<V> {
|
pub fn into_stateful(self, id: impl Into<ElementId>) -> StatefulInteractivity<V> {
|
||||||
StatefulInteraction {
|
StatefulInteractivity {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
stateless: self,
|
stateless: self,
|
||||||
click_listeners: SmallVec::new(),
|
click_listeners: SmallVec::new(),
|
||||||
@ -877,7 +902,7 @@ impl InteractiveElementState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> Default for StatelessInteraction<V> {
|
impl<V> Default for StatelessInteractivity<V> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
dispatch_context: DispatchContext::default(),
|
dispatch_context: DispatchContext::default(),
|
||||||
@ -895,20 +920,20 @@ impl<V> Default for StatelessInteraction<V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static> ElementInteraction<V> for StatelessInteraction<V> {
|
impl<V: 'static> ElementInteractivity<V> for StatelessInteractivity<V> {
|
||||||
fn as_stateful(&self) -> Option<&StatefulInteraction<V>> {
|
fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteraction<V>> {
|
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_stateless(&self) -> &StatelessInteraction<V> {
|
fn as_stateless(&self) -> &StatelessInteractivity<V> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_stateless_mut(&mut self) -> &mut StatelessInteraction<V> {
|
fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,7 +277,7 @@ impl Style {
|
|||||||
pub fn paint<V: 'static>(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
|
pub fn paint<V: 'static>(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
|
||||||
let rem_size = cx.rem_size();
|
let rem_size = cx.rem_size();
|
||||||
|
|
||||||
cx.stack(0, |cx| {
|
cx.with_z_index(0, |cx| {
|
||||||
cx.paint_shadows(
|
cx.paint_shadows(
|
||||||
bounds,
|
bounds,
|
||||||
self.corner_radii.to_pixels(bounds.size, rem_size),
|
self.corner_radii.to_pixels(bounds.size, rem_size),
|
||||||
@ -287,7 +287,7 @@ impl Style {
|
|||||||
|
|
||||||
let background_color = self.background.as_ref().and_then(Fill::color);
|
let background_color = self.background.as_ref().and_then(Fill::color);
|
||||||
if background_color.is_some() || self.is_border_visible() {
|
if background_color.is_some() || self.is_border_visible() {
|
||||||
cx.stack(1, |cx| {
|
cx.with_z_index(1, |cx| {
|
||||||
cx.paint_quad(
|
cx.paint_quad(
|
||||||
bounds,
|
bounds,
|
||||||
self.corner_radii.to_pixels(bounds.size, rem_size),
|
self.corner_radii.to_pixels(bounds.size, rem_size),
|
||||||
|
@ -142,8 +142,6 @@ impl Line {
|
|||||||
color,
|
color,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
dbg!(content_mask.bounds, max_glyph_bounds);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1698,8 +1698,8 @@ impl<'a, V: 'static> ViewContext<'a, V> {
|
|||||||
&mut self.window_cx
|
&mut self.window_cx
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R {
|
pub fn with_z_index<R>(&mut self, z_index: u32, f: impl FnOnce(&mut Self) -> R) -> R {
|
||||||
self.window.z_index_stack.push(order);
|
self.window.z_index_stack.push(z_index);
|
||||||
let result = f(self);
|
let result = f(self);
|
||||||
self.window.z_index_stack.pop();
|
self.window.z_index_stack.pop();
|
||||||
result
|
result
|
||||||
|
@ -9,4 +9,5 @@ path = "src/menu2.rs"
|
|||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gpui = { package = "gpui2", path = "../gpui2" }
|
serde.workspace = true
|
||||||
|
serde_derive.workspace = true
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
// todo!(use actions! macro)
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||||
pub struct Cancel;
|
pub struct Cancel;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||||
pub struct Confirm;
|
pub struct Confirm;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||||
pub struct SecondaryConfirm;
|
pub struct SecondaryConfirm;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||||
pub struct SelectPrev;
|
pub struct SelectPrev;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||||
pub struct SelectNext;
|
pub struct SelectNext;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||||
pub struct SelectFirst;
|
pub struct SelectFirst;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||||
pub struct SelectLast;
|
pub struct SelectLast;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||||
pub struct ShowContextMenu;
|
pub struct ShowContextMenu;
|
||||||
|
@ -18,11 +18,11 @@
|
|||||||
// Dismiss,
|
// Dismiss,
|
||||||
// }
|
// }
|
||||||
|
|
||||||
use std::ops::Range;
|
use std::cmp;
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, list, red, AppContext, Component, Div, Element, ElementId, ParentElement, Render, Styled,
|
div, list, Component, ElementId, FocusHandle, Focusable, ParentElement, StatelessInteractive,
|
||||||
ViewContext,
|
Styled, ViewContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
// pub struct Picker<D> {
|
// pub struct Picker<D> {
|
||||||
@ -43,8 +43,9 @@ pub trait PickerDelegate: Sized + 'static {
|
|||||||
|
|
||||||
fn match_count(&self, picker_id: ElementId) -> usize;
|
fn match_count(&self, picker_id: ElementId) -> usize;
|
||||||
|
|
||||||
// fn selected_index(&self) -> usize;
|
fn selected_index(&self, picker_id: ElementId) -> usize;
|
||||||
// fn set_selected_index(&mut self, ix: usize, cx: &mut ViewContext<Picker<Self>>);
|
fn set_selected_index(&mut self, ix: usize, picker_id: ElementId, cx: &mut ViewContext<Self>);
|
||||||
|
|
||||||
// fn update_matches(&mut self, query: String, cx: &mut ViewContext<Picker<Self>>) -> Task<()>;
|
// fn update_matches(&mut self, query: String, cx: &mut ViewContext<Picker<Self>>) -> Task<()>;
|
||||||
// fn confirm(&mut self, secondary: bool, cx: &mut ViewContext<Picker<Self>>);
|
// fn confirm(&mut self, secondary: bool, cx: &mut ViewContext<Picker<Self>>);
|
||||||
// fn dismissed(&mut self, cx: &mut ViewContext<Picker<Self>>);
|
// fn dismissed(&mut self, cx: &mut ViewContext<Picker<Self>>);
|
||||||
@ -53,8 +54,6 @@ pub trait PickerDelegate: Sized + 'static {
|
|||||||
fn render_match(
|
fn render_match(
|
||||||
&self,
|
&self,
|
||||||
ix: usize,
|
ix: usize,
|
||||||
active: bool,
|
|
||||||
hovered: bool,
|
|
||||||
selected: bool,
|
selected: bool,
|
||||||
picker_id: ElementId,
|
picker_id: ElementId,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
@ -84,32 +83,72 @@ pub trait PickerDelegate: Sized + 'static {
|
|||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct Picker<V: PickerDelegate> {
|
pub struct Picker<V: PickerDelegate> {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
|
focus_handle: FocusHandle,
|
||||||
phantom: std::marker::PhantomData<V>,
|
phantom: std::marker::PhantomData<V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: PickerDelegate> Picker<V> {
|
impl<V: PickerDelegate> Picker<V> {
|
||||||
pub fn new(id: impl Into<ElementId>) -> Self {
|
pub fn new(id: impl Into<ElementId>, focus_handle: FocusHandle) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
|
focus_handle,
|
||||||
phantom: std::marker::PhantomData,
|
phantom: std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static + PickerDelegate> Picker<V> {
|
impl<V: 'static + PickerDelegate> Picker<V> {
|
||||||
pub fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
|
pub fn render(self, view: &mut V, _cx: &mut ViewContext<V>) -> impl Component<V> {
|
||||||
div().size_full().id(self.id.clone()).child(
|
let id = self.id.clone();
|
||||||
list(
|
div()
|
||||||
"candidates",
|
.size_full()
|
||||||
view.match_count(self.id.clone()),
|
.id(self.id.clone())
|
||||||
move |this: &mut V, visible_range, cx| {
|
.track_focus(&self.focus_handle)
|
||||||
visible_range
|
.context("picker")
|
||||||
.map(|ix| this.render_match(ix, false, false, false, self.id.clone(), cx))
|
.on_focus(|v, e, cx| {
|
||||||
.collect()
|
dbg!("FOCUSED!");
|
||||||
},
|
})
|
||||||
|
.on_blur(|v, e, cx| {
|
||||||
|
dbg!("BLURRED!");
|
||||||
|
})
|
||||||
|
.on_action({
|
||||||
|
let id = id.clone();
|
||||||
|
move |view: &mut V, _: &menu::SelectNext, cx| {
|
||||||
|
let index = view.selected_index(id.clone());
|
||||||
|
let count = view.match_count(id.clone());
|
||||||
|
if count > 0 {
|
||||||
|
view.set_selected_index(cmp::min(index + 1, count - 1), id.clone(), cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on_action({
|
||||||
|
let id = id.clone();
|
||||||
|
move |view, _: &menu::SelectPrev, cx| {
|
||||||
|
let index = view.selected_index(id.clone());
|
||||||
|
let count = view.match_count(id.clone());
|
||||||
|
if count > 0 {
|
||||||
|
view.set_selected_index((index + 1) % count, id.clone(), cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on_action(|view, _: &menu::SelectFirst, cx| {})
|
||||||
|
.on_action(|view, _: &menu::SelectLast, cx| {})
|
||||||
|
.on_action(|view, _: &menu::Cancel, cx| {})
|
||||||
|
.on_action(|view, _: &menu::Confirm, cx| {})
|
||||||
|
.on_action(|view, _: &menu::SecondaryConfirm, cx| {})
|
||||||
|
.child(
|
||||||
|
list(
|
||||||
|
"candidates",
|
||||||
|
view.match_count(self.id.clone()),
|
||||||
|
move |view: &mut V, visible_range, cx| {
|
||||||
|
let selected_ix = view.selected_index(self.id.clone());
|
||||||
|
visible_range
|
||||||
|
.map(|ix| view.render_match(ix, ix == selected_ix, self.id.clone(), cx))
|
||||||
|
.collect()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.size_full(),
|
||||||
)
|
)
|
||||||
.size_full(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ smallvec.workspace = true
|
|||||||
strum = { version = "0.25.0", features = ["derive"] }
|
strum = { version = "0.25.0", features = ["derive"] }
|
||||||
theme = { path = "../theme" }
|
theme = { path = "../theme" }
|
||||||
theme2 = { path = "../theme2" }
|
theme2 = { path = "../theme2" }
|
||||||
|
menu = { package = "menu2", path = "../menu2" }
|
||||||
ui = { package = "ui2", path = "../ui2", features = ["stories"] }
|
ui = { package = "ui2", path = "../ui2", features = ["stories"] }
|
||||||
util = { path = "../util" }
|
util = { path = "../util" }
|
||||||
picker = { package = "picker2", path = "../picker2" }
|
picker = { package = "picker2", path = "../picker2" }
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use gpui::{
|
use gpui::{
|
||||||
div, Div, FocusEnabled, Focusable, KeyBinding, ParentElement, Render, StatefulInteraction,
|
div, Div, FocusEnabled, Focusable, KeyBinding, ParentElement, Render, StatefulInteractivity,
|
||||||
StatelessInteractive, Styled, View, VisualContext, WindowContext,
|
StatelessInteractive, Styled, View, VisualContext, WindowContext,
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@ -31,7 +31,7 @@ impl FocusStory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Render for FocusStory {
|
impl Render for FocusStory {
|
||||||
type Element = Div<Self, StatefulInteraction<Self>, FocusEnabled<Self>>;
|
type Element = Div<Self, StatefulInteractivity<Self>, FocusEnabled<Self>>;
|
||||||
|
|
||||||
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
|
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
|
||||||
let theme = cx.theme();
|
let theme = cx.theme();
|
||||||
@ -48,20 +48,18 @@ impl Render for FocusStory {
|
|||||||
.id("parent")
|
.id("parent")
|
||||||
.focusable()
|
.focusable()
|
||||||
.context("parent")
|
.context("parent")
|
||||||
.on_action(|_, action: &ActionA, phase, cx| {
|
.on_action(|_, action: &ActionA, cx| {
|
||||||
println!("Action A dispatched on parent during {:?}", phase);
|
println!("Action A dispatched on parent during");
|
||||||
})
|
})
|
||||||
.on_action(|_, action: &ActionB, phase, cx| {
|
.on_action(|_, action: &ActionB, cx| {
|
||||||
println!("Action B dispatched on parent during {:?}", phase);
|
println!("Action B dispatched on parent during");
|
||||||
})
|
})
|
||||||
.on_focus(|_, _, _| println!("Parent focused"))
|
.on_focus(|_, _, _| println!("Parent focused"))
|
||||||
.on_blur(|_, _, _| println!("Parent blurred"))
|
.on_blur(|_, _, _| println!("Parent blurred"))
|
||||||
.on_focus_in(|_, _, _| println!("Parent focus_in"))
|
.on_focus_in(|_, _, _| println!("Parent focus_in"))
|
||||||
.on_focus_out(|_, _, _| println!("Parent focus_out"))
|
.on_focus_out(|_, _, _| println!("Parent focus_out"))
|
||||||
.on_key_down(|_, event, phase, _| {
|
.on_key_down(|_, event, phase, _| println!("Key down on parent {:?}", event))
|
||||||
println!("Key down on parent {:?} {:?}", phase, event)
|
.on_key_up(|_, event, phase, _| println!("Key up on parent {:?}", event))
|
||||||
})
|
|
||||||
.on_key_up(|_, event, phase, _| println!("Key up on parent {:?} {:?}", phase, event))
|
|
||||||
.size_full()
|
.size_full()
|
||||||
.bg(color_1)
|
.bg(color_1)
|
||||||
.focus(|style| style.bg(color_2))
|
.focus(|style| style.bg(color_2))
|
||||||
@ -70,8 +68,8 @@ impl Render for FocusStory {
|
|||||||
div()
|
div()
|
||||||
.track_focus(&child_1)
|
.track_focus(&child_1)
|
||||||
.context("child-1")
|
.context("child-1")
|
||||||
.on_action(|_, action: &ActionB, phase, cx| {
|
.on_action(|_, action: &ActionB, cx| {
|
||||||
println!("Action B dispatched on child 1 during {:?}", phase);
|
println!("Action B dispatched on child 1 during");
|
||||||
})
|
})
|
||||||
.w_full()
|
.w_full()
|
||||||
.h_6()
|
.h_6()
|
||||||
@ -82,20 +80,16 @@ impl Render for FocusStory {
|
|||||||
.on_blur(|_, _, _| println!("Child 1 blurred"))
|
.on_blur(|_, _, _| println!("Child 1 blurred"))
|
||||||
.on_focus_in(|_, _, _| println!("Child 1 focus_in"))
|
.on_focus_in(|_, _, _| println!("Child 1 focus_in"))
|
||||||
.on_focus_out(|_, _, _| println!("Child 1 focus_out"))
|
.on_focus_out(|_, _, _| println!("Child 1 focus_out"))
|
||||||
.on_key_down(|_, event, phase, _| {
|
.on_key_down(|_, event, phase, _| println!("Key down on child 1 {:?}", event))
|
||||||
println!("Key down on child 1 {:?} {:?}", phase, event)
|
.on_key_up(|_, event, phase, _| println!("Key up on child 1 {:?}", event))
|
||||||
})
|
|
||||||
.on_key_up(|_, event, phase, _| {
|
|
||||||
println!("Key up on child 1 {:?} {:?}", phase, event)
|
|
||||||
})
|
|
||||||
.child("Child 1"),
|
.child("Child 1"),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.track_focus(&child_2)
|
.track_focus(&child_2)
|
||||||
.context("child-2")
|
.context("child-2")
|
||||||
.on_action(|_, action: &ActionC, phase, cx| {
|
.on_action(|_, action: &ActionC, cx| {
|
||||||
println!("Action C dispatched on child 2 during {:?}", phase);
|
println!("Action C dispatched on child 2 during");
|
||||||
})
|
})
|
||||||
.w_full()
|
.w_full()
|
||||||
.h_6()
|
.h_6()
|
||||||
@ -104,12 +98,8 @@ impl Render for FocusStory {
|
|||||||
.on_blur(|_, _, _| println!("Child 2 blurred"))
|
.on_blur(|_, _, _| println!("Child 2 blurred"))
|
||||||
.on_focus_in(|_, _, _| println!("Child 2 focus_in"))
|
.on_focus_in(|_, _, _| println!("Child 2 focus_in"))
|
||||||
.on_focus_out(|_, _, _| println!("Child 2 focus_out"))
|
.on_focus_out(|_, _, _| println!("Child 2 focus_out"))
|
||||||
.on_key_down(|_, event, phase, _| {
|
.on_key_down(|_, event, phase, _| println!("Key down on child 2 {:?}", event))
|
||||||
println!("Key down on child 2 {:?} {:?}", phase, event)
|
.on_key_up(|_, event, phase, _| println!("Key up on child 2 {:?}", event))
|
||||||
})
|
|
||||||
.on_key_up(|_, event, phase, _| {
|
|
||||||
println!("Key up on child 2 {:?} {:?}", phase, event)
|
|
||||||
})
|
|
||||||
.child("Child 2"),
|
.child("Child 2"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{story::Story, story_selector::ComponentStory};
|
use crate::{story::Story, story_selector::ComponentStory};
|
||||||
use gpui::{Div, Render, StatefulInteraction, View, VisualContext};
|
use gpui::{Div, Render, StatefulInteractivity, View, VisualContext};
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
use ui::prelude::*;
|
use ui::prelude::*;
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ impl KitchenSinkStory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Render for KitchenSinkStory {
|
impl Render for KitchenSinkStory {
|
||||||
type Element = Div<Self, StatefulInteraction<Self>>;
|
type Element = Div<Self, StatefulInteractivity<Self>>;
|
||||||
|
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||||
let component_stories = ComponentStory::iter()
|
let component_stories = ComponentStory::iter()
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
use gpui::{
|
use gpui::{
|
||||||
black, div, red, Div, Fill, ParentElement, Render, SharedString, Styled, View, VisualContext,
|
div, Component, Div, FocusHandle, KeyBinding, ParentElement, Render, SharedString,
|
||||||
WindowContext,
|
StatelessInteractive, Styled, View, VisualContext, WindowContext,
|
||||||
};
|
};
|
||||||
use picker::{Picker, PickerDelegate};
|
use picker::{Picker, PickerDelegate};
|
||||||
|
use theme2::ActiveTheme;
|
||||||
|
|
||||||
pub struct PickerStory {
|
pub struct PickerStory {
|
||||||
|
selected_ix: usize,
|
||||||
candidates: Vec<SharedString>,
|
candidates: Vec<SharedString>,
|
||||||
|
focus_handle: FocusHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PickerDelegate for PickerStory {
|
impl PickerDelegate for PickerStory {
|
||||||
type ListItem = SharedString;
|
type ListItem = Div<Self>;
|
||||||
|
|
||||||
fn match_count(&self, _picker_id: gpui::ElementId) -> usize {
|
fn match_count(&self, _picker_id: gpui::ElementId) -> usize {
|
||||||
self.candidates.len()
|
self.candidates.len()
|
||||||
@ -18,46 +21,118 @@ impl PickerDelegate for PickerStory {
|
|||||||
fn render_match(
|
fn render_match(
|
||||||
&self,
|
&self,
|
||||||
ix: usize,
|
ix: usize,
|
||||||
_active: bool,
|
selected: bool,
|
||||||
_hovered: bool,
|
|
||||||
_selected: bool,
|
|
||||||
_picker_id: gpui::ElementId,
|
_picker_id: gpui::ElementId,
|
||||||
cx: &mut gpui::ViewContext<Self>,
|
cx: &mut gpui::ViewContext<Self>,
|
||||||
) -> Self::ListItem {
|
) -> Self::ListItem {
|
||||||
self.candidates[ix].clone()
|
let colors = cx.theme().colors();
|
||||||
|
|
||||||
|
div()
|
||||||
|
.text_color(colors.text)
|
||||||
|
.when(selected, |s| {
|
||||||
|
s.border_l_10().border_color(colors.terminal_ansi_yellow)
|
||||||
|
})
|
||||||
|
.hover(|style| {
|
||||||
|
style
|
||||||
|
.bg(colors.element_active)
|
||||||
|
.text_color(colors.text_accent)
|
||||||
|
})
|
||||||
|
.child(self.candidates[ix].clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn selected_index(&self, picker_id: gpui::ElementId) -> usize {
|
||||||
|
self.selected_ix
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_selected_index(
|
||||||
|
&mut self,
|
||||||
|
ix: usize,
|
||||||
|
_picker_id: gpui::ElementId,
|
||||||
|
_cx: &mut gpui::ViewContext<Self>,
|
||||||
|
) {
|
||||||
|
self.selected_ix = ix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PickerStory {
|
impl PickerStory {
|
||||||
pub fn new(cx: &mut WindowContext) -> View<Self> {
|
pub fn new(cx: &mut WindowContext) -> View<Self> {
|
||||||
cx.build_view(|cx| PickerStory {
|
cx.build_view(|cx| {
|
||||||
candidates: vec![
|
cx.bind_keys([
|
||||||
"Pizza (Italy)".into(),
|
KeyBinding::new("up", menu::SelectPrev, Some("picker")),
|
||||||
"Sushi (Japan)".into(),
|
KeyBinding::new("pageup", menu::SelectFirst, Some("picker")),
|
||||||
"Paella (Spain)".into(),
|
KeyBinding::new("shift-pageup", menu::SelectFirst, Some("picker")),
|
||||||
"Tacos (Mexico)".into(),
|
KeyBinding::new("ctrl-p", menu::SelectPrev, Some("picker")),
|
||||||
"Peking Duck (China)".into(),
|
KeyBinding::new("down", menu::SelectNext, Some("picker")),
|
||||||
"Fish and Chips (UK)".into(),
|
KeyBinding::new("pagedown", menu::SelectLast, Some("picker")),
|
||||||
"Croissant (France)".into(),
|
KeyBinding::new("shift-pagedown", menu::SelectFirst, Some("picker")),
|
||||||
"Bratwurst (Germany)".into(),
|
KeyBinding::new("ctrl-n", menu::SelectNext, Some("picker")),
|
||||||
"Poutine (Canada)".into(),
|
KeyBinding::new("cmd-up", menu::SelectFirst, Some("picker")),
|
||||||
"Chicken Tikka Masala (India)".into(),
|
KeyBinding::new("cmd-down", menu::SelectLast, Some("picker")),
|
||||||
"Feijoada (Brazil)".into(),
|
KeyBinding::new("enter", menu::Confirm, Some("picker")),
|
||||||
"Kimchi (Korea)".into(),
|
KeyBinding::new("ctrl-enter", menu::ShowContextMenu, Some("picker")),
|
||||||
"Borscht (Ukraine)".into(),
|
KeyBinding::new("cmd-enter", menu::SecondaryConfirm, Some("picker")),
|
||||||
"Falafel (Middle East)".into(),
|
KeyBinding::new("escape", menu::Cancel, Some("picker")),
|
||||||
"Baklava (Turkey)".into(),
|
KeyBinding::new("ctrl-c", menu::Cancel, Some("picker")),
|
||||||
"Shepherd's Pie (Ireland)".into(),
|
]);
|
||||||
"Rendang (Indonesia)".into(),
|
|
||||||
"Kebab (Middle East)".into(),
|
let fh = cx.focus_handle();
|
||||||
"Ceviche (Peru)".into(),
|
cx.focus(&fh);
|
||||||
"Pierogi (Poland)".into(),
|
|
||||||
"Churrasco (Brazil)".into(),
|
PickerStory {
|
||||||
"Moussaka (Greece)".into(),
|
focus_handle: fh,
|
||||||
"Lasagna (Italy)".into(),
|
candidates: vec![
|
||||||
"Pad Thai (Thailand)".into(),
|
"Baguette (France)".into(),
|
||||||
"Pho (Vietnam)".into(),
|
"Baklava (Turkey)".into(),
|
||||||
],
|
"Beef Wellington (UK)".into(),
|
||||||
|
"Biryani (India)".into(),
|
||||||
|
"Borscht (Ukraine)".into(),
|
||||||
|
"Bratwurst (Germany)".into(),
|
||||||
|
"Bulgogi (Korea)".into(),
|
||||||
|
"Burrito (USA)".into(),
|
||||||
|
"Ceviche (Peru)".into(),
|
||||||
|
"Chicken Tikka Masala (India)".into(),
|
||||||
|
"Churrasco (Brazil)".into(),
|
||||||
|
"Couscous (North Africa)".into(),
|
||||||
|
"Croissant (France)".into(),
|
||||||
|
"Dim Sum (China)".into(),
|
||||||
|
"Empanada (Argentina)".into(),
|
||||||
|
"Fajitas (Mexico)".into(),
|
||||||
|
"Falafel (Middle East)".into(),
|
||||||
|
"Feijoada (Brazil)".into(),
|
||||||
|
"Fish and Chips (UK)".into(),
|
||||||
|
"Fondue (Switzerland)".into(),
|
||||||
|
"Goulash (Hungary)".into(),
|
||||||
|
"Haggis (Scotland)".into(),
|
||||||
|
"Kebab (Middle East)".into(),
|
||||||
|
"Kimchi (Korea)".into(),
|
||||||
|
"Lasagna (Italy)".into(),
|
||||||
|
"Maple Syrup Pancakes (Canada)".into(),
|
||||||
|
"Moussaka (Greece)".into(),
|
||||||
|
"Pad Thai (Thailand)".into(),
|
||||||
|
"Paella (Spain)".into(),
|
||||||
|
"Pancakes (USA)".into(),
|
||||||
|
"Pasta Carbonara (Italy)".into(),
|
||||||
|
"Pavlova (Australia)".into(),
|
||||||
|
"Peking Duck (China)".into(),
|
||||||
|
"Pho (Vietnam)".into(),
|
||||||
|
"Pierogi (Poland)".into(),
|
||||||
|
"Pizza (Italy)".into(),
|
||||||
|
"Poutine (Canada)".into(),
|
||||||
|
"Pretzel (Germany)".into(),
|
||||||
|
"Ramen (Japan)".into(),
|
||||||
|
"Rendang (Indonesia)".into(),
|
||||||
|
"Sashimi (Japan)".into(),
|
||||||
|
"Satay (Indonesia)".into(),
|
||||||
|
"Shepherd's Pie (Ireland)".into(),
|
||||||
|
"Sushi (Japan)".into(),
|
||||||
|
"Tacos (Mexico)".into(),
|
||||||
|
"Tandoori Chicken (India)".into(),
|
||||||
|
"Tortilla (Spain)".into(),
|
||||||
|
"Tzatziki (Greece)".into(),
|
||||||
|
"Wiener Schnitzel (Austria)".into(),
|
||||||
|
],
|
||||||
|
selected_ix: 0,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,9 +141,11 @@ impl Render for PickerStory {
|
|||||||
type Element = Div<Self>;
|
type Element = Div<Self>;
|
||||||
|
|
||||||
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
|
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
|
||||||
|
let theme = cx.theme();
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.text_color(red())
|
.bg(theme.styles.colors.background)
|
||||||
.size_full()
|
.size_full()
|
||||||
.child(Picker::new("picker_story"))
|
.child(Picker::new("picker_story", self.focus_handle.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use gpui::{
|
use gpui::{
|
||||||
div, px, Component, Div, ParentElement, Render, SharedString, StatefulInteraction, Styled,
|
div, px, Component, Div, ParentElement, Render, SharedString, StatefulInteractivity, Styled,
|
||||||
View, VisualContext, WindowContext,
|
View, VisualContext, WindowContext,
|
||||||
};
|
};
|
||||||
use theme2::ActiveTheme;
|
use theme2::ActiveTheme;
|
||||||
@ -13,7 +13,7 @@ impl ScrollStory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Render for ScrollStory {
|
impl Render for ScrollStory {
|
||||||
type Element = Div<Self, StatefulInteraction<Self>>;
|
type Element = Div<Self, StatefulInteractivity<Self>>;
|
||||||
|
|
||||||
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
|
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
|
||||||
let theme = cx.theme();
|
let theme = cx.theme();
|
||||||
|
@ -128,7 +128,7 @@ impl<V: 'static> Checkbox<V> {
|
|||||||
// click area for the checkbox.
|
// click area for the checkbox.
|
||||||
.size_5()
|
.size_5()
|
||||||
// Because we've enlarged the click area, we need to create a
|
// Because we've enlarged the click area, we need to create a
|
||||||
// `group` to pass down interaction events to the checkbox.
|
// `group` to pass down interactivity events to the checkbox.
|
||||||
.group(group_id.clone())
|
.group(group_id.clone())
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
@ -148,7 +148,7 @@ impl<V: 'static> Checkbox<V> {
|
|||||||
.bg(bg_color)
|
.bg(bg_color)
|
||||||
.border()
|
.border()
|
||||||
.border_color(border_color)
|
.border_color(border_color)
|
||||||
// We only want the interaction states to fire when we
|
// We only want the interactivity states to fire when we
|
||||||
// are in a checkbox that isn't disabled.
|
// are in a checkbox that isn't disabled.
|
||||||
.when(!self.disabled, |this| {
|
.when(!self.disabled, |this| {
|
||||||
// Here instead of `hover()` we use `group_hover()`
|
// Here instead of `hover()` we use `group_hover()`
|
||||||
|
@ -37,4 +37,3 @@
|
|||||||
|
|
||||||
((symbol) @comment
|
((symbol) @comment
|
||||||
(#match? @comment "^#[cC][iIsS]$"))
|
(#match? @comment "^#[cC][iIsS]$"))
|
||||||
|
|
||||||
|
@ -37,4 +37,3 @@
|
|||||||
|
|
||||||
((symbol) @comment
|
((symbol) @comment
|
||||||
(#match? @comment "^#[cC][iIsS]$"))
|
(#match? @comment "^#[cC][iIsS]$"))
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user