Page 1 of 3

move/drag canvas image

Posted: Tue Mar 26, 2013 5:20 am
by J. Baker
I'm not familiar with the canvas gadget at all. I feel like I'm missing or overlooking needed info. Any help would be great.

Code: Select all

LoadImage(0, #PB_Compiler_Home + "Examples/Sources/Data/PureBasic.bmp")

If OpenWindow(0, 0, 0, 420, 420, "Move/Drag Canvas Image", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    CanvasGadget(0, 10, 10, 400, 400)
    
    SetGadgetAttribute(0, #PB_Canvas_Image, ImageID(0))
    
    Repeat
      Event = WaitWindowEvent()
          
      If Event = #PB_Event_Gadget And EventGadget() = 0 
        
        ;code to move a canvas image by dragging it with the mouse
        
      EndIf    
      
    Until Event = #PB_Event_CloseWindow
EndIf

Re: move/drag canvas image

Posted: Tue Mar 26, 2013 5:28 am
by Demivec
J. Baker wrote:I'm not familiar with the canvas gadget at all. I feel like I'm missing or overlooking needed info. Any help would be great.

Code: Select all

;code to move a canvas image by dragging it with the mouse
Did you want to drag the canvas or reposition the image on the canvas?

Re: move/drag canvas image

Posted: Tue Mar 26, 2013 5:32 am
by flaith
Start of a code :

Code: Select all

LoadImage(0, #PB_Compiler_Home + "Examples/Sources/Data/PureBasic.bmp")

If OpenWindow(0, 0, 0, 420, 420, "Move/Drag Canvas Image", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    CanvasGadget(0, 10, 10, 400, 400)
   
    SetGadgetAttribute(0, #PB_Canvas_Image, ImageID(0))
   
    Repeat
      Event = WaitWindowEvent()
         
      If Event = #PB_Event_Gadget And EventGadget() = 0
         Select EventType()
            Case #PB_EventType_LeftButtonDown
              StartDrawing(CanvasOutput(0))
                _x = GetGadgetAttribute(0, #PB_Canvas_MouseX)
                _y = GetGadgetAttribute(0, #PB_Canvas_MouseY)
              StopDrawing()
              Drag = #True
            Case #PB_EventType_LeftButtonUp
              Drag = #False
            Case #PB_EventType_MouseMove
              If Drag = #True
              ; Code to move an image
              EndIf       
      EndIf   
     
    Until Event = #PB_Event_CloseWindow
EndIf 

Re: move/drag canvas image

Posted: Tue Mar 26, 2013 5:33 am
by J. Baker
Demivec wrote:
J. Baker wrote:I'm not familiar with the canvas gadget at all. I feel like I'm missing or overlooking needed info. Any help would be great.

Code: Select all

;code to move a canvas image by dragging it with the mouse
Did you want to drag the canvas or reposition the image on the canvas?
Well, eventually, there will be multiple images on the canvas. I just can not figure out how to reposition them with a mouse?

Re: move/drag canvas image

Posted: Tue Mar 26, 2013 5:42 am
by J. Baker
flaith wrote:Start of a code :

Code: Select all

LoadImage(0, #PB_Compiler_Home + "Examples/Sources/Data/PureBasic.bmp")

If OpenWindow(0, 0, 0, 420, 420, "Move/Drag Canvas Image", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    CanvasGadget(0, 10, 10, 400, 400)
   
    SetGadgetAttribute(0, #PB_Canvas_Image, ImageID(0))
   
    Repeat
      Event = WaitWindowEvent()
         
      If Event = #PB_Event_Gadget And EventGadget() = 0
         Select EventType()
            Case #PB_EventType_LeftButtonDown
              StartDrawing(CanvasOutput(0))
                _x = GetGadgetAttribute(0, #PB_Canvas_MouseX)
                _y = GetGadgetAttribute(0, #PB_Canvas_MouseY)
              StopDrawing()
              Drag = #True
            Case #PB_EventType_LeftButtonUp
              Drag = #False
            Case #PB_EventType_MouseMove
              If Drag = #True
              ; Code to move an image
              EndIf       
      EndIf   
     
    Until Event = #PB_Event_CloseWindow
EndIf 
Yes it is a start and thanks but it's not helping much here?

Re: move/drag canvas image

Posted: Tue Mar 26, 2013 7:27 am
by Zach
You probably want to trigger a redraw of the image you are painting to the canvas?

Sounds horribly inefficient though, but you would handle all the images being painted onto the image you are painting on the canvas (Image 0), interally, as separate images. Then treat the image you are displaying on the canvas gadget (Image 0)as the "surface". So when you redraw the images to that surface, change their X/Y locations within that surface image?

As for the specifics of manipulating and copying other images onto each other in that manner, I of course have 0 input..

Surely someone knows of a better idea than that though

Re: move/drag canvas image

Posted: Tue Mar 26, 2013 7:47 am
by Danilo
J. Baker wrote:Well, eventually, there will be multiple images on the canvas. I just can not figure out how to reposition them with a mouse?
Simple example, started with flaith's code:

Code: Select all

Structure canvasitem
    img.i : x.i : y.i : width.i : height.i
EndStructure

Global isCurrentItem = #False
Global currentItemXOffset.i, currentItemYOffset.i

Global NewList Images.canvasitem()

Procedure AddImage(x,y,img)
    If AddElement(Images())
        Images()\img    = img
        Images()\x      = x
        Images()\y      = y
        Images()\width  = ImageWidth(img)
        Images()\height = ImageHeight(img)
    EndIf
EndProcedure

Procedure DrawCanvas()
    If StartDrawing(CanvasOutput(0))
        Box(0,0,GadgetWidth(0),GadgetHeight(0),RGB(255,255,255))
        ForEach Images()
            DrawImage(ImageID(Images()\img),Images()\x,Images()\y) ; draw all images with z-order
        Next
        StopDrawing()
    EndIf
EndProcedure

Procedure HitTest(x,y)
    If LastElement(Images()) ; search for hit, starting from end (z-order)
        Repeat
            If x >= Images()\x And x <  Images()\x + Images()\width
                If y >= Images()\y And y < Images()\y + Images()\height
                    match = #True
                    Break
                EndIf
            EndIf
        Until PreviousElement(Images())=0
    EndIf
    If match
        isCurrentItem = #True
        currentItemXOffset = x - Images()\x
        currentItemYOffset = y - Images()\y
        temp.canvasitem = Images()
        DeleteElement(Images())
        LastElement(Images()) ; move match to last position (z-order)
        AddElement(Images())
        Images() = temp
    Else
        isCurrentItem = #False
    EndIf
    ProcedureReturn isCurrentItem
EndProcedure

AddImage(10,10,LoadImage(#PB_Any, #PB_Compiler_Home + "Examples/Sources/Data/PureBasic.bmp"))
AddImage(100,100,LoadImage(#PB_Any, #PB_Compiler_Home + "Examples/Sources/Data/GeeBee2.bmp"))
AddImage(50,200,LoadImage(#PB_Any, #PB_Compiler_Home + "Examples/Sources/Data/AlphaChannel.bmp"))

If OpenWindow(0, 0, 0, 420, 420, "Move/Drag Canvas Image", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    CanvasGadget(0, 10, 10, 400, 400)
    
    DrawCanvas()
    
    Repeat
      Event = WaitWindowEvent()
         
      If Event = #PB_Event_Gadget And EventGadget() = 0
         Select EventType()
            Case #PB_EventType_LeftButtonDown
              x = GetGadgetAttribute(0, #PB_Canvas_MouseX)
              y = GetGadgetAttribute(0, #PB_Canvas_MouseY)
              If HitTest(x,y)
                  DrawCanvas()
              EndIf
              Drag = #True
            Case #PB_EventType_LeftButtonUp
              Drag = #False
            Case #PB_EventType_MouseMove
              If Drag = #True
                If isCurrentItem
                  x = GetGadgetAttribute(0, #PB_Canvas_MouseX)
                  y = GetGadgetAttribute(0, #PB_Canvas_MouseY)
                  If LastElement(Images())
                      Images()\x = x - currentItemXOffset
                      Images()\y = y - currentItemYOffset
                      DrawCanvas()
                  EndIf
                EndIf
              EndIf
          EndSelect
      EndIf   
     
    Until Event = #PB_Event_CloseWindow
EndIf
With many images you may want to add some buffering, so you don't need to redraw all images on every little mouse move.
(Background buffer image with all images but the topmost one + 1 active/topmost image)

Re: move/drag canvas image

Posted: Tue Mar 26, 2013 8:12 am
by J. Baker
Now that's a treat! Thanks Danilo! ;)

Re: move/drag canvas image

Posted: Tue Mar 26, 2013 8:46 am
by davido
J. Baker: Thank you for asking this question. I was just thinking how I might achieve this the other day.

Also thanks to flaith & Danilo for the solution.

You guys have just made my day - thanks again. :D

Re: move/drag canvas image

Posted: Tue Mar 26, 2013 11:46 am
by wilbert
Nice code Danilo. :D
For the HitTest procedure, you could also use MoveElement

Code: Select all

Procedure HitTest(x,y)
  isCurrentItem = #False
  If LastElement(Images()) ; search for hit, starting from end (z-order)
    Repeat
      If x >= Images()\x And x < Images()\x + Images()\width
        If y >= Images()\y And y < Images()\y + Images()\height
          MoveElement(Images(), #PB_List_Last)
          isCurrentItem = #True
          currentItemXOffset = x - Images()\x
          currentItemYOffset = y - Images()\y
          Break
        EndIf
      EndIf
    Until PreviousElement(Images())=0
  EndIf
  ProcedureReturn isCurrentItem
EndProcedure

Re: move/drag canvas image

Posted: Tue Mar 26, 2013 11:49 am
by Danilo
wilbert wrote:For the HitTest procedure, you could also use MoveElement
Even better, thanks! :)

Re: move/drag canvas image

Posted: Tue Mar 26, 2013 11:53 am
by flaith
:lol: Sorry J. Baker, I just put a quick code just after your thread, didn't had a better one at that time :wink:
And Danilo's code is really good :D

Re: move/drag canvas image

Posted: Tue Mar 26, 2013 12:26 pm
by Danilo
Optional alpha testing for 32bit images (optional last argument in AddImage()):

Code: Select all

Structure canvasitem
    img.i : x.i : y.i : width.i : height.i : alphatest.i
EndStructure

Global isCurrentItem = #False
Global currentItemXOffset.i, currentItemYOffset.i

Global NewList Images.canvasitem()

Procedure AddImage(x,y,img,alphatest=0)
    If AddElement(Images())
        Images()\img    = img
        Images()\x      = x
        Images()\y      = y
        Images()\width  = ImageWidth(img)
        Images()\height = ImageHeight(img)
        Images()\alphatest = alphatest
    EndIf
EndProcedure

Procedure DrawCanvas()
    If StartDrawing(CanvasOutput(0))
        Box(0,0,GadgetWidth(0),GadgetHeight(0),RGB(255,255,255))
        DrawingMode(#PB_2DDrawing_AlphaBlend)
        ForEach Images()
            DrawImage(ImageID(Images()\img),Images()\x,Images()\y) ; draw all images with z-order
        Next
        StopDrawing()
    EndIf
EndProcedure

Procedure HitTest(x,y)
  isCurrentItem = #False
  If LastElement(Images()) ; search for hit, starting from end (z-order)
    Repeat
      If x >= Images()\x And x < Images()\x + Images()\width
        If y >= Images()\y And y < Images()\y + Images()\height
          alpha=255
          If Images()\alphatest And ImageDepth(Images()\img)>31
            If StartDrawing(ImageOutput(Images()\img))
              DrawingMode(#PB_2DDrawing_AlphaChannel)
              alpha = Alpha(Point(x-Images()\x,y-Images()\y)) ; get alpha
              StopDrawing()
            EndIf
          EndIf
          If alpha
            MoveElement(Images(), #PB_List_Last)
            isCurrentItem = #True
            currentItemXOffset = x - Images()\x
            currentItemYOffset = y - Images()\y
            Break
          EndIf
        EndIf
      EndIf
    Until PreviousElement(Images())=0
  EndIf
  ProcedureReturn isCurrentItem
EndProcedure

AddImage(10,10,LoadImage(#PB_Any, #PB_Compiler_Home + "Examples/Sources/Data/PureBasic.bmp"))
AddImage(100,100,LoadImage(#PB_Any, #PB_Compiler_Home + "Examples/Sources/Data/GeeBee2.bmp"))
AddImage(50,200,LoadImage(#PB_Any, #PB_Compiler_Home + "Examples/Sources/Data/AlphaChannel.bmp"))

hole = CreateImage(#PB_Any,100,100,32)
If StartDrawing(ImageOutput(hole))
    DrawingMode(#PB_2DDrawing_AllChannels)
    Box(0,0,100,100,RGBA($00,$00,$00,$00))
    Circle(50,50,48,RGBA($00,$FF,$FF,$FF))
    Circle(50,50,30,RGBA($00,$00,$00,$00))
    StopDrawing()
EndIf

AddImage(170,70,hole,1)

If OpenWindow(0, 0, 0, 420, 420, "Move/Drag Canvas Image", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    CanvasGadget(0, 10, 10, 400, 400)
    
    DrawCanvas()
    
    Repeat
      Event = WaitWindowEvent()
         
      If Event = #PB_Event_Gadget And EventGadget() = 0
         Select EventType()
            Case #PB_EventType_LeftButtonDown
              x = GetGadgetAttribute(0, #PB_Canvas_MouseX)
              y = GetGadgetAttribute(0, #PB_Canvas_MouseY)
              If HitTest(x,y)
                  DrawCanvas()
              EndIf
              Drag = #True
            Case #PB_EventType_LeftButtonUp
              Drag = #False
            Case #PB_EventType_MouseMove
              If Drag = #True
                If isCurrentItem
                  x = GetGadgetAttribute(0, #PB_Canvas_MouseX)
                  y = GetGadgetAttribute(0, #PB_Canvas_MouseY)
                  If LastElement(Images())
                      Images()\x = x - currentItemXOffset
                      Images()\y = y - currentItemYOffset
                      DrawCanvas()
                  EndIf
                EndIf
              EndIf
          EndSelect
      EndIf   
     
    Until Event = #PB_Event_CloseWindow
EndIf

Re: move/drag canvas image

Posted: Tue Mar 26, 2013 2:59 pm
by Little John
Cool, thank you Danilo!

I made some changes to your most recent code:
  • Now there are no global variables anymore (converted to local variables or parameters where possible, otherwise to shared variables).
  • Added EnableExplicit and some variable declarations which were then missing.
  • Made the code more generic: Now any number (not only 0) can be used for the canvas gadget.
  • Tiny cosmetic changes.
But the code works as before. :-)
Thanks again!

Code: Select all

EnableExplicit

Structure canvasitem
   img.i
   x.i
   y.i
   width.i
   height.i
   alphatest.i
EndStructure

Enumeration
   #MyCanvas = 1   ; just to test whether a number different from 0 works now
EndEnumeration

Define isCurrentItem=#False
Define currentItemXOffset.i, currentItemYOffset.i
Define Event.i, x.i, y.i, drag.i, hole.i
NewList Images.canvasitem()


Procedure AddImage (List Images.canvasitem(), x, y, img, alphatest=0)
   If AddElement(Images())
      Images()\img    = img
      Images()\x      = x
      Images()\y      = y
      Images()\width  = ImageWidth(img)
      Images()\height = ImageHeight(img)
      Images()\alphatest = alphatest
   EndIf
EndProcedure

Procedure DrawCanvas (canvas.i, List Images.canvasitem())
   If StartDrawing(CanvasOutput(canvas))
      Box(0, 0, GadgetWidth(canvas), GadgetHeight(canvas), RGB(255,255,255))
      DrawingMode(#PB_2DDrawing_AlphaBlend)
      ForEach Images()
         DrawImage(ImageID(Images()\img),Images()\x,Images()\y) ; draw all images with z-order
      Next
      StopDrawing()
   EndIf
EndProcedure

Procedure.i HitTest (List Images.canvasitem(), x, y)
   Shared currentItemXOffset.i, currentItemYOffset.i
   Protected alpha.i, isCurrentItem.i = #False

   If LastElement(Images()) ; search for hit, starting from end (z-order)
      Repeat
         If x >= Images()\x And x < Images()\x + Images()\width
            If y >= Images()\y And y < Images()\y + Images()\height
               alpha = 255
               If Images()\alphatest And ImageDepth(Images()\img)>31
                  If StartDrawing(ImageOutput(Images()\img))
                     DrawingMode(#PB_2DDrawing_AlphaChannel)
                     alpha = Alpha(Point(x-Images()\x,y-Images()\y)) ; get alpha
                     StopDrawing()
                  EndIf
               EndIf
               If alpha
                  MoveElement(Images(), #PB_List_Last)
                  isCurrentItem = #True
                  currentItemXOffset = x - Images()\x
                  currentItemYOffset = y - Images()\y
                  Break
               EndIf
            EndIf
         EndIf
      Until PreviousElement(Images()) = 0
   EndIf

   ProcedureReturn isCurrentItem
EndProcedure


AddImage(Images(),  10, 10, LoadImage(#PB_Any, #PB_Compiler_Home + "Examples/Sources/Data/PureBasic.bmp"))
AddImage(Images(), 100,100, LoadImage(#PB_Any, #PB_Compiler_Home + "Examples/Sources/Data/GeeBee2.bmp"))
AddImage(Images(),  50,200, LoadImage(#PB_Any, #PB_Compiler_Home + "Examples/Sources/Data/AlphaChannel.bmp"))

hole = CreateImage(#PB_Any,100,100,32)
If StartDrawing(ImageOutput(hole))
   DrawingMode(#PB_2DDrawing_AllChannels)
   Box(0,0,100,100,RGBA($00,$00,$00,$00))
   Circle(50,50,48,RGBA($00,$FF,$FF,$FF))
   Circle(50,50,30,RGBA($00,$00,$00,$00))
   StopDrawing()
EndIf
AddImage(Images(),170,70,hole,1)

If OpenWindow(0, 0, 0, 420, 420, "Move/Drag Canvas Image", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) = 0
   MessageRequester("Fatal error", "Program terminated.")
   End
EndIf

CanvasGadget(#MyCanvas, 10, 10, 400, 400)
DrawCanvas(#MyCanvas, Images())

Repeat
   Event = WaitWindowEvent()
   
   If Event = #PB_Event_Gadget And EventGadget() = #MyCanvas
      Select EventType()
         Case #PB_EventType_LeftButtonDown
            x = GetGadgetAttribute(#MyCanvas, #PB_Canvas_MouseX)
            y = GetGadgetAttribute(#MyCanvas, #PB_Canvas_MouseY)
            isCurrentItem = HitTest(Images(), x, y)
            If isCurrentItem
               DrawCanvas(#MyCanvas, Images())
            EndIf
            Drag = #True
         Case #PB_EventType_LeftButtonUp
            Drag = #False
         Case #PB_EventType_MouseMove
            If Drag = #True
               If isCurrentItem
                  x = GetGadgetAttribute(#MyCanvas, #PB_Canvas_MouseX)
                  y = GetGadgetAttribute(#MyCanvas, #PB_Canvas_MouseY)
                  If LastElement(Images())
                     Images()\x = x - currentItemXOffset
                     Images()\y = y - currentItemYOffset
                     DrawCanvas(#MyCanvas, Images())
                  EndIf
               EndIf
            EndIf
      EndSelect
   EndIf   
Until Event = #PB_Event_CloseWindow

Re: move/drag canvas image

Posted: Tue Mar 26, 2013 5:07 pm
by Demivec
Great code! Thanks to each of you. :)