Mercurial
comparison infinite_canvas/main.c @ 278:8d560f50ed4c
Improve infinite canvas interactions and browser chrome
Render Lucide icons directly with Raylib, add searchable icon browsing, robust text editing, entity lifecycle animations, z-order-safe input, semantic themes, and animated editable browser controls. Document rendering, pinning, context, and component extension for future agents.
Co-authored-by: Copilot <[email protected]>
Copilot-Session: f68442b1-fa8f-46a0-9689-81710613bbd4
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 17 Aug 2026 22:16:14 -0700 |
| parents | b55c22cff335 |
| children | 49e9e591c9bb |
comparison
equal
deleted
inserted
replaced
| 277:1d99147f520c | 278:8d560f50ed4c |
|---|---|
| 38 | 38 |
| 39 boolean block_pointer_input = FALSE; | 39 boolean block_pointer_input = FALSE; |
| 40 #if defined(INFINITE_CANVAS_DEV_UI) | 40 #if defined(INFINITE_CANVAS_DEV_UI) |
| 41 block_pointer_input = Canvas_Dev_UI_Contains_Pointer(&g_app->dev_ui); | 41 block_pointer_input = Canvas_Dev_UI_Contains_Pointer(&g_app->dev_ui); |
| 42 #endif | 42 #endif |
| 43 boolean web_input = Canvas_Web_Surface_Update_Input( | 43 Canvas_Web_Surface_Set_Dark_Mode( |
| 44 &g_app->web_surface, | 44 &g_app->web_surface, |
| 45 &g_app->camera, | 45 g_app->theme.resolved_mode == CANVAS_THEME_DARK ? TRUE : FALSE); |
| 46 &g_app->scene); | 46 Canvas_Web_Chrome_Action chrome_action = CANVAS_WEB_CHROME_NONE; |
| 47 block_pointer_input = block_pointer_input || web_input; | 47 if (!block_pointer_input) { |
| 48 const char *p_current_url = NULL; | |
| 49 if (g_app->scene.selected_index >= 0 && | |
| 50 g_app->scene.selected_index < | |
| 51 (int32)Dowa_Array_Length(g_app->scene.p_entities)) { | |
| 52 const Canvas_Entity *p_selected = | |
| 53 &g_app->scene.p_entities[g_app->scene.selected_index]; | |
| 54 p_current_url = Canvas_Web_Surface_URL( | |
| 55 &g_app->web_surface, | |
| 56 p_selected->id); | |
| 57 } | |
| 58 chrome_action = Canvas_Web_Chrome_Update_Input( | |
| 59 &g_app->camera, | |
| 60 &g_app->scene, | |
| 61 g_app->font, | |
| 62 p_current_url); | |
| 63 } | |
| 64 if (chrome_action == CANVAS_WEB_CHROME_BACK || | |
| 65 chrome_action == CANVAS_WEB_CHROME_FORWARD) { | |
| 66 const Canvas_Entity *p_selected = | |
| 67 &g_app->scene.p_entities[g_app->scene.selected_index]; | |
| 68 if (chrome_action == CANVAS_WEB_CHROME_BACK) { | |
| 69 Canvas_Web_Surface_Go_Back( | |
| 70 &g_app->web_surface, | |
| 71 p_selected->id); | |
| 72 } else { | |
| 73 Canvas_Web_Surface_Go_Forward( | |
| 74 &g_app->web_surface, | |
| 75 p_selected->id); | |
| 76 } | |
| 77 } | |
| 78 boolean web_input = FALSE; | |
| 79 if (!block_pointer_input && chrome_action == CANVAS_WEB_CHROME_NONE) { | |
| 80 web_input = Canvas_Web_Surface_Update_Input( | |
| 81 &g_app->web_surface, | |
| 82 &g_app->camera, | |
| 83 &g_app->scene); | |
| 84 } | |
| 85 block_pointer_input = | |
| 86 block_pointer_input || | |
| 87 chrome_action != CANVAS_WEB_CHROME_NONE || | |
| 88 web_input; | |
| 48 boolean entity_input = Canvas_Scene_Update_Interaction( | 89 boolean entity_input = Canvas_Scene_Update_Interaction( |
| 49 &g_app->scene, | 90 &g_app->scene, |
| 50 &g_app->camera, | 91 &g_app->camera, |
| 92 g_app->font, | |
| 51 block_pointer_input); | 93 block_pointer_input); |
| 52 boolean keyboard_focus = | 94 boolean keyboard_focus = |
| 53 Canvas_Scene_Is_Text_Editing(&g_app->scene) || | 95 Canvas_Scene_Is_Text_Editing(&g_app->scene) || |
| 96 Canvas_Web_Chrome_Is_Editing(&g_app->scene) || | |
| 54 Canvas_Web_Surface_Is_Focused(&g_app->web_surface); | 97 Canvas_Web_Surface_Is_Focused(&g_app->web_surface); |
| 55 if (!keyboard_focus && IsKeyPressed(KEY_P)) { | 98 if (!keyboard_focus && IsKeyPressed(KEY_P)) { |
| 56 Canvas_Scene_Toggle_Selected_Pin(&g_app->scene, &g_app->camera); | 99 Canvas_Scene_Toggle_Selected_Pin(&g_app->scene, &g_app->camera); |
| 100 } | |
| 101 if (!keyboard_focus && | |
| 102 (IsKeyPressed(KEY_DELETE) || IsKeyPressed(KEY_BACKSPACE))) { | |
| 103 Canvas_Scene_Fade_Out_Selected(&g_app->scene); | |
| 57 } | 104 } |
| 58 Canvas_Update_Camera_Input( | 105 Canvas_Update_Camera_Input( |
| 59 &g_app->camera, | 106 &g_app->camera, |
| 60 block_pointer_input || entity_input, | 107 block_pointer_input || entity_input, |
| 61 keyboard_focus); | 108 keyboard_focus); |
| 64 | 111 |
| 65 Canvas_Web_Surface_Sync(&g_app->web_surface, &g_app->camera, &g_app->scene); | 112 Canvas_Web_Surface_Sync(&g_app->web_surface, &g_app->camera, &g_app->scene); |
| 66 | 113 |
| 67 BeginDrawing(); | 114 BeginDrawing(); |
| 68 ClearBackground(g_app->theme.background); | 115 ClearBackground(g_app->theme.background); |
| 69 Canvas_Draw_World( | 116 Canvas_Draw_World_Background( |
| 117 &g_app->camera, | |
| 118 &g_app->scene, | |
| 119 &g_app->theme); | |
| 120 for (size_t index = 0; | |
| 121 index < Dowa_Array_Length(g_app->scene.p_entities); | |
| 122 index++) { | |
| 123 Canvas_Draw_World_Entity( | |
| 124 &g_app->camera, | |
| 125 &g_app->scene, | |
| 126 index, | |
| 127 g_app->font, | |
| 128 &g_app->theme); | |
| 129 Canvas_Web_Surface_Draw_Entity( | |
| 130 &g_app->web_surface, | |
| 131 &g_app->camera, | |
| 132 &g_app->scene, | |
| 133 index); | |
| 134 const Canvas_Entity *p_entity = &g_app->scene.p_entities[index]; | |
| 135 const char *p_url = Canvas_Web_Surface_URL( | |
| 136 &g_app->web_surface, | |
| 137 p_entity->id); | |
| 138 Canvas_Draw_Web_Chrome_Entity( | |
| 139 &g_app->camera, | |
| 140 &g_app->scene, | |
| 141 index, | |
| 142 g_app->font, | |
| 143 &g_app->theme, | |
| 144 p_url ? p_url : p_entity->text, | |
| 145 Canvas_Web_Surface_Can_Go_Back( | |
| 146 &g_app->web_surface, | |
| 147 p_entity->id), | |
| 148 Canvas_Web_Surface_Can_Go_Forward( | |
| 149 &g_app->web_surface, | |
| 150 p_entity->id)); | |
| 151 } | |
| 152 Canvas_Draw_World_Overlays( | |
| 70 &g_app->camera, | 153 &g_app->camera, |
| 71 &g_app->scene, | 154 &g_app->scene, |
| 72 g_app->font, | 155 g_app->font, |
| 73 &g_app->theme); | 156 &g_app->theme); |
| 74 Canvas_Web_Surface_Draw(&g_app->web_surface, &g_app->camera, &g_app->scene); | |
| 75 #if defined(INFINITE_CANVAS_DEV_UI) | 157 #if defined(INFINITE_CANVAS_DEV_UI) |
| 76 Canvas_Dev_UI_Draw( | 158 Canvas_Dev_UI_Draw( |
| 77 &g_app->dev_ui, | 159 &g_app->dev_ui, |
| 78 &g_app->camera, | 160 &g_app->camera, |
| 79 &g_app->scene, | 161 &g_app->scene, |
| 129 #endif | 211 #endif |
| 130 SetTargetFPS(60); | 212 SetTargetFPS(60); |
| 131 #if !defined(PLATFORM_WEB) | 213 #if !defined(PLATFORM_WEB) |
| 132 SetWindowFocused(); | 214 SetWindowFocused(); |
| 133 #endif | 215 #endif |
| 134 if (!Canvas_Web_Surface_Init(&g_app->web_surface, p_arena)) { | 216 if (!Canvas_Web_Surface_Init( |
| 217 &g_app->web_surface, | |
| 218 p_arena, | |
| 219 g_app->theme.resolved_mode == CANVAS_THEME_DARK ? TRUE : FALSE)) { | |
| 135 TraceLog(LOG_WARNING, "Web surface initialization failed"); | 220 TraceLog(LOG_WARNING, "Web surface initialization failed"); |
| 136 } | 221 } |
| 137 | 222 |
| 138 g_app->font = LoadFontEx("infinite_canvas/assets/Inter-Variable.ttf", 48, NULL, 0); | 223 g_app->font = LoadFontEx("infinite_canvas/assets/Inter-Variable.ttf", 48, NULL, 0); |
| 139 g_app->owns_font = g_app->font.texture.id != 0; | 224 g_app->owns_font = g_app->font.texture.id != 0; |