File indexing completed on 2025-02-02 04:11:34

0001 /*
0002  * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best>
0003  *
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  */
0006 
0007 #include "timeline_treeview.hpp"
0008 
0009 #include <QMouseEvent>
0010 #include <QPainter>
0011 
0012 #include "item_models/property_model_full.hpp"
0013 #include "item_models/comp_filter_model.hpp"
0014 
0015 class glaxnimate::gui::TimelineTreeview::Private
0016 {
0017 public:
0018     QModelIndex source_index(const QModelIndex& index)
0019     {
0020         return proxy_model()->mapToSource(index);
0021     }
0022 
0023     item_models::CompFilterModel* proxy_model()
0024     {
0025         return static_cast<item_models::CompFilterModel*>(parent->model());
0026     }
0027 
0028     item_models::PropertyModelFull* source_model()
0029     {
0030         return static_cast<item_models::PropertyModelFull*>(proxy_model()->sourceModel());
0031     }
0032 
0033     model::Layer* layer(const QModelIndex& source_index)
0034     {
0035         return qobject_cast<model::Layer*>(source_model()->node(source_index));
0036     }
0037 
0038     void on_drag()
0039     {
0040         auto index = parent->indexAt(drag_to_local);
0041         auto source_index = this->source_index(index);
0042 
0043         auto layer = this->layer(source_index);
0044 
0045         if ( layer && drag_from_layer->is_valid_parent(layer) )
0046         {
0047             drag_to_layer = layer;
0048             drag_to_index = index;
0049         }
0050         else
0051         {
0052             drag_to_layer = nullptr;
0053             drag_to_index = {};
0054         }
0055 
0056         parent->viewport()->update();
0057     }
0058 
0059     QPoint relpoint()
0060     {
0061         return parent->visualRect(parent->model()->index(0, 0)).topLeft();
0062     }
0063 
0064     TimelineTreeview* parent;
0065     QPoint drag_from;
0066     QPoint drag_to;
0067     QPoint drag_to_local;
0068     QModelIndex drag_from_index;
0069     QModelIndex drag_to_index;
0070     model::Layer* drag_from_layer = nullptr;
0071     model::Layer* drag_to_layer = nullptr;
0072     bool dragging = false;
0073 };
0074 
0075 glaxnimate::gui::TimelineTreeview::TimelineTreeview(QWidget* parent)
0076     : QTreeView(parent), d(std::make_unique<Private>())
0077 {
0078     d->parent = this;
0079 }
0080 
0081 glaxnimate::gui::TimelineTreeview::~TimelineTreeview() = default;
0082 
0083 void glaxnimate::gui::TimelineTreeview::mousePressEvent(QMouseEvent* event)
0084 {
0085     if ( event->button() == Qt::LeftButton )
0086     {
0087         auto index = indexAt(event->pos());
0088         auto source_index = d->source_index(index);
0089 
0090         if ( source_index.column() == item_models::PropertyModelFull::ColumnValue )
0091         {
0092             auto layer = d->layer(source_index);
0093             if ( layer && !layer->docnode_locked_recursive()  )
0094             {
0095                 d->drag_from_layer = layer;
0096                 d->drag_from = d->drag_to = event->pos() - d->relpoint();
0097                 d->drag_to_local = event->pos();
0098                 d->drag_from_index = index;
0099                 d->drag_to_layer = nullptr;
0100                 d->drag_to_layer = nullptr;
0101                 d->drag_to_index = {};
0102                 d->dragging = true;
0103 
0104                 event->accept();
0105                 viewport()->update();
0106                 return;
0107             }
0108         }
0109     }
0110 
0111     QTreeView::mousePressEvent(event);
0112 }
0113 
0114 void glaxnimate::gui::TimelineTreeview::mouseMoveEvent(QMouseEvent* event)
0115 {
0116     if ( d->dragging )
0117     {
0118         d->drag_to = event->pos() - d->relpoint();
0119         d->drag_to_local = event->pos();
0120         d->on_drag();
0121     }
0122     else
0123     {
0124         QTreeView::mouseMoveEvent(event);
0125     }
0126 }
0127 
0128 void glaxnimate::gui::TimelineTreeview::mouseReleaseEvent(QMouseEvent* event)
0129 {
0130     if ( d->dragging && event->button() == Qt::LeftButton )
0131     {
0132         d->dragging = false;
0133 
0134         // if moved less than 3 pixels, treat as a click
0135         if ( math::length_squared<QPointF>(d->drag_to - d->drag_from) < 9 )
0136         {
0137             QTreeView::mousePressEvent(event);
0138             QTreeView::mouseReleaseEvent(event);
0139         }
0140         else
0141         {
0142             d->drag_from_layer->parent.set_undoable(QVariant::fromValue(d->drag_to_layer));
0143         }
0144 
0145         d->drag_from_layer = d->drag_to_layer = nullptr;
0146         d->drag_from_index = d->drag_to_index = {};
0147         viewport()->update();
0148     }
0149     else
0150     {
0151         QTreeView::mouseReleaseEvent(event);
0152     }
0153 }
0154 
0155 void glaxnimate::gui::TimelineTreeview::paintEvent(QPaintEvent* event)
0156 {
0157     QTreeView::paintEvent(event);
0158 
0159     if ( d->dragging )
0160     {
0161         QPainter painter(viewport());
0162         painter.setRenderHint(QPainter::Antialiasing);
0163 
0164         if ( d->drag_to_index.isValid() )
0165         {
0166             painter.setPen(QPen(palette().text(), 2));
0167 
0168             auto rect = visualRect(d->drag_to_index);
0169             rect.setX(0);
0170             rect.setWidth(width());
0171             painter.drawRect(rect);
0172         }
0173 
0174         painter.setPen(QPen(palette().highlight(), 2));
0175         QPoint off = d->relpoint();
0176         painter.drawLine(
0177             d->drag_from + off,
0178             d->drag_to + off
0179         );
0180     }
0181 }
0182 
0183 void glaxnimate::gui::TimelineTreeview::scrollContentsBy(int dx, int dy)
0184 {
0185     QTreeView::scrollContentsBy(dx, dy);
0186 
0187     if ( d->dragging )
0188     {
0189         d->drag_to = d->drag_to_local - d->relpoint();
0190         d->on_drag();
0191     }
0192 }