docs(flows): DoD obligatorio con user-facing surface + abrir issues 0100-0103 (taxonomia, frontmatter migration, dev_console, work dashboard)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-17 00:07:03 +02:00
parent a03675113a
commit 6ad82167bb
72 changed files with 3920 additions and 303 deletions
+67 -1
View File
@@ -1,4 +1,5 @@
#include "app_base.h"
#include "version_generated.h"
#include "imgui.h"
#include "imgui_impl_glfw.h"
@@ -24,6 +25,7 @@
#include <string>
#include <sys/stat.h>
#include <unordered_map>
#include <unordered_set>
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
@@ -178,6 +180,50 @@ static void install_sizemove_subclass_hwnd(HWND hwnd) {
g_subclassed[hwnd] = orig;
}
// Resource ID generado por cpp/CMakeLists.txt en <target>_appicon.rc:
// 101 ICON "<app_dir>/appicon.ico"
// Si la app no tiene appicon.ico el .rc no se genera y LoadImageW devuelve
// NULL — no error visible, los HWND quedan con el icono GLFW por defecto.
#define FN_APP_ICON_RES_ID 101
// Carga el icono embebido al tamaño OS-recomendado para small (title bar) y
// big (Alt+Tab / taskbar). LR_SHARED -> Windows gestiona el handle; no hay
// que DestroyIcon. Cacheado por HMODULE+ID+size.
static HICON load_app_icon(int cx, int cy) {
HMODULE mod = GetModuleHandleW(nullptr);
return (HICON)LoadImageW(mod, MAKEINTRESOURCEW(FN_APP_ICON_RES_ID),
IMAGE_ICON, cx, cy, LR_SHARED | LR_DEFAULTCOLOR);
}
// Adjunta el icono embebido al HWND:
// WM_SETICON ICON_SMALL -> title bar (16x16) y Alt+Tab small variant.
// WM_SETICON ICON_BIG -> taskbar (32x32) y Alt+Tab big variant.
// SetClassLongPtrW propaga el icono al WNDCLASS para que nuevos HWNDs de la
// misma clase lo hereden (no critico — el per-frame scan ya cubre cada
// viewport secundario via su HWND propio, que puede tener WNDCLASS distinta).
static std::unordered_set<HWND> g_icon_attached;
static void attach_app_icon_to_hwnd(HWND hwnd) {
if (!hwnd) return;
if (g_icon_attached.count(hwnd)) return; // idempotent
HICON hSmall = load_app_icon(GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON));
HICON hBig = load_app_icon(GetSystemMetrics(SM_CXICON),
GetSystemMetrics(SM_CYICON));
if (!hSmall && !hBig) return; // no appicon.ico embebido — nada que hacer
if (hSmall) SendMessageW(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hSmall);
if (hBig) SendMessageW(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hBig);
if (hSmall) SetClassLongPtrW(hwnd, GCLP_HICONSM, (LONG_PTR)hSmall);
if (hBig) SetClassLongPtrW(hwnd, GCLP_HICON, (LONG_PTR)hBig);
g_icon_attached.insert(hwnd);
}
static void prune_dead_icon_attached() {
for (auto it = g_icon_attached.begin(); it != g_icon_attached.end();) {
if (!IsWindow(*it)) it = g_icon_attached.erase(it);
else ++it;
}
}
static void install_sizemove_subclass(GLFWwindow* w) {
if (!w) return;
install_sizemove_subclass_hwnd(glfwGetWin32Window(w));
@@ -337,6 +383,14 @@ void migrate_to_local_files(const char* const* names, std::size_t n) {
}
}
const char* framework_version() {
return FN_MODULE_FRAMEWORK_VERSION;
}
const char* framework_description() {
return FN_MODULE_FRAMEWORK_DESCRIPTION;
}
int run_app(AppConfig config, std::function<void()> render_fn) {
// Logger primero para capturar fallos del propio init (GLFW, ventana, GL).
if (config.log.file_path != nullptr) {
@@ -401,6 +455,11 @@ int run_app(AppConfig config, std::function<void()> render_fn) {
// thread; we observe them and skip render+swap so the compositor moves
// the existing buffer (same contract as native title-bar drag).
install_sizemove_subclass(window);
// Adjuntar appicon embebido al HWND principal para que aparezca en la
// barra de tareas, Alt+Tab y title bar (GLFW no propaga el icono de
// recursos del .exe a su WNDCLASS por defecto).
attach_app_icon_to_hwnd(glfwGetWin32Window(window));
#endif
// Carga punteros a funciones GL >= 2.0 si la app lo pide. En Linux es
@@ -565,11 +624,18 @@ int run_app(AppConfig config, std::function<void()> render_fn) {
// their very first frame onwards.
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
prune_dead_subclassed();
prune_dead_icon_attached();
ImGuiPlatformIO& pio_sub = ImGui::GetPlatformIO();
for (int i = 0; i < pio_sub.Viewports.Size; ++i) {
ImGuiViewport* vp = pio_sub.Viewports[i];
if (!vp || !vp->PlatformHandle) continue;
install_sizemove_subclass((GLFWwindow*)vp->PlatformHandle);
GLFWwindow* gw = (GLFWwindow*)vp->PlatformHandle;
install_sizemove_subclass(gw);
// Floating panels = secondary HWNDs creados por el backend
// GLFW. WNDCLASS distinta de la main -> no heredan icono via
// SetClassLongPtrW. WM_SETICON per-HWND es la unica forma de
// que el taskbar/titlebar muestren el icono.
attach_app_icon_to_hwnd(glfwGetWin32Window(gw));
}
}
#endif
+5
View File
@@ -82,6 +82,11 @@ const char* asset_path(const char* name);
// 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.
+32
View File
@@ -0,0 +1,32 @@
// Module manifest visible to fn_framework's About panel.
//
// Each app gets an auto-generated <app>_modules_generated.cpp (codegen via
// python/functions/infra/codegen_app_modules.py, invoked by add_imgui_app at
// CMake configure time) that defines the array + count below from the app's
// `uses_modules:` declaration in its app.md.
//
// Apps without uses_modules still get a stub array of length 0 — links cleanly.
//
// Framework reads via:
//
// for (size_t i = 0; i < fn::app_modules_count; ++i) {
// const auto& m = fn::app_modules_array[i];
// ImGui::Text("%s v%s — %s", m.name, m.version, m.description);
// }
#pragma once
#include <cstddef>
namespace fn {
struct ModuleInfo {
const char* name;
const char* version;
const char* description;
};
extern const ModuleInfo app_modules_array[];
extern const unsigned long app_modules_count;
} // namespace fn