I was sitting around trying to organize some of my plasmoids... and
realized that you can't easily make a stack of plasmoids all exactly
aligned ... at least not that I could figure out. I thought it would
be really cool to be able to snap plasmoids to other plasmoids as well
as to virtual "guidelines" created by the bounding boxes of the
plasmoids. I spent a few hours and finally got the effect I was
looking for. Should work for both moves and resizes. Attached is the
patch against kdelibs head. Right now the snap "strength" is hard
coded to 3 pixels.

~Roman
From 9f2af11848d6ed72977beb8320c1d503a0f3978d Mon Sep 17 00:00:00 2001
From: Roman Shtylman <shtyl...@gmail.com>
Date: Sat, 2 Jan 2010 01:15:26 -0500
Subject: [PATCH] added plasma widget snap

plasma widgets snap to other plasma widget's grid lines
---
 plasma/private/applethandle.cpp |  123 ++++++++++++++++++++++++++++++++++++++-
 plasma/private/applethandle_p.h |    3 +
 2 files changed, 125 insertions(+), 1 deletions(-)

diff --git a/plasma/private/applethandle.cpp b/plasma/private/applethandle.cpp
index 1f56f5d..4039ec1 100644
--- a/plasma/private/applethandle.cpp
+++ b/plasma/private/applethandle.cpp
@@ -587,9 +587,29 @@ QPointF _k_projectPoint(QPointF point, QPointF v)
     return QMatrix(a, b, b, d, 0., 0.).map(point);
 }
 
+QRectF AppletHandle::maskedBoundingRect() const
+{
+    if (!m_applet) {
+        return QRectF();
+    }
+    
+    //snap to other plasmoid grid
+    QRectF srect;
+    if (m_applet->d->background) {
+        srect = m_applet->d->background->mask().boundingRect();
+    } else {
+        srect = m_applet->boundingRect();
+    }
+    
+    srect.translate(m_applet->pos());
+    
+    return srect;
+}
+
 void AppletHandle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
 {
     static const qreal snapAngle = M_PI_2 /* $i 3.14159 / 2.0 */;
+    static const qreal snapDist = 3; // distance (px) for widget snap
 
     if (!m_applet) {
         QGraphicsItem::mouseMoveEvent(event);
@@ -617,6 +637,59 @@ void AppletHandle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
         if (m_applet) {
             QPointF mappedPoint = transform().map(QPointF(deltaScene.x(), deltaScene.y()));
             m_applet->moveBy(mappedPoint.x(), mappedPoint.y());
+            
+            //snap to other plasmoid grid
+            const QRectF srect = maskedBoundingRect();
+            
+            foreach (Plasma::Applet* applet, m_containment->applets()) {
+                //make sure we don't match against ourselves
+                if (applet != m_applet) {
+                    QRectF drect;
+                    
+                    if (applet->d->background) {
+                        drect = applet->d->background->mask().boundingRect();
+                    } else {
+                        drect = applet->boundingRect();
+                    }
+                    
+                    drect.translate(applet->pos());
+                    
+                    const qreal x1 = drect.right() - srect.right();
+                    const qreal x2 = drect.right() - srect.left();
+                    const qreal x3 = drect.left() - srect.right();
+                    const qreal x4 = drect.left() - srect.left();
+                    
+                    const qreal y1 = drect.bottom() - srect.bottom();
+                    const qreal y2 = drect.bottom() - srect.top();
+                    const qreal y3 = drect.top() - srect.bottom();
+                    const qreal y4 = drect.top() - srect.top();
+                    
+                    QPointF moveBy;
+                    
+                    if (qAbs(x1) < snapDist)
+                        moveBy.setX(x1);
+                    else if (qAbs(x2) < snapDist)
+                        moveBy.setX(x2);
+                    else if (qAbs(x3) < snapDist)
+                        moveBy.setX(x3);
+                    else if (qAbs(x4) < snapDist)
+                        moveBy.setX(x4);
+                    
+                    if (qAbs(y1) < snapDist)
+                        moveBy.setY(y1);
+                    else if (qAbs(y2) < snapDist)
+                        moveBy.setY(y2);
+                    else if (qAbs(y3) < snapDist)
+                        moveBy.setY(y3);
+                    else if (qAbs(y4) < snapDist)
+                        moveBy.setY(y4);
+                    
+                    if (!moveBy.isNull()) {
+                        m_applet->moveBy(moveBy.x(), moveBy.y());
+                        break;
+                    }
+                }
+            }
         }
     } else if (m_pressedButton == ResizeButton || m_pressedButton == RotateButton) {
         QPointF cursorPoint = event->scenePos();
@@ -701,6 +774,54 @@ void AppletHandle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
 
             newAngle = m_angle;
         }
+        
+        //snap to other plasmoid grid
+        const QRectF srect = maskedBoundingRect();
+        const QPointF snapPoint = (m_buttonsOnRight) ? srect.topRight() : srect.topLeft();
+        
+        foreach (Plasma::Applet* applet, m_containment->applets()) {
+            //make sure we don't match against ourselves
+            if (applet != m_applet) {
+                QRectF drect;    
+                if (applet->d->background) {
+                    drect = applet->d->background->mask().boundingRect();
+                } else {
+                    drect = applet->boundingRect();
+                }
+                drect.translate(applet->pos());
+                
+                const qreal x1 = drect.right() - snapPoint.x();
+                const qreal x2 = drect.left() - snapPoint.x();
+                
+                const qreal y1 = drect.bottom() - snapPoint.y();
+                const qreal y2 = drect.top() - snapPoint.y();
+                
+                QPointF moveBy;
+                if (qAbs(x1) < snapDist)
+                    moveBy.setX(x1);
+                else if (qAbs(x2) < snapDist)
+                    moveBy.setX(x2);
+                
+                if (qAbs(y1) < snapDist)
+                    moveBy.setY(y1);
+                else if (qAbs(y2) < snapDist)
+                    moveBy.setY(y2);
+                
+                if (!moveBy.isNull()) {
+                    
+                    newCenter += moveBy/2;
+                    m_resizeGrabPoint -= moveBy;
+                    
+                    if (m_buttonsOnRight) {
+                        moveBy.setX(-moveBy.x());
+                    }
+                    
+                    //we have to change the size in the direction of the resize
+                    newSize -= moveBy;
+                    break;
+                }
+            }
+        }
 
         // apply size
         m_applet->resize(newSize.x(), newSize.y());
@@ -708,7 +829,7 @@ void AppletHandle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
         if (m_pressedButton != RotateButton) {
             m_applet->setPos(m_containment->mapFromScene(newCenter - newSize/2));
         }
-
+        
         // apply angle
         QTransform at;
         at.translate(newSize.x()/2, newSize.y()/2);
diff --git a/plasma/private/applethandle_p.h b/plasma/private/applethandle_p.h
index d78635f..0267dd9 100644
--- a/plasma/private/applethandle_p.h
+++ b/plasma/private/applethandle_p.h
@@ -96,6 +96,9 @@ class AppletHandle : public QGraphicsObject
         ButtonType mapToButton(const QPointF &point) const;
         void forceDisappear();
         int minimumHeight();
+        
+        /** returns the boudning rectangle of the "visible" area */
+        QRectF maskedBoundingRect() const;
 
         /**
          * move our applet to another containment
-- 
1.6.5

_______________________________________________
Plasma-devel mailing list
Plasma-devel@kde.org
https://mail.kde.org/mailman/listinfo/plasma-devel

Reply via email to