packages feed

brick-3.0: programs/MenuBarDemo.hs

{-# LANGUAGE CPP #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where

import Lens.Micro ((^.))
import Lens.Micro.TH (makeLenses)
import Lens.Micro.Mtl ((%=), use)
import Control.Monad (void, when)
import Control.Monad.Trans (liftIO)
#if !(MIN_VERSION_base(4,11,0))
import Data.Monoid ((<>))
#endif
import qualified Data.Text as Text
import qualified Graphics.Vty as V

import qualified Brick.Types as T
import Brick.AttrMap
import Brick.Util
import Brick.Types (Widget)
import qualified Brick.Main as M
import Brick.Widgets.Core (txtWrap, hLimit)
import Brick.Widgets.Center (center)
import Brick.Widgets.Menu
import Brick.Widgets.MenuBar

data Name = FileMenu MenuRegion
          | EditMenu MenuRegion
          | HelpMenu MenuRegion
          deriving (Show, Ord, Eq)

data St =
    St { _menuBar :: SimpleMenuBar St Name
       , _menuBarOrientation :: MenuOrientation
       }

makeLenses ''St

drawUi :: St -> [Widget Name]
drawUi st =
    [ renderMenuBar st (st^.menuBar)
    , center $
      hLimit 40 $
      txtWrap $
      Text.unlines $
      [ "Click the menu title with the mouse or press Alt-F, Alt-E, " <>
        "or Alt-H to open the menus."
      , ""
      , "Press 'o' to toggle the orientation of the menu bar and its menus."
      , ""
      , "When a menu is open:"
      , ""
      , "- Press up/down arrow keys to select items and then " <>
        "press Enter to activate them, or click them with the mouse instead."
      , ""
      , "- Press left/right arrow keys cycle through open menus."
      , ""
      , "Press Esc to quit the program."
      ]
    ]

appEvent :: T.BrickEvent Name e -> T.EventM Name St ()
appEvent e = do
    handled <- handleMenuBarEvent menuBar e
    when (not handled) $ handleNonMenuBarEvent e

handleNonMenuBarEvent :: T.BrickEvent Name e -> T.EventM Name St ()
handleNonMenuBarEvent (T.VtyEvent (V.EvKey V.KEsc [])) =
    -- Esc quits the application
    M.halt
handleNonMenuBarEvent (T.VtyEvent (V.EvKey (V.KChar 'f') [V.MMeta])) =
    menuBar %= toggleMenuAtIndex 0
handleNonMenuBarEvent (T.VtyEvent (V.EvKey (V.KChar 'e') [V.MMeta])) =
    menuBar %= toggleMenuAtIndex 1
handleNonMenuBarEvent (T.VtyEvent (V.EvKey (V.KChar 'h') [V.MMeta])) =
    menuBar %= toggleMenuAtIndex 2
handleNonMenuBarEvent (T.VtyEvent (V.EvKey (V.KChar 'o') [])) = do
    menuBarOrientation %= nextOrientation
    o <- use menuBarOrientation
    menuBar %= setMenuBarOrientation o
handleNonMenuBarEvent _ =
    return ()

nextOrientation :: MenuOrientation -> MenuOrientation
nextOrientation LeftToRight = RightToLeft
nextOrientation RightToLeft = LeftToRight

aMap :: AttrMap
aMap = attrMap V.defAttr
    [ (menuAttr, fg V.white)
    , (menuTitleAttr, V.white `on` V.blue)
    , (menuTitleSelectedAttr, V.black `on` V.white)
    , (menuEntryDisabledAttr, fg V.red)
    , (menuEntrySelectedAttr, V.black `on` V.yellow)
    , (menuEntrySelectedDisabledAttr, V.black `on` V.red)
    , (menuTitleKeyHighlightAttr, style V.underline)
    ]

app :: M.App St e Name
app =
    M.App { M.appDraw = drawUi
          , M.appStartEvent = do
              vty <- M.getVtyHandle
              liftIO $ V.setMode (V.outputIface vty) V.Mouse True
          , M.appHandleEvent = appEvent
          , M.appAttrMap = const aMap
          , M.appChooseCursor = M.showFirstCursor
          }

newFileMenu :: SimpleMenu St Name
newFileMenu =
    setTitleRenderer (titleHightlightKey 'f') $
    simpleMenu "File" FileMenu
        [ menuEntry "New..." (return ())
        , menuEntry "Open..." (return ())
        , menuSeparator
        , menuEntry "Exit" M.halt
        ]

newEditMenu :: SimpleMenu St Name
newEditMenu =
    setTitleRenderer (titleHightlightKey 'e') $
    simpleMenu "Edit" EditMenu
        [ menuEntry "Undo" (return ())
        , menuEntry "Redo" (return ())
        , menuSeparator
        , menuEntry "Cut" (return ())
        , menuEntry "Copy" (return ())
        , menuEntry "Paste" (return ())
        ]

newHelpMenu :: SimpleMenu St Name
newHelpMenu =
    setTitleRenderer (titleHightlightKey 'h') $
    simpleMenu "Help" HelpMenu
        [ menuEntry "About" (return ())
        , menuEntry "Check for updates" (return ())
        ]

main :: IO ()
main = do
    let mb = newMenuBar [ newFileMenu
                        , newEditMenu
                        , newHelpMenu
                        ]
    void $ M.defaultMain app $ St mb LeftToRight