Mapping screen for mouse
#1
How can I map several sections of the screen so that a (left) mouse click selects the one it's in, and allows actions based on this?
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, W.A.) Big Grin
Reply
#2
hello Phil, using the example of _MOUSEX in qb64 wiki, a few modifications, detect if mouse down on left side of screen (1) or right side of screen (2)

 is the beginning, you add more sectors to detect:

Code: (Select All)
DIM mousesector(10, 5) AS INTEGER

mousesector(1, 1) = 1 'xi
mousesector(1, 2) = 1 'yi
mousesector(1, 3) = 320 'xf
mousesector(1, 4) = 480 'yf
mousesector(1, 5) = 1 'option selected

mousesector(2, 1) = 321 'xi
mousesector(2, 2) = 1 'yi
mousesector(2, 3) = 639 'xf
mousesector(2, 4) = 480 'yf
mousesector(2, 5) = 2 'option selected


SCREEN 12
LINE (99, 9)-(601, 401), 7, BF
LINE (101, 11)-(599, 399), 8, BF
tm$ = " Column = ###  Row = ###  Button1 = ##  Button2 = ##  Button3 = ##"
LOCATE 29, 20: PRINT "LeftButton = draw - RightButton = Erase";
DO: K$ = INKEY$
    DO WHILE _MOUSEINPUT
        X = _MOUSEX: Y = _MOUSEY
        IF X > 100 AND X < 600 AND PX > 100 AND PX < 600 THEN
            IF Y > 10 AND Y < 400 AND PY > 10 AND PY < 400 THEN
                IF _MOUSEBUTTON(1) THEN LINE (PX, PY)-(X, Y), 15
                IF _MOUSEBUTTON(2) THEN LINE (101, 11)-(599, 399), 8, BF
            END IF
        END IF
        PX = X: PY = Y
        LOCATE 27, 10: PRINT USING tm$; X; Y; _MOUSEBUTTON(1); _MOUSEBUTTON(2); _MOUSEBUTTON(3)        
    LOOP
    '---------------------- code detecting sector --------------
    IF _MOUSEBUTTON(1) THEN
        FOR i = 1 TO 2
            IF X > mousesector(i, 1) AND Y > mousesector(i, 2) AND X < mousesector(i, 3) AND Y < mousesector(i, 4) THEN
                OptionSelected = mousesector(i, 5)
            END IF
        NEXT
    END IF

    LOCATE 28, 19: PRINT "OPTION SELECTED: "; OptionSelected
    '----------------- end code -------------

LOOP UNTIL K$ = CHR$(27)
SYSTEM
Reply
#3
Might want to put a _LIMIT statement to "guard" the big loop. Otherwise this program is going to take over the entire CPU. :O

Also just after the LINE and PRINT statements for the mouse buttons, put a _DISPLAY if the LINE statements are constantly erasing the central area of the program. People get easily irritated with screen flickering even in simple programs.

THIS IS HOW I FIXED IT:

Code: (Select All)
DIM updscreen AS _BYTE
DIM mousesector(10, 5) AS INTEGER

mousesector(1, 1) = 1 'xi
mousesector(1, 2) = 1 'yi
mousesector(1, 3) = 320 'xf
mousesector(1, 4) = 480 'yf
mousesector(1, 5) = 1 'option selected

mousesector(2, 1) = 321 'xi
mousesector(2, 2) = 1 'yi
mousesector(2, 3) = 639 'xf
mousesector(2, 4) = 480 'yf
mousesector(2, 5) = 2 'option selected


SCREEN 12
LINE (99, 9)-(601, 401), 7, BF
LINE (101, 11)-(599, 399), 8, BF
tm$ = " Column = ### Row = ### Button1 = ## Button2 = ## Button3 = ##"
LOCATE 29, 20: PRINT "LeftButton = draw - RightButton = Erase";
DO
_LIMIT 1000
updscreen = 0
K$ = INKEY$
DO WHILE _MOUSEINPUT
X = _MOUSEX: Y = _MOUSEY
IF X > 100 AND X < 600 AND PX > 100 AND PX < 600 THEN
IF Y > 10 AND Y < 400 AND PY > 10 AND PY < 400 THEN
IF _MOUSEBUTTON(1) THEN LINE (PX, PY)-(X, Y), 15 : updscreen = 1
IF _MOUSEBUTTON(2) THEN LINE (101, 11)-(599, 399), 8, BF : updscreen = 1
END IF
END IF
PX = X: PY = Y
IF updscreen THEN
LOCATE 27, 10: PRINT USING tm$; X; Y; _MOUSEBUTTON(1); _MOUSEBUTTON(2); _MOUSEBUTTON(3)
_DISPLAY
updscreen = 0
END IF
LOOP
'---------------------- code detecting sector --------------
IF _MOUSEBUTTON(1) THEN
FOR i = 1 TO 2
IF X > mousesector(i, 1) AND Y > mousesector(i, 2) AND X < mousesector(i, 3) AND Y < mousesector(i, 4) THEN
OptionSelected = mousesector(i, 5)
LOCATE 28, 19: PRINT "OPTION SELECTED: "; OptionSelected
updscreen = 1
END IF
NEXT
END IF

'----------------- end code -------------

IF updscreen THEN _DISPLAY

LOOP UNTIL K$ = CHR$(27)
SYSTEM
Reply
#4
Some code aids could help for that double-dimensional array like so:

Code: (Select All)
CONST XTOPLEFT = 1, YTOPLEFT = 2, XBOTRIGHT = 3, YBOTRIGHT = 4, WHICHOPT = 5

then one of the sections to initialize could be written like this:

Code: (Select All)
mousesector(2, XTOPLEFT) = 321 'xi
mousesector(2, YTOPLEFT) = 1 'yi
mousesector(2, XBOTRIGHT) = 639 'xf
mousesector(2, YBOTRIGHT) = 480 'yf
mousesector(2, WHICHOPT) = 2 'option selected

Taking this further, it could be changed so it could respond to right mouse button instead of the left, or a different mouse button. But most people have three-button devices (including pressing down on mouse wheel).

This example could also be modified so that specific buttons are drawn on the screen and the program responds differently to one or the other being touched with the left mouse button. Use the "mousesector" information to draw the bounding box of the button on display.

EDIT: Sorry, had to completely rewrite it, it was more confusing. I wanted to use "TOPLEFT", "TOPRIGHT", "BOTLEFT", "BOTRIGHT" but it would have required pairs of coordinates rather than just X or Y for one point of the bounding rectangle.
Reply
#5
Thanks both.
That's given me a great start. This is my first venture into mouseology, and I can experiment now with that information.

What I want to do is draw several squares on the screen, then by clicking on one, the box number and location are returned.
I think I can do this with your examples.
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, W.A.) Big Grin
Reply
#6
(08-07-2023, 01:52 AM)PhilOfPerth Wrote: How can I map several sections of the screen so that a (left) mouse click selects the one it's in, and allows actions based on this?

Easiest way is just to make an array to store your segment coordinates for the mouse.  

Code: (Select All)
TYPE Box 'a type to hold the mouse section information
    x AS INTEGER
    y AS INTEGER
    x2 AS INTEGER
    y2 AS INTEGER
END TYPE


DIM MouseSection(9) AS Box 'our mouse sections

SCREEN _NEWIMAGE(640, 480, 32)
FOR x = 0 TO 2
    FOR y = 0 TO 2
        i = i + 1
        MouseSection(i).x = x * 213
        MouseSection(i).x2 = x * 213 + 213
        MouseSection(i).y = y * 160
        MouseSection(i).y2 = y * 160 + 160
    NEXT
NEXT
'color the segments just to be pretty
FOR i = 1 TO 9
    LINE (MouseSection(i).x, MouseSection(i).y)-(MouseSection(i).x2, MouseSection(i).y2), _RGB32(RND * 255, RND * 255, RND * 255), BF
NEXT
PCOPY 0, 1


DO
    PCOPY 1, 0
    WHILE _MOUSEINPUT: WEND
    mx = _MOUSEX: my = _MOUSEY
    IF _MOUSEBUTTON(1) THEN
        FOR i = 0 TO 9 'check the 9 segments
            IF mx >= MouseSection(i).x AND mx <= MouseSection(i).x2 THEN
                IF my >= MouseSection(i).y AND my <= MouseSection(i).y2 THEN
                    LOCATE 1, 1: PRINT "Mouse last down in segment #"; i
                    EXIT FOR
                END IF
            END IF
        NEXT
    END IF
    IF _MOUSEBUTTON(2) THEN SYSTEM
    _LIMIT 30
    _DISPLAY
