packages feed

hexmino-0.1.0.0: src/Widgets.hs

module Widgets where

import qualified Hex
import qualified Table
import qualified Score
import qualified Graphics.Gloss.Data.Picture as Pict
import qualified Graphics.Gloss.Data.Color as Color
import qualified Graphics.Gloss.Data.Point as Point

data Name = Banner | Level | RightArrow | LeftArrow | NewGame | Time | Completed |
  TimeRes | Player | Delete | Submit | LeaderLabel | LeaderSep | LeaderEntry Int |
  InfoLine Int | Info | CloseInfo | CloseGame

-- sizes and positions
shape :: Name -> (Float, Float, Float, Float)
shape name = case name of
  Banner -> (Table.gridX, 100, 350, 80)
  Level -> (Table.gridX, -100, 250, 30)
  RightArrow -> (Table.gridX + 150, -100, 40, 40)
  LeftArrow -> (Table.gridX - 150, -100, 40, 40)
  NewGame -> (Table.gridX, -150, 150, 40)
  Time -> (-270, 220, 160, 30)
  Completed -> (Table.gridX, 120, 200, 30)
  TimeRes -> (Table.gridX, 80, 300, 50)
  Player -> (Table.gridX -30, -100, 90, 30)
  Delete -> (Table.gridX +50, -100, 40, 30)
  Submit -> (Table.gridX, -150, 150, 40)
  LeaderLabel -> (Table.listX, 200, 200, 40)
  LeaderSep -> (Table.listX, 180, 200, 5)
  LeaderEntry n -> (Table.listX, 160 - 40 * fromIntegral n, 230, 45)
  InfoLine n -> (Table.gridX, 40 - 35 * fromIntegral n, 470, 40)
  Info -> (-280, -220, 100, 40)
  CloseInfo -> (Table.gridX, -150, 80, 40)
  CloseGame -> (-280, -220, 100, 40)

-- rendering
renderButton :: Name -> String -> Pict.Picture
renderButton name txt = Pict.translate x y $ Pict.pictures [
    Pict.color buttonColor $ Hex.rectangleBlunt w h,
    Pict.Color Color.white $ Hex.rectangleBluntLine w h,
    Pict.color Color.white $ Hex.hexagonText w h txt
  ]
  where (x, y, w, h) = shape name

renderLabel :: Name -> String -> Pict.Picture
renderLabel name txt = Pict.translate x y $ Pict.pictures [
    Pict.color labelColor $ Pict.rectangleSolid w h,
    Pict.color Color.white $ Hex.hexagonText w h txt
  ]
  where (x, y, w, h) = shape name

renderText :: Name -> String -> Pict.Picture
renderText name = Pict.translate x y . Pict.color Color.white . Hex.hexagonText w h
  where (x, y, w, h) = shape name

renderBanner :: Pict.Picture
renderBanner = renderText Banner "hexmino"

renderGameSelector :: Score.Score -> Pict.Picture
renderGameSelector score = Pict.pictures [
    renderLabel Level $ show lvl,
    renderButton NewGame "new game",
    if Score.isMinLevel lvl then Pict.Blank else renderButton LeftArrow "<",
    if Score.isMaxLevel lvl then Pict.Blank else renderButton RightArrow ">"
  ]
  where lvl = Score.level score

renderTime :: Score.Score -> Pict.Picture
renderTime = renderLabel Time . Score.showTime

renderCompleted :: Score.Score -> Pict.Picture
renderCompleted score = Pict.pictures [
    renderText Completed "completed in",
    renderText TimeRes $ Score.showTime score
  ]

renderNameSelector :: Score.Score -> Pict.Picture
renderNameSelector score = Pict.pictures [
    renderLabel Player txt,
    renderButton Delete "del",
    renderButton Submit "submit"
  ]
  where
    name = Score.player score
    l = length name
    txt = if l < 3 then name ++ ('_' : replicate (2-l) ' ') else take 3 name

renderInfo :: Pict.Picture
renderInfo = Pict.pictures [
    renderButton CloseInfo "back",
    Pict.pictures $ zipWith renderText (map InfoLine [0..]) infoText
  ]

infoText :: [String]
infoText = [
    "drag the tiles on the grid",
    "rotate a tile using space",
    "neighbouring sides must match",
    "",
    "can you solve the expert puzzle?"
  ]

renderInfoButton :: Pict.Picture
renderInfoButton = renderButton Info "info"

renderCloseGame :: Pict.Picture
renderCloseGame = renderButton CloseGame "back"

renderTopTen :: Score.Leaderboard -> Pict.Picture
renderTopTen topTen = Pict.pictures [
    renderText LeaderLabel "leaderboard",
    renderLabel LeaderSep "",
    Pict.pictures . zipWith renderText (map LeaderEntry [0..]) $ map Score.display topTen
  ]

buttonColor :: Color.Color
buttonColor = Color.light Color.blue

labelColor :: Color.Color
labelColor = Color.dark Color.azure

-- click checking
findClicked :: Pict.Point -> [Name] -> Maybe Name
findClicked pos names = case filter (isClicked pos) names of
  [] -> Nothing
  (x:xs) -> Just x

isClicked :: Pict.Point -> Name -> Bool
isClicked pos name = Point.pointInBox pos (x - w/2, y - h/2) (x + w/2, y + h/2)
  where (x, y, w, h) = shape name