#pragma once #include #include #include #include enum class UIEventType { ASTChanged, BufferSwitched, DiagnosticsUpdated, ThemeChanged, SettingsChanged, FileModified, AgentConnected, NotificationPosted }; struct UIEvent { UIEventType type = UIEventType::ASTChanged; std::string path; std::string detail; double timestamp = 0.0; }; class UIEventBus { public: using Handler = std::function; int subscribe(UIEventType type, Handler handler) { int id = ++nextId; handlers[keyFor(type)].push_back({id, std::move(handler)}); return id; } void publish(UIEventType type, const std::string& path = {}, const std::string& detail = {}, double nowSeconds = 0.0) { UIEvent ev; ev.type = type; ev.path = path; ev.detail = detail; ev.timestamp = nowSeconds; dispatch(ev); } void publishDebounced(UIEventType type, const std::string& path, const std::string& detail, double nowSeconds, double delaySeconds) { PendingEvent& pendingEvent = pending[keyFor(type)]; pendingEvent.event.type = type; pendingEvent.event.path = path; pendingEvent.event.detail = detail; pendingEvent.event.timestamp = nowSeconds; pendingEvent.readyAt = nowSeconds + delaySeconds; } void tick(double nowSeconds) { std::vector ready; ready.reserve(pending.size()); for (const auto& kv : pending) { if (nowSeconds >= kv.second.readyAt) { ready.push_back(kv.first); } } for (int key : ready) { auto it = pending.find(key); if (it == pending.end()) continue; dispatch(it->second.event); pending.erase(it); } } private: struct HandlerEntry { int id = 0; Handler fn; }; struct PendingEvent { UIEvent event; double readyAt = 0.0; }; int nextId = 0; std::unordered_map> handlers; std::unordered_map pending; static int keyFor(UIEventType type) { return static_cast(type); } void dispatch(const UIEvent& ev) { auto it = handlers.find(keyFor(ev.type)); if (it == handlers.end()) return; for (const auto& entry : it->second) { if (entry.fn) entry.fn(ev); } } };