pfx_editor_style/widgets/
header.rs1use egui::{Align2, CornerRadius, Id, Rect, Response, Sense, Stroke, StrokeKind, Ui, Vec2, Widget};
2
3use super::{State, place, shaped};
4use crate::theme::Theme;
5
6pub struct Header<'a> {
7 code: &'a str,
8 title: &'a str,
9 info: Option<&'a str>,
10 focused: bool,
11 width: Option<f32>,
12 id: Option<Id>,
13}
14
15impl<'a> Header<'a> {
16 pub fn new(code: &'a str, title: &'a str) -> Header<'a> {
17 Header {
18 code,
19 title,
20 info: None,
21 focused: false,
22 width: None,
23 id: None,
24 }
25 }
26
27 pub fn info(mut self, info: &'a str) -> Header<'a> {
28 self.info = Some(info);
29 self
30 }
31
32 pub fn width(mut self, width: f32) -> Header<'a> {
33 self.width = Some(width);
34 self
35 }
36
37 pub fn id(mut self, id: Id) -> Header<'a> {
38 self.id = Some(id);
39 self
40 }
41
42 pub fn focused(mut self, focused: bool) -> Header<'a> {
43 self.focused = focused;
44 self
45 }
46}
47
48impl Widget for Header<'_> {
49 fn ui(self, ui: &mut Ui) -> Response {
50 let theme = Theme::of(ui.ctx());
51 let size = Vec2::new(
52 self.width.unwrap_or_else(|| ui.available_width()),
53 theme.row_height + 2.0,
54 );
55 let (rect, response) = match self.id {
56 Some(id) => {
57 let (rect, _) = ui.allocate_exact_size(size, Sense::hover());
58 (rect, ui.interact(rect, id, Sense::click()))
59 }
60 None => ui.allocate_exact_size(size, Sense::click()),
61 };
62 if !ui.is_rect_visible(rect) {
63 return response;
64 }
65 let state = State::of(&response, self.focused);
66 let painter = ui.painter();
67 let code_font = theme.font(theme.size_code);
68 let code_width = painter
69 .layout_no_wrap(self.code.into(), code_font.clone(), theme.dim)
70 .size()
71 .x;
72 let code_rect = Rect::from_min_size(
73 rect.left_center() - Vec2::new(0.0, 8.0),
74 Vec2::new((code_width + 8.0).round(), 16.0),
75 );
76 let (code_fill, code_border, code_text, title_text) = match state {
77 State::Rest => (theme.bg, theme.line, theme.dim, theme.text2),
78 State::Hovered => (theme.bg, theme.accent, theme.text2, theme.text),
79 State::Active => (theme.hot, theme.hot, theme.on_accent, theme.text),
80 };
81 painter.rect(
82 code_rect,
83 CornerRadius::same(theme.radius),
84 code_fill,
85 Stroke::new(theme.stroke, code_border),
86 StrokeKind::Inside,
87 );
88 painter.text(
89 code_rect.center(),
90 Align2::CENTER_CENTER,
91 self.code,
92 code_font,
93 code_text,
94 );
95 let title = shaped(
96 painter,
97 self.title,
98 theme.title_font(theme.size_small),
99 title_text,
100 theme.titles,
101 );
102 place(
103 painter,
104 code_rect.right_center() + Vec2::new(8.0, 0.0),
105 Align2::LEFT_CENTER,
106 title,
107 title_text,
108 );
109 if let Some(info) = self.info {
110 let info = shaped(
111 painter,
112 info,
113 theme.font(theme.size_code),
114 theme.muted,
115 theme.labels,
116 );
117 place(
118 painter,
119 rect.right_center(),
120 Align2::RIGHT_CENTER,
121 info,
122 theme.muted,
123 );
124 }
125 response
126 }
127}