LOOP
Reply
#7
Here's a quick and dirty demo I wrote as another possibility of defining screen areas to interact with the mouse.

- Move the mouse to select an area

- Left mouse button to trap the mouse

- Right mouse button to release the mouse

- ESC to exit

Code: (Select All)
'
' Quick and dirty demo of trapping the mouse pointer within areas on the screen
'

CONST FALSE = 0, TRUE = NOT FALSE ' truth detectors
CONST SWIDTH = 800, SHEIGHT = 600 ' screen dimensions


TYPE TYPE_POINT '                  COORDINATE POINT PROPERTIES
    x AS INTEGER '                  x,y point
    y AS INTEGER
END TYPE

TYPE TYPE_SCREENAREA '              SCREEN AREA PROPERTIES
    min AS TYPE_POINT '            upper left
    max AS TYPE_POINT '            lower right
    Visible AS INTEGER '            this screen is available to mouse (t/f)
    Trapped AS INTEGER '            this screen has mouse trapped (t/f)
END TYPE

TYPE TYPE_MOUSE '                  MOUSE PROPERTIES
    x AS INTEGER '                  x location
    y AS INTEGER '                  y location
    trapped AS INTEGER '            screen area mouse trapped in (0 for none)
    hovering AS INTEGER '          screen area mouse is hovering over (0 for none)
    min AS TYPE_POINT '            upper left corner of trapped area
    max AS TYPE_POINT '            lower right corner of trapped area
END TYPE

REDIM ScreenArea(0) AS TYPE_SCREENAREA ' screen area array
DIM Mouse AS TYPE_MOUSE '                mouse properties

'+---------------------+
'| Define screen areas |
'+---------------------+

Screen1 = DefineScreenArea(10, 10, 90, 90, TRUE) '    (x1, y1, x2, y2, Visible)
Screen2 = DefineScreenArea(100, 10, 190, 90, TRUE)
Screen3 = DefineScreenArea(10, 100, 190, 190, TRUE)
Screen4 = DefineScreenArea(200, 10, 380, 190, TRUE)
screen5 = DefineScreenArea(10, 200, 380, 380, TRUE)

SCREEN _NEWIMAGE(SWIDTH, SHEIGHT, 32) ' create graphics screen
_MOUSEHIDE '                            hide the default mouse pointer (rem this line to see why)    <<---------------
DO
    _LIMIT 30
    CLS
    LOCATE 2, 50: PRINT "Move mouse to select screen area."
    LOCATE 4, 50: PRINT "Left mouse button to trap mouse pointer."
    LOCATE 6, 50: PRINT "Right mouse button to release mouse pointer."
    LOCATE 8, 50: PRINT "ESC to exit."
    LOCATE 10, 50: PRINT "Currently hovering screen area"; Mouse.hovering
    LOCATE 12, 50: PRINT "Currently trapped in area"; Mouse.trapped
    LOCATE 14, 50: PRINT "This area is defined as ";
    SELECT CASE Mouse.hovering
        CASE 0
            PRINT "the main screen."
        CASE Screen1
            PRINT CHR$(34); "Screen1"; CHR$(34)
        CASE Screen2
            PRINT CHR$(34); "Screen2"; CHR$(34)
        CASE Screen3
            PRINT CHR$(34); "Screen3"; CHR$(34)
        CASE Screen4
            PRINT CHR$(34); "Screen4"; CHR$(34)
        CASE screen5
            PRINT CHR$(34); "Screen5"; CHR$(34)
    END SELECT
    DrawScreenAreas
    _DISPLAY
LOOP UNTIL _KEYDOWN(27)

