1. +Help!

Hi everybody!
      Can someone explain me with accuracy and simplicity how can i
      make 'clickeable' by the mouse a certain area of a text-
      mode screen?
      Imagine that i have the text 'Quit' at position (10,10).I've
      tried to figure out Jiri Babor's textmenu.e but it's quite
      complex for me!

see ya!:)
       - Luis -
  (no more dosshell!i have already installed the cool-looking Norton
   Commander)

new topic     » topic index » view message » categorize

2. Re: +Help!

Luis wrote:

> Can someone explain me with accuracy and simplicity how can i
> make 'clickeable' by the mouse a certain area of a text
> mode screen?

In graphics or text mode, it's pretty simple. The process is called "hit =
testing". Whenever there's a mouse event, you have to check to see if =
it's hit anything, typically by checking if it fell within some =
boundary.

For example, the text "Quit" at {10,10} falls within a bounds rectangle =
of {{10,10},{14,10}}, because the text is 4 characters across (10+4-1) =
and 1 character high (10+1-1). Notice I subtracted 1 from both values, =
because we are using {1,1} as the offset of our coordinates, instead of =
{0,0}.

The point falls into the bounding rectangle if it is greater or equal to =
the upper-left hand corner, and less or equal to the lower-right hand =
corner. It looks something like:

    if mouse_click() then  -- simplified
        -- greater or equal to the upper left corner
        if  mouse_x >=3D 10
        and mouse_y >=3D 10
        -- less or equal to the lower right corner
        and mouse_x <=3D 14
        and mouse_y <=3D 10 then

            -- the user pressed "Quit"

        end if        =20
    end if

You could write this as a routine:

    function in_bounds( sequence mouse, sequence p1, sequence p2 )

        -- returns true if mouse inside rectangle defined by p1, p2

        return  -- returns true if all tests are true
            mouse[1] >=3D p1[1]      -- upper left x
            and mouse[2] >=3D p1[2]  -- upper left y
            and mouse[1] <=3D p2[1]  -- lower right x
            and mouse[2] <=3D p2[2]  -- lower right y

    end function
   =20

Here's a call to the function:

   if mouse_click() then
      if in_bounds( mousePos, {10,10}, {10,14} ) then
         -- "quit" clicked
      end if
   end if

For handling several buttons on the screen, you could save the buttons =
in a sequence, such as:


    constant
      Owner =3D 1,
      Title =3D 2,
      P1    =3D 3,
      P2    =3D 4

    sequence buttons =3D {
        { 1, "Quit", {10, 10}, {14, 10} },
        { 1, "Help", {16, 10}, {20, 10} } }

  =20
The routine would then look at each button to see if it had been =
pressed:
      =20

   -- mouse click?
   if mouse_click() then
      -- look at each button
      button =3D ""
      for i =3D 1 to length( buttons ) do
         -- was this button hit by the mouse?
         if in_bounds( mousePos, button[i][P1], button[i][p2] ) then
            -- save the button name
            button =3D button[i][Title]
            -- leave the loop
            exit
         end if
      end for
   end if

If you wanted to add windows to your application, it would be a little =
bit more complex, but not much. Because windows can overlap, you need to =
test the closest window first:

   +----------------+
   | window 2       |
   |                |
   |    +--------------+
   |    | window 1  |  |
   |    |           |  |
   |    |   X       |  |
   +----|-----------+  |
        |              |
        +--------------+

As you can see (if you are looking at this with a fixed-width font), the =
"X" is a point shared by both windows. Which window does it belong to? =
The answer is: whichever window is tested first:

   +----------------+
   | window 2       |
   |                |
   |    +--------------+
   |    | window 1     |
   |    |              |
   |    |   X          |
   +----|              |
        |              |
        +--------------+


