Version: HEAD (using KDE KDE 3.5.0) OS: Linux PROBLEM: When an object is being resized it is no longer snapping to the border of other view objects STEPS TO REPRODUCE: Start Kst Create two rectangles in the default window (with a sibling relationship) Switch to layout mode Move one of the rectangles around RESULTS: The rectangle being moved does not snap to the other rectangle when their edges are close RESULTS: The rectangle being moved does snap to the other rectangle when their edges are close
Do we still want this? I find snapping behaviour on resize difficult to use. On Wed, 2006-08-02 at 17:37 +0000, Andrew Walker wrote: [bugs.kde.org quoted mail]
SVN commit 660784 by arwalker: CCBUG:131739 Reinstate snap to border on resize. Alt key can be used to override snap behaviour for both move and resize. Still need to address *moving end point of line *centred resize of ellipse while maintaining aspect ratio *snap behaviour of rectangles when maintaining aspect M +74 -51 ksttoplevelview.cpp M +7 -7 ksttoplevelview.h M +1 -1 kstviewwidget.cpp --- branches/work/kst/1.5/kst/src/libkstapp/ksttoplevelview.cpp #660783:660784 @@ -517,9 +517,9 @@ for (KstViewObjectList::ConstIterator i = obj->children().begin(); i != obj->children().end(); ++i) { if (_selectionList.find(*i) == _selectionList.end() && _pressTarget != *i) { const QRect rect((*i)->geometry()); - + moveSnapToBorders(xMin, yMin, *i, r); - + int overlapLo = r.top() > rect.top() ? r.top() : rect.top(); int overlapHi = r.bottom() < rect.bottom() ? r.bottom() : rect.bottom(); if (overlapHi - overlapLo > 0) { @@ -533,7 +533,7 @@ *xMin = r.right() - rect.right(); } } - + overlapLo = r.left() > rect.left() ? r.left() : rect.left(); overlapHi = r.right() < rect.right() ? r.right() : rect.right(); if (overlapHi - overlapLo > 0) { @@ -556,9 +556,9 @@ for (KstViewObjectList::ConstIterator i = obj->children().begin(); i != obj->children().end(); ++i) { if (_pressTarget != *i) { const QRect rect((*i)->geometry()); - + resizeSnapToBorders(xMin, yMin, *i, r, direction); - + int overlapLo = r.top() > rect.top() ? r.top() : rect.top(); int overlapHi = r.bottom() < rect.bottom() ? r.bottom() : rect.bottom(); if (overlapHi - overlapLo > 0) { @@ -566,7 +566,7 @@ if (labs(r.left() - rect.left()) < labs(*xMin)) { *xMin = r.left() - rect.left(); } else if (labs(r.left() - rect.right()) < labs(*xMin)) { - *xMin = r.left() - rect.right(); + *xMin = r.left() - rect.right(); } } else if (direction & RIGHT) { if (labs(r.right() - rect.left()) < labs(*xMin)) { @@ -574,7 +574,7 @@ } else if (labs(r.right() - rect.right()) < labs(*xMin)) { *xMin = r.right() - rect.right(); } - } + } } overlapLo = r.left() > rect.left() ? r.left() : rect.left(); @@ -584,7 +584,7 @@ if (labs(r.top() - rect.top()) < labs(*yMin)) { *yMin = r.top() - rect.top(); } else if (labs(r.top() - rect.bottom()) < labs(*yMin)) { - *yMin = r.top() - rect.bottom(); + *yMin = r.top() - rect.bottom(); } } else if (direction & DOWN) { if (labs(r.bottom() - rect.top()) < labs(*yMin)) { @@ -603,25 +603,37 @@ QRect rectNew = r; int xMin = STICKY_THRESHOLD; int yMin = STICKY_THRESHOLD; - + resizeSnapToBorders(&xMin, &yMin, this, r, direction); if (labs(yMin) < STICKY_THRESHOLD) { if (direction & UP) { rectNew.setTop(r.top() - yMin); + if (direction & CENTEREDRESIZE) { + rectNew.setBottom(r.bottom() + yMin); + } } else if (direction & DOWN) { rectNew.setBottom(r.bottom() - yMin); + if (direction & CENTEREDRESIZE) { + rectNew.setTop(r.top() + yMin); + } } } - + if (labs(xMin) < STICKY_THRESHOLD) { if (direction & LEFT) { rectNew.setLeft(r.left() - xMin); - } else if (direction & RIGHT) { + if (direction & CENTEREDRESIZE) { + rectNew.setRight(r.right() + xMin); + } + } else if (direction & RIGHT) { rectNew.setRight(r.right() - xMin); + if (direction & CENTEREDRESIZE) { + rectNew.setLeft(r.left() + xMin); + } } } - + return rectNew.normalize(); } @@ -645,18 +657,18 @@ } -void KstTopLevelView::pressMove(const QPoint& pos, bool shift) { +void KstTopLevelView::pressMove(const QPoint& pos, bool shift, bool alt) { if (_activeHandler) { _activeHandler->pressMove(this, pos, shift, _geom); return; } - + // in these cases there is nothing to do if (_mode == DisplayMode || _mode == Unknown) { _pressTarget = 0L; return; } - + if (_pressDirection == -1 && _pressTarget) { // menu released return; } @@ -664,44 +676,47 @@ if (shift && _moveOffset == QPoint(-1, -1) && _pressDirection < 1) { return; } - + _mouseMoved = true; - + // handle as in layout mode - pressMoveLayoutMode(pos, shift); + pressMoveLayoutMode(pos, shift, alt); } -void KstTopLevelView::pressMoveLayoutMode(const QPoint& pos, bool shift) { +void KstTopLevelView::pressMoveLayoutMode(const QPoint& pos, bool shift, bool alt) { if (_pressTarget) { + bool snapToBorder = !alt; + if (_pressDirection == 0) { // moving an object - pressMoveLayoutModeMove(pos, shift); + pressMoveLayoutModeMove(pos, shift, snapToBorder); KstApp::inst()->slotUpdateDataMsg(i18n("(x0,y0)-(x1,y1)", "(%1,%2)-(%3,%4)").arg(_prevBand.topLeft().x()).arg(_prevBand.topLeft().y()).arg(_prevBand.bottomRight().x()).arg(_prevBand.bottomRight().y())); } else if (_pressTarget->isResizable()) { bool maintainAspect = shift ^ _pressTarget->maintainAspect(); // if default behaviour is to maintainAspect on resize, then shift will now have opposite behaviour. + if (_pressDirection & ENDPOINT) { // moving an endpoint of an object - pressMoveLayoutModeEndPoint(pos, maintainAspect); + pressMoveLayoutModeEndPoint(pos, maintainAspect, snapToBorder); } else if (_pressDirection & CENTEREDRESIZE) { // resizing an object with fixed center - pressMoveLayoutModeCenteredResize(pos, maintainAspect); + pressMoveLayoutModeCenteredResize(pos, maintainAspect, snapToBorder); } else { // resizing a rectangular object - pressMoveLayoutModeResize(pos, maintainAspect); + pressMoveLayoutModeResize(pos, maintainAspect, snapToBorder); } KstApp::inst()->slotUpdateDataMsg(i18n("(x0,y0)-(x1,y1)", "(%1,%2)-(%3,%4)").arg(_prevBand.topLeft().x()).arg(_prevBand.topLeft().y()).arg(_prevBand.bottomRight().x()).arg(_prevBand.bottomRight().y())); } } else { // selecting objects - pressMoveLayoutModeSelect(pos, shift); + pressMoveLayoutModeSelect(pos); } } -void KstTopLevelView::pressMoveLayoutModeMove(const QPoint& pos, bool shift) { +void KstTopLevelView::pressMoveLayoutModeMove(const QPoint& pos, bool shift, bool snapToBorder) { Q_UNUSED(shift) - + const QRect old(_prevBand); QRect r(_pressTarget->geometry()); @@ -712,31 +727,32 @@ QPoint topLeft(pos - _moveOffset - _pressTarget->geometry().topLeft() + r.topLeft()); r.moveTopLeft(topLeft); _moveOffsetSticky = QPoint(0, 0); - - int xMin = STICKY_THRESHOLD; - int yMin = STICKY_THRESHOLD; - - moveSnapToBorders(&xMin, &yMin, this, r); - - if (labs(xMin) < STICKY_THRESHOLD) { - _moveOffsetSticky.setX(xMin); - topLeft.setX(topLeft.x() - xMin); + + if (snapToBorder) { + int xMin = STICKY_THRESHOLD; + int yMin = STICKY_THRESHOLD; + + moveSnapToBorders(&xMin, &yMin, this, r); + + if (labs(xMin) < STICKY_THRESHOLD) { + _moveOffsetSticky.setX(xMin); + topLeft.setX(topLeft.x() - xMin); + } + + if (labs(yMin) < STICKY_THRESHOLD) { + _moveOffsetSticky.setY(yMin); + topLeft.setY(topLeft.y() - yMin); + } + r.moveTopLeft(topLeft); } - - if (labs(yMin) < STICKY_THRESHOLD) { - _moveOffsetSticky.setY(yMin); - topLeft.setY(topLeft.y() - yMin); - } - r.moveTopLeft(topLeft); - if (!_geom.contains(r, true)) { slideInto(_geom, r); } _prevBand = r; if (_prevBand != old) { KstPainter p; - + p.begin(_w); p.setRasterOp(Qt::NotROP); p.setPen(QPen(Qt::black, 0, Qt::DotLine)); @@ -758,13 +774,18 @@ } -void KstTopLevelView::pressMoveLayoutModeResize(const QPoint& pos, bool maintainAspect) { +void KstTopLevelView::pressMoveLayoutModeResize(const QPoint& pos, bool maintainAspect, bool snapToBorders) { const QRect old(_prevBand); _prevBand = newSize(_pressTarget->geometry(), _pressTarget->_parent->geometry(), _pressDirection, pos, maintainAspect); + + if (snapToBorders) { + _prevBand = resizeSnapToObjects(_prevBand, _pressDirection); + } + if (_prevBand != old) { KstPainter p; - + p.begin(_w); p.setRasterOp(Qt::NotROP); p.setPen(QPen(Qt::black, 0, Qt::DotLine)); @@ -777,9 +798,7 @@ } -void KstTopLevelView::pressMoveLayoutModeSelect(const QPoint& pos, bool shift) { - Q_UNUSED(shift) - +void KstTopLevelView::pressMoveLayoutModeSelect(const QPoint& pos) { const QRect old(_prevBand); QRect r; r.setTopLeft(_moveOffset); @@ -797,7 +816,7 @@ } -void KstTopLevelView::pressMoveLayoutModeEndPoint(const QPoint& pos, bool maintainAspect) { +void KstTopLevelView::pressMoveLayoutModeEndPoint(const QPoint& pos, bool maintainAspect, bool snapToBorder) { // FIXME: remove this!! Should not know about any specific type // for now we only know how to deal with lines @@ -821,7 +840,7 @@ } else { return; } - + if (maintainAspect) { movePoint = KstGfxMouseHandlerUtils::findNearestPtOnLine(anchorPoint, movePoint, pos, bounds); } else { @@ -851,12 +870,16 @@ } -void KstTopLevelView::pressMoveLayoutModeCenteredResize(const QPoint& pos, bool maintainAspect) { +void KstTopLevelView::pressMoveLayoutModeCenteredResize(const QPoint& pos, bool maintainAspect, bool snapToBorder) { //centered resize means that the center of the object stays constant const QRect old(_prevBand); _prevBand = newSizeCentered(_pressTarget->geometry(), _pressTarget->_parent->geometry(), _pressDirection, pos, maintainAspect); + if (snapToBorder) { + _prevBand = resizeSnapToObjects(_prevBand, _pressDirection); + } + if (_prevBand != old) { KstPainter p; --- branches/work/kst/1.5/kst/src/libkstapp/ksttoplevelview.h #660783:660784 @@ -103,14 +103,14 @@ bool handleDoubleClick(const QPoint& pos, bool shift = false); // press move handlers - void pressMove(const QPoint& pos, bool shift = false); - void pressMoveLayoutMode(const QPoint& pos, bool shift = false); + void pressMove(const QPoint& pos, bool shift = false, bool alt = false); + void pressMoveLayoutMode(const QPoint& pos, bool shift = false, bool alt = false); // helpers for pressMoveLayoutMode - void pressMoveLayoutModeMove(const QPoint& pos, bool shift = false); - void pressMoveLayoutModeResize(const QPoint& pos, bool maintainAspect = false); - void pressMoveLayoutModeSelect(const QPoint& pos, bool shift = false); - void pressMoveLayoutModeEndPoint(const QPoint& pos, bool maintainAspect = false); - void pressMoveLayoutModeCenteredResize(const QPoint& pos, bool maintainAspect = false); + void pressMoveLayoutModeMove(const QPoint& pos, bool shift = false, bool snapToBorder = true); + void pressMoveLayoutModeResize(const QPoint& pos, bool maintainAspect = false, bool snapToBorder = true); + void pressMoveLayoutModeSelect(const QPoint& pos); + void pressMoveLayoutModeEndPoint(const QPoint& pos, bool maintainAspect = false, bool snapToBorder = true); + void pressMoveLayoutModeCenteredResize(const QPoint& pos, bool maintainAspect = false, bool snapToBorder = true); // release press handlers void releasePress(const QPoint& pos, bool shift = false); --- branches/work/kst/1.5/kst/src/libkstapp/kstviewwidget.cpp #660783:660784 @@ -187,7 +187,7 @@ e->accept(); } else if (e->state() & Qt::LeftButton) { //setCursor(QCursor(Qt::ArrowCursor)); - _view->pressMove(e->pos(), e->state() & Qt::ShiftButton); + _view->pressMove(e->pos(), e->state() & Qt::ShiftButton, e->state() & Qt::AltButton); e->accept(); } }
SVN commit 660878 by arwalker: CCBUG:131739 still needs further testing M +11 -2 kstgfxmousehandlerutils.cpp M +92 -15 ksttoplevelview.cpp M +3 -0 ksttoplevelview.h --- branches/work/kst/1.5/kst/src/libkstapp/kstgfxmousehandlerutils.cpp #660877:660878 @@ -175,15 +175,24 @@ if (vertical) { newHalfHeight = kMin(newHalfHeight, anchorPoint.y() - bounds.top()); newHalfHeight = kMin(newHalfHeight, bounds.bottom() - anchorPoint.y()); - newSize.scale(originalRect.width(), 2*newHalfHeight, QSize::ScaleMin); + if (newHalfHeight > originalRect.height()/2) { + newSize.scale(originalRect.width(), 2*newHalfHeight, QSize::ScaleMax); + } else { + newSize.scale(originalRect.width(), 2*newHalfHeight, QSize::ScaleMin); + } } else { newHalfWidth = kMin(newHalfWidth, anchorPoint.x() - bounds.left()); newHalfWidth = kMin(newHalfWidth, bounds.right() - anchorPoint.x()); - newSize.scale(2*newHalfWidth, originalRect.height(), QSize::ScaleMin); + if (newHalfWidth > originalRect.width()/2) { + newSize.scale(2*newHalfWidth, originalRect.height(), QSize::ScaleMax); + } else { + newSize.scale(2*newHalfWidth, originalRect.height(), QSize::ScaleMin); + } } newRect.setSize(newSize); newRect.moveCenter(anchorPoint); + newRect = newRect.intersect(bounds); } else { if (vertical) { newRect = QRect(0, 0, originalRect.width(), 2*newHalfHeight); --- branches/work/kst/1.5/kst/src/libkstapp/ksttoplevelview.cpp #660877:660878 @@ -599,6 +599,91 @@ } +void KstTopLevelView::pointSnapToBorders(int *xMin, int *yMin, const KstViewObjectPtr &obj, const QPoint &p) const { + for (KstViewObjectList::ConstIterator i = obj->children().begin(); i != obj->children().end(); ++i) { + if (_pressTarget != *i) { + const QRect rect((*i)->geometry()); + + pointSnapToBorders(xMin, yMin, *i, p); + + if (rect.top() <= p.y() && rect.bottom() >= p.y()) { + if (labs(p.x() - rect.left()) < labs(*xMin)) { + *xMin = p.x() - rect.left(); + } else if (labs(p.x() - rect.right()) < labs(*xMin)) { + *xMin = p.x() - rect.right(); + } + } + + if (rect.left() <= p.x() && rect.right() >= p.x()) { + if (labs(p.y() - rect.top()) < labs(*yMin)) { + *yMin = p.y() - rect.top(); + } else if (labs(p.y() - rect.bottom()) < labs(*yMin)) { + *yMin = p.y() - rect.bottom(); + } + } + } + } +} + + +QPoint KstTopLevelView::pointSnapToObjects(const QPoint& p) { + QRect rectNew; + QRect r; + int xMin = STICKY_THRESHOLD; + int yMin = STICKY_THRESHOLD; + + r.setTopLeft(QPoint(0, 0)); + r.setBottomRight(p); + + pointSnapToBorders(&xMin, &yMin, this, p); + + if (labs(yMin) < STICKY_THRESHOLD) { + r.setBottom(r.bottom() - yMin); + } + + if (labs(xMin) < STICKY_THRESHOLD) { + r.setRight(r.right() - xMin); + } + + return r.bottomRight(); +} + + +QRect KstTopLevelView::resizeCenteredSnapToObjects(const QRect& r, const QRect& bounds, int direction) { + QRect rectNew = r; + int xMin = STICKY_THRESHOLD; + int yMin = STICKY_THRESHOLD; + + resizeSnapToBorders(&xMin, &yMin, this, r, direction); + + if (labs(yMin) < STICKY_THRESHOLD) { + if (direction & UP) { + rectNew.setTop(r.top() - yMin); + rectNew.setBottom(r.bottom() + yMin); + } else if (direction & DOWN) { + rectNew.setBottom(r.bottom() - yMin); + rectNew.setTop(r.top() + yMin); + } + } + + if (labs(xMin) < STICKY_THRESHOLD) { + if (direction & LEFT) { + rectNew.setLeft(r.left() - xMin); + rectNew.setRight(r.right() + xMin); + } else if (direction & RIGHT) { + rectNew.setRight(r.right() - xMin); + rectNew.setLeft(r.left() + xMin); + } + } + + if (!bounds.contains(rectNew)) { + rectNew = r; + } + + return rectNew.normalize(); +} + + QRect KstTopLevelView::resizeSnapToObjects(const QRect& r, int direction) { QRect rectNew = r; int xMin = STICKY_THRESHOLD; @@ -609,28 +694,16 @@ if (labs(yMin) < STICKY_THRESHOLD) { if (direction & UP) { rectNew.setTop(r.top() - yMin); - if (direction & CENTEREDRESIZE) { - rectNew.setBottom(r.bottom() + yMin); - } } else if (direction & DOWN) { rectNew.setBottom(r.bottom() - yMin); - if (direction & CENTEREDRESIZE) { - rectNew.setTop(r.top() + yMin); - } } } if (labs(xMin) < STICKY_THRESHOLD) { if (direction & LEFT) { rectNew.setLeft(r.left() - xMin); - if (direction & CENTEREDRESIZE) { - rectNew.setRight(r.right() + xMin); - } } else if (direction & RIGHT) { rectNew.setRight(r.right() - xMin); - if (direction & CENTEREDRESIZE) { - rectNew.setLeft(r.left() + xMin); - } } } @@ -851,6 +924,10 @@ } } + if (snapToBorder) { + movePoint = pointSnapToObjects(movePoint); + } + const QRect old(_prevBand); _prevBand.setTopLeft(*fromPoint); _prevBand.setBottomRight(*toPoint); @@ -873,11 +950,11 @@ void KstTopLevelView::pressMoveLayoutModeCenteredResize(const QPoint& pos, bool maintainAspect, bool snapToBorder) { //centered resize means that the center of the object stays constant const QRect old(_prevBand); - + _prevBand = newSizeCentered(_pressTarget->geometry(), _pressTarget->_parent->geometry(), _pressDirection, pos, maintainAspect); if (snapToBorder) { - _prevBand = resizeSnapToObjects(_prevBand, _pressDirection); + _prevBand = resizeCenteredSnapToObjects(_prevBand, _pressTarget->_parent->geometry(), _pressDirection); } if (_prevBand != old) { @@ -933,7 +1010,7 @@ if (!_selectionList.isEmpty()) { for (KstViewObjectList::ConstIterator i = _selectionList.begin(); i != _selectionList.end(); ++i) { obj = obj.unite((*i)->geometry()); - } + } } const QPoint objOffset(old.topLeft() - obj.topLeft()); --- branches/work/kst/1.5/kst/src/libkstapp/ksttoplevelview.h #660877:660878 @@ -131,7 +131,10 @@ QRect correctHeightForRatio(const QRect& oldRect, double ratio, int direction, int origRight, int origLeft); void moveSnapToBorders(int *xMin, int *yMin, const KstViewObjectPtr &obj, const QRect &r) const; void resizeSnapToBorders(int *xMin, int *yMin, const KstViewObjectPtr& obj, const QRect &r, int direction) const; + QRect resizeCenteredSnapToObjects(const QRect& r, const QRect& bounds, int direction); QRect resizeSnapToObjects(const QRect& r, int direction); + void pointSnapToBorders(int *xMin, int *yMin, const KstViewObjectPtr &obj, const QPoint &p) const; + QPoint pointSnapToObjects(const QPoint& p); // Called as a response to drag re-entering widget() void restartMove();
No problems encountered, so close the bug.