openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
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

#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();
}
}