Programming C, C++, Java, PHP, Ruby, Turing, VB
Computer Science Canada 
Programming C, C++, Java, PHP, Ruby, Turing, VB  

Username:   Password: 
 RegisterRegister   
 Custom Buttons
Index -> Programming, Turing -> Turing Submissions
View previous topic Printable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic
Author Message
Clayton




PostPosted: Sat Dec 09, 2006 10:40 am   Post subject: Custom Buttons

I was asked by a friend the other day why he couldn't pass procedures with parameters when he created a button in Turing. I told him quite plainly that Turing's built in GUI sucked. So he asked me how to get around it. I told him to make one himself, he claimed he didn't know how, so I did. Heres the source with an example program:

Turing:

class Buttons
    import Mouse
    export Pressed, Create, CreateFull, Refresh, EnableRollover

    var x, y, width, height : int
    var text : string
    var rollover_enabled : boolean := false
    var rollover_color : int
    const font := Font.New ("times new roman:12")

    %Mouse Variables to keep track of whether the button is being pressed or not
    var oldbutton : int := 0

    procedure Create (x_, y_ : int, text_ : string)
        x := x_
        y := y_
        text := text_
        width := Font.Width (text, font) + 10
        height := 16
        Draw.Box (x, y, x + width, y + height, black)
        Draw.Fill (x + 1, y + 1, grey, black)
        Font.Draw (text, x + (width div 2) - (Font.Width (text, font) div 2), y + (height div 2 - 4), font, black)
    end Create

    procedure CreateFull (x_, y_, width_, height_ : int, text_ : string)
        text := text_
        x := x_
        y := y_
        width := width_
        height := height_
        Draw.Box (x, y, x + width, y + height, black)
        Draw.Fill (x + 1, y + 1, grey, black)
        Font.Draw (text, x + (width div 2) - (Font.Width (text, font) div 2), y + (height div 2 - 4), font, black)
    end CreateFull

    fcn MouseHover : boolean
        var mx, my, mb : int
        Mouse.Where (mx, my, mb)
        if mx >= x and my >= y and mx <= x + width and my <= y + height then
            result true
        else
            result false
        end if
    end MouseHover

    procedure Rollover
        Draw.Box (x, y, x + width, y + height, black)
        Draw.Fill (x + 1, y + 1, rollover_color, black)
        Font.Draw (text, x + (width div 2) - (Font.Width (text, font) div 2), y + (height div 2 - 4), font, black)
    end Rollover

    procedure EnableRollover (choice : boolean, clr : int)
        rollover_color := clr
        rollover_enabled := choice
    end EnableRollover

    fcn Pressed : boolean
        var mx, my, mb : int
        Mouse.Where (mx, my, mb)
        if MouseHover and mb >= 1 and oldbutton = 0 then
            oldbutton := 1
            result false
        elsif MouseHover and mb = 0 and oldbutton = 1 then
            oldbutton := 0
            result true
        else
            result false
        end if
        result false
    end Pressed

    procedure Refresh
        if rollover_enabled and MouseHover then
            Rollover
        else
            Draw.Box (x, y, x + width, y + height, black)
            Draw.Fill (x + 1, y + 1, grey, black)
            Font.Draw (text, x + (width div 2) - (Font.Width (text, font) div 2), y + (height div 2 - 4), font, black)
        end if
    end Refresh
end Buttons

View.Set ("graphics, offscreenonly")
var button1 : ^Buttons
var button2 : ^Buttons

new Buttons, button1
new Buttons, button2

button1 -> CreateFull (maxx div 2, maxy div 2, 300, 100, "Hello World Happy Gilmore")
button2 -> Create (5, 5, "Button 2")
button1 -> EnableRollover (true, brightred)
button2 -> EnableRollover (true, purple)
loop
    if button1 -> Pressed then
        Draw.FillBox (0, 0, maxx, maxy, brightred)
        View.Update
        Time.Delay (1000)
    end if
    if button2 -> Pressed then
        Draw.FillBox (0, 0, maxx, maxy, purple)
        View.Update
        Time.Delay (1000)
    end if
    button1 -> Refresh
    button2 -> Refresh
    View.Update
    Draw.Cls
    exit when hasch
