Bug 143804

Summary: Resizing ellipses from edge grab-boxes not working correctly
Product: [Applications] kst Reporter: Andrew Walker <arwalker>
Component: generalAssignee: Duncan Hanson <duncan.hanson>
Status: RESOLVED FIXED    
Severity: normal    
Priority: NOR    
Version: 1.x   
Target Milestone: ---   
Platform: unspecified   
OS: Linux   
Latest Commit: Version Fixed In:
Sentry Crash Report:

Description Andrew Walker 2007-04-03 20:29:48 UTC
Version:           HEAD (using KDE KDE 3.5.1)
OS:                Linux

STEPS TO REPRODUCE:

Start Kst
Create an ellipse object
Switch to layout mode
Select the ellipse object
Click on the right centre drag-box
Move it slightly to the left or right while dragging
Release the mouse button

RESULTS:

The ellipse outline has no height and when the mouse is released the newly sized ellipse similarly has no height

EXPECTED RESULTS:

The ellipse outline and newly sized ellipse retain the existing height

NOTE:

Analogous problems occur for any of the centre drag-boxes
Comment 1 Andrew Walker 2007-04-30 20:31:41 UTC
Duncan, could you check this fix in to the 1.5 branch before the 1.4 release so we can backport if necessary.
Comment 2 Duncan Hanson 2007-04-30 21:20:25 UTC
SVN commit 659768 by dhanson:

CCBUG:143804 most straightforward solution-- non-centered resizing of ellipses when edges are dragged.

 M  +5 -12     kstviewellipse.cpp  


--- branches/work/kst/1.5/kst/src/libkstapp/kstviewellipse.cpp #659767:659768
@@ -95,22 +95,15 @@
     }
   }
 
-  const QRect g(geometry());
-  int bw(_borderWidth * p.lineWidthAdjustmentFactor());
-  if (bw > g.width()/2) {
-    bw = g.width()/2;
-  }
-  if (bw > g.height()/2) {
-    bw = g.height()/2;
-  }
+  const int bw(_borderWidth * p.lineWidthAdjustmentFactor());
   QPen pen(bw > 0 ? _borderColor : _foregroundColor, bw);
   p.setPen(pen);
   if (_transparentFill) {
-    p.setBrush(Qt::NoBrush);
+    p.setBrush(Qt::NoBrush);  
   } else {
     p.setBrush(_foregroundColor);
   }
-
+  const QRect g(geometry());
   p.drawEllipse(g.x() + bw/2, g.y() + bw/2, g.width() - bw, g.height() - bw);
   p.restore();
 }
