Copyright | (c) Daniel Winograd-Cort 2014 |
---|---|
License | see the LICENSE file in the distribution |
Maintainer | dwc@cs.yale.edu |
Stability | experimental |
Safe Haskell | None |
Language | Haskell98 |
- type TerminationProc = Maybe (IO ())
- nullTP :: TerminationProc
- mergeTP :: TerminationProc -> TerminationProc -> TerminationProc
- data CTX = CTX {}
- data Flow
- makeLayout :: LayoutType -> LayoutType -> Layout
- data LayoutType
- nullLayout :: Layout
- data Layout
- divideCTX :: CTX -> Layout -> Layout -> (CTX, CTX)
- mergeLayout :: Flow -> Layout -> Layout -> Layout
- mergeGraphics :: CTX -> (Graphic, Layout) -> (Graphic, Layout) -> Graphic
- type DirtyBit = Bool
- type Focus = (WidgetID, FocusInfo)
- type WidgetID = Int
- data FocusInfo
- data UIEvent
- data Key
- data SpecialKey
- = KeyF1
- | KeyF2
- | KeyF3
- | KeyF4
- | KeyF5
- | KeyF6
- | KeyF7
- | KeyF8
- | KeyF9
- | KeyF10
- | KeyF11
- | KeyF12
- | KeyLeft
- | KeyUp
- | KeyRight
- | KeyDown
- | KeyPageUp
- | KeyPageDown
- | KeyHome
- | KeyEnd
- | KeyInsert
- | KeyNumLock
- | KeyBegin
- | KeyDelete
- | KeyShiftL
- | KeyShiftR
- | KeyCtrlL
- | KeyCtrlR
- | KeyAltL
- | KeyAltR
- | KeyEnter
- | KeyTab
- | KeyEsc
- | KeyBackspace
- | KeyUnknown Int
- data MouseButton
- hasShiftModifier :: [Key] -> Bool
- hasCtrlModifier :: [Key] -> Bool
- hasAltModifier :: [Key] -> Bool
- isKeyPressed :: Key -> IO Bool
- updateKeyState :: Key -> Bool -> IO [Key]
UI Types
In this module, we will declare the various types to make creating the
overall UI possible. We will discuss the ideas for widgets in some
detail, but for specifics on the type of a widget (the UISF
type),
see the UISF type in FRP.UISF.UISF, and for information on specific
widgets, see FRP.UISF.Widget.
Widgets are arrows that map multiple inputs to multiple outputs. Additionally, they have a relatively static layout argument that, while it can change over time, is not dependent on any of its inputs at any given moment.
On the input end, a widget will accept:
- a graphical context,
- some information about which widget is in focus (for the purposes of routing key presses and mouse clicks and potentially for drawing the widget differently),
- and the current time.
- an event with data relating to UI actions.
On the output end, a widget will produce from these inputs:
- an indicator of whether the widget needs to be redrawn,
- any focus information that needs to be conveyed to future widgets,
- the graphics to render to display this widget,
- and a procedure to run upon termination (for proper shutdown when finished).
Additionally, as widgets are generic arrows, there will be a parameterized input and output types.
type TerminationProc = Maybe (IO ()) Source
The termination procedure is simply a potential IO action.
nullTP :: TerminationProc Source
The null termination procedure is no action.
mergeTP :: TerminationProc -> TerminationProc -> TerminationProc Source
A method for merging two termination procedures.
Rendering Context
A rendering context specifies the following:
CTX | |
|
Flow determines widget ordering.
UI Layout
:: LayoutType | Horizontal Layout information |
-> LayoutType | Vertical Layout information |
-> Layout |
Layouts for individual widgets typically come in a few standard flavors, so we have this convenience function for their creation. This function takes layout information for first the horizontal dimension and then the vertical.
data LayoutType Source
A dimension can either be:
The null layout is useful for "widgets" that do not appear or take up space on the screen.
More complicated layouts can be manually constructed with direct access to the Layout data type.
- wStretch and hStretch specify how much stretching space (in comparative units) in the width and height should be allocated for this widget.
- wFixed and hFixed specify how much non-stretching space (in pixels) of width and height should be allocated for this widget.
- wMin and hMin specify minimum values (in pixels) of width and height for the widget's stretchy dimensions.
- lFill specifies how much expanding space (in comparative units) this widget should fill out in excess space that would otherwise be unused.
Context and Layout Functions
divideCTX :: CTX -> Layout -> Layout -> (CTX, CTX) Source
Divides the CTX among the two given layouts.
Graphics
mergeGraphics :: CTX -> (Graphic, Layout) -> (Graphic, Layout) -> Graphic Source
Merging two graphics can be achieved with overGraphic, but the mergeGraphic function additionally constrains the graphics based on their layouts and the context. TODO: Make sure this works as well as it should
System State
type Focus = (WidgetID, FocusInfo) Source
The Focus type helps focusable widgets communicate with each other about which widget is in focus. It consists of a WidgetID and a FocusInfo.
The WidgetID for any given widget is dynamic based on how many focusable widgets are active at the moment. It is designed basically as a counter that focusable widgets will automatically (via the focusable function) increment.
The FocusInfo means one of the following:
HasFocus | Indicates that this widget is a subwidget of a widget that is in focus. Thus, this widget too is in focus, and this widget should pass HasFocus forward. |
NoFocus | Indicates that there is no focus information to communicate between widgets. |
SetFocusTo WidgetID | Indicates that the widget whose id is given should take focus. That widget should then pass NoFocus onward. |
DenyFocus | Any widget that sees this value should recognize that they are no longer in focus. This is useful for nested focus. |
UIEvent
The UIEvent data type captures the various types of events that
the UI can produce. These are covered by regular keys, special
keys, mouse button presses, and mouse movement. Any key event
is accompanied by a list of Key
s that were down when the given
event took place.
Key | A Key UIEvent indicates that the user has typed a regular key on his/her keyboard. These will either be upper or lowercase characters. |
SKey | A SKey UIEvent indicates that the user has typed a special
key. These are Enter, Backspace, Tab, Delete, etc. See
|
Button | A Button UIEvent indicates that the user has pressed a mouse button. |
MouseMove | Every time the mouse moves, a MouseMove UIEvent will fire. |
NoUIEvent | The NoUIEvent fires when nothing else is going on. It is important that this happens to allow interaction-independent processing to continue (e.g. timers, animations, etc.). |
A Key can either be a character, a special key, or a mouse button.
data SpecialKey Source
A special key is any non-standard character key. According to
GLUT, KeyUnknown
should never be used, probably because it will
be treated as a weird Char instead of a SpecialKey.
data MouseButton Source
The standard mouse buttons are represented, but for specialty mice,
one can also use the AdditionalButton
value.
Key State Checks
hasShiftModifier :: [Key] -> Bool Source
This is a convenience function that tests whether either of the right or left shift keys is in the given list.
hasCtrlModifier :: [Key] -> Bool Source
This is a convenience function that tests whether either of the right or left control keys is in the given list.
hasAltModifier :: [Key] -> Bool Source
This is a convenience function that tests whether either of the right or left alt keys is in the given list.
isKeyPressed :: Key -> IO Bool Source
Checks the global key state to determine whether the given key is currently pressed down.
Framework Connections
The updateKeyState
function is for use by the GUI framework. It is
not intended for use unless one wants to build their own framework.
The key state is kept around so that it is easy to check if a given key or button is currently pressed down. Unfortunately, I've coded it as a global IORef, which means I'm using unsafePerformIO.