Now it is time to add some interactivity to our canvas. We want our users to be able to drag and drop the comic covers around and organize them as they want.
Let’s start with some properties we’ll need on the ABCanvas:
mLastX as integer ' our last X position mLastY as integer ' our last Y position DragElem as ABelement ' the element we're dragging
We are going to use some of the Canvas events to do the mouse handeling, but we still want those events to be available later so we have to declare them:
Event MouseDown(x as integer, y as integer) As boolean Sub () Event MouseDrag(x as integer, y as integer) Sub () Event MouseUp(X as integer, Y as integer) Sub () Event MouseMove(X as integer, Y as integer) Sub ()
Next we need some functions on the ABCanvas to refresh an ABElement, to find an ABElement and to bring this element to the front.
RefreshElement(): this function will refresh only the given element:
Sub RefreshElement(tmpElem as ABElement) Dim iLeft, iTop as Integer ' get the real left and right from our center x and y iLeft = tmpElem.x - tmpElem.w \ 2 iTop = tmpElem.y - tmpElem.h \ 2 ' redraw only me and all other ABElements we are covering DrawMe iLeft,iTop,tmpElem.w,tmpElem.h End Sub
In Tutorial 3 we learned how to find a mousedown in a irriguar shape. For this tutorial we’ll going to use only part of this method in ElementHit(). As all our objects are rectangles and we’ll know their positions we are going to find them the conventional way. To check if we’re in the shadow, we’ll use the method from tutorial 3.
Function ElementHit(x as integer, y as integer) As ABElement
' Find the ABelement hit by the point x,y (if any).
Dim tmpElem As ABElement
Dim i, halfw, halfh As Integer
for i = UBound(MyElements) downTo 0
tmpElem = MyElements(i)
if tmpElem.Visible then
' all ABElements x and y positions are in the center, so we take half the width and height to get the left and top
halfw = tmpElem.w / 2
halfh = tmpElem.h / 2
' Are we within the bounds of this picture?
if Abs(x - tmpElem.x) < halfw and Abs(y - tmpElem.y) < halfh then
' yes we are, but we want it only if our mask is not transparent
if ComicMask.Graphics.Pixel(Abs(x - tmpElem.x + halfw), Abs(y - tmpElem.y + halfh)) = &c000000 then
return tmpElem
end if
end if
end if
next
' nothing found so we return nil
return nil
End Function
And then a function to bring the ABElement to the front if we click on it:
Sub BringToFront(FrontElem as ABelement)
#pragma disableBackgroundTasks
' Bring the given ABElement to the front, so it's drawn on top of all others.
Dim i As Integer
Dim j as integer
Dim maxi as integer
maxi = UBound(MyElements)
' in reverse order
for i = maxi downTo 0
if MyElements(i) = FrontElem then
' Found! Remove it from the list
MyElements.Remove i
' and add it at the end
MyElements.Append FrontElem
Return
end if
next
End Sub
Now we’re ready to add some interactivity to our canvas! Let’s start with changing our mouse cursor if we are above a comic cover. We’ll use the MouseMove() event of the canvas for this
Sub MouseMove(X As Integer, Y As Integer)
' if we are above one of our Elements, we change the mouse cursor to a little hand
if ElementHit(X,Y) <> nil then
self.MouseCursor = System.Cursors.FingerPointer
else
self.MouseCursor = System.Cursors.StandardPointer
end if
' continue with the default MouseMove event
MouseMove X,Y
End Sub
Done! Let’s grab the cover and drag it a little around.
We start in the MouseDown() event of the canvas. We’ll search if we have hit an ABElement. If so we’ll remember our position, bring it to the front and set the DragElem to the found element:
Function MouseDown(X As Integer, Y As Integer) As Boolean
Dim tmpElem as ABElement
tmpElem = ElementHit(X,Y)
if tmpElem <> nil then
' remember our current position
mLastX = X
mLastY = Y
' bring the found ABelement to the front
BringToFront tmpElem
' refresh the element so it is redrawn
RefreshElement tmpElem
' remember this ABElement so we can drag it around
DragElem = tmpElem
Return true
end if
' continue with the default MouseDown event
return MouseDown(X,Y)
End Function
In the MouseDrag() event we’ll redraw our ABElement to the position of the cursor. Here a couple of things that need to happen:
- If our current position = our previous position, don’t redraw
- We add some extra pixels around the object to prevent ‘trailing’
- We calculate our new position
- As we draw our element to its new position, we also have to redraw the background and other objects on the old position.
- We remember our current position for the next pass
Sub MouseDrag(X As Integer, Y As Integer)
#pragma disableBackgroundTasks
if DragElem <> nil then
if mLastX = X and mLastY = Y then
' no need to redraw, it is the same position as before
Return
end if
Dim oldX, oldY, newX, newY, fullLeft, fullTop, fullWidth, fullHeight as integer
Dim Extra as integer
' we add some extra pixels around the object when we redraw because otherwise we sometimes ge a 'trail'
Extra = 5
' we remember the old position
oldX = DragElem.X
oldY = DragElem.Y
' calculate the new position
newX = oldX + X - mLastX
newY = oldY + Y - mLastY
' Find the union between the old and the new position
fullLeft = Min(oldX,newX) - DragElem.w \ 2 - Extra
fullTop = Min(oldY,newY) - DragElem.h \ 2 - Extra
fullWidth = Max(oldX,newX) - DragElem.w \ 2 + DragElem.w - fullLeft + Extra * 2
fullHeight = Max(oldY,newY) - DragElem.h \ 2 + DragElem.h - fullTop + Extra * 2
' set our new position
DragElem.X = newX
DragElem.Y = newY
' redraw only what is needed
DrawMe fullLeft, fullTop, fullWidth, fullHeight
' remember the last mouse position
mLastX = X
mLastY = Y
end if
' continue with the default MouseDrag event
MouseDrag X,Y
End Sub
And last we handle the mouse up. Just to be sure, we do a last redraw of our element and we set the DragElem back to nil.
Sub MouseUp(X As Integer, Y As Integer)
if DragElem <> nil then
' refresh one last time so we have the very last position
RefreshElement DragElem
' set our DragElem to nothing
DragElem = Nil
end if
' continue with the default MouseUp event
MouseUp X,Y
End Sub
Ok, Let us run our program! We should be able to see by the mouse cursor if we’re above an Element. If we click on it, it will jump to the front and we can drag it around. A lot of stuff happended in this tutorial so if you have questions or suggestions, please leave a message.
Here is a small video to show what we made:
In our next lesson we’ll expand a little what we have learned so far so that we can play around with multiple types of objects.
Source code for this tutorial: http://www.gorgeousapps.com/Tut4.zip
Happy programming!


if you like my work











