Skip to main content

khora_editor/widgets/
brand.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// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Brand-mark painters — the Khora "diamond" shape and its containing pills.
16//!
17//! The diamond itself is defined once in `khora_tool_ui::widgets`; the helpers
18//! here adapt it to the editor's `(cx, cy, half_extent)` convention and add the
19//! editor-only outline + brand-pill composite.
20
21use khora_sdk::editor_ui::{FontFamilyHint, TextAlign, UiBuilder, UiTheme};
22
23use super::paint::with_alpha;
24
25/// Paints a 4-point diamond (rotated square) outline centered at `(cx, cy)`.
26///
27/// Editor-only: the shared library ships a filled diamond, not an outlined one
28/// (the empty-state used to draw it, but that now uses the shared `empty_state`
29/// widget). Kept here for the few chrome call sites that still want the ring.
30pub fn paint_diamond_outline(
31    ui: &mut dyn UiBuilder,
32    cx: f32,
33    cy: f32,
34    size: f32,
35    color: [f32; 4],
36    thickness: f32,
37) {
38    let top = [cx, cy - size];
39    let right = [cx + size, cy];
40    let bottom = [cx, cy + size];
41    let left = [cx - size, cy];
42    ui.paint_line(top, right, color, thickness);
43    ui.paint_line(right, bottom, color, thickness);
44    ui.paint_line(bottom, left, color, thickness);
45    ui.paint_line(left, top, color, thickness);
46}
47
48/// Paints a filled 4-point diamond centred at `(cx, cy)` with half-extent
49/// `size`. Adapter over [`khora_tool_ui::widgets::diamond`] (whose `size` is
50/// the full width), so the geometry is defined in exactly one place.
51pub fn paint_diamond_filled(ui: &mut dyn UiBuilder, cx: f32, cy: f32, size: f32, color: [f32; 4]) {
52    khora_tool_ui::widgets::diamond(ui, [cx, cy], size * 2.0, color);
53}
54
55/// Paints the editor's branded "pill" (rounded 999 background containing a
56/// diamond, the engine name, a separator and the active project name).
57///
58/// Returns the right edge of the pill in screen-space, so the caller can
59/// position the next widget after it.
60pub fn paint_brand_pill(
61    ui: &mut dyn UiBuilder,
62    origin: [f32; 2],
63    height: f32,
64    engine_name: &str,
65    project_name: &str,
66    theme: &UiTheme,
67) -> f32 {
68    // Real font measurement (Phase 3 — replaces the previous 7px-per-char
69    // guess that broke at large font sizes / non-ASCII names).
70    let engine_w = ui.measure_text(
71        engine_name,
72        theme.font_size_body,
73        FontFamilyHint::Proportional,
74    )[0];
75    let project_w = ui.measure_text(
76        project_name,
77        theme.font_size_body - 1.0,
78        FontFamilyHint::Proportional,
79    )[0];
80    let total_w = 18.0 /* diamond */ + 12.0 + engine_w + 14.0 /* sep */ + project_w + 24.0;
81
82    let pad_y = (height - 24.0).max(0.0) * 0.5;
83    let pill_h = (height - pad_y * 2.0).max(20.0);
84    let pill_x = origin[0];
85    let pill_y = origin[1] + pad_y;
86
87    // Background
88    ui.paint_rect_filled(
89        [pill_x, pill_y],
90        [total_w, pill_h],
91        with_alpha(theme.background, 0.6),
92        pill_h * 0.5,
93    );
94    ui.paint_rect_stroke(
95        [pill_x, pill_y],
96        [total_w, pill_h],
97        with_alpha(theme.separator, 0.6),
98        pill_h * 0.5,
99        1.0,
100    );
101
102    // Diamond
103    let diamond_cx = pill_x + 14.0;
104    let diamond_cy = pill_y + pill_h * 0.5;
105    paint_diamond_filled(ui, diamond_cx, diamond_cy, 6.5, theme.primary);
106
107    // Engine name
108    let text_y = pill_y + (pill_h - theme.font_size_body) * 0.5;
109    ui.paint_text_styled(
110        [pill_x + 26.0, text_y],
111        engine_name,
112        theme.font_size_body,
113        theme.text,
114        FontFamilyHint::Proportional,
115        TextAlign::Left,
116    );
117
118    // Vertical separator after engine name
119    let sep_x = pill_x + 26.0 + engine_w + 6.0;
120    ui.paint_line(
121        [sep_x, pill_y + 5.0],
122        [sep_x, pill_y + pill_h - 5.0],
123        with_alpha(theme.border, 0.7),
124        1.0,
125    );
126
127    // Project name
128    ui.paint_text_styled(
129        [sep_x + 8.0, text_y],
130        project_name,
131        theme.font_size_body - 1.0,
132        theme.text_muted,
133        FontFamilyHint::Proportional,
134        TextAlign::Left,
135    );
136
137    pill_x + total_w
138}