Compare commits
3 Commits
thread3
...
gpui-butto
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1711f91f6 | ||
|
|
8fd2316deb | ||
|
|
7357796969 |
@@ -1,14 +1,15 @@
|
|||||||
use gpui::{
|
use gpui::{
|
||||||
App, Application, Bounds, Context, SharedString, Window, WindowBounds, WindowOptions, div,
|
App, Application, Bounds, Context, SharedString, Window, WindowBounds, WindowOptions, button,
|
||||||
prelude::*, px, rgb, size,
|
div, prelude::*, px, rgb, size,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HelloWorld {
|
struct HelloWorld {
|
||||||
text: SharedString,
|
text: SharedString,
|
||||||
|
count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for HelloWorld {
|
impl Render for HelloWorld {
|
||||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
.flex_col()
|
.flex_col()
|
||||||
@@ -23,6 +24,14 @@ impl Render for HelloWorld {
|
|||||||
.text_xl()
|
.text_xl()
|
||||||
.text_color(rgb(0xffffff))
|
.text_color(rgb(0xffffff))
|
||||||
.child(format!("Hello, {}!", &self.text))
|
.child(format!("Hello, {}!", &self.text))
|
||||||
|
.child(
|
||||||
|
button("counter-button")
|
||||||
|
.on_click(Box::new(cx.listener(move |this, _, _, cx| {
|
||||||
|
this.count += 1;
|
||||||
|
cx.notify();
|
||||||
|
})))
|
||||||
|
.child(div().child(format!("Count: {}", &self.count))),
|
||||||
|
)
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
@@ -97,6 +106,7 @@ fn main() {
|
|||||||
|_, cx| {
|
|_, cx| {
|
||||||
cx.new(|_| HelloWorld {
|
cx.new(|_| HelloWorld {
|
||||||
text: "World".into(),
|
text: "World".into(),
|
||||||
|
count: 0,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
187
crates/gpui/src/elements/button.rs
Normal file
187
crates/gpui/src/elements/button.rs
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
#![allow(missing_docs)]
|
||||||
|
use super::{FocusableElement, InteractiveElement, Interactivity, StatefulInteractiveElement};
|
||||||
|
use crate::{
|
||||||
|
AbsoluteLength, AnyElement, App, BorderStyle, ClickEvent, CornersRefinement, Edges,
|
||||||
|
EdgesRefinement, Element, ElementId, GlobalElementId, Hitbox, IntoElement, LayoutId,
|
||||||
|
ParentElement, SharedString, StyleRefinement, Styled, TextStyleRefinement, Window,
|
||||||
|
colors::Colors, px,
|
||||||
|
};
|
||||||
|
use refineable::Refineable;
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
use taffy::FlexDirection;
|
||||||
|
use util::default;
|
||||||
|
|
||||||
|
pub fn button(id: impl Into<ElementId>) -> Button {
|
||||||
|
Button {
|
||||||
|
id: id.into(),
|
||||||
|
interactivity: Interactivity::default(),
|
||||||
|
children: SmallVec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Button {
|
||||||
|
id: ElementId,
|
||||||
|
interactivity: Interactivity,
|
||||||
|
children: SmallVec<[AnyElement; 2]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Element for Button {
|
||||||
|
type RequestLayoutState = ();
|
||||||
|
type PrepaintState = Option<Hitbox>;
|
||||||
|
|
||||||
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
Some(self.id.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut App,
|
||||||
|
) -> (LayoutId, Self::RequestLayoutState) {
|
||||||
|
// Get a LayoutId, an identifier Taffy uses to indicate a unique layout element
|
||||||
|
let layout_id =
|
||||||
|
self.interactivity
|
||||||
|
.request_layout(global_id, window, cx, |style, window, cx| {
|
||||||
|
let mut child_layout_ids = Vec::new();
|
||||||
|
for child in &mut self.children {
|
||||||
|
let child_layout_id = child.request_layout(window, cx);
|
||||||
|
child_layout_ids.push(child_layout_id);
|
||||||
|
}
|
||||||
|
window.request_layout(style, child_layout_ids, cx)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize the layout state
|
||||||
|
let layout_state = ();
|
||||||
|
|
||||||
|
(layout_id, layout_state)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepaint(
|
||||||
|
&mut self,
|
||||||
|
global_id: Option<&crate::GlobalElementId>,
|
||||||
|
bounds: crate::Bounds<crate::Pixels>,
|
||||||
|
_request_layout: &mut Self::RequestLayoutState,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut App,
|
||||||
|
) -> Self::PrepaintState {
|
||||||
|
if let Some(handle) = self.interactivity.scroll_anchor.as_ref() {
|
||||||
|
*handle.last_origin.borrow_mut() = bounds.origin - window.element_offset();
|
||||||
|
}
|
||||||
|
let content_size = bounds.size;
|
||||||
|
|
||||||
|
// Prepaint children
|
||||||
|
for child in &mut self.children {
|
||||||
|
child.prepaint(window, cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.interactivity.prepaint(
|
||||||
|
global_id,
|
||||||
|
bounds,
|
||||||
|
content_size,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
|_style, _scroll_offset, hitbox, _window, _cx| hitbox,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint(
|
||||||
|
&mut self,
|
||||||
|
global_id: Option<&crate::GlobalElementId>,
|
||||||
|
bounds: crate::Bounds<crate::Pixels>,
|
||||||
|
_request_layout: &mut Self::RequestLayoutState,
|
||||||
|
hitbox: &mut Option<Hitbox>,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut App,
|
||||||
|
) {
|
||||||
|
let colors = Colors::for_appearance(window);
|
||||||
|
let text_style = self.text_style().clone();
|
||||||
|
let abs_px = |number: f32| AbsoluteLength::Pixels(px(number));
|
||||||
|
|
||||||
|
let mut text_style = if let Some(style) = text_style {
|
||||||
|
style.clone()
|
||||||
|
} else {
|
||||||
|
TextStyleRefinement::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_style = StyleRefinement {
|
||||||
|
background: Some(colors.container.into()),
|
||||||
|
text: Some(TextStyleRefinement {
|
||||||
|
color: Some(colors.text.into()),
|
||||||
|
font_size: Some(px(13.).into()),
|
||||||
|
..text_style
|
||||||
|
}),
|
||||||
|
border_color: Some(colors.border.into()),
|
||||||
|
border_style: Some(BorderStyle::Solid),
|
||||||
|
border_widths: EdgesRefinement {
|
||||||
|
top: Some(abs_px(1.)),
|
||||||
|
right: Some(abs_px(1.)),
|
||||||
|
bottom: Some(abs_px(1.)),
|
||||||
|
left: Some(abs_px(1.)),
|
||||||
|
},
|
||||||
|
corner_radii: CornersRefinement {
|
||||||
|
top_left: Some(abs_px(4.)),
|
||||||
|
top_right: Some(abs_px(4.)),
|
||||||
|
bottom_left: Some(abs_px(4.)),
|
||||||
|
bottom_right: Some(abs_px(4.)),
|
||||||
|
},
|
||||||
|
flex_direction: Some(FlexDirection::Row),
|
||||||
|
flex_grow: Some(0.),
|
||||||
|
..StyleRefinement::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let refined = self.style().refine(&new_style);
|
||||||
|
|
||||||
|
self.interactivity.paint(
|
||||||
|
global_id,
|
||||||
|
bounds,
|
||||||
|
hitbox.as_ref(),
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
|style, window, cx| {
|
||||||
|
for child in &mut self.children {
|
||||||
|
child.paint(window, cx);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoElement for Button {
|
||||||
|
type Element = Self;
|
||||||
|
|
||||||
|
fn into_element(self) -> Self::Element {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Styled for Button {
|
||||||
|
fn style(&mut self) -> &mut StyleRefinement {
|
||||||
|
&mut self.interactivity.base_style
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InteractiveElement for Button {
|
||||||
|
fn interactivity(&mut self) -> &mut Interactivity {
|
||||||
|
&mut self.interactivity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl StatefulInteractiveElement for Button {}
|
||||||
|
impl FocusableElement for Button {}
|
||||||
|
|
||||||
|
impl ParentElement for Button {
|
||||||
|
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
|
||||||
|
self.children.extend(elements)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Button {
|
||||||
|
pub fn on_click(
|
||||||
|
mut self,
|
||||||
|
callback: Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>,
|
||||||
|
) -> Self {
|
||||||
|
self.interactivity
|
||||||
|
.on_click(move |event, window, cx| callback(event, window, cx));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2877,8 +2877,8 @@ where
|
|||||||
/// Contrary to [ScrollHandle::scroll_to_item], an anchored element does not have to be an immediate child of the parent.
|
/// Contrary to [ScrollHandle::scroll_to_item], an anchored element does not have to be an immediate child of the parent.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ScrollAnchor {
|
pub struct ScrollAnchor {
|
||||||
handle: ScrollHandle,
|
pub(super) handle: ScrollHandle,
|
||||||
last_origin: Rc<RefCell<Point<Pixels>>>,
|
pub(super) last_origin: Rc<RefCell<Point<Pixels>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScrollAnchor {
|
impl ScrollAnchor {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
mod anchored;
|
mod anchored;
|
||||||
mod animation;
|
mod animation;
|
||||||
|
mod button;
|
||||||
mod canvas;
|
mod canvas;
|
||||||
mod deferred;
|
mod deferred;
|
||||||
mod div;
|
mod div;
|
||||||
@@ -13,6 +14,7 @@ mod uniform_list;
|
|||||||
|
|
||||||
pub use anchored::*;
|
pub use anchored::*;
|
||||||
pub use animation::*;
|
pub use animation::*;
|
||||||
|
pub use button::*;
|
||||||
pub use canvas::*;
|
pub use canvas::*;
|
||||||
pub use deferred::*;
|
pub use deferred::*;
|
||||||
pub use div::*;
|
pub use div::*;
|
||||||
|
|||||||
Reference in New Issue
Block a user