]> git.sesse.net Git - kdenlive/blobdiff - src/abstractgroupitem.cpp
const modifiers are useless on integral return types [PATCH by Ray Lehtiniemi]
[kdenlive] / src / abstractgroupitem.cpp
index 268bb930654776b8ab3abd17f03b507e4d1eac99..136745daeea515cda61586bd34719d2a3d7bf0c3 100644 (file)
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
  ***************************************************************************/
 
-#include <QGraphicsScene>
-#include <QGraphicsView>
-#include <QScrollBar>
-#include <QToolTip>
-
-#include <KDebug>
-#include <KLocale>
-
 #include "abstractgroupitem.h"
 #include "abstractclipitem.h"
 #include "kdenlivesettings.h"
 #include "customtrackscene.h"
 
+#include <KDebug>
+
+#include <QPainter>
+#include <QStyleOptionGraphicsItem>
+
+
 AbstractGroupItem::AbstractGroupItem(double fps): QGraphicsItemGroup(), m_fps(fps) {
+    setZValue(2);
     setFlags(QGraphicsItem::ItemClipsToShape | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
 }
 
@@ -39,22 +38,25 @@ int AbstractGroupItem::type() const {
     return GROUPWIDGET;
 }
 
+int AbstractGroupItem::track() const {
+    return (int)(scenePos().y() / KdenliveSettings::trackheight());
+}
+
 CustomTrackScene* AbstractGroupItem::projectScene() {
     if (scene()) return static_cast <CustomTrackScene*>(scene());
     return NULL;
 }
 
-
-QPolygonF AbstractGroupItem::groupShape(QPointF offset) {
+QPainterPath AbstractGroupItem::groupShape(QPointF offset) {
+    QPainterPath path;
     QList<QGraphicsItem *> children = childItems();
-    QPolygonF path;
     for (int i = 0; i < children.count(); i++) {
         if (children.at(i)->type() == AVWIDGET) {
-            QPolygonF r = QPolygonF(children.at(i)->sceneBoundingRect());
-            path = path.united(r);
+            QRectF r(children.at(i)->sceneBoundingRect());
+            r.translate(offset);
+            path.addRect(r);
         }
     }
-    path.translate(offset);
     return path;
 }
 
@@ -72,96 +74,104 @@ void AbstractGroupItem::fixItemRect() {
 }
 
 // virtual
-void AbstractGroupItem::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) {
-    p->fillRect(boundingRect(), QColor(200, 100, 100, 100));
+void AbstractGroupItem::paint(QPainter *p, const QStyleOptionGraphicsItem *option, QWidget *) {
+    p->fillRect(option->exposedRect, QColor(200, 100, 100, 100));
 }
 
 //virtual
 QVariant AbstractGroupItem::itemChange(GraphicsItemChange change, const QVariant &value) {
     if (change == ItemPositionChange && scene()) {
         // calculate new position.
+        const int trackHeight = KdenliveSettings::trackheight();
         QPointF newPos = value.toPointF();
-        QPointF start = sceneBoundingRect().topLeft();
-        int posx = start.x() + newPos.x(); //projectScene()->getSnapPointForPos(start.x() + sc.x(), KdenliveSettings::snaptopoints());
-
-        int startTrack = (start.y()) / KdenliveSettings::trackheight();
-        int newTrack = (start.y() + newPos.y()) / KdenliveSettings::trackheight();
-        //kDebug()<<"// GROUP NEW TRACK: "<<newTrack<<", START TRACK: "<<startTrack;
-        newTrack = qMin(newTrack, projectScene()->tracksCount() - 1);
+        int xpos = projectScene()->getSnapPointForPos((int) newPos.x(), KdenliveSettings::snaptopoints());
+        xpos = qMax(xpos, 0);
+        newPos.setX(xpos);
+
+        QPointF start = pos();
+        //int startTrack = (start.y() + trackHeight / 2) / trackHeight;
+        int newTrack = (newPos.y()) / trackHeight;
+        //kDebug()<<"// GROUP NEW T:"<<newTrack<<",START T:"<<startTrack<<",MAX:"<<projectScene()->tracksCount() - 1;
+        newTrack = qMin(newTrack, projectScene()->tracksCount() - (int)(boundingRect().height() + 5) / trackHeight);
         newTrack = qMax(newTrack, 0);
-        newPos.setY((int)((newTrack - startTrack) * KdenliveSettings::trackheight()));
 
-        //kDebug() << "------------------------------------GRUOP MOVE";
+        // Check if top item is a clip or a transition
+        int offset = 0;
+        int topTrack = -1;
+        QList<QGraphicsItem *> children = childItems();
+        for (int i = 0; i < children.count(); i++) {
+            int currentTrack = (int)(children.at(i)->scenePos().y() / trackHeight);
+            if (children.at(i)->type() == AVWIDGET) {
+                if (topTrack == -1 || currentTrack <= topTrack) {
+                    offset = 0;
+                    topTrack = currentTrack;
+                }
+            } else if (children.at(i)->type() == TRANSITIONWIDGET) {
+                if (topTrack == -1 || currentTrack < topTrack) {
+                    offset = (int)(trackHeight / 3 * 2 - 1);
+                    topTrack = currentTrack;
+                }
+            }
+        }
+        newPos.setY((int)((newTrack) * trackHeight) + offset);
+        if (newPos == start) return start;
 
-        if (start.x() + newPos.x() - pos().x() < 0) {
+        if (newPos.x() < 0) {
             // If group goes below 0, adjust position to 0
             return QPointF(pos().x() - start.x(), pos().y());
         }
 
-        QPolygonF sceneShape = groupShape(newPos - pos());
-        QList<QGraphicsItem*> collindingItems = scene()->items(sceneShape, Qt::IntersectsItemShape);
-        QList<QGraphicsItem *> children = childItems();
+        QPainterPath shape = groupShape(newPos - pos());
+        QList<QGraphicsItem*> collindingItems = scene()->items(shape, Qt::IntersectsItemShape);
         for (int i = 0; i < children.count(); i++) {
             collindingItems.removeAll(children.at(i));
         }
         if (collindingItems.isEmpty()) return newPos;
         else {
+            bool forwardMove = newPos.x() > start.x();
+            int offset = 0;
             for (int i = 0; i < collindingItems.count(); i++) {
                 QGraphicsItem *collision = collindingItems.at(i);
                 if (collision->type() == AVWIDGET) {
                     // Collision
-                    return pos();
-                    //TODO: improve movement when collision happens
-                    /*if (startTrack != newTrack) return pos();
-                    if (collision->pos().x() > pos().x()) {
-                    return QPointF(collision->sceneBoundingRect().x() - sceneBoundingRect().width() + pos().x() - start.x() - 1, newPos.y());
-                    }*/
-                }
-            }
-            return newPos;
-        }
-
-        //else posx -= startx;
-        //posx = qMax(posx, 0);
-        //newPos.setX(posx);
-        //kDebug()<<"Y POS: "<<start.y() + newPos.y()<<"SCN MP: "<<sc;
-        /*int newTrack = (start.y() + newPos.y()) / KdenliveSettings::trackheight();
-        int oldTrack = (start.y() + pos().y()) / KdenliveSettings::trackheight();
-        newPos.setY((newTrack) * KdenliveSettings::trackheight() - start.y() + 1);*/
-
-
-        //if (start.y() + newPos.y() < 1)  newTrack = oldTrack;
-
-        return newPos;
-
-        // Only one clip is moving
-
-        QList<QGraphicsItem*> items = scene()->items(sceneShape, Qt::IntersectsItemShape);
-
-
-        if (!items.isEmpty()) {
-            for (int i = 0; i < items.count(); i++) {
-                if (items.at(i)->type() == AVWIDGET) {
-                    // Collision!
-                    //kDebug()<<"/// COLLISION WITH ITEM: "<<items.at(i)->sceneBoundingRect();
-                    return pos();
-                    QPointF otherPos = items.at(i)->pos();
-                    if ((int) otherPos.y() != (int) pos().y()) return pos();
-                    if (pos().x() < otherPos.x()) {
-                        // move clip just before colliding clip
-                        int npos = (static_cast < AbstractClipItem* >(items.at(i))->startPos()).frames(m_fps) - sceneBoundingRect().width();
-                        newPos.setX(npos);
+                    //kDebug()<<"// COLLISION WIT:"<<collision->sceneBoundingRect();
+                    if (newPos.y() != start.y()) {
+                        // Track change results in collision, restore original position
+                        return start;
+                    }
+                    AbstractClipItem *item = static_cast <AbstractClipItem *>(collision);
+                    if (forwardMove) {
+                        // Moving forward, determine best pos
+                        QPainterPath clipPath;
+                        clipPath.addRect(item->sceneBoundingRect());
+                        QPainterPath res = shape.intersected(clipPath);
+                        offset = qMax(offset, (int)(res.boundingRect().width() + 0.5));
                     } else {
-                        // get pos just after colliding clip
-                        int npos = static_cast < AbstractClipItem* >(items.at(i))->endPos().frames(m_fps);
-                        newPos.setX(npos);
+                        // Moving backward, determine best pos
+                        QPainterPath clipPath;
+                        clipPath.addRect(item->sceneBoundingRect());
+                        QPainterPath res = shape.intersected(clipPath);
+                        offset = qMax(offset, (int)(res.boundingRect().width() + 0.5));
                     }
-                    return newPos;
                 }
             }
+            if (offset > 0) {
+                if (forwardMove) {
+                    newPos.setX(newPos.x() - offset);
+                } else {
+                    newPos.setX(newPos.x() + offset);
+                }
+                // If there is still a collision after our position adjust, restore original pos
+                collindingItems = scene()->items(groupShape(newPos - pos()), Qt::IntersectsItemShape);
+                for (int i = 0; i < children.count(); i++) {
+                    collindingItems.removeAll(children.at(i));
+                }
+                for (int i = 0; i < collindingItems.count(); i++)
+                    if (collindingItems.at(i)->type() == AVWIDGET) return pos();
+            }
+            return newPos;
         }
-        return newPos;
     }
-    return QGraphicsItem::itemChange(change, value);
+    return QGraphicsItemGroup::itemChange(change, value);
 }