If you test window 1 first (because it's the first window), then it gets =
the mouse hit. The order of the windows is called the "z order". The "z" =
refers to the third dimension (depth).=20

When you draw the windows, you draw them in reverse z order, so the =
first windows ends up on top of all the rest.

Once you know which window is hit, you then do the button test on each =
button in the window to see which button, if any, was pressed. So the =
logic looks something like:

   if the mouse is pressed, then
      check windows in z order for a hit
      if a window was hit, then
         if that window wasn't on top, then
            put it on top
         else
            if a button in the window was hit then
               do that action
            end if
         end if
      end if
   end if

That's more or less what the inner loop of a windowing system looks =
like. I've included a simple windowing program at the end of this =
e-mail. There are a number of differences in the code:

   - The second window point is a relative size, not a screen point
   - The button position is relative to the window's {2,2} position
   - The button size is calculated on the text size

A major bit that is missing here is the clipping routines. When you =
write into a window, any text that doesn't fit should be clipped, such =
as:

   +----------------+
   | In a real windo|
   |                |
   |                |
   +----------------+

instead of this:

   +----------------+
   | In a real window, this wouldn't look like this.
   |                |
   |                |
   +----------------+

But I needed to leave *something* for you to do. blink

Hope this helps!

-- David Cuny


-- HERE'S THE CODE!

-- textwin.e
-- simple text windows

include mouse.e

-- attributes
constant
    Owner =3D 1,
    Title =3D 2,
    P1    =3D 3,
    P2    =3D 4

sequence buttons, windows, z_order

-- define some buttons
buttons =3D {
    { 1, "< Quit >", {1, 1} },
    { 2, "< Help >", {1, 1} } }

-- define some windows
windows =3D {
    { 1, "Window 1", {3, 3}, {17, 17} },
    { 1, "Window 2", {10, 10}, {40, 15} } }

-- the drawing order of the windows
z_order =3D { 1, 2 }   =20

integer key, clicked
sequence mouse_pos
object mouse


function remove( object o, sequence s )
    -- remove all instances of o from s
    sequence s2                   =20
   =20
    -- empty list
    s2 =3D {}     =20
   =20
    -- go though list
    for i =3D 1 to length( s ) do
        -- if NOT a match
        if compare( s[i], o ) then
            -- add to list
            s2 =3D append( s2, s[i] )
        end if
    end for              =20
       =20
    return s2
   =20
end function


procedure put_on_top( integer window )

    -- place window first in z order  =20
   =20
    -- remove from list
    z_order =3D remove( window, z_order )
   =20
    -- place first
    z_order =3D prepend( z_order, window )
   =20
end procedure



procedure draw_button( integer button )

    -- draw button in owner's window        =20
    integer owner
    sequence at, ownerAt


    -- get button's position
    at =3D buttons[button][P1]

    -- get owner
    owner =3D buttons[button][Owner]

    -- get owner's position
    ownerAt =3D windows[owner][P1]
   =20
    -- add to owner's position, and adjust
    at =3D at + ownerAt
   =20
    -- position
    position( at[2], at[1] )=20
   =20
    -- text
    puts( 1, buttons[button][Title] )

end procedure


procedure draw_buttons( integer owner )

    -- draw buttons in windows
    -- buttons are relative to the owner's position
   =20
    -- look though all the buttons   =20
    for i =3D 1 to length( buttons ) do
        -- owned by this window?
        if buttons[i][Owner] =3D owner then
            -- draw the button           =20
            draw_button( i )
        end if
       =20
    end for

end procedure


procedure draw_rect( integer x1, integer y1,=20
                    integer cx, integer cy )

    -- draw top
    position( y1, x1 )
    puts( 1, "+" & repeat( '-', cx-2 ) & "+" )

    -- draw middle
    for y =3D y1+1 to y1+cy-2 do
        position( y, x1 )
        puts( 1, "|" & repeat( ' ', cx-2 ) & "|" )
    end for                   =20
   =20
    -- draw bottom
    position( y1+cy-1, x1 )
    puts( 1, "+" & repeat( '-', cx-2 ) & "+" )
                       =20
end procedure               =20



procedure draw_window( integer window )

    -- draw button in owner's window
    integer x, y, cx, cy

    -- get position
    x  =3D windows[window][P1][1]
    y  =3D windows[window][P1][2]
    cx =3D windows[window][P2][1]
    cy =3D windows[window][P2][2]

    -- draw a rectangle
    draw_rect( x, y, cx, cy )
   =20
    -- title
    position( y, x+2  )   =20
    puts( 1, " " & windows[window][Title] & " " )

    -- draw the buttons
    draw_buttons( window )

end procedure


procedure draw_windows()
   =20
    -- draw in reverse z order
    for i =3D length( z_order ) to 1 by -1 do
        draw_window( z_order[i] )
    end for

end procedure


function in_rect( integer x, integer y,=20
                    integer x1, integer y1,=20
                    integer x2, integer y2 )

    -- true if point is in rectangle
    return
        x >=3D x1 and
        y >=3D y1 and
        x <=3D x2 and
        y <=3D y2
       =20
end function       =20


function hit_window( integer x, integer y, integer window )

    -- true if point is in window   =20
    integer x1, y1, x2, y2      =20
   =20
    -- window point
    x1 =3D windows[window][P1][1]
    y1 =3D windows[window][P1][2]
    x2 =3D x1 + windows[window][P2][1]
    y2 =3D y1 + windows[window][P2][2]
   =20
    return in_rect( x, y, x1, y1, x2, y2 )
   =20
end function
   =20


function hit_button( integer x, integer y, integer button )

    -- true if point is in button
    integer x1, y1, x2, y2, owner
   =20
    -- get owner
    owner =3D buttons[button][Owner]
   =20
    -- button point
    x1 =3D buttons[button][P1][1]
    y1 =3D buttons[button][P1][2]
   =20
    -- add owner
    x1 =3D x1 + windows[owner][P1][1] -1
    y1 =3D y1 + windows[owner][P1][2] -1
   =20
    -- calculate size
    x2 =3D x1 + length( buttons[button][Title] ) - 1
    y2 =3D y1
   =20
    return in_rect( x, y, x1, y1, x2, y2 )
   =20
end function



integer clicked_window, clicked_button

-- draw all the controls
draw_windows()

-- event loop
while 1 do               =20

    -- was the escape key pressed?
    if get_key() =3D 27 then
        exit
    end if

    -- look for mouse event
    mouse =3D get_mouse()

    -- event?
    if sequence( mouse ) then
        -- mouse press?
        clicked =3D and_bits( mouse[1], LEFT_DOWN )
        -- adjust
        mouse[2] =3D mouse[2]/8
        mouse[3] =3D mouse[3]/8
    else
        -- no click
        clicked =3D 0
    end if

    -- if clicked...   =20
    if clicked then       =20
        -- clear variables
        clicked_window =3D 0
        clicked_button =3D 0
       =20
        -- go through windows in z order
        for i =3D 1 to length( z_order ) do
            -- hit?
            if hit_window( mouse[2], mouse[3], z_order[i] ) then
                -- save window
                clicked_window =3D z_order[i]           =20
                -- exit loop
                exit
            end if
        end for
       =20
        -- hit window?                           =20
        if clicked_window then       =20
            -- is it on top?
            if z_order[1] =3D clicked_window then
                -- check buttons
                for i =3D 1 to length( buttons ) do
                    -- owned by window?
                    if buttons[i][Owner] =3D clicked_window then
                        -- hit button?
                        if hit_button( mouse[2], mouse[3], i ) then
                            -- save button
                            clicked_button =3D i
                            -- exit
                            exit                                         =
  =20
                        end if
                    end if
                end for               =20
            else           =20
                -- put window on top
                put_on_top( clicked_window )
                -- redraw windows
                draw_windows()
            end if
        end if

        -- display results
        position( 1, 1 )
        if clicked_window then
            if clicked_button then
                -- put up button title
                printf( 1, "hit button %s",=20
                        {buttons[clicked_button][Title]} )
           =20
            else
                -- put up window title
                printf( 1, "hit window %s",=20
                        {windows[clicked_window][Title]} )
            end if
        end if
       =20
    end if       =20

end while

new topic     » goto parent     » topic index » view message » categorize

3. Re: +Help!

Greetings,

>      Can someone explain me with accuracy and simplicity how can i
>      make 'clickeable' by the mouse a certain area of a text-
>      mode screen?
>      Imagine that i have the text 'Quit' at position (10,10).I've
>      tried to figure out Jiri Babor's textmenu.e but it's quite
>      complex for me!
>
>see ya!:)
>       - Luis -

