/
SilovAndrey
/
LotShell
Обзор
Документация
Войти
/
SilovAndrey
/
LotShell
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/modules/clock/clock_module.hpp
240 строк
7 KB
Andrey HomePC
output.cpp update
5 часов назад
5 часов назад
ed502b1
Код
Авторство
О чём код?
#pragma once #include "core/module.hpp" #include "core/messages.hpp" #include "clock_messages.hpp" #include <thorvg.h> #include <ctime> #include <string> #include <vector> #include <algorithm> namespace clock_module { // ============================================================================ // МОДУЛЬ ЧАСОВ // ============================================================================ class ClockModule : public mvu::DirtyModule<ClockModule> { private: // ===== МОДЕЛЬ ===== struct Model { std::string time_str{"00:00:00"}; std::string date_str{"01.01.1970"}; std::time_t timestamp{0}; bool is_hovered{false}; Rect bounds{0, 0, 220, 70}; }; Model model_; ElementId id_{INVALID_ID}; // ===== MASTER-ДЕРЕВО ===== tvg::Scene* master_scene_{nullptr}; tvg::Shape* master_bg_{nullptr}; tvg::Text* master_time_{nullptr}; tvg::Text* master_date_{nullptr}; // ===== КОПИИ ДЛЯ ПАНЕЛЕЙ ===== struct SceneCopy { tvg::Scene* scene{nullptr}; tvg::Shape* bg{nullptr}; tvg::Text* time_text{nullptr}; tvg::Text* date_text{nullptr}; ElementId panel_id{INVALID_ID}; }; std::vector<SceneCopy> copies_; public: ClockModule(ElementId id) : id_(id) { init_master_tree(); } ~ClockModule() { if (master_scene_) { master_scene_->unref(); master_scene_ = nullptr; } for (auto& copy : copies_) { if (copy.scene) { copy.scene->unref(); } } } // ===== IModule ===== ElementId get_id() const override { return id_; } Rect get_bounds() const override { return model_.bounds; } void set_bounds(const Rect& bounds) override { model_.bounds = bounds; mark_dirty(); } bool hit_test(const Point& point) const override { return model_.bounds.contains(point); } void register_handlers(mvu::HandlerRegistry& registry) override { registry.register_handler<TickMsg>( id_, [this](const Tick& data) { return handle_timer_tick(data); } ); registry.register_handler<mvu::user::MouseMoveMsg>( id_, [this](const mvu::user::MouseMove& data) { return handle_mouse_move(data); } ); registry.register_handler<mvu::user::MouseDownMsg>( id_, [this](const mvu::user::MouseDown& data) { return handle_mouse_down(data); } ); } // ===== ОБРАБОТЧИКИ ===== mvu::HandlerResult handle_timer_tick(const Tick& data) { model_.time_str = data.time_string; model_.date_str = data.date_string; model_.timestamp = data.timestamp; mark_dirty(); return {true, true, {}}; } mvu::HandlerResult handle_mouse_move(const mvu::user::MouseMove& data) { if (!model_.bounds.contains(Point{data.x, data.y})) { return {true, false, {}}; } bool hover = model_.bounds.contains(Point{data.x, data.y}); if (hover != model_.is_hovered) { model_.is_hovered = hover; mark_dirty(); return {true, true, {}}; } return {true, false, {}}; } mvu::HandlerResult handle_mouse_down(const mvu::user::MouseDown& data) { if (!model_.bounds.contains(Point{data.x, data.y})) { return {true, false, {}}; } auto cmd = std::make_unique<mvu::LogCommand>(); cmd->message = "🕐 Clock clicked: " + model_.time_str; return {true, false, std::move(cmd)}; } // ===== THORVG ===== void init_master_tree() { using namespace tvg; master_scene_ = Scene::gen(); master_scene_->translate(model_.bounds.x, model_.bounds.y); master_bg_ = Shape::gen(); master_bg_->appendRect(0, 0, model_.bounds.w, model_.bounds.h, 10, 10); master_bg_->fill(30, 30, 40, 220); master_scene_->push(master_bg_); master_time_ = Text::gen(); master_time_->text(model_.time_str.c_str()); master_time_->fill(255, 255, 255, 255); master_time_->translate(15, 8); master_scene_->push(master_time_); master_date_ = Text::gen(); master_date_->text(model_.date_str.c_str()); master_date_->fill(180, 180, 190, 255); master_date_->translate(15, 40); master_scene_->push(master_date_); } void update_nodes_impl() override { using namespace tvg; master_scene_->translate(model_.bounds.x, model_.bounds.y); master_bg_->reset(); master_bg_->appendRect(0, 0, model_.bounds.w, model_.bounds.h, 10, 10); if (model_.is_hovered) { master_bg_->fill(50, 50, 60, 220); } else { master_bg_->fill(30, 30, 40, 220); } master_time_->text(model_.time_str.c_str()); master_date_->text(model_.date_str.c_str()); for (auto& copy : copies_) { if (!copy.scene) continue; copy.scene->translate(model_.bounds.x, model_.bounds.y); copy.bg->reset(); copy.bg->appendRect(0, 0, model_.bounds.w, model_.bounds.h, 10, 10); if (model_.is_hovered) { copy.bg->fill(50, 50, 60, 220); } else { copy.bg->fill(30, 30, 40, 220); } copy.time_text->text(model_.time_str.c_str()); copy.date_text->text(model_.date_str.c_str()); } } // ===== КОПИРОВАНИЕ ДЛЯ ПАНЕЛЕЙ ===== SceneCopy create_copy_for_panel(ElementId panel_id) { using namespace tvg; tvg::Scene* copy_scene = master_scene_->duplicate(); auto paints = copy_scene->paints(); tvg::Shape* copy_bg = nullptr; tvg::Text* copy_time = nullptr; tvg::Text* copy_date = nullptr; for (auto* paint : paints) { if (auto* shape = dynamic_cast<tvg::Shape*>(paint)) { copy_bg = shape; } else if (auto* text = dynamic_cast<tvg::Text*>(paint)) { if (!copy_time) { copy_time = text; } else { copy_date = text; } } } SceneCopy copy; copy.scene = copy_scene; copy.bg = copy_bg; copy.time_text = copy_time; copy.date_text = copy_date; copy.panel_id = panel_id; copies_.push_back(copy); return copy; } void remove_copy(ElementId panel_id) { auto it = std::find_if(copies_.begin(), copies_.end(), [panel_id](const SceneCopy& copy) { return copy.panel_id == panel_id; }); if (it != copies_.end()) { if (it->scene) { it->scene->unref(); } copies_.erase(it); } } }; } // namespace clock_module