[HJG] 2008-12 This program simulates the candles burning down on an advent-wreath, and keeps track of statistics, such as how many times each candle was lit, and how many times each advent was celebrated. So you can try to maximize the usage you might get out of a set of candles... ---- #!/bin/sh # Restart with tcl: -*- mode: tcl; tab-width: 4; -*- \ exec wish $0 ${1+"$@"} # http://wiki.tcl.tk/20479 - advent16.tcl - 2008-12-26 # Simulate an advent-wreath: select which candles to light, press button to burn # 1.1 2008-12-21: log to console # 1.2 2008-12-22: wick # 1.3 2008-12-23: bind, Click, tk_optionMenu for initial length of candles # 1.4 2008-12-24: Click, CountButtons, CheckButtons : # click on candle to toggle checkbox + update text on "Burn"-button # 1.5 2008-12-25: len -> burncount, Flame/Smoke # 1.6 2008-12-26: code cleanup # Todo: # * variable number of candles/checkbuttons/stats-displays # * allow initial state with candles of different length # * load/save # * delete+redraw --> itemconfig # * show stats on candle/holder: current len, burn-count # * disable checkboxes of burnt-out candles # * some other shape for "flame" of burnt-out candles -> smoke # * use grid for positioning the candles # * candleflames + animation # * Menu: File/Edit/Options/Help # * Options: # ** candle-colors # * icon in program itself: include data for iconbitmap # * selfrunning Demo package require Tk global Prg set Prg(Title) "Advent-Wreath" set Prg(Version) "v1.6" set Prg(Date) "2008-12-26" set Prg(Author) "Hans-Joachim Gurt" set Prg(Contact) [string map -nocase {: @ ! .} gurt:gmx!de] set Prg(About) "Simulate an advent-wreath: select which candles to light, press button to burn one slice." proc ClrCanvas {w} { $w delete "all" } proc decr {x y} { expr $x - $y } #---+----1----+----2----+----3----+----4----+----5----+----6----+----7-- proc DrawCandle {w nr} { #: Draw one of the candles / calculate its position on the canvas global candle len active stat LenC $w delete "c$nr" set ww [expr { $candle(sC) + $candle(wC) } ] set x1 [expr { $candle(sC) + ($nr-1) * $ww } ] set x2 $x1 incr x2 $candle(wC) set y1 [expr { $::maxY - 40 } ] set ll [expr { $len($nr) * $candle(bC) + $candle(hC) } ] set y2 [expr { $y1 - $ll } ] # Candle: .cv create rect $x1 $y1 $x2 $y2 -width 1 -fill $candle(cC) -tag "c$nr" # Holder: incr x1 -5 incr x2 5 set y2 $y1 incr y1 10 .cv create rect $x1 $y1 $x2 $y2 -width 1 -fill gold -tag "c$nr" # Wick: set c grey if { $len($nr) < $LenC } { set c black } set x1 [expr { $candle(sC) + ($nr-1) * $ww + 22 } ] set x2 $x1 incr x2 3 set ll [expr { $len($nr) * $candle(bC) + $candle(hC) } ] set y1 [expr { $::maxY - 40 - $ll } ] set y2 $y1 incr y2 -15 .cv create rect $x1 $y1 $x2 $y2 -width 1 -fill $c -tag "c$nr" # Flame: ##Todo: use some other shape for smoke set c yellow if { $len($nr) < 1 } { set c grey } if $active($nr) { incr x1 -10 incr x2 10 incr y1 -5 incr y2 -35 .cv create oval $x1 $y1 $x2 $y2 -width 1 -fill $c -tag "c$nr" } } #---+----1----+----2----+----3----+----4----+----5----+----6----+----7-- proc Burn {w} { #: Burn one slice of selected candles + update statistics. global candle len active stat set ok 1 set adv 0 for { set i 1 } { $i <= $candle(maxC) } { incr i 1 } { if $active($i) { if { $::len($i) < 1 } { set ok 0; bell; puts "fail: $i" } incr adv 1 } } if {$ok && $adv} { incr stat(a$adv) 1 puts -nonewline "Advent $adv - Candles:" for { set nr 1 } { $nr <= $candle(maxC) } { incr nr 1 } { if $active($nr) { incr len($nr) -1 DrawCandle $w $nr incr stat(c$nr) 1 puts -nonewline " $nr" } } puts " " } } #---+----1----+----2----+----3----+----4----+----5----+----6----+----7-- proc Click {w} { #: When clicking on a candle, toggle the corresponding checkbutton set i 0 set Tags [$w itemcget current -tag ] scan $Tags "%c%d%s" x i y ## puts "$Tags: $i" if { $i } { .cb$i invoke } } proc CheckButtons {w} { #: Check how many checkbuttons are active, update "Burn"-Button and candle/flame global candle len active stat set adv 0 for { set i 1 } { $i <= $candle(maxC) } { incr i 1 } { if $active($i) { incr adv 1 } DrawCandle $w $i } if {$adv} { .b1 configure -text "Advent $adv" -state active } else { .b1 configure -text " - - - - - " -state disabled } } proc Init {w} { #: Assign variables, draw all candles global candle len active stat LenC $w delete "all" set candle(iC) $LenC puts "# New: $candle(iC)" for { set i 1 } { $i <= $candle(maxC) } { incr i 1 } { set len($i) $candle(iC) set active($i) 0 set stat(c$i) 0 set stat(a$i) 0 DrawCandle $w $i } # set active(1) 1 .cb1 invoke } #---+----1----+----2----+----3----+----4----+----5----+----6----+----7-- wm title . "$Prg(Title) $Prg(Version)" puts "$Prg(Title) $Prg(Version)" if {[file exists advent.ico]} { wm iconbitmap . advent.ico } frame .f1 ;# display frame .f2 ;# buttons frame .f3 ;# candle-stats frame .f4 ;# advent-stats pack .f1 .f2 .f3 .f4 # Candle-attr.: totalnumber, color, init, height0,width, spacing, burn-amount array set candle { maxC 4 cC red2 iC 10 hC 2 wC 50 sC 50 bC 10 } #set maxX 450 set maxX [expr { $candle(maxC) * ($candle(wC) + $candle(sC)) + 50 } ] #set maxY [expr { $candle(hC) + $candle(iC) * $candle(bC) + 100 } ] set maxY 305 ;# room for candles of length 20 for { set i 1 } { $i <= $candle(maxC) } { incr i 1 } { checkbutton .cb$i -variable active($i) -text $i -command { CheckButtons .cv } entry .ec$i -textvar stat(c$i) -width 5 -state readonly entry .ea$i -textvar stat(a$i) -width 5 -state readonly } canvas .cv -width $maxX -height $maxY -bg white pack .cv -in .f1 set LenC $candle(iC) tk_optionMenu .m1 LenC 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 .m1 configure -width 3 button .bN -text "New" -command { Init .cv } button .b1 -text "Burn" -command { Burn .cv } -width 8 ##Todo: var. number of checkbuttons+displays / put on canvas at candle pack .m1 .bN .cb1 .cb2 .cb3 .cb4 .b1 -in .f2 -side left -padx 2 label .lab1 -text "Candle burnt:" -width 21 label .lab2 -text "Advent:" -width 21 label .lab0 -text " " -width 16 label .lab9 -text " " -width 16 pack .lab1 .ec1 .ec2 .ec3 .ec4 .lab0 -in .f3 -side left -padx 2 pack .lab2 .ea1 .ea2 .ea3 .ea4 .lab9 -in .f4 -side left -padx 2 Init .cv bind .cv <1> { Click .cv } focus -force . # Debug: bind . { console show } bind . { source $argv0 } if 0 { proc int x { expr int($x) } bind .cv {wm title . "[int [%W canvasx %x]],[int [%W canvasy %y]]=[.cv find withtag current]"} } #catch {console show} #catch {wm withdraw .} ---- Updated, mostly to allow to select the starting candle-length. Clicking on a candle also toggles the corresponding checkbox. F1 activates a console, that shows a log of all actions. ---- [Category Graphics] - [Category Toys]