Mapping screen for mouse - PhilOfPerth - 08-07-2023
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?
RE: Mapping screen for mouse - commandvom - 08-07-2023
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
RE: Mapping screen for mouse - mnrvovrfc - 08-07-2023
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
RE: Mapping screen for mouse - mnrvovrfc - 08-07-2023
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.
RE: Mapping screen for mouse - PhilOfPerth - 08-07-2023
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.
RE: Mapping screen for mouse - SMcNeill - 08-07-2023
(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
RE: Mapping screen for mouse - TerryRitchie - 08-07-2023
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
RE: Mapping screen for mouse - grymmjack - 08-07-2023
(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!
Screenshot for others:
RE: Mapping screen for mouse - bplus - 08-07-2023
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.
RE: Mapping screen for mouse - TerryRitchie - 08-07-2023
(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!
Screenshot for others:
Thank you. Any and all code I post is freely available to everyone to modify and use for their needs. Hack away
|