move/drag canvas image

Just starting out? Need help? Post your questions and find answers here.
User avatar
J. Baker
Addict
Addict
Posts: 2181
Joined: Sun Apr 27, 2003 8:12 am
Location: USA
Contact:

move/drag canvas image

Post 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
www.posemotion.com

PureBasic Tools for OS X: PureMonitor, plist Tool, Data Maker & App Chef


Even the vine knows it surroundings but the man with eyes does not.
User avatar
Demivec
Addict
Addict
Posts: 4260
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: move/drag canvas image

Post 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?
User avatar
flaith
Enthusiast
Enthusiast
Posts: 704
Joined: Mon Apr 25, 2005 9:28 pm
Location: $300:20 58 FC 60 - Rennes
Contact:

Re: move/drag canvas image

Post 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 
“Fear is a reaction. Courage is a decision.” - WC
User avatar
J. Baker
Addict
Addict
Posts: 2181
Joined: Sun Apr 27, 2003 8:12 am
Location: USA
Contact:

Re: move/drag canvas image

Post 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?
www.posemotion.com

PureBasic Tools for OS X: PureMonitor, plist Tool, Data Maker & App Chef


Even the vine knows it surroundings but the man with eyes does not.
User avatar
J. Baker
Addict
Addict
Posts: 2181
Joined: Sun Apr 27, 2003 8:12 am
Location: USA
Contact:

Re: move/drag canvas image

Post 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?
www.posemotion.com

PureBasic Tools for OS X: PureMonitor, plist Tool, Data Maker & App Chef


Even the vine knows it surroundings but the man with eyes does not.
Zach
Addict
Addict
Posts: 1675
Joined: Sun Dec 12, 2010 12:36 am
Location: Somewhere in the midwest
Contact:

Re: move/drag canvas image

Post 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
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: move/drag canvas image

Post 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)
User avatar
J. Baker
Addict
Addict
Posts: 2181
Joined: Sun Apr 27, 2003 8:12 am
Location: USA
Contact:

Re: move/drag canvas image

Post by J. Baker »

Now that's a treat! Thanks Danilo! ;)
www.posemotion.com

PureBasic Tools for OS X: PureMonitor, plist Tool, Data Maker & App Chef


Even the vine knows it surroundings but the man with eyes does not.
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: move/drag canvas image

Post 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
DE AA EB
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: move/drag canvas image

Post 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
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: move/drag canvas image

Post by Danilo »

wilbert wrote:For the HitTest procedure, you could also use MoveElement
Even better, thanks! :)
User avatar
flaith
Enthusiast
Enthusiast
Posts: 704
Joined: Mon Apr 25, 2005 9:28 pm
Location: $300:20 58 FC 60 - Rennes
Contact:

Re: move/drag canvas image

Post 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
“Fear is a reaction. Courage is a decision.” - WC
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: move/drag canvas image

Post 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
Little John
Addict
Addict
Posts: 4777
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: move/drag canvas image

Post 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
User avatar
Demivec
Addict
Addict
Posts: 4260
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: move/drag canvas image

Post by Demivec »

Great code! Thanks to each of you. :)
Post Reply