packages feed

fudgets-0.18.3: Demos/clock/ClockF.hs

{-# LANGUAGE CPP #-}
module ClockF(clockShellF) where
import AllFudgets
--import DialogueIO hiding (IOError)
import Data.Maybe(fromMaybe)
#ifdef VERSION_old_time
import System.Time(CalendarTime(..))
#else
import Data.Time(TimeOfDay(..),localTimeOfDay,zonedTimeToLocalTime)
#endif

--default(Int)

trace x y = y
--ctr s x = ctrace s (show x) x

data ClockMode = Analog | Digital deriving (Show,Eq)

clockShellF =
  let size = fsize
      gcattrs = [GCFont digFont,
		 GCLineWidth width,
		 GCCapStyle CapRound]
      clockShellK = safeLoadQueryFont digFont (\font ->
		       dynShapeK gcattrs (const [])
				 (clockK startMode (digsize font)
			                 (Point 0 (font_ascent font))
			                 size))
      menuF = menuAltsF menuFont [Analog,Digital] show -- >=^<Left
      tickF = (Left. Right. Right)>^=<startupF [Just (update,1000)] timerF
      startcmds = map (Low . XCmd) [StoreName "ClockFudget"
                   --,ConfigureWindow [CWBorderWidth 5] -- testing
		  ]
      route msg =
	 case msg of
	   Left (Right (Left shape)) -> Left (Left shape)
	   Left (Right (Right pop)) -> Right pop
	   Right mode -> Left (Right (Left mode))
  in loopOnlyF (route>^=<shellKF (putsK startcmds clockShellK) menuF)>==<tickF

clockK :: ClockMode -> Size -> Point -> Size -> K (Either ClockMode Tick) (Either (Point->[DrawCommand]) PopupMenu)
clockK dig digsize bp size =
  let clockP dig size =
        let redraw s t = putsK [--Low (ConfigureWindow [CWBorderWidth 5]), -- testing
	                       High (Left (clockface dig bp t))] (clockP dig s)
            --gettime dig s = putLow (DReq GetLocalTime) (clockP dig s)
#ifdef VERSION_old_time
            gettime dig s = getLocalTime (redraw s)
#else
            gettime dig s = getZonedTime (redraw s)
#endif
            same = clockP dig size
        in getK $ \msg ->
	   case msg of
	     --Low (Expose _ 0)-> gettime dig size -- ??
	     --Low (DResp (Dbl t))-> redraw size t
	     Low (XEvt ev@(ButtonEvent _ _ rootpos _ Pressed _)) ->
	       putK (High (Right (PopupMenu rootpos ev))) same
	     Low (XEvt (ButtonEvent _ _ _ _ Released _))->
	       putK (High (Right PopdownMenu)) same
	     High (Right _) -> gettime dig size
	     High (Left mode) -> if mode==dig
			        then same
				else putK (layout mode) (gettime mode size)
	     _-> same

      layout mode =
        let s = case mode of
	          Digital-> digsize
		  Analog-> size
	in Low (layoutRequestCmd (plainLayout s False False))
      layout0 = layout dig
      startcmds =
        [ layout0,
          Low (XCmd $ GrabButton True AnyButton [] [ButtonPressMask,ButtonReleaseMask])
	]
  in changeBg color (putsK startcmds (clockP dig size))

#ifdef VERSION_old_time
timeofday CalendarTime{ctHour=h,ctMin=min,ctSec=s} =
  let t = s+60*(min+60*h)
      m = itof t / 60.0
  in (fmod (m/60.0) 24.0 ,fmod m 60.0)
#else
timeofday zt = (fmod (m/60.0) 24.0 ,fmod m 60.0)
  where
    t = round s+60*(min+60*h)
    m = itof t / 60
    TimeOfDay h min s = localTimeOfDay (zonedTimeToLocalTime zt)
#endif

clockface mode bp t size =
    case mode of
      Digital-> [DrawString bp (digits t)]
      Analog-> hands t size ++ scalemarks size

digits t =
  let (h,m) = aboth floor' (timeofday t)
  in show h ++ ":" ++ drop 1 (show (100+m))

hands t size =
  let (h,m) = timeofday t
  in hand h 12 0.6 size ++ hand m 60 0.95 size

hand v d r size =
  let a = v / itof d * 2.0 * pi
      h = scalePoint 0.5 size
  in [DrawLine (Line h (toRect r h a))]

scalemarks size =
  let r = scalePoint 0.5 size
      w2 = width*2
  in let mark n =
	  let a = itof n*pi/6.0
	  in Rect (psub (toRect 0.9 r a) (Point width width)) (Point w2 w2)
  in [FillArc (mark n) 0 (64*360) | n<-[0..11]]

toRect k (Point w h) r = Point (w+floor' (k*itof w*sin r)) (h+floor' (k*itof (-h)*cos r))

fmod :: Double -> Double -> Double
fmod a b =
  let y = a - b * fromIntegral (floor' (a/b))
  in {-if y<0.0 && argFlag "floor" False 
     then trace (show (a,b,y)) y
     else -}y

digsize font = string_box_size font "88:88"

width = argReadKey "width" 10
fsize = fromMaybe (diag (argReadKey "size" 200)) defaultSize
color = argKey "color" "gold"
update = (argReadKey "update" 20) * 1000
startMode = if argKey "mode" "analog" == "digital" then Digital else Analog
digFont = defaultFont

itof=fromIntegral

rightadj s n pad = [pad|i<-[length s+1..n]]++s

floor' x = floor x
-- Solves a problem on slip-02 with direct calls to PfloorDouble2Int. TH 970314.