YODAU 1.0
YEAR OF THE DEPEND ADULT UNDERGARMENT
Loading...
Searching...
No Matches
stream_cell Class Referencefinal

Widget representing one video stream cell in the frontend. More...

#include <frontend/include/widgets/stream_cell.hpp>

Inheritance diagram for stream_cell:
Collaboration diagram for stream_cell:

Classes

struct  line_instance
 Instance of a persistent (saved) line to be rendered on the stream. More...
struct  event_instance
 Instance of a transient visual event marker. More...
struct  hit_info
 Hit info attached to a line highlight. More...

Signals

void request_close (const QString &name)
 Emitted when the user requests closing this stream cell.
void request_focus (const QString &name)
 Emitted when the user requests focusing/enlarging this cell.
void frame_ready (const QString &stream_name, const QImage &image)
 Emitted whenever a new frame image becomes available.

Public Member Functions

 stream_cell (const QString &name, QWidget *parent=nullptr)
 Construct a stream cell.
const QString & get_name () const
 Get logical name of this stream cell.
bool is_active () const
 Check whether this cell is currently active (focused).
std::vector< QPointF > draft_points_pct () const
 Get current draft polyline points (percentage coordinates).
bool draft_closed () const
 Get whether current draft line is closed.
QString draft_name () const
 Get current draft line name.
QColor draft_color () const
 Get current draft line color.
bool is_draft_preview () const
 Check whether the draft is in preview-only mode.
void set_active (bool val)
 Set active (focused) state.
void set_drawing_enabled (bool on)
 Enable or disable interactive drawing on this cell.
void set_draft_params (const QString &name, const QColor &color, bool closed)
 Set draft line parameters (name, color, closed flag).
void set_draft_points_pct (const std::vector< QPointF > &pts)
 Replace current draft points (percentage coordinates).
void clear_draft ()
 Clear all draft data (points, hover point, preview flag).
void set_persistent_lines (const std::vector< line_instance > &lines)
 Replace all persistent lines.
void add_persistent_line (const line_instance &line)
 Append a persistent line to the list.
void clear_persistent_lines ()
 Remove all persistent lines.
void set_draft_preview (bool on)
 Enable or disable draft preview mode.
void set_labels_enabled (bool on)
 Enable or disable rendering of persistent line labels.
void set_source (const QUrl &source)
 Set media player source.
void set_loop (bool on)
 Enable or disable looping for file-based playback.
void set_camera_id (const QByteArray &id)
 Switch to camera input by device id.
void add_event (const QPointF &pos_pct, const QColor &color)
 Add a transient event marker.
void set_repaint_interval_ms (int ms)
 Set minimum repaint interval for video frame updates.
void highlight_line (const QString &line_name)
 Highlight a persistent line by name.
void highlight_line_at (const QString &line_name, const QPointF &pos_pct)
 Highlight a line and record a hit position for spatial falloff.

Protected Member Functions

void paintEvent (QPaintEvent *event) override
 Paint handler.
void mousePressEvent (QMouseEvent *event) override
 Mouse press handler for drawing draft points.
void mouseMoveEvent (QMouseEvent *event) override
 Mouse move handler for hover updates while drawing.
void leaveEvent (QEvent *event) override
 Leave handler to clear hover state.
void keyPressEvent (QKeyEvent *event) override
 Key press handler for draft undo.

Private Slots

void on_frame_changed (const QVideoFrame &frame)
 Slot called when the video sink receives a new frame.
void on_media_status_changed (QMediaPlayer::MediaStatus status)
 Slot called on media status changes.
void on_player_error (QMediaPlayer::Error error, const QString &error_string)
 Slot called when media player errors occur.
void on_camera_error (QCamera::Error error)
 Slot called on camera errors.

Private Member Functions

void build_ui ()
 Build child UI widgets (buttons, sink/player connections).
void update_icon ()
 Update focus button icon/tooltip based on active state.
void draw_poly_with_points (QPainter &p, const std::vector< QPointF > &pts_pct, const QColor &color, bool closed, Qt::PenStyle style, qreal width) const
 Draw a polyline/polygon with point markers.
void draw_persistent (QPainter &p) const
 Draw all persistent lines and their labels/highlights.
void draw_draft (QPainter &p) const
 Draw the draft line (if any).
void draw_hover_point (QPainter &p) const
 Draw hover point indicator (if any).
void draw_hover_coords (QPainter &p) const
 Draw hover coordinate text (if enabled).
void draw_preview_segment (QPainter &p) const
 Draw preview segment from last draft point to hover point.
void draw_stream_name (QPainter &p) const
 Draw stream name overlay at top-left.
QPointF label_pos_px (const line_instance &l) const
 Compute label anchor position for a line in pixel coordinates.
QPointF to_pct (const QPointF &pos_px) const
 Convert pixel position to percentage coordinates.
QPointF to_px (const QPointF &pos_pct) const
 Convert percentage coordinates to pixel position.
void draw_events (QPainter &p)
 Draw transient events and prune expired ones.

Private Attributes

QString name
 Logical stream name.
QPushButton * close_btn { nullptr }
 UI close button (top-right).
QPushButton * focus_btn { nullptr }
 UI focus/enlarge button (top-right).
QLabel * name_label { nullptr }
 Optional name label (unused in current implementation).
bool active { false }
 Whether the cell is focused/active.
bool drawing_enabled { false }
 Whether interactive drawing is enabled.
bool draft_preview { false }
 Whether draft line is shown in preview mode.
bool labels_enabled { true }
 Whether persistent line labels are shown when active.
QString draft_line_name
 Draft line name.
QColor draft_line_color { Qt::red }
 Draft line color.
bool draft_line_closed { false }
 Draft line closed flag.
std::vector< QPointF > draft_line_points_pct
 Draft polyline points in percentage coordinates.
std::optional< QPointF > hover_point_pct
 Current hover position in percentage coordinates.
std::vector< line_instancepersistent_lines
 Persisted lines to render.
QMediaPlayer * player { nullptr }
 Media player for file/URL sources.
QVideoSink * sink { nullptr }
 Video sink feeding decoded frames into the widget.
QImage last_frame
 Most recent received frame as an image.
bool loop_enabled { true }
 Whether playback looping is enabled.