I've never tried it on a text screen before but this should work.
Ok, you know the get_mouse command? well you use that like this I think:

-- untested code --

include mouse.e  -- of course
sequence qbutton,mouse
qbutton = "Quit"
position(10,10)
puts(1,qbutton)
mouse = get_mouse()
if mouse[2]>10 then
    if mouse[3]>{10} then
        if mouse[2]<10+length(qbutton) then
            --   ^
            --the [2] and [3] might need to be
            --switched on these two lines to work
            --   v
            if mouse[3]<10 then
                if find(LEFT_UP,mouse[1]) then
                    run_quit_routine() --you get the idea?
                end if
            end if
        end if
    end if
end if

-- end untested code --

I hope this isn't too complicated and in fact there is
probably a much simpler way to do it, I just haven't
figured it out yet:  you might use find() more and compare()
but I'm not sure.  I waited to see if anyone else would
answer your question before I did.

I didn't test this code but it should be close to working,
I just wish it didn't take so many statements.

Good luck,

Lewis Townsend
|      ____ _     _     _ _    __
|\    | __/ ||   / |   // || / __ \
| \   ||_   ||  //||  //  || ||__\|
|  \  | _|  || // || //   || \___ \
| | \ ||__  ||//  ||//    || |\__||
| |\ \|___\ |_/   |_/     || \____/
| | \ \      _____    ________
| |  \ \     | __ \  | __  __ |
| |   \ \    ||__||  |/  ||  \|
| |    \ \   | __ /      ||
| |_____\ \  ||  \\      ||
|__________\ ||  ||      ||
Keroltarr at hotmail.com

