Page 1 of 1

Selector module; select rectangle on canvas using mouse

Posted: Wed Feb 25, 2015 2:39 am
by BasicallyPure
This module allows you to select an area on a canvas gadget using the mouse.

Once an area has been selected you can move the selection by dragging it.
It can also be resized by dragging the adjustment square in the lower right corner.

You can retrieve an image of the selected area if desired.
Other information about the selection is also available such as x, y coordinates.

I have tested with Windows and Linux.

Usage example follows the module code.

Edit: 6/25/2015
Fixed contrast problem when selecting on a gray background.

Module code.

Code: Select all

; select a rectangular area on a canvas using the mouse.
;
; Filename      : Selector_Module.pbi
; Module name   : Selector
; Author        : BasicallyPure
; original date : 2/24/2015
;
; OS platforms  : cross platform, tested on Windows 7 and Linux
;    
; Compiler      : tested using Windows PureBasic 5.31 (x86),
;               : Linux PureBasic 5.30 (x64)
;
; License       : free
;
; forum topic   : http://www.purebasic.fr/english/viewtopic.php?f=12&t=61736
;
; last revision : 6/25/2015
;
;
; EnableExplicit


DeclareModule Selector
   
   ; Usage:
   ; 1. INITIALIZE_SELECTOR(canvas, scrollArea = -1)
   ;    Call the INITIALIZE_SELECTOR() procedure to activate the selector.
   ;    Repeat a call to INITIALIZE_SELECTOR() if the canvas is resized or when
   ;    switching to another canvas.  If your are using Windows and your canvas
   ;    is inside a ScrollAreaGadget, provide the scroll area number as the
   ;    second parameter in the procedure.
   ;
   ; 2. The following custom events are generated by mouse activity on the canvas gadget.
   ;    a. #SelectionComplete  : when a valid selection has been completed on the canvas.
   ;    b. #SelectionCancelled : when a selection has been cancelled by mouse or program.
   ;    c. #SelectionAltered   : when the selection has been moved or resized.
   ;
   ; 3. Use these additional module procedures in your program as needed.
   ;    a. CANCEL_SELECTION() ; removes an active selection programatically.  Also a selection
   ;       may be automatically cancelled by clicking outside the selection rectangle.
   ;
   ;    b. CAPTURE_SELECTION(image = #PB_Any)
   ;       This procedure creates a new image using the selected area.  If #PB_Any is used or
   ;       the image parameter is omitted the automatically generated image number will be
   ;       returned.  If an image number is provided then the ImageID will be returned.
   ;
   ;    c. DEACTIVATE_SELECTOR() ; the selector feature will be deactivated.
   ;
   ; 4. Global sturctured variable 'Selector::selection\xxx' is available to determine selection
   ;    details; see comments in structure 'SelType' below.
   ;
   
   #MaskPattern = $888888
   
   Enumeration #PB_Event_FirstCustomValue + 47
      #SelectionComplete
      #SelectionCancelled
      #SelectionAltered
   EndEnumeration
   
   Declare CANCEL_SELECTION()
   Declare INITIALIZE_SELECTOR(canvas, scrollArea = -1)
   Declare DEACTIVATE_SELECTOR()
   Declare CAPTURE_SELECTION(image = #PB_Any)
   
   Structure SelType
      canvas.i    ; canvas number or -1 if selector is deactivated
      sFlag.i     ; if #True an area is selected
      left.i      ; left edge 'x' value of selected area
      right.i     ; right edge 'x' value of selected area
      top.i       ; top edge 'y' value of selected area
      bottom.i    ; bottom edge 'y' value of selected area
      limLeft.i   ; left boundary limit of selection area
      limRight.i  ; right boundary limit of selection area
      limTop.i    ; top boundary limit of selection area
      limBottom.i ; bottom boundary limit of selection area
   EndStructure
   
   Global selection.SelType
   selection\canvas = -1
   
EndDeclareModule


Module Selector
   
   Declare SELECT_AREA(canvasEvent)
   Declare MASK_SELECTION_RECTANGLE()
   Declare CANVAS_EVENT_HANDLER()
   
   Global canvas.i, userCursor, scroll, mouseDown
   
   #SelectorCursor = #PB_Cursor_Cross
   
   Enumeration
      #CanvasMouseUP
      #CanvasMouseDown
      #CanvasMouseMove
   EndEnumeration
   
   Procedure INITIALIZE_SELECTOR(canvas, scrollArea = -1)
      ; call this procedure to activate the selector, or
      ; any time the canvas size is changed, or if you switch to
      ; another canvas gadget.  For Windows only, Provide the
      ; scrollArea number if the canvas is inside a ScrollAreaGadget.
      
      Protected result = #False, scrollError = #False
      
      scroll = scrollArea
      If scroll <> -1
         If IsGadget(scroll)
            If GadgetType(scroll) <> #PB_GadgetType_ScrollArea
               scrollError = #True
            EndIf
         Else
            scrollError = #True
         EndIf
      EndIf
      
      If IsGadget(canvas) And scrollError = #False
         If GadgetType(canvas) = #PB_GadgetType_Canvas
            
            With selection
               If canvas <> \canvas
                  
                  userCursor = GetGadgetAttribute(canvas, #PB_Canvas_Cursor)
                  If userCursor <> -1
                     SetGadgetAttribute(canvas,#PB_Canvas_Cursor, #SelectorCursor)
                  EndIf
                  
                  If IsGadget(\canvas)
                     UnbindGadgetEvent(\canvas, @CANVAS_EVENT_HANDLER())
                  EndIf
                  
                  BindGadgetEvent(canvas, @CANVAS_EVENT_HANDLER())
               EndIf
               
               \canvas    = canvas
               \sFlag     = #False
               \left      = 0
               \right     = 0
               \top       = 0
               \bottom    = 0
               \limLeft   = 0
               \limTop    = 0
               \limRight  = GadgetWidth(canvas)
               \limBottom = GadgetHeight(canvas)
            EndWith
            
            mouseDown = #False
            result = #True
         EndIf
      EndIf
      
      If scrollError = #True
         MessageRequester("INITIALIZE_SELECTOR()","Error! Parameter is not a valid ScrollArea number.")
      ElseIf result = #False
         MessageRequester("INITIALIZE_SELECTOR()","Error! Parameter is not a valid canvas number.")
      EndIf
      
      ProcedureReturn result
   EndProcedure

Procedure SELECT_AREA(canvasEvent)
   ; Uses the mouse to select an area on the canvas gadget.
   
   Static.i x, y, lenX, lenY, lastX, lastY, boxSet, drag
   Static.i WIC = #PB_Window_InnerCoordinate
   Protected.i msx, msy, ox, oy
   Protected.i Win = GetActiveWindow()
   
   With selection
      Select canvasEvent
         Case #CanvasMouseDown
            x = WindowMouseX(Win) - GadgetX(\canvas,#PB_Gadget_WindowCoordinate)
            y = WindowMouseY(Win) - GadgetY(\canvas,#PB_Gadget_WindowCoordinate)
            
            If \sFlag
               If boxSet = #True And x > \right-9 And x < \right And y > \bottom-9 And y < \bottom
                  ; adjust the rectangle
                  
                  lastX = \left : lastY = \top : lenX = \right-\left : lenY = \bottom-\top ;<-- added 6/22/15
                  x = lastX
                  y = lastY
                  drag = #False
               ElseIf x > \left And x < \right And y > \top And y < \bottom
                  drag = #True ; drage selection rectangle is active
                  
                  lastX = \left : lastY = \top : lenX = \right-\left : lenY = \bottom-\top ;<-- added 6/22/15
                  
                  ; optional for windows
                  ; moves cursor to center of selected area on mouse button down
                  CompilerIf #PB_Compiler_OS = #PB_OS_Windows
                     
                     If scroll > -1 ; use this if the canvas is inside a ScrollArea gadget
                        ox = \left + Abs(lenX / 2) + WindowX(Win, WIC) + GadgetX(scroll) + 1
                        oy = \top  + Abs(lenY / 2) + WindowY(Win, WIC) + GadgetY(scroll) + 1
                        SetCursorPos_(ox-GetGadgetAttribute(scroll,#PB_ScrollArea_X)+1,
                                      oy-GetGadgetAttribute(scroll,#PB_ScrollArea_Y)+1)
                     Else ; use this if the canvas is NOT inside a ScrollArea gadget
                        ox = \left + Abs(lenX / 2) + WindowX(Win, WIC) + GadgetX(\canvas)
                        oy = \top  + Abs(lenY / 2) + WindowY(Win, WIC) + GadgetY(\canvas)
                        SetCursorPos_(ox,oy)
                     EndIf
                  CompilerEndIf
                  
               Else ; prepare for selection removal on mouse up
                  MASK_SELECTION_RECTANGLE()
                  \sFlag  = #False
                  \left = x : \right  = x
                  \top  = y : \bottom = y
               EndIf
            Else 
               \left = x : \right  = x
               \top  = y : \bottom = y
            EndIf
            
         Case #CanvasMouseMove
            Delay(10)
            If mouseDown
               StartDrawing(CanvasOutput(\canvas))
                  DrawingMode(#PB_2DDrawing_XOr | #PB_2DDrawing_Outlined)
                  
                  If \sFlag = #True ; erase previous selection rectangle
                     Box(lastX,lastY,lenX,lenY,#MaskPattern)
                     DrawingMode(#PB_2DDrawing_XOr)
                     If boxSet = #True
                        boxSet = #False
                        Box(\right - 8, \bottom - 8, 7, 7, #MaskPattern)
                     EndIf
                  Else ; reset the lastX and lastY values
                     \sFlag = #True
                     lastX = x
                     lastY = y
                     boxSet = #False
                  EndIf
                  
                  msx = WindowMouseX(Win) - GadgetX(\canvas,#PB_Gadget_WindowCoordinate)
                  msy = WindowMouseY(Win) - GadgetY(\canvas,#PB_Gadget_WindowCoordinate)
                  
                  ; check if mouse cursor is in bounds
                  If msx >= \limLeft And msx < \limRight And msy >= \limTop And msy < \limBottom
                     If drag = #False ; calculate size of next selection outline
                        lenX = msx - x
                        lenY = msy - y
                     Else             ; drag the selection outline
                        x = msx - lenX >> 1
                        y = msy - lenY >> 1
                        
                        ; prevent out of bounds dragging
                        If x < \limLeft : x = \limLeft : EndIf ; check left side
                        If y < \limTop  : y = \limTop  : EndIf ; check top side
                        If x > \limRight -1 - lenX             ; check right side
                           x = \limRight -1 - lenX
                        EndIf
                        If y > \limBottom -1 - lenY ; check bottom side
                           y = \limBottom -1 - lenY
                        EndIf
                     EndIf
                  EndIf
                  
                  ; draw the selection rectangle
                  DrawingMode(#PB_2DDrawing_XOr | #PB_2DDrawing_Outlined)
                  Box(x,y,lenX,lenY,#MaskPattern)
                  
                  lastX = x
                  lastY = y
               StopDrawing()
               
               \left   = x
               \top    = y
               \right  = x + lenX
               \bottom = y + lenY
               
               PostEvent(#SelectionAltered)
            EndIf
            
         Case #CanvasMouseUP ; mouse button was released
            drag = #False
            
            If \left > \right ; fix left/right crossover
               Swap \left, \right : x + lenX : lastX = x : lenX * -1
            EndIf
            
            If \top > \bottom ; fix top/bottom crossover
               Swap \top, \bottom : y + lenY : lastY = y : lenY * -1
            EndIf
            
            If \left = \right And \top = \bottom ; single point so no selection
               \sFlag = #False
               boxSet = #False
               PostEvent(#SelectionCancelled)
            Else ; a valid selection has been made
                 ; draw the selection resize box
               If boxSet = #False
                  StartDrawing(CanvasOutput(\canvas))
                     DrawingMode(#PB_2DDrawing_XOr)
                     Box(\right - 8, \bottom - 8, 7, 7, #MaskPattern)
                  StopDrawing()
                  boxSet = #True
               EndIf
               PostEvent(#SelectionComplete) ; custom event
            EndIf
            
      EndSelect
   EndWith
   
EndProcedure

Procedure MASK_SELECTION_RECTANGLE()
   ; toggle, hide or unhide the selection rectangle
   
   With selection
      If \sFlag
         StartDrawing(CanvasOutput(\canvas))
            DrawingMode(#PB_2DDrawing_XOr | #PB_2DDrawing_Outlined)
            Box(\left, \top, \right-\left, \bottom-\top, #MaskPattern)
            DrawingMode(#PB_2DDrawing_XOr)
            Box(\right - 8, \bottom - 8, 7, 7, #MaskPattern)
         StopDrawing()
      EndIf
   EndWith
   
EndProcedure

Procedure CANCEL_SELECTION()
   ; erase the selection rectangle
   With selection
      If \sFlag
         MASK_SELECTION_RECTANGLE()
         \sFlag  = #False
         \top    = \bottom
         \left   = \right
         PostEvent(#SelectionCancelled)
      EndIf
   EndWith
   
EndProcedure

Procedure CAPTURE_SELECTION(image = #PB_Any)
   ; creates an image of the selected canvas area
   ; image: the image number to create or #PB_Any (default)
   ; Returns the ImageID(img) Or the automatically
   ; generated image number if #PB_Any is used.
   
   With selection
      MASK_SELECTION_RECTANGLE() ; temporarily hide the rectangle
      
      StartDrawing(CanvasOutput(\canvas))
         image = GrabDrawingImage(image,\left,\top,\right - \left + 1,\bottom - \top + 1)
      StopDrawing()
      
      MASK_SELECTION_RECTANGLE() ; restore the rectangle
   EndWith
   
   ProcedureReturn image
EndProcedure

Procedure DEACTIVATE_SELECTOR()
   With selection
      If \canvas <> -1
         UnbindGadgetEvent(\canvas, @CANVAS_EVENT_HANDLER())
         If \sFlag : CANCEL_SELECTION() : EndIf
         
         If userCursor <> -1
            SetGadgetAttribute(\canvas,#PB_Canvas_Cursor, userCursor)
         EndIf
         
         \canvas = -1
      EndIf
   EndWith
EndProcedure

Procedure CANVAS_EVENT_HANDLER()
   Select EventType()
      Case #PB_EventType_LeftButtonDown
         mouseDown = #True
         SELECT_AREA(#CanvasMouseDown)
      Case #PB_EventType_LeftButtonUp
         mouseDown = #False
         SELECT_AREA(#CanvasMouseUP)
      Case #PB_EventType_MouseMove
         SELECT_AREA(#CanvasMouseMove)
   EndSelect
EndProcedure
   
   
EndModule
Usage example.

Code: Select all

; demo program for 'Selector_Module.pbi'
; Author: BasicallyPure
; 2/24/2015

EnableExplicit

XIncludeFile "Selector_Module.pbi"
;UseModule Selector

UseJPEGImageDecoder()
UsePNGImageDecoder()

Declare UPDATE_STATUS()
Declare DISPLAY_SELECTION()
Declare REMOVE_DISPLAY()
Declare LOAD_IMAGE()
Declare CANVAS_CALLBACK()

#WinMain = 0
#WinShow = 1

#StatusBar = 0
#DispImg = 1
#Font = 1

; gadgets
Enumeration
   #ScrollArea
   #Canvas
   #ButtonCancel
   #ButtonDeactivate
   #ButtonActivate
EndEnumeration

If OpenWindow(#WinMain,0,0,770,500,"Rectangle Selector Demo",
       #PB_Window_ScreenCentered | #PB_Window_SystemMenu) = 0
   End
EndIf

;{- build GUI
LoadFont(#Font,"Arial",10)
SetGadgetFont(#PB_Default, FontID(#Font))

CreateStatusBar(#StatusBar,WindowID(#WinMain))
AddStatusBarField(#PB_Ignore)
AddStatusBarField(#PB_Ignore)
AddStatusBarField(#PB_Ignore)
AddStatusBarField(#PB_Ignore)
AddStatusBarField(#PB_Ignore)
AddStatusBarField(#PB_Ignore)
AddStatusBarField(#PB_Ignore)

ResizeWindow(#WinMain,#PB_Ignore,#PB_Ignore,#PB_Ignore,WindowHeight(#WinMain)+StatusBarHeight(#StatusBar))

ScrollAreaGadget(#ScrollArea,120,10,644,484,640,480)
CanvasGadget(#Canvas,0,0,640,480,#PB_Canvas_ClipMouse)
CloseGadgetList()
SetGadgetAttribute(#Canvas,#PB_Canvas_Cursor,#PB_Cursor_Hand)

BindGadgetEvent(#Canvas,@CANVAS_CALLBACK())

StartDrawing(CanvasOutput(#Canvas))
   Box(0,0,640,480,$B8CE8C)
   DrawText(10,10,"Right click to load image",0,$B8CE8C)
   DrawText(10,30,"Left click and drag mouse to select area"   ,0,$B8CE8C)
   DrawText(10,50,"To cancel selection, click outside selected",0,$B8CE8C)
   DrawText(10,70,"rectangle or use 'Cancel' button at left" ,0,$B8CE8C)
StopDrawing()

ButtonGadget(#ButtonDeactivate,10,070,100,50,"DEACTIVATE SELECTOR",#PB_Button_MultiLine)
ButtonGadget(#ButtonActivate  ,10,010,100,50,"ACTIVATE SELECTOR"  ,#PB_Button_MultiLine)
ButtonGadget(#ButtonCancel    ,10,130,100,50,"CANCEL SELECTION"   ,#PB_Button_MultiLine)
DisableGadget(#ButtonDeactivate,1)
DisableGadget(#ButtonCancel,1)
;}

;{- event loop
Repeat
   Select WaitWindowEvent()
      Case #PB_Event_CloseWindow : Break
      Case #PB_Event_RightClick  : LOAD_IMAGE()
         
      ; *** custom module events ***
      Case Selector::#SelectionComplete    : DISPLAY_SELECTION() : UPDATE_STATUS()
      Case Selector::#SelectionCancelled   : REMOVE_DISPLAY()    : UPDATE_STATUS()
      Case Selector::#SelectionAltered     : UPDATE_STATUS()
      ; *** end custom events ***
      
      Case #PB_Event_Gadget
         Select EventGadget()
            Case #ButtonCancel
               Selector::CANCEL_SELECTION() ; module procedure call
               DISPLAY_SELECTION()
               
            Case #ButtonDeactivate
               Selector::DEACTIVATE_SELECTOR() ; module procedure call
               DisableGadget(#ButtonDeactivate,1)
               DisableGadget(#ButtonActivate,0)
               UPDATE_STATUS()
            Case #ButtonActivate
               Selector::INITIALIZE_SELECTOR(#Canvas, #ScrollArea) ; module procedure call
               DisableGadget(#ButtonActivate,1)
               DisableGadget(#ButtonDeactivate,0)
               UPDATE_STATUS()
         EndSelect
   EndSelect
ForEver
;}

End

Procedure UPDATE_STATUS()
   ; update the information displayed in the status bar
   Protected text.s, lenX.i, lenY.i, i.i
   
   With Selector::selection
      lenX = \right - \left + 1
      lenY = \bottom - \top + 1
      
      If IsStatusBar(#StatusBar)
         If \canvas <> -1
            StatusBarText(#StatusBar,0,"Size = " + Str(lenX) + " x " + Str(lenY))
            StatusBarText(#StatusBar,1,"x/y ratio = " + StrF(lenX / lenY,5))
            StatusBarText(#StatusBar,2,"x_Left = " + Str(\left))
            StatusBarText(#StatusBar,3,"y_Top = " + Str(\top))
            StatusBarText(#StatusBar,4,"x_Right = " + Str(\right))
            StatusBarText(#StatusBar,5,"y_Bottom = " + Str(\bottom))
            If \sFlag : text = "True" : Else : text = "False" : EndIf
            StatusBarText(#StatusBar,6,"Selection = " + text)
         Else
            For i = 0 To 6
               StatusBarText(#StatusBar,i,"")
            Next i
         EndIf
      EndIf
   EndWith
EndProcedure

Procedure DISPLAY_SELECTION()
   Protected w, h
   Static imgGad, image = #DispImg
   
   With Selector::selection
      If \sFlag
         w = \right - \left + 1
         h = \bottom - \top + 1
         
         If IsWindow(#WinShow) = 0
            OpenWindow(#WinShow,20,20,w,h,"selection",#PB_Window_TitleBar|#PB_Window_NoActivate)
            imgGad = ImageGadget(#PB_Any,1,1,w,h,0)
         EndIf
         
         ; capture the image within the selected area
         Selector::CAPTURE_SELECTION(image) ; <--- module procedure call
         
         If IsImage(image)
            SetGadgetState(imgGad,ImageID(image))
            ResizeWindow(#WinShow,#PB_Ignore,#PB_Ignore,w+1,h+1)
         EndIf
         
         DisableGadget(#ButtonCancel,0)
      EndIf
      
   EndWith
   
EndProcedure

Procedure REMOVE_DISPLAY()
   Static image = #DispImg
   
   If IsWindow(#WinShow)
      CloseWindow(#WinShow)
      If IsImage(image) : FreeImage(image) : EndIf
   EndIf
   
   DisableGadget(#ButtonCancel,1)
EndProcedure

Procedure LOAD_IMAGE()
   Protected f$, p$, img
   
   CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      p$ = GetHomeDirectory() + "My Pictures\"
   CompilerElse
      p$ = GetHomeDirectory() + "Pictures/"
   CompilerEndIf
   
   f$ = OpenFileRequester("choose an image",p$,"IMAGES|*.bmp;*.jpeg;*.jpg;*.jpe;*.png",0)
   If f$
      img = LoadImage(#PB_Any,f$)
   EndIf
   
   If img
      With Selector::selection
         
         If \sFlag ; check for active selection
            Selector::CANCEL_SELECTION()
            REMOVE_DISPLAY()
            \left   = 0
            \right  = 0
            \top    = 0
            \bottom = 0
            UPDATE_STATUS()
         EndIf
         
         ResizeGadget(#Canvas,0,0,ImageWidth(img),ImageHeight(img))
         
         ;must do after canvas is resized if selector is active
         If \canvas <> -1
            Selector::INITIALIZE_SELECTOR(#Canvas, #ScrollArea)
         EndIf
         
         SetGadgetAttribute(#ScrollArea,#PB_ScrollArea_InnerWidth,ImageWidth(img))
         SetGadgetAttribute(#ScrollArea,#PB_ScrollArea_InnerHeight,ImageHeight(img))
         
      EndWith
      
      StartDrawing(CanvasOutput(#Canvas))
         DrawImage(ImageID(img),0,0)
      StopDrawing()
   EndIf
   
   CompilerIf #PB_Compiler_OS = #PB_OS_Linux
      While WindowEvent() : Wend
   CompilerEndIf
   
EndProcedure

Procedure CANVAS_CALLBACK()
   ; triggers a '#PB_Event_RightClick' just like
   ; right clicking on the main window.
   If EventType() = #PB_EventType_RightButtonUp
      PostEvent(#PB_Event_RightClick)
   EndIf
EndProcedure


Re: Selector module; select rectangle on canvas using mouse

Posted: Fri Feb 27, 2015 11:06 am
by Kwai chang caine
Works fine here on W7
Very usefull !!
Cool the moving of selection :shock:
Thanks for sharing 8)

Re: Selector module; select rectangle on canvas using mouse

Posted: Sat Feb 28, 2015 6:13 pm
by BasicallyPure
Thank you for the report KCC.
I am happy you find it useful.

Re: Selector module; select rectangle on canvas using mouse

Posted: Sat Feb 28, 2015 11:26 pm
by Andre
Sounds interesting.... :D

Unfortunately it don't work as expected on MacOS (tested on 10.5.8 with PB 5.31 x86), you can't select / drag anything.
Would be good, if this can be added too :mrgreen:

Re: Selector module; select rectangle on canvas using mouse

Posted: Sun Mar 01, 2015 5:12 pm
by BasicallyPure
Andre, thank you for the report.

Questions for you.
Before you click the 'Activate Selector' button, is the cursor a hand when the mouse is over the canvas?
After you click 'Activate Selector' button has the mouse cursor changed to a cross?

Remove this line of code from the example; at line number 60.

Code: Select all

BindGadgetEvent(#Canvas,@CANVAS_CALLBACK())
Try running it again and see if it works.
You may have to right click on the window background to load an image.

Re: Selector module; select rectangle on canvas using mouse

Posted: Sun Mar 01, 2015 6:10 pm
by bbanelli
BasicallyPure wrote:Andre, thank you for the report.

Questions for you.
Before you click the 'Activate Selector' button, is the cursor a hand when the mouse is over the canvas?
After you click 'Activate Selector' button has the mouse cursor changed to a cross?

Remove this line of code from the example; at line number 60.

Code: Select all

BindGadgetEvent(#Canvas,@CANVAS_CALLBACK())
Try running it again and see if it works.
You may have to right click on the window background to load an image.
I can confirm same thing on 10.9.

Cursor changes, coordinates also change (with first click - but no rectangle is shown), however, what is strange is the fact that y coordinates are in minus. It would seem that GadgetY(\canvas,#PB_Gadget_WindowCoordinate) for same image and coordinates display different value on OS X and Windows...

Re: Selector module; select rectangle on canvas using mouse

Posted: Mon Mar 02, 2015 5:47 am
by BasicallyPure
bbanelli,

It might be a problem related to the canvas being inside a scroll area gadget.
Can you try this quick experiment.

In the selector module example code change lines 55, 56, and 57 to this so
the scroll area gadget is not used and the canvas is repositioned.

Code: Select all

;ScrollAreaGadget(#ScrollArea,120,10,644,484,640,480)
CanvasGadget(#Canvas,120,10,640,480,#PB_Canvas_ClipMouse)
;CloseGadgetList()
and change line 101 to this.

Code: Select all

               Selector::INITIALIZE_SELECTOR(#Canvas, -1) ; module procedure call
edit: It seems the reason it will not work for Mac OS is because of this bug as reported by Danilo.
http://www.purebasic.fr/english/viewtop ... =61780&sid
The problem being this:
GadgetY(CanvasGadget,#PB_Gadget_WindowCoordinate) does not return the Y-Coordinate on the window.
Looks like it returns GadgetY(CanvasGadget,#PB_Gadget_ContainerCoordinate) + GadgetHeight(CanvasGadget).