checkbox: Add children to Radio, Checkbox to display long texts. (#724)
This change is going to solve the wrapped text line-height. Before this change, the Label is must set `line-height: 100%` to render at same line with the checkbox. But if there have a long text in label, wrapped lines need more line-height to leave lines spaces. But if we set line-height over the 100%, that the checkbox will not align horizontal center. So, this change to use other child to solve this issue, we can set line-height to the child not to the label. <img width="1204" alt="image" src="https://github.com/user-attachments/assets/981cf925-01c7-48d7-9dd2-881c727a1759" />
This commit is contained in:
parent
49e8b06ccb
commit
c98e4f0521
3 changed files with 80 additions and 34 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
use gpui::{
|
use gpui::{
|
||||||
px, App, AppContext, Context, Div, Entity, Focusable, IntoElement, ParentElement, Render,
|
div, px, App, AppContext, Context, Div, Entity, Focusable, IntoElement, ParentElement, Render,
|
||||||
SharedString, Styled, Window,
|
SharedString, Styled, Window,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -205,20 +205,27 @@ impl Render for SwitchStory {
|
||||||
v.check3 = !v.check3;
|
v.check3 = !v.check3;
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
.child(Checkbox::new("longlong-checkbox").w(px(300.)).label(
|
.child(
|
||||||
"The long long label text, \
|
Checkbox::new("longlong-checkbox")
|
||||||
it should wrap when the text is too long.",
|
.w(px(300.))
|
||||||
))
|
.label("The long long label text.")
|
||||||
|
.child(div().text_color(cx.theme().muted_foreground).child(
|
||||||
|
"This is a long long label text that \
|
||||||
|
should wrap when the text is too long.",
|
||||||
|
)),
|
||||||
|
)
|
||||||
.child(
|
.child(
|
||||||
Checkbox::new("longlong-markdown-checkbox")
|
Checkbox::new("longlong-markdown-checkbox")
|
||||||
.w(px(300.))
|
.w(px(300.))
|
||||||
.label(
|
.label("Label with description")
|
||||||
|
.child(div().text_color(cx.theme().muted_foreground).child(
|
||||||
TextView::markdown(
|
TextView::markdown(
|
||||||
"longlong-markdown-checkbox",
|
"longlong-markdown-checkbox",
|
||||||
"The [long long label](https://github.com) text used markdown, \
|
"The [long long label](https://github.com) \
|
||||||
it should wrap when the text is too long.",
|
text used markdown, \
|
||||||
)
|
it should wrap when the text is too long.",
|
||||||
),
|
),
|
||||||
|
)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -269,9 +276,11 @@ impl Render for SwitchStory {
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Radio::new("radio3")
|
Radio::new("radio3")
|
||||||
.label(
|
.label("The long long label text.")
|
||||||
"The long long label text, \
|
.child(
|
||||||
it should wrap when the text is too long.",
|
div().text_color(cx.theme().muted_foreground).child(
|
||||||
|
"This line should wrap when the text is too long.",
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.w(px(300.))
|
.w(px(300.))
|
||||||
.checked(true)
|
.checked(true)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::{h_flex, text::Text, v_flex, ActiveTheme, Disableable, IconName, Selectable};
|
use crate::{h_flex, text::Text, v_flex, ActiveTheme, Disableable, IconName, Selectable};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::FluentBuilder as _, px, relative, svg, App, Div, ElementId, InteractiveElement,
|
div, prelude::FluentBuilder as _, px, relative, svg, AnyElement, App, Div, ElementId,
|
||||||
IntoElement, ParentElement, RenderOnce, StatefulInteractiveElement as _, Styled, Window,
|
InteractiveElement, IntoElement, ParentElement, RenderOnce, StatefulInteractiveElement as _,
|
||||||
|
Styled, Window,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A Checkbox element.
|
/// A Checkbox element.
|
||||||
|
|
@ -10,6 +11,7 @@ pub struct Checkbox {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
base: Div,
|
base: Div,
|
||||||
label: Option<Text>,
|
label: Option<Text>,
|
||||||
|
children: Vec<AnyElement>,
|
||||||
checked: bool,
|
checked: bool,
|
||||||
disabled: bool,
|
disabled: bool,
|
||||||
on_click: Option<Box<dyn Fn(&bool, &mut Window, &mut App) + 'static>>,
|
on_click: Option<Box<dyn Fn(&bool, &mut Window, &mut App) + 'static>>,
|
||||||
|
|
@ -21,6 +23,7 @@ impl Checkbox {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
base: div(),
|
base: div(),
|
||||||
label: None,
|
label: None,
|
||||||
|
children: Vec::new(),
|
||||||
checked: false,
|
checked: false,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
on_click: None,
|
on_click: None,
|
||||||
|
|
@ -66,6 +69,12 @@ impl Selectable for Checkbox {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ParentElement for Checkbox {
|
||||||
|
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
|
||||||
|
self.children.extend(elements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RenderOnce for Checkbox {
|
impl RenderOnce for Checkbox {
|
||||||
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
let (color, icon_color) = if self.disabled {
|
let (color, icon_color) = if self.disabled {
|
||||||
|
|
@ -110,13 +119,26 @@ impl RenderOnce for Checkbox {
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.map(|this| {
|
.child(
|
||||||
if let Some(label) = self.label {
|
v_flex()
|
||||||
this.child(div().size_full().line_height(relative(1.)).child(label))
|
.w_full()
|
||||||
} else {
|
.line_height(relative(1.2))
|
||||||
this
|
.gap_1()
|
||||||
}
|
.map(|this| {
|
||||||
})
|
if let Some(label) = self.label {
|
||||||
|
this.child(
|
||||||
|
div()
|
||||||
|
.size_full()
|
||||||
|
.text_color(cx.theme().foreground)
|
||||||
|
.line_height(relative(1.))
|
||||||
|
.child(label),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.children(self.children),
|
||||||
|
)
|
||||||
.when(self.disabled, |this| {
|
.when(self.disabled, |this| {
|
||||||
this.cursor_not_allowed()
|
this.cursor_not_allowed()
|
||||||
.text_color(cx.theme().muted_foreground)
|
.text_color(cx.theme().muted_foreground)
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ use std::rc::Rc;
|
||||||
|
|
||||||
use crate::{h_flex, text::Text, v_flex, ActiveTheme, AxisExt, IconName};
|
use crate::{h_flex, text::Text, v_flex, ActiveTheme, AxisExt, IconName};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::FluentBuilder, relative, svg, App, Axis, Div, ElementId, InteractiveElement,
|
div, prelude::FluentBuilder, relative, svg, AnyElement, App, Axis, Div, ElementId,
|
||||||
IntoElement, ParentElement, RenderOnce, SharedString, StatefulInteractiveElement,
|
InteractiveElement, IntoElement, ParentElement, RenderOnce, SharedString,
|
||||||
StyleRefinement, Styled, Window,
|
StatefulInteractiveElement, StyleRefinement, Styled, Window,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A Radio element.
|
/// A Radio element.
|
||||||
|
|
@ -15,6 +15,7 @@ pub struct Radio {
|
||||||
base: Div,
|
base: Div,
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
label: Option<Text>,
|
label: Option<Text>,
|
||||||
|
children: Vec<AnyElement>,
|
||||||
checked: bool,
|
checked: bool,
|
||||||
disabled: bool,
|
disabled: bool,
|
||||||
on_click: Option<Box<dyn Fn(&bool, &mut Window, &mut App) + 'static>>,
|
on_click: Option<Box<dyn Fn(&bool, &mut Window, &mut App) + 'static>>,
|
||||||
|
|
@ -26,6 +27,7 @@ impl Radio {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
base: div(),
|
base: div(),
|
||||||
label: None,
|
label: None,
|
||||||
|
children: Vec::new(),
|
||||||
checked: false,
|
checked: false,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
on_click: None,
|
on_click: None,
|
||||||
|
|
@ -59,6 +61,12 @@ impl Styled for Radio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ParentElement for Radio {
|
||||||
|
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
|
||||||
|
self.children.extend(elements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RenderOnce for Radio {
|
impl RenderOnce for Radio {
|
||||||
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
let color = if self.disabled {
|
let color = if self.disabled {
|
||||||
|
|
@ -100,15 +108,22 @@ impl RenderOnce for Radio {
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.when_some(self.label, |this, label| {
|
.child(
|
||||||
this.child(
|
v_flex()
|
||||||
div()
|
.w_full()
|
||||||
.size_full()
|
.line_height(relative(1.2))
|
||||||
.overflow_hidden()
|
.gap_1()
|
||||||
.line_height(relative(1.))
|
.when_some(self.label, |this, label| {
|
||||||
.child(label),
|
this.child(
|
||||||
)
|
div()
|
||||||
})
|
.size_full()
|
||||||
|
.overflow_hidden()
|
||||||
|
.line_height(relative(1.))
|
||||||
|
.child(label),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.children(self.children),
|
||||||
|
)
|
||||||
.when_some(
|
.when_some(
|
||||||
self.on_click.filter(|_| !self.disabled),
|
self.on_click.filter(|_| !self.disabled),
|
||||||
|this, on_click| {
|
|this, on_click| {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue