Re: +Help!

new topic     » goto parent     » topic index » view thread      » older message » newer message

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 thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu