mirror of
https://github.com/dragonpilot/dragonpilot.git
synced 2026-03-01 16:43:52 +08:00
cabana: drag&drop to change chart order (#27832)
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
#include <QtConcurrent>
|
||||
|
||||
const int MAX_COLUMN_COUNT = 4;
|
||||
const QString mime_type = "application/x-cabanachartview";
|
||||
static inline bool xLessThan(const QPointF &p, float x) { return p.x() < x; }
|
||||
|
||||
// ChartsWidget
|
||||
@@ -75,14 +76,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : align_timer(this), auto_scroll_tim
|
||||
main_layout->addWidget(toolbar);
|
||||
|
||||
// charts
|
||||
charts_layout = new QGridLayout();
|
||||
charts_layout->setSpacing(10);
|
||||
|
||||
charts_container = new QWidget(this);
|
||||
QVBoxLayout *charts_main_layout = new QVBoxLayout(charts_container);
|
||||
charts_main_layout->setContentsMargins(0, 0, 0, 0);
|
||||
charts_main_layout->addLayout(charts_layout);
|
||||
charts_main_layout->addStretch(0);
|
||||
charts_container = new ChartsContainer(this);
|
||||
|
||||
charts_scroll = new QScrollArea(this);
|
||||
charts_scroll->setFrameStyle(QFrame::NoFrame);
|
||||
@@ -227,7 +221,7 @@ ChartView *ChartsWidget::createChart() {
|
||||
QObject::connect(chart, &ChartView::seriesAdded, this, &ChartsWidget::seriesChanged);
|
||||
QObject::connect(chart, &ChartView::axisYLabelWidthChanged, &align_timer, qOverload<>(&QTimer::start));
|
||||
QObject::connect(chart, &ChartView::hovered, this, &ChartsWidget::showValueTip);
|
||||
charts.push_back(chart);
|
||||
charts.push_front(chart);
|
||||
updateLayout();
|
||||
updateToolBar();
|
||||
return chart;
|
||||
@@ -236,7 +230,7 @@ ChartView *ChartsWidget::createChart() {
|
||||
void ChartsWidget::showChart(const MessageId &id, const cabana::Signal *sig, bool show, bool merge) {
|
||||
ChartView *chart = findChart(id, sig);
|
||||
if (show && !chart) {
|
||||
chart = merge && charts.size() > 0 ? charts.back() : createChart();
|
||||
chart = merge && charts.size() > 0 ? charts.front() : createChart();
|
||||
chart->addSeries(id, sig);
|
||||
} else if (!show && chart) {
|
||||
chart->removeIf([&](auto &s) { return s.msg_id == id && s.sig == sig; });
|
||||
@@ -252,7 +246,8 @@ void ChartsWidget::setColumnCount(int n) {
|
||||
}
|
||||
}
|
||||
|
||||
void ChartsWidget::updateLayout() {
|
||||
void ChartsWidget::updateLayout(bool force) {
|
||||
auto charts_layout = charts_container->charts_layout;
|
||||
int n = MAX_COLUMN_COUNT;
|
||||
for (; n > 1; --n) {
|
||||
if ((n * CHART_MIN_WIDTH + (n - 1) * charts_layout->spacing()) < charts_layout->geometry().width()) break;
|
||||
@@ -262,13 +257,13 @@ void ChartsWidget::updateLayout() {
|
||||
columns_action->setVisible(show_column_cb);
|
||||
|
||||
n = std::min(column_count, n);
|
||||
if (charts.size() != charts_layout->count() || n != current_column_count) {
|
||||
if ((charts.size() != charts_layout->count() || n != current_column_count) || force) {
|
||||
current_column_count = n;
|
||||
charts_layout->parentWidget()->setUpdatesEnabled(false);
|
||||
charts_container->setUpdatesEnabled(false);
|
||||
for (int i = 0; i < charts.size(); ++i) {
|
||||
charts_layout->addWidget(charts[charts.size() - i - 1], i / n, i % n);
|
||||
charts_layout->addWidget(charts[i], i / n, i % n);
|
||||
}
|
||||
QTimer::singleShot(0, [this]() { charts_layout->parentWidget()->setUpdatesEnabled(true); });
|
||||
QTimer::singleShot(0, [this]() { charts_container->setUpdatesEnabled(true); });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,6 +294,13 @@ void ChartsWidget::doAutoScroll() {
|
||||
bool vertical_unchanged = value == scroll->value();
|
||||
if (vertical_unchanged) {
|
||||
stopAutoScroll();
|
||||
} else {
|
||||
// mouseMoveEvent to updates the drag-selection rectangle
|
||||
const QPoint globalPos = charts_scroll->viewport()->mapToGlobal(pos);
|
||||
const QPoint windowPos = charts_scroll->window()->mapFromGlobal(globalPos);
|
||||
QMouseEvent mm(QEvent::MouseMove, pos, windowPos, globalPos,
|
||||
Qt::NoButton, Qt::LeftButton, Qt::NoModifier, Qt::MouseEventSynthesizedByQt);
|
||||
QApplication::sendEvent(charts_scroll->viewport(), &mm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,7 +425,7 @@ ChartView::ChartView(const std::pair<double, double> &x_range, ChartsWidget *par
|
||||
|
||||
void ChartView::createToolButtons() {
|
||||
move_icon = new QGraphicsPixmapItem(utils::icon("grip-horizontal"), chart());
|
||||
move_icon->setToolTip(tr("Drag and drop to combine charts"));
|
||||
move_icon->setToolTip(tr("Drag and drop to move chart"));
|
||||
|
||||
QToolButton *remove_btn = toolButton("x", tr("Remove Chart"));
|
||||
close_btn_proxy = new QGraphicsProxyWidget(chart());
|
||||
@@ -864,32 +866,23 @@ void ChartView::hideTip() {
|
||||
}
|
||||
|
||||
void ChartView::dragEnterEvent(QDragEnterEvent *event) {
|
||||
can_drop = event->source() != this;
|
||||
viewport()->update();
|
||||
QChartView::dragEnterEvent(event);
|
||||
}
|
||||
void ChartView::dragLeaveEvent(QDragLeaveEvent *event) {
|
||||
can_drop = false;
|
||||
viewport()->update();
|
||||
QChartView::dragLeaveEvent(event);
|
||||
if (event->mimeData()->hasFormat(mime_type)) {
|
||||
drawDropIndicator(event->source() != this);
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
}
|
||||
|
||||
void ChartView::dragMoveEvent(QDragMoveEvent *event) {
|
||||
if (event->mimeData()->hasFormat(mime_type)) {
|
||||
event->setDropAction(event->source() == this ? Qt::MoveAction : Qt::CopyAction);
|
||||
event->accept();
|
||||
} else {
|
||||
event->ignore();
|
||||
}
|
||||
charts_widget->startAutoScroll();
|
||||
}
|
||||
|
||||
void ChartView::dropEvent(QDropEvent *event) {
|
||||
if (event->mimeData()->hasFormat(mime_type)) {
|
||||
if (event->source() == this) {
|
||||
event->setDropAction(Qt::MoveAction);
|
||||
event->accept();
|
||||
} else {
|
||||
if (event->source() != this) {
|
||||
ChartView *source_chart = (ChartView *)event->source();
|
||||
for (auto &s : source_chart->sigs) {
|
||||
source_chart->chart()->removeSeries(s.series);
|
||||
@@ -906,8 +899,6 @@ void ChartView::dropEvent(QDropEvent *event) {
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
can_drop = false;
|
||||
} else {
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1199,3 +1190,55 @@ void ValueTipLabel::paintEvent(QPaintEvent *ev) {
|
||||
p.end();
|
||||
QLabel::paintEvent(ev);
|
||||
}
|
||||
|
||||
// ChartsContainer
|
||||
|
||||
ChartsContainer::ChartsContainer(ChartsWidget *parent) : charts_widget(parent), QWidget(parent) {
|
||||
setAcceptDrops(true);
|
||||
QVBoxLayout *charts_main_layout = new QVBoxLayout(this);
|
||||
charts_main_layout->setContentsMargins(0, 0, 0, 0);
|
||||
charts_layout = new QGridLayout();
|
||||
charts_layout->setSpacing(10);
|
||||
charts_main_layout->addLayout(charts_layout);
|
||||
charts_main_layout->addStretch(0);
|
||||
}
|
||||
|
||||
void ChartsContainer::dragEnterEvent(QDragEnterEvent *event) {
|
||||
if (event->mimeData()->hasFormat(mime_type)) {
|
||||
event->acceptProposedAction();
|
||||
drawDropIndicator(event->pos());
|
||||
}
|
||||
}
|
||||
|
||||
void ChartsContainer::dropEvent(QDropEvent *event) {
|
||||
if (event->mimeData()->hasFormat(mime_type)) {
|
||||
auto w = getDropBefore(event->pos());
|
||||
auto chart = qobject_cast<ChartView *>(event->source());
|
||||
if (w != chart) {
|
||||
charts_widget->charts.removeOne(chart);
|
||||
int to = w ? charts_widget->charts.indexOf(w) : charts_widget->charts.size();
|
||||
charts_widget->charts.insert(to, chart);
|
||||
charts_widget->updateLayout(true);
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
drawDropIndicator({});
|
||||
}
|
||||
}
|
||||
|
||||
void ChartsContainer::paintEvent(QPaintEvent *ev) {
|
||||
if (!drop_indictor_pos.isNull() && !childAt(drop_indictor_pos)) {
|
||||
if (auto insert_after = getDropBefore(drop_indictor_pos)) {
|
||||
auto area = insert_after->geometry();
|
||||
QRect r = QRect(area.left(), area.top() - 10, area.width(), 10);
|
||||
QPainter(this).fillRect(r, qApp->palette().highlight());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ChartView *ChartsContainer::getDropBefore(const QPoint &pos) const {
|
||||
auto it = std::find_if(charts_widget->charts.cbegin(), charts_widget->charts.cend(), [&pos](auto c) {
|
||||
auto area = c->geometry();
|
||||
return pos.x() >= area.left() && pos.x() <= area.right() && pos.y() < area.top();
|
||||
});
|
||||
return it == charts_widget->charts.cend() ? nullptr : *it;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ private:
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *ev) override;
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void dragLeaveEvent(QDragLeaveEvent *event) override;
|
||||
void dragLeaveEvent(QDragLeaveEvent *event) override { drawDropIndicator(false); }
|
||||
void dragMoveEvent(QDragMoveEvent *event) override;
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
@@ -96,6 +96,7 @@ private:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void drawForeground(QPainter *painter, const QRectF &rect) override;
|
||||
void drawBackground(QPainter *painter, const QRectF &rect) override;
|
||||
void drawDropIndicator(bool draw) { can_drop = draw; viewport()->update(); }
|
||||
std::tuple<double, double, int> getNiceAxisNumbers(qreal min, qreal max, int tick_count);
|
||||
qreal niceNumber(qreal x, bool ceiling);
|
||||
QXYSeries *createSeries(SeriesType type, QColor color);
|
||||
@@ -113,7 +114,6 @@ private:
|
||||
ValueTipLabel tip_label;
|
||||
QList<SigItem> sigs;
|
||||
double cur_sec = 0;
|
||||
const QString mime_type = "application/x-cabanachartview";
|
||||
SeriesType series_type = SeriesType::Line;
|
||||
bool is_scrubbing = false;
|
||||
bool resume_after_scrub = false;
|
||||
@@ -122,7 +122,22 @@ private:
|
||||
double tooltip_x = -1;
|
||||
ChartsWidget *charts_widget;
|
||||
friend class ChartsWidget;
|
||||
};
|
||||
};
|
||||
|
||||
class ChartsContainer : public QWidget {
|
||||
public:
|
||||
ChartsContainer(ChartsWidget *parent);
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
void dragLeaveEvent(QDragLeaveEvent *event) override { drawDropIndicator({}); }
|
||||
void drawDropIndicator(const QPoint &pt) { drop_indictor_pos = pt; update(); }
|
||||
void paintEvent(QPaintEvent *ev) override;
|
||||
ChartView *getDropBefore(const QPoint &pos) const;
|
||||
|
||||
QGridLayout *charts_layout;
|
||||
ChartsWidget *charts_widget;
|
||||
QPoint drop_indictor_pos;
|
||||
};
|
||||
|
||||
class ChartsWidget : public QFrame {
|
||||
Q_OBJECT
|
||||
@@ -158,7 +173,7 @@ private:
|
||||
void doAutoScroll();
|
||||
void updateToolBar();
|
||||
void setMaxChartRange(int value);
|
||||
void updateLayout();
|
||||
void updateLayout(bool force = false);
|
||||
void settingChanged();
|
||||
void showValueTip(double sec);
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
@@ -178,9 +193,8 @@ private:
|
||||
QUndoStack *zoom_undo_stack;
|
||||
|
||||
QAction *remove_all_btn;
|
||||
QGridLayout *charts_layout;
|
||||
QList<ChartView *> charts;
|
||||
QWidget *charts_container;
|
||||
ChartsContainer *charts_container;
|
||||
QScrollArea *charts_scroll;
|
||||
uint32_t max_chart_range = 0;
|
||||
bool is_zoomed = false;
|
||||
@@ -194,6 +208,7 @@ private:
|
||||
QTimer align_timer;
|
||||
friend class ZoomCommand;
|
||||
friend class ChartView;
|
||||
friend class ChartsContainer;
|
||||
};
|
||||
|
||||
class ZoomCommand : public QUndoCommand {
|
||||
|
||||
Reference in New Issue
Block a user