Version 4 of Advent Wreath

Updated 2009-01-05 23:26:42 by HJG

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 .  <F1>     { console show }
  bind .  <Escape> { source $argv0 }

  if 0 {
  proc int x  { expr int($x) }
  bind .cv <Motion> {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