Mercurial > gui
view calendar.ur @ 14:0827320b0f04
Write calendarCtl in terms of a source with a listener.
author | Karn Kallio <kkallio@eka> |
---|---|
date | Fri, 05 Aug 2011 18:55:24 -0430 |
parents | |
children | 8300d5f0dc19 |
line wrap: on
line source
style calendar style prev style this style next style weekday style curday style otherday style selday datatype month = Prev | This | Next type date = {Year : int, Month : int, Day : int} val date_eq = mkEq (fn {Year = y, Month = m, Day = d} {Year = y', Month = m', Day = d'} => y = y' && m = m' && d = d') val date_ord = mkOrd {Lt = fn {Year = y1, Month = m1, Day = d1} {Year = y2, Month = m2, Day = d2} => y1 < y2 || (y1 = y2 && m1 < m2) || (y1 = y2 && m1 = m2 && d1 < d2), Le = fn {Year = y1, Month = m1, Day = d1} {Year = y2, Month = m2, Day = d2} => y1 < y2 || (y1 = y2 && m1 < m2) || (y1 = y2 && m1 = m2 && d1 <= d2)} type t = {Month : source {ThisMonth : int, Year : int, ThisMonthLength : int, PrevMonthLength : int, MondayMonth : month, MondayDay : int, PrevMonthName : string, ThisMonthName : string, NextMonthName : string}, Day : ChangePoller.changePoller date} fun pad len n = let val s = show n fun pad' len s = if len <= 0 then s else pad' (len-1) ("0" ^ s) in pad' (len - String.length s) s end fun time {Year = y, Month = m, Day = d} = readError (show y ^ "-" ^ pad 2 m ^ "-" ^ pad 2 d ^ " 00:00:00") fun date tm = let val y = readError (timef "%Y" tm) val m = readError (timef "%m" tm) val d = readError (timef "%d" tm) in {Year = y, Month = m, Day = d} end fun monthLen m = let fun f n tm = let val next = addSeconds tm (60 * 60 * 24) val nextMon = readError (timef "%m" next) in if nextMon = m.Month then f (n+1) next else n end in f 28 (readError (show m.Year ^ "-" ^ pad 2 m.Month ^ "-28 00:00:00")) end fun weekdayToNum s = case s of "Mon" => 0 | "Tue" => 1 | "Wed" => 2 | "Thu" => 3 | "Fri" => 4 | "Sat" => 5 | "Sun" => 6 | _ => error <xml>Datebox: Bad weekday name</xml> fun timeOfMonth my = readError (show my.Year ^ "-" ^ pad 2 my.Month ^ "-01 00:00:00") fun monthInfo' this = let val prev = if this.Month = 1 then {Month = 12, Year = this.Year - 1} else {Month = this.Month-1, Year = this.Year} val prevLen = monthLen prev val next = if this.Month = 12 then {Month = 1, Year = this.Year + 1} else {Month = this.Month + 1, Year = this.Year} val firstDow = weekdayToNum (timef "%a" (timeOfMonth this)) in {ThisMonth = this.Month, Year = this.Year, ThisMonthLength = monthLen this, PrevMonthLength = prevLen, MondayMonth = if firstDow = 0 then This else Prev, MondayDay = if firstDow = 0 then 1 else prevLen - (firstDow - 1), PrevMonthName = timef "%b" (timeOfMonth prev), ThisMonthName = timef "%b" (timeOfMonth this), NextMonthName = timef "%b" (timeOfMonth next)} end fun monthInfo this = return (monthInfo' this) fun create tm = year <- return (readError (timef "%Y" tm)); month <- return (readError (timef "%m" tm)); minf <- source (monthInfo' {Month = month, Year = year}); day <- return (readError (timef "%d" tm)); day <- ChangePoller.create {Year = year, Month = month, Day = day}; return {Month = minf, Day = day} fun render' t = minf <- signal t.Month; let fun rows year month day = let fun row year month day weekday = if weekday >= 7 then <xml/> else <xml> <dyn signal={let val thisDate = {Year = year, Month = case month of Prev => if minf.ThisMonth = 1 then 12 else minf.ThisMonth - 1 | This => minf.ThisMonth | Next => if minf.ThisMonth = 12 then 1 else minf.ThisMonth + 1, Day = day} in cday <- ChangePoller.value t.Day; return (if Record.equal thisDate cday then <xml><td class={selday}>{[day]}</td></xml> else case month of This => <xml><td class={curday} onclick={set (ChangePoller.ctl t.Day) thisDate}>{[day]}</td></xml> | _ => <xml><td class={otherday}>{[day]}</td></xml>) end}/> {let val (year, month, day) = case month of Prev => if day = minf.PrevMonthLength then (if minf.ThisMonth = 1 then year + 1 else year, This, 1) else (year, Prev, day+1) | This => if day = minf.ThisMonthLength then (if minf.ThisMonth = 12 then year + 1 else year, Next, 1) else (year, This, day+1) | Next => (year, Next, day+1) in row year month day (weekday+1) end} </xml> in case month of Next => <xml/> | _ => <xml> <tr>{row year month day 0}</tr> {let val next = case month of Prev => Some (if minf.ThisMonth = 1 then year + 1 else year, This, day + 7 - minf.PrevMonthLength) | This => Some (if day + 7 > minf.ThisMonthLength then (if minf.ThisMonth = 12 then year + 1 else year, Next, day + 7 - minf.ThisMonthLength) else (year, This, day + 7)) | Next => None in case next of None => <xml/> | Some (year, month, day) => rows year month day end} </xml> end in return <xml> <table class={calendar}> <tr> <th class={prev} colspan={2} onclick={minf <- rpc (monthInfo (if minf.ThisMonth = 1 then {Month = 12, Year = minf.Year - 1} else {Month = minf.ThisMonth - 1, Year = minf.Year})); set t.Month minf}><< {[minf.PrevMonthName]}</th> <th class={this} colspan={3}>{[minf.ThisMonthName]} {[minf.Year]}</th> <th class={next} colspan={2} onclick={minf <- rpc (monthInfo (if minf.ThisMonth = 12 then {Month = 1, Year = minf.Year + 1} else {Month = minf.ThisMonth + 1, Year = minf.Year})); set t.Month minf}>{[minf.NextMonthName]} >></th> </tr> <tr class={weekday}> <th>M</th> <th>Tu</th> <th>W</th> <th>Th</th> <th>F</th> <th>Sa</th> <th>Su</th> </tr> {rows (if minf.ThisMonth = 1 && (case minf.MondayMonth of This => False | _ => True) then minf.Year - 1 else minf.Year) minf.MondayMonth minf.MondayDay} </table> </xml> end fun addListener f ctl = ChangePoller.addChangeListener f 100 ctl.Day val gui_t = Gui.mkGui (fn ctl => <xml> <dyn signal={render' ctl}/> </xml>) fun set ctl day = minf <- rpc (monthInfo (day -- #Day)); Basis.set ctl.Month minf; Basis.set (ChangePoller.ctl ctl.Day) day fun value ctl = ChangePoller.value ctl.Day