Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gpui: Fix text hover style #24723

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 53 additions & 21 deletions crates/gpui/examples/hello_world.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use gpui::{
div, prelude::*, px, rgb, size, App, Application, Bounds, Context, SharedString, Window,
WindowBounds, WindowOptions,
div, prelude::*, px, relative, rgb, size, App, Application, Bounds, Context, SharedString,
Window, WindowBounds, WindowOptions,
};

struct HelloWorld {
Expand All @@ -10,36 +10,66 @@ struct HelloWorld {
impl Render for HelloWorld {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
div()
.size_full()
.flex()
.flex_col()
.gap_3()
.bg(rgb(0x505050))
.size(px(500.0))
.justify_center()
.items_center()
.shadow_lg()
.border_1()
.border_color(rgb(0x0000ff))
.text_xl()
.text_color(rgb(0xffffff))
.child(format!("Hello, {}!", &self.text))
.justify_center()
.bg(gpui::white())
.child(
div()
.flex()
.gap_2()
.child(div().size_8().bg(gpui::red()))
.child(div().size_8().bg(gpui::green()))
.child(div().size_8().bg(gpui::blue()))
.child(div().size_8().bg(gpui::yellow()))
.child(div().size_8().bg(gpui::black()))
.child(div().size_8().bg(gpui::white())),
.flex_col()
.gap_3()
.p_5()
.bg(rgb(0x505050))
.size(px(500.0))
.justify_center()
.items_center()
.shadow_lg()
.border_3()
.border_color(rgb(0x303030))
.rounded_xl()
.text_xl()
.line_height(relative(1.))
.child(
div()
.id("hello")
.w_48()
.py_2()
.rounded_md()
.text_center()
.text_color(gpui::white())
.active(|this| {
this.text_color(gpui::red())
.text_center()
.text_decoration_1()
.text_decoration_wavy()
})
.hover(|this| {
this.text_color(gpui::yellow())
.text_center()
.text_decoration_1()
})
.child(format!("Hello, {}!", &self.text)),
)
.child(
div()
.flex()
.gap_2()
.child(div().size_8().bg(gpui::red()))
.child(div().size_8().bg(gpui::green()))
.child(div().size_8().bg(gpui::blue()))
.child(div().size_8().bg(gpui::yellow()))
.child(div().size_8().bg(gpui::black()))
.child(div().size_8().bg(gpui::white())),
),
)
}
}

fn main() {
Application::new().run(|cx: &mut App| {
let bounds = Bounds::centered(None, size(px(500.), px(500.0)), cx);
let bounds = Bounds::centered(None, size(px(600.), px(600.0)), cx);
cx.open_window(
WindowOptions {
window_bounds: Some(WindowBounds::Windowed(bounds)),
Expand All @@ -52,5 +82,7 @@ fn main() {
},
)
.unwrap();

cx.activate(true);
});
}
4 changes: 1 addition & 3 deletions crates/gpui/src/elements/div.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1661,8 +1661,6 @@ impl Interactivity {
window: &mut Window,
cx: &mut App,
) {
use crate::TextAlign;

if global_id.is_some()
&& (style.debug || style.debug_below || cx.has_global::<crate::DebugBelow>())
&& hitbox.is_hovered(window)
Expand All @@ -1684,7 +1682,7 @@ impl Interactivity {
.ok()
.and_then(|mut text| text.pop())
{
text.paint(hitbox.origin, FONT_SIZE, TextAlign::Left, None, window, cx)
text.paint(hitbox.origin, FONT_SIZE, None, None, window, cx)
.ok();

let text_bounds = crate::Bounds {
Expand Down
15 changes: 11 additions & 4 deletions crates/gpui/src/elements/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ use crate::{
register_tooltip_mouse_handlers, set_tooltip_on_window, ActiveTooltip, AnyView, App, Bounds,
DispatchPhase, Element, ElementId, GlobalElementId, HighlightStyle, Hitbox, IntoElement,
LayoutId, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point, SharedString, Size,
TextOverflow, TextRun, TextStyle, TooltipId, WhiteSpace, Window, WrappedLine,
WrappedLineLayout,
TextOverflow, TextRun, TextStyle, TextStyleRefinement, TooltipId, WhiteSpace, Window,
WrappedLine, WrappedLineLayout,
};
use anyhow::anyhow;
use parking_lot::{Mutex, MutexGuard};
use refineable::Refineable;
use smallvec::SmallVec;
use std::{
cell::{Cell, RefCell},
Expand Down Expand Up @@ -390,12 +391,18 @@ impl TextLayout {

let line_height = element_state.line_height;
let mut line_origin = bounds.origin;
let text_style = window.text_style();

// Get current text_style refinements
let mut text_style = TextStyleRefinement::default();
for style in window.text_style_stack.iter().as_ref() {
text_style.refine(&style);
}

for line in &element_state.lines {
line.paint(
line_origin,
line_height,
text_style.text_align,
Some(&text_style),
Some(bounds),
window,
cx,
Expand Down
2 changes: 1 addition & 1 deletion crates/gpui/src/styled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ pub trait Styled: Sized {
}

/// Sets the decoration of the text to have a line through it.
/// [Docs](https://tailwindcss.com/docs/text-decoration#setting-the-text-decoration)
/// [Docs](https://tailwindcss.com/docs/text-decoration-line#adding-a-line-through-text)
fn line_through(mut self) -> Self {
let style = self.text_style().get_or_insert_with(Default::default);
style.strikethrough = Some(StrikethroughStyle {
Expand Down
57 changes: 41 additions & 16 deletions crates/gpui/src/text_system/line.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
black, fill, point, px, size, App, Bounds, Half, Hsla, LineLayout, Pixels, Point, Result,
SharedString, StrikethroughStyle, TextAlign, UnderlineStyle, Window, WrapBoundary,
WrappedLineLayout,
SharedString, StrikethroughStyle, TextAlign, TextStyleRefinement, UnderlineStyle, Window,
WrapBoundary, WrappedLineLayout,
};
use derive_more::{Deref, DerefMut};
use smallvec::SmallVec;
Expand Down Expand Up @@ -71,7 +71,7 @@ impl ShapedLine {
origin,
&self.layout,
line_height,
TextAlign::default(),
None,
None,
&self.decoration_runs,
&[],
Expand Down Expand Up @@ -102,11 +102,12 @@ impl WrappedLine {
}

/// Paint this line of text to the window.
#[allow(clippy::too_many_arguments)]
pub fn paint(
&self,
origin: Point<Pixels>,
line_height: Pixels,
align: TextAlign,
text_style: Option<&TextStyleRefinement>,
bounds: Option<Bounds<Pixels>>,
window: &mut Window,
cx: &mut App,
Expand All @@ -120,7 +121,7 @@ impl WrappedLine {
origin,
&self.layout.unwrapped_layout,
line_height,
align,
text_style,
align_width,
&self.decoration_runs,
&self.wrap_boundaries,
Expand All @@ -137,7 +138,7 @@ fn paint_line(
origin: Point<Pixels>,
layout: &LineLayout,
line_height: Pixels,
align: TextAlign,
text_style: Option<&TextStyleRefinement>,
align_width: Option<Pixels>,
decoration_runs: &[DecorationRun],
wrap_boundaries: &[WrapBoundary],
Expand All @@ -151,6 +152,12 @@ fn paint_line(
line_height * (wrap_boundaries.len() as f32 + 1.),
),
);

// TODO: text_align and line_height need to inherit from normal style when is hovered or activated.
let mut text_align = text_style
.and_then(|s| s.text_align)
.unwrap_or(TextAlign::Left);

window.paint_layer(line_bounds, |window| {
let padding_top = (line_height - layout.ascent - layout.descent) / 2.;
let baseline_offset = point(px(0.), padding_top + layout.ascent);
Expand All @@ -167,7 +174,7 @@ fn paint_line(
origin,
align_width.unwrap_or(layout.width),
px(0.0),
&align,
&text_align,
layout,
wraps.peek(),
),
Expand Down Expand Up @@ -229,7 +236,7 @@ fn paint_line(
origin,
align_width.unwrap_or(layout.width),
glyph.position.x,
&align,
&text_align,
layout,
wraps.peek(),
);
Expand All @@ -253,12 +260,30 @@ fn paint_line(
}

if let Some(style_run) = style_run {
let mut run_color = style_run.color;
let mut run_underline = style_run.underline.as_ref();
let mut run_background_color = style_run.background_color;
let mut run_strikethrough = style_run.strikethrough;
// Override by text run by current style when hovered or activated.
if let Some(val) = text_style.and_then(|s| s.color) {
run_color = val;
}
if let Some(val) = text_style.and_then(|s| s.underline.as_ref()) {
run_underline = Some(val);
}
if let Some(val) = text_style.and_then(|s| s.background_color) {
run_background_color = Some(val);
}
if let Some(val) = text_style.and_then(|s| s.strikethrough) {
run_strikethrough = Some(val);
}

if let Some((_, background_color)) = &mut current_background {
if style_run.background_color.as_ref() != Some(background_color) {
if run_background_color.as_ref() != Some(background_color) {
finished_background = current_background.take();
}
}
if let Some(run_background) = style_run.background_color {
if let Some(run_background) = run_background_color {
current_background.get_or_insert((
point(glyph_origin.x, glyph_origin.y),
run_background,
Expand All @@ -270,40 +295,40 @@ fn paint_line(
finished_underline = current_underline.take();
}
}
if let Some(run_underline) = style_run.underline.as_ref() {
if let Some(run_underline) = run_underline.as_ref() {
current_underline.get_or_insert((
point(
glyph_origin.x,
glyph_origin.y + baseline_offset.y + (layout.descent * 0.618),
),
UnderlineStyle {
color: Some(run_underline.color.unwrap_or(style_run.color)),
color: Some(run_underline.color.unwrap_or(run_color)),
thickness: run_underline.thickness,
wavy: run_underline.wavy,
},
));
}
if let Some((_, strikethrough_style)) = &mut current_strikethrough {
if style_run.strikethrough.as_ref() != Some(strikethrough_style) {
if run_strikethrough.as_ref() != Some(strikethrough_style) {
finished_strikethrough = current_strikethrough.take();
}
}
if let Some(run_strikethrough) = style_run.strikethrough.as_ref() {
if let Some(mut run_strikethrough) = run_strikethrough.as_ref() {
current_strikethrough.get_or_insert((
point(
glyph_origin.x,
glyph_origin.y
+ (((layout.ascent * 0.5) + baseline_offset.y) * 0.5),
),
StrikethroughStyle {
color: Some(run_strikethrough.color.unwrap_or(style_run.color)),
color: Some(run_strikethrough.color.unwrap_or(run_color)),
thickness: run_strikethrough.thickness,
},
));
}

run_end += style_run.len as usize;
color = style_run.color;
color = run_color;
} else {
run_end = layout.len;
finished_background = current_background.take();
Expand Down
Loading