codeworld-base-0.2.0.0: Replacement base module for CodeWorld

Safe HaskellNone
LanguageHaskell98

Extras.Widget

Contents

Description

A very simple Graphical User Interface (GUI) for user interaction with buttons, checkboxes, sliders and a few others.

Synopsis

Documentation

Widget API

To use the extra features in this module, you must begin your code with this line:

import Extras.Widget

guiDrawingOf :: ([Widget], [Number] -> Picture) -> Program #

The function guiDrawingOf is an entry point for drawing that allows access to a simple GUI. It needs two arguments: a list of Widgets and a function to create your drawing. This user-supplied drawing function will have access to the list of the current values of the widgets, which is passed as an argument.

Example of use:

program = guiDrawingOf(widgets,draw)
  where
  widgets = [ withConversion(\v -> 1 + 19 * v   , slider("width"        ,-7,-7))
            , withConversion(\v -> 1 + 19 * v   , slider("height"       ,-7,-9))
            , withConversion(flipflop           , toggle("show circle"  ,-7,-5))
            , withConversion(flipflop           , button("show in green",-7,-3))
            , withConversion(\v -> 0.2 + 0.8 * v, randomBox("radius"    ,-7,-1))
            ]

  flipflop(v) = truncation(1 + 2 * v)

draw(values) = blank
  & [blank, circle(r)]#s
  & colored(solidRectangle(w,h),[red,green]#c)
  where
  w = values#1
  h = values#2
  s = values#3
  c = values#4
  r = values#5

Note that the order in which the widgets are defined is important, because it determines how to access the correct value. Each widget fits in a box 4 units wide and 1 unit high.

guiActivityOf :: ([Widget], [Number] -> state, ([Number], state, Event) -> state, ([Number], state) -> Picture) -> Program #

The function guiActivityOf is similar to activityOf, but it also takes in a list of widgets. The updating and drawing functions also receive a list of the current values of the widgets.

Example of use:

program = guiActivityOf(widgets,init,update,draw)
  where
  widgets = [ withConversion(\v -> 20 * v, slider("width",-7,-7))
            , withConversion(\v -> 2 + 3 * v, slider("height",-7,-9))
            , withConversion
              (\v -> truncation(1 + 2*v), toggle("show circle",-7,-5))
            , button("restart",-7,-3)
            , randomBox("new color",-7,-1)
            ]

draw(values,(color@(RGB(r1,r2,r3)),angle,_)) = colored(base,color)
    & [blank, circle(5)]#s
    & translated(lettering(msg),0,9)
    where
    msg = joined(["(",printed(r1),",",printed(r2),",",printed(r3),")"])
    base = rotated(solidRectangle(w,h),angle)
    w = values#1
    h = values#2
    s = values#3

  init(rs) = (RGB(rs#1,rs#2,rs#3),0,0)

  update(values,(color@(RGB(r1,r2,r3)),angle,wait),TimePassing(_))
    | values#4 > 0 , wait == 0 = (RGB(r2,r3,r),0,values#4)
    | otherwise = (color,angle+1,wait)
    where
    r = values#5

  update(values,(color,angle,wait),PointerRelease(_)) = (color,angle,0)

  update(values,state,event) = state

Note that pre-defined actions on the widgets take precedence over anything that you define in your updating function, so you cannot alter the default behavior of the widgets.

Widgets

data Widget #

The internal structure of a Widget is not exposed in the user interface. You have access only to the current value of each widget.

toggle :: (Text, Number, Number) -> Widget #

A toggle (checkbox) with the given label at the given location. When the box is not set, the value produced is 0. When the box is set, the value produced is 0.5

button :: (Text, Number, Number) -> Widget #

A button placed at the given location. While the button is pressed, the value produced is 0.5, but when the button is released, the value reverts back to 0.

slider :: (Text, Number, Number) -> Widget #

A slider with the given label at the given location. The possible values will range from 0 to 1, and the initial value will be 0.

randomBox :: (Text, Number, Number) -> Widget #

A box that produces a random number between 0 and 1. Each time you click on it, the value will change. The value 1 is never produced, so the actual range of values is 0 to 0.99999...

timer :: (Text, Number, Number) -> Widget #

A toggle that counts time up when you set it. When you click on the left side of the widget, the current value is reset to 0. You can stop the timer and start it again, and the value will increase from where it was when you stopped it.

Example:

program = guiDrawingOf(widgets,draw)
  where
  widgets = [ withConversion(\v -> 1 + 9 * v , slider("length",-7,-7))
            , withConversion(\v -> v * 30    , timer("angle"  ,-7,-9)) ]

  draw([l,a]) = rotated(translated(colored(solidRectangle(l,0.25),red),l/2,0),a)

The timer operates in seconds, including decimals. However, the precision of the timer is not guaranteed beyond one or two decimals.

counter :: (Text, Number, Number) -> Widget #

A button that keeps incrementing the value each time you press it. The initial value is 1.

Convenience functions

withConversion :: (Number -> Number, Widget) -> Widget #

Make the widget use the provided function to convert values from the default range of a widget to a different range.

Example:

newSlider = withConversion(\v -> 20 * v - 10, oldSlider)

Assuming that the old slider did not have any conversion function applied to it, the example above will make the new slider produce values between -10 and 10, while the old slider will still produce values between 0 and 1

setConversion :: (Number -> Number) -> Widget -> Widget #

Same functionality as withConversion, but using a different convention for the arguments.

Examples

widgetExample1 :: Program #

This is the example shown in the documentation for guiDrawingOf

widgetExample2 :: Program #

This is the example shown in the documentation for guiActivityOf

widgetExample3 :: Program #

This is the example shown in the documentation for timer

widgetExample4 :: Program #

This example shows a tree created by a recursive function