QString last_error
 Last error string to display when no frame is available.
QCamera * camera { nullptr }
 Active camera (if using live input).
QMediaCaptureSession * session { nullptr }
 Capture session binding camera to sink.
QByteArray camera_id
 Selected camera id.
QVector< event_instanceevents
 Transient events currently displayed.
QElapsedTimer repaint_timer
 Timer throttling repaint frequency.
int repaint_interval_ms { 66 }
 Minimum repaint interval in ms.
QHash< QString, QDateTime > line_highlights
 Line highlight timestamps by line name.
int line_highlight_ttl_ms { 2500 }
 Highlight time-to-live in ms.
QHash< QString, hit_infoline_hits
 Optional hit positions per line name.

Detailed Description

Widget representing one video stream cell in the frontend.

A stream cell is a self-contained view of a video source that can be:

  • inactive (thumbnail in a grid),
  • active (focused/enlarged and optionally editable).

Coordinate system:

  • All geometry overlays (draft and persistent lines, events) are stored in percentage coordinates:
    • x,y in range [0.0; 100.0]
    • (0,0) is top-left of the widget
    • (100,100) is bottom-right of the widget

Interaction:

  • When drawing is enabled and the cell is active:
    • Left click adds a draft point at cursor position.
    • Mouse move updates hover position (preview segment).
    • Backspace / Ctrl+Z removes last draft point.

Rendering:

  • Video frame fills the widget area.
  • Persistent lines are drawn solid, with optional labels.
  • Draft line is drawn dashed.
  • Hover point/coords and preview segments are shown while drawing.
  • Recent events are drawn as fading circles.
  • Line highlights (by name and optional hit point) animate for a short TTL.

Definition at line 75 of file stream_cell.hpp.

Constructor & Destructor Documentation

◆ stream_cell()

stream_cell::stream_cell ( const QString & name,
QWidget * parent = nullptr )
explicit

Construct a stream cell.

Parameters
nameLogical stream name displayed in the widget.
parentOptional parent widget.

Definition at line 18 of file stream_cell.cpp.

19 : QWidget(parent)
20 , name(name)
21 , close_btn(nullptr)
22 , focus_btn(nullptr)
23 , name_label(nullptr)
24 , player(nullptr)
25 , sink(nullptr)
26 , camera(nullptr)
27 , session(nullptr) {
28 build_ui();
29 setFocusPolicy(Qt::StrongFocus);
30 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
31 repaint_timer.start();
32}
QMediaPlayer * player
Media player for file/URL sources.
QPushButton * close_btn
UI close button (top-right).
QCamera * camera
Active camera (if using live input).
QVideoSink * sink
Video sink feeding decoded frames into the widget.
QMediaCaptureSession * session
Capture session binding camera to sink.
QLabel * name_label
Optional name label (unused in current implementation).
QElapsedTimer repaint_timer
Timer throttling repaint frequency.
QPushButton * focus_btn
UI focus/enlarge button (top-right).
QString name
Logical stream name.
void build_ui()
Build child UI widgets (buttons, sink/player connections).

References build_ui(), close_btn, focus_btn, and name_label.

Here is the call graph for this function:

Member Function Documentation

◆ add_event()

void stream_cell::add_event ( const QPointF & pos_pct,
const QColor & color )

Add a transient event marker.

Parameters
pos_pctEvent position in percentage coordinates.
colorEvent color.

Definition at line 183 of file stream_cell.cpp.

183 {
185 e.pos_pct = pos_pct;
186 e.color = color;
187 e.ts = QDateTime::currentDateTime();
188
189 events.push_back(e);
190 update();
191}
QVector< event_instance > events
Transient events currently displayed.
Instance of a transient visual event marker.
QPointF pos_pct
Event position in percentage coordinates.

◆ add_persistent_line()

void stream_cell::add_persistent_line ( const line_instance & line)

Append a persistent line to the list.

Parameters
lineLine instance to add.

Definition at line 100 of file stream_cell.cpp.

100 {
101 persistent_lines.push_back(line);
102 update();
103}
std::vector< line_instance > persistent_lines
Persisted lines to render.

◆ build_ui()

void stream_cell::build_ui ( )
private

Build child UI widgets (buttons, sink/player connections).

Definition at line 329 of file stream_cell.cpp.

329 {
330 const auto root = new QVBoxLayout(this);
331 root->setContentsMargins(6, 6, 6, 6);
332 root->setSpacing(6);
333
334 const auto top_row = new QHBoxLayout();
335 top_row->setContentsMargins(0, 0, 0, 0);
336 top_row->setSpacing(4);
337
338 top_row->addStretch();
339
340 focus_btn = new QPushButton(this);
341 focus_btn->setFixedSize(24, 24);
342 focus_btn->setIconSize(QSize(16, 16));
343 focus_btn->setFlat(true);
344 focus_btn->setFocusPolicy(Qt::NoFocus);
345 update_icon();
346 top_row->addWidget(focus_btn);
347
348 close_btn = new QPushButton(this);
349 close_btn->setFixedSize(24, 24);
350 close_btn->setIconSize(QSize(16, 16));
351 close_btn->setToolTip(tr("close"));
352 close_btn->setFlat(true);
353 close_btn->setFocusPolicy(Qt::NoFocus);
354
355#if defined(KC_KDE)
356 close_btn->setIcon(
358 { "window-close", "dialog-close", "edit-delete" },
359 QStyle::SP_TitleBarCloseButton
360 )
361 );
362#else
363 close_btn->setIcon(
365 { "window-close", "dialog-close" }, QStyle::SP_TitleBarCloseButton
366 )
367 );
368#endif
369 top_row->addWidget(close_btn);
370 root->addLayout(top_row);
371 root->addStretch(1);
372
373 sink = new QVideoSink(this);
374 connect(
375 sink, &QVideoSink::videoFrameChanged, this,
377 );
378
379 player = new QMediaPlayer(this);
380 player->setVideoOutput(sink);
381 // player->setSource(QUrl::fromLocalFile("/home/yarro/Pictures/kino/1080.mp4"));
382 // player->play();
383
384 connect(close_btn, &QPushButton::clicked, this, [this]() {
385 emit request_close(name);
386 });
387 connect(focus_btn, &QPushButton::clicked, this, [this]() {
388 emit request_focus(name);
389 });
390 connect(
391 player, &QMediaPlayer::mediaStatusChanged, this,
393 );
394 connect(
395 player, &QMediaPlayer::errorOccurred, this,
397 );
398}
static QIcon themed(std::initializer_list< const char * > names, QStyle::StandardPixmap fallback)
Load a themed icon using multiple candidate names.
void request_focus(const QString &name)
Emitted when the user requests focusing/enlarging this cell.
void update_icon()
Update focus button icon/tooltip based on active state.
void on_player_error(QMediaPlayer::Error error, const QString &error_string)
Slot called when media player errors occur.
void on_frame_changed(const QVideoFrame &frame)
Slot called when the video sink receives a new frame.
void on_media_status_changed(QMediaPlayer::MediaStatus status)
Slot called on media status changes.
void request_close(const QString &name)
Emitted when the user requests closing this stream cell.

