opacity.rs

  1#![cfg_attr(target_family = "wasm", no_main)]
  2
  3use std::{fs, path::PathBuf};
  4
  5use anyhow::Result;
  6use gpui::{
  7    App, AssetSource, Bounds, BoxShadow, ClickEvent, Context, SharedString, Task, Window,
  8    WindowBounds, WindowOptions, div, hsla, img, point, prelude::*, px, rgb, size, svg,
  9};
 10use gpui_platform::application;
 11
 12struct Assets {
 13    base: PathBuf,
 14}
 15
 16impl AssetSource for Assets {
 17    fn load(&self, path: &str) -> Result<Option<std::borrow::Cow<'static, [u8]>>> {
 18        fs::read(self.base.join(path))
 19            .map(|data| Some(std::borrow::Cow::Owned(data)))
 20            .map_err(|e| e.into())
 21    }
 22
 23    fn list(&self, path: &str) -> Result<Vec<SharedString>> {
 24        fs::read_dir(self.base.join(path))
 25            .map(|entries| {
 26                entries
 27                    .filter_map(|entry| {
 28                        entry
 29                            .ok()
 30                            .and_then(|entry| entry.file_name().into_string().ok())
 31                            .map(SharedString::from)
 32                    })
 33                    .collect()
 34            })
 35            .map_err(|e| e.into())
 36    }
 37}
 38
 39struct HelloWorld {
 40    _task: Option<Task<()>>,
 41    opacity: f32,
 42    animating: bool,
 43}
 44
 45impl HelloWorld {
 46    fn new(_window: &mut Window, _: &mut Context<Self>) -> Self {
 47        Self {
 48            _task: None,
 49            opacity: 0.5,
 50            animating: false,
 51        }
 52    }
 53
 54    fn start_animation(&mut self, _: &ClickEvent, _: &mut Window, cx: &mut Context<Self>) {
 55        self.opacity = 0.0;
 56        self.animating = true;
 57        cx.notify();
 58    }
 59}
 60
 61impl Render for HelloWorld {
 62    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 63        if self.animating {
 64            self.opacity += 0.005;
 65            if self.opacity >= 1.0 {
 66                self.animating = false;
 67                self.opacity = 1.0;
 68            } else {
 69                window.request_animation_frame();
 70            }
 71        }
 72
 73        div()
 74            .flex()
 75            .flex_row()
 76            .size_full()
 77            .bg(rgb(0xe0e0e0))
 78            .text_xl()
 79            .child(
 80                div()
 81                    .flex()
 82                    .size_full()
 83                    .justify_center()
 84                    .items_center()
 85                    .border_1()
 86                    .text_color(gpui::blue())
 87                    .child(div().child("This is background text.")),
 88            )
 89            .child(
 90                div()
 91                    .id("panel")
 92                    .on_click(cx.listener(Self::start_animation))
 93                    .absolute()
 94                    .top_8()
 95                    .left_8()
 96                    .right_8()
 97                    .bottom_8()
 98                    .opacity(self.opacity)
 99                    .flex()
100                    .justify_center()
101                    .items_center()
102                    .bg(gpui::white())
103                    .border_3()
104                    .border_color(gpui::red())
105                    .text_color(gpui::yellow())
106                    .child(
107                        div()
108                            .flex()
109                            .flex_col()
110                            .gap_2()
111                            .justify_center()
112                            .items_center()
113                            .size(px(300.))
114                            .bg(gpui::blue())
115                            .border_3()
116                            .border_color(gpui::black())
117                            .shadow(vec![BoxShadow {
118                                color: hsla(0.0, 0.0, 0.0, 0.5),
119                                blur_radius: px(1.0),
120                                spread_radius: px(5.0),
121                                offset: point(px(10.0), px(10.0)),
122                            }])
123                            .child(img("image/app-icon.png").size_8())
124                            .child("Opacity Panel (Click to test)")
125                            .child(
126                                div()
127                                    .id("deep-level-text")
128                                    .flex()
129                                    .justify_center()
130                                    .items_center()
131                                    .p_4()
132                                    .bg(gpui::black())
133                                    .text_color(gpui::white())
134                                    .text_decoration_2()
135                                    .text_decoration_wavy()
136                                    .text_decoration_color(gpui::red())
137                                    .child(format!("opacity: {:.1}", self.opacity)),
138                            )
139                            .child(
140                                svg()
141                                    .path("image/arrow_circle.svg")
142                                    .text_color(gpui::black())
143                                    .text_2xl()
144                                    .size_8(),
145                            )
146                            .child(
147                                div()
148                                    .flex()
149                                    .children(["🎊", "✈️", "🎉", "🎈", "🎁", "🎂"].map(|emoji| {
150                                        div()
151                                            .child(emoji.to_string())
152                                            .hover(|style| style.opacity(0.5))
153                                    })),
154                            )
155                            .child(img("image/black-cat-typing.gif").size_12()),
156                    ),
157            )
158    }
159}
160
161fn run_example() {
162    application()
163        .with_assets(Assets {
164            base: PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples"),
165        })
166        .run(|cx: &mut App| {
167            let bounds = Bounds::centered(None, size(px(500.0), px(500.0)), cx);
168            cx.open_window(
169                WindowOptions {
170                    window_bounds: Some(WindowBounds::Windowed(bounds)),
171                    ..Default::default()
172                },
173                |window, cx| cx.new(|cx| HelloWorld::new(window, cx)),
174            )
175            .unwrap();
176            cx.activate(true);
177        });
178}
179
180#[cfg(not(target_family = "wasm"))]
181fn main() {
182    run_example();
183}
184
185#[cfg(target_family = "wasm")]
186#[wasm_bindgen::prelude::wasm_bindgen(start)]
187pub fn start() {
188    gpui_platform::web_init();
189    run_example();
190}