-- The cplus module can create buttons, sliders, check boxes, etc.

local glu = glu()
local cv = canvas()
local gp = require "gplus"
local cp = require "cplus"

local cvwd = 550
local cvht = 450

local big_button, label_button, exit_button
local show_checkbox, enable_checkbox
local r_slider, g_slider, b_slider
local back_radio, text_radio, border_radio

-- initial state of big_button
local currlabel = "A Very Big Button"
local shown = true
local enabled = true
local backcolor = {0,160,0,255}     -- dark green background
local textcolor = {255,255,0,255}   -- yellow text
local bordercolor = {0,0,0,255}     -- black border
local color = backcolor             -- sliders will change background color

--------------------------------------------------------------------------------

function ChangeLabel()
    local newlabel = glu.getstring("Enter new label for button:", currlabel)
    if newlabel then
        currlabel = newlabel
        big_button.setlabel(currlabel, true) -- adjust width
        DrawCanvas()
    end
end

--------------------------------------------------------------------------------

function ToggleShown()
    shown = not shown
    if not shown then
        big_button.hide() -- prevents button being clicked when invisible
    end
    DrawCanvas()
end

--------------------------------------------------------------------------------

function ToggleEnabled()
    enabled = not enabled
    big_button.enable(enabled)
    DrawCanvas()
end

--------------------------------------------------------------------------------

function SelectColor(button)
    -- note that cp.process passes in which button was selected
    if button == back_radio then color = backcolor end
    if button == text_radio then color = textcolor end
    if button == border_radio then color = bordercolor end
    DrawCanvas()
end

--------------------------------------------------------------------------------


function ColorChanged(newval, slider)
    -- note that cp.process passes in the new slider value and the slider
    if slider == r_slider then color[1] = newval end
    if slider == g_slider then color[2] = newval end
    if slider == b_slider then color[3] = newval end

    if color == backcolor then big_button.setbackcolor(color) end
    if color == textcolor then big_button.settextcolor(color) end
    if color == bordercolor then big_button.setborder(nil,color) end
                                                   -- nil means don't change border size

    DrawCanvas() -- calls UpdateSlider to draw text at right end of slider
end

--------------------------------------------------------------------------------

function UpdateSlider(slider, ypos, char, val)
    -- show slider at given ypos but centered horizontally in canvas
    slider.show((cvwd - slider.wd) // 2, ypos, val)
    -- show char=val at right end of slider
    local _, ht = cv.text("temp", char.."="..val)
    cv.paste("temp", slider.x+slider.wd+5, ypos+((slider.ht-ht)/2+0.5)//1)
end

--------------------------------------------------------------------------------

function CreateCanvas()
    cv.create(cvwd, cvht)
    cv.position("middle")

    -- change the default settings for future buttons
    cp.textshadowx = 2
    cp.textshadowy = 2
    
    -- this button will call glu.exit with no args
    exit_button = cp.button("Exit", glu.exit, {})
    
    -- this button will call ChangeLabel
    label_button = cp.button("Change Label...", ChangeLabel)
    
    -- this button will call glu.note with 2 args (false means don't show Cancel button)
    big_button = cp.button(currlabel, glu.note, {"Ouch!",false})
    
    -- after a button has been created we can change its settings
    big_button.setfont("roman-bold",30)
    big_button.ht = 80
    big_button.radius = 20
    big_button.setbackcolor(backcolor)
    big_button.settextcolor(textcolor)
    big_button.setborder(10,bordercolor)
    big_button.settextgap(20)

    -- turn off shadows for labels in check boxes, radio buttons, sliders
    cp.textshadowx = 0
    cp.textshadowy = 0
    cp.radius = 3
    
    -- create check boxes that will call a corresponding Toggle function
    show_checkbox = cp.checkbox("Show", ToggleShown)
    enable_checkbox = cp.checkbox("Enable", ToggleEnabled)
    
    -- create radio buttons for specifying which color the sliders will change
    back_radio = cp.radiobutton("Background", SelectColor)
    border_radio = cp.radiobutton("Border", SelectColor)
    text_radio = cp.radiobutton("Label", SelectColor)
    
    -- make slider buttons circular
    cp.sliderht = 20
    cp.sliderwd = 20
    cp.radius = 10

    -- create sliders for adjusting various colors;
    -- ColorChanged will only be called when a slider's value changes
    r_slider = cp.slider(256, 0, 255, ColorChanged)
    g_slider = cp.slider(256, 0, 255, ColorChanged)
    b_slider = cp.slider(256, 0, 255, ColorChanged)
    r_slider.setbackcolor(cp.red)
    g_slider.setbackcolor(cp.green)
    b_slider.setbackcolor(cp.blue)

    cv.rgba(cp.black)
    cv.text("msg", "Use the sliders to change these colors:")
end

--------------------------------------------------------------------------------

function DrawCanvas()
    cv.rgba(cp.white)
    cv.fill()
    cv.rgba(cp.black)   -- for UpdateSlider text
    cv.blend(2)         -- canvas background is opaque

    -- show Exit button in bottom right corner of canvas
    exit_button.show(cvwd - exit_button.wd - 10, cvht - exit_button.ht - 10)

    local y = 20
    -- show label_button near top of canvas and centered horizontally
    label_button.show((cvwd - label_button.wd) // 2, y)
    y = y + label_button.ht + 20
    
    -- show big_button under label_button
    if shown then big_button.show((cvwd - big_button.wd) // 2, y) end
    
    -- show check boxes under big_button
    local x = (cvwd - math.max(show_checkbox.wd, enable_checkbox.wd)) // 2
    y = y + big_button.ht + 20
    show_checkbox.show(x, y, shown)
    y = y + show_checkbox.ht + 5
    enable_checkbox.show(x, y, enabled)

    -- show sliders under check boxes
    y = y + enable_checkbox.ht + 20
    UpdateSlider(r_slider, y, "R", color[1])
    y = y + r_slider.ht + 5
    UpdateSlider(g_slider, y, "G", color[2])
    y = y + r_slider.ht + 5
    UpdateSlider(b_slider, y, "B", color[3])

    -- show msg under sliders
    y = y + b_slider.ht + 15
    local msgwd, msght = cv.getsize("msg")
    cv.paste("msg", (cvwd - msgwd) // 2, y)

    -- show radio buttons under msg
    y = y + msght + 5
    back_radio.show(x, y, color == backcolor)
    y = y + back_radio.ht + 5
    border_radio.show(x, y, color == bordercolor)
    y = y + back_radio.ht + 5
    text_radio.show(x, y, color == textcolor)

    glu.update()
end

--------------------------------------------------------------------------------

function EventLoop()
    while true do
        local event = cp.process( glu.getevent() )
        -- event is an empty string if glu.getevent() was empty or if
        -- cp.process handled a click in a button, slider, check box, etc
        if #event == 0 then
            glu.sleep(5) -- don't hog CPU if idle
        else
            -- allow key events like "key h none" to show help window
            glu.doevent(event)
        end
    end
end

--------------------------------------------------------------------------------

function Main()
    glu.settitle("Buttons")
    CreateCanvas()
    DrawCanvas()
    EventLoop()
end

--------------------------------------------------------------------------------

status, err = xpcall(Main, gp.trace)
if err then glu.continue(err) end
-- the following code is always executed
cv.delete()