References close_btn, focus_btn, and update_icon().

Referenced by stream_cell().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear_draft()

void stream_cell::clear_draft ( )

Clear all draft data (points, hover point, preview flag).

Definition at line 86 of file stream_cell.cpp.

86 {
88 hover_point_pct.reset();
89 draft_preview = false;
90 update();
91}
std::vector< QPointF > draft_line_points_pct
Draft polyline points in percentage coordinates.
bool draft_preview
Whether draft line is shown in preview mode.
std::optional< QPointF > hover_point_pct
Current hover position in percentage coordinates.

References draft_preview.

Referenced by controller::apply_added_line(), controller::apply_template_preview(), controller::on_active_edit_mode_changed(), controller::on_active_stream_selected(), and set_active().

Here is the caller graph for this function:

◆ clear_persistent_lines()

void stream_cell::clear_persistent_lines ( )

Remove all persistent lines.

Definition at line 105 of file stream_cell.cpp.

105 {
106 persistent_lines.clear();
107 update();
108}

◆ draft_closed()

bool stream_cell::draft_closed ( ) const
nodiscard

Get whether current draft line is closed.

Returns
true if draft is closed.

Definition at line 42 of file stream_cell.cpp.

42{ return draft_line_closed; }
bool draft_line_closed
Draft line closed flag.

References draft_line_closed.

◆ draft_color()

QColor stream_cell::draft_color ( ) const
nodiscard

Get current draft line color.

Returns
Draft color.

Definition at line 46 of file stream_cell.cpp.

46{ return draft_line_color; }
QColor draft_line_color
Draft line color.

◆ draft_name()

QString stream_cell::draft_name ( ) const
nodiscard

Get current draft line name.

Returns
Draft name, may be empty.

Definition at line 44 of file stream_cell.cpp.

44{ return draft_line_name; }
QString draft_line_name
Draft line name.

◆ draft_points_pct()

std::vector< QPointF > stream_cell::draft_points_pct ( ) const
nodiscard

Get current draft polyline points (percentage coordinates).

Returns
Copy of draft points.

Definition at line 38 of file stream_cell.cpp.

38 {
40}

◆ draw_draft()

void stream_cell::draw_draft ( QPainter & p) const
private

Draw the draft line (if any).

Definition at line 573 of file stream_cell.cpp.

573 {
574 if (draft_line_points_pct.empty()) {
575 return;
576 }
577
580 Qt::DashLine, 2.0
581 );
582}
void draw_poly_with_points(QPainter &p, const std::vector< QPointF > &pts_pct, const QColor &color, bool closed, Qt::PenStyle style, qreal width) const
Draw a polyline/polygon with point markers.

Referenced by paintEvent().

Here is the caller graph for this function:

◆ draw_events()

void stream_cell::draw_events ( QPainter & p)
private

Draw transient events and prune expired ones.

Definition at line 673 of file stream_cell.cpp.

673 {
674 const auto now = QDateTime::currentDateTime();
675 const int ttl_ms = 2000;
676
677 const QRect r = rect();
678 const double w = static_cast<double>(r.width());
679 const double h = static_cast<double>(r.height());
680 const double base = std::min(w, h);
681 const double radius = base * 0.015;
682
683 QVector<event_instance> alive;
684 alive.reserve(events.size());
685
686 for (const auto& e : events) {
687 const int age = static_cast<int>(e.ts.msecsTo(now));
688 if (age >= ttl_ms) {
689 continue;
690 }
691
692 alive.push_back(e);
693
694 const double k = 1.0 - static_cast<double>(age) / ttl_ms;
695 int a = static_cast<int>(120.0 * k);
696 if (a < 0) {
697 a = 0;
698 }
699
700 QColor c = e.color;
701 c.setAlpha(a);
702
703 const double x = r.left() + w * (e.pos_pct.x() / 100.0);
704 const double y = r.top() + h * (e.pos_pct.y() / 100.0);
705
706 p.setPen(Qt::NoPen);
707 p.setBrush(c);
708 p.drawEllipse(QPointF(x, y), radius, radius);
709 }
710
711 events = std::move(alive);
712}

Referenced by paintEvent().

Here is the caller graph for this function:

◆ draw_hover_coords()

void stream_cell::draw_hover_coords ( QPainter & p) const
private

Draw hover coordinate text (if enabled).

Definition at line 597 of file stream_cell.cpp.

597 {
598 if (!(hover_point_pct.has_value() && drawing_enabled && active)) {
599 return;
600 }
601
602 const auto& hp = *hover_point_pct;
603 QString txt
604 = QString("x=%1 y=%2").arg(hp.x(), 0, 'f', 1).arg(hp.y(), 0, 'f', 1);
605
606 QRect r = rect().adjusted(6, 6, -6, -6);
607 p.setPen(palette().color(QPalette::Text));
608 p.drawText(r, Qt::AlignLeft | Qt::AlignBottom, txt);
609}
bool active
Whether the cell is focused/active.
bool drawing_enabled
Whether interactive drawing is enabled.

Referenced by paintEvent().

Here is the caller graph for this function:

◆ draw_hover_point()

void stream_cell::draw_hover_point ( QPainter & p) const
private

Draw hover point indicator (if any).

Definition at line 584 of file stream_cell.cpp.

