Skip to repository content247 lines · 11.2 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T02:35:11.362Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
window_shadow.rs
1#![cfg_attr(target_family = "wasm", no_main)]
2
3use gpui::{
4 App, Bounds, Context, CursorStyle, Decorations, HitboxBehavior, Hsla, MouseButton, Pixels,
5 Point, ResizeEdge, Size, Window, WindowBackgroundAppearance, WindowBounds, WindowDecorations,
6 WindowOptions, black, canvas, div, green, point, prelude::*, px, rgb, size, transparent_black,
7 white,
8};
9use gpui_platform::application;
10
11struct WindowShadow {}
12
13// Things to do:
14// 1. We need a way of calculating which edge or corner the mouse is on,
15// and then dispatch on that
16// 2. We need to improve the shadow rendering significantly
17// 3. We need to implement the techniques in here in Zed
18
19impl Render for WindowShadow {
20 fn render(&mut self, window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
21 let decorations = window.window_decorations();
22 let rounding = px(10.0);
23 let shadow_size = px(10.0);
24 let border_size = px(1.0);
25 let grey = rgb(0x808080);
26 window.set_client_inset(shadow_size);
27
28 div()
29 .id("window-backdrop")
30 .bg(transparent_black())
31 .map(|div| match decorations {
32 Decorations::Server => div,
33 Decorations::Client { tiling, .. } => div
34 .bg(gpui::transparent_black())
35 .child(
36 canvas(
37 |_bounds, window, _cx| {
38 window.insert_hitbox(
39 Bounds::new(
40 point(px(0.0), px(0.0)),
41 window.window_bounds().get_bounds().size,
42 ),
43 HitboxBehavior::Normal,
44 )
45 },
46 move |_bounds, hitbox, window, _cx| {
47 let mouse = window.mouse_position();
48 let size = window.window_bounds().get_bounds().size;
49 let Some(edge) = resize_edge(mouse, shadow_size, size) else {
50 return;
51 };
52 window.set_cursor_style(
53 match edge {
54 ResizeEdge::Top | ResizeEdge::Bottom => {
55 CursorStyle::ResizeUpDown
56 }
57 ResizeEdge::Left | ResizeEdge::Right => {
58 CursorStyle::ResizeLeftRight
59 }
60 ResizeEdge::TopLeft | ResizeEdge::BottomRight => {
61 CursorStyle::ResizeUpLeftDownRight
62 }
63 ResizeEdge::TopRight | ResizeEdge::BottomLeft => {
64 CursorStyle::ResizeUpRightDownLeft
65 }
66 },
67 &hitbox,
68 );
69 },
70 )
71 .size_full()
72 .absolute(),
73 )
74 .when(!(tiling.top || tiling.right), |div| {
75 div.rounded_tr(rounding)
76 })
77 .when(!(tiling.top || tiling.left), |div| div.rounded_tl(rounding))
78 .when(!tiling.top, |div| div.pt(shadow_size))
79 .when(!tiling.bottom, |div| div.pb(shadow_size))
80 .when(!tiling.left, |div| div.pl(shadow_size))
81 .when(!tiling.right, |div| div.pr(shadow_size))
82 .on_mouse_move(|_e, window, _cx| window.refresh())
83 .on_mouse_down(MouseButton::Left, move |e, window, _cx| {
84 let size = window.window_bounds().get_bounds().size;
85 let pos = e.position;
86
87 match resize_edge(pos, shadow_size, size) {
88 Some(edge) => window.start_window_resize(edge),
89 None => window.start_window_move(),
90 };
91 }),
92 })
93 .size_full()
94 .child(
95 div()
96 .cursor(CursorStyle::Arrow)
97 .map(|div| match decorations {
98 Decorations::Server => div,
99 Decorations::Client { tiling } => div
100 .border_color(grey)
101 .when(!(tiling.top || tiling.right), |div| {
102 div.rounded_tr(rounding)
103 })
104 .when(!(tiling.top || tiling.left), |div| div.rounded_tl(rounding))
105 .when(!tiling.top, |div| div.border_t(border_size))
106 .when(!tiling.bottom, |div| div.border_b(border_size))
107 .when(!tiling.left, |div| div.border_l(border_size))
108 .when(!tiling.right, |div| div.border_r(border_size))
109 .when(!tiling.is_tiled(), |div| {
110 div.shadow(vec![
111 gpui::BoxShadow::new(
112 px(0.),
113 px(0.),
114 Hsla {
115 h: 0.,
116 s: 0.,
117 l: 0.,
118 a: 0.4,
119 },
120 )
121 .blur_radius(shadow_size / 2.),
122 ])
123 }),
124 })
125 .on_mouse_move(|_e, _, cx| {
126 cx.stop_propagation();
127 })
128 .bg(gpui::rgb(0xCCCCFF))
129 .size_full()
130 .flex()
131 .flex_col()
132 .justify_around()
133 .child(
134 div().w_full().flex().flex_row().justify_around().child(
135 div()
136 .flex()
137 .bg(white())
138 .size(px(300.0))
139 .justify_center()
140 .items_center()
141 .shadow_lg()
142 .border_1()
143 .border_color(rgb(0x0000ff))
144 .text_xl()
145 .text_color(rgb(0xffffff))
146 .child(
147 div()
148 .id("hello")
149 .w(px(200.0))
150 .h(px(100.0))
151 .bg(green())
152 .shadow(vec![
153 gpui::BoxShadow::new(
154 px(0.),
155 px(0.),
156 Hsla {
157 h: 0.,
158 s: 0.,
159 l: 0.,
160 a: 1.0,
161 },
162 )
163 .blur_radius(px(20.0)),
164 ])
165 .map(|div| match decorations {
166 Decorations::Server => div,
167 Decorations::Client { .. } => div
168 .on_mouse_down(
169 MouseButton::Left,
170 |_e, window, _| {
171 window.start_window_move();
172 },
173 )
174 .on_click(|e, window, _| {
175 if e.is_right_click() {
176 window.show_window_menu(e.position());
177 }
178 })
179 .text_color(black())
180 .child("this is the custom titlebar"),
181 }),
182 ),
183 ),
184 ),
185 )
186 }
187}
188
189fn resize_edge(pos: Point<Pixels>, shadow_size: Pixels, size: Size<Pixels>) -> Option<ResizeEdge> {
190 let edge = if pos.y < shadow_size && pos.x < shadow_size {
191 ResizeEdge::TopLeft
192 } else if pos.y < shadow_size && pos.x > size.width - shadow_size {
193 ResizeEdge::TopRight
194 } else if pos.y < shadow_size {
195 ResizeEdge::Top
196 } else if pos.y > size.height - shadow_size && pos.x < shadow_size {
197 ResizeEdge::BottomLeft
198 } else if pos.y > size.height - shadow_size && pos.x > size.width - shadow_size {
199 ResizeEdge::BottomRight
200 } else if pos.y > size.height - shadow_size {
201 ResizeEdge::Bottom
202 } else if pos.x < shadow_size {
203 ResizeEdge::Left
204 } else if pos.x > size.width - shadow_size {
205 ResizeEdge::Right
206 } else {
207 return None;
208 };
209 Some(edge)
210}
211
212fn run_example() {
213 application().run(|cx: &mut App| {
214 let bounds = Bounds::centered(None, size(px(600.0), px(600.0)), cx);
215 cx.open_window(
216 WindowOptions {
217 window_bounds: Some(WindowBounds::Windowed(bounds)),
218 window_background: WindowBackgroundAppearance::Opaque,
219 window_decorations: Some(WindowDecorations::Client),
220 ..Default::default()
221 },
222 |window, cx| {
223 cx.new(|cx| {
224 cx.observe_window_appearance(window, |_, window, _| {
225 window.refresh();
226 })
227 .detach();
228 WindowShadow {}
229 })
230 },
231 )
232 .unwrap();
233 });
234}
235
236#[cfg(not(target_family = "wasm"))]
237fn main() {
238 run_example();
239}
240
241#[cfg(target_family = "wasm")]
242#[wasm_bindgen::prelude::wasm_bindgen(start)]
243pub fn start() {
244 gpui_platform::web_init();
245 run_example();
246}
247