#include "Plot_p.h" #include "../bridge/Qt_Event_Adapter.h" #include "../bridge/Qt_Image_Adapter.h" #include "../bridge/Qt_Presentation_Sink.h" #include "Core/architecture/Render_Time.h" #include "Core/base/global.h" #include "Core/plottable/export.h" #include "Core/plot/Plot_Core_Access.h" #include "Core/architecture/Plot_Render_Context.h" #include #include #include #include namespace renderive { namespace { Color from_qcolor(const QColor& color) { return { static_cast(color.red()), static_cast(color.green()), static_cast(color.blue()), static_cast(color.alpha()) }; } QColor to_qcolor(Color color) { return QColor(color.r, color.g, color.b, color.a); } std::string to_utf8_string(const QString& text) { QByteArray bytes = text.toUtf8(); return std::string(bytes.constData(), static_cast(bytes.size())); } } // namespace void start_render_scheduler(Render_Runtime_Config config) { Global::instance()->start_render_scheduler(config); } Abs_Plot_Private::Abs_Plot_Private(std::unique_ptr frame_flow) : flow(frame_flow.get()), core(std::make_unique(std::move(frame_flow))) {} Abs_Plot_Private::~Abs_Plot_Private() = default; void Abs_Plot_Private::attach_widget(Abs_Plot* plot) { presentation_sink = std::make_shared(plot); core->set_presentation_sink(presentation_sink); QPointer guarded_plot(plot); auto pending = performance_update_pending; set_performance_overlay_update_callback(*core, [guarded_plot, pending]() mutable { if (!guarded_plot || pending->exchange(true, std::memory_order_acq_rel)) return; QTimer::singleShot(0, guarded_plot.data(), [guarded_plot, pending]() mutable { pending->store(false, std::memory_order_release); if (guarded_plot) guarded_plot->update(); }); }); } Abs_Plot::Abs_Plot(Abs_Plot_Private* private_data) : d(private_data) { d->attach_widget(this); setAttribute(Qt::WA_OpaquePaintEvent, true); setMouseTracking(true); setFocusPolicy(Qt::NoFocus); } Abs_Plot::~Abs_Plot() { if (d) { set_performance_overlay_update_callback(*d->core, {}); d->core->deactivate_view(); delete d; d = nullptr; } } void Abs_Plot::init() { init_renderable_tree(); } void Abs_Plot::init_renderable_tree() { d->core->init(); } Plot_Core* Abs_Plot::core() const { return d ? d->core.get() : nullptr; } std::shared_ptr Abs_Plot::root_renderable() const { return d->core->root_renderable(); } std::shared_ptr Abs_Plot::create_renderable_node(const std::shared_ptr& parent, const QString& object_name) const { return d->core->create_renderable_node(parent, to_utf8_string(object_name)); } void Abs_Plot::remove_renderable(const std::shared_ptr& able) { d->core->remove_renderable(able); } QColor Abs_Plot::background_color() { return to_qcolor(d->core->background_color()); } void Abs_Plot::set_background_color(const QColor& color) { d->core->set_background_color(from_qcolor(color)); } void Abs_Plot::paintEvent(QPaintEvent* event) { d->paint_event(this, event); } bool Abs_Plot::event(QEvent* event) { bool base_result = QWidget::event(event); return d->event(this, event, base_result); } void Abs_Plot_Private::paint_event(Abs_Plot* plot, QPaintEvent* event) { (void)event; std::uint64_t paint_begin_time = steady_now_ns(); auto frame = core->begin_present(); QPainter painter(plot); if (frame && !frame.image().empty()) { QImage image = Qt_Image_Adapter::to_qimage(frame.image()); painter.drawImage(QPoint(0, 0), image); } else { painter.fillRect(plot->rect(), plot->background_color()); } auto performance_snapshot = performance_overlay_snapshot(*core); if (performance_snapshot && !performance_snapshot->image.empty()) { Size current_size = core->viewport_size(); auto ctx = Plot_Core_Context_Access::render_context(*core); std::uint64_t current_viewport_version = ctx ? ctx->viewport_version.load(std::memory_order_acquire) : 0; if (performance_snapshot->viewport_size == current_size && performance_snapshot->viewport_version == current_viewport_version) { QImage overlay = Qt_Image_Adapter::to_qimage(performance_snapshot->image.view()); const RectF& target = performance_snapshot->destination_rect; painter.drawImage(QRectF(target.x, target.y, target.width, target.height), overlay); } } painter.end(); core->end_present(std::move(frame), paint_begin_time, steady_now_ns()); } void Abs_Plot_Private::request_performance_overlay_update(Abs_Plot* plot) { if (!plot || performance_update_pending->exchange(true, std::memory_order_acq_rel)) return; QPointer guarded_plot(plot); auto pending = performance_update_pending; QTimer::singleShot(0, plot, [guarded_plot, pending]() mutable { pending->store(false, std::memory_order_release); if (guarded_plot) guarded_plot->update(); }); } bool Abs_Plot_Private::event(Abs_Plot* plot, QEvent* event, bool base_result) { switch (event->type()) { case QEvent::Resize: { auto* resize_event = static_cast(event); core->set_viewport_size(Qt_Event_Adapter::to_size(resize_event->size())); notify_performance_overlay_viewport_changed(*core); core->dispatch_event(Qt_Event_Adapter::to_resize_event(resize_event)); core->notify_model_dirty(); break; } case QEvent::Show: { Event show_event(Event_Type::Show); core->dispatch_event(show_event); core->activate_view(); break; } case QEvent::Hide: { Event hide_event(Event_Type::Hide); core->dispatch_event(hide_event); core->deactivate_view(); break; } case QEvent::Leave: { Event leave_event(Event_Type::Leave); core->dispatch_event(leave_event); break; } case QEvent::Wheel: { auto wheel_event = Qt_Event_Adapter::to_wheel_event(static_cast(event)); if (performance_overlay_handle_wheel(*core, wheel_event.position, wheel_event.angle_delta_y, wheel_event.pixel_delta_y)) { event->accept(); request_performance_overlay_update(plot); return true; } core->dispatch_event(wheel_event); break; } case QEvent::MouseMove: { auto pointer_event = Qt_Event_Adapter::to_pointer_event(static_cast(event), Event_Type::Pointer_Move); if (performance_overlay_handle_pointer_move(*core, pointer_event.position)) { event->accept(); request_performance_overlay_update(plot); return true; } core->dispatch_event(pointer_event); break; } case QEvent::MouseButtonPress: { auto* mouse_event = static_cast(event); auto pointer_event = Qt_Event_Adapter::to_pointer_event(mouse_event, Event_Type::Pointer_Press); if (mouse_event->button() == Qt::LeftButton && performance_overlay_handle_pointer_press(*core, pointer_event.position)) { event->accept(); request_performance_overlay_update(plot); return true; } core->dispatch_event(pointer_event); break; } case QEvent::MouseButtonRelease: { auto* mouse_event = static_cast(event); auto pointer_event = Qt_Event_Adapter::to_pointer_event(mouse_event, Event_Type::Pointer_Release); if (mouse_event->button() == Qt::LeftButton && performance_overlay_handle_pointer_release(*core, pointer_event.position)) { event->accept(); request_performance_overlay_update(plot); return true; } core->dispatch_event(pointer_event); break; } case QEvent::KeyPress: core->dispatch_event(Qt_Event_Adapter::to_key_event(static_cast(event), Event_Type::Key_Press)); break; case QEvent::KeyRelease: core->dispatch_event(Qt_Event_Adapter::to_key_event(static_cast(event), Event_Type::Key_Release)); break; default: break; } return base_result; } } // namespace renderive