module Graphics.UI.WX.Controls
    ( 
        Align(..), Aligned, alignment
      , Wrap(..), Wrapped, wrap
      , Sorted, sorted
      
      , Panel, panel, panelEx
      , Notebook, notebook
      , focusOn
      
      
      , Button, button, buttonEx, smallButton, buttonRes
      , BitmapButton, bitmapButton, bitmapButtonRes
      
      , TextCtrl, entry, textEntry, textCtrl, textCtrlRich, textCtrlEx
      , textCtrlRes, processEnter, processTab
      
      , CheckBox, checkBox, checkBoxRes
      
      , Choice, choice, choiceEx, choiceRes
      
      , ComboBox, comboBox, comboBoxEx, comboBoxRes
      
      , ListBox, SingleListBox, MultiListBox
      , singleListBox, singleListBoxRes, multiListBox, multiListBoxRes
      
      , RadioBox, radioBox, radioBoxRes
      
      , SpinCtrl, spinCtrl, spinCtrlRes
      
      , Slider, hslider, vslider, sliderEx, sliderRes
      
      , Gauge, hgauge, vgauge, gaugeEx, gaugeRes
      
      , ToggleButton, BitmapToggleButton
      , toggleButton, bitmapToggleButton
      
      , TreeCtrl, treeCtrl, treeCtrlEx, treeEvent, treeCtrlRes
      
      , ListCtrl, listCtrl, listCtrlEx, listCtrlRes, listCtrlSetColumnWidths, listEvent, columns
      , ListView(..), listViewLayout, listViewSetHandler, listViewSelectHandle, listViewSetItems, listViewGetItems, listViewAddItem, listView
      
      , StaticText, staticText, staticTextRes
      
      , SplitterWindow, splitterWindow
      
      , ImageList, imageList, imageListFromFiles
      
      , MediaCtrlBackend(..), MediaCtrl, mediaCtrl, mediaCtrlWithBackend, mediaCtrlEx
      
      , StyledTextCtrl, stcEvent, styledTextCtrl, styledTextCtrlEx
      
      , PropertyGrid, propertyGrid, propertyGridEvent
    ) where
import Graphics.UI.WXCore hiding (Event)
import Graphics.UI.WX.Types
import Graphics.UI.WX.Attributes
import Graphics.UI.WX.Classes
import Graphics.UI.WX.Events
import Graphics.UI.WX.Layout
import Graphics.UI.WX.Media (Media(..))
import Graphics.UI.WX.Variable (variable)
import Graphics.UI.WX.Window
import Control.Monad (forM_)
import Data.Dynamic  
import System.Info (os)
defaultStyle
  = wxCLIP_CHILDREN 
panel :: Window a -> [Prop (Panel ())] -> IO (Panel ())
panel parent props
  = panelEx parent (wxTAB_TRAVERSAL .+. defaultStyle) props
panelEx :: Window a -> Style -> [Prop (Panel ())] -> IO (Panel ())
panelEx parent style props
  = feed2 props style $
    initialContainer $ \id rect -> \props flags  ->
    do p <- panelCreate parent id rect flags
       windowSetFocus p
       set p props
       return p
instance Form (Panel a) where
  layout
    = writeAttr "layout" windowSetLayout
focusOn :: Window a -> IO ()
focusOn w
  = windowSetFocus w
notebook :: Window a -> [Prop (Notebook ())] -> IO (Notebook ())
notebook parent props
  = feed2 props defaultStyle $
    initialContainer $ \id rect -> \props flags ->
    do nb <- notebookCreate parent id rect flags
       set nb props
       return nb
button :: Window a -> [Prop (Button ())] -> IO (Button ())
button parent props
  = buttonEx parent 0 props
smallButton :: Window a -> [Prop (Button ())] -> IO (Button ())
smallButton parent props
  = buttonEx parent wxBU_EXACTFIT props
buttonEx :: Window a -> Style -> [Prop (Button ())] -> IO (Button ())
buttonEx parent stl props
  = feed2 props stl $
    initialWindow $ \id rect ->
    initialText   $ \txt -> \props flags ->
    do b <- buttonCreate parent id txt rect flags
       set b props
       return b
buttonRes :: Window a -> String -> [Prop (Button ())] -> IO (Button ())
buttonRes parent name props =
    do b <- xmlResourceGetButton parent name
       set b props
       return b
