Fix stories switch.
This commit is contained in:
parent
b70f5d6dc7
commit
11af9900eb
6 changed files with 140 additions and 125 deletions
|
|
@ -138,6 +138,7 @@ impl RenderOnce for Button {
|
||||||
})
|
})
|
||||||
.when(!self.disabled, |this| {
|
.when(!self.disabled, |this| {
|
||||||
this.hover(|this| this.border_color(theme.blue))
|
this.hover(|this| this.border_color(theme.blue))
|
||||||
|
.active(|this| this.bg(theme.blue.lighten(10.0)))
|
||||||
})
|
})
|
||||||
.when_some(
|
.when_some(
|
||||||
self.on_click.filter(|_| !self.disabled),
|
self.on_click.filter(|_| !self.disabled),
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,30 @@
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, ClickEvent, IntoElement, ParentElement as _, Render, Styled as _, ViewContext,
|
div, ClickEvent, IntoElement, ParentElement as _, Render, Styled as _, ViewContext,
|
||||||
VisualContext as _, WindowContext,
|
WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::text_field::TextField;
|
use crate::text_field::TextField;
|
||||||
|
|
||||||
use super::story_case;
|
use super::story_case;
|
||||||
|
|
||||||
pub struct InputStory;
|
pub struct InputStory {
|
||||||
|
input1: TextField,
|
||||||
|
input2: TextField,
|
||||||
|
}
|
||||||
|
|
||||||
impl InputStory {
|
impl InputStory {
|
||||||
|
pub(crate) fn new(cx: &mut ViewContext<Self>) -> Self {
|
||||||
|
let input1 = TextField::new("Enter text here...", false, cx);
|
||||||
|
input1
|
||||||
|
.view
|
||||||
|
.update(cx, |text_view, cx| text_view.set_text("Hello 世界", cx));
|
||||||
|
|
||||||
|
Self {
|
||||||
|
input1,
|
||||||
|
input2: TextField::new("Enter text here...", true, cx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn on_change(ev: &ClickEvent, cx: &mut WindowContext) {
|
fn on_change(ev: &ClickEvent, cx: &mut WindowContext) {
|
||||||
println!("Input changed: {:?}", ev);
|
println!("Input changed: {:?}", ev);
|
||||||
|
|
@ -18,14 +33,17 @@ impl InputStory {
|
||||||
|
|
||||||
impl Render for InputStory {
|
impl Render for InputStory {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
|
let input1 = self.input1.clone();
|
||||||
|
let input2 = self.input2.clone();
|
||||||
|
|
||||||
story_case("Input", "A text input field.").child(
|
story_case("Input", "A text input field.").child(
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
.flex_col()
|
.flex_col()
|
||||||
.justify_start()
|
.justify_start()
|
||||||
.gap_3()
|
.gap_3()
|
||||||
.child(cx.new_view(|cx| TextField::new("Enter text here...", false, cx)))
|
.child(input1)
|
||||||
.child(cx.new_view(|cx| TextField::new("Enter text here...", false, cx))),
|
.child(input2),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ use core::fmt;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::FluentBuilder as _, px, AnyElement, ElementId, IntoElement, ParentElement,
|
div, prelude::FluentBuilder as _, px, AnyElement, IntoElement, ParentElement, Render,
|
||||||
Render, RenderOnce, SharedString, Styled as _, View, ViewContext, VisualContext, WindowContext,
|
RenderOnce, SharedString, Styled as _, View, ViewContext, VisualContext, WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod button_story;
|
mod button_story;
|
||||||
|
|
@ -76,22 +76,26 @@ impl Display for StoryType {
|
||||||
|
|
||||||
pub struct Stories {
|
pub struct Stories {
|
||||||
active: StoryType,
|
active: StoryType,
|
||||||
|
|
||||||
|
button_story: View<ButtonStory>,
|
||||||
|
input_story: View<InputStory>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stories {
|
impl Stories {
|
||||||
fn new() -> Self {
|
fn new(cx: &mut ViewContext<Self>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
active: StoryType::Button,
|
active: StoryType::Button,
|
||||||
|
button_story: cx.new_view(|cx| ButtonStory {}),
|
||||||
|
input_story: cx.new_view(InputStory::new),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view(cx: &mut WindowContext) -> View<Self> {
|
pub fn view(cx: &mut WindowContext) -> View<Self> {
|
||||||
cx.new_view(|_cx| Self::new())
|
cx.new_view(Self::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_active(&mut self, ty: StoryType, cx: &mut ViewContext<Self>) {
|
fn set_active(&mut self, ty: StoryType, cx: &mut ViewContext<Self>) {
|
||||||
self.active = ty;
|
self.active = ty;
|
||||||
dbg!("--------------------- set_active: {}", ty);
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,20 +115,12 @@ impl Stories {
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> impl IntoElement {
|
) -> impl IntoElement {
|
||||||
let name = format!("{}", ty);
|
let name = format!("{}", ty);
|
||||||
Button::new(SharedString::from(id.to_string()), name)
|
|
||||||
.on_click(move |_e, cx| {
|
|
||||||
dbg!("--------------------- on_click: {}", ty);
|
|
||||||
// cx.update_view(self, |this| {
|
|
||||||
// this.set_active(ty, cx);
|
|
||||||
// });
|
|
||||||
})
|
|
||||||
.style(crate::button::ButtonStyle::Secondary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Stories {
|
Button::new(SharedString::from(id.to_string()), name)
|
||||||
fn default() -> Self {
|
.on_click(cx.listener(move |this, _, cx| {
|
||||||
Self::new()
|
this.set_active(ty, cx);
|
||||||
|
}))
|
||||||
|
.style(crate::button::ButtonStyle::Secondary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -136,8 +132,8 @@ impl Render for Stories {
|
||||||
.gap_4()
|
.gap_4()
|
||||||
.child(self.render_story_buttons(cx))
|
.child(self.render_story_buttons(cx))
|
||||||
.map(|this| match self.active {
|
.map(|this| match self.active {
|
||||||
StoryType::Button => this.child(cx.new_view(|_cx| ButtonStory {})),
|
StoryType::Button => this.child(self.button_story.clone()),
|
||||||
StoryType::Input => this.child(cx.new_view(|_cx| InputStory {})),
|
StoryType::Input => this.child(self.input_story.clone()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,16 @@ mod text_view;
|
||||||
use crate::{disableable::Disableable, theme::Theme};
|
use crate::{disableable::Disableable, theme::Theme};
|
||||||
use blink_manager::BlinkManager;
|
use blink_manager::BlinkManager;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, px, relative, ClipboardItem, Context, Element, EventEmitter, FocusHandle, HighlightStyle,
|
div, ClipboardItem, Context, EventEmitter, FocusHandle, InteractiveElement, IntoElement,
|
||||||
InteractiveElement, InteractiveText, IntoElement, KeyDownEvent, Model, ParentElement, Pixels,
|
KeyDownEvent, Model, ParentElement, Render, RenderOnce, Styled, View, ViewContext,
|
||||||
Render, Style, Styled, StyledText, TextStyle, View, ViewContext, VisualContext, WindowContext,
|
WindowContext,
|
||||||
};
|
};
|
||||||
use std::{ops::Range, time::Duration};
|
use std::time::Duration;
|
||||||
use text_view::TextView;
|
use text_view::TextView;
|
||||||
|
|
||||||
const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
|
const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, IntoElement)]
|
||||||
pub struct TextField {
|
pub struct TextField {
|
||||||
focus_handle: FocusHandle,
|
focus_handle: FocusHandle,
|
||||||
disable: bool,
|
disable: bool,
|
||||||
|
|
@ -23,14 +23,14 @@ pub struct TextField {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextField {
|
impl TextField {
|
||||||
pub fn new(placeholder: &str, disable: bool, cx: &mut ViewContext<Self>) -> Self {
|
pub fn new(placeholder: &str, disable: bool, cx: &mut WindowContext) -> Self {
|
||||||
let focus_handle = cx.focus_handle();
|
let focus_handle = cx.focus_handle();
|
||||||
let view = TextView::init(cx, &focus_handle, placeholder, disable);
|
let view = TextView::init(cx, &focus_handle, placeholder, disable);
|
||||||
|
|
||||||
let blink_manager = cx.new_model(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
|
let blink_manager = cx.new_model(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
|
||||||
|
|
||||||
cx.on_focus(&focus_handle, Self::handle_focus).detach();
|
// cx.on_focus(&focus_handle, Self::handle_focus).detach();
|
||||||
cx.on_blur(&focus_handle, Self::handle_blur).detach();
|
// cx.on_blur(&focus_handle, Self::handle_blur).detach();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
focus_handle,
|
focus_handle,
|
||||||
|
|
@ -67,42 +67,34 @@ impl Disableable for TextField {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl RenderOnce for TextField {
|
||||||
impl Render for TextField {
|
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
||||||
fn render<'a>(&mut self, cx: &mut ViewContext<'a, Self>) -> impl IntoElement {
|
|
||||||
cx.focus(&self.focus_handle);
|
cx.focus(&self.focus_handle);
|
||||||
let theme = cx.global::<Theme>();
|
let theme = cx.global::<Theme>();
|
||||||
|
|
||||||
let text_view = self.view.clone();
|
let view = self.view.clone();
|
||||||
let text_view1 = text_view.clone();
|
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.border_color(if self.focus_handle.is_focused(cx) {
|
|
||||||
theme.blue
|
|
||||||
} else {
|
|
||||||
theme.crust
|
|
||||||
})
|
|
||||||
.border_1()
|
|
||||||
.track_focus(&self.focus_handle)
|
.track_focus(&self.focus_handle)
|
||||||
.on_key_down(move |ev, cx| {
|
.on_key_down(move |ev, cx| {
|
||||||
text_view1.update(cx, |editor, cx| {
|
self.view.update(cx, |text_view, cx| {
|
||||||
let prev = editor.text.clone();
|
let prev = text_view.text.clone();
|
||||||
cx.emit(TextEvent::KeyDown(ev.clone()));
|
cx.emit(TextEvent::KeyDown(ev.clone()));
|
||||||
let keystroke = &ev.keystroke.key;
|
let keystroke = &ev.keystroke.key;
|
||||||
let chars = editor.text.chars().collect::<Vec<char>>();
|
let chars = text_view.text.chars().collect::<Vec<char>>();
|
||||||
let m = ev.keystroke.modifiers.secondary();
|
let m = ev.keystroke.modifiers.secondary();
|
||||||
|
|
||||||
dbg!("---------------- {:?}", ev);
|
dbg!(&text_view.text, &text_view.selection);
|
||||||
|
|
||||||
if m {
|
if m {
|
||||||
match keystroke.as_str() {
|
match keystroke.as_str() {
|
||||||
"a" => {
|
"a" => {
|
||||||
editor.selection = 0..chars.len();
|
text_view.selection = 0..chars.len();
|
||||||
}
|
}
|
||||||
"c" => {
|
"c" => {
|
||||||
// if !editor.masked {
|
// if !text_view.masked {
|
||||||
let selected_text =
|
let selected_text =
|
||||||
chars[editor.selection.clone()].iter().collect();
|
chars[text_view.selection.clone()].iter().collect();
|
||||||
cx.write_to_clipboard(ClipboardItem::new(selected_text));
|
cx.write_to_clipboard(ClipboardItem::new(selected_text));
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
@ -110,96 +102,107 @@ impl Render for TextField {
|
||||||
let clipboard = cx.read_from_clipboard();
|
let clipboard = cx.read_from_clipboard();
|
||||||
if let Some(clipboard) = clipboard {
|
if let Some(clipboard) = clipboard {
|
||||||
let text = clipboard.text();
|
let text = clipboard.text();
|
||||||
editor.text.replace_range(
|
text_view.text.replace_range(
|
||||||
editor.char_range_to_text_range(&editor.text),
|
text_view.char_range_to_text_range(&text_view.text),
|
||||||
text,
|
text,
|
||||||
);
|
);
|
||||||
let i = editor.selection.start + text.chars().count();
|
let i = text_view.selection.start + text.chars().count();
|
||||||
editor.selection = i..i;
|
text_view.selection = i..i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"x" => {
|
"x" => {
|
||||||
let selected_text =
|
let selected_text =
|
||||||
chars[editor.selection.clone()].iter().collect();
|
chars[text_view.selection.clone()].iter().collect();
|
||||||
cx.write_to_clipboard(ClipboardItem::new(selected_text));
|
cx.write_to_clipboard(ClipboardItem::new(selected_text));
|
||||||
editor.text.replace_range(
|
text_view.text.replace_range(
|
||||||
editor.char_range_to_text_range(&editor.text),
|
text_view.char_range_to_text_range(&text_view.text),
|
||||||
"",
|
"",
|
||||||
);
|
);
|
||||||
editor.selection.end = editor.selection.start;
|
text_view.selection.end = text_view.selection.start;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
} else if !ev.keystroke.ime_key.clone().unwrap_or_default().is_empty() {
|
} else if !ev.keystroke.ime_key.clone().unwrap_or_default().is_empty() {
|
||||||
let ime_key = &ev.keystroke.ime_key.clone().unwrap_or_default();
|
let ime_key = &ev.keystroke.ime_key.clone().unwrap_or_default();
|
||||||
editor
|
text_view.text.replace_range(
|
||||||
.text
|
text_view.char_range_to_text_range(&text_view.text),
|
||||||
.replace_range(editor.char_range_to_text_range(&editor.text), ime_key);
|
ime_key,
|
||||||
let i = editor.selection.start + ime_key.chars().count();
|
);
|
||||||
editor.selection = i..i;
|
let i = text_view.selection.start + ime_key.chars().count();
|
||||||
|
text_view.selection = i..i;
|
||||||
} else {
|
} else {
|
||||||
match keystroke.as_str() {
|
match keystroke.as_str() {
|
||||||
"left" => {
|
"left" => {
|
||||||
if editor.selection.start > 0 {
|
if text_view.selection.start > 0 {
|
||||||
let i = if editor.selection.start == editor.selection.end {
|
let i = if text_view.selection.start == text_view.selection.end
|
||||||
editor.selection.start - 1
|
{
|
||||||
|
text_view.selection.start - 1
|
||||||
} else {
|
} else {
|
||||||
editor.selection.start
|
text_view.selection.start
|
||||||
};
|
};
|
||||||
editor.selection = i..i;
|
text_view.selection = i..i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"right" => {
|
"right" => {
|
||||||
if editor.selection.end < editor.text.len() {
|
if text_view.selection.end < text_view.text.len() {
|
||||||
let i = if editor.selection.start == editor.selection.end {
|
let i = if text_view.selection.start == text_view.selection.end
|
||||||
editor.selection.end + 1
|
{
|
||||||
|
text_view.selection.end + 1
|
||||||
} else {
|
} else {
|
||||||
editor.selection.end
|
text_view.selection.end
|
||||||
};
|
};
|
||||||
editor.selection = i..i;
|
text_view.selection = i..i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"backspace" => {
|
"backspace" => {
|
||||||
if editor.text.is_empty() && !ev.is_held {
|
if text_view.text.is_empty() && !ev.is_held {
|
||||||
// cx.emit(TextEvent::Back);
|
// cx.emit(TextEvent::Back);
|
||||||
} else if editor.selection.start == editor.selection.end
|
} else if text_view.selection.start == text_view.selection.end
|
||||||
&& editor.selection.start > 0
|
&& text_view.selection.start > 0
|
||||||
{
|
{
|
||||||
let i = (editor.selection.start - 1).min(chars.len());
|
let i = (text_view.selection.start - 1).min(chars.len());
|
||||||
editor.text = chars[0..i].iter().collect::<String>()
|
text_view.text = chars[0..i].iter().collect::<String>()
|
||||||
+ &(chars[editor.selection.end.min(chars.len())..]
|
+ &(chars[text_view.selection.end.min(chars.len())..]
|
||||||
.iter()
|
.iter()
|
||||||
.collect::<String>());
|
.collect::<String>());
|
||||||
editor.selection = i..i;
|
text_view.selection = i..i;
|
||||||
} else {
|
} else {
|
||||||
editor.text.replace_range(
|
text_view.text.replace_range(
|
||||||
editor.char_range_to_text_range(&editor.text),
|
text_view.char_range_to_text_range(&text_view.text),
|
||||||
"",
|
"",
|
||||||
);
|
);
|
||||||
editor.selection.end = editor.selection.start;
|
text_view.selection.end = text_view.selection.start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"enter" => {
|
"enter" => {
|
||||||
if ev.keystroke.modifiers.shift {
|
if ev.keystroke.modifiers.shift {
|
||||||
editor.text.insert(
|
text_view.text.insert(
|
||||||
editor.char_range_to_text_range(&editor.text).start,
|
text_view.char_range_to_text_range(&text_view.text).start,
|
||||||
'\n',
|
'\n',
|
||||||
);
|
);
|
||||||
let i = editor.selection.start + 1;
|
let i = text_view.selection.start + 1;
|
||||||
editor.selection = i..i;
|
text_view.selection = i..i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if prev != editor.text {
|
|
||||||
|
if prev != text_view.text {
|
||||||
cx.emit(TextEvent::Input {
|
cx.emit(TextEvent::Input {
|
||||||
text: editor.text.clone(),
|
text: text_view.text.clone(),
|
||||||
});
|
});
|
||||||
|
dbg!(&text_view.text, &text_view.selection);
|
||||||
}
|
}
|
||||||
cx.notify();
|
cx.notify();
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
.border_color(if self.focus_handle.is_focused(cx) {
|
||||||
|
theme.blue
|
||||||
|
} else {
|
||||||
|
theme.crust
|
||||||
|
})
|
||||||
|
.border_1()
|
||||||
.rounded_sm()
|
.rounded_sm()
|
||||||
.py_1p5()
|
.py_1p5()
|
||||||
.px_3()
|
.px_3()
|
||||||
|
|
@ -209,7 +212,7 @@ impl Render for TextField {
|
||||||
} else {
|
} else {
|
||||||
theme.base
|
theme.base
|
||||||
})
|
})
|
||||||
.child(text_view)
|
.child(view)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,14 @@
|
||||||
use std::{ops::Range, time::Duration};
|
use std::ops::Range;
|
||||||
|
|
||||||
use gpui::{
|
|
||||||
div, px, relative, ClipboardItem, Context, Element, EventEmitter, FocusHandle, HighlightStyle,
|
|
||||||
InteractiveElement, InteractiveText, IntoElement, KeyDownEvent, Model, ParentElement, Pixels,
|
|
||||||
Render, Style, Styled, StyledText, TextStyle, View, ViewContext, VisualContext, WindowContext,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{disableable::Disableable, hls, theme::Theme};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
blink_manager::BlinkManager, cursor_layout::CursorLayout, TextEvent, CURSOR_BLINK_INTERVAL,
|
blink_manager::BlinkManager, cursor_layout::CursorLayout, TextEvent, CURSOR_BLINK_INTERVAL,
|
||||||
};
|
};
|
||||||
|
use crate::{hls, theme::Theme};
|
||||||
|
use gpui::{
|
||||||
|
px, relative, Context, Element, EventEmitter, FocusHandle, HighlightStyle, InteractiveText,
|
||||||
|
IntoElement, Model, Render, Style, StyledText, TextStyle, View, ViewContext, VisualContext,
|
||||||
|
WindowContext,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct TextView {
|
pub struct TextView {
|
||||||
pub text: String,
|
pub text: String,
|
||||||
|
|
@ -20,6 +18,7 @@ pub struct TextView {
|
||||||
pub disable: bool,
|
pub disable: bool,
|
||||||
pub blink_manager: Model<BlinkManager>,
|
pub blink_manager: Model<BlinkManager>,
|
||||||
pub cursor: CursorLayout,
|
pub cursor: CursorLayout,
|
||||||
|
pub masked: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventEmitter<TextEvent> for TextView {}
|
impl EventEmitter<TextEvent> for TextView {}
|
||||||
|
|
@ -49,6 +48,7 @@ impl TextView {
|
||||||
blink_manager,
|
blink_manager,
|
||||||
cursor,
|
cursor,
|
||||||
disable,
|
disable,
|
||||||
|
masked: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let view = cx.new_view(|cx| {
|
let view = cx.new_view(|cx| {
|
||||||
|
|
@ -74,7 +74,7 @@ impl TextView {
|
||||||
&view,
|
&view,
|
||||||
move |subscriber, emitter: &TextEvent, cx| match emitter {
|
move |subscriber, emitter: &TextEvent, cx| match emitter {
|
||||||
TextEvent::Input { text: _ } => {
|
TextEvent::Input { text: _ } => {
|
||||||
subscriber.update(cx, |editor, cx| {
|
subscriber.update(cx, |editor, _cx| {
|
||||||
editor.word_click = (0, 0);
|
editor.word_click = (0, 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -184,7 +184,7 @@ impl Element for TextView {
|
||||||
let mut style = Style::default();
|
let mut style = Style::default();
|
||||||
style.size.width = relative(1.).into();
|
style.size.width = relative(1.).into();
|
||||||
style.size.height = relative(24.).into();
|
style.size.height = relative(24.).into();
|
||||||
|
dbg!("--------- request_layout", &style);
|
||||||
(cx.request_layout(style, None), ())
|
(cx.request_layout(style, None), ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -216,6 +216,7 @@ impl Render for TextView {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
let theme = cx.global::<Theme>();
|
let theme = cx.global::<Theme>();
|
||||||
let mut text = self.text.clone();
|
let mut text = self.text.clone();
|
||||||
|
dbg!("textView render", &text);
|
||||||
|
|
||||||
let mut style = TextStyle {
|
let mut style = TextStyle {
|
||||||
color: theme.text,
|
color: theme.text,
|
||||||
|
|
@ -223,21 +224,24 @@ impl Render for TextView {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if self.masked {
|
||||||
|
text = "•".repeat(text.len());
|
||||||
|
}
|
||||||
|
|
||||||
let mut selection_style = HighlightStyle::default();
|
let mut selection_style = HighlightStyle::default();
|
||||||
let mut color = theme.lavender;
|
let mut color = theme.lavender;
|
||||||
color.fade_out(0.8);
|
color.fade_out(0.8);
|
||||||
selection_style.background_color = Some(color);
|
selection_style.background_color = Some(color);
|
||||||
|
|
||||||
let highlights = vec![(self.char_range_to_text_range(&text), selection_style)];
|
let mut highlights = vec![(self.char_range_to_text_range(&text), selection_style)];
|
||||||
|
|
||||||
let styled_text: StyledText = if text.is_empty() {
|
if text.is_empty() {
|
||||||
text = self.placeholder.to_string();
|
text = self.placeholder.to_string();
|
||||||
style.color = theme.subtext0;
|
style.color = theme.subtext0;
|
||||||
StyledText::new(text).with_highlights(&style, highlights)
|
highlights = vec![];
|
||||||
} else {
|
}
|
||||||
StyledText::new(text).with_highlights(&style, highlights)
|
|
||||||
};
|
|
||||||
|
|
||||||
|
let styled_text = StyledText::new(text + " ").with_highlights(&style, highlights);
|
||||||
let view = cx.view().clone();
|
let view = cx.view().clone();
|
||||||
|
|
||||||
InteractiveText::new("text", styled_text).on_click(self.word_ranges(), move |ev, cx| {
|
InteractiveText::new("text", styled_text).on_click(self.word_ranges(), move |ev, cx| {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,14 @@
|
||||||
use gpui::{prelude::FluentBuilder, *};
|
use gpui::{prelude::FluentBuilder, *};
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use ui::{button::Button, disableable::Clickable as _, text_field::TextField, theme::Theme, Color};
|
use ui::{
|
||||||
|
button::Button,
|
||||||
|
disableable::Clickable as _,
|
||||||
|
story::Stories,
|
||||||
|
text_field::{self, TextField},
|
||||||
|
theme::Theme,
|
||||||
|
Color,
|
||||||
|
};
|
||||||
use util::ResultExt as _;
|
use util::ResultExt as _;
|
||||||
|
|
||||||
mod app_state;
|
mod app_state;
|
||||||
|
|
@ -11,6 +18,7 @@ pub use app_state::AppState;
|
||||||
|
|
||||||
pub struct Workspace {
|
pub struct Workspace {
|
||||||
weak_self: WeakView<Self>,
|
weak_self: WeakView<Self>,
|
||||||
|
stories: View<Stories>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Workspace {
|
impl Workspace {
|
||||||
|
|
@ -23,6 +31,7 @@ impl Workspace {
|
||||||
|
|
||||||
Workspace {
|
Workspace {
|
||||||
weak_self: weak_handle.clone(),
|
weak_self: weak_handle.clone(),
|
||||||
|
stories: Stories::view(cx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,8 +91,6 @@ pub fn open_new(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Workspace {}
|
|
||||||
|
|
||||||
impl Render for Workspace {
|
impl Render for Workspace {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
let theme = cx.global::<Theme>();
|
let theme = cx.global::<Theme>();
|
||||||
|
|
@ -113,20 +120,6 @@ impl Render for Workspace {
|
||||||
.on_click(|_e, cx| Theme::change(ui::theme::ThemeMode::Dark, cx)),
|
.on_click(|_e, cx| Theme::change(ui::theme::ThemeMode::Dark, cx)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(
|
.child(div().flex().py_3().gap_2().child(self.stories.clone()))
|
||||||
div()
|
|
||||||
.flex()
|
|
||||||
.py_3()
|
|
||||||
.gap_2()
|
|
||||||
.child(ui::story::Stories::view(cx)),
|
|
||||||
)
|
|
||||||
.child({
|
|
||||||
cx.new_view(|cx| {
|
|
||||||
let txt = TextField::new("Enter text here...", false, cx);
|
|
||||||
txt.view
|
|
||||||
.update(cx, |this, cx| this.set_text("This is default text.", cx));
|
|
||||||
txt
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue