Define the generic operations available on concrete widgets in terms of
a generic set of classes. We can then make individual instantiations 
eg for Tcl. This allows abstract definitions of the rendering operations
for abstract widgets (Widget.lhs DisplayWidget.lhs)
\begin{code}
module WH (module WH,PlacePos(..)) where
import StaticTypes
import Dynamic
import Identify
import IOExts
import Maybe
import PlacePos
import Listener
import WidgetExports (Config)

\end{code}

WidgetItem - a basic widget. 
   It can be configure action to set values such as color, this uses the 
   Config type which is imported from the actual widget system 
   (such as TclHaskell);
   It has an action to destroy itself;
   It has a unique Identifier;
   It has a method to add a finaliser, which is an action that is run when
   the widget is destroyed

\begin{code}

class WidgetItem w where
 cset :: w -> [Config] -> IO ()
 destroy :: w -> IO ()
 uniqueId :: w -> Ident
 addFinaliserW :: w -> IO () -> IO ()

\end{code}

   A Window Item - a toplevel window. It can be mapped, unmapped, iconified.
   We can also get a panel from it to display panel item widgets in.
   It is assumed there will be one win panel in the window. We should 
   make sub panels from the winpanel the rest of the time.

\begin{code}
class WidgetItem w => WindowItem w where
 showWindow :: w -> IO ()
 hideWindow :: w -> IO ()
 iconifyWindow :: w -> IO ()
 getWinPanel :: w -> IO Panel
\end{code}

A Panel item. It can be added to a grid or to a box. Box items have an 
ordering.
It can be raised or lowered in stacking order.
(Panels, boxes and grids are defined later)

\begin{code}

class WidgetItem w => PanelItem w where
 gridAdd :: w -> Grid -> GridLoc -> [GridBagConstraint] -> IO Remover
 boxAdd :: w -> Box -> PlacePos Ident -> [PackInfo] -> IO Remover

 raise :: w -> Maybe Ident -> IO ()
 lower :: w -> Maybe Ident -> IO ()

\end{code}

A canvas item. It has be mapped unmapped, transformed, raised or lowered in
the stacking order. It therefore uses absolute coordinates within its canvas.

\begin{code}

class WidgetItem w => CanvasItem w where
 showItem :: w -> IO ()
 hideItem :: w -> IO ()
 transformItem :: Transform2 -> w -> IO ()
 raiseItem :: w -> Maybe Ident -> IO ()
 lowerItem :: w -> Maybe Ident -> IO ()

\end{code}

 Bindable - bind user input to widgets. Ask to listen for a particular action
 Here values of type UserAction; get a remove action to unregister interest

\begin{code}
class WidgetItem w => Bindable w where
 bind :: w -> Action -> Listener UserAction -> IO (IO ())
\end{code}

   Has_Action - widgets with actions, such as command buttons. 
   They tell a listener when fired, and provide a remove action to unregister

\begin{code}
class WidgetItem w => Has_Action w where
 action :: w -> Listener () -> IO (IO ())
\end{code}

 Scrollable widgets - 
   1) what percentage is scrolled, (first value is position of top of real 
      object in widget, and the second is the position of the bottom, both as 
      percentages), 
   2) move to a given percentage, 
   3) move by a number of scroll units 

\begin{code}
class XViewScroll w where
 xviewPercent :: w -> IO (Double,Double)
 xviewMoveTo :: w -> Double -> IO ()
 xviewScroll :: w -> ScrollUnits -> IO ()

class YViewScroll w where
 yviewPercent :: w -> IO (Double,Double)
 yviewMoveTo :: w -> Double -> IO ()
 yviewScroll :: w -> ScrollUnits -> IO ()

data ScrollUnits = FullScreens Int | Units Int
\end{code}
{- Scan through to give appearance of dragging. mark marks a given point to
   start dragging, drag performs a drag from the last mark -}
\begin{code}
class Scan w where
 scanMark :: w -> Int -> Int -> IO ()
 scanDrag :: w -> Int -> Int -> IO ()
\end{code}

A panel is a class. We can make subpanels, and make a grid or box layout
for the panel. 

A Panel is an existential type containing something that is a panel (IsPanel)

\begin{code}
class (Bindable w,PanelItem w) => IsPanel w where
 mkSubPanel :: w -> IO Panel
 setGridLayout :: w -> IO Grid
 setBoxLayout :: w -> IO Box
 
data Panel = forall w . IsPanel w => Panel w

instance WidgetItem Panel where
 uniqueId (Panel x) = uniqueId x
 cset (Panel x) = cset x
 destroy (Panel x) = destroy x
 addFinaliserW (Panel x) = addFinaliserW x

instance PanelItem Panel where
 gridAdd (Panel x) = gridAdd x
 boxAdd (Panel x) = boxAdd x
 raise (Panel x) = raise x
 lower (Panel x) = lower x

instance Bindable Panel where
 bind (Panel x) = bind x

instance IsPanel Panel where
 mkSubPanel (Panel x) = mkSubPanel x
 setGridLayout (Panel x) = setGridLayout x
 setBoxLayout (Panel x) = setBoxLayout x

\end{code}

Grids. A grid is a form of panel. 
Grid items are layout out in a 2d grid, and therefore each element has 
a containing area.
It allows constraints to set: 
the x and y width of a grid item;
pad grid items;
anchor grid items to a particular corner;
fill the grid item containing area in X or Y.