instance Commanding (Button a) where
  command  = newEvent "command" buttonGetOnCommand buttonOnCommand
bitmapButton :: Window a -> [Prop (BitmapButton ())] -> IO (BitmapButton ())
bitmapButton parent props
  = feed2 props 0 $
    initialWindow $ \id rect -> \props flags ->
    do bb <- bitmapButtonCreate parent id nullBitmap rect flags
       set bb props
       windowReLayout bb
       return bb
bitmapButtonRes :: Window a -> String -> [Prop (BitmapButton ())] -> IO (BitmapButton ())
bitmapButtonRes parent name props =
    do b <- xmlResourceGetBitmapButton parent name
       set b props
       return b
instance Pictured (BitmapButton a) where
  picture
    = writeAttr "picture" setter
    where
      setter w fname
        = do fpath <- getAbsoluteFilePath fname
             withBitmapFromFile fpath (bitmapButtonSetBitmapLabel w)
data Align   = AlignLeft | AlignRight | AlignCentre
             deriving (Eq,Show,Read,Typeable)
data Wrap    = WrapNone   
             | WrapLine   
             | WrapWord   
             deriving (Eq,Show,Read,Typeable)
instance BitMask Align where
  assocBitMask
    = [(AlignCentre,wxALIGN_CENTRE_HORIZONTAL)
      ,(AlignRight, wxALIGN_RIGHT)
      ,(AlignLeft,  wxALIGN_LEFT)]
instance BitMask Wrap where
  assocBitMask
    = [(WrapNone, wxHSCROLL)
      ,(WrapLine, wxTE_CHARWRAP)
      ,(WrapWord, wxTE_WORDWRAP)]
class Aligned w where
  
  
  alignment :: CreateAttr w Align
initialAlignment :: Aligned w => ([Prop w] -> Style -> a) -> [Prop w] -> Style -> a
initialAlignment cont props style
  = case filterProperty alignment props of
      (PropValue x, ps)  -> cont ps (setBitMask x style)
      (PropModify f, ps) -> cont ps (setBitMask (f (fromBitMask style)) style)
      (PropNone, ps)     -> cont ps style
instance Aligned (TextCtrl a) where
  alignment
    = reflectiveAttr "alignment" getter setter
    where
      getter w
        = do st <- get w style
             return (fromBitMask st)
      setter w align
        = set w [style :~ setBitMask align ]
class Wrapped w where
  
  wrap :: CreateAttr w Wrap
initialWrap cont props style
  = case filterProperty wrap props of
      (PropValue x, ps)  -> cont ps (setBitMask x style)
      (PropModify f, ps) -> cont ps (setBitMask (f (fromBitMask style)) style)
      (PropNone, ps)     -> cont ps style
instance Wrapped (TextCtrl a) where
  wrap
    = reflectiveAttr "wrap" getter setter
    where
      getter w
        = do st <- get w style
             return (fromBitMask st)
      setter w mode
        = set w [style :~ setBitMask mode]
getRichTE =  if (os == "mingw32") || (os == "win32")
             then wxTE_RICH
             else 0
getRichTE2 = if (os == "mingw32") || (os == "win32")
             then wxTE_RICH2
             else 0
entry :: Window a -> [Prop (TextCtrl ())] -> IO (TextCtrl ())
entry parent props
  = textCtrlEx parent getRichTE props
textEntry :: Window a -> [Prop (TextCtrl ())] -> IO (TextCtrl ())
textEntry parent props
  = textCtrlEx parent getRichTE props
textCtrl :: Window a -> [Prop (TextCtrl ())] -> IO (TextCtrl ())
textCtrl parent props
  = textCtrlEx parent (wxTE_MULTILINE .+. getRichTE) props
textCtrlRich :: Window a -> [Prop (TextCtrl ())] -> IO (TextCtrl ())
textCtrlRich parent props
  = textCtrlEx parent (wxTE_MULTILINE .+. getRichTE2) props
textCtrlEx :: Window a -> Style -> [Prop (TextCtrl ())] -> IO (TextCtrl ())
textCtrlEx parent stl props
  = feed2 props stl $
    initialWindow    $ \id rect ->
    initialText      $ \txt ->
    initialWrap      $
    initialAlignment $ \props flags ->
    do e <- textCtrlCreate parent id txt rect flags
       set e props
       return e