end loop


a couple of procedures you should know about when using this:

Create (x, y : int, text : string)

Creates a button at (x,y) with text inside of it. The button will automatically become the width and height required for the text.

CreateFull (x, y, width, height : int, text : string)

Like Create, except you specify its width and height.

Pressed : boolean

Pressed simply returns true if the button has been pressed (ie the mouse button was released over it)

Refresh

Simply redraws the button on the screen again

EnableRollover (choice : boolean, Color : int)

Enables a rollover effect on the button (true for it to happen, false for it not to). With rollover enabled, the button will change color to Color when the mouse is over the button

Have fun with it, just remember to give credit to me if you use it.

NOTE: I will be making this a module later on so that more people will be able to use it.

EDIT: Any additions you would like to see are welcome! I'm always open to suggestions
Sponsor
Sponsor
Sponsor
sponsor
Cervantes




PostPosted: Sat Dec 09, 2006 11:02 am   Post subject: Re: Custom Buttons

Freakman wrote:
I was asked by a friend the other day why he couldn't pass procedures with parameters when he created a button in Turing. I told him quite plainly that Turing's built in GUI sucked.

I'd just like to point out that there is a reason this can't be done. It's because each button is an object, and one of it's instance variables is an action procedure. That is, a procedure with no parameters. Turing is a typed language, and a procedure with one parameter has a different type than a procedure with no parameters. In the class for the button, the instance variable must be given a type. It's got to be either a procedure with no parameters, or a procedure with one parameter, or.... Thus, all buttons have to be consistant with each other. The best way to do this is to make all buttons use action procedures.

This wouldn't be much of a problem if Turing had support for anonymous functions.
Clayton




PostPosted: Sat Dec 09, 2006 11:04 am   Post subject: (No subject)

Aye, I know that. I was just explaining that too him (also didn't want to drone on with my post [Which I think I did anyway]). Any other suggestions though Cervantes?
Cervantes




PostPosted: Sat Dec 09, 2006 11:14 am   Post subject: (No subject)

You've handled the buttons' actions the same way I did. I'm actually not so sure that's the best way to do it, anymore. It means having a really big main loop, because you've got to do all those if statements yourself. Can you find a way to make both approaches possible?

I'd also suggest giving the buttons some visual charactersitc that shows when they are pressed down. The button should look different when the mouse is pressing it than when the mouse is merely hovering over it.

In your Create procedure, you assigned a value to `height'. Why not assign that variable outside that procedure, right when you declare the variable? The code inside a class is run each time an object is created, and `self' is that object, so doing it this way would give you the same effect. It's not necessarily better, though. Just something to consider.

Here's something else to consider. Your code checks the state of the mouse each time the Pressed function is called. You'll be checking the state of the mouse once for each button you've got. That's not really necessary. We should only have to check the state of the mouse at most once each time through the loop. So, one possibility is to use a global variable for the state of the mouse, but we all hate global variables. Another possibility is to pass the state of the mouse into the Pressed function as a parameter. This could also give you the power to sort of fudge the position of the mouse if you wanted to, by passing in bogus values.

To show off the fact that your buttons don't act like the action-procedure slaves that Turing's GUI's buttons are, why don't you make a procedure that takes in a colour as a parameter and does your little "draw the screen that colour, View.Update, then delay(1000)"?
Clayton




PostPosted: Sat Dec 09, 2006 11:28 am   Post subject: (No subject)

Thanks for the suggestions Cervantes, I'll be sure to try and get those points worked into there somehow. For now though, I have decided to get everything moved into a module (the class still exists, but the programmer doesn't deal directly with it). The modules' name has become Buttons for simplicity. the class name is now buttons instead. The code: (with the procedure Cervantes mentioned above)