______________________________________________________
Get Your Private, Free Email at http://www.hotmail.com

new topic     » goto parent     » topic index » view message » categorize

4. Re: +Help!

In the windows test example code David Cuny wrote in the event loop of
the program:
   -- look for mouse event
    mouse = get_mouse()

    -- event?
    if sequence( mouse ) then
        -- mouse press?
        clicked = and_bits( mouse[1], LEFT_DOWN )
        -- adjust
        mouse[2] = mouse[2]/8
        mouse[3] = mouse[3]/8
    else
        -- no click
        clicked = 0
    end if

I get a bug reported when running the program about a type mismatch with
mouse[2] when the procedure hit_window is called.  I was able to
circumvent the problem by "flooring" the results for mouse[2] and
mouse[3].  The changes to the above line result in:

   -- look for mouse event
    mouse = get_mouse()

    -- event?
    if sequence( mouse ) then
        -- mouse press?
        clicked = and_bits( mouse[1], LEFT_DOWN )
        -- adjust
        mouse[2] = floor(mouse[2]/8)
        mouse[3] = floor(mouse[3]/8)
    else
        -- no click
        clicked = 0
    end if

I am very new to euphoria so I do not know if this is the best solution,
but I found it let the program run without fault.

Steve Ranta

new topic     » goto parent     » topic index » view message » categorize

5. Re: +Help!

Steve Ranta suggested the fix:

>>        mouse[2] =3D floor(mouse[2]/8)
>>        mouse[3] =3D floor(mouse[3]/8)

Sorry about that. I hadn't gotten that result when I tested it. I looked =
at the code in my editor, but hadn't notice that the floor() function =
was applied later. You can also write:

   mouse[2..3] =3D floor(mouse[2..3]/8)

I tend to forget you can do that sort of thing with sequences.

Thanks for the fix!

-- David Cuny

new topic     » goto parent     » topic index » view message » categorize

6. Re: +Help!

> Data de tramesa:   Fri, 08 May 1998 15:03:36 -0500 (CDT)
> De  :              Lewis Townsend <keroltarr at HOTMAIL.COM>
> Assumpte:          Re: +Help!
> A:                 Multiple recipients of list EUPHORIA
 <EUPHORIA at MIAMIU.ACS.MUOHIO.EDU>
> Enviar resposta a: Euphoria Programming for MS-DOS
 <EUPHORIA at MIAMIU.ACS.MUOHIO.EDU>

