packages feed

macbeth-lib-0.0.12: src/Macbeth/Wx/ToolBox.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}

module Macbeth.Wx.ToolBox (
  wxToolBox
) where

import Macbeth.Fics.FicsMessage
import Macbeth.Fics.Api.Player
import Macbeth.Wx.Configuration
import Macbeth.Wx.Finger
import Macbeth.Wx.GamesList
import Macbeth.Wx.Login
import Macbeth.Wx.Match
import Macbeth.Wx.Seek
import Macbeth.Wx.Utils
import Macbeth.Wx.PlayersList
import Macbeth.Wx.SoughtList
import Macbeth.Wx.Game
import Macbeth.Wx.Challenge
import Macbeth.Wx.PartnerOffer
import Macbeth.Wx.Pending
import Paths

import Control.Concurrent
import Control.Concurrent.Chan ()
import Control.Monad
import Foreign.Marshal.Alloc
import Foreign.Storable
import Foreign.Ptr
import Foreign.C.Types
import Graphics.UI.WX hiding (when)
import Graphics.UI.WXCore hiding (when)
import System.FilePath
import System.IO
import System.IO.Unsafe

eventId = wxID_HIGHEST + 1

wxToolBox :: Handle -> Chan FicsMessage -> IO ()
wxToolBox h chan = do
    f  <- frame [ text := "Macbeth"]

    tbar   <- toolBarEx f False False []
    tbarItem_seek <- toolItem tbar "Seek" False (unsafePerformIO $ getDataFileName $ "icons" </> "bullhorn.gif")
      [ on command := dupChan chan >>= wxSeek h False, enabled := False, tooltip := "Seek" ]

    tbarItem_match <- toolItem tbar "Match" False  (unsafePerformIO $ getDataFileName $ "icons" </> "dot-circle-o.gif")
      [ on command := dupChan chan >>= wxMatch h False, enabled := False, tooltip := "Match" ]

    tbarItem_finger <- toolItem tbar "Finger" False  (unsafePerformIO $ getDataFileName $ "icons" </> "fa-question.gif")
      [ on command := hPutStrLn h "4 finger", enabled := False, tooltip := "Finger"]

    status <- statusField []
    statusLag <- statusField [ statusWidth := 100 ]
    _ <- timer f [ interval := 2 * 60 * 1000, on command := hPutStrLn h "4 ping"]
    statusLoggedIn <- statusField [ statusWidth := 100]


    nb <- notebook f []

    -- Sought list
    slp <- panel nb []
    (sl, soughtListHandler) <- wxSoughtList slp h

    -- Games list
    glp <- panel nb []
    (gl, gamesListHandler)  <- wxGamesList glp h

    -- Pending
    pending <- panel nb []
    (pendingWidget, pendingHandler) <- wxPending h pending

    -- Players
    players <- panel nb []
    (playersWidget, playersHandler) <- wxPlayersList players h

    -- Console
    cp <- panel nb []
    ct <- textCtrlEx cp (wxTE_MULTILINE .+. wxTE_RICH .+. wxTE_READONLY) [font := fontFixed]
    ce <- entry cp []
    set ce [on enterKey := emitCommand ce h]


    -- menu
    m_file   <- menuPane [text := "&File"]
    menuItem m_file [text := "Settings", on command := dupChan chan >>= wxConfiguration ]

    set f [ statusBar := [status, statusLoggedIn, statusLag],
            layout := tabs nb
                        [ tab "Sought" $ container slp $ fill $ widget sl
                        , tab "Games" $ container glp $ fill $ widget gl
                        , tab "Pending" $ container pending $ fill $ widget pendingWidget
                        , tab "Players" $ container players $ fill $ widget playersWidget
                        , tab "Console" $ container cp ( column 5  [ fill $ widget ct
                                                                   , hfill $ widget ce])
                        ]
          , menuBar := [m_file]
          , outerSize := sz 600 600
          ]

    -- preselect first tab
    notebookSetSelection nb 0

    vCmd <- newEmptyMVar
    threadId <- forkIO $ eventLoop eventId chan vCmd f
    windowOnDestroy f $ writeChan chan WxClose >> killThread threadId

    evtHandlerOnMenuCommand f eventId $ takeMVar vCmd >>= \cmd ->
      gamesListHandler cmd >>
      soughtListHandler cmd >>
      pendingHandler cmd >>
      playersHandler cmd >>
      case cmd of

        NoSuchGame -> do
          set status [text := "No such game. Updating games..."]
          hPutStrLn h "4 games"

        UserNotLoggedIn username -> do
          set status [text := username ++ " is not logged in."]
          hPutStrLn h "4 who"

        PartnerNotOpen userHandle -> set status [text := name userHandle ++ " is not open for bughouse."]

        PartnerOffer userHandle -> dupChan chan >>= wxPartnerOffer h userHandle

        PartnerAccepted userHandle -> set status [text := name userHandle ++ " agrees to be your partner."]

        PartnerDeclined userHandle -> set status [text := name userHandle ++ " declines the partnership request."]

        SeekNotAvailable -> set status [text := "That seek is not available."]

        InvalidPassword  -> void $ set status [text := "Invalid password."]

        LoginTimeout -> set status [ text := "Login Timeout." ]

        Login -> dupChan chan >>= wxLogin h

        LoggedIn handle -> do
          set nb [on click := (onMouse nb >=> clickHandler h nb)]
          hPutStrLn h `mapM_` [ "ping", "set seek 0", "set style 12", "iset pendinfo 1", "iset seekinfo 1", "iset nowrap 1", "iset defprompt 1", "iset block 1", "2 iset lock 1"]
          set statusLoggedIn [ text := name handle]
          mapM_ (`set` [ enabled := True ]) [tbarItem_seek, tbarItem_match, tbarItem_finger]

        GuestLogin _ -> do
          set tbarItem_seek  [on command := dupChan chan >>= wxSeek h True ]
          set tbarItem_match  [on command := dupChan chan >>= wxMatch h True ]

        msg@(Finger {}) -> dupChan chan >>= wxInfo msg

        msg@(History {}) -> dupChan chan >>= wxInfo msg

        WxObserve move chan' -> wxGame h move chan'

        MatchRequested c -> dupChan chan >>= wxChallenge h c

        WxMatchAccepted move chan' -> wxGame h move chan'

        MatchDeclined user -> set status [text := user ++ " declines the match offer."]

        MatchUserNotLoggedIn user -> set status [text := user ++ " not logged in."]

        Ping _ avg _ -> set statusLag [ text := "Lag: " ++ show avg ++ "ms"]

        TextMessage text -> appendText ct text

        _ -> return ()


emitCommand :: TextCtrl () -> Handle -> IO ()
emitCommand textCtrl h = get textCtrl text >>= hPutStrLn h . ("5 " ++) >> set textCtrl [text := ""]


onMouse :: Notebook() -> Point -> IO Int
onMouse nb p = propagateEvent >> notebookHitTest nb p flag

clickHandler :: Handle -> Notebook () -> Int -> IO ()
clickHandler h nb idx = notebookGetPageText nb idx >>= \case
  "Games" -> hPutStrLn h "5 games"
  "Players" -> hPutStrLn h "5 who"
  _ -> return ()


{-# NOINLINE flag #-}
flag :: Ptr CInt
flag  =  unsafePerformIO flag'
  where flag' = do
             work <- malloc::IO (Ptr CInt)
             poke work (fromIntegral wxBK_HITTEST_ONPAGE)
             return work