fix(infra): gradle_run detecta android-sdk — issue 0076 #2
@@ -0,0 +1,129 @@
|
||||
#include "icon_font.h"
|
||||
|
||||
#include "app_settings.h"
|
||||
#include "imgui.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#ifndef FN_CPP_ROOT
|
||||
#define FN_CPP_ROOT ""
|
||||
#endif
|
||||
|
||||
namespace fn_ui {
|
||||
|
||||
namespace {
|
||||
|
||||
bool g_text_loaded = false;
|
||||
bool g_tabler_loaded = false;
|
||||
|
||||
bool file_exists(const char* path) {
|
||||
if (!path || !*path) return false;
|
||||
if (FILE* f = std::fopen(path, "rb")) { std::fclose(f); return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
// Busca un asset (TTF) en las rutas estandar del registry. Devuelve la primera
|
||||
// ruta valida o vacio.
|
||||
//
|
||||
// Orden: ./<filename> → ./assets/<filename> → $FN_ASSETS_DIR/<filename>
|
||||
// → ${FN_CPP_ROOT}/<repo_subpath>
|
||||
std::string find_asset(const char* filename, const char* repo_subpath) {
|
||||
std::string p;
|
||||
p = std::string("./") + filename; if (file_exists(p.c_str())) return p;
|
||||
p = std::string("./assets/") + filename; if (file_exists(p.c_str())) return p;
|
||||
if (const char* env = std::getenv("FN_ASSETS_DIR")) {
|
||||
p = std::string(env) + "/" + filename;
|
||||
if (file_exists(p.c_str())) return p;
|
||||
}
|
||||
if (std::strlen(FN_CPP_ROOT) > 0 && repo_subpath) {
|
||||
p = std::string(FN_CPP_ROOT) + "/" + repo_subpath;
|
||||
if (file_exists(p.c_str())) return p;
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const char* repo_subpath_for(FontId id) {
|
||||
switch (id) {
|
||||
case FontId::Karla: return "vendor/imgui/misc/fonts/Karla-Regular.ttf";
|
||||
case FontId::Roboto: return "vendor/imgui/misc/fonts/Roboto-Medium.ttf";
|
||||
case FontId::DroidSans: return "vendor/imgui/misc/fonts/DroidSans.ttf";
|
||||
case FontId::Cousine: return "vendor/imgui/misc/fonts/Cousine-Regular.ttf";
|
||||
case FontId::ProggyClean: return ""; // bitmap default
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void load_fonts_from_settings() {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.Fonts->Clear();
|
||||
|
||||
const AppSettings& s = settings();
|
||||
const float size_px = s.font_size_px;
|
||||
|
||||
// 1. Texto.
|
||||
g_text_loaded = false;
|
||||
if (s.font_id == FontId::ProggyClean) {
|
||||
// Bitmap default: ignora size_px (ProggyClean es 13 px nativo).
|
||||
io.Fonts->AddFontDefault();
|
||||
} else {
|
||||
const char* fname = font_filename(s.font_id);
|
||||
std::string ttf = find_asset(fname, repo_subpath_for(s.font_id));
|
||||
if (!ttf.empty()) {
|
||||
ImFontConfig cfg;
|
||||
cfg.OversampleH = 2;
|
||||
cfg.OversampleV = 1;
|
||||
cfg.PixelSnapH = false;
|
||||
if (io.Fonts->AddFontFromFileTTF(ttf.c_str(), size_px, &cfg)) {
|
||||
g_text_loaded = true;
|
||||
} else {
|
||||
std::fprintf(stderr, "[fn_ui] AddFontFromFileTTF fallo (%s)\n", ttf.c_str());
|
||||
io.Fonts->AddFontDefault();
|
||||
}
|
||||
} else {
|
||||
std::fprintf(stderr,
|
||||
"[fn_ui] %s no encontrado — fallback a ProggyClean. "
|
||||
"Buscado en: ./%s, ./assets/, $FN_ASSETS_DIR, %s/vendor/imgui/misc/fonts/\n",
|
||||
fname, fname, FN_CPP_ROOT[0] ? FN_CPP_ROOT : "(FN_CPP_ROOT no definido)");
|
||||
io.Fonts->AddFontDefault();
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Iconos Tabler — mergea sobre la fuente activa.
|
||||
std::string ico = find_asset("tabler-icons.ttf", "vendor/tabler-icons/tabler-icons.ttf");
|
||||
if (ico.empty()) {
|
||||
std::fprintf(stderr,
|
||||
"[fn_ui] tabler-icons.ttf no encontrado — los TI_* saldran como cuadritos. "
|
||||
"Buscado en: ./tabler-icons.ttf, ./assets/, $FN_ASSETS_DIR, %s/vendor/tabler-icons/\n",
|
||||
FN_CPP_ROOT[0] ? FN_CPP_ROOT : "(FN_CPP_ROOT no definido)");
|
||||
g_tabler_loaded = false;
|
||||
return;
|
||||
}
|
||||
|
||||
static const ImWchar tabler_ranges[] = {0xE000, 0xFCFF, 0};
|
||||
// Tabler matchea el tamaño de texto, salvo en ProggyClean (13 px) donde lo
|
||||
// forzamos a 13 tambien para no romper line-height.
|
||||
const float tabler_px = (s.font_id == FontId::ProggyClean) ? 13.0f : size_px;
|
||||
|
||||
ImFontConfig icfg;
|
||||
icfg.MergeMode = true;
|
||||
icfg.PixelSnapH = true;
|
||||
icfg.OversampleH = icfg.OversampleV = 1;
|
||||
icfg.GlyphMinAdvanceX = tabler_px;
|
||||
icfg.GlyphOffset.y = 1.0f;
|
||||
if (io.Fonts->AddFontFromFileTTF(ico.c_str(), tabler_px, &icfg, tabler_ranges)) {
|
||||
g_tabler_loaded = true;
|
||||
} else {
|
||||
std::fprintf(stderr, "[fn_ui] AddFontFromFileTTF tabler fallo (%s)\n", ico.c_str());
|
||||
g_tabler_loaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool text_font_loaded() { return g_text_loaded; }
|
||||
bool tabler_font_loaded() { return g_tabler_loaded; }
|
||||
|
||||
} // namespace fn_ui
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
// Carga de fuentes para apps ImGui del registry: TTF de texto vectorial
|
||||
// (Karla / Roboto / DroidSans / Cousine, segun core/app_settings.h) +
|
||||
// fuente de iconos Tabler mergeada en el mismo ImFont.
|
||||
//
|
||||
// Llamar desde fn::run_app despues de ImGui::CreateContext y de
|
||||
// settings_load(). Tras esta llamada, los TI_* (core/icons_tabler.h) se
|
||||
// renderizan inline con el texto al tamaño activo.
|
||||
|
||||
namespace fn_ui {
|
||||
|
||||
// Carga la fuente de texto + Tabler usando los valores actuales de
|
||||
// fn_ui::settings() (font_id + font_size_px). Llamada por run_app al inicio
|
||||
// y de nuevo cuando hay font dirty (rebuild de atlas).
|
||||
void load_fonts_from_settings();
|
||||
|
||||
// True si la ultima carga incluyo una TTF de texto (no fallback ProggyClean).
|
||||
bool text_font_loaded();
|
||||
|
||||
// True si la ultima carga incluyo Tabler.
|
||||
bool tabler_font_loaded();
|
||||
|
||||
} // namespace fn_ui
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
name: icon_font
|
||||
kind: function
|
||||
lang: cpp
|
||||
domain: core
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "void fn_ui::load_default_fonts(float size_px = 13.0f)"
|
||||
description: "Carga Karla-Regular (texto vectorial) + mergea Tabler Icons al mismo tamaño en el atlas de ImGui. Tras esta llamada los TI_* (icons_tabler.h) renderizan inline con el texto."
|
||||
tags: [imgui, fonts, icons, tabler, atlas, init]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: [imgui, cstdio, cstdlib, cstring, string]
|
||||
tested: false
|
||||
tests: []
|
||||
test_file_path: ""
|
||||
file_path: "cpp/functions/core/icon_font.cpp"
|
||||
framework: imgui
|
||||
params:
|
||||
- name: size_px
|
||||
desc: "Tamaño en px compartido por texto e iconos. Default 13 = ImGui default historico, render vectorial nitido en Karla y Tabler. El icon merge cuadra el line-height con el texto al usar el mismo tamaño"
|
||||
output: "void — texto + iconos quedan activos en io.Fonts. Si Karla no se encuentra, fallback a ProggyClean default; si Tabler no se encuentra, los TI_* salen como cuadritos. Estado consultable via text_font_loaded() y tabler_font_loaded()"
|
||||
---
|
||||
|
||||
# icon_font
|
||||
|
||||
Carga la fuente de texto + iconos Tabler en el atlas de ImGui de forma que `TI_*` (de `core/icons_tabler.h`) y texto se mezclen en el mismo glyph stream:
|
||||
|
||||
```cpp
|
||||
icon_button("##rl", TI_REFRESH, "Reload");
|
||||
button(TI_DEVICE_FLOPPY " Save", V::Primary); // icono + texto en la misma label
|
||||
```
|
||||
|
||||
## Cuando llamarla
|
||||
|
||||
Una sola vez por contexto ImGui, despues de `ImGui::CreateContext()` y antes del primer `ImGui::NewFrame()`. La llamada ya esta hecha automaticamente por `fn::run_app` (`framework/app_base.cpp`). En apps que NO usan `fn::run_app`, llamar manualmente:
|
||||
|
||||
```cpp
|
||||
ImGui::CreateContext();
|
||||
fn_ui::load_default_fonts();
|
||||
// ... resto del setup
|
||||
```
|
||||
|
||||
## Fuentes cargadas
|
||||
|
||||
| Rol | TTF | Origen | Render |
|
||||
|---|---|---|---|
|
||||
| Texto | `Karla-Regular.ttf` (17 KB) | `cpp/vendor/imgui/misc/fonts/` (vendoreado por ImGui) | vectorial, humanist sans-serif, OversampleH=2 |
|
||||
| Iconos | `tabler-icons.ttf` (2.7 MB) | `cpp/vendor/tabler-icons/` (Tabler v3.41.1, MIT) | vectorial, mergeado en el mismo `ImFont` con `MergeMode = true`, range U+E000..U+FCFF |
|
||||
|
||||
Los dos al mismo `size_px` para que el line-height sea uniforme. ImGui no aplica hinting nativo, pero Karla a 13 px con `OversampleH=2` queda nitida.
|
||||
|
||||
## Resolucion del path de las TTF
|
||||
|
||||
Para cada TTF, busca en este orden (primer match gana):
|
||||
|
||||
1. `./<filename>` (cwd / junto al exe en deploys)
|
||||
2. `./assets/<filename>`
|
||||
3. `$FN_ASSETS_DIR/<filename>` (override manual)
|
||||
4. `${FN_CPP_ROOT}/<repo_subpath>` — compile-time define inyectado por CMake:
|
||||
- Karla → `vendor/imgui/misc/fonts/Karla-Regular.ttf`
|
||||
- Tabler → `vendor/tabler-icons/tabler-icons.ttf`
|
||||
|
||||
Si Karla no se encuentra, fallback automatico a `io.Fonts->AddFontDefault()` (ProggyClean bitmap) — la app arranca igual, solo cambia la tipografia. Si Tabler no se encuentra, los `TI_*` salen como cuadritos vacios pero el texto sigue funcionando.
|
||||
|
||||
## CMake
|
||||
|
||||
Un app que use `add_imgui_app` ya hereda el define `FN_CPP_ROOT` y la copia post-build de la TTF. Si compilas a mano:
|
||||
|
||||
```cmake
|
||||
target_compile_definitions(my_app PRIVATE FN_CPP_ROOT="${CMAKE_SOURCE_DIR}")
|
||||
```
|
||||
|
||||
## Range cubierto
|
||||
|
||||
`U+E000..U+FCFF` — Private Use Area, donde Tabler v3.41 ubica todos sus glyphs (rango real efectivo aprox U+EA5E..U+FC93, pero cubrimos toda la PUA por margen).
|
||||
|
||||
## Tamaño del atlas
|
||||
|
||||
Cargar 5093 iconos a 13 px crea un atlas de aprox 2048x2048 px en memoria de GPU. Si necesitas un atlas mas pequeño, edita el array `tabler_ranges[]` en `.cpp` para cubrir solo los iconos que uses (ej: `{0xEA5E, 0xEC00, 0}`).
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```cpp
|
||||
#include "core/icons_tabler.h"
|
||||
#include "core/button.h"
|
||||
#include "core/icon_button.h"
|
||||
|
||||
if (button(TI_PLUS " New", V::Primary)) create();
|
||||
if (button(TI_DEVICE_FLOPPY " Save", V::Secondary)) save();
|
||||
if (icon_button("##del", TI_TRASH, "Delete")) confirm();
|
||||
if (icon_button("##cfg", TI_SETTINGS, "Settings")) open_settings();
|
||||
```
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user