584 {
585 if (!hover_point_pct.has_value()) {
586 return;
587 }
588
589 QPen hpen(draft_line_color);
590 hpen.setWidthF(1.0);
591 hpen.setStyle(Qt::DashLine);
592 p.setPen(hpen);
593
594 p.drawEllipse(to_px(*hover_point_pct), 4.0, 4.0);
595}
QPointF to_px(const QPointF &pos_pct) const
Convert percentage coordinates to pixel position.

Referenced by paintEvent().

Here is the caller graph for this function:

◆ draw_persistent()

void stream_cell::draw_persistent ( QPainter & p) const
private

Draw all persistent lines and their labels/highlights.

Definition at line 471 of file stream_cell.cpp.

471 {
472 const auto now = QDateTime::currentDateTime();
473
474 for (const auto& l : persistent_lines) {
475 const auto key = l.template_name.trimmed();
476
477 if (!key.isEmpty() && line_highlights.contains(key)) {
478 const int age = static_cast<int>(line_highlights[key].msecsTo(now));
479 if (age < line_highlight_ttl_ms) {
480 double ktime
481 = 1.0 - static_cast<double>(age) / line_highlight_ttl_ms;
482 if (ktime < 0.0) {
483 ktime = 0.0;
484 }
485
486 const double falloff_pct = 30.0;
487 const double base_w = 2.0;
488 const double peak_w = 22.0;
489
490 bool has_hit = false;
491 QPointF hit_pct;
492
493 if (line_hits.contains(key)) {
494 const auto& h = line_hits[key];
495 const int hit_age = static_cast<int>(h.ts.msecsTo(now));
496 if (hit_age < line_highlight_ttl_ms) {
497 has_hit = true;
498 hit_pct = h.pos_pct;
499 }
500 }
501
502 if (!has_hit) {
503 QColor hc = l.color;
504 int a = static_cast<int>(255.0 * ktime);
505 if (a < 0) {
506 a = 0;
507 }
508 hc.setAlpha(a);
509
510 const double w = base_w + (peak_w - base_w) * ktime;
511
513 p, l.pts_pct, hc, l.closed, Qt::SolidLine, w
514 );
515 } else {
516 for (size_t i = 1; i < l.pts_pct.size(); ++i) {
517 const QPointF a_pct = l.pts_pct[i - 1];
518 const QPointF b_pct = l.pts_pct[i];
519
520 const QPointF mid = (a_pct + b_pct) * 0.5;
521 const double dx = mid.x() - hit_pct.x();
522 const double dy = mid.y() - hit_pct.y();
523 double dist = std::sqrt(dx * dx + dy * dy);
524
525 double kspace = 1.0 - dist / falloff_pct;
526 if (kspace < 0.0) {
527 kspace = 0.0;
528 }
529
530 kspace = kspace * kspace;
531
532 const double k = ktime * kspace;
533 if (k <= 0.0) {
534 continue;
535 }
536
537 QColor hc = l.color;
538 int a = static_cast<int>(255.0 * k);
539 if (a < 0) {
540 a = 0;
541 }
542 hc.setAlpha(a);
543
544 const double w = base_w + (peak_w - base_w) * k;
545
546 std::vector<QPointF> seg { a_pct, b_pct };
548 p, seg, hc, false, Qt::SolidLine, w
549 );
550 }
551 }
552 }
553 }
554
556 p, l.pts_pct, l.color, l.closed, Qt::SolidLine, 2.0
557 );
558
559 if (!(active && labels_enabled)) {
560 continue;
561 }
562
563 const auto text = key;
564 if (text.isEmpty()) {
565 continue;
566 }
567
568 p.setPen(l.color);
569 p.drawText(label_pos_px(l), text);
570 }
571}
QHash< QString, QDateTime > line_highlights
Line highlight timestamps by line name.
bool labels_enabled
Whether persistent line labels are shown when active.
QHash< QString, hit_info > line_hits
Optional hit positions per line name.
int line_highlight_ttl_ms
Highlight time-to-live in ms.
QPointF label_pos_px(const line_instance &l) const
Compute label anchor position for a line in pixel coordinates.

Referenced by paintEvent().

Here is the caller graph for this function:

◆ draw_poly_with_points()

void stream_cell::draw_poly_with_points ( QPainter & p,
const std::vector< QPointF > & pts_pct,
const QColor & color,
bool closed,
Qt::PenStyle style,
qreal width ) const
private

Draw a polyline/polygon with point markers.

Points are given in percentage coordinates and projected to widget space.

Parameters
pPainter to draw with.
pts_pctPoints in percentage coordinates.
colorStroke color.
closedWhether to draw polygon instead of polyline.
stylePen style.
widthPen width in pixels.

Definition at line 441 of file stream_cell.cpp.

444 {
445 if (pts_pct.size() < 2) {
446 return;
447 }
448
449 QPen pen(color);
450 pen.setWidthF(width);
451 pen.setStyle(style);
452 p.setPen(pen);
453
454 QPolygonF poly;
455 poly.reserve(static_cast<int>(pts_pct.size()));
456 for (const auto& pt_pct : pts_pct) {
457 poly << to_px(pt_pct);
458 }
459
460 if (closed && poly.size() >= 3) {
461 p.drawPolygon(poly);
462 } else {
463 p.drawPolyline(poly);
464 }
465
466 for (const auto& pt_px : poly) {
467 p.drawEllipse(pt_px, 3.0, 3.0);
468 }
469}

◆ draw_preview_segment()

void stream_cell::draw_preview_segment ( QPainter & p) const
private

Draw preview segment from last draft point to hover point.

Definition at line 611 of file stream_cell.cpp.

611 {
612 if (!(drawing_enabled && active && hover_point_pct.has_value()
613 && !draft_line_points_pct.empty())) {
614 return;
615 }
616
617 QPen pen(draft_line_color);
618 pen.setWidthF(1.5);
619 pen.setStyle(Qt::DashLine);
620 p.setPen(pen);
621
622 const QPointF last_px = to_px(draft_line_points_pct.back());
623 const QPointF hover_px = to_px(*hover_point_pct);
624
625 p.drawLine(last_px, hover_px);
626
627 if (draft_line_closed && draft_line_points_pct.size() >= 2) {
628 const QPointF first_px = to_px(draft_line_points_pct.front());
629 p.drawLine(hover_px, first_px);
630 }
631}

