1use gpui::{
2 App, AppContext, Application, Bounds, ClickEvent, Context, Entity, HashMapImageCache,
3 KeyBinding, Menu, MenuItem, SharedString, TitlebarOptions, Window, WindowBounds, WindowOptions,
4 actions, div, image_cache, img, prelude::*, px, rgb, size,
5};
6use reqwest_client::ReqwestClient;
7use std::sync::Arc;
8
9struct ImageGallery {
10 image_key: String,
11 items_count: usize,
12 total_count: usize,
13 image_cache: Entity<HashMapImageCache>,
14}
15
16impl ImageGallery {
17 fn on_next_image(&mut self, _: &ClickEvent, window: &mut Window, cx: &mut Context<Self>) {
18 self.image_cache
19 .update(cx, |image_cache, cx| image_cache.clear(window, cx));
20
21 let t = std::time::SystemTime::now()
22 .duration_since(std::time::UNIX_EPOCH)
23 .unwrap()
24 .as_millis();
25
26 self.image_key = format!("{}", t);
27 self.total_count += self.items_count;
28 cx.notify();
29 }
30}
31
32impl Render for ImageGallery {
33 fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
34 let image_url: SharedString =
35 format!("https://picsum.photos/400/200?t={}", self.image_key).into();
36
37 image_cache(&self.image_cache).child(
38 div()
39 .id("main")
40 .font_family(".SystemUIFont")
41 .bg(rgb(0xE9E9E9))
42 .overflow_y_scroll()
43 .p_4()
44 .size_full()
45 .flex()
46 .flex_col()
47 .items_center()
48 .gap_2()
49 .child(
50 div()
51 .w_full()
52 .flex()
53 .flex_row()
54 .justify_between()
55 .child(format!(
56 "Example to show images and test memory usage (Rendered: {} images).",
57 self.total_count
58 ))
59 .child(
60 div()
61 .id("btn")
62 .py_1()
63 .px_4()
64 .bg(gpui::black())
65 .hover(|this| this.opacity(0.8))
66 .text_color(gpui::white())
67 .text_center()
68 .w_40()
69 .child("Next Photos")
70 .on_click(cx.listener(Self::on_next_image)),
71 ),
72 )
73 .child(
74 div()
75 .id("image-gallery")
76 .flex()
77 .flex_row()
78 .flex_wrap()
79 .gap_x_4()
80 .gap_y_2()
81 .justify_around()
82 .children(
83 (0..self.items_count)
84 .map(|ix| img(format!("{}-{}", image_url, ix)).size_20()),
85 ),
86 ),
87 )
88 }
89}
90
91actions!(image, [Quit]);
92
93fn main() {
94 env_logger::init();
95
96 Application::new().run(move |cx: &mut App| {
97 let http_client = ReqwestClient::user_agent("gpui example").unwrap();
98 cx.set_http_client(Arc::new(http_client));
99
100 cx.activate(true);
101 cx.on_action(|_: &Quit, cx| cx.quit());
102 cx.bind_keys([KeyBinding::new("cmd-q", Quit, None)]);
103 cx.set_menus(vec![Menu {
104 name: "Image Gallery".into(),
105 items: vec![MenuItem::action("Quit", Quit)],
106 }]);
107
108 let window_options = WindowOptions {
109 titlebar: Some(TitlebarOptions {
110 title: Some(SharedString::from("Image Gallery")),
111 appears_transparent: false,
112 ..Default::default()
113 }),
114
115 window_bounds: Some(WindowBounds::Windowed(Bounds::centered(
116 None,
117 size(px(1100.), px(860.)),
118 cx,
119 ))),
120
121 ..Default::default()
122 };
123
124 cx.open_window(window_options, |_, cx| {
125 cx.new(|ctx| ImageGallery {
126 image_key: "".into(),
127 items_count: 99,
128 total_count: 0,
129 image_cache: HashMapImageCache::new(ctx),
130 })
131 })
132 .unwrap();
133 });
134}