logiguard fork v3: full patch set on verified 8c74db0 tree
Includes prior-session patches (carry forward so the app compiles): - crates/gpui/build.rs: cross-compile manifest fix - crates/gpui/src/platform.rs: PlatformWindow::activate_with_token trait method - crates/gpui/src/window.rs: Window::activate_with_token public API - crates/gpui_linux/src/linux/wayland/window.rs: WaylandWindow::activate_with_token + activate() keyboard-serial fix Plus the focus-serial fix: - serial.rs: SerialKind::KeyboardEnter - client.rs: store wl_keyboard.enter serial; latest_serial_of() Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
409
crates/gpui/examples/text.rs
Normal file
409
crates/gpui/examples/text.rs
Normal file
@@ -0,0 +1,409 @@
|
||||
#![cfg_attr(target_family = "wasm", no_main)]
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
ops::{Deref, DerefMut},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use gpui::{
|
||||
AbsoluteLength, App, Context, DefiniteLength, ElementId, Global, Hsla, Menu, SharedString,
|
||||
TextStyle, TitlebarOptions, Window, WindowBounds, WindowOptions, bounds, colors::DefaultColors,
|
||||
div, point, prelude::*, px, relative, rgb, size,
|
||||
};
|
||||
use gpui_platform::application;
|
||||
use std::iter;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TextContext {
|
||||
font_size: f32,
|
||||
line_height: f32,
|
||||
type_scale: f32,
|
||||
}
|
||||
|
||||
impl Default for TextContext {
|
||||
fn default() -> Self {
|
||||
TextContext {
|
||||
font_size: 16.0,
|
||||
line_height: 1.3,
|
||||
type_scale: 1.33,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TextContext {
|
||||
pub fn get_global(cx: &App) -> &Arc<TextContext> {
|
||||
&cx.global::<GlobalTextContext>().0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GlobalTextContext(pub Arc<TextContext>);
|
||||
|
||||
impl Deref for GlobalTextContext {
|
||||
type Target = Arc<TextContext>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for GlobalTextContext {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Global for GlobalTextContext {}
|
||||
|
||||
pub trait ActiveTextContext {
|
||||
fn text_context(&self) -> &Arc<TextContext>;
|
||||
}
|
||||
|
||||
impl ActiveTextContext for App {
|
||||
fn text_context(&self) -> &Arc<TextContext> {
|
||||
&self.global::<GlobalTextContext>().0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct SpecimenTheme {
|
||||
pub bg: Hsla,
|
||||
pub fg: Hsla,
|
||||
}
|
||||
|
||||
impl Default for SpecimenTheme {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bg: gpui::white(),
|
||||
fg: gpui::black(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SpecimenTheme {
|
||||
pub fn invert(&self) -> Self {
|
||||
Self {
|
||||
bg: self.fg,
|
||||
fg: self.bg,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, IntoElement)]
|
||||
struct Specimen {
|
||||
id: ElementId,
|
||||
scale: f32,
|
||||
text_style: Option<TextStyle>,
|
||||
string: SharedString,
|
||||
invert: bool,
|
||||
}
|
||||
|
||||
impl Specimen {
|
||||
pub fn new(id: usize) -> Self {
|
||||
let string = SharedString::new_static("The quick brown fox jumps over the lazy dog");
|
||||
let id_string = format!("specimen-{}", id);
|
||||
let id = ElementId::Name(id_string.into());
|
||||
Self {
|
||||
id,
|
||||
scale: 1.0,
|
||||
text_style: None,
|
||||
string,
|
||||
invert: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn invert(mut self) -> Self {
|
||||
self.invert = !self.invert;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn scale(mut self, scale: f32) -> Self {
|
||||
self.scale = scale;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for Specimen {
|
||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let rem_size = window.rem_size();
|
||||
let scale = self.scale;
|
||||
let global_style = cx.text_context();
|
||||
|
||||
let style_override = self.text_style;
|
||||
|
||||
let mut font_size = global_style.font_size;
|
||||
let mut line_height = global_style.line_height;
|
||||
|
||||
if let Some(style_override) = style_override {
|
||||
font_size = style_override.font_size.to_pixels(rem_size).into();
|
||||
line_height = match style_override.line_height {
|
||||
DefiniteLength::Absolute(absolute_len) => match absolute_len {
|
||||
AbsoluteLength::Rems(absolute_len) => absolute_len.to_pixels(rem_size).into(),
|
||||
AbsoluteLength::Pixels(absolute_len) => absolute_len.into(),
|
||||
},
|
||||
DefiniteLength::Fraction(value) => value,
|
||||
};
|
||||
}
|
||||
|
||||
let mut theme = SpecimenTheme::default();
|
||||
|
||||
if self.invert {
|
||||
theme = theme.invert();
|
||||
}
|
||||
|
||||
div()
|
||||
.id(self.id)
|
||||
.bg(theme.bg)
|
||||
.text_color(theme.fg)
|
||||
.text_size(px(font_size * scale))
|
||||
.line_height(relative(line_height))
|
||||
.p(px(10.0))
|
||||
.child(self.string)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, IntoElement)]
|
||||
struct CharacterGrid {
|
||||
scale: f32,
|
||||
invert: bool,
|
||||
text_style: Option<TextStyle>,
|
||||
}
|
||||
|
||||
impl CharacterGrid {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
scale: 1.0,
|
||||
invert: false,
|
||||
text_style: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scale(mut self, scale: f32) -> Self {
|
||||
self.scale = scale;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for CharacterGrid {
|
||||
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
|
||||
let mut theme = SpecimenTheme::default();
|
||||
|
||||
if self.invert {
|
||||
theme = theme.invert();
|
||||
}
|
||||
|
||||
let characters = vec![
|
||||
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "A", "B", "C", "D", "E", "F", "G",
|
||||
"H", "I", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y",
|
||||
"Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "p", "q",
|
||||
"r", "s", "t", "u", "v", "w", "x", "y", "z", "ẞ", "ſ", "ß", "ð", "Þ", "þ", "α", "β",
|
||||
"Γ", "γ", "Δ", "δ", "η", "θ", "ι", "κ", "Λ", "λ", "μ", "ν", "ξ", "π", "τ", "υ", "φ",
|
||||
"χ", "ψ", "∂", "а", "в", "Ж", "ж", "З", "з", "К", "к", "л", "м", "Н", "н", "Р", "р",
|
||||
"У", "у", "ф", "ч", "ь", "ы", "Э", "э", "Я", "я", "ij", "öẋ", ".,", "⣝⣑", "~", "*",
|
||||
"_", "^", "`", "'", "(", "{", "«", "#", "&", "@", "$", "¢", "%", "|", "?", "¶", "µ",
|
||||
"❮", "<=", "!=", "==", "--", "++", "=>", "->", "🏀", "🎊", "😍", "❤️", "👍", "👎",
|
||||
];
|
||||
|
||||
let columns = 20;
|
||||
let rows = characters.len().div_ceil(columns);
|
||||
|
||||
let grid_rows = (0..rows).map(|row_idx| {
|
||||
let start_idx = row_idx * columns;
|
||||
let end_idx = (start_idx + columns).min(characters.len());
|
||||
|
||||
div()
|
||||
.w_full()
|
||||
.flex()
|
||||
.flex_row()
|
||||
.children((start_idx..end_idx).map(|i| {
|
||||
div()
|
||||
.text_center()
|
||||
.size(px(62.))
|
||||
.bg(theme.bg)
|
||||
.text_color(theme.fg)
|
||||
.text_size(px(24.0))
|
||||
.line_height(relative(1.0))
|
||||
.child(characters[i])
|
||||
}))
|
||||
.when(end_idx - start_idx < columns, |d| {
|
||||
d.children(
|
||||
iter::repeat_with(|| div().flex_1()).take(columns - (end_idx - start_idx)),
|
||||
)
|
||||
})
|
||||
});
|
||||
|
||||
div().p_4().gap_2().flex().flex_col().children(grid_rows)
|
||||
}
|
||||
}
|
||||
|
||||
struct TextExample {
|
||||
next_id: usize,
|
||||
font_family: SharedString,
|
||||
}
|
||||
|
||||
impl TextExample {
|
||||
fn next_id(&mut self) -> usize {
|
||||
self.next_id += 1;
|
||||
self.next_id
|
||||
}
|
||||
|
||||
fn button(
|
||||
text: &str,
|
||||
cx: &mut Context<Self>,
|
||||
on_click: impl Fn(&mut Self, &mut Context<Self>) + 'static,
|
||||
) -> impl IntoElement {
|
||||
div()
|
||||
.id(text.to_string())
|
||||
.flex_none()
|
||||
.child(text.to_string())
|
||||
.bg(gpui::black())
|
||||
.text_color(gpui::white())
|
||||
.active(|this| this.opacity(0.8))
|
||||
.px_3()
|
||||
.py_1()
|
||||
.on_click(cx.listener(move |this, _, _, cx| on_click(this, cx)))
|
||||
}
|
||||
}
|
||||
|
||||
const FONT_FAMILIES: [&str; 5] = [
|
||||
".ZedMono",
|
||||
".SystemUIFont",
|
||||
"Menlo",
|
||||
"Monaco",
|
||||
"Courier New",
|
||||
];
|
||||
|
||||
impl Render for TextExample {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let tcx = cx.text_context();
|
||||
let colors = cx.default_colors().clone();
|
||||
|
||||
let type_scale = tcx.type_scale;
|
||||
|
||||
let step_down_2 = 1.0 / (type_scale * type_scale);
|
||||
let step_down_1 = 1.0 / type_scale;
|
||||
let base = 1.0;
|
||||
let step_up_1 = base * type_scale;
|
||||
let step_up_2 = step_up_1 * type_scale;
|
||||
let step_up_3 = step_up_2 * type_scale;
|
||||
let step_up_4 = step_up_3 * type_scale;
|
||||
let step_up_5 = step_up_4 * type_scale;
|
||||
let step_up_6 = step_up_5 * type_scale;
|
||||
|
||||
div()
|
||||
.font_family(self.font_family.clone())
|
||||
.size_full()
|
||||
.child(
|
||||
div()
|
||||
.bg(gpui::white())
|
||||
.border_b_1()
|
||||
.border_color(gpui::black())
|
||||
.p_3()
|
||||
.flex()
|
||||
.child(Self::button(&self.font_family, cx, |this, cx| {
|
||||
let new_family = FONT_FAMILIES
|
||||
.iter()
|
||||
.position(|f| *f == this.font_family.as_str())
|
||||
.map(|idx| FONT_FAMILIES[(idx + 1) % FONT_FAMILIES.len()])
|
||||
.unwrap_or(FONT_FAMILIES[0]);
|
||||
|
||||
this.font_family = SharedString::new(new_family);
|
||||
cx.notify();
|
||||
})),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.id("text-example")
|
||||
.overflow_y_scroll()
|
||||
.overflow_x_hidden()
|
||||
.bg(rgb(0xffffff))
|
||||
.size_full()
|
||||
.child(div().child(CharacterGrid::new().scale(base)))
|
||||
.child(
|
||||
div()
|
||||
.child(Specimen::new(self.next_id()).scale(step_down_2))
|
||||
.child(Specimen::new(self.next_id()).scale(step_down_2).invert())
|
||||
.child(Specimen::new(self.next_id()).scale(step_down_1))
|
||||
.child(Specimen::new(self.next_id()).scale(step_down_1).invert())
|
||||
.child(Specimen::new(self.next_id()).scale(base))
|
||||
.child(Specimen::new(self.next_id()).scale(base).invert())
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_1))
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_1).invert())
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_2))
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_2).invert())
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_3))
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_3).invert())
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_4))
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_4).invert())
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_5))
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_5).invert())
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_6))
|
||||
.child(Specimen::new(self.next_id()).scale(step_up_6).invert()),
|
||||
),
|
||||
)
|
||||
.child(div().w(px(240.)).h_full().bg(colors.container))
|
||||
}
|
||||
}
|
||||
|
||||
fn run_example() {
|
||||
application().run(|cx: &mut App| {
|
||||
cx.set_menus(vec![Menu {
|
||||
name: "GPUI Typography".into(),
|
||||
disabled: false,
|
||||
items: vec![],
|
||||
}]);
|
||||
|
||||
let fonts = [include_bytes!(
|
||||
"../../../assets/fonts/lilex/Lilex-Regular.ttf"
|
||||
)]
|
||||
.iter()
|
||||
.map(|b| Cow::Borrowed(&b[..]))
|
||||
.collect();
|
||||
|
||||
_ = cx.text_system().add_fonts(fonts);
|
||||
|
||||
cx.init_colors();
|
||||
cx.set_global(GlobalTextContext(Arc::new(TextContext::default())));
|
||||
|
||||
let window = cx
|
||||
.open_window(
|
||||
WindowOptions {
|
||||
titlebar: Some(TitlebarOptions {
|
||||
title: Some("GPUI Typography".into()),
|
||||
..Default::default()
|
||||
}),
|
||||
window_bounds: Some(WindowBounds::Windowed(bounds(
|
||||
point(px(0.0), px(0.0)),
|
||||
size(px(920.), px(720.)),
|
||||
))),
|
||||
..Default::default()
|
||||
},
|
||||
|_window, cx| {
|
||||
cx.new(|_cx| TextExample {
|
||||
next_id: 0,
|
||||
font_family: ".ZedMono".into(),
|
||||
})
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
window
|
||||
.update(cx, |_view, _window, cx| {
|
||||
cx.activate(true);
|
||||
})
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
fn main() {
|
||||
run_example();
|
||||
}
|
||||
|
||||
#[cfg(target_family = "wasm")]
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(start)]
|
||||
pub fn start() {
|
||||
gpui_platform::web_init();
|
||||
run_example();
|
||||
}
|
||||
Reference in New Issue
Block a user