[RESOLVED] Resizing a shape - how to implement MinimumSize?
Hi,
I am creating a simple shape editor, much like the Visual Studio form designer. You can create shapes, select them and move/resize them using drag handles just like in Visual Studio or most other applications (Visio, etc).
I have run into some problems trying to implement a MinimumSize property for the shapes.
First of all, this is how I'm resizing the shapes. Each shape has a Resize method, accepting two integers (dx and dy) that represent how much the shape must resize by, and one 'HitStatus', which determines in which direction the resize must take place (for example, from the TopLeft, or Bottom, or BottomRight, etc..)
What it does basically is use a large Select Case statement for the hit status. In each case, it changes the Bounds property of the shape (which determines the location and size), so that it is resized:
vb.net Code:
Public Sub Resize(ByVal hitStatus As HitStatus, ByVal dx As Integer, ByVal dy As Integer)
Dim newBounds As Rectangle = Me.Bounds
Select Case hitStatus
Case HitStatus.TopLeft
newBounds = New Rectangle(newBounds.X + dx,
newBounds.Y + dy,
newBounds.Width - dx,
newBounds.Height - dy)
Case HitStatus.Bottom
newBounds = New Rectangle(newBounds.X,
newBounds.Y,
newBounds.Width,
newBounds.Height + dy)
'etc, for all sides
End Select
Me.Bounds = newBounds
End Sub
This method is called in the OnMouseMove override of the 'canvas panel' that the shapes live in:
vb.net Code:
Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
MyBase.OnMouseMove(e)
If mouseDown Then
If Me.SelectedShape IsNot Nothing Then
If hitStatus = Shape.HitStatus.Drag Then 'we are dragging
Me.SelectedShape.Move(e.X - moveStart.X, e.Y - moveStart.Y)
moveStart = e.Location
ElseIf hitStatus <> Shape.HitStatus.None Then 'we are resizing
Me.SelectedShape.Resize(hitStatus, e.X - resizeStart.X, e.Y - resizeStart.Y)
resizeStart = e.Location
End If
End If
End If
End Sub
Using this code, I can resize the shapes from every direction.
Now on to the problem... I want to implement a MinimumSize, so that the shape cannot be resized any smaller than that.
Naively, I thought I could simply check, in the Resize method, whether the new bounds were smaller then the minimum, and if they were, I 'reset' them to the minimum. I accomplished that 'cleverly' using the Math.Max method:
vb.net Code:
newBounds.Height = Math.Max(Me.MinimumSize.Height, newBounds.Height)
newBounds.Width = Math.Max(Me.MinimumSize.Width, newBounds.Width)
Me.Bounds = newBounds
But, this does not work properly... Yes, it does keep me from making the shape any smaller, but if I keep 'trying' (by moving the mouse further still), I get some strange behavior. It's a little hard to explain, so I made a little video of it:
http://www.youtube.com/watch?v=gPg8ZK2KJI8
In the first few seconds you can see me dragging + resizing from the bottom right corner, works fine. Then, I hit the minimum size, but I keep moving the mouse upwards (button still held down).
When I then move the mouse back to the bottom-right, the strange behavior occurs: the shape starts resizing even though I'm nowhere near the corner! If you try resizing a control in VS that way, you will see that it only starts to grow bigger again after the mouse has passed the corner.
I think this issue has to do with me resetting the resizeStart field after resizing. Should I only do that if the resize 'succeeded' (did not result in a too small shape), or something..?
Also, after that, I resize the shape from the left side. If I make it bigger, no problems. But then I make it smaller and hit the minimum size. The shape starts moving to the right..! That's obviously not what I had in mind :)
The reason why this happens is clear to me: newBounds is shifted to the right, while also growing smaller in size (correct). But after the Select Case statement, the size is reset to the minimum size. But, the bounds are still shifted! So I need to shift them back or something...?
Can anyone see how I can solve these issues? Any examples on resizing shapes or anything? I've tried various methods but my first naive (wrong) approach was the best yet... All others resulted in even stranger behavior!
Re: Resizing a shape - how to implement MinimumSize?
Implement some Boolean flags to determine if we're resizing? Somewhere, some logic is not clicking that is causing it to move. Perhaps when the minimum size is hit, you lock the control from moving period until you aren't resizing it?
Re: Resizing a shape - how to implement MinimumSize?
You are referring to the second problem I think, that the shape moves to the right when I resize it from the left? That problem is caused by the way I implement the resizing. For resizing from the left, I set the new bounds as such:
Code:
newBounds = New Rectangle(newBounds.X + dx,
newBounds.Y,
newBounds.Width - dx,
newBounds.Height)
As you can see, I add "dx" to the X coordinate, and subtract dx from the width. If I would only contract the width (Width - dx), then it would resize from the right, because that's just how Rectangles are defined in .NET (with the upper-left corner). So, in addition to making the Width smaller, I also have to move it (the same amount) to the right, so that it appears to resize from the left.
It's this moving that is causing the problem. After this code, I check if the new width is less than the minimum, and if it is I set the new width to the minimum. But the move to the right is not affected by that, so it still moves without resizing further.
I've found a slightly better solution to this second problem. Instead of using the two Math.Max lines, I use
Code:
If newBounds.Height < Me.MinimumSize.Height Then
newBounds.Height = Me.MinimumSize.Height 'reset height
newBounds.Y = Me.Bounds.Y 'reset location
End If
If newBounds.Width < Me.MinimumSize.Width Then
newBounds.Width = Me.MinimumSize.Width 'reset height
newBounds.X = Me.Bounds.X 'reset location
End If
Now, I can no longer move the shape by resizing, but it doesn't seem smooth anymore. If I repeatedly try resizing the shape smaller than the minimum, it actually moves slightly to the left, so it seems to jump a little... Still not good :(
There has to be some kind of example or something on this, don't you think? There's so many applications that make use of exactly this... Some that come to mind: basically all Office products, Visual Studio, photoshop, etc...
Perhaps I'll take a look at the source of that free .NET GUI (SharpDevelop or something?) if I can find something in there...
Re: [RESOLVED] Resizing a shape - how to implement MinimumSize?
Well nevermind, it's resolved after I posted this in a different forum. Apparently my method of using dx and dy (the difference between new and old mouse positions) to determine the new bounds is flawed. I should be using simply the actual x and y values of the mouse location. The Resize method changes quite a lot but it works just fine now :)
Thanks for reading and the input anyway.