textCtrlRes :: Window a -> String -> [Prop (TextCtrl ())] -> IO (TextCtrl ())
textCtrlRes parent name props =
    do t <- xmlResourceGetTextCtrl parent name
       set t props
       return t
instance Commanding (TextCtrl a) where
  command = newEvent "command" textCtrlGetOnTextEnter textCtrlOnTextEnter
processEnter :: Styled w => Attr w Bool
processEnter
  = newAttr "processEnter" getter setter
  where
    getter w
      = do s <- get w style
           return (bitsSet wxTE_PROCESS_ENTER s)
    setter w p
      = set w [style :~ \stl -> stl .+. wxTE_PROCESS_ENTER]
processTab :: Styled w => Attr w Bool
processTab
  = newAttr "processTab" getter setter
  where
    getter w
      = do s <- get w style
           return (bitsSet wxTE_PROCESS_TAB s)
    setter w p
      = set w [style :~ \stl -> stl .+. wxTE_PROCESS_TAB]
staticText :: Window a -> [Prop (StaticText ())] -> IO (StaticText ())
staticText parent props
  = feed2 props 0 $
    initialWindow $ \id rect ->
    initialText   $ \txt -> \props flags ->
    do t <- staticTextCreate parent id txt rect flags 
       set t props
       return t
staticTextRes :: Window a -> String -> [Prop (StaticText ())] -> IO (StaticText ())
staticTextRes parent name props =
    do t <- xmlResourceGetStaticText parent name
       set t props
       return t
instance Commanding (CheckBox a) where
  command = newEvent "command" checkBoxGetOnCommand checkBoxOnCommand
instance Checkable (CheckBox a) where
  checkable
    = enabled
  checked
    = newAttr "checked" checkBoxGetValue checkBoxSetValue
checkBox :: Window a -> [Prop (CheckBox ())] -> IO (CheckBox ())
checkBox parent props
  = feed2 props 0 $
    initialWindow $ \id rect ->
    initialText   $ \txt -> \props flags ->
    do c <- checkBoxCreate parent id txt rect flags
       set c props
       return c
checkBoxRes :: Window a -> String -> [Prop (CheckBox ())] -> IO (CheckBox ())
checkBoxRes parent name props =
    do c <- xmlResourceGetCheckBox parent name
       set c props
       return c
class Sorted w where
  
  sorted :: CreateAttr w Bool
instance Sorted (Choice a) where
  sorted
    = createAttr "sorted" getter setter
    where
      getter w
        = do st <- get w style
             return (bitsSet wxCB_SORT st)
      setter w sort
        = set w [style :~ \st -> if sort then st .+. wxCB_SORT else st .-. wxCB_SORT]
initialSorted :: Sorted w => ([Prop w] -> Style -> a) -> [Prop w] -> Style -> a
initialSorted
  = withStyleProperty sorted wxCB_SORT
instance Selecting (Choice ()) where
  select = newEvent "select" choiceGetOnCommand choiceOnCommand
instance Selection (Choice ()) where
  selection
    = newAttr "selection" choiceGetSelection choiceSetSelection
instance Items (Choice a) String where
  itemCount
    = readAttr "itemCount" choiceGetCount
  item i
    = newAttr "item" (\w -> choiceGetString w i) (\w x -> choiceSetString w i x)
  itemAppend w x
    = choiceAppend w x
  itemDelete w i
    = choiceDelete w i
choice :: Window a -> [Prop (Choice ())] -> IO (Choice ())
choice parent props
  = choiceEx parent 0 props
choiceEx :: Window a -> Style -> [Prop (Choice ())] -> IO (Choice ())
choiceEx parent flags props
  = feed2 props flags $
    initialWindow $ \id rect ->
    initialSorted $ \props flags ->
    do c <- choiceCreate parent id rect [] flags
       set c props
       return c
choiceRes :: Window a -> String -> [Prop (Choice ())] -> IO (Choice ())
choiceRes parent name props =
    do c <- xmlResourceGetChoice parent name
       set c props
       return c
instance Commanding (ComboBox a) where
  command
    = newEvent "command" comboBoxGetOnTextEnter comboBoxOnTextEnter
instance Selecting (ComboBox a) where
  select
    = newEvent "select" comboBoxGetOnCommand comboBoxOnCommand
instance Selection (ComboBox a) where
  selection
    = newAttr "selection" comboBoxGetSelection comboBoxSetSelection
comboBox :: Window a -> [Prop (ComboBox ())] -> IO (ComboBox ())
comboBox parent props
  = comboBoxEx parent (wxCB_DROPDOWN) props
comboBoxEx :: Window a -> Style -> [Prop (ComboBox ())] -> IO (ComboBox ())
comboBoxEx parent flags props
  = feed2 props flags $
    initialWindow $ \id rect ->
    initialText   $ \txt ->
    initialSorted $ \props flags ->
    do cb <- comboBoxCreate parent id txt rect [] flags
       set cb props
       return cb
comboBoxRes :: Window a -> String -> [Prop (ComboBox ())] -> IO (ComboBox ())
comboBoxRes parent name props =
    do c <- xmlResourceGetComboBox parent name
       set c props
       return c
instance Sorted (ListBox a) where
  sorted
    = createAttr "sorted" getter setter
    where
      getter w
        = do st <- get w style
             return (bitsSet wxLB_SORT st)
      setter w sort
        = set w [style :~ \st -> if sort then st .+. wxLB_SORT else st .-. wxLB_SORT]
instance Selecting (ListBox a) where
  select
    = newEvent "select" listBoxGetOnCommand listBoxOnCommand
instance Items (ListBox a) String where
  itemCount
    = readAttr "itemCount" listBoxGetCount
  item i
    = newAttr "item" (\w -> listBoxGetString w i) (\w x -> listBoxSetString w i x)
  itemAppend w x
    = listBoxAppend w x
  itemDelete w i
    = listBoxDelete w i
type SingleListBox a  = ListBox (CSingleListBox a)
data CSingleListBox a = CSingleListBox
instance Selection (SingleListBox a) where
  selection
    = newAttr "selection" listBoxGetSelection (\w x -> listBoxSetSelection w x True)
type MultiListBox a   = ListBox (CMultiListBox a)
data CMultiListBox a  = CMultiListBox           
instance Selections (MultiListBox a) where
  selections
    = newAttr "selections" listBoxGetSelectionList setter
    where
      setter w is =
        do oldSelection <- listBoxGetSelectionList w
           sequence_ [ listBoxSetSelection w i False 
                     | i <- oldSelection
                     , i `notElem` is 
                     ]
           mapM_ (\i -> listBoxSetSelection w i True) is
singleListBox :: Window a -> [Prop (SingleListBox ())] -> IO (SingleListBox ())
singleListBox parent props
  = feed2 props (wxLB_SINGLE .+. wxHSCROLL .+. wxLB_NEEDED_SB) $
    initialWindow $ \id rect ->
    initialSorted $ \props flags ->
    do lb <- listBoxCreate parent id rect [] flags
       let sl = (objectCast lb :: SingleListBox ())
       set sl props
       return sl
singleListBoxRes :: Window a -> String -> [Prop (SingleListBox ())] -> IO (SingleListBox ())
singleListBoxRes parent name props =
    do l <- xmlResourceGetListBox parent name
       let sl = (objectCast l :: SingleListBox())
       set sl props
       return sl
multiListBox :: Window a -> [Prop (MultiListBox ())] -> IO (MultiListBox ())
multiListBox parent props
  = feed2 props (wxLB_EXTENDED .+. wxHSCROLL .+. wxLB_NEEDED_SB) $
    initialWindow $ \id rect ->
    initialSorted $ \props flags ->
    do lb <- listBoxCreate parent id rect [] flags
       let ml = (objectCast lb :: MultiListBox ())
       set ml props
       return ml
multiListBoxRes :: Window a -> String -> [Prop (MultiListBox ())] -> IO (MultiListBox ())
multiListBoxRes parent name props =
    do l <- xmlResourceGetListBox parent name
       let ml = (objectCast l :: MultiListBox())
       set ml props
       return ml
instance Selecting (RadioBox a) where
  select
    = newEvent "select" radioBoxGetOnCommand radioBoxOnCommand
instance Selection (RadioBox a) where
  selection
    = newAttr "selection" radioBoxGetSelection radioBoxSetSelection
instance Items (RadioBox a) String where
  itemCount
    = readAttr "itemCount" radioBoxNumber
  item i
    = newAttr "item" (\r -> radioBoxGetItemLabel r i) (\r s -> radioBoxSetItemLabel r i s)
  itemAppend
    = error "Controls.itemAppend: you can not append items to a radiobox"
  itemDelete
    = error "Controls.itemDelete: you can not delete items of a radiobox"
radioBox :: Window a -> Orientation -> [String] -> [Prop (RadioBox ())] -> IO (RadioBox ())
radioBox parent direction labels props
  = feed2 props (if (direction==Horizontal) then wxRA_SPECIFY_ROWS else wxRA_SPECIFY_COLS) $
    initialWindow $ \id rect ->
    initialText   $ \title -> \props flags ->
    do r <- radioBoxCreate parent id title rect labels 1 flags
       set r props
       return r
radioBoxRes :: Window a -> String -> [Prop (RadioBox ())] -> IO (RadioBox ())
radioBoxRes parent name props =
    do rb <- xmlResourceGetRadioBox parent name
       set rb props
       return rb
hgauge :: Window a -> Int -> [Prop (Gauge ())] -> IO (Gauge ())
hgauge parent range props
  = gaugeEx parent range (wxHORIZONTAL .+. wxGA_SMOOTH) props
vgauge :: Window a -> Int -> [Prop (Gauge ())] -> IO (Gauge ())
vgauge parent range props
  = gaugeEx parent range (wxVERTICAL .+. wxGA_SMOOTH) props
gaugeEx :: Window a -> Int -> Style -> [Prop (Gauge ())] -> IO (Gauge ())
gaugeEx parent range style props
  = do g <- gaugeCreate parent idAny range rectNull style
       set g props
       return g
gaugeRes :: Window a -> String -> [Prop (Gauge ())] -> IO (Gauge ())
gaugeRes parent name props =
    do g <- xmlResourceGetGauge parent name
       set g props
       return g
instance Selection (Gauge a) where
  selection
    = newAttr "selection" getter setter
    where
      getter g
        = do i  <- gaugeGetValue g
             hi <- gaugeGetRange g
             return (max 0 (min hi i))
      setter g i
        = do hi <- gaugeGetRange g
             gaugeSetValue g (max 0 (min hi i))
instance Commanding (Slider a) where
  command = newEvent "command" sliderGetOnCommand sliderOnCommand
hslider :: Window a -> Bool -> Int -> Int -> [Prop (Slider ())] -> IO (Slider ())
hslider parent showLabels min max props
  = sliderEx parent min max (wxHORIZONTAL .+. (if showLabels then wxSL_LABELS else 0)) props
vslider :: Window a -> Bool -> Int -> Int -> [Prop (Slider ())] -> IO (Slider ())
vslider parent showLabels min max props
  = sliderEx parent min max (wxVERTICAL .+. (if showLabels then wxSL_LABELS else 0)) props
sliderEx :: Window a -> Int -> Int -> Style -> [Prop (Slider ())] -> IO (Slider ())
sliderEx parent min max style props
  = do s <- sliderCreate parent style min min max rectNull style
       set s props
       return s
sliderRes :: Window a -> String -> [Prop (Slider ())] -> IO (Slider ())
sliderRes parent name props =
    do s <- xmlResourceGetSlider parent name
       set s props
       return s
instance Selection (Slider a) where
  selection
    = newAttr "selection" getter setter
    where
      getter s
        = do i  <- sliderGetValue s
             lo <- sliderGetMin s
             hi <- sliderGetMax s
             return (max lo (min hi i))
      setter s i
        = do lo <- sliderGetMin s
             hi <- sliderGetMax s
             sliderSetValue s (max lo (min hi i))
spinCtrl :: Window a -> Int -> Int -> [Prop (SpinCtrl ())] -> IO (SpinCtrl ())
spinCtrl parent lo hi props
  = feed2 props wxSP_ARROW_KEYS $
    initialWindow $ \id rect ->
    initialText   $ \txt -> \props flags ->
    do sc <- spinCtrlCreate parent id txt rect flags (min lo hi) (max lo hi) lo
       set sc props
       return sc
spinCtrlRes :: Window a -> String -> [Prop (SpinCtrl ())] -> IO (SpinCtrl ())
spinCtrlRes parent name props =
    do s <- xmlResourceGetSpinCtrl parent name
       set s props
       return s
instance Selection (SpinCtrl a) where
  selection
    = newAttr "selection" getter setter
    where
      getter sc
        = do i  <- spinCtrlGetValue sc
             lo <- spinCtrlGetMin sc
             hi <- spinCtrlGetMax sc
             return (max lo (min hi i))
      setter sc i
        = do lo <- spinCtrlGetMin sc
             hi <- spinCtrlGetMax sc
             spinCtrlSetValue sc (max lo (min hi i))
instance Selecting (SpinCtrl a) where
  select 
    = newEvent "select" spinCtrlGetOnCommand spinCtrlOnCommand
toggleButton :: Window a -> [Prop (ToggleButton ())] -> IO (ToggleButton ())
toggleButton parent props
  = feed2 props defaultStyle $
    initialWindow $ \id rect -> \props flags ->
    do bb <- toggleButtonCreate parent id "" rect flags
       set bb props
       return bb
instance Commanding (ToggleButton a) where
  command  = newEvent "command" toggleButtonGetOnCommand toggleButtonOnCommand
instance Checkable (ToggleButton a) where
  checkable = enabled 
  checked   = newAttr "checked" toggleButtonGetValue toggleButtonSetValue
bitmapToggleButton :: Window a -> [Prop (BitmapToggleButton ())] -> IO (BitmapToggleButton ())
bitmapToggleButton parent props
  = feed2 props defaultStyle $
    initialWindow $ \id rect -> \props flags ->
    do img <- imageCreateFromPixels (Size 1 1) [black]
       bm  <- bitmapCreateFromImage img (1)
       bb  <- bitmapToggleButtonCreate parent id bm rect flags
       set bb props
       return bb
instance Pictured (BitmapToggleButton a) where
  picture
    = writeAttr "picture" setter
    where
      setter w fname
        = do fpath <- getAbsoluteFilePath fname
             withBitmapFromFile fpath (bitmapToggleButtonSetBitmapLabel w)
treeEvent :: Event (TreeCtrl a) (EventTree -> IO ())
treeEvent
  = newEvent "treeEvent" treeCtrlGetOnTreeEvent treeCtrlOnTreeEvent
treeCtrl :: Window a -> [Prop (TreeCtrl ())] -> IO (TreeCtrl ())
treeCtrl parent props
  = treeCtrlEx parent (wxTR_HAS_BUTTONS .+. defaultStyle) props
treeCtrlEx :: Window a -> Style -> [Prop (TreeCtrl ())] -> IO (TreeCtrl ())
treeCtrlEx parent style props
  = feed2 props style $
    initialContainer $ \id rect -> \props flags ->
    do t <- treeCtrlCreate2 parent id rect flags
       set t props
       return t
treeCtrlRes :: Window a -> String -> [Prop (TreeCtrl ())] -> IO (TreeCtrl ())
treeCtrlRes parent name props =
    do t <- xmlResourceGetTreeCtrl parent name
       set t props
       return t
instance Items (ListCtrl a) [String] where
  itemCount
    = readAttr "itemCount" listCtrlGetItemCount
  item i
    = newAttr "item" getter setter
    where
      getter l
        = bracket listItemCreate
                  listItemDelete
                  (\li -> do count <- listCtrlGetColumnCount l
                             mapM (\column -> do listItemSetColumn li (column1)
                                                 listItemSetId li i
                                                 listItemSetMask li wxLIST_MASK_TEXT
                                                 listCtrlGetItem l li
                                                 listItemGetText li) [1..count])
      setter l texts
        = do count <- listCtrlGetItemCount l
             when (i == count) (do listCtrlInsertItemWithLabel l i (show i) (1); return ())
             mapM_ (\(column,txt) -> listCtrlSetItem l i column txt (1)) (zip [0..] texts)
  itemAppend l texts
    = do count <- listCtrlGetItemCount l
         listCtrlInsertItemWithLabel l count (show count) (1)
         mapM_ (\(column,txt) -> listCtrlSetItem l count column txt (1)) (zip [0..] texts)
  itemDelete l i
    = do listCtrlDeleteItem l i
         return ()
  itemsDelete l
    = do listCtrlDeleteAllItems l
         return ()