Referenced by paintEvent().

Here is the caller graph for this function:

◆ draw_stream_name()

void stream_cell::draw_stream_name ( QPainter & p) const
private

Draw stream name overlay at top-left.

Definition at line 633 of file stream_cell.cpp.

633 {
634 if (name.isEmpty()) {
635 return;
636 }
637
638 QRect r = rect().adjusted(6, 6, -6, -6);
639 p.setPen(palette().color(QPalette::Text));
640 p.drawText(r, Qt::AlignLeft | Qt::AlignTop, name);
641}

Referenced by paintEvent().

Here is the caller graph for this function:

◆ frame_ready

void stream_cell::frame_ready ( const QString & stream_name,
const QImage & image )
signal

Emitted whenever a new frame image becomes available.

Useful for forwarding frames to backend processing or snapshots.

Parameters
stream_nameName of the stream.
imageConverted QImage representing the latest frame.

◆ get_name()

const QString & stream_cell::get_name ( ) const
nodiscard

Get logical name of this stream cell.

Returns
Reference to stored name.

Definition at line 34 of file stream_cell.cpp.

34{ return name; }

Referenced by board::set_active_stream().

Here is the caller graph for this function:

◆ highlight_line()

void stream_cell::highlight_line ( const QString & line_name)

Highlight a persistent line by name.

Triggers a temporal highlight animation (thicker/alpha pulse).

Parameters
line_nameName of the line to highlight.

Definition at line 200 of file stream_cell.cpp.

200 {
201 if (line_name.isEmpty()) {
202 return;
203 }
204 line_highlights[line_name] = QDateTime::currentDateTime();
205 update();
206}

◆ highlight_line_at()

void stream_cell::highlight_line_at ( const QString & line_name,
const QPointF & pos_pct )

Highlight a line and record a hit position for spatial falloff.

The highlight animation will concentrate around pos_pct if the line supports segment-wise highlighting.

Parameters
line_nameName of the line to highlight.
pos_pctHit position in percentage coordinates.

Definition at line 208 of file stream_cell.cpp.

210 {
211 if (line_name.isEmpty()) {
212 return;
213 }
214
215 hit_info h;
216 h.pos_pct = pos_pct;
217 h.ts = QDateTime::currentDateTime();
218 line_hits[line_name] = h;
219 line_highlights[line_name] = h.ts;
220 update();
221}
Hit info attached to a line highlight.
QPointF pos_pct
Hit position in percentage coordinates.

◆ is_active()

bool stream_cell::is_active ( ) const

Check whether this cell is currently active (focused).

Returns
true if active.

Definition at line 36 of file stream_cell.cpp.

36{ return active; }

References active.

◆ is_draft_preview()

bool stream_cell::is_draft_preview ( ) const

Check whether the draft is in preview-only mode.

Preview mode means draft is shown but not necessarily editable.

Definition at line 48 of file stream_cell.cpp.

48{ return draft_preview; }

References draft_preview.

◆ keyPressEvent()

void stream_cell::keyPressEvent ( QKeyEvent * event)
overrideprotected

Key press handler for draft undo.

Definition at line 305 of file stream_cell.cpp.

305 {
306 if (!(drawing_enabled && active)) {
307 QWidget::keyPressEvent(event);
308 return;
309 }
310
311 const bool undo_key = (event->key() == Qt::Key_Backspace)
312 || (event->key() == Qt::Key_Z
313 && (event->modifiers() & Qt::ControlModifier));
314
315 if (!undo_key) {
316 QWidget::keyPressEvent(event);
317 return;
318 }
319
320 if (!draft_line_points_pct.empty()) {
321 draft_line_points_pct.pop_back();
322 hover_point_pct.reset();
323 update();
324 }
325
326 event->accept();
327}

References active, and drawing_enabled.

◆ label_pos_px()

QPointF stream_cell::label_pos_px ( const line_instance & l) const
private

Compute label anchor position for a line in pixel coordinates.

Uses first or last point depending on closed flag.

Definition at line 643 of file stream_cell.cpp.

643 {
644 if (l.pts_pct.empty()) {
645 return {};
646 }
647
648 const QPointF anchor_pct = l.closed ? l.pts_pct.back() : l.pts_pct.front();
649 const QPointF anchor_px = to_px(anchor_pct);
650 return { anchor_px.x() + 6.0, anchor_px.y() + 14.0 };
651}

◆ leaveEvent()

void stream_cell::leaveEvent ( QEvent * event)
overrideprotected

Leave handler to clear hover state.

Definition at line 299 of file stream_cell.cpp.

299 {
300 hover_point_pct.reset();
301 update();
302 QWidget::leaveEvent(event);
303}

◆ mouseMoveEvent()

void stream_cell::mouseMoveEvent ( QMouseEvent * event)
overrideprotected

Mouse move handler for hover updates while drawing.

Definition at line 288 of file stream_cell.cpp.

288 {
289 if (!drawing_enabled || !active) {
290 QWidget::mouseMoveEvent(event);
291 return;
292 }
293
294 hover_point_pct = to_pct(event->pos());
295 update();
296 event->accept();
297}
QPointF to_pct(const QPointF &pos_px) const
Convert pixel position to percentage coordinates.

References active, and drawing_enabled.

◆ mousePressEvent()

void stream_cell::mousePressEvent ( QMouseEvent * event)
overrideprotected

Mouse press handler for drawing draft points.

Definition at line 265 of file stream_cell.cpp.

265 {
266 if (!drawing_enabled || !active) {
267 QWidget::mousePressEvent(event);
268 return;
269 }
270
271 auto* child = childAt(event->pos());
272 if (child == close_btn || child == focus_btn) {
273 QWidget::mousePressEvent(event);
274 return;
275 }
276
277 if (event->button() == Qt::LeftButton) {
278 setFocus();
279 draft_line_points_pct.push_back(to_pct(event->pos()));
280 update();
281 event->accept();
282 return;
283 }
284
285 QWidget::mousePressEvent(event);
286}

References active, close_btn, drawing_enabled, and focus_btn.

◆ on_camera_error

void stream_cell::on_camera_error ( QCamera::Error error)
privateslot

Slot called on camera errors.

Stores camera error string and triggers a repaint.

Definition at line 768 of file stream_cell.cpp.

768 {
769 Q_UNUSED(error);
770
771 if (!camera) {
772 return;
773 }
774
775 last_error = camera->errorString();
776 update();
777}
QString last_error
Last error string to display when no frame is available.

◆ on_frame_changed

void stream_cell::on_frame_changed ( const QVideoFrame & frame)
privateslot

Slot called when the video sink receives a new frame.

Converts the frame to QImage, emits frame_ready, and schedules repaint respecting repaint_interval_ms.

Definition at line 714 of file stream_cell.cpp.

714 {
715 if (!frame.isValid()) {
716 return;
717 }
718
719 QVideoFrame copy(frame);
720 if (!copy.map(QVideoFrame::ReadOnly)) {
721 return;
722 }
723
724 last_frame = copy.toImage();
725 copy.unmap();
726
728
729 if (!repaint_timer.isValid()) {
730 repaint_timer.start();
731 update();
732 return;
733 }
734
735 if (repaint_timer.elapsed() < repaint_interval_ms) {
736 return;
737 }
738
739 repaint_timer.restart();
740 update();
741}
QImage last_frame
Most recent received frame as an image.
int repaint_interval_ms
Minimum repaint interval in ms.
void frame_ready(const QString &stream_name, const QImage &image)
Emitted whenever a new frame image becomes available.

◆ on_media_status_changed

void stream_cell::on_media_status_changed ( QMediaPlayer::MediaStatus status)
privateslot

Slot called on media status changes.

Used to implement looping on end-of-media when enabled.

Definition at line 743 of file stream_cell.cpp.

745 {
746 if (!loop_enabled) {
747 return;
748 }
749 if (status != QMediaPlayer::EndOfMedia) {
750 return;
751 }
752 if (!player) {
753 return;
754 }
755
756 player->setPosition(0);
757 player->play();
758}
bool loop_enabled
Whether playback looping is enabled.

References loop_enabled.

◆ on_player_error

void stream_cell::on_player_error ( QMediaPlayer::Error error,
const QString & error_string )
privateslot

Slot called when media player errors occur.

Stores the error string and triggers a repaint.

Definition at line 760 of file stream_cell.cpp.

762 {
763 Q_UNUSED(error);
764 last_error = error_string;
765 update();
766}

◆ paintEvent()

void stream_cell::paintEvent ( QPaintEvent * event)
overrideprotected

Paint handler.

Draws:

  • widget background,
  • last video frame or "no signal" message,
  • stream name,
  • events, lines, draft and hover overlays.

Definition at line 223 of file stream_cell.cpp.

223 {
224 Q_UNUSED(event);
225
226 QStyleOption opt;
227 opt.initFrom(this);
228
229 QPainter p(this);
230 style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
231
232 if (!last_frame.isNull()) {
233 p.drawImage(rect(), last_frame);
234 } else {
235 const QString txt = last_error.isEmpty() ? "no signal" : last_error;
236 const QRect r = rect().adjusted(6, 6, -6, -6);
237 p.setPen(palette().color(QPalette::Text));
238 p.drawText(r, Qt::AlignCenter, txt);
239 }
240
242
243 p.drawRect(rect().adjusted(0, 0, -1, -1));
244 p.setRenderHint(QPainter::Antialiasing, true);
245
246 const auto now = QDateTime::currentDateTime();
247
248 for (auto it = line_highlights.begin(); it != line_highlights.end();) {
249 const int age = static_cast<int>(it.value().msecsTo(now));
250 if (age >= line_highlight_ttl_ms) {
251 it = line_highlights.erase(it);
252 } else {
253 ++it;
254 }
255 }
256
257 draw_events(p);
259 draw_draft(p);
263}
void draw_hover_point(QPainter &p) const
Draw hover point indicator (if any).
void draw_stream_name(QPainter &p) const
Draw stream name overlay at top-left.
void draw_preview_segment(QPainter &p) const
Draw preview segment from last draft point to hover point.
void draw_draft(QPainter &p) const
Draw the draft line (if any).
void draw_persistent(QPainter &p) const
Draw all persistent lines and their labels/highlights.
void draw_events(QPainter &p)
Draw transient events and prune expired ones.
void draw_hover_coords(QPainter &p) const
Draw hover coordinate text (if enabled).

References draw_draft(), draw_events(), draw_hover_coords(), draw_hover_point(), draw_persistent(), draw_preview_segment(), draw_stream_name(), and line_highlight_ttl_ms.

Here is the call graph for this function:

◆ request_close

void stream_cell::request_close ( const QString & name)
signal

Emitted when the user requests closing this stream cell.

Typically triggered by clicking the close button.

Parameters
nameStream cell name.

◆ request_focus

void stream_cell::request_focus ( const QString & name)
signal

Emitted when the user requests focusing/enlarging this cell.

Typically triggered by clicking the focus button.

Parameters
nameStream cell name.

◆ set_active()

void stream_cell::set_active ( bool val)

Set active (focused) state.

Deactivating a cell automatically disables drawing and clears draft.

Parameters
valNew active state.

Definition at line 50 of file stream_cell.cpp.

50 {
51 if (active == val) {
52 return;
53 }
54 active = val;
55 if (!active) {
58 }
60 update();
61}
void clear_draft()
Clear all draft data (points, hover point, preview flag).
void set_drawing_enabled(bool on)
Enable or disable interactive drawing on this cell.

References active, clear_draft(), set_drawing_enabled(), and update_icon().

Referenced by board::clear_active(), board::set_active_stream(), and board::take_active_cell().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_camera_id()

void stream_cell::set_camera_id ( const QByteArray & id)

Switch to camera input by device id.

Stops any previous player/camera, creates capture session if needed, finds a matching camera device by id, and starts capture.

Parameters
idCamera device id returned by Qt multimedia.

Definition at line 137 of file stream_cell.cpp.

137 {
138 camera_id = id;
139
140 last_error.clear();
141 last_frame = QImage();
142
143 if (player) {
144 player->stop();
145 }
146
147 if (camera) {
148 camera->stop();
149 camera->deleteLater();
150 camera = nullptr;
151 }
152
153 if (!session) {
154 session = new QMediaCaptureSession(this);
155 session->setVideoSink(sink);
156 }
157
158 QCameraDevice device;
159 const auto cams = QMediaDevices::videoInputs();
160 for (const auto& c : cams) {
161 if (c.id() == id) {
162 device = c;
163 break;
164 }
165 }
166
167 if (device.isNull()) {
168 last_error = tr("camera not found");
169 update();
170 return;
171 }
172
173 camera = new QCamera(device, this);
174 session->setCamera(camera);
175
176 connect(
177 camera, &QCamera::errorOccurred, this, &stream_cell::on_camera_error
178 );
179
180 camera->start();
181}
QByteArray camera_id
Selected camera id.
void on_camera_error(QCamera::Error error)
Slot called on camera errors.

◆ set_draft_params()

void stream_cell::set_draft_params ( const QString & name,
const QColor & color,
bool closed )

Set draft line parameters (name, color, closed flag).

Does not modify draft points.

Parameters
nameDraft line name.
colorDraft line color.
closedDraft line closed flag.

Definition at line 72 of file stream_cell.cpp.

74 {
76 draft_line_color = color;
77 draft_line_closed = closed;
78 update();
79}

References draft_line_closed.

◆ set_draft_points_pct()

void stream_cell::set_draft_points_pct ( const std::vector< QPointF > & pts)

Replace current draft points (percentage coordinates).

Parameters
ptsNew draft points.

Definition at line 81 of file stream_cell.cpp.

81 {
83 update();
84}

◆ set_draft_preview()

void stream_cell::set_draft_preview ( bool on)

Enable or disable draft preview mode.

Parameters
onTrue to enable preview.

Definition at line 110 of file stream_cell.cpp.

110 {
111 draft_preview = on;
112 update();
113}

References draft_preview.

◆ set_drawing_enabled()

void stream_cell::set_drawing_enabled ( bool on)

Enable or disable interactive drawing on this cell.

Enabling drawing also enables mouse tracking to receive hover updates.

Parameters
onTrue to enable drawing.

Definition at line 63 of file stream_cell.cpp.

63 {
64 drawing_enabled = on;
65 if (!on) {
66 hover_point_pct.reset();
67 }
68 setMouseTracking(drawing_enabled);
69 update();
70}

References drawing_enabled.

Referenced by controller::on_active_edit_mode_changed(), controller::on_active_stream_selected(), and set_active().

Here is the caller graph for this function:

◆ set_labels_enabled()

void stream_cell::set_labels_enabled ( bool on)

Enable or disable rendering of persistent line labels.

Labels are only shown when the cell is active.

Parameters
onTrue to enable labels.

Definition at line 115 of file stream_cell.cpp.

115 {
116 if (labels_enabled == on) {
117 return;
118 }
119 labels_enabled = on;
120 update();
121}

References labels_enabled.

Referenced by controller::on_active_labels_enabled_changed(), and controller::on_active_stream_selected().

Here is the caller graph for this function:

◆ set_loop()

void stream_cell::set_loop ( bool on)

Enable or disable looping for file-based playback.

Parameters
onTrue to loop on end-of-media.

Definition at line 135 of file stream_cell.cpp.

135{ loop_enabled = on; }

References loop_enabled.

Referenced by controller::handle_show_stream_changed().

Here is the caller graph for this function:

◆ set_persistent_lines()

void stream_cell::set_persistent_lines ( const std::vector< line_instance > & lines)

Replace all persistent lines.

Parameters
linesNew list of persistent line instances.

Definition at line 93 of file stream_cell.cpp.

95 {
96 persistent_lines = lines;
97 update();
98}

◆ set_repaint_interval_ms()

void stream_cell::set_repaint_interval_ms ( int ms)

Set minimum repaint interval for video frame updates.

Frames arriving faster than this interval will be coalesced.

Parameters
msInterval in milliseconds (> 0).

Definition at line 193 of file stream_cell.cpp.

193 {
194 if (ms <= 0) {
195 return;
196 }
198}

References repaint_interval_ms.

◆ set_source()

void stream_cell::set_source ( const QUrl & source)

Set media player source.

If a media player is available, switches it to source and starts playback.

Parameters
sourceURL of local file or network stream.

Definition at line 123 of file stream_cell.cpp.

123 {
124 if (!player) {
125 return;
126 }
127
128 last_error.clear();
129 last_frame = QImage();
130
131 player->setSource(source);
132 player->play();
133}

◆ to_pct()

QPointF stream_cell::to_pct ( const QPointF & pos_px) const
private

Convert pixel position to percentage coordinates.

Definition at line 653 of file stream_cell.cpp.

653 {
654 if (width() <= 0 || height() <= 0) {
655 return {};
656 }
657
658 float x
659 = static_cast<float>(pos_px.x()) / static_cast<float>(width()) * 100.0f;
660 float y = static_cast<float>(pos_px.y()) / static_cast<float>(height())
661 * 100.0f;
662
663 x = std::clamp(x, 0.f, 100.f);
664 y = std::clamp(y, 0.f, 100.f);
665
666 return { x, y };
667}

◆ to_px()

QPointF stream_cell::to_px ( const QPointF & pos_pct) const
private

Convert percentage coordinates to pixel position.

Definition at line 669 of file stream_cell.cpp.

669 {
670 return { pos_pct.x() / 100.0 * width(), pos_pct.y() / 100.0 * height() };
671}

◆ update_icon()

void stream_cell::update_icon ( )
private

Update focus button icon/tooltip based on active state.

Definition at line 400 of file stream_cell.cpp.

400 {
401 if (!focus_btn) {
402 return;
403 }
404 if (active) {
405 focus_btn->setToolTip(tr("shrink"));
406#if defined(KC_KDE)
407 focus_btn->setIcon(
409 { "view-restore", "window-restore", "transform-scale" },
410 QStyle::SP_TitleBarNormalButton
411 )
412 );
413#else
414 focus_btn->setIcon(
416 { "view-restore", "window-restore" },
417 QStyle::SP_TitleBarNormalButton
418 )
419 );
420#endif
421 } else {
422 focus_btn->setToolTip(tr("enlarge"));
423#if defined(KC_KDE)
424 focus_btn->setIcon(
426 { "view-fullscreen", "window-maximize", "transform-scale" },
427 QStyle::SP_TitleBarMaxButton
428 )
429 );
430#else
431 focus_btn->setIcon(
433 { "view-fullscreen", "fullscreen", "window-maximize" },
434 QStyle::SP_TitleBarMaxButton
435 )
436 );
437#endif
438 }
439}

References active, and focus_btn.

Referenced by build_ui(), and set_active().

Here is the caller graph for this function:

Member Data Documentation

◆ active

bool stream_cell::active { false }
private

Whether the cell is focused/active.

Definition at line 465 of file stream_cell.hpp.

465{ false };

Referenced by is_active(), keyPressEvent(), mouseMoveEvent(), mousePressEvent(), set_active(), and update_icon().

◆ camera

QCamera* stream_cell::camera { nullptr }
private

Active camera (if using live input).

Definition at line 500 of file stream_cell.hpp.

500{ nullptr };

◆ camera_id

QByteArray stream_cell::camera_id
private

Selected camera id.

Definition at line 504 of file stream_cell.hpp.

◆ close_btn

QPushButton* stream_cell::close_btn { nullptr }
private

UI close button (top-right).

Definition at line 458 of file stream_cell.hpp.

458{ nullptr };

Referenced by build_ui(), mousePressEvent(), and stream_cell().

◆ draft_line_closed

bool stream_cell::draft_line_closed { false }
private

Draft line closed flag.

Definition at line 479 of file stream_cell.hpp.

479{ false };

Referenced by draft_closed(), and set_draft_params().

◆ draft_line_color

QColor stream_cell::draft_line_color { Qt::red }
private

Draft line color.

Definition at line 477 of file stream_cell.hpp.

477{ Qt::red };

◆ draft_line_name

QString stream_cell::draft_line_name
private

Draft line name.

Definition at line 475 of file stream_cell.hpp.

◆ draft_line_points_pct

std::vector<QPointF> stream_cell::draft_line_points_pct
private

Draft polyline points in percentage coordinates.

Definition at line 481 of file stream_cell.hpp.

◆ draft_preview

bool stream_cell::draft_preview { false }
private

Whether draft line is shown in preview mode.

Definition at line 470 of file stream_cell.hpp.

470{ false };

Referenced by clear_draft(), is_draft_preview(), and set_draft_preview().

◆ drawing_enabled

bool stream_cell::drawing_enabled { false }
private

Whether interactive drawing is enabled.

Definition at line 468 of file stream_cell.hpp.

468{ false };

Referenced by keyPressEvent(), mouseMoveEvent(), mousePressEvent(), and set_drawing_enabled().

◆ events

QVector<event_instance> stream_cell::events
private

Transient events currently displayed.

Definition at line 507 of file stream_cell.hpp.

◆ focus_btn

QPushButton* stream_cell::focus_btn { nullptr }
private

UI focus/enlarge button (top-right).

Definition at line 460 of file stream_cell.hpp.

460{ nullptr };

Referenced by build_ui(), mousePressEvent(), stream_cell(), and update_icon().

◆ hover_point_pct

std::optional<QPointF> stream_cell::hover_point_pct
private

Current hover position in percentage coordinates.

Definition at line 483 of file stream_cell.hpp.

◆ labels_enabled

bool stream_cell::labels_enabled { true }
private

Whether persistent line labels are shown when active.

Definition at line 472 of file stream_cell.hpp.

472{ true };

Referenced by set_labels_enabled().

◆ last_error

QString stream_cell::last_error
private

Last error string to display when no frame is available.

Definition at line 497 of file stream_cell.hpp.

◆ last_frame

QImage stream_cell::last_frame
private

Most recent received frame as an image.

Definition at line 493 of file stream_cell.hpp.

◆ line_highlight_ttl_ms

int stream_cell::line_highlight_ttl_ms { 2500 }
private

Highlight time-to-live in ms.

Definition at line 522 of file stream_cell.hpp.

522{ 2500 };

Referenced by paintEvent().

◆ line_highlights

QHash<QString, QDateTime> stream_cell::line_highlights
private

Line highlight timestamps by line name.

Used to animate highlight effects for a fixed TTL.

Definition at line 519 of file stream_cell.hpp.

◆ line_hits

QHash<QString, hit_info> stream_cell::line_hits
private

Optional hit positions per line name.

Definition at line 537 of file stream_cell.hpp.

◆ loop_enabled

bool stream_cell::loop_enabled { true }
private

Whether playback looping is enabled.

Definition at line 495 of file stream_cell.hpp.

495{ true };

Referenced by on_media_status_changed(), and set_loop().

◆ name

QString stream_cell::name
private

Logical stream name.

Definition at line 455 of file stream_cell.hpp.

◆ name_label

QLabel* stream_cell::name_label { nullptr }
private

Optional name label (unused in current implementation).

Definition at line 462 of file stream_cell.hpp.

462{ nullptr };

Referenced by stream_cell().

◆ persistent_lines

std::vector<line_instance> stream_cell::persistent_lines
private

Persisted lines to render.

Definition at line 486 of file stream_cell.hpp.

◆ player

QMediaPlayer* stream_cell::player { nullptr }
private

Media player for file/URL sources.

Definition at line 489 of file stream_cell.hpp.

489{ nullptr };

◆ repaint_interval_ms

int stream_cell::repaint_interval_ms { 66 }
private

Minimum repaint interval in ms.

Definition at line 512 of file stream_cell.hpp.

512{ 66 };

Referenced by set_repaint_interval_ms().

◆ repaint_timer

QElapsedTimer stream_cell::repaint_timer
private

Timer throttling repaint frequency.

Definition at line 510 of file stream_cell.hpp.

◆ session

QMediaCaptureSession* stream_cell::session { nullptr }
private

Capture session binding camera to sink.

Definition at line 502 of file stream_cell.hpp.

502{ nullptr };

◆ sink

QVideoSink* stream_cell::sink { nullptr }
private

Video sink feeding decoded frames into the widget.

Definition at line 491 of file stream_cell.hpp.

491{ nullptr };

The documentation for this class was generated from the following files: