-- | This module implements a very simple text-based clock widget. -- The widget also toggles a calendar widget when clicked. This -- calendar is not fancy at all and has no data backend. module System.Taffybar.SimpleClock ( textClockNew, textClockNewWith, defaultClockConfig, ClockConfig(..) ) where import Control.Monad.Trans ( MonadIO, liftIO ) import Data.Time.Calendar ( toGregorian ) import qualified Data.Time.Clock as Clock import Data.Time.Format import Data.Time.LocalTime import Graphics.UI.Gtk import System.Locale import System.Taffybar.Widgets.PollingLabel import System.Taffybar.Widgets.Util makeCalendar :: IO Window makeCalendar = do container <- windowNew cal <- calendarNew containerAdd container cal -- update the date on show _ <- onShow container $ liftIO $ resetCalendarDate cal -- prevent calendar from being destroyed, it can be only hidden: _ <- on container deleteEvent $ do liftIO (widgetHideAll container) return True return container resetCalendarDate :: Calendar -> IO () resetCalendarDate cal = do (y,m,d) <- Clock.getCurrentTime >>= return . toGregorian . Clock.utctDay calendarSelectMonth cal (fromIntegral m - 1) (fromIntegral y) calendarSelectDay cal (fromIntegral d) toggleCalendar :: WidgetClass w => w -> Window -> IO Bool toggleCalendar w c = do isVis <- get c widgetVisible if isVis then widgetHideAll c else do attachPopup w "Calendar" c displayPopup w c return True -- | Create the widget. I recommend passing @Nothing@ for the -- TimeLocale parameter. The format string can include Pango markup -- (http://developer.gnome.org/pango/stable/PangoMarkupFormat.html). textClockNew :: Maybe TimeLocale -> String -> Double -> IO Widget textClockNew userLocale fmt updateSeconds = textClockNewWith cfg fmt updateSeconds where cfg = defaultClockConfig { clockTimeLocale = userLocale } data ClockConfig = ClockConfig { clockTimeZone :: Maybe TimeZone , clockTimeLocale :: Maybe TimeLocale } deriving (Eq, Ord, Show) -- | A clock configuration that defaults to the current locale defaultClockConfig :: ClockConfig defaultClockConfig = ClockConfig Nothing Nothing data TimeInfo = TimeInfo { getTZ :: IO TimeZone , getLocale :: IO TimeLocale } -- | A configurable text-based clock widget. It currently allows for -- a configurable time zone through the 'ClockConfig'. -- -- See also 'textClockNew'. textClockNewWith :: ClockConfig -> String -> Double -> IO Widget textClockNewWith cfg fmt updateSeconds = do let ti = TimeInfo { getTZ = maybe getCurrentTimeZone return userZone , getLocale = maybe (return defaultTimeLocale) return userLocale } l <- pollingLabelNew "" updateSeconds (getCurrentTime' ti fmt) ebox <- eventBoxNew containerAdd ebox l eventBoxSetVisibleWindow ebox False cal <- makeCalendar _ <- on ebox buttonPressEvent $ onClick [SingleClick] (toggleCalendar l cal) widgetShowAll ebox return (toWidget ebox) where userZone = clockTimeZone cfg userLocale = clockTimeLocale cfg -- alternate getCurrentTime that takes a specific TZ getCurrentTime' :: TimeInfo -> String -> IO String getCurrentTime' ti f = do l <- getLocale ti z <- getTZ ti t <- Clock.getCurrentTime return $ formatTime l f $ utcToZonedTime z t