\begin{code}

data Grid = forall w . IsPanel w => Grid w

data GridBagConstraint = 
	  WidthX ! Int
	| WidthY ! Int
	| GridPad ! Pad
	| GridPadInternal ! Pad
	| GridAnchor ! Anchor
	| GridFill ! Fill

type GridLoc = (Int,Int)
\end{code}

A box is a form of panel.
Items in a box are placed either above each other or beside each other. 
A box has a current mode (one of above or beside).
A box contains a list of items. New items are inserted in this list.
A box item can be told to 
 fill in x or y.
 expand to fill extra available space
 anchor to a corner
 pad extra space
 (or a system depenent pack info PackFree)
\begin{code}
data Box = forall w . IsPanel w => Box w (IORef PackMode) (IORef [Ident])

boxSetMode :: Box -> PackMode -> IO ()
boxSetMode (Box _ ref _) = writeIORef ref

boxGetMode :: Box -> IO PackMode
boxGetMode (Box _ ref _) = readIORef ref
 
data PackInfo = 
        PackFill ! Fill
      | PackExpand ! Bool
      | PackFree ! String ! String
      | PackAnchor ! Anchor
      | PackPad ! Pad
      | PackPadInternal ! Pad
 deriving (Show,Eq)

samePack :: PackInfo -> PackInfo -> Bool
samePack (PackFill _) (PackFill _) = True
samePack (PackExpand _) (PackExpand _) = True
samePack (PackAnchor _) (PackAnchor _) = True
samePack (PackFree s1 _) (PackFree s2 _) = s1 == s2
samePack (PackPad _) (PackPad _) = True
samePack (PackPadInternal _) (PackPadInternal _) = True
samePack _ _ = False

data Pad = PadX ! Int | PadY ! Int 
 deriving (Show,Eq)

data PackMode = PackAbove | PackBeside
 deriving (Show,Eq)

data Fill = FillX | FillY | FillXY
 deriving (Show,Eq)

data Anchor = N | S | E | W | NE | NW | SE | SW | C
 deriving (Eq,Show)
\end{code}

Some abstract generic types that can be used in configuration information.

\begin{code}
data SelectMode = SingleMode | BrowseMode | MultipleMode
                | ExtendedMode
 deriving (Show,Eq)
data Justify = LeftJ | RightJ | CenterJ
 deriving (Show,Eq)
data Relief = Raised | Sunken | Flat | Ridge | Solid | Groove
 deriving (Show,Eq)
data Wrap = NoWrap | CharWrap | WordWrap
 deriving (Show,Eq)
data ActiveState = Active | Disabled | Normal
 deriving (Show,Eq)
\end{code}

Request to listen to particular actions ie user input. We may be interested
in restricted case with only modifiers.

\begin{code}
data Action = AskButton Int Bool [Modifier]
            | AskMotion [Modifier]
            | AskResize
            | AskDestroy
            | AskAction String String
	    | AskEnter [Modifier]
	    | AskLeave [Modifier]
	    | AskKey Bool (Maybe Key) [Modifier]
 deriving Show

instance Eq Action where
 AskButton n1 b1 m1  == AskButton n2 b2 m2 = n1 == n2 && b1 == b2 && m1 == m2
 AskMotion m1 == AskMotion m2 = m1 == m2
 AskDestroy == AskDestroy = True
 AskAction s1 s12 == AskAction s2 s22 = s1 == s2 && s12 == s22
 AskKey b1 mbk1 ms1 == AskKey b2 mbk2 ms2 =
    b1 == b2 && ms1 == ms2 && ((not $ isJust mbk1 && isJust mbk2)
				|| 
				(fromJust mbk1 == fromJust mbk2)) 
 AskEnter ms1 == AskEnter ms2 = ms1 == ms2
 AskLeave ms1 == AskLeave ms2 = ms1 == ms2
 AskResize == AskResize = True
 _ == _ = False

data Key = Return | Escape | KeyChar Char | Key String | Tab | Caps | Shift 
	 | Control | Alt | Space | App | CursorLeft | CursorDown | CursorRight 
	 | CursorUp | Next | Prior | Delete | Insert | Home | End 
	 | BackSpace | F Int 
 deriving (Eq,Show)
\end{code}

The Modifier type is defined as follows. We can restrict input to only repeated events, such as double clicks (DoubleM) or triple clicks (TripleM); to input only when the control (ControlM), alt (AltM) or shift (ShiftM) key is pressed; to input to when only a button is pressed (ButtonPressedM). We can also use system specific modifiers through a String name. This allows access to specific Tcl modifiers that are not covered here.

\begin{code}

data Modifier = 
      DoubleM
	| TripleM
	| ControlM
	| ShiftM
	| AltM
	| ButtonPressedM Int
	| AMod String
 deriving (Show,Eq)
\end{code}

when listening for input we hear user actions
 
\begin{code}

data UserAction 
  = Resize      -- new size
      Vector2
  | Button
      Int       -- which button
      Bool      -- down(True) or up(False)?  (dbl click == down)
      [Modifier]
  | MouseMove
      Point2 [Modifier]
  | CharKey
      Bool      -- press(True) or release(False) ?
      Key       -- the ASCII key press (no up/down)
      [Modifier]
  | Enter [Modifier] | Leave [Modifier] 
  | ExtAction String String
  | ExtActionDyn String Dynamic
  | Destroy
  deriving (Show)  

\end{code}