columns :: Attr (ListCtrl a) [(String,Align,Int)]
columns
  = newAttr "columns" getter setter
  where
    setter l xs
      = do n <- listCtrlGetColumnCount l
           mapM_ (\c -> listCtrlDeleteColumn l 0) (reverse [1..n])
           mapM_ (insertColumn l) (zip [0..] xs)
      where
        insertColumn l (idx,(name,align,width))
          = let alignment = case align of
                              AlignRight -> wxLIST_FORMAT_RIGHT
                              AlignCentre-> wxLIST_FORMAT_CENTER
                              other      -> wxLIST_FORMAT_LEFT
            in listCtrlInsertColumn l idx name alignment width
    getter l
      = do n <- listCtrlGetColumnCount l
           mapM (getColumn l) [0..n]
      where
        getColumn l idx
          = bracket (listCtrlGetColumn2 l idx)
                    (listItemDelete)
                    (\item -> do name      <- listItemGetText item
                                 alignment <- listItemGetAlign item
                                 width     <- listItemGetWidth item
                                 let align | alignment == wxLIST_FORMAT_RIGHT  = AlignRight
                                           | alignment == wxLIST_FORMAT_CENTER = AlignCentre
                                           | otherwise                         = AlignLeft
                                 return (name,align,width)
                    )
listEvent :: Event (ListCtrl a) (EventList -> IO ())
listEvent
  = newEvent "listEvent" listCtrlGetOnListEvent listCtrlOnListEvent
listCtrl :: Window a -> [Prop (ListCtrl ())] -> IO (ListCtrl ())
listCtrl parent props
  = listCtrlEx parent (wxLC_REPORT .+. defaultStyle) props
listCtrlEx :: Window a -> Style -> [Prop (ListCtrl ())] -> IO (ListCtrl ())
listCtrlEx parent style props
  = feed2 props style $
    initialContainer $ \id rect -> \props flags ->
    do l <- listCtrlCreate parent id rect flags
       set l props
       return l
listCtrlRes :: Window a -> String -> [Prop (ListCtrl ())] -> IO (ListCtrl ())
listCtrlRes parent name props =
    do l <- xmlResourceGetListCtrl parent name
       set l props
       return l
listCtrlSetColumnWidths :: ListCtrl () -> Int -> IO ()
listCtrlSetColumnWidths ctrl w = do
  cols <- listCtrlGetColumnCount ctrl
  forM_ [0 .. cols  1] $ \i -> listCtrlSetColumnWidth ctrl i w
data ListView a = ListView {
  listViewCtrl  :: ListCtrl (),
  listViewItems :: Var [a],
  listViewToRow :: a -> [String]
}
listViewLayout :: ListView a -> Layout
listViewLayout = fill . widget . listViewCtrl
listViewSetHandler :: ListView a -> (EventList -> IO ()) -> IO ()
listViewSetHandler list handler =
  set (listViewCtrl list) [on listEvent := handler]
listViewSelectHandle :: ListView a -> (Maybe a -> IO ()) -> EventList -> IO ()
listViewSelectHandle _    _   (ListItemActivated (1)) = propagateEvent
listViewSelectHandle list end (ListItemActivated   n ) = end . Just =<< (!! n) `fmap` listViewGetItems list
listViewSelectHandle _    _   _                        = propagateEvent
listViewSetItems :: ListView a -> [a] -> IO ()
listViewSetItems list its = do
  set (listViewItems list) [value := its]
  set (listViewCtrl list)  [items := map (listViewToRow list) its]
listViewGetItems :: ListView a -> IO [a]
listViewGetItems list = get (listViewItems list) value
listViewAddItem :: ListView a -> a -> IO ()
listViewAddItem list it = do
  its <- (it:) `fmap` get (listViewItems list) value
  listViewSetItems list its
listViewSetColumnWidths :: ListView a -> Int -> IO ()
listViewSetColumnWidths list w = do
  listCtrlSetColumnWidths (listViewCtrl list) w
listView :: Window b -> [String] -> (a -> [String]) -> IO (ListView a)
listView parent cols toRow = do
  ctrl <- listCtrl parent [columns := map (\n -> (n, AlignLeft, 1)) cols]
  var  <- variable [value := []]
  return $ ListView ctrl var toRow