@@ -185,8 +178,8 @@
 
 signed int KstViewEllipse::directionFor(const QPoint& pos) {
   signed int direction = KstViewObject::directionFor(pos);
-  if (direction != 0) {
-    // not moving, so in any resize direction, we want it centred
+  if (!(((direction & (UP|DOWN)) == 0) || ((direction & (LEFT|RIGHT)) == 0))) {
+    // not an edge.
     direction |= CENTEREDRESIZE;  
   }  
   return direction;
Comment 3 Andrew Walker 2007-05-01 01:26:51 UTC
There is one remaining problems with this fix:

resizing from a corner leaves the center fixed, resizing from an edge does not. This behaviour should be made consistent to avoid confusing the user.
Comment 4 Duncan Hanson 2007-05-01 08:06:41 UTC
We could do that... my own thought is that it would be nicest to just
have ellipses resize in the same way as rectangles (boxes?)

We could have ellipses `resize from center' when you drag their edges,
but I think that will give you exactly the same functionality as
resizing from a corner.

I can't see anyone getting confused by the way that things are now.
For both drag types, there are separate visual cues to tip you off to
what is happening. So-- I don't think that anything should be done.

Duncan.

On 30 Apr 2007 23:26:52 -0000, Andrew Walker <arwalker@sumusltd.com> wrote:
[bugs.kde.org quoted mail]
Comment 5 Andrew Walker 2007-05-01 19:20:44 UTC
The existing functionality shouldn't be changed because of a bug report without at least some discussion first. 

'Resize from center' for an ellipse from the edges (the pre-existing functionality if there had been no bug) would behave differently than from the corners as the former would change only the width or height, while the latter would change both width and height.
Comment 6 Andrew Walker 2007-05-02 00:47:32 UTC
SVN commit 660202 by arwalker:

BUG:143804 fix problem with resizing of ellipses while maintaining intended functionality

 M  +72 -32    kstgfxmousehandlerutils.cpp  
 M  +2 -0      kstgfxmousehandlerutils.h  
 M  +23 -4     ksttoplevelview.cpp  
 M  +1 -1      ksttoplevelview.h  
 M  +2 -2      kstviewellipse.cpp  


--- branches/work/kst/1.5/kst/src/libkstapp/kstgfxmousehandlerutils.cpp #660201:660202
@@ -92,12 +92,12 @@
     newHalfHeight = kMin(newHalfHeight,bounds.bottom() - anchorPoint.y());
 
     QSize newSize(originalRect.size());
-    newSize.scale(2*newHalfWidth,2*newHalfHeight,QSize::ScaleMin);
+    newSize.scale(2*newHalfWidth, 2*newHalfHeight, QSize::ScaleMin);
 
     newRect.setSize(newSize);
     newRect.moveCenter(anchorPoint);
   } else {
-    newRect = QRect(0,0,2*newHalfWidth,2*newHalfHeight);
+    newRect = QRect(0, 0, 2*newHalfWidth, 2*newHalfHeight);
     newRect.moveCenter(anchorPoint);
     newRect = newRect.intersect(bounds);
   }
@@ -110,51 +110,91 @@
   QRect newSize(originalSize);
 
   if (movePoint.y() == anchorPoint.y()) {
-      int newWidth = pos.x() - anchorPoint.x(); //defined differently than in QRect.
+    int newWidth = pos.x() - anchorPoint.x(); //defined differently than in QRect.
 
-      if (maintainAspect) {
-        double newHalfHeight = originalSize.height() * (abs(newWidth) + 1) / originalSize.width() / 2.0; //defined with the QRect convention (height = bot - top + 1)
+    if (maintainAspect) {
+      double newHalfHeight = originalSize.height() * (abs(newWidth) + 1) / originalSize.width() / 2.0; //defined with the QRect convention (height = bot - top + 1)
 
-        newHalfHeight = kMin(double(movePoint.y() - bounds.top()) + 1, newHalfHeight); // ensure we are still within the bounds.
-        newHalfHeight = kMin(double(bounds.bottom() - movePoint.y()) + 1, newHalfHeight);
+      newHalfHeight = kMin(double(movePoint.y() - bounds.top()) + 1, newHalfHeight); // ensure we are still within the bounds.
+      newHalfHeight = kMin(double(bounds.bottom() - movePoint.y()) + 1, newHalfHeight);
 
-        if (newWidth == 0) { // anything better to be done?
-          newWidth = 1;
-        }
+      if (newWidth == 0) { // anything better to be done?
+        newWidth = 1;
+      }
 
-        newWidth = (int(originalSize.width() * (newHalfHeight * 2.0) / originalSize.height()) - 1)*newWidth/abs(newWidth); // consistency of width w/ the newly calculated height.
+      newWidth = (int(originalSize.width() * (newHalfHeight * 2.0) / originalSize.height()) - 1)*newWidth/abs(newWidth); // consistency of width w/ the newly calculated height.
 
-        newSize.setTop(anchorPoint.y() + int(newHalfHeight - 0.5));
-        newSize.setBottom(anchorPoint.y() - int(newHalfHeight - 0.5));
+      newSize.setTop(anchorPoint.y() + int(newHalfHeight - 0.5));
+      newSize.setBottom(anchorPoint.y() - int(newHalfHeight - 0.5));
+    }
+
+    newSize.setLeft(anchorPoint.x());
+    newSize.setRight(anchorPoint.x() + newWidth); // +1 for the way widths are defined in QRect.
+  } else if (movePoint.x() == anchorPoint.x()) {
+    // mimic the case for (movePoint.y() == anchorPoint.y()). comments are there.
+    int newHeight = pos.y() - anchorPoint.y();
+
+    if (maintainAspect) {
+      double newHalfWidth = originalSize.width() * (abs(newHeight) + 1) / originalSize.height() / 2.0;
+
+      newHalfWidth = kMin(double(movePoint.x() - bounds.left() + 1), newHalfWidth);
+      newHalfWidth = kMin(double(bounds.right() - movePoint.x() + 1), newHalfWidth);
+
+      if (newHeight == 0) {
+        newHeight = 1;
       }
 
-      newSize.setLeft(anchorPoint.x());
-      newSize.setRight(anchorPoint.x() + newWidth); // +1 for the way widths are defined in QRect.
+      newHeight = (int(originalSize.height() * newHalfWidth * 2.0 / originalSize.width()) - 1)*newHeight/abs(newHeight);
+      newSize.setLeft(anchorPoint.x() + int(newHalfWidth - 0.5));
+      newSize.setRight(anchorPoint.x() - int(newHalfWidth - 0.5));
+    }
 
-    } else if (movePoint.x() == anchorPoint.x()) {
-      // mimic the case for (movePoint.y() == anchorPoint.y()). comments are there.
-      int newHeight = pos.y() - anchorPoint.y();
+    newSize.setTop(anchorPoint.y());
+    newSize.setBottom(anchorPoint.y() + newHeight);
+  }
 
-      if (maintainAspect) {
-        double newHalfWidth = originalSize.width() * (abs(newHeight) + 1) / originalSize.height() / 2.0;
+  return newSize.normalize();
+}
 
-        newHalfWidth = kMin(double(movePoint.x() - bounds.left() + 1), newHalfWidth);
-        newHalfWidth = kMin(double(bounds.right() - movePoint.x() + 1), newHalfWidth);
 
-        if (newHeight == 0) {
-          newHeight = 1;
-        }
+QRect KstGfxMouseHandlerUtils::resizeRectFromEdgeCentered(const QRect& originalRect, const QPoint& anchorPoint, const QPoint& movePoint, const QPoint& pos, const QRect& bounds, bool maintainAspect) {
+  QRect newRect;
+  bool vertical;
+  int newHalfWidth = abs((pos - anchorPoint).x());
+  int newHalfHeight = abs((pos - anchorPoint).y());
 
-        newHeight = (int(originalSize.height() * newHalfWidth * 2.0 / originalSize.width()) - 1)*newHeight/abs(newHeight);
-        newSize.setLeft(anchorPoint.x() + int(newHalfWidth - .5));
-        newSize.setRight(anchorPoint.x() - int(newHalfWidth - .5));
-      }
+  if (movePoint.x() == anchorPoint.x()) {
+    vertical = true;
+  } else {
+    vertical = false;
+  }
 
-      newSize.setTop(anchorPoint.y());
-      newSize.setBottom(anchorPoint.y() + newHeight);
+  if (maintainAspect) {
+    QSize newSize(originalRect.size());
+
+    if (vertical) {
+      newHalfHeight = kMin(newHalfHeight, anchorPoint.y() - bounds.top());
+      newHalfHeight = kMin(newHalfHeight, bounds.bottom() - anchorPoint.y());
+      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);
     }
 
-    return newSize.normalize();
+    newRect.setSize(newSize);
+    newRect.moveCenter(anchorPoint);
+  } else {
+    if (vertical) {
+      newRect = QRect(0, 0, originalRect.width(), 2*newHalfHeight);
+    } else {
+      newRect = QRect(0, 0, 2*newHalfWidth, originalRect.height());
+    }
+    newRect.moveCenter(anchorPoint);
+    newRect = newRect.intersect(bounds);
+  }
+
+  return newRect;
 }
 
 
--- branches/work/kst/1.5/kst/src/libkstapp/kstgfxmousehandlerutils.h #660201:660202
@@ -30,6 +30,8 @@
     QRect resizeRectFromCornerCentered(const QRect& originalRect, const QPoint& pos, const QRect& bounds, bool maintainAspect);
     // resizes a rect from an edge, keeping anchorPoint fixed. movePoint = center of edge being dragged. anchorPoint = center of opposite edge. anchorPoint and movePoint must be inside bounds already.
     QRect resizeRectFromEdge(const QRect& originalSize, const QPoint& anchorPoint, const QPoint& movePoint, const QPoint& pos, const QRect &bounds, bool maintainAspect);
+    // resizes a rect from an edge, keeping anchorPoint fixed. movePoint = center of edge being dragged. anchorPoint = center of opposite edge. anchorPoint and movePoint must be inside bounds already.
+    QRect resizeRectFromEdgeCentered(const QRect& originalRect, const QPoint& anchorPoint, const QPoint& movePoint, const QPoint& pos, const QRect& bounds, bool maintainAspect);
     // returns a new rectangle. mouseOrigin must be inside bounds already.
     QRect newRect(const QPoint& pos, const QPoint& mouseOrigin, const QRect& bounds, bool squareAspect);
     // returns a new rectangle, mouseOrigin must be inside bounds already.
--- branches/work/kst/1.5/kst/src/libkstapp/ksttoplevelview.cpp #660201:660202
@@ -433,13 +433,14 @@
   if ( ((direction & (UP|DOWN)) == 0) || ((direction & (LEFT|RIGHT)) == 0) ) { //resizing from edge.
     return KstGfxMouseHandlerUtils::resizeRectFromEdge(originalSize, anchor_pt, move_pt, npos, bounds, maintainAspect);
   } else { //resizing from corner.
-    return KstGfxMouseHandlerUtils::resizeRectFromCorner(anchor_pt, move_pt, npos, bounds,maintainAspect);
+    return KstGfxMouseHandlerUtils::resizeRectFromCorner(anchor_pt, move_pt, npos, bounds, maintainAspect);
   }
 
 }
 
 
-QRect KstTopLevelView::newSizeCentered(const QRect& oldSize, const QRect& bounds, const QPoint& pos, bool maintainAspect) {
+QRect KstTopLevelView::newSizeCentered(const QRect& originalSize, const QRect& bounds, int direction, const QPoint& pos, bool maintainAspect) {
+  QPoint anchor_pt, move_pt;
   QPoint npos = pos;
 
   npos.setX(kMax(npos.x(), bounds.left()));
@@ -447,7 +448,25 @@
   npos.setY(kMin(npos.y(), bounds.bottom()));
   npos.setY(kMax(npos.y(), bounds.top()));
 
-  return KstGfxMouseHandlerUtils::resizeRectFromCornerCentered(oldSize, npos, bounds, maintainAspect);
+  anchor_pt = move_pt = originalSize.center();
+
+  if ((direction & UP) != 0) {
+    move_pt.setY(originalSize.top());
+  } else if ((direction & DOWN) != 0) {
+    move_pt.setY(originalSize.bottom());
+  }
+
+  if ((direction & LEFT) != 0) {
+    move_pt.setX(originalSize.left());
+  } else if ((direction & RIGHT) != 0) {
+    move_pt.setX(originalSize.right());
+  }
+
+  if ( ((direction & (UP|DOWN)) == 0) || ((direction & (LEFT|RIGHT)) == 0) ) { //resizing from edge.
+    return KstGfxMouseHandlerUtils::resizeRectFromEdgeCentered(originalSize, anchor_pt, move_pt, npos, bounds, maintainAspect);
+  } else { //resizing from corner.
+    return KstGfxMouseHandlerUtils::resizeRectFromCornerCentered(originalSize, npos, bounds, maintainAspect);
+  }
 }
 
 
@@ -836,7 +855,7 @@
   //centered resize means that the center of the object stays constant
   const QRect old(_prevBand);
   
-  _prevBand = newSizeCentered(_pressTarget->geometry(), _pressTarget->_parent->geometry(), pos, maintainAspect);
+  _prevBand = newSizeCentered(_pressTarget->geometry(), _pressTarget->_parent->geometry(), _pressDirection, pos, maintainAspect);
 
   if (_prevBand != old) {
     KstPainter p;
--- branches/work/kst/1.5/kst/src/libkstapp/ksttoplevelview.h #660201:660202
@@ -126,7 +126,7 @@
     bool popupMenu(KPopupMenu *menu, const QPoint& pos);
     void correctPosition(KstViewObjectPtr pObject, QPoint point);
     QRect newSize(const QRect& originalSize, const QRect& bounds, int direction, const QPoint& pos, bool maintainAspect = false);
-    QRect newSizeCentered(const QRect& oldSize, const QRect& bounds, const QPoint& pos, bool maintainAspect);
+    QRect newSizeCentered(const QRect& oldSize, const QRect& bounds, int direction, const QPoint& pos, bool maintainAspect);
     QRect correctWidthForRatio(const QRect& oldRect, double ratio, int direction);
     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;
--- branches/work/kst/1.5/kst/src/libkstapp/kstviewellipse.cpp #660201:660202
@@ -185,8 +185,8 @@
 
 signed int KstViewEllipse::directionFor(const QPoint& pos) {
   signed int direction = KstViewObject::directionFor(pos);
-  if (!(((direction & (UP|DOWN)) == 0) || ((direction & (LEFT|RIGHT)) == 0))) {    
-    // not an edge
+
+  if (direction != 0) {
     direction |= CENTEREDRESIZE;  
   }
   return direction;