Here is a sample code to illustrate the problem
Code: Select all
EnableExplicit
#canvasWidth = 1000
#canvasHeight = 1000
#viewportScrollStep = 10
#objectWidth = 100
#objectHeight = 50
#mainWidth = 400
#mainHeight = 300
Enumeration
#main
#viewport
#canvas
EndEnumeration
Structure Object
x.i
y.i
img.i
EndStructure
Global objectBeingDragged, currentObject
Global deltaX, deltaY, mouseX, mouseY
Global NewList objects.Object()
Procedure LoadCanvas()
ScrollAreaGadget(#viewport, 0,0, #mainWidth, #mainHeight,
#canvasWidth, #canvasHeight,
#viewportScrollStep, #PB_ScrollArea_BorderLess | #PB_ScrollArea_Center)
CanvasGadget(#canvas, 0, 0, #canvasWidth, #canvasHeight)
CloseGadgetList()
SetGadgetAttribute(#viewport, #PB_ScrollArea_X, (#canvasWidth-GadgetWidth(#viewport))/2)
SetGadgetAttribute(#viewport, #PB_ScrollArea_Y, (#canvasHeight-GadgetHeight(#viewport))/2)
EndProcedure
Procedure RefreshCanvas()
StartDrawing(CanvasOutput(#canvas))
Box(0, 0, #canvasWidth, #canvasHeight, #White)
ForEach objects()
DrawImage(ImageID(objects()\img), objects()\x, objects()\y)
Next
StopDrawing()
EndProcedure
Procedure NewObjectImage()
Protected newImage
newImage = CreateImage(#PB_Any, #objectWidth, #objectHeight)
StartDrawing(ImageOutput(newImage))
DrawingMode(#PB_2DDrawing_Transparent)
Box(0, 0, #objectWidth, #objectHeight, RGB(Random(255),Random(255),Random(255)))
Box(2, 2, #objectWidth-4, #objectHeight-4, $CCCCCC)
StopDrawing()
ProcedureReturn newImage
EndProcedure
Procedure ObjectAt(x,y)
currentObject = #False
LastElement(objects())
Repeat
With objects()
If (x >= \x) And (x < \x+#objectWidth) And (y >= \y) And (y < \y+#objectHeight)
deltaX = x - \x
deltaY = y - \y
currentObject = #True
MoveElement(objects(), #PB_List_Last)
ProcedureReturn currentObject
EndIf
EndWith
Until PreviousElement(objects()) = 0
ProcedureReturn currentObject
EndProcedure
Procedure DoMouseLeftClick()
If currentObject
objectBeingDragged = #True
EndIf
RefreshCanvas()
EndProcedure
Procedure DoMouseMove()
mouseX = GetGadgetAttribute(#canvas, #PB_Canvas_MouseX)
mouseY = GetGadgetAttribute(#canvas, #PB_Canvas_MouseY)
If objectBeingDragged
LastElement(objects())
objects()\x = mouseX - deltaX
objects()\y = mouseY - deltaY
RefreshCanvas()
Else
If ObjectAt(mouseX,mouseY)
SetGadgetAttribute(#canvas, #PB_Canvas_Cursor, #PB_Cursor_Hand)
Else
SetGadgetAttribute(#canvas, #PB_Canvas_Cursor, #PB_Cursor_Default)
EndIf
EndIf
EndProcedure
Procedure DoMouseUp()
currentObject = #False
objectBeingDragged = #False
EndProcedure
Procedure NewObject()
AddElement(objects())
objects()\x = (GadgetWidth(#canvas)/2) - (#objectWidth/2)
objects()\y = (GadgetHeight(#canvas)/2) - (#objectHeight/2)
objects()\img = NewObjectImage()
MoveElement(objects(), #PB_List_Last)
RefreshCanvas()
EndProcedure
Procedure CenterObjects()
Protected maxX, maxY, minX, minY, x, y
Protected maxScrollWidthValue, maxScrollHeightValue, scrollPosX, scrollPosY
Protected middlePosX, middlePosY
; Isn't there a cross-platform solution for this?
Protected si.SCROLLINFO
With si
\cbSize = SizeOf(SCROLLINFO)
\fMask = #SIF_PAGE|#SIF_RANGE
EndWith
GetScrollInfo_(GadgetID(#viewport), #SB_HORZ, si)
maxScrollWidthValue = si\nMax - si\nMin + 1 - si\nPage
GetScrollInfo_(GadgetID(#viewport), #SB_VERT, si)
maxScrollHeightValue = si\nMax - si\nMin + 1 - si\nPage
; Find the middlepoint of all objects
minX = #canvasWidth
minY = #canvasHeight
maxX = 0
maxY = 0
ForEach objects()
x = objects()\x + #objectWidth/2
y = objects()\y + #objectHeight/2
If x < minX : minX = x : EndIf
If y < minY : minY = y : EndIf
If x > maxX : maxX = x : EndIf
If y > maxY : maxY = y : EndIf
Next
middlePosX = minX + ((maxX-MinX)/2)
middlePosY = minY + ((maxY-MinY)/2)
; Try to calculate a scrollbar value that would center
; the viewport (scroll area) on the target point (middlePosX, middlePosY)
; located on the canvas gadget...
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
scrollPosX = middlePosX*maxScrollWidthValue/#canvasWidth ;; This does not
scrollPosY = middlePosY*maxScrollHeightValue/#canvasHeight ;; work!
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SetGadgetAttribute(#viewport, #PB_ScrollArea_X, scrollPosX)
SetGadgetAttribute(#viewport, #PB_ScrollArea_Y, scrollPosY)
EndProcedure
Procedure ResizeGadgets()
ResizeGadget(#viewport, #PB_Ignore, #PB_Ignore, WindowWidth(#main), WindowHeight(#main))
RefreshCanvas()
EndProcedure
OpenWindow(#main, 0, 0, #mainWidth, #mainHeight, "Right-click to add, double-click to center objects",
#PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_ScreenCentered)
LoadCanvas()
BindEvent(#PB_Event_SizeWindow, @ResizeGadgets())
BindGadgetEvent(#canvas,@DoMouseLeftClick(),#PB_EventType_LeftButtonDown)
BindGadgetEvent(#canvas,@DoMouseMove(),#PB_EventType_MouseMove)
BindGadgetEvent(#canvas,@DoMouseUP(),#PB_EventType_LeftButtonUp)
BindGadgetEvent(#canvas,@NewObject(),#PB_EventType_RightClick)
BindGadgetEvent(#canvas,@CenterObjects(),#PB_EventType_LeftDoubleClick)
NewObject()
RefreshCanvas()
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
End