Turing:

class buttons
    import Mouse
    export Pressed, Create, CreateFull, Refresh, EnableRollover

    var x, y, width, height : int
    var text : string
    var rollover_enabled : boolean := false
    var rollover_color : int
    const font := Font.New ("times new roman:12")

    %Mouse Variables to keep track of whether the button is being pressed or not
    var oldbutton : int := 0

    procedure Create (x_, y_ : int, text_ : string)
        x := x_
        y := y_
        text := text_
        width := Font.Width (text, font) + 10
        height := 16
        Draw.Box (x, y, x + width, y + height, black)
        Draw.Fill (x + 1, y + 1, grey, black)
        Font.Draw (text, x + (width div 2) - (Font.Width (text, font) div 2), y + (height div 2 - 4), font, black)
    end Create

    procedure CreateFull (x_, y_, width_, height_ : int, text_ : string)
        text := text_
        x := x_
        y := y_
        width := width_
        height := height_
        Draw.Box (x, y, x + width, y + height, black)
        Draw.Fill (x + 1, y + 1, grey, black)
        Font.Draw (text, x + (width div 2) - (Font.Width (text, font) div 2), y + (height div 2 - 4), font, black)
    end CreateFull

    fcn MouseHover : boolean
        var mx, my, mb : int
        Mouse.Where (mx, my, mb)
        if mx >= x and my >= y and mx <= x + width and my <= y + height then
            result true
        else
            result false
        end if
    end MouseHover

    procedure Rollover
        Draw.Box (x, y, x + width, y + height, black)
        Draw.Fill (x + 1, y + 1, rollover_color, black)
        Font.Draw (text, x + (width div 2) - (Font.Width (text, font) div 2), y + (height div 2 - 4), font, black)
    end Rollover

    procedure EnableRollover (choice : boolean, clr : int)
        rollover_color := clr
        rollover_enabled := choice
    end EnableRollover

    fcn Pressed : boolean
        var mx, my, mb : int
        Mouse.Where (mx, my, mb)
        if MouseHover and mb >= 1 and oldbutton = 0 then
            oldbutton := 1
            result false
        elsif MouseHover and mb = 0 and oldbutton = 1 then
            oldbutton := 0
            result true
        else
            result false
        end if
        result false
    end Pressed

    procedure Refresh
        if rollover_enabled and MouseHover then
            Rollover
        else
            Draw.Box (x, y, x + width, y + height, black)
            Draw.Fill (x + 1, y + 1, grey, black)
            Font.Draw (text, x + (width div 2) - (Font.Width (text, font) div 2), y + (height div 2 - 4), font, black)
        end if
    end Refresh
end buttons

%Actual module to use to make buttons
module Buttons
    import buttons
    export Create, CreateFull, Refresh, EnableRollover, Pressed

    var button_stack : flexible array 1 .. 0 of ^buttons


    fcn Create (x, y : int, text : string) : int
        new button_stack, upper (button_stack) + 1
        new buttons, button_stack (upper (button_stack))
        button_stack (upper (button_stack)) -> Create (x, y, text)
        result upper (button_stack)
    end Create

    fcn CreateFull (x, y, width, height : int, text : string) : int
        new button_stack, upper (button_stack) + 1
        new buttons, button_stack (upper (button_stack))
        button_stack (upper (button_stack)) -> CreateFull (x, y, width, height, text)
        result upper (button_stack)
    end CreateFull

    procedure Refresh (button_id : int)
        button_stack (button_id) -> Refresh
    end Refresh

    procedure EnableRollover (button_id : int, choice : boolean, clr : int)
        button_stack (button_id) -> EnableRollover (choice, clr)
    end EnableRollover

    fcn Pressed (button_id : int) : boolean
        result button_stack (button_id) -> Pressed
    end Pressed