splitterWindow :: Window a -> [Prop (SplitterWindow ())] -> IO (SplitterWindow ())
splitterWindow parent props
  = feed2 props (defaultStyle .+. wxSP_LIVE_UPDATE) $
    initialContainer $ \id rect -> \props flags ->
    do s <- splitterWindowCreate parent id rect flags
       set s props
       return s
imageList :: Size -> IO (ImageList ())
imageList size
  = imageListCreate size True 10
imageListFromFiles :: Size -> [FilePath] -> IO (ImageList ())
imageListFromFiles size files
  = do images <- imageListCreate size True (length files)
       imageListAddIconsFromFiles images size files
       return images
data MediaCtrlBackend =
      DirectShow            
    | MediaControlInterface 
    | WindowsMediaPlayer10  
    | QuickTime             
    | GStreamer             
    | DefaultBackend        
   deriving (Eq,Show)
fromMediaCtrlBackend :: MediaCtrlBackend -> String
fromMediaCtrlBackend back
  = case back of
      DirectShow            -> wxMEDIABACKEND_DIRECTSHOW
      MediaControlInterface -> wxMEDIABACKEND_MCI
      WindowsMediaPlayer10  -> wxMEDIABACKEND_WMP10
      QuickTime             -> wxMEDIABACKEND_QUICKTIME
      GStreamer             -> wxMEDIABACKEND_GSTREAMER
      DefaultBackend        -> ""
wxMEDIABACKEND_DIRECTSHOW = "wxAMMediaBackend"
wxMEDIABACKEND_MCI = "wxMCIMediaBackend"
wxMEDIABACKEND_WMP10 = "wxWMP10MediaBackend"
wxMEDIABACKEND_QUICKTIME = "wxQTMediaBackend"
wxMEDIABACKEND_GSTREAMER = "wxGStreamerMediaBackend"
mediaCtrl :: Window a -> [Prop (MediaCtrl ())] -> IO (MediaCtrl ())
mediaCtrl parent props
  = mediaCtrlEx parent defaultStyle DefaultBackend props
mediaCtrlWithBackend :: Window a -> MediaCtrlBackend -> [Prop (MediaCtrl ())] -> IO (MediaCtrl ())
mediaCtrlWithBackend parent back props
  = mediaCtrlEx parent defaultStyle back props
mediaCtrlEx :: Window a -> Style -> MediaCtrlBackend -> [Prop (MediaCtrl ())] -> IO (MediaCtrl ())
mediaCtrlEx parent style back props
  = feed2 props style $
    initialContainer $ \id rect -> \props flags ->
    do s <- mediaCtrlCreate parent id "" rect style (fromMediaCtrlBackend back) ""
       set s props
       return s
instance Media (MediaCtrl a) where
  play media = unitIO (mediaCtrlPlay media)
  stop media = unitIO (mediaCtrlStop media)
stcEvent :: Event (StyledTextCtrl ()) (EventSTC -> IO ())
stcEvent
  = newEvent "stcEvent" stcGetOnSTCEvent stcOnSTCEvent
styledTextCtrl :: Window a -> [Prop (StyledTextCtrl ())] -> IO (StyledTextCtrl ())
styledTextCtrl parent props
  = styledTextCtrlEx parent defaultStyle props
styledTextCtrlEx :: Window a -> Style -> [Prop (StyledTextCtrl ())] -> IO (StyledTextCtrl ())
styledTextCtrlEx parent style props
  = feed2 props style $
    initialContainer $ \id rect -> \props flags ->
    do s <- styledTextCtrlCreate parent id "" rect style
       set s props
       return s
propertyGridEvent :: Event (PropertyGrid a) (EventPropertyGrid -> IO ())
propertyGridEvent
  = newEvent "propertyGridEvent" propertyGridGetOnPropertyGridEvent propertyGridOnPropertyGridEvent
propertyGrid :: Window a -> [Prop (PropertyGrid ())] -> IO (PropertyGrid ())
propertyGrid parent props
  = feed2 props wxPG_DEFAULT_STYLE $
    initialContainer $ \id rect -> \props flags ->
    do l <- propertyGridCreate parent id rect flags
       set l props
       return l