> Greetings,
>
> >      Can someone explain me with accuracy and simplicity how can i
> >      make 'clickeable' by the mouse a certain area of a text-
> >      mode screen?
> >      Imagine that i have the text 'Quit' at position (10,10).I've
> >      tried to figure out Jiri Babor's textmenu.e but it's quite
> >      complex for me!
> >
> >see ya!:)
> >       - Luis -
>
> I've never tried it on a text screen before but this should work.
> Ok, you know the get_mouse command? well you use that like this I think:
>
> -- untested code --
>
> include mouse.e  -- of course
> sequence qbutton,mouse
> qbutton = "Quit"
> position(10,10)
> puts(1,qbutton)
> mouse = get_mouse()
> if mouse[2]>10 then
>     if mouse[3]>{10} then
>         if mouse[2]<10+length(qbutton) then
>             --   ^
>             --the [2] and [3] might need to be
>             --switched on these two lines to work
>             --   v
>             if mouse[3]<10 then
>                 if find(LEFT_UP,mouse[1]) then
>                     run_quit_routine() --you get the idea?
>                 end if
>             end if
>         end if
>     end if
> end if
>
> -- end untested code --
>
> I hope this isn't too complicated and in fact there is
> probably a much simpler way to do it, I just haven't
> figured it out yet:  you might use find() more and compare()
> but I'm not sure.  I waited to see if anyone else would
> answer your question before I did.
>
> I didn't test this code but it should be close to working,
> I just wish it didn't take so many statements.
>
> Good luck,
>
> Lewis Townsend
> |      ____ _     _     _ _    __
> |\    | __/ ||   / |   // || / __ \
> | \   ||_   ||  //||  //  || ||__\|
> |  \  | _|  || // || //   || \___ \
> | | \ ||__  ||//  ||//    || |\__||
> | |\ \|___\ |_/   |_/     || \____/
> | | \ \      _____    ________
> | |  \ \     | __ \  | __  __ |
> | |   \ \    ||__||  |/  ||  \|
> | |    \ \   | __ /      ||
> | |_____\ \  ||  \\      ||
> |__________\ ||  ||      ||
> Keroltarr at hotmail.com
>
> ______________________________________________________
> Get Your Private, Free Email at http://www.hotmail.com


Hi Lewis,
 I tested your code and it doesn't works.There's a type-check failure
 that i think that i've remove it changing 'mouse' to a object.

  Please,check out the following code! ;)

-- tested code --
include mouse.e  -- of course
with trace
-- trace(1)
sequence qbutton
object mouse
integer clicked
mouse_events(LEFT_DOWN + LEFT_UP + RIGHT_DOWN)
----> we dont need the mouse to report the MOVE event i suppose!
qbutton = "Quit"
position(10,10)
puts(1,qbutton)
while 1 do
mouse = get_mouse()
--if mouse != -1 then ----> error!
---------------------------------------------------------------------
if sequence( mouse ) then  -----> if not,mouse = -1 would cause error!
--    if sequence( mouse ) then
        -- mouse press?
        clicked = and_bits( mouse[1], LEFT_DOWN ) ----->???????
        -- some one knows the use of and_bits() in here????????
        -- adjust
        mouse[2] = mouse[2]/8 --------> to scale the coordinates!
        mouse[3] = mouse[3]/8 --------> Thanks David Cuny,I missed
                                     -- this error!:)
 if mouse[2]>10 and mouse[2]<15 and mouse[3] = 10 then -->it should
                                                      --  be the
                                                      -- coordinates
                                                      -- of the button
     puts(1,"quiting...")
     exit
 else
 position(1,1)
 puts(1,"you must hit Quit!")
 end if
    else
        -- no click
        clicked = 0
--    if mouse[3]>{10} then
--        if mouse[2]<10+length(qbutton) then
            --   ^
            --the [2] and [3] might need to be
            --switched on these two lines to work
            --   v
--            if mouse[3]<10 then
--                if find(LEFT_UP,mouse[1]) then
               --     run_quit_routine() --you get the idea?
--            end if
--        end if
--    end if
--end if
end if
mouse = {0,0,0} ---> to make sure that will be a sequence
end while


-- Thanks to David Cuny,Lewis Townsend and everybody!

   - Luis -

>

new topic     » goto parent     » topic index » view message » categorize

7. Re: +Help!

(I think) Luis Campos wrote:

>        -- mouse press?
>        clicked =3D and_bits( mouse[1], LEFT_DOWN ) ----->???????
>        -- some one knows the use of and_bits() in here????????

The 'and_bits' is needed because there can be more than one mouse event =
at a time. For example, the mouse could move AND the left button could =
be clicked. The flags are ORd together. In this case, the returned =
result would be:

   MOVE AND LEFT_DOWN

which equals=20

   1 AND 2

which is, of course, 3. In this case, the test:

   if mouse[1] =3D LEFT_DOWN

would not detect the mouse click event, because 2 !=3D 3. If you look at =
the flags, they are set up in powers of 2:

   global constant
      MOVE =3D 1,
      LEFT_DOWN =3D 2,
      LEFT_UP =3D 4,
      RIGHT_DOWN =3D 8
      RIGHT_UP =3D 16,
      MIDDLE_DOWN =3D 32,
      MIDDLE_UP =3D 64

This is not by accident - you store all the flags into a single byte, by =
setting the _bits_ in the flag:

   1 =3D bit 0 =3D 2^0
   2 =3D bit 1 =3D 2^1
   4 =3D bit 2 =3D 2^2
   8 =3D bit 3 =3D 2^3
  16 =3D bit 4 =3D 2^4
  32 =3D bit 5 =3D 2^5
  64 =3D bit 6 =3D 2^6

To look at a _single_ bit in the byte, you AND the bits together. So the =
test:

   if and_bits( mouse[1], LEFT_DOWN )

works because

   3 AND 1

is equal to 1, and a non-zero result is treated as true.

Note that 'and_bits' is different than 'and'; 'and' returns true if both =
values are non-zero. It works like this:

   function and( object o1, object o2 )
      if o1 then
         if o2 then
            return 1
         end if
      end if
      return 0
   end function

So the test:

   -- WRONG!
   if mouse[1] and LEFT_DOWN then

tests to see if both values are non-zero. It doesn't do actually do a =
bit-by-bit comparison of the values.

Hope this helps!

-- David Cuny

new topic     » goto parent     » topic index » view message » categorize

8. Re: +Help!

I had mistakenly written:

>The flags are ORd together. In this case, the returned result would be:
>
>   MOVE AND LEFT_DOWN
>
>which equals
>
>   1 AND 2
>
>which is, of course, 3.

I should have written:

>The flags are ORd together. In this case, the returned result would be:
>
>   MOVE OR LEFT_DOWN => or_bits( MOVE, LEFT_DOWN )
>
>which equals
>
>   1 OR 2 => or_bits( 1, 2 )
>
>which is, of course, 3.

because 'and_bits( 1, 2 )' equals 0.

Sorry about the typo.

-- David Cuny

new topic     » goto parent     » topic index » view message » categorize

9. Re: +Help!

Salutations,

>Hi Lewis,
> I tested your code and it doesn't works.There's a type-check failure
> that i think that i've remove it changing 'mouse' to a object.
>
>  Please,check out the following code! ;)

I'll be surprised if a type-check failure was all that was wrong with my
code.  I used to call everything an object so that I wouldn't have to
worry about types much but I've been trying to be more specific
recently. Maybe it's better that way. (of course mouse needs to be an
object) I guess debugging type check errors is easier than trying to
figure out why your program is trying to subscript an atom (reading from
it) ;)


>-- Thanks to David Cuny,Lewis Townsend and everybody!

I'm flattered that you actually used some of my code.  I figured that
some one else would have a much better solution.

Sincerely,
Lewis Townsend
|\      ____ _     _     _ _    __
| \    | __/ ||   / |   // || / __ \
|  \   ||_   ||  //||  //  || ||__\|
|   \  | _|  || // || //   || \___ \
| |\ \ ||__  ||//  ||//    || |\__||
| | \ \|___\ |_/   |_/     || \____/
| |  \ \      _____    ________
| |   \ \     | __ \  | __  __ |
| |    \ \    ||__||  |/  ||  \|
| |     \ \   | __ /      ||
| |______\ \  ||  \\      ||
|___________\ ||  ||      ||
Keroltarr at hotmail.com

______________________________________________________
Get Your Private, Free Email at http://www.hotmail.com

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu