#pragma once #include #include // Forward declarations para evitar incluir headers pesados aqui. Las // definiciones reales viven en cpp/functions/core/*.h y se incluyen desde // app_base.cpp. namespace fn_ui { struct PanelToggle; struct LayoutCallbacks; // Info estatica para la ventana About. Si name != nullptr, fn::run_app // llama about_window_set_info(name, version, description) tras settings_load(). struct AppAboutInfo { const char* name = nullptr; const char* version = nullptr; const char* description = nullptr; }; // Config de logging. Si file_path != nullptr, fn::run_app llama // fn_log::logger_init(file_path, level) al inicio y fn_log::logger_close() // al exit. file_path se interpreta relativo al cwd (junto al ejecutable, // igual que app_settings.ini). Si file_path == nullptr, no se escribe a // disco — la ventana Logs sigue funcionando contra el buffer in-memory. // // level: 0=Debug, 1=Info, 2=Warn, 3=Error. Default Info. struct AppLogConfig { const char* file_path = nullptr; int level = 1; // fn_log::Level::Info }; } namespace fn { // ---------------------------------------------------------------------------- // Local files — separacion de archivos distribuibles vs estado local. // ---------------------------------------------------------------------------- // // Convencion del registry: TODA app coloca sus archivos escribibles // (settings, DBs, layouts ImGui, caches, proyectos del usuario) bajo // `/local_files/`. Los archivos distribuibles (.exe, .ttf, // .dll, runtime/, enrichers/) viven directos en `/`. // // Esto mantiene la carpeta del .exe limpia para distribuir, separa // nitidamente "lo que vino con el zip" de "lo que el PC genero", y // facilita el reset (basta con borrar local_files/). // // `fn::run_app` configura `io.IniFilename = local_path("imgui.ini")` y // `app_settings.ini` se lee/escribe desde local_files/ automaticamente. // Cualquier archivo escribible adicional de la app debe usar // `fn::local_path("nombre")` al construir su path. // // La carpeta se crea on-demand en la primera llamada a `local_dir()`. // Si existen archivos viejos en el cwd (compat con versiones previas // del registry), `migrate_to_local_files()` los mueve. // Devuelve el directorio del ejecutable actual (sin trailing slash). // "" si no se puede resolver (raro — fallback al cwd). const char* exe_dir(); // Devuelve el path absoluto a `/local_files/`. Crea la // carpeta si no existe. Sin trailing slash. const char* local_dir(); // Construye `/`. El puntero retornado apunta a un // std::string interno por-thread que permanece valido hasta la // proxima llamada — copia el valor si vas a guardarlo. const char* local_path(const char* name); // Devuelve `/assets/` — read-only sidecar shipped con la // app (ttfs, enrichers, runtime Python, etc.). NO crea la carpeta; // si no existe, la app debe fallback a buscar los assets en // FN_CPP_ROOT u otras rutas. Sin trailing slash. const char* asset_dir(); // Construye `/`. Mismo lifetime que local_path. const char* asset_path(const char* name); // Mueve los archivos listados de cwd o exe_dir a local_files/ si // existen ahi pero NO existen ya en local_files/. Idempotente. Las // apps lo llaman al iniciar para migrar instalaciones viejas. void migrate_to_local_files(const char* const* names, std::size_t n); // Framework metadata (auto-generated from modules/framework/module.md via // `fn index`). About panel reads these. const char* framework_version(); const char* framework_description(); // Modos de tema para run_app. enum class ThemeMode { FnDark, // Identidad del registry (Mantine v9 dark + indigo). DEFAULT. ImGuiDark, // Tema estandar de ImGui (ImGui::StyleColorsDark). ImGuiLight, None, // No tocar el ImGuiStyle — la app lo configura. }; struct AppConfig { const char* title = "fn_registry"; int width = 1280; int height = 720; bool vsync = true; bool viewports = true; // Multi-viewport ON por defecto: ventanas ImGui arrastrables fuera del main window ThemeMode theme = ThemeMode::FnDark; // Identidad visual unificada por defecto float bg_r = 0.102f; // fn_tokens::colors::bg (dark.7 #1A1B1E) float bg_g = 0.106f; float bg_b = 0.118f; // About window. Si about.name != nullptr, run_app llama // fn_ui::about_window_set_info(name, version, description) tras settings_load(). fn_ui::AppAboutInfo about{}; // Paneles toggleables del menubar. Si panels != nullptr y panel_count > 0, // run_app llama fn_ui::app_menubar(panels, panel_count, layouts_cb) cada frame // ANTES de render_fn(). const fn_ui::PanelToggle* panels = nullptr; std::size_t panel_count = 0; // Callbacks de layouts persistentes. Si layouts_cb != nullptr, run_app // llama fn_ui::app_menubar(panels, panel_count, layouts_cb) cada frame. // Si layouts_cb == nullptr y auto_layouts == true (default), run_app abre // un fn_ui::LayoutStorage por defecto sobre `/`, // genera unos LayoutCallbacks estandar (save/load/list/delete/reset), // los aplica al inicio de cada frame y los cierra al salir. Asi cualquier // app obtiene el menu Layouts gratis sin tocar codigo. fn_ui::LayoutCallbacks* layouts_cb = nullptr; // Auto-wiring del menu Layouts cuando layouts_cb == nullptr. // - true (default): run_app crea LayoutStorage interno con SQLite. // - false: no se crea storage. Util si la app no quiere persistencia // (ej. demo headless, capture mode). bool auto_layouts = true; // Nombre del archivo SQLite (relativo a `/local_files/`) usado // por el layout storage por defecto. Solo se consulta si layouts_cb es // nullptr y auto_layouts es true. Default "layouts.db". const char* auto_layouts_db = "layouts.db"; // Items extra dentro del menu "View", al final tras los toggles de // paneles. Si view_extras != nullptr, run_app lo pasa a app_menubar. // El callback se invoca dentro de un BeginMenu("View") ya abierto: // la app llama directamente a ImGui::Separator(), MenuItem(), etc. // NO debe abrir/cerrar el menu View. std::function view_extras{}; // Si true, run_app llama fn::gfx::gl_loader_init() tras crear el contexto // GL y antes del primer frame. Necesario para apps que llaman gl* directo // en Windows (en Linux es no-op). bool init_gl_loader = false; // Auto-dockspace: si true, run_app llama // ImGui::DockSpaceOverViewport(0, GetMainViewport(), PassthruCentralNode) // ANTES de render_fn() cada frame. Asi cualquier app obtiene un dockspace // central donde re-anclar ventanas flotantes (incl. viewports OS) sin // tocar su render(). Apps con layout custom (shaders_lab) o galerias // (primitives_gallery) pueden poner false para gestionarlo ellas. bool auto_dockspace = true; // Logging opcional. Si log.file_path != nullptr, run_app inicializa el // logger global antes del primer frame y lo cierra al exit. La ventana // "Logs..." en el menubar siempre esta disponible (lee del buffer // in-memory aunque no haya archivo). fn_ui::AppLogConfig log{}; // Hook opcional ejecutado al inicio de cada frame (despues de // ImGui::NewFrame, ANTES de app_menubar y de auto-dockspace). Pensado para // que apps con LayoutStorage propio llamen layout_storage_apply_pending // en el momento correcto: ImGui requiere LoadIniSettingsFromMemory antes // de cualquier Begin() del frame para que las dock-nodes guardadas se // restauren correctamente. Si la app llama LoadIni mid-frame (dentro de // render_fn) las ventanas docked aparecen flotantes hasta el siguiente // ciclo. Default null = no-op. std::function pre_frame{}; }; // Run an ImGui application. The render_fn is called every frame // between ImGui::NewFrame() and ImGui::Render(). // Returns 0 on clean exit, 1 on error. int run_app(AppConfig config, std::function render_fn); // Convenience: run with default config int run_app(std::function render_fn); // Test-only observability hooks for the Win32 anti-jitter / Alt+RMB resize // subclass. Counters increment monotonically across the life of the process. // On non-Windows targets they always return 0. namespace internal { int sizemove_enter_count(); int alt_rmb_resize_count(); int alt_lmb_move_count(); int rbuttondown_seen_count(); void set_force_alt_for_test(bool v); } } // namespace fn // ---------------------------------------------------------------------------- // E2E testing — Dear ImGui Test Engine integration. // ---------------------------------------------------------------------------- // // Only available when the registry is built with -DFN_BUILD_TESTS=ON. The // CMake option defines IMGUI_ENABLE_TEST_ENGINE on imgui+fn_framework and // links the imgui_test_engine static lib. Without the option, run_app_test is // not declared and apps build identically to today. #ifdef IMGUI_ENABLE_TEST_ENGINE struct ImGuiTestEngine; namespace fn { // Run an app under Dear ImGui Test Engine. Same as run_app, but: // 1. Creates a test engine and binds it to the ImGui context. // 2. Calls register_tests(engine) once before the main loop. Tests are // registered with IM_REGISTER_TEST(engine, "category", "name") and // assigned a TestFunc lambda that drives the UI. // 3. Queues all tests matching `filter` (default "all") and ticks frames // until the queue empties. // 4. Exits with code 0 if all tests pass, 1 if any failed or crashed. // // register_tests must be non-null and must register at least one test or the // function returns 1. int run_app_test(AppConfig config, std::function render_fn, std::function register_tests, const char* filter = "all"); } // namespace fn #endif // IMGUI_ENABLE_TEST_ENGINE