{-# LANGUAGE FlexibleInstances #-}

-- | This module provides access to bitmap resources.
module HTk.Components.BitMap (

  BitMap,
  newBitMap,

  BitMapHandle(..),
  HasBitMap(..),
  BitMapDesignator(..),

  errmap,
  gray50,
  gray25,
  hourglass,
  info,
  questhead,
  question,
  warning,

  setBitMapHandle,
  getBitMapHandle,
  stringToBitMapHandle

) where

import HTk.Kernel.Core
import HTk.Kernel.BaseClasses(Widget)
import HTk.Kernel.Configuration
import Data.Char(isDigit)
import Util.Computation
import Events.Synchronized
import Events.Destructible

-- -----------------------------------------------------------------------
-- BitMap designators
-- -----------------------------------------------------------------------

-- | The @BitMapHandle@ datatype - a handle for a bitmap
-- resource.
data BitMapHandle =
          Predefined String
        | BitMapHandle BitMap
        | BitMapFile String

-- | Internal.
class BitMapDesignator d where
  toBitMap :: d -> BitMapHandle

-- | Internal.
instance BitMapDesignator BitMapHandle where
  toBitMap = id

-- | Internal.
instance BitMapDesignator BitMap where
  toBitMap h = BitMapHandle h

-- | A string is a handle for a bitmap file.
instance BitMapDesignator [Char] where
  toBitMap h = BitMapFile h


-- -----------------------------------------------------------------------
-- BitMap'ed widgets
-- -----------------------------------------------------------------------

-- | Containers for bitmaps instantiate the @class HasBitMap@.
class GUIObject w => HasBitMap w where
  bitmap          :: BitMapDesignator d => d -> Config w
  getBitMap       :: w -> IO BitMapHandle
  bitmap d w      = setBitMapHandle w "bitmap" (toBitMap d) True
  getBitMap w     = getBitMapHandle w "bitmap"


-- -----------------------------------------------------------------------
-- type BitMap
-- -----------------------------------------------------------------------

-- | The @BitMap@ datatype.
newtype BitMap = BitMapWDG GUIOBJECT deriving Eq


-- -----------------------------------------------------------------------
-- commands
-- -----------------------------------------------------------------------

-- | Constructs a new bitmap object and returns a handler.
-- The bitmap object can be packed like a widget, then it is implicitely
-- displayed inside a label widget.
newBitMap :: [Config BitMap]
   -- ^ the list of configuration options for this bitmap  object.
   -> IO BitMap
   -- ^ A bitmap object.
newBitMap confs =
  do
    w <- createWidget ROOT LABEL
    configure (BitMapWDG w) confs


-- -----------------------------------------------------------------------
-- predefined Tk BitMaps
-- -----------------------------------------------------------------------

-- | A handle for the predefined \"error\" bitmap.
errmap :: BitMapHandle
errmap = Predefined "error"

-- | A handle for the predefined \"gray50\" bitmap.
gray50 :: BitMapHandle
gray50 = Predefined "gray50"

-- | A handle for the predefined \"gray25\" bitmap.
gray25 :: BitMapHandle
gray25 = Predefined "gray25"

-- | A handle for the predefined \"hourglass\" bitmap.
hourglass :: BitMapHandle
hourglass = Predefined "hourglass"

-- | A handle for the predefined \"info\" bitmap.
info :: BitMapHandle
info = Predefined "info"

-- | A handle for the predefined \"questhead\" bitmap.
questhead :: BitMapHandle
questhead = Predefined "questhead"

-- | A handle for the predefined \"question\" bitmap.
question :: BitMapHandle
question = Predefined "question"

-- | A handle for the predefined \"warning\" bitmap.
warning :: BitMapHandle
warning = Predefined "warning"


-- -----------------------------------------------------------------------
-- configuration options
-- -----------------------------------------------------------------------

-- | Internal.
instance GUIObject BitMap where
  toGUIObject (BitMapWDG w) = w
  cname _ = "BitMap"

-- | A bitmap object can be destroyed.
instance Destroyable BitMap where
  -- Destroys a bitmap object.
  destroy = destroy . toGUIObject

-- | A bitmap object has standard widget properties
-- (concerning focus, cursor \/ if implicitely displayed inside a label
-- widget).
instance Widget BitMap

-- | A bitmap object has a configureable border (if implicitely displayed
-- inside a label widget).
instance HasBorder BitMap

-- | A bitmap object has a configureable foreground and background colour
-- (if implicitely displayed inside a label widget).
instance HasColour BitMap where
  legalColourID = hasForeGroundColour

-- | You can specify the size of the containing label, if the bitmap is
-- implicitely displayed inside a label widget.
instance HasSize BitMap

-- | Bitmaps can be read from files.
instance HasFile BitMap where
  -- Specifies the bitmap\'s file path.
  filename fname w =
    execTclScript [tkBitMapCreate no fname] >> cset w "image" no
    where no = getObjectNo (toGUIObject w)
  -- Gets the bitmap\'s file name.
  getFileName w = evalTclScript [tkGetBitMapFile no]
    where no = getObjectNo (toGUIObject w)

-- | You can synchronize on a bitmap object.
instance Synchronized BitMap where
  -- Synchronizes on a bitmap object.
  synchronize (BitMapWDG w) = synchronize w


-- -----------------------------------------------------------------------
-- auxiliary functions
-- -----------------------------------------------------------------------

-- | Internal.
setBitMapHandle :: GUIObject w => w -> ConfigID -> BitMapHandle ->
                   Bool -> IO w
setBitMapHandle w cnm (Predefined d) _ = cset w cnm d
setBitMapHandle w cnm (BitMapFile f) _ = cset w cnm ('@':f)
setBitMapHandle w _ (BitMapHandle h) True =
  cset w "image" (getObjectNo (toGUIObject h))
setBitMapHandle w cnm (BitMapHandle h) False =
  do
    fname <- getFileName h
    setBitMapHandle w cnm (BitMapFile fname) False
    return w
{-
   the last parameter determines whether integer numbers are acceptable
   as bitmap denotations or not. If not, we use the corresponding file
   name associated with the widget! Numbers are allowed for labels and
   buttons, but not for windows!
-}

-- | Internal.
getBitMapHandle :: GUIObject w => w -> ConfigID -> IO BitMapHandle
getBitMapHandle w cnm = cget w cnm >>= stringToBitMapHandle

-- | Internal.
stringToBitMapHandle :: String -> IO BitMapHandle
stringToBitMapHandle "" = return (Predefined "")
stringToBitMapHandle ('@':tl) = return (BitMapFile tl)
stringToBitMapHandle (str @ (x:tl)) | isDigit x =
  lookupGUIObject (read str)      >>= return . BitMapHandle . BitMapWDG
stringToBitMapHandle str = return (Predefined str)


-- -----------------------------------------------------------------------
-- Tk commands
-- -----------------------------------------------------------------------

tkBitMapCreate :: Int -> String -> String
tkBitMapCreate no f = "image create bitmap " ++ show no ++ " -file " ++ show f
{-# INLINE tkBitMapCreate #-}

tkGetBitMapFile :: Int -> String
tkGetBitMapFile no = (show no) ++ " cget -file "
{-# INLINE tkGetBitMapFile #-}