'---------------------------------------------------------------------------------------------------------------------------------
SUB UpdateMouse ()

    '+--------------------------------------------------------------------------------------------------------+
    '| Tracks the mouse movement and controls when the mouse pointer is trapped within a defined screen area. |
    '|                                                                                                        |
    '| Left mouse button  - trap the mouse within a screen area                                              |
    '| Right mouse button - release a trapped mouse from within a screen area                                |
    '+--------------------------------------------------------------------------------------------------------+

    SHARED Mouse AS TYPE_MOUSE '            need access to mouse properties
    SHARED ScreenArea() AS TYPE_SCREENAREA ' need access to screen areas
    DIM m AS TYPE_POINT '                    current mouse location
    DIM s AS INTEGER '                      screen area counter

    WHILE _MOUSEINPUT: WEND '                                    get latest mouse updates
    m.x = _MOUSEX '                                              record mouse position
    m.y = _MOUSEY
    IF Mouse.trapped THEN '                                      is mouse currently trapped?
        IF m.x < Mouse.min.x THEN m.x = Mouse.min.x '            yes, confine mouse to screen area
        IF m.x > Mouse.max.x THEN m.x = Mouse.max.x
        IF m.y < Mouse.min.y THEN m.y = Mouse.min.y
        IF m.y > Mouse.max.y THEN m.y = Mouse.max.y
        _MOUSEMOVE m.x, m.y '                                    force mouse to updated coordinates
        IF _MOUSEBUTTON(2) THEN '                                right button clicked?
            ScreenArea(Mouse.trapped).Trapped = 0 '              yes, screen area is no longer trapped
            Mouse.trapped = 0 '                                  mouse is no longer trapped
        END IF
    ELSE '                                                      no, mouse is not trapped
        IF _MOUSEBUTTON(1) AND UBOUND(ScreenArea) THEN '        is there a defined screen area to enter?
            s = 0 '                                              reset screen area counter
            DO '                                                cycle through screen areas
                s = s + 1 '                                      increment screen area counter
                IF MouseHovering(ScreenArea(s)) THEN '          is mouse hovering over this screen area?
                    ScreenArea(s).Trapped = -1 '                yes, this screen area is no trapping the mouse
                    Mouse.trapped = s '                          remember screen area mouse trapped in
                    Mouse.min = ScreenArea(s).min '              record upper left coordinate of screen area
                    Mouse.max = ScreenArea(s).max '              record lower right coordinate of screen area
                END IF
            LOOP UNTIL s = UBOUND(ScreenArea) OR Mouse.trapped ' leave when all screen areas checked or the mouse became trapped
        END IF
    END IF
    CIRCLE (m.x, m.y), 5 '                                      draw mouse pointer
    PSET (m.x, m.y) '                                            (replace with an image of a mouse pointer by using _PUTIMAGE)

END SUB

'---------------------------------------------------------------------------------------------------------------------------------
SUB DrawScreenAreas ()

    '+-----------------------------------------------------+
    '| Draws the visible defined screen area borders.      |
    '|                                                    |
    '| Bright white - screen area has mouse trapped within |
    '| White        - mouse is hovering over screen area  |
    '| Gray        - no mouse activity within screen area |
    '+-----------------------------------------------------+

    SHARED ScreenArea() AS TYPE_SCREENAREA '  need access to screen areas
    SHARED Mouse AS TYPE_MOUSE '              need access to mouse properties
    STATIC Colour(-1 TO 1) AS _UNSIGNED LONG ' border colors
    DIM Area AS TYPE_SCREENAREA '              current screen area being checked
    DIM s AS INTEGER '                        screen area counter
    DIM Border AS INTEGER '                    current screen area border color

    IF UBOUND(ScreenArea) = 0 THEN EXIT SUB '                                      leave if no defined screen areas
    IF NOT Colour(-1) THEN '                                                        set border colors if not set yet
        Colour(-1) = _RGB32(255, 255, 255) '                                        trapped (bright white)
        Colour(0) = _RGB32(127, 127, 127) '                                        not hovering (gray)
        Colour(1) = _RGB32(192, 192, 192) '                                        hovering (white)
    END IF
    Mouse.hovering = 0
    s = 0 '                                                                        reset screen area counter
    DO '                                                                            cycle through screen areas
        s = s + 1 '                                                                increment screen area counter
        Area = ScreenArea(s) '                                                      get screen area
        IF Area.Visible THEN '                                                      is this area visible?
            IF Area.Trapped THEN '                                                  yes, is this area trapping the mouse?
                Border = -1 '                                                      yes, set border color
            ELSE '                                                                  no, this area is not trapping mouse
                IF Mouse.trapped THEN '                                            is the mouse trapped in another area?
                    Border = 0 '                                                    yes, set border color to non hovering
                ELSE '                                                              no, mouse is not trapped in any area
                    Border = MouseHovering(Area) '                                  set border color (0 not hovering, 1 hovering)
                    IF Border THEN Mouse.hovering = s
                END IF
            END IF
        END IF
        LINE (Area.min.x, Area.min.y)-(Area.max.x, Area.max.y), Colour(Border), B ' draw screen area border
        UpdateMouse '                                                              update mouse
    LOOP UNTIL s = UBOUND(ScreenArea) '                                            leave when all screen areas checked
END SUB

'---------------------------------------------------------------------------------------------------------------------------------
FUNCTION MouseHovering (Area AS TYPE_SCREENAREA)

    '+--------------------------------------------------------------------------------+
    '| Returns a value of 1 if the mouse is hovering over the given area, 0 otherwise |
    '+--------------------------------------------------------------------------------+

    MouseHovering = 0 '                          assume mouse not hovering over area
    WHILE _MOUSEINPUT: WEND '                    get latest mouse updates
    IF _MOUSEX >= Area.min.x THEN '              is mouse pointer currently within area limits?
        IF _MOUSEX <= Area.max.x THEN
            IF _MOUSEY >= Area.min.y THEN
                IF _MOUSEY <= Area.max.y THEN
                    MouseHovering = 1 '          yes, report that mouse is hovering this area
                END IF
            END IF
        END IF
    END IF

END FUNCTION

'---------------------------------------------------------------------------------------------------------------------------------
FUNCTION DefineScreenArea (x1 AS INTEGER, y1 AS INTEGER, x2 AS INTEGER, y2 AS INTEGER, Visible AS INTEGER)

    '+-------------------------------------------------------------+
    '| Defines areas on the screen for the mouse to get trapped in |
    '+-------------------------------------------------------------+

    SHARED ScreenArea() AS TYPE_SCREENAREA ' need access to screen areas

    REDIM _PRESERVE ScreenArea(UBOUND(ScreenArea) + 1) AS TYPE_SCREENAREA ' increase array size
    ScreenArea(UBOUND(ScreenArea)).min.x = x1 '                            set new screen area coordinates
    ScreenArea(UBOUND(ScreenArea)).max.x = x2
    ScreenArea(UBOUND(ScreenArea)).min.y = y1
    ScreenArea(UBOUND(ScreenArea)).max.y = y2
    ScreenArea(UBOUND(ScreenArea)).Visible = Visible '                      set visible status
    DefineScreenArea = UBOUND(ScreenArea) '                                return handle of screen area

END FUNCTION
Software and cathedrals are much the same — first we build them, then we pray.
QB64 Tutorial
Reply
#8
Heart 
(08-07-2023, 08:36 AM)TerryRitchie Wrote: Here's a quick and dirty demo I wrote as another possibility of defining screen areas to interact with the mouse.
Your version of quick and dirty is of great quality! Is it OK to use this in our own projects?

This is an awesome example, thank you for sharing it! Heart

Screenshot for others:

[Image: mouse-ritchie.png]
grymmjack (gj!)
GitHubYouTube | Soundcloud | 16colo.rs
Reply
#9
Yeah this is essential functionality, it is core of my GUI stuff and just about any game I've done.

SdlBasic called these MouseZones and had a function for IDing which you were in.
b = b + ...
Reply
#10
(08-07-2023, 02:32 PM)grymmjack Wrote:
(08-07-2023, 08:36 AM)TerryRitchie Wrote: Here's a quick and dirty demo I wrote as another possibility of defining screen areas to interact with the mouse.
Your version of quick and dirty is of great quality! Is it OK to use this in our own projects?

This is an awesome example, thank you for sharing it! Heart

Screenshot for others:

[Image: mouse-ritchie.png]
Thank you. Any and all code I post is freely available to everyone to modify and use for their needs. Hack away Smile
Software and cathedrals are much the same — first we build them, then we pray.
QB64 Tutorial
Reply




Users browsing this thread: 2 Guest(s)