1use gpui::{
2 Anchor, App, Entity, IntoElement, ParentElement, Pixels, RenderOnce, Styled, Window, div,
3 prelude::FluentBuilder as _, px,
4};
5use std::time::Duration;
6
7use crate::monitor::FpsMonitor;
8
9const MARGIN: Pixels = px(12.);
11
12#[derive(IntoElement)]
34pub struct FpsOverlay {
35 monitor: Entity<FpsMonitor>,
36 anchor: Anchor,
37 frame_budget: Option<Duration>,
38 continuous: Option<bool>,
39}
40
41impl FpsOverlay {
42 pub fn new(monitor: &Entity<FpsMonitor>) -> Self {
43 Self {
44 monitor: monitor.clone(),
45 anchor: Anchor::TopRight,
46 frame_budget: None,
47 continuous: None,
48 }
49 }
50
51 pub fn anchor(mut self, anchor: Anchor) -> Self {
53 self.anchor = anchor;
54 self
55 }
56
57 pub fn frame_budget(mut self, budget: Duration) -> Self {
59 self.frame_budget = Some(budget);
60 self
61 }
62
63 pub fn continuous(mut self, continuous: bool) -> Self {
66 self.continuous = Some(continuous);
67 self
68 }
69}
70
71impl RenderOnce for FpsOverlay {
72 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
73 if self.frame_budget.is_some() || self.continuous.is_some() {
74 self.monitor.update(cx, |monitor, _| {
75 if let Some(budget) = self.frame_budget {
76 monitor.set_frame_budget(budget);
77 }
78 if let Some(continuous) = self.continuous {
79 monitor.set_continuous(continuous);
80 }
81 });
82 }
83 let margin = MARGIN;
84
85 div()
90 .absolute()
91 .flex()
92 .map(|this| match self.anchor {
93 Anchor::TopLeft => this.top(margin).left(margin),
94 Anchor::TopRight => this.top(margin).right(margin),
95 Anchor::BottomLeft => this.bottom(margin).left(margin),
96 Anchor::BottomRight => this.bottom(margin).right(margin),
97 Anchor::TopCenter => this.top(margin).left_0().right_0().justify_center(),
98 Anchor::BottomCenter => this.bottom(margin).left_0().right_0().justify_center(),
99 Anchor::LeftCenter => this.left(margin).top_0().bottom_0().items_center(),
100 Anchor::RightCenter => this.right(margin).top_0().bottom_0().items_center(),
101 })
102 .child(self.monitor)
103 }
104}