You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							148 lines
						
					
					
						
							4.8 KiB
						
					
					
				
			
		
		
	
	
							148 lines
						
					
					
						
							4.8 KiB
						
					
					
				#include "tools/cabana/videowidget.h"
 | 
						|
 | 
						|
#include <QButtonGroup>
 | 
						|
#include <QDateTime>
 | 
						|
#include <QHBoxLayout>
 | 
						|
#include <QMouseEvent>
 | 
						|
#include <QPainter>
 | 
						|
#include <QStyleOptionSlider>
 | 
						|
#include <QTimer>
 | 
						|
#include <QVBoxLayout>
 | 
						|
 | 
						|
inline QString formatTime(int seconds) {
 | 
						|
  return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh:mm:ss" : "mm:ss");
 | 
						|
}
 | 
						|
 | 
						|
VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) {
 | 
						|
  QVBoxLayout *main_layout = new QVBoxLayout(this);
 | 
						|
  main_layout->setContentsMargins(0, 0, 0, 0);
 | 
						|
 | 
						|
  cam_widget = new CameraWidget("camerad", VISION_STREAM_ROAD, false, this);
 | 
						|
  cam_widget->setFixedSize(parent->width(), parent->width() / 1.596);
 | 
						|
  main_layout->addWidget(cam_widget);
 | 
						|
 | 
						|
  // slider controls
 | 
						|
  QHBoxLayout *slider_layout = new QHBoxLayout();
 | 
						|
  QLabel *time_label = new QLabel("00:00");
 | 
						|
  slider_layout->addWidget(time_label);
 | 
						|
 | 
						|
  slider = new Slider(this);
 | 
						|
  slider->setSingleStep(0);
 | 
						|
  slider_layout->addWidget(slider);
 | 
						|
 | 
						|
  end_time_label = new QLabel(this);
 | 
						|
  slider_layout->addWidget(end_time_label);
 | 
						|
  main_layout->addLayout(slider_layout);
 | 
						|
 | 
						|
  // btn controls
 | 
						|
  QHBoxLayout *control_layout = new QHBoxLayout();
 | 
						|
  play_btn = new QPushButton("⏸");
 | 
						|
  play_btn->setStyleSheet("font-weight:bold; height:16px");
 | 
						|
  control_layout->addWidget(play_btn);
 | 
						|
 | 
						|
  QButtonGroup *group = new QButtonGroup(this);
 | 
						|
  group->setExclusive(true);
 | 
						|
  for (float speed : {0.1, 0.5, 1., 2.}) {
 | 
						|
    QPushButton *btn = new QPushButton(QString("%1x").arg(speed), this);
 | 
						|
    btn->setCheckable(true);
 | 
						|
    QObject::connect(btn, &QPushButton::clicked, [=]() { can->setSpeed(speed); });
 | 
						|
    control_layout->addWidget(btn);
 | 
						|
    group->addButton(btn);
 | 
						|
    if (speed == 1.0) btn->setChecked(true);
 | 
						|
  }
 | 
						|
  main_layout->addLayout(control_layout);
 | 
						|
 | 
						|
  setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
 | 
						|
 | 
						|
  QObject::connect(can, &CANMessages::updated, this, &VideoWidget::updateState);
 | 
						|
  QObject::connect(slider, &QSlider::sliderReleased, [this]() { can->seekTo(slider->value() / 1000.0); });
 | 
						|
  QObject::connect(slider, &QSlider::valueChanged, [=](int value) { time_label->setText(formatTime(value / 1000)); });
 | 
						|
  QObject::connect(cam_widget, &CameraWidget::clicked, [this]() { pause(!can->isPaused()); });
 | 
						|
  QObject::connect(play_btn, &QPushButton::clicked, [=]() { pause(!can->isPaused()); });
 | 
						|
  QObject::connect(can, &CANMessages::streamStarted, [this]() {
 | 
						|
    end_time_label->setText(formatTime(can->totalSeconds()));
 | 
						|
    slider->setRange(0, can->totalSeconds() * 1000);
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
void VideoWidget::pause(bool pause) {
 | 
						|
  play_btn->setText(!pause ? "⏸" : "▶");
 | 
						|
  can->pause(pause);
 | 
						|
}
 | 
						|
 | 
						|
void VideoWidget::rangeChanged(double min, double max, bool is_zoomed) {
 | 
						|
  if (!is_zoomed) {
 | 
						|
    min = 0;
 | 
						|
    max = can->totalSeconds();
 | 
						|
  }
 | 
						|
  end_time_label->setText(formatTime(max));
 | 
						|
  slider->setRange(min * 1000, max * 1000);
 | 
						|
}
 | 
						|
 | 
						|
void VideoWidget::updateState() {
 | 
						|
  if (!slider->isSliderDown())
 | 
						|
    slider->setValue(can->currentSec() * 1000);
 | 
						|
}
 | 
						|
 | 
						|
// Slider
 | 
						|
Slider::Slider(QWidget *parent) : QSlider(Qt::Horizontal, parent) {
 | 
						|
  QTimer *timer = new QTimer(this);
 | 
						|
  timer->setInterval(2000);
 | 
						|
  timer->callOnTimeout([this]() {
 | 
						|
    timeline = can->getTimeline();
 | 
						|
    update();
 | 
						|
  });
 | 
						|
  QObject::connect(can, SIGNAL(streamStarted()), timer, SLOT(start()));
 | 
						|
}
 | 
						|
 | 
						|
void Slider::sliderChange(QAbstractSlider::SliderChange change) {
 | 
						|
  if (change == QAbstractSlider::SliderValueChange) {
 | 
						|
    int x = width() * ((value() - minimum()) / double(maximum() - minimum()));
 | 
						|
    if (x != slider_x) {
 | 
						|
      slider_x = x;
 | 
						|
      update();
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    QAbstractSlider::sliderChange(change);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void Slider::paintEvent(QPaintEvent *ev) {
 | 
						|
  static const QColor colors[] = {
 | 
						|
    [(int)TimelineType::None] = QColor(111, 143, 175),
 | 
						|
    [(int)TimelineType::Engaged] = QColor(0, 163, 108),
 | 
						|
    [(int)TimelineType::UserFlag] = Qt::white,
 | 
						|
    [(int)TimelineType::AlertInfo] = Qt::green,
 | 
						|
    [(int)TimelineType::AlertWarning] = QColor(255, 195, 0),
 | 
						|
    [(int)TimelineType::AlertCritical] = QColor(199, 0, 57)};
 | 
						|
 | 
						|
  QPainter p(this);
 | 
						|
  QRect r = rect().adjusted(0, 4, 0, -4);
 | 
						|
  p.fillRect(r, colors[(int)TimelineType::None]);
 | 
						|
  double min = minimum() / 1000.0;
 | 
						|
  double max = maximum() / 1000.0;
 | 
						|
  for (auto [begin, end, type] : timeline) {
 | 
						|
    if (begin > max || end < min)
 | 
						|
      continue;
 | 
						|
    r.setLeft(((std::max(min, (double)begin) - min) / (max - min)) * width());
 | 
						|
    r.setRight(((std::min(max, (double)end) - min) / (max - min)) * width());
 | 
						|
    p.fillRect(r, colors[(int)type]);
 | 
						|
  }
 | 
						|
 | 
						|
  QStyleOptionSlider opt;
 | 
						|
  opt.initFrom(this);
 | 
						|
  opt.minimum = minimum();
 | 
						|
  opt.maximum = maximum();
 | 
						|
  opt.subControls = QStyle::SC_SliderHandle;
 | 
						|
  opt.sliderPosition = value();
 | 
						|
  style()->drawComplexControl(QStyle::CC_Slider, &opt, &p);
 | 
						|
}
 | 
						|
 | 
						|
void Slider::mousePressEvent(QMouseEvent *e) {
 | 
						|
  QSlider::mousePressEvent(e);
 | 
						|
  if (e->button() == Qt::LeftButton && !isSliderDown()) {
 | 
						|
    int value = minimum() + ((maximum() - minimum()) * e->x()) / width();
 | 
						|
    setValue(value);
 | 
						|
    emit sliderReleased();
 | 
						|
  }
 | 
						|
}
 | 
						|
 |