diff --git a/cpp/apps/primitives_gallery/CMakeLists.txt b/cpp/apps/primitives_gallery/CMakeLists.txt index d4691387..6812bf9f 100644 --- a/cpp/apps/primitives_gallery/CMakeLists.txt +++ b/cpp/apps/primitives_gallery/CMakeLists.txt @@ -7,6 +7,7 @@ add_imgui_app(primitives_gallery demos_gfx.cpp demos_text_editor.cpp demos_gl_texture.cpp + demos_extras.cpp # text_editor + file_watcher (issue 0025) ${CMAKE_SOURCE_DIR}/functions/core/text_editor.cpp ${CMAKE_SOURCE_DIR}/functions/core/file_watcher.cpp @@ -34,6 +35,10 @@ add_imgui_app(primitives_gallery ${CMAKE_SOURCE_DIR}/functions/viz/scatter_plot.cpp ${CMAKE_SOURCE_DIR}/functions/viz/histogram.cpp ${CMAKE_SOURCE_DIR}/functions/viz/sparkline.cpp + ${CMAKE_SOURCE_DIR}/functions/viz/candlestick.cpp + ${CMAKE_SOURCE_DIR}/functions/viz/gauge.cpp + ${CMAKE_SOURCE_DIR}/functions/viz/heatmap.cpp + ${CMAKE_SOURCE_DIR}/functions/viz/table_view.cpp # Graph stack (instanced GPU + Barnes-Hut + spatial hash) ${CMAKE_SOURCE_DIR}/functions/viz/graph_types.cpp ${CMAKE_SOURCE_DIR}/functions/viz/graph_renderer.cpp diff --git a/cpp/apps/primitives_gallery/demos.h b/cpp/apps/primitives_gallery/demos.h index ada59e70..b7f22c32 100644 --- a/cpp/apps/primitives_gallery/demos.h +++ b/cpp/apps/primitives_gallery/demos.h @@ -18,6 +18,9 @@ void demo_badge(); void demo_empty_state(); void demo_page_header(); void demo_dashboard_panel(); +void demo_text_editor(); // wave 1, issue 0025 +void demo_file_watcher(); // wave 1, issue 0025 +void demo_process_runner(); // --- Viz --- void demo_bar_chart(); @@ -27,12 +30,13 @@ void demo_scatter_plot(); void demo_histogram(); void demo_sparkline(); void demo_graph(); +void demo_candlestick(); +void demo_gauge(); +void demo_heatmap(); +void demo_table_view(); // --- Gfx --- void demo_shader_canvas(); -void demo_gl_texture(); - -// --- Core (combined demo: text_editor + file_watcher) --- -void demo_text_editor(); +void demo_gl_texture(); // wave 1, issue 0026 } // namespace gallery diff --git a/cpp/apps/primitives_gallery/demos_extras.cpp b/cpp/apps/primitives_gallery/demos_extras.cpp new file mode 100644 index 00000000..dec8ace3 --- /dev/null +++ b/cpp/apps/primitives_gallery/demos_extras.cpp @@ -0,0 +1,215 @@ +// Demos faltantes: process_runner (Core), candlestick / gauge / heatmap / +// table_view (Viz). Aniade cobertura sobre los primitivos del registry que +// no tenian su entry en la gallery. + +#include "demos.h" +#include "demo.h" + +#include "core/process_runner.h" +#include "viz/candlestick.h" +#include "viz/gauge.h" +#include "viz/heatmap.h" +#include "viz/table_view.h" + +#include +#include +#include +#include +#include +#include + +namespace gallery { + +// --------------------------------------------------------------------------- +// process_runner (Core) +// --------------------------------------------------------------------------- + +void demo_process_runner() { + demo_header("process_runner", "v1.0.0", + "Ejecuta una tarea en std::thread en background y expone estado thread-safe " + "(idle/running/success/error). El widget runner_status() dibuja inline un " + "spinner mientras corre y un mensaje de Success/Error al terminar."); + + static fn_ui::ProcessRunner runner; + + section("Tarea simulada (sleep 2s)"); + { + if (ImGui::Button("Run task")) { + if (!runner.is_busy()) { + fn_ui::runner_trigger(runner, [](std::string& out) -> bool { + std::this_thread::sleep_for(std::chrono::seconds(2)); + out = "task done in 2s"; + return true; + }); + } + } + ImGui::SameLine(); + if (ImGui::Button("Run failing task")) { + if (!runner.is_busy()) { + fn_ui::runner_trigger(runner, [](std::string& out) -> bool { + std::this_thread::sleep_for(std::chrono::seconds(1)); + out = "simulated failure"; + return false; + }); + } + } + ImGui::SameLine(); + if (ImGui::Button("Reset")) runner.reset(); + fn_ui::runner_status(runner, "Working..."); + } + + code_block( + "static fn_ui::ProcessRunner r;\n" + "if (button(\"Run\", Primary) && !r.is_busy()) {\n" + " fn_ui::runner_trigger(r, [](std::string& out) -> bool {\n" + " return do_work(&out);\n" + " });\n" + "}\n" + "fn_ui::runner_status(r, \"Working...\");" + ); +} + +// --------------------------------------------------------------------------- +// candlestick (Viz) +// --------------------------------------------------------------------------- + +void demo_candlestick() { + demo_header("candlestick", "v1.0.0", + "Grafico de velas OHLC con ImPlot custom rendering. Verde si close >= open, " + "rojo si bajista. Tooltip al hover muestra OHLC del dia."); + + section("OHLC sintetico (30 dias)"); + { + static std::vector dates, opens, closes, lows, highs; + if (dates.empty()) { + dates.reserve(30); opens.reserve(30); closes.reserve(30); + lows.reserve(30); highs.reserve(30); + double price = 100.0; + for (int i = 0; i < 30; ++i) { + double drift = std::sin(i * 0.4) * 1.2; + double o = price; + double c = price + drift + (i % 3 == 0 ? -0.6 : 0.4); + double l = std::min(o, c) - 0.8 - (i % 5) * 0.1; + double h = std::max(o, c) + 0.8 + (i % 4) * 0.1; + dates.push_back(double(i)); + opens.push_back(o); + closes.push_back(c); + lows.push_back(l); + highs.push_back(h); + price = c; + } + } + candlestick("##cs", dates.data(), opens.data(), closes.data(), + lows.data(), highs.data(), int(dates.size())); + } + + code_block( + "candlestick(\"##cs\", dates, opens, closes, lows, highs, n,\n" + " /*width_percent=*/0.25f, /*tooltip=*/true);" + ); +} + +// --------------------------------------------------------------------------- +// gauge (Viz) +// --------------------------------------------------------------------------- + +void demo_gauge() { + demo_header("gauge", "v1.0.0", + "Indicador circular tipo velocimetro con ImGui DrawList. Color interpolado " + "verde -> amarillo -> rojo segun el valor normalizado."); + + static float v_cpu = 0.32f, v_mem = 0.78f, v_gpu = 0.55f; + + section("Tres gauges con sliders"); + { + ImGui::SliderFloat("cpu", &v_cpu, 0.0f, 1.0f); + ImGui::SliderFloat("mem", &v_mem, 0.0f, 1.0f); + ImGui::SliderFloat("gpu", &v_gpu, 0.0f, 1.0f); + + ImGui::Spacing(); + ImGui::BeginGroup(); + gauge("CPU", v_cpu, 0.0f, 1.0f, 60.0f); + ImGui::EndGroup(); + ImGui::SameLine(0.0f, 24.0f); + ImGui::BeginGroup(); + gauge("MEM", v_mem, 0.0f, 1.0f, 60.0f); + ImGui::EndGroup(); + ImGui::SameLine(0.0f, 24.0f); + ImGui::BeginGroup(); + gauge("GPU", v_gpu, 0.0f, 1.0f, 60.0f); + ImGui::EndGroup(); + } + + code_block("gauge(\"CPU\", 0.32f, 0.0f, 1.0f, 60.0f);"); +} + +// --------------------------------------------------------------------------- +// heatmap (Viz) +// --------------------------------------------------------------------------- + +void demo_heatmap() { + demo_header("heatmap", "v1.0.0", + "Mapa de calor 2D con ImPlot. Datos row-major. Util para correlation " + "matrices, attention maps, distribuciones 2D discretas."); + + constexpr int R = 12; + constexpr int C = 12; + static float values[R * C] = {0}; + static bool init = false; + if (!init) { + for (int r = 0; r < R; ++r) { + for (int c = 0; c < C; ++c) { + float dx = (c - C * 0.5f) / float(C); + float dy = (r - R * 0.5f) / float(R); + values[r * C + c] = std::exp(-(dx * dx + dy * dy) * 6.0f); + } + } + init = true; + } + + section("Gaussian 12x12"); + { + heatmap("##hm", values, R, C, 0.0f, 1.0f); + } + + code_block( + "float values[R * C];\n" + "// fill row-major: values[r * C + c] = ...\n" + "heatmap(\"##hm\", values, R, C, /*min=*/0.0f, /*max=*/1.0f);" + ); +} + +// --------------------------------------------------------------------------- +// table_view (Viz) +// --------------------------------------------------------------------------- + +void demo_table_view() { + demo_header("table_view", "v1.0.0", + "Tabla interactiva con sorting indicators y scroll usando la ImGui Tables API. " + "Headers + cells row-major. Util para dashboards y inspectores."); + + section("Lenguajes del registry"); + { + const char* headers[] = {"id", "lang", "domain", "purity"}; + // 6 filas x 4 cols, row-major + const char* cells[] = { + "filter_slice_go_core", "go", "core", "pure", + "metabase_setup_py_infra", "py", "infra", "impure", + "rsync_deploy_bash_infra", "sh", "infra", "impure", + "button_cpp_core", "cpp", "core", "pure", + "gl_texture_load_cpp_gfx", "cpp", "gfx", "impure", + "audio_fft_cpp_core", "cpp", "core", "pure", + }; + const int row_count = 6; + const int col_count = 4; + table_view("##tbl", headers, col_count, cells, row_count); + } + + code_block( + "const char* headers[] = {\"id\", \"lang\", \"domain\"};\n" + "const char* cells[] = {/* row-major: r0c0,r0c1,r0c2, r1c0,... */};\n" + "table_view(\"##tbl\", headers, 3, cells, n_rows);" + ); +} + +} // namespace gallery diff --git a/cpp/apps/primitives_gallery/demos_text_editor.cpp b/cpp/apps/primitives_gallery/demos_text_editor.cpp index 36c4c895..c6a32f4f 100644 --- a/cpp/apps/primitives_gallery/demos_text_editor.cpp +++ b/cpp/apps/primitives_gallery/demos_text_editor.cpp @@ -1,10 +1,8 @@ -// Demo combinada: text_editor + file_watcher. +// Demos individuales de text_editor y file_watcher (Wave 1, issue 0025). // -// Layout (split horizontal): -// - Izquierda: text_editor con CodeLang::GLSL precargado con un fragment -// shader simple. Boton "Save to /tmp/fn_demo.glsl". -// - Derecha: panel de info — dirty flag, ultimo error, lista scrollable de -// eventos del watcher activo sobre /tmp/fn_demo.glsl. +// Aunque las dos primitivas estan diseñadas para componerse, en gallery se +// muestran por separado para que cada entry exhiba un solo primitivo y su +// API minima. #include "demos.h" #include "demo.h" @@ -25,13 +23,15 @@ namespace gallery { +// =========================================================================== +// text_editor — editor de codigo con syntax highlighting +// =========================================================================== + namespace { -constexpr const char* kDemoPath = "/tmp/fn_demo.glsl"; - -const char* kInitialGLSL = +const char* kSampleGLSL = "#version 330\n" - "// Demo fragment shader (text_editor + file_watcher).\n" + "// fragment shader demo\n" "out vec4 frag_color;\n" "uniform vec2 u_resolution;\n" "uniform float u_time;\n" @@ -42,40 +42,144 @@ const char* kInitialGLSL = " frag_color = vec4(col, 1.0);\n" "}\n"; -struct EventLogEntry { - double t_seconds; // tiempo relativo al primer evento mostrado - std::string label; +const char* kSampleSQL = + "-- fts5 search sobre el registry\n" + "SELECT id, kind, purity, description\n" + "FROM functions\n" + "WHERE id IN (\n" + " SELECT id FROM functions_fts\n" + " WHERE functions_fts MATCH 'name:slic* OR description:slic*'\n" + ")\n" + "ORDER BY name\n" + "LIMIT 50;\n"; + +const char* kSampleCpp = + "#include \n" + "namespace fn {\n" + " bool button(const char* label, ButtonVariant v) {\n" + " auto& tk = tokens::current();\n" + " ImGui::PushStyleColor(ImGuiCol_Button, tk.bg_for(v));\n" + " bool clicked = ImGui::Button(label);\n" + " ImGui::PopStyleColor();\n" + " return clicked;\n" + " }\n" + "}\n"; + +struct EditorState { + fn::TextEditorState* ed = nullptr; + fn::CodeLang lang = fn::CodeLang::GLSL; }; -struct DemoState { - fn::TextEditorState* editor = nullptr; - fn::FileWatcher* watcher = nullptr; - std::deque events; - std::string save_status; - std::string watch_error; - bool watcher_active = false; -}; - -DemoState& state() { - static DemoState s; +EditorState& editor_state() { + static EditorState s; return s; } -void ensure_init() { - auto& s = state(); - if (!s.editor) { - s.editor = fn::text_editor_create(fn::CodeLang::GLSL); - fn::text_editor_set_text(s.editor, kInitialGLSL); +void ensure_editor() { + auto& s = editor_state(); + if (!s.ed) { + s.ed = fn::text_editor_create(s.lang); + fn::text_editor_set_text(s.ed, kSampleGLSL); } - if (!s.watcher) { - s.watcher = fn::file_watcher_create(); - // Si /tmp/fn_demo.glsl no existe aun, file_watcher_add fallara — - // se reintenta tras el primer Save. - s.watcher_active = fn::file_watcher_add(s.watcher, kDemoPath); - if (!s.watcher_active) { - s.watch_error = fn::file_watcher_last_error(s.watcher); +} + +void apply_language(fn::CodeLang next) { + auto& s = editor_state(); + if (next == s.lang) return; + fn::text_editor_destroy(s.ed); + s.ed = fn::text_editor_create(next); + s.lang = next; + switch (next) { + case fn::CodeLang::GLSL: fn::text_editor_set_text(s.ed, kSampleGLSL); break; + case fn::CodeLang::SQL: fn::text_editor_set_text(s.ed, kSampleSQL); break; + case fn::CodeLang::Cpp: fn::text_editor_set_text(s.ed, kSampleCpp); break; + case fn::CodeLang::Generic: fn::text_editor_set_text(s.ed, ""); break; + } +} + +} // namespace + +void demo_text_editor() { + using namespace fn_tokens; + + demo_header("text_editor", "v1.0.0", + "Editor de codigo embebido en ImGui con syntax highlighting (GLSL/SQL/Cpp/Generic). " + "Wrapper PIMPL sobre ImGuiColorTextEdit (MIT). API: create / set_text / get_text / " + "render / is_dirty."); + + ensure_editor(); + auto& s = editor_state(); + + section("language"); + { + const char* labels[] = {"GLSL", "SQL", "Cpp", "Generic"}; + const fn::CodeLang langs[] = { + fn::CodeLang::GLSL, fn::CodeLang::SQL, fn::CodeLang::Cpp, fn::CodeLang::Generic + }; + for (int i = 0; i < 4; ++i) { + if (i > 0) ImGui::SameLine(); + bool active = (s.lang == langs[i]); + if (active) ImGui::PushStyleColor(ImGuiCol_Button, colors::primary); + if (ImGui::Button(labels[i])) apply_language(langs[i]); + if (active) ImGui::PopStyleColor(); } } + + section("editor"); + { + ImVec2 avail = ImGui::GetContentRegionAvail(); + float h = avail.y - 60.0f; + if (h < 220.0f) h = 220.0f; + fn::text_editor_render(s.ed, "##fn_text_editor_solo", ImVec2(-1, h)); + + if (fn::text_editor_is_dirty(s.ed)) { + ImGui::PushStyleColor(ImGuiCol_Text, colors::warning); + ImGui::TextUnformatted("(modified)"); + ImGui::PopStyleColor(); + ImGui::SameLine(); + if (ImGui::Button("clear dirty##te_solo")) fn::text_editor_clear_dirty(s.ed); + } else { + ImGui::PushStyleColor(ImGuiCol_Text, colors::text_dim); + ImGui::TextUnformatted("(clean)"); + ImGui::PopStyleColor(); + } + } + + code_block( + "auto* ed = fn::text_editor_create(fn::CodeLang::GLSL);\n" + "fn::text_editor_set_text(ed, src);\n" + "if (fn::text_editor_render(ed, \"##ed\", {600, 400}))\n" + " on_changed(fn::text_editor_get_text(ed));" + ); +} + +// =========================================================================== +// file_watcher — watcher cross-platform no bloqueante +// =========================================================================== + +namespace { + +constexpr const char* kWatchPath = "/tmp/fn_demo.glsl"; + +struct WatcherDemoState { + fn::FileWatcher* fw = nullptr; + bool active = false; + std::string err; + std::deque events; +}; + +WatcherDemoState& watcher_state() { + static WatcherDemoState s; + return s; +} + +void ensure_watcher() { + auto& s = watcher_state(); + if (!s.fw) { + s.fw = fn::file_watcher_create(); + s.active = fn::file_watcher_add(s.fw, kWatchPath); + if (!s.active) s.err = fn::file_watcher_last_error(s.fw); + } } const char* kind_label(fn::FileEvent::Kind k) { @@ -88,132 +192,88 @@ const char* kind_label(fn::FileEvent::Kind k) { } void poll_and_log() { - auto& s = state(); - if (!s.watcher) return; - auto evs = fn::file_watcher_poll(s.watcher); - if (evs.empty()) return; - double now = (double)std::time(nullptr); + auto& s = watcher_state(); + if (!s.fw) return; + auto evs = fn::file_watcher_poll(s.fw); for (auto& e : evs) { char buf[512]; std::snprintf(buf, sizeof(buf), "[%s] %s", kind_label(e.kind), e.path.c_str()); - s.events.push_back({now, buf}); + s.events.push_back(buf); } while (s.events.size() > 200) s.events.pop_front(); } -bool save_to_disk() { - auto& s = state(); - FILE* f = std::fopen(kDemoPath, "w"); - if (!f) { - s.save_status = std::string("save failed: ") + std::strerror(errno); - return false; - } - const char* txt = fn::text_editor_get_text(s.editor); - std::fputs(txt, f); +bool touch_demo_file(std::string& err_out) { + FILE* f = std::fopen(kWatchPath, "a"); + if (!f) { err_out = std::strerror(errno); return false; } + std::fprintf(f, "// touch %ld\n", (long)std::time(nullptr)); std::fclose(f); - fn::text_editor_clear_dirty(s.editor); - s.save_status = std::string("saved -> ") + kDemoPath; - - // Si el watcher no estaba activo (archivo no existia al iniciar), reintentar. - if (!s.watcher_active) { - s.watcher_active = fn::file_watcher_add(s.watcher, kDemoPath); - if (!s.watcher_active) s.watch_error = fn::file_watcher_last_error(s.watcher); - else s.watch_error.clear(); - } return true; } } // namespace -void demo_text_editor() { +void demo_file_watcher() { using namespace fn_tokens; - demo_header("text_editor + file_watcher", "v1.0.0", - "Editor de codigo GLSL con syntax highlighting (PIMPL sobre ImGuiColorTextEdit) " - "+ watcher de archivos no bloqueante (inotify Linux / ReadDirectoryChangesW Win). " - "Edita, pulsa Save y observa el evento llegar al panel derecho."); + demo_header("file_watcher", "v1.0.0", + "Watcher de archivos cross-platform no bloqueante. Linux: inotify. Windows: " + "ReadDirectoryChangesW. API: create / add / poll (drain) / destroy. Cap del " + "buffer de eventos: 200."); - ensure_init(); + ensure_watcher(); poll_and_log(); - auto& s = state(); + auto& s = watcher_state(); - // Layout: two-column table. Editor a la izquierda, info a la derecha. - if (ImGui::BeginTable("##te_layout", 2, - ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingStretchProp)) { - ImGui::TableSetupColumn("editor", ImGuiTableColumnFlags_WidthStretch, 0.62f); - ImGui::TableSetupColumn("info", ImGuiTableColumnFlags_WidthStretch, 0.38f); - ImGui::TableNextRow(); + section("watcher state"); + ImGui::Text("path: %s", kWatchPath); + ImGui::Text("active: %s", s.active ? "yes" : "no"); + if (!s.err.empty()) { + ImGui::PushStyleColor(ImGuiCol_Text, colors::error); + ImGui::TextWrapped("err: %s", s.err.c_str()); + ImGui::PopStyleColor(); + } - // ---------- Columna izquierda: editor ---------- - ImGui::TableSetColumnIndex(0); - - section("editor (CodeLang::GLSL)"); - - ImVec2 avail = ImGui::GetContentRegionAvail(); - float editor_h = avail.y - 60.0f; - if (editor_h < 200.0f) editor_h = 200.0f; - fn::text_editor_render(s.editor, "##fn_text_editor", ImVec2(-1, editor_h)); - - ImGui::Spacing(); - if (fn_ui::button("Save to /tmp/fn_demo.glsl", fn_ui::ButtonVariant::Primary)) { - save_to_disk(); - } - ImGui::SameLine(); - if (fn::text_editor_is_dirty(s.editor)) { - ImGui::PushStyleColor(ImGuiCol_Text, colors::warning); - ImGui::TextUnformatted("(modified)"); - ImGui::PopStyleColor(); - } else { - ImGui::PushStyleColor(ImGuiCol_Text, colors::text_dim); - ImGui::TextUnformatted("(clean)"); - ImGui::PopStyleColor(); - } - - if (!s.save_status.empty()) { - ImGui::PushStyleColor(ImGuiCol_Text, colors::text_dim); - ImGui::TextUnformatted(s.save_status.c_str()); - ImGui::PopStyleColor(); - } - - // ---------- Columna derecha: info + eventos ---------- - ImGui::TableSetColumnIndex(1); - - section("watcher state"); - - ImGui::Text("path: %s", kDemoPath); - ImGui::Text("active: %s", s.watcher_active ? "yes" : "no"); - - if (!s.watch_error.empty()) { - ImGui::PushStyleColor(ImGuiCol_Text, colors::error); - ImGui::TextWrapped("err: %s", s.watch_error.c_str()); - ImGui::PopStyleColor(); - } - - ImGui::Spacing(); - section("events"); - - ImGui::Text("captured: %d", (int)s.events.size()); - ImGui::SameLine(); - if (fn_ui::button("clear##evlog", fn_ui::ButtonVariant::Subtle, fn_ui::ButtonSize::Sm)) { - s.events.clear(); - } - - ImGui::BeginChild("##evlog", ImVec2(0, 0), ImGuiChildFlags_Borders); - if (s.events.empty()) { - ImGui::PushStyleColor(ImGuiCol_Text, colors::text_dim); - ImGui::TextWrapped("Sin eventos. Modifica el editor + Save, " - "o desde otro terminal: echo hi >> %s", kDemoPath); - ImGui::PopStyleColor(); - } else { - for (auto it = s.events.rbegin(); it != s.events.rend(); ++it) { - ImGui::TextUnformatted(it->label.c_str()); + section("trigger events"); + { + if (ImGui::Button("touch (append timestamp)")) { + std::string e; + if (!touch_demo_file(e)) s.err = "touch failed: " + e; + else s.err.clear(); + // Si el archivo no existia al inicio, reintenta el add. + if (!s.active) { + s.active = fn::file_watcher_add(s.fw, kWatchPath); + if (!s.active) s.err = fn::file_watcher_last_error(s.fw); } } - ImGui::EndChild(); - - ImGui::EndTable(); + ImGui::SameLine(); + if (ImGui::Button("clear events")) s.events.clear(); + ImGui::SameLine(); + ImGui::TextDisabled("(o desde otro terminal: echo hi >> %s)", kWatchPath); } + + section("event log"); + ImGui::Text("captured: %d", (int)s.events.size()); + ImGui::BeginChild("##fw_evlog", ImVec2(0, 0), ImGuiChildFlags_Borders); + if (s.events.empty()) { + ImGui::PushStyleColor(ImGuiCol_Text, colors::text_dim); + ImGui::TextWrapped("Sin eventos. Pulsa touch o modifica el path desde otro terminal."); + ImGui::PopStyleColor(); + } else { + for (auto it = s.events.rbegin(); it != s.events.rend(); ++it) { + ImGui::TextUnformatted(it->c_str()); + } + } + ImGui::EndChild(); + + code_block( + "auto* fw = fn::file_watcher_create();\n" + "fn::file_watcher_add(fw, \"/tmp/foo.glsl\");\n" + "for (auto& e : fn::file_watcher_poll(fw)) {\n" + " handle_event(e.path, e.kind);\n" + "}" + ); } } // namespace gallery diff --git a/cpp/apps/primitives_gallery/main.cpp b/cpp/apps/primitives_gallery/main.cpp index fa9d41f2..269bfe6b 100644 --- a/cpp/apps/primitives_gallery/main.cpp +++ b/cpp/apps/primitives_gallery/main.cpp @@ -46,7 +46,9 @@ static const DemoEntry k_demos[] = { {"page_header", "page_header", "Core", &gallery::demo_page_header}, {"dashboard_panel", "dashboard_panel", "Core", &gallery::demo_dashboard_panel}, {"kpi_card", "kpi_card", "Core", &gallery::demo_kpi_card}, - {"text_editor", "text_editor + watcher", "Core", &gallery::demo_text_editor}, + {"text_editor", "text_editor", "Core", &gallery::demo_text_editor}, // wave 1 + {"file_watcher", "file_watcher", "Core", &gallery::demo_file_watcher}, // wave 1 + {"process_runner", "process_runner", "Core", &gallery::demo_process_runner}, // Viz {"bar_chart", "bar_chart", "Viz", &gallery::demo_bar_chart}, {"pie_chart", "pie_chart", "Viz", &gallery::demo_pie_chart}, @@ -55,9 +57,13 @@ static const DemoEntry k_demos[] = { {"histogram", "histogram", "Viz", &gallery::demo_histogram}, {"sparkline", "sparkline", "Viz", &gallery::demo_sparkline}, {"graph_viewport", "graph_viewport", "Viz", &gallery::demo_graph}, + {"candlestick", "candlestick", "Viz", &gallery::demo_candlestick}, + {"gauge", "gauge", "Viz", &gallery::demo_gauge}, + {"heatmap", "heatmap", "Viz", &gallery::demo_heatmap}, + {"table_view", "table_view", "Viz", &gallery::demo_table_view}, // Gfx (shaders_lab core) {"shader_canvas", "shader_canvas", "Gfx", &gallery::demo_shader_canvas}, - {"gl_texture", "gl_texture_load", "Gfx", &gallery::demo_gl_texture}, + {"gl_texture", "gl_texture_load", "Gfx", &gallery::demo_gl_texture}, // wave 1 }; static constexpr int k_demo_count = sizeof(k_demos) / sizeof(k_demos[0]);