comparison infinite_canvas/dev_ui.c @ 280:49e9e591c9bb

Add persistent dictation, prewarmed WebRTC speech input, Copilot SDK routing, animated conversation lifecycle controls, parking, and architecture coverage.
author MrJuneJune <me@mrjunejune.com>
date Tue, 18 Aug 2026 19:14:53 -0700
parents 8d560f50ed4c
children c57149ad216e
comparison
equal deleted inserted replaced
279:b3b547563ec7 280:49e9e591c9bb
3 #include <math.h> 3 #include <math.h>
4 4
5 #define RAYGUI_IMPLEMENTATION 5 #define RAYGUI_IMPLEMENTATION
6 #include "third_party/raylib/include/raygui.h" 6 #include "third_party/raylib/include/raygui.h"
7 7
8 static const Rectangle DEV_PANEL = {18.0f, 18.0f, 264.0f, 478.0f}; 8 static const Rectangle DEV_PANEL = {18.0f, 18.0f, 264.0f, 520.0f};
9 static const Rectangle DEV_PANEL_COLLAPSED = {18.0f, 18.0f, 44.0f, 44.0f};
9 10
10 static Rectangle Canvas_Dev_UI_Context_Bounds(void) 11 static Rectangle Canvas_Dev_UI_Context_Bounds(void)
11 { 12 {
12 float width = 610.0f; 13 float width = 610.0f;
13 float x = (float)GetScreenWidth() - width - 18.0f; 14 float x = (float)GetScreenWidth() - width - 18.0f;
204 Font font, 205 Font font,
205 const Canvas_Theme *p_theme) 206 const Canvas_Theme *p_theme)
206 { 207 {
207 *p_ui = (Canvas_Dev_UI){ 208 *p_ui = (Canvas_Dev_UI){
208 .selected_type = CANVAS_ENTITY_RECTANGLE, 209 .selected_type = CANVAS_ENTITY_RECTANGLE,
210 .collapsed = FALSE,
209 .dropdown_open = FALSE, 211 .dropdown_open = FALSE,
210 .context_open = FALSE, 212 .context_open = FALSE,
211 }; 213 };
212 Canvas_Dev_UI_Set_Style(font, p_theme); 214 Canvas_Dev_UI_Set_Style(font, p_theme);
213 } 215 }
217 // The expanded dropdown is modal: it draws outside DEV_PANEL and also 219 // The expanded dropdown is modal: it draws outside DEV_PANEL and also
218 // consumes outside clicks to close itself. 220 // consumes outside clicks to close itself.
219 if (p_ui->dropdown_open) return TRUE; 221 if (p_ui->dropdown_open) return TRUE;
220 222
221 Vector2 pointer = GetMousePosition(); 223 Vector2 pointer = GetMousePosition();
222 if (CheckCollisionPointRec(pointer, DEV_PANEL)) return TRUE; 224 if (CheckCollisionPointRec(
225 pointer,
226 p_ui->collapsed ? DEV_PANEL_COLLAPSED : DEV_PANEL)) {
227 return TRUE;
228 }
223 if (p_ui->context_open && 229 if (p_ui->context_open &&
224 CheckCollisionPointRec(pointer, Canvas_Dev_UI_Context_Bounds())) { 230 CheckCollisionPointRec(pointer, Canvas_Dev_UI_Context_Bounds())) {
225 return TRUE; 231 return TRUE;
226 } 232 }
227 return FALSE; 233 return FALSE;
232 Canvas_Camera *p_camera, 238 Canvas_Camera *p_camera,
233 Canvas_Scene *p_scene, 239 Canvas_Scene *p_scene,
234 Font font, 240 Font font,
235 Canvas_Theme *p_theme) 241 Canvas_Theme *p_theme)
236 { 242 {
243 if (p_ui->collapsed) {
244 Canvas_Theme_Draw_Shadow(
245 p_theme,
246 DEV_PANEL_COLLAPSED,
247 0.24f,
248 12,
249 1.0f,
250 1.0f);
251 DrawRectangleRounded(
252 DEV_PANEL_COLLAPSED,
253 0.24f,
254 12,
255 p_theme->surface);
256 DrawRectangleRoundedLinesEx(
257 DEV_PANEL_COLLAPSED,
258 0.24f,
259 12,
260 1.0f,
261 p_theme->border);
262 if (GuiButtonRounded(
263 (Rectangle){24.0f, 24.0f, 32.0f, 32.0f},
264 ">",
265 0.30f,
266 10)) {
267 p_ui->collapsed = FALSE;
268 }
269 return;
270 }
271
237 Canvas_Context_Snapshot context = Canvas_Scene_Build_Visible_Context( 272 Canvas_Context_Snapshot context = Canvas_Scene_Build_Visible_Context(
238 p_scene, 273 p_scene,
239 p_camera, 274 p_camera,
240 p_ui->context_buffer, 275 p_ui->context_buffer,
241 sizeof(p_ui->context_buffer)); 276 sizeof(p_ui->context_buffer));
254 "Developer controls", 289 "Developer controls",
255 (Vector2){34.0f, 61.0f}, 290 (Vector2){34.0f, 61.0f},
256 12.0f, 291 12.0f,
257 0.1f, 292 0.1f,
258 p_theme->text_muted); 293 p_theme->text_muted);
294 if (GuiButtonRounded(
295 (Rectangle){230.0f, 30.0f, 36.0f, 30.0f},
296 "<",
297 0.30f,
298 10)) {
299 p_ui->collapsed = TRUE;
300 p_ui->dropdown_open = FALSE;
301 p_ui->context_open = FALSE;
302 return;
303 }
259 304
260 if (p_ui->dropdown_open) GuiLock(); 305 if (p_ui->dropdown_open) GuiLock();
261 306
262 if (GuiButtonRounded((Rectangle){34.0f, 126.0f, 112.0f, 34.0f}, "Add entity", 0.32f, 10)) { 307 if (GuiButtonRounded((Rectangle){34.0f, 126.0f, 112.0f, 34.0f}, "Add entity", 0.32f, 10)) {
263 Canvas_Scene_Add( 308 Canvas_Scene_Add(
320 0.32f, 365 0.32f,
321 10)) { 366 10)) {
322 Canvas_Scene_Show_Lucide_Gallery(p_scene, p_camera); 367 Canvas_Scene_Show_Lucide_Gallery(p_scene, p_camera);
323 } 368 }
324 369
325 DrawTextEx(font, TextFormat("%d FPS", GetFPS()), (Vector2){34.0f, 396.0f}, 12.0f, 0.0f, p_theme->text_muted); 370 size_t parked_count = Canvas_Scene_Parked_Conversation_Count(p_scene);
326 DrawTextEx(font, TextFormat("%.2fx zoom", p_camera->zoom), (Vector2){104.0f, 396.0f}, 12.0f, 0.0f, p_theme->text_muted); 371 if (GuiButtonRounded(
372 (Rectangle){34.0f, 378.0f, 232.0f, 34.0f},
373 TextFormat("Parking lot (%d)", (int)parked_count),
374 0.32f,
375 10)) {
376 Canvas_Scene_Show_Parking_Lot(p_scene, p_camera);
377 }
378
379 DrawTextEx(font, TextFormat("%d FPS", GetFPS()), (Vector2){34.0f, 438.0f}, 12.0f, 0.0f, p_theme->text_muted);
380 DrawTextEx(font, TextFormat("%.2fx zoom", p_camera->zoom), (Vector2){104.0f, 438.0f}, 12.0f, 0.0f, p_theme->text_muted);
327 DrawTextEx( 381 DrawTextEx(
328 font, 382 font,
329 TextFormat("%d objects", (int)Dowa_Array_Length(p_scene->p_entities)), 383 TextFormat("%d objects", (int)Dowa_Array_Length(p_scene->p_entities)),
330 (Vector2){196.0f, 396.0f}, 384 (Vector2){196.0f, 438.0f},
331 12.0f, 385 12.0f,
332 0.0f, 386 0.0f,
333 p_theme->text_muted); 387 p_theme->text_muted);
334 DrawTextEx( 388 DrawTextEx(
335 font, 389 font,
336 "Drag objects directly on the canvas", 390 "Drag objects directly on the canvas",
337 (Vector2){34.0f, 442.0f}, 391 (Vector2){34.0f, 484.0f},
338 12.0f, 392 12.0f,
339 0.0f, 393 0.0f,
340 p_theme->text_muted); 394 p_theme->text_muted);
341 395
342 if (p_ui->context_open) { 396 if (p_ui->context_open) {