-- | -- Module : System.Dzen -- Copyright : (c) 2009 Felipe A. Lessa -- License : GPL 3 (see the LICENSE file in the distribution) -- -- Maintainer : felipe.lessa@gmail.com -- Stability : experimental -- Portability : semi-portable (uses MPTC and type families) -- -- Hello! -- -- This is @dzen-utils@' main module. It re-exports every other -- module from this library, so you may just say -- -- > import System.Dzen -- -- and you'll have everything in hand. To learn more about this -- library, please see the documentation of each module exported here. -- To get you started, there are some simple examples below. :) module System.Dzen (-- * Example 1 -- $example1p1 -- ** Constructing - Part 1 -- $example1p2 -- ** Constructing - Part 2 -- $example1p3 -- ** Applying -- $example1p4 -- ** Whole code -- $example1p5 -- * Example 2 -- $example2p1 -- ** Separator -- $example2p2 -- ** Time bar -- $example2p3 -- ** Glueing the time text with the bar -- $example2p4 -- ** Whole code -- $example2p5 -- * Module exports module System.Dzen.Base ,module System.Dzen.Colour ,module System.Dzen.Graphics ,module System.Dzen.Padding ,module System.Dzen.Bars ,module System.Dzen.Process ) where import System.Dzen.Base import System.Dzen.Colour import System.Dzen.Graphics import System.Dzen.Padding import System.Dzen.Bars import System.Dzen.Process -- $example1p1 -- -- Suppose you have -- -- > import Data.Time -- > import System.Locale -- > -- > getZonedTime :: IO ZonedTime -- from time package -- > getCurrentWindow :: IO String -- from somewhere you know :) -- -- and that you want your bar to look like -- -- > "Wndw: [my window title here] - Sun 15 Mar 07:10:02" -- -- Okay, that's pretty nice. What you will do first will be to -- construct the 'Printer' of your bar. Basically, what you want is to -- concatenate @\"Wndw: \"@, the result of @getCurrentWindow@, the -- separator, and the formated result of @getZonedTime@. The @Printer@ -- we'll build below contain all the information necessary to create -- the final output string above from the two @get@ functions! -- $example1p2 -- -- To write the constant strings, we use 'str': -- -- > str :: String -> DString -- > str "Wndw: " :: DString -- > str " - " :: DString -- -- That is pretty straightforward. But how can we print the current -- window? We will just use 'cstr' here -- -- > cstr :: Printer String -- -- While @str@ is used as a common function, you just apply the -- string you want to it, @cstr@ will get the string from another -- source. What we'll do shortly is to pipe @IO String@ into -- @Printer String@ to obtain our final output. Instead of -- @Printer a@, think of it as @Printer input@. -- -- To concatenate we just have to use '+++' from 'Combine', which -- is an ugly class used to create beautiful types: -- -- > str "Wndn: " +++ cstr +++ str " - " :: Printer String -- -- Whenever you concatenate a @DString@ with a @Printer input@, you -- get a @Printer input@ as a result. That is, if you concatenate a -- constant string to something that takes an input and produces a -- string, what you get is something that takes an input and produces -- the concatenated string. Note that you don't need to write the -- type above. -- $example1p3 -- -- Now we can't just go ahead and use @cstr@ directly with -- @getZonedTime@ because, unlike @getCurrentWindow@, its result is -- not a string, but a @ZonedTime@. To format the @ZonedTime@ is -- outside the scope of this example, but you can get the format -- shown above with -- -- > format :: ZonedTime -> String -- > format = formatTime defaultTimeLocale "%a %e %b %H:%M:%S" -- -- While you can write -- -- > fmap format getZoneTime :: IO String -- -- you don't need to push the format function into the @IO@ monad, -- just put it in the @Printer@, the place where it belongs! To -- accomplish that use 'simple'' instead of 'cstr': -- -- > simple' :: (input -> String) -> Printer input -- > simple' format :: Printer ZonedTime -- -- And it's done! Concatenating everything: -- -- > printer :: Printer (String, ZonedTime) -- > printer = str "Wndn: " +++ cstr +++ str " - " +++ simple' format -- -- Whenever you concatenate @Printer a@ with @Printer b@ you -- get @Printer (a,b)@. -- $example1p4 -- -- In the end we just want strings, not @Printer@s, so we need to -- apply our @printer@ to some inputs. We already have functions for -- each part of our input, but we need to combine them. We may just -- use @##@ from "System.Dzen.Process" in this case (and in most others as -- well): -- -- > supply :: IO (String, ZonedTime) -- > supply = getCurrentWindow ## getZonedTime -- -- Now we could use 'apply', 'applyMany' or 'applyForever' to -- get strings out of our printer, but we'll use 'runDzen' directly -- which is a tad easier: -- -- > myDzen :: IO () -- > myDzen = runDzen "dzen2" [] 500 printer supply -- -- And that's it! You may use @myDzen@ directly as @main@, or you -- may use @forkIO myDzen@ inside @xmonad@. Pretty nice, uh? -- $example1p5 -- -- This is the whole code plus a stub @getCurrentWindow@ and a @main@. -- We omit the signatures on purpose to show how you could have -- written it lazily. You may also get the file @Example1.hs@ from the -- source code which contains all the type signatures. -- -- >import Data.Time -- >import System.Dzen -- >import System.Locale -- > -- >printer = str "Wndn: " +++ cstr +++ str " - " +++ simple' format -- >format = formatTime defaultTimeLocale "%a %e %b %H:%M:%S" -- >supply = getCurrentWindow ## getZonedTime -- >myDzen = runDzen "dzen2" [] 500 printer supply -- > -- >getCurrentWindow = return "My =^.^= Lolcats" -- >main = myDzen -- $example2p1 -- -- Now we want to do something different: let's have a graphical -- bar for our clock! And, why not, a graphical separator. -- $example2p2 -- -- The graphical separator will be very simple. Instead of dash -- (@\" - \"@) we'll use a small dot: -- -- > import Data.Monoid -- > -- > sep :: DString -- > sep = mconcat [pos 4, rect 3 3, pos 4] -- -- This is a 3x3 rectangle with 4 pixels of spacing on each side. -- And, thats it! -- $example2p3 -- -- Now something more challenging. Instead of showing the minutes -- and the seconds, we want to show a graphical bar, something like -- -- > "Wndw: [my window title here] - Sun 15 Mar 07:[== ]" -- -- Well, that bar will show minutes and seconds, but we can -- take as input just seconds, ranging from @0@ to @60*60-1@. -- We'll use plain simple 'cgdbar', which mimics @gdbar@: -- (please look at "System.Dzen.Bars" for more info) -- -- > timeBar :: Printer Int -- > timeBar = cgdbar False (40,10) Nothing Nothing True (0, 60*60-1) -- -- But what we have is not the number of seconds, but a @ZonedTime@. -- So we need -- -- > zonedSecs :: ZonedTime -> Int -- > zonedSecs = extract . localTimeOfDay . zonedTimeToLocalTime -- > where extract t = let minutes = fromIntegral (todMin t) -- > in round (minutes * 60 + todSec t) -- -- As @Printer@s are cofunctors, we can use 'comap' to get -- a suitable @timeBar@: -- -- > timeBar' :: Printer ZonedTime -- > timeBar' = comap zonedSecs timeBar -- $example2p4 -- -- We also want the rest of the time, not just the bar. First, -- we need a new @format@, as we don't want to show the minutes -- anymore: -- -- > format :: ZonedTime -> String -- > format = formatTime defaultTimeLocale "%a %e %b %H:" -- -- You may be tempted to write @simple' format +++ timeBar'@ now, -- but there's a small glitch: it would have type -- @Printer (ZonedTime, ZonedTime)@, but we want both to use -- the same @ZonedTime@. We could use 'comap' again or 'combine', -- but it is easier to write -- -- > time :: Printer ZonedTime -- > time = simple' format +=+ timeBar' -- $example2p5 -- -- The rest is just glue! So we now present the whole code, -- again in a compact form. See @Example2.hs@ for the whole -- code with type signatures: -- -- >import Data.Monoid -- >import Data.Time -- >import System.Dzen -- >import System.Locale -- > -- >zonedSecs = extract . localTimeOfDay . zonedTimeToLocalTime -- > where extract t = let minutes = fromIntegral (todMin t) -- > in round (minutes * 60 + todSec t) -- > -- >time = simple' format +=+ comap zonedSecs timeBar -- > where format = formatTime defaultTimeLocale "%a %e %b %H:" -- > timeBar = cgdbar False (40,10) Nothing Nothing True (0, 60*60-1) -- > -- >printer = str "Wndn: " +++ cstr +++ sep +++ time -- > where sep = mconcat [str " ", rectO 5 5, str " "] -- > -- >supply = getCurrentWindow ## getZonedTime -- >myDzen = runDzen "dzen2" [] 500 printer supply -- > -- >getCurrentWindow = return "My =^.^= Lolcats" -- >main = myDzen