Skip to main content

khora_editor/widgets/inspector/
header.rs

1// Copyright 2025 eraflo
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8
9//! Inspector header — composite widget used by the Properties panel.
10
11use khora_sdk::editor_ui::{FontFamilyHint, Icon, TextAlign, UiBuilder, UiTheme};
12
13use crate::widgets::paint::{paint_icon, paint_text_size, with_alpha};
14
15/// Paints the Inspector's rich header — large icon tile + name + meta row
16/// (tag + status pill + id). Returns the bottom edge in screen-space.
17#[allow(clippy::too_many_arguments)]
18pub fn paint_inspector_header(
19    ui: &mut dyn UiBuilder,
20    origin: [f32; 2],
21    width: f32,
22    icon: Icon,
23    name: &str,
24    type_tag: &str,
25    status_label: &str,
26    status_color: [f32; 4],
27    id_label: Option<&str>,
28    theme: &UiTheme,
29) -> f32 {
30    let h = 64.0;
31    let pad = 12.0;
32
33    // Background
34    ui.paint_rect_filled(origin, [width, h], theme.surface, 0.0);
35    ui.paint_line(
36        [origin[0], origin[1] + h],
37        [origin[0] + width, origin[1] + h],
38        with_alpha(theme.separator, 0.55),
39        1.0,
40    );
41
42    // Icon tile
43    let tile_x = origin[0] + pad;
44    let tile_y = origin[1] + 14.0;
45    ui.paint_rect_filled([tile_x, tile_y], [36.0, 36.0], theme.surface_active, 8.0);
46    ui.paint_rect_stroke([tile_x, tile_y], [36.0, 36.0], theme.border, 8.0, 1.0);
47    paint_icon(
48        ui,
49        [tile_x + 10.0, tile_y + 10.0],
50        icon,
51        16.0,
52        theme.primary,
53    );
54
55    // Name
56    let name_x = tile_x + 48.0;
57    paint_text_size(ui, [name_x, origin[1] + 14.0], name, 14.5, theme.text);
58
59    // Meta row
60    let meta_y = origin[1] + 36.0;
61    // Type tag
62    let tag_w = ui.measure_text(type_tag, 10.0, FontFamilyHint::Monospace)[0] + 14.0;
63    ui.paint_rect_filled([name_x, meta_y], [tag_w, 16.0], theme.surface_active, 3.0);
64    ui.paint_text_styled(
65        [name_x + tag_w * 0.5, meta_y + 2.5],
66        type_tag,
67        10.0,
68        theme.text_dim,
69        FontFamilyHint::Monospace,
70        TextAlign::Center,
71    );
72
73    // Status pill
74    let pill_x = name_x + tag_w + 8.0;
75    let label_w = ui.measure_text(status_label, 10.5, FontFamilyHint::Proportional)[0] + 22.0;
76    ui.paint_rect_filled(
77        [pill_x, meta_y],
78        [label_w, 16.0],
79        with_alpha(status_color, 0.18),
80        999.0,
81    );
82    ui.paint_circle_filled([pill_x + 8.0, meta_y + 8.0], 2.5, status_color);
83    paint_text_size(
84        ui,
85        [pill_x + 14.0, meta_y + 3.0],
86        status_label,
87        10.5,
88        status_color,
89    );
90
91    // Id
92    if let Some(id) = id_label {
93        ui.paint_text_styled(
94            [pill_x + label_w + 10.0, meta_y + 3.5],
95            id,
96            10.0,
97            theme.text_muted,
98            FontFamilyHint::Monospace,
99            TextAlign::Left,
100        );
101    }
102
103    origin[1] + h
104}