view_example_main.rs

  1#![cfg_attr(target_family = "wasm", no_main)]
  2
  3//! **view_example** — an end-to-end GPUI example demonstrating how Entity,
  4//! Element, View, and Render compose together to build rich text components.
  5//!
  6//! ## Architecture
  7//!
  8//! Each module has a focused job:
  9//!
 10//! | Module          | Layer   | Job                                                      |
 11//! |-----------------|---------|----------------------------------------------------------|
 12//! | `editor`        | Entity  | Owns text, cursor, blink task, `EntityInputHandler`      |
 13//! | `editor_text`   | Element | Shapes text, paints cursor, wires `handle_input`         |
 14//! | `input`         | View    | Single-line input — composes `ExampleEditorText` with styling   |
 15//! | `text_area`     | View    | Multi-line text area — same entity, different layout      |
 16//! | `main` (here)   | Render  | Root view — creates entities with `use_state`, assembles  |
 17//!
 18//! ## Running
 19//!
 20//! ```sh
 21//! cargo run --example view_example -p gpui
 22//! ```
 23//!
 24//! ## Testing
 25//!
 26//! ```sh
 27//! cargo test --example view_example -p gpui
 28//! ```
 29
 30mod example_editor;
 31mod example_input;
 32mod example_text_area;
 33
 34#[cfg(test)]
 35mod example_tests;
 36
 37use gpui::{
 38    App, Bounds, Context, Hsla, KeyBinding, Window, WindowBounds, WindowOptions, actions, div,
 39    hsla, prelude::*, px, rgb, size,
 40};
 41use gpui_platform::application;
 42
 43use example_editor::ExampleEditor;
 44use example_input::ExampleInput;
 45use example_text_area::ExampleTextArea;
 46
 47actions!(
 48    view_example,
 49    [Backspace, Delete, Left, Right, Home, End, Enter, Quit,]
 50);
 51
 52// ---------------------------------------------------------------------------
 53// ViewExample — the root view using `Render` and `window.use_state()`
 54// ---------------------------------------------------------------------------
 55
 56struct ViewExample {
 57    input_color: Hsla,
 58    textarea_color: Hsla,
 59}
 60
 61impl ViewExample {
 62    fn new() -> Self {
 63        Self {
 64            input_color: hsla(0., 0., 0.1, 1.),
 65            textarea_color: hsla(250. / 360., 0.7, 0.4, 1.),
 66        }
 67    }
 68}
 69
 70impl Render for ViewExample {
 71    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 72        let input_editor = window.use_state(cx, |_window, cx| ExampleEditor::new(cx));
 73        let textarea_editor = window.use_state(cx, |_window, cx| ExampleEditor::new(cx));
 74        let input_color = self.input_color;
 75        let textarea_color = self.textarea_color;
 76
 77        div()
 78            .flex()
 79            .flex_col()
 80            .size_full()
 81            .bg(rgb(0xf0f0f0))
 82            .p(px(24.))
 83            .gap(px(20.))
 84            .child(
 85                div()
 86                    .flex()
 87                    .flex_col()
 88                    .gap(px(4.))
 89                    .child(
 90                        div()
 91                            .text_sm()
 92                            .text_color(hsla(0., 0., 0.3, 1.))
 93                            .child("Single-line input (Input — View with cached ExampleEditorText)"),
 94                    )
 95                    .child(
 96                        ExampleInput::new(input_editor)
 97                            .width(px(320.))
 98                            .color(input_color),
 99                    ),
100            )
101            .child(
102                div()
103                    .flex()
104                    .flex_col()
105                    .gap(px(4.))
106                    .child(div().text_sm().text_color(hsla(0., 0., 0.3, 1.)).child(
107                        "Multi-line text area (TextArea — same entity type, different View)",
108                    ))
109                    .child(ExampleTextArea::new(textarea_editor, 5).color(textarea_color)),
110            )
111            .child(
112                div()
113                    .flex()
114                    .flex_col()
115                    .gap(px(2.))
116                    .mt(px(12.))
117                    .text_xs()
118                    .text_color(hsla(0., 0., 0.5, 1.))
119                    .child("• ExampleEditor entity owns state, blink task, EntityInputHandler")
120                    .child("• ExampleEditorText element shapes text, paints cursor, wires handle_input")
121                    .child("• Input / TextArea views compose ExampleEditorText with container styling")
122                    .child("• ViewElement::cached() enables render caching via #[derive(Hash)]")
123                    .child("• Entities created via window.use_state()"),
124            )
125    }
126}
127
128// ---------------------------------------------------------------------------
129// Entry point
130// ---------------------------------------------------------------------------
131
132fn run_example() {
133    application().run(|cx: &mut App| {
134        let bounds = Bounds::centered(None, size(px(500.0), px(500.0)), cx);
135        cx.bind_keys([
136            KeyBinding::new("backspace", Backspace, None),
137            KeyBinding::new("delete", Delete, None),
138            KeyBinding::new("left", Left, None),
139            KeyBinding::new("right", Right, None),
140            KeyBinding::new("home", Home, None),
141            KeyBinding::new("end", End, None),
142            KeyBinding::new("enter", Enter, None),
143            KeyBinding::new("cmd-q", Quit, None),
144        ]);
145
146        cx.open_window(
147            WindowOptions {
148                window_bounds: Some(WindowBounds::Windowed(bounds)),
149                ..Default::default()
150            },
151            |_, cx| cx.new(|_| ViewExample::new()),
152        )
153        .unwrap();
154
155        cx.on_action(|_: &Quit, cx| cx.quit());
156        cx.activate(true);
157    });
158}
159
160#[cfg(not(target_family = "wasm"))]
161fn main() {
162    run_example();
163}
164
165#[cfg(target_family = "wasm")]
166#[wasm_bindgen::prelude::wasm_bindgen(start)]
167pub fn start() {
168    gpui_platform::web_init();
169    run_example();
170}