1use crate::active_call_popover::{self, ActiveCallPopover};
2use call::ActiveCall;
3use gpui::{
4 actions,
5 color::Color,
6 elements::*,
7 geometry::{rect::RectF, vector::vec2f},
8 Appearance, Entity, MouseButton, MutableAppContext, RenderContext, View, ViewContext,
9 ViewHandle, WindowKind,
10};
11
12actions!(menu_bar_extra, [ToggleActiveCallPopover]);
13
14pub fn init(cx: &mut MutableAppContext) {
15 cx.add_action(MenuBarExtra::toggle_active_call_popover);
16
17 let mut status_bar_item_id = None;
18 cx.observe(&ActiveCall::global(cx), move |call, cx| {
19 let had_room = status_bar_item_id.is_some();
20 let has_room = call.read(cx).room().is_some();
21 if had_room != has_room {
22 if let Some(status_bar_item_id) = status_bar_item_id.take() {
23 cx.remove_status_bar_item(status_bar_item_id);
24 }
25
26 if has_room {
27 let (id, _) = cx.add_status_bar_item(|_| MenuBarExtra::new());
28 status_bar_item_id = Some(id);
29 }
30 }
31 })
32 .detach();
33}
34
35struct MenuBarExtra {
36 popover: Option<ViewHandle<ActiveCallPopover>>,
37}
38
39impl Entity for MenuBarExtra {
40 type Event = ();
41
42 fn release(&mut self, cx: &mut MutableAppContext) {
43 if let Some(popover) = self.popover.take() {
44 cx.remove_window(popover.window_id());
45 }
46 }
47}
48
49impl View for MenuBarExtra {
50 fn ui_name() -> &'static str {
51 "MenuBarExtra"
52 }
53
54 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
55 let color = match cx.appearance {
56 Appearance::Light | Appearance::VibrantLight => Color::black(),
57 Appearance::Dark | Appearance::VibrantDark => Color::white(),
58 };
59 MouseEventHandler::<Self>::new(0, cx, |_, _| {
60 Svg::new("icons/zed_22.svg")
61 .with_color(color)
62 .aligned()
63 .boxed()
64 })
65 .on_click(MouseButton::Left, |_, cx| {
66 cx.dispatch_action(ToggleActiveCallPopover);
67 })
68 .boxed()
69 }
70}
71
72impl MenuBarExtra {
73 fn new() -> Self {
74 Self { popover: None }
75 }
76
77 fn toggle_active_call_popover(
78 &mut self,
79 _: &ToggleActiveCallPopover,
80 cx: &mut ViewContext<Self>,
81 ) {
82 match self.popover.take() {
83 Some(popover) => {
84 cx.remove_window(popover.window_id());
85 }
86 None => {
87 let window_bounds = cx.window_bounds();
88 let size = vec2f(360., 460.);
89 let origin = window_bounds.lower_left()
90 + vec2f(window_bounds.width() / 2. - size.x() / 2., 0.);
91 let (_, popover) = cx.add_window(
92 gpui::WindowOptions {
93 bounds: gpui::WindowBounds::Fixed(RectF::new(origin, size)),
94 titlebar: None,
95 center: false,
96 kind: WindowKind::PopUp,
97 is_movable: false,
98 },
99 |cx| ActiveCallPopover::new(cx),
100 );
101 cx.subscribe(&popover, Self::on_popover_event).detach();
102 self.popover = Some(popover);
103 }
104 }
105 }
106
107 fn on_popover_event(
108 &mut self,
109 popover: ViewHandle<ActiveCallPopover>,
110 event: &active_call_popover::Event,
111 cx: &mut ViewContext<Self>,
112 ) {
113 match event {
114 active_call_popover::Event::Deactivated => {
115 self.popover.take();
116 cx.remove_window(popover.window_id());
117 }
118 }
119 }
120}