end Buttons

%Example Program
procedure fill_screen (clr : int)
    Draw.FillBox (0, 0, maxx, maxy, clr)
    View.Update
    Time.Delay (1000)
end fill_screen

View.Set ("graphics, offscreenonly")
var button1 : int := Buttons.CreateFull (maxx div 2, maxy div 2, 300, 100, "Hello World Happy Gilmore")
var button2 : int := Buttons.Create (5, 5, "Button 2")

Buttons.EnableRollover (button1, true, brightred)
Buttons.EnableRollover (button2, true, purple)
loop
    if Buttons.Pressed (button1) then
        fill_screen (brightred)
    end if
    if Buttons.Pressed (button2) then
        fill_screen (purple)
    end if
    Buttons.Refresh (button1)
    Buttons.Refresh (button2)
    View.Update
    Draw.Cls
    exit when hasch
end loop


Because the class is now being handled through a module, I had to find a way to get my procedures and functions to act upon seperate buttons (as opposed to all of them). So now Create and CreateFull are functions returning ints. This is your button id. The procedures breakdown like this:

Create (x, y : int, text : string) : int

Same as before, it just returns the buttons new id.

CreateFull (x, y, width, height : int, text : string) : int

Again, only thing that is different is that it returns a button id.

Refresh (button_id : int)

You now have to pass it the button id that you want it to refresh.

EnableRollover (button_id : int, choice : boolean, clr : int)

Just like the above, except you have to pass it the button id that you want to have the rollover.

Pressed (button_id : int) : boolean

Just pass it the button id now.

Any other suggestions, just say them.
Hackmaster




PostPosted: Sat Dec 09, 2006 3:56 pm   Post subject: (No subject)

I would just like to point out that there is another way around the first stated problem, altough it's ugly, and quite frankly, your way is much better. but, for people who are new, and don't know about objects, a very, very verboten way to do this is simply to use global variables in your procedure. (shudder)

it counts as an action proc now, because it dosen't take parameters... but all other coders will hate you. just putting that out there.
joedirt




PostPosted: Sun Dec 17, 2006 7:19 pm   Post subject: (No subject)

hey freakman,

I'm a fairly new to turing a i was woundering if you could explain or make a code for a simple custon button. One where all you do is click and there is no rollover of whatever, just as simple as you can.

-thanks
Clayton




PostPosted: Sun Dec 17, 2006 7:30 pm   Post subject: (No subject)

code:

var button1 : int := Buttons.Create (30, 30, "Hello")
loop
    if Buttons.Pressed (button1) then
        Draw.FillBox (maxx div 2, maxy div 2, maxx, maxy, brightred)
        Time.Delay(100)
    end if
end loop


Read my above posts and it well tell you all you need to know to understand.
Sponsor
Sponsor
Sponsor
sponsor
joedirt




PostPosted: Sun Dec 17, 2006 8:03 pm   Post subject: (No subject)

i got this far but i still can't figure out how to make a if statment which only works when the mouse is over a button and the mouse is clicked at the same time. in this code i'll click away from the button then move my mouse over it and it still works. Please help.



var x, y, button : int
procedure redbox
Draw.FillBox (10, 10, 50, 50, red)
end redbox
procedure box
Draw.FillBox (10, 10, 50, 50, black)
end box


loop
Mouse.Where (x, y, button)
box
var x1, y1 : int
if x < 50 and y < 50 and Mouse.ButtonMoved ("down") then

redbox
delay (1000)
end if
end loop
ericfourfour




PostPosted: Sun Dec 17, 2006 11:28 pm   Post subject: (No subject)

I have two ideas to handle the actions. The first one is to use an action class. The second is to inherit the button object and use it.
Display posts from previous:   
   Index -> Programming, Turing -> Turing Submissions
View previous topic Tell A FriendPrintable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic

Page 1 of 1  [ 10 Posts ]
Jump to:   


Style:  
Search: