109 lines
3.1 KiB
C++
109 lines
3.1 KiB
C++
|
|
#include "video_grid_widget.h"
|
||
|
|
#include <QFrame>
|
||
|
|
#include <cmath>
|
||
|
|
|
||
|
|
namespace scar {
|
||
|
|
|
||
|
|
VideoGridWidget::VideoGridWidget(QWidget* parent)
|
||
|
|
: QWidget(parent) {
|
||
|
|
|
||
|
|
gridLayout_ = new QGridLayout(this);
|
||
|
|
gridLayout_->setSpacing(5);
|
||
|
|
gridLayout_->setContentsMargins(5, 5, 5, 5);
|
||
|
|
|
||
|
|
// Placeholder when no streams
|
||
|
|
placeholderLabel_ = new QLabel("No active video streams", this);
|
||
|
|
placeholderLabel_->setAlignment(Qt::AlignCenter);
|
||
|
|
placeholderLabel_->setStyleSheet("color: #888; font-size: 16px;");
|
||
|
|
gridLayout_->addWidget(placeholderLabel_, 0, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
void VideoGridWidget::addStream(const QString& streamId, const QString& username) {
|
||
|
|
if (streams_.size() >= MAX_STREAMS) {
|
||
|
|
return; // Max streams reached
|
||
|
|
}
|
||
|
|
|
||
|
|
// Remove placeholder if this is first stream
|
||
|
|
if (streams_.empty()) {
|
||
|
|
placeholderLabel_->hide();
|
||
|
|
}
|
||
|
|
|
||
|
|
VideoStream stream;
|
||
|
|
stream.streamId = streamId;
|
||
|
|
stream.username = username;
|
||
|
|
|
||
|
|
// Create video label
|
||
|
|
stream.videoLabel = new QLabel(this);
|
||
|
|
stream.videoLabel->setMinimumSize(160, 120);
|
||
|
|
stream.videoLabel->setStyleSheet("QLabel { background-color: #2C2F33; border: 1px solid #23272A; }");
|
||
|
|
stream.videoLabel->setScaledContents(true);
|
||
|
|
stream.videoLabel->setAlignment(Qt::AlignCenter);
|
||
|
|
stream.videoLabel->setText(username + "\n(No video)");
|
||
|
|
stream.videoLabel->setToolTip(username);
|
||
|
|
|
||
|
|
streams_.push_back(stream);
|
||
|
|
updateGridLayout();
|
||
|
|
}
|
||
|
|
|
||
|
|
void VideoGridWidget::removeStream(const QString& streamId) {
|
||
|
|
for (auto it = streams_.begin(); it != streams_.end(); ++it) {
|
||
|
|
if (it->streamId == streamId) {
|
||
|
|
delete it->videoLabel;
|
||
|
|
streams_.erase(it);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (streams_.empty()) {
|
||
|
|
placeholderLabel_->show();
|
||
|
|
} else {
|
||
|
|
updateGridLayout();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void VideoGridWidget::updateFrame(const QString& streamId, const QPixmap& frame) {
|
||
|
|
for (auto& stream : streams_) {
|
||
|
|
if (stream.streamId == streamId) {
|
||
|
|
stream.videoLabel->setPixmap(frame);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void VideoGridWidget::clear() {
|
||
|
|
for (auto& stream : streams_) {
|
||
|
|
delete stream.videoLabel;
|
||
|
|
}
|
||
|
|
streams_.clear();
|
||
|
|
placeholderLabel_->show();
|
||
|
|
}
|
||
|
|
|
||
|
|
void VideoGridWidget::updateGridLayout() {
|
||
|
|
// Remove all widgets from layout
|
||
|
|
for (auto& stream : streams_) {
|
||
|
|
gridLayout_->removeWidget(stream.videoLabel);
|
||
|
|
}
|
||
|
|
|
||
|
|
int columns = calculateColumns(streams_.size());
|
||
|
|
int rows = std::ceil(static_cast<double>(streams_.size()) / columns);
|
||
|
|
|
||
|
|
// Re-add widgets in grid
|
||
|
|
for (size_t i = 0; i < streams_.size(); ++i) {
|
||
|
|
int row = i / columns;
|
||
|
|
int col = i % columns;
|
||
|
|
gridLayout_->addWidget(streams_[i].videoLabel, row, col);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int VideoGridWidget::calculateColumns(int streamCount) {
|
||
|
|
if (streamCount <= 1) return 1;
|
||
|
|
if (streamCount <= 4) return 2;
|
||
|
|
if (streamCount <= 9) return 3;
|
||
|
|
if (streamCount <= 16) return 4;
|
||
|
|
if (streamCount <= 25) return 5;
|
||
|
|
if (streamCount <= 36) return 6;
|
||
|
|
return std::ceil(std::sqrt(streamCount));
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace scar
|