Tk Library Source Code

Changes On Branch tcl80
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch tcl80 Excluding Merge-Ins

This is equivalent to a diff from 411c59b769 to c6c64c78fc

2000-07-30
19:47
in toggle{}, when last selected index no longer exists, no longer try to keep track of selected index as it would be too complicated (removes a crash that occured after toggling cell 1, cell 2, cell 2 and cell 1). Closed-Leaf check-in: c6c64c78fc user: jfontain tags: tcl80
2000-04-06
19:34
in columnHeight{}, forgot double quotes in fully qualified name. check-in: 490a6a278c user: jfontain tags: tcl80
2000-03-05
20:48
added labelSlice{}. check-in: 4033332bc8 user: jfontain tags: tcl80
1999-10-02
20:53
changed email address to free in copyright notice. check-in: 2573bcaf3f user: jfontain tags: trunk
1999-08-16
20:59
in selected{}, use array get instead of names for better performance. check-in: 411c59b769 user: jfontain tags: trunk
1999-03-30
21:23
version 5.3. check-in: 4e7d49df37 user: jfontain tags: trunk

Changes to modules/tkpiechart/README.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Some people have asked for a Tcl/Tk pie utility: so here is my little
implementation with Tcl, not as an extension.

This is version 5.3. It was tested with Tcl8.0/Tk8.0, Tcl8.1/Tk8.1 and
the netscape plug-in 2.0, on both Linux and Windows platforms (it
should work on all Tcl/Tk supported platforms).

It is object oriented using the stooop (Simple Tcl Only Object
Oriented Programming) extension (version 3.7 or above, tcl file
included).

If you have netscape with the Tcl plug-in installed, just Open File...
demo.tcl and voila!

Run the demo script to see what it looks like, read the man pages to
understand how to use it.

Whether you like it (or hate it), please let me know. I would like to
hear about bugs and improvements you would like to see. I will correct
the bugs quickly, especially if you send me a test script.

If you find a bug in the Tcl code and correct it yourself, please
email the modified code so I can include it in the next release. The
same goes for improvements.

Jean-Luc Fontaine
(http://www.multimania.com/jfontain/, mailto:jfontain@multimania.com)
|
|

|
|
|




















|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Tkpiechart is a Tcl only library which allows the creation of pies
with labels in Tcl canvases.

This is version 5.4. It was tested with Tcl8.0/Tk8.0 and the netscape
plug-in 2.0, on both Linux and Windows platforms (it should work on
all Tcl/Tk supported platforms).

It is object oriented using the stooop (Simple Tcl Only Object
Oriented Programming) extension (version 3.7 or above, tcl file
included).

If you have netscape with the Tcl plug-in installed, just Open File...
demo.tcl and voila!

Run the demo script to see what it looks like, read the man pages to
understand how to use it.

Whether you like it (or hate it), please let me know. I would like to
hear about bugs and improvements you would like to see. I will correct
the bugs quickly, especially if you send me a test script.

If you find a bug in the Tcl code and correct it yourself, please
email the modified code so I can include it in the next release. The
same goes for improvements.

Jean-Luc Fontaine
(http://jfontain.free.fr/, mailto:jfontain@free.fr)

Changes to modules/tkpiechart/boxlabel.tcl.

1
2
3
4
5
6
7
8
set rcsId {$Id: boxlabel.tcl,v 1.41 1999/03/27 21:41:06 jfontain Exp $}

class pieBoxLabeler {

    proc pieBoxLabeler {this canvas args} pieLabeler {$canvas $args} switched {$args} {
        ::set pieBoxLabeler::($this,array) [::new canvasLabelsArray $canvas]
        switched::complete $this
    }
|







1
2
3
4
5
6
7
8
set rcsId {$Id: boxlabel.tcl,v 1.41.1.1 2000/03/05 20:55:56 jfontain Exp $}

class pieBoxLabeler {

    proc pieBoxLabeler {this canvas args} pieLabeler {$canvas $args} switched {$args} {
        ::set pieBoxLabeler::($this,array) [::new canvasLabelsArray $canvas]
        switched::complete $this
    }
43
44
45
46
47
48
49





50





51
52

53
54
55
56
57
58
59

    proc delete {this label} {
        canvasLabelsArray::delete $pieBoxLabeler::($this,array) $label
        unset pieBoxLabeler::($this,selected,$label)
    }

    proc set {this label value} {





        regsub {:.*$} [switched::cget $label -text] ": $value" text





        switched::configure $label -text $text
    }


    proc selectState {this label {selected {}}} {
        if {[string length $selected]==0} {                                                   ;# return current state if no argument
            return $pieBoxLabeler::($this,selected,$label)
        }
        switched::configure $label -select $selected
        ::set pieBoxLabeler::($this,selected,$label) $selected







>
>
>
>
>
|
>
>
>
>
>
|
|
>







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

    proc delete {this label} {
        canvasLabelsArray::delete $pieBoxLabeler::($this,array) $label
        unset pieBoxLabeler::($this,selected,$label)
    }

    proc set {this label value} {
        regsub {:[^:]*$} [switched::cget $label -text] ": $value" text                  ;# update string part after last semi-column
        switched::configure $label -text $text
    }

    proc label {this label args} {
        ::set text [switched::cget $label -text]
        if {[llength $args]==0} {
            regexp {^(.*):} $text dummy text
            return $text
        } else {
            regsub {^.*:} $text [lindex $args 0]: text                                 ;# update string part before last semi-column
            switched::configure $label -text $text
        }
    }

    proc selectState {this label {selected {}}} {
        if {[string length $selected]==0} {                                                   ;# return current state if no argument
            return $pieBoxLabeler::($this,selected,$label)
        }
        switched::configure $label -select $selected
        ::set pieBoxLabeler::($this,selected,$label) $selected

Deleted modules/tkpiechart/canlabel.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
set rcsId {$Id: canlabel.tcl,v 1.25 1999/03/30 20:11:01 jfontain Exp $}

class canvasLabel {

    proc canvasLabel {this canvas args} switched {$args} {
        set canvasLabel::($this,canvas) $canvas
        # use an empty image as an origin marker with only 2 coordinates
        set canvasLabel::($this,origin) [$canvas create image 0 0 -tags canvasLabel($this)]
        set canvasLabel::($this,rectangle) [$canvas create rectangle 0 0 0 0 -tags canvasLabel($this)]
        # select rectangle is on top for default box style
        set canvasLabel::($this,selectRectangle) [$canvas create rectangle 0 0 0 0 -tags canvasLabel($this)]
        set canvasLabel::($this,text) [$canvas create text 0 0 -tags canvasLabel($this)]
        switched::complete $this
    }

    proc ~canvasLabel {this} {
        $canvasLabel::($this,canvas) delete canvasLabel($this)
    }

    proc options {this} {
        # force font for proper initialization
        return [list\
            [list -anchor center center]\
            [list -background {} {}]\
            [list -bordercolor black black]\
            [list -borderwidth 1 1]\
            [list -bulletwidth 10 10]\
            [list -font {Helvetica -12}]\
            [list -foreground black black]\
            [list -justify left left]\
            [list -padding 2 2]\
            [list -scale {1 1} {1 1}]\
            [list -select 0 0]\
            [list -selectcolor white white]\
            [list -stipple {} {}]\
            [list -style box box]\
            [list -text {} {}]\
            [list -width 0 0]\
        ]
    }

    proc set-background {this value} {
        $canvasLabel::($this,canvas) itemconfigure $canvasLabel::($this,rectangle) -fill $value
    }
    proc set-bordercolor {this value} {
        $canvasLabel::($this,canvas) itemconfigure $canvasLabel::($this,rectangle) -outline $value
        if {[string compare $switched::($this,-style) box]==0} {
            $canvasLabel::($this,canvas) itemconfigure $canvasLabel::($this,selectRectangle) -outline $value
        }
    }
    proc set-borderwidth {this value} {
        $canvasLabel::($this,canvas) itemconfigure $canvasLabel::($this,selectRectangle) -width $value
        $canvasLabel::($this,canvas) itemconfigure $canvasLabel::($this,rectangle) -width $value
        update $this
    }
    proc set-foreground {this value} {
        $canvasLabel::($this,canvas) itemconfigure $canvasLabel::($this,text) -fill $value
    }
    proc set-scale {this value} {                                   ;# value is a list of ratios of the horizontal and vertical axis
        update $this                                                           ;# refresh display which takes new scale into account
    }
    proc set-stipple {this value} {
        $canvasLabel::($this,canvas) itemconfigure $canvasLabel::($this,rectangle) -stipple $value
    }
    proc set-style {this value} {
        switch $value {
            box {
                $canvasLabel::($this,canvas) raise $canvasLabel::($this,selectRectangle) $canvasLabel::($this,rectangle)
            }
            split {
                $canvasLabel::($this,canvas) lower $canvasLabel::($this,selectRectangle) $canvasLabel::($this,rectangle)
            }
            default {
                error "bad style value \"$value\": must be box or split"
            }
        }
        update $this
    }
    foreach option {-anchor -bulletwidth -padding -select -selectcolor} {
        proc set$option {this value} {update $this}
    }
    foreach option {-font -justify -text -width} {
        proc set$option {this value} "
            \$canvasLabel::(\$this,canvas) itemconfigure \$canvasLabel::(\$this,text) $option \$value
            update \$this
        "
    }

    proc update {this} {
        set canvas $canvasLabel::($this,canvas)
        set rectangle $canvasLabel::($this,rectangle)
        set selectRectangle $canvasLabel::($this,selectRectangle)
        set text $canvasLabel::($this,text)

        foreach {x y} [$canvas coords $canvasLabel::($this,origin)] {}

        set border [$canvas itemcget $rectangle -width]
        set textBox [$canvas bbox $text]
        set padding [winfo fpixels $canvas $switched::($this,-padding)]
        set bulletWidth [winfo fpixels $canvas $switched::($this,-bulletwidth)]

        $canvas itemconfigure $selectRectangle -fill {} -outline {}
        set split [expr {[string compare $switched::($this,-style) split]==0}]

        # position rectangle and text as if anchor was center (the default)
        if {$split} {                                                                                                 ;# split style
            set halfWidth [expr {($bulletWidth+$border+$padding+([lindex $textBox 2]-[lindex $textBox 0]))/2.0}]
            set halfHeight [expr {(([lindex $textBox 3]-[lindex $textBox 1])/2.0)+$border}]
        } else {                                                                                                        ;# box style
            set width [expr {$switched::($this,-width)==0?[lindex $textBox 2]-[lindex $textBox 0]:$switched::($this,-width)}]
            set halfWidth [expr {$bulletWidth+$border+$padding+($width/2.0)}]
            set halfHeight [expr {(([lindex $textBox 3]-[lindex $textBox 1])/2.0)+$border+$padding}]
        }
        set left [expr {$x-$halfWidth}]
        set top [expr {$y-$halfHeight}]
        set right [expr {$x+$halfWidth}]
        set bottom [expr {$y+$halfHeight}]
        $canvas coords $text [expr {$x+(($bulletWidth+$border+$padding)/2.0)}] $y
        if {$split} {
            $canvas coords $selectRectangle $left $top $right $bottom
            $canvas coords $rectangle $left $top [expr {$left+$bulletWidth}] $bottom
            if {$switched::($this,-select)} {
                $canvas itemconfigure $selectRectangle\
                    -fill $switched::($this,-selectcolor) -outline $switched::($this,-selectcolor)
            }
        } else {
            $canvas coords $selectRectangle $left $top [expr {$left+$bulletWidth}] $bottom
            $canvas coords $rectangle $left $top $right $bottom
            $canvas itemconfigure $selectRectangle -outline $switched::($this,-bordercolor)
            if {$switched::($this,-select)} {
                $canvas itemconfigure $selectRectangle -fill $switched::($this,-selectcolor)
            }
        }

        set anchor $switched::($this,-anchor)                                     ;# now move rectangle and text according to anchor
        set xDelta [expr {([string match *w $anchor]-[string match *e $anchor])*$halfWidth}]
        set yDelta [expr {([string match n* $anchor]-[string match s* $anchor])*$halfHeight}]
        $canvas move $rectangle $xDelta $yDelta
        $canvas move $selectRectangle $xDelta $yDelta
        $canvas move $text $xDelta $yDelta
        eval $canvas scale canvasLabel($this) $x $y $switched::($this,-scale)                                 ;# finally apply scale
    }

}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































































































































































































































































Changes to modules/tkpiechart/labarray.tcl.

1
2
3
4
5
6
7
8
set rcsId {$Id: labarray.tcl,v 1.20 1998/06/07 13:47:02 jfontain Exp $}

class canvasLabelsArray {

    proc canvasLabelsArray {this canvas args} switched {$args} {
        set canvasLabelsArray::($this,canvas) $canvas
        # use an empty image as an origin marker with only 2 coordinates
        set canvasLabelsArray::($this,origin) [$canvas create image 0 0 -tags canvasLabelsArray($this)]
|







1
2
3
4
5
6
7
8
set rcsId {$Id: labarray.tcl,v 1.20.1.2 2000/04/06 19:34:36 jfontain Exp $}

class canvasLabelsArray {

    proc canvasLabelsArray {this canvas args} switched {$args} {
        set canvasLabelsArray::($this,canvas) $canvas
        # use an empty image as an origin marker with only 2 coordinates
        set canvasLabelsArray::($this,origin) [$canvas create image 0 0 -tags canvasLabelsArray($this)]
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

86
87
88
89
90
91
92
93
94



95

96
97


98
99
100

101
102
103

104

            position $this $label $index
            incr index
        }
    }

    proc position {this label index} {
        set canvas $canvasLabelsArray::($this,canvas)

        foreach {x y} [$canvas coords $canvasLabelsArray::($this,origin)] {}
        set coordinates [$canvas bbox canvasLabel($label)]
        set y [expr {$y+(($index/2)*([lindex $coordinates 3]-[lindex $coordinates 1]))}]           ;# take label height into account

        switch $switched::($this,-justify) {                                                        ;# arrange labels in two columns
            left {
                set x [expr {$x+(($index%2)*($canvasLabelsArray::($this,width)/2.0))}]
                set anchor nw
            }
            right {
                set x [expr {$x+((($index%2)+1)*($canvasLabelsArray::($this,width)/2.0))}]
                set anchor ne
            }
            default {                                                                                            ;# should be center
                set x [expr {$x+((1.0+(2*($index%2)))*$canvasLabelsArray::($this,width)/4)}]
                set anchor n
            }
        }

        switched::configure $label -anchor $anchor
        foreach {xDelta yDelta} [$canvas coords canvasLabel($label)] {}                ;# do an absolute positioning using label tag
        $canvas move canvasLabel($label) [expr {$x-$xDelta}] [expr {$y-$yDelta}]
    }

    proc labels {this} {
        return $canvasLabelsArray::($this,labels)
    }




    proc height {this} {

        set number [llength $canvasLabelsArray::($this,labels)]
        if {$number==0} {


            return 0
        }
        set coordinates [$canvasLabelsArray::($this,canvas) bbox canvasLabel([lindex $canvasLabelsArray::($this,labels) 0])]

        return [expr {(($number+1)/2)*([lindex $coordinates 3]-[lindex $coordinates 1])}]
    }


}








<

<
<
|


|



|



|



>









>
>
>
|
>
|
<
>
>
|
|
|
>
|


>
|
>
60
61
62
63
64
65
66

67


68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

99
100
101
102
103
104
105
106
107
108
109
110
            position $this $label $index
            incr index
        }
    }

    proc position {this label index} {
        set canvas $canvasLabelsArray::($this,canvas)

        foreach {x y} [$canvas coords $canvasLabelsArray::($this,origin)] {}


        set column [expr {$index%2}]
        switch $switched::($this,-justify) {                                                        ;# arrange labels in two columns
            left {
                set x [expr {$x+($column*($canvasLabelsArray::($this,width)/2.0))}]
                set anchor nw
            }
            right {
                set x [expr {$x+(($column+1)*($canvasLabelsArray::($this,width)/2.0))}]
                set anchor ne
            }
            default {                                                                                            ;# should be center
                set x [expr {$x+((1.0+(2*$column))*$canvasLabelsArray::($this,width)/4)}]
                set anchor n
            }
        }
        set y [expr {$y+[columnHeight $this $column [expr {$index/2}]]}]
        switched::configure $label -anchor $anchor
        foreach {xDelta yDelta} [$canvas coords canvasLabel($label)] {}                ;# do an absolute positioning using label tag
        $canvas move canvasLabel($label) [expr {$x-$xDelta}] [expr {$y-$yDelta}]
    }

    proc labels {this} {
        return $canvasLabelsArray::($this,labels)
    }

    proc columnHeight {this column {rows 2147483647}} {                                              ;# column must be either 0 or 1
        set canvas $canvasLabelsArray::($this,canvas)
        set length [llength $canvasLabelsArray::($this,labels)]
        set height 0
        for {set index $column; set row 0} {($index<$length)&&($row<$rows)} {incr index 2; incr row} {
            set coordinates [$canvas bbox canvasLabel([lindex $canvasLabelsArray::($this,labels) $index])]

            incr height [expr {[lindex $coordinates 3]-[lindex $coordinates 1]}]
        }
        return $height
    }

    proc height {this} {
        return [maximum [columnHeight $this 0] [columnHeight $this 1]]
    }

    proc maximum {a b} {return [expr {$a>$b?$a:$b}]}

}

Deleted modules/tkpiechart/objselec.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# copyright (C) 1997-98 Jean-Luc Fontaine (mailto:[email protected])
# this program is free software: please read the COPYRIGHT file enclosed in this package or use the Help Copyright menu

set rcsId {$Id: objselec.tcl,v 1.7 1999/01/31 18:53:01 jfontain Exp $}

# implements selection on a list of object identifiers (sortable list of integer), for a listbox implementation, for example

class objectSelector {

    proc objectSelector {this args} selector {$args} {}

    proc ~objectSelector {this} {}

    ### public procedures follow:

    proc extend {this id} {
        if {[info exists selector::($this,lastSelected)]} {
            set list [lsort -integer [selector::list $this]]
            set last [lsearch -exact $list $selector::($this,lastSelected)]
            set index [lsearch -exact $list $id]
            selector::clear $this
            if {$index>$last} {
                selector::set $this [lrange $list $last $index] 1
            } else {
                selector::set $this [lrange $list $index $last] 1
            }
        } else {
            selector::select $this $id
        }
    }

}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































Changes to modules/tkpiechart/perilabel.tcl.

1
2
3
4
5
6
7
8
set rcsId {$Id: perilabel.tcl,v 1.47 1999/03/24 21:57:40 jfontain Exp $}

class piePeripheralLabeler {

    variable PI 3.14159265358979323846

    proc piePeripheralLabeler {this canvas args} pieLabeler {$canvas $args} switched {$args} {
        switched::complete $this
|







1
2
3
4
5
6
7
8
set rcsId {$Id: perilabel.tcl,v 1.47.1.1 2000/03/05 21:04:00 jfontain Exp $}

class piePeripheralLabeler {

    variable PI 3.14159265358979323846

    proc piePeripheralLabeler {this canvas args} pieLabeler {$canvas $args} switched {$args} {
        switched::complete $this
72
73
74
75
76
77
78








79
80
81
82
83
84
85
    unset index anchor

    proc set {this label value} {
        ::set text $piePeripheralLabeler::($this,textItem,$label)
        position $this $text $piePeripheralLabeler::($this,slice,$label)
        $pieLabeler::($this,canvas) itemconfigure $text -text $value
    }









    proc position {this text slice} {              ;# place the value text item next to the outter border of the corresponding slice
        variable PI

        slice::data $slice data                                                    ;# retrieve current slice position and dimensions
        # calculate text closest point coordinates in normal coordinates system (y increasing in north direction)
        ::set midAngle [expr {$data(start)+($data(extent)/2.0)}]







>
>
>
>
>
>
>
>







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
    unset index anchor

    proc set {this label value} {
        ::set text $piePeripheralLabeler::($this,textItem,$label)
        position $this $text $piePeripheralLabeler::($this,slice,$label)
        $pieLabeler::($this,canvas) itemconfigure $text -text $value
    }

    proc label {this label args} {
        if {[llength $args]==0} {
            return [switched::cget $label -text]
        } else {
            switched::configure $label -text [lindex $args 0]
        }
    }

    proc position {this text slice} {              ;# place the value text item next to the outter border of the corresponding slice
        variable PI

        slice::data $slice data                                                    ;# retrieve current slice position and dimensions
        # calculate text closest point coordinates in normal coordinates system (y increasing in north direction)
        ::set midAngle [expr {$data(start)+($data(extent)/2.0)}]

Changes to modules/tkpiechart/pie.tcl.

1
2
3
4
5
6
7
8
9
10
set rcsId {$Id: pie.tcl,v 1.85 1999/03/27 21:41:51 jfontain Exp $}

package provide tkpiechart 5.3

class pie {
    set pie::(colors) {#7FFFFF #7FFF7F #FF7F7F #FFFF7F #7F7FFF #FFBF00 #BFBFBF #FF7FFF #FFFFFF}
}

proc pie::pie {this canvas x y args} switched {$args} {                         ;# note: all pie elements are tagged with pie($this)
    set pie::($this,canvas) $canvas
|

|







1
2
3
4
5
6
7
8
9
10
set rcsId {$Id: pie.tcl,v 1.85.1.3 2000/04/06 19:29:27 jfontain Exp $}

package provide tkpiechart 5.4.1

class pie {
    set pie::(colors) {#7FFFFF #7FFF7F #FF7F7F #FFFF7F #7F7FFF #FFBF00 #BFBFBF #FF7FFF #FFFFFF}
}

proc pie::pie {this canvas x y args} switched {$args} {                         ;# note: all pie elements are tagged with pie($this)
    set pie::($this,canvas) $canvas
197
198
199
200
201
202
203





204
205
206
207
208
209
210
    }

    set value [expr {-1*$growth}]                                                               ;# finally move the following slices
    foreach slice [lrange $pie::($this,slices) [incr index] end] {
        slice::rotate $slice $value
    }
}






proc pie::selectedSlices {this} {                                                      ;# return a list of currently selected slices
    set list {}
    foreach slice $pie::($this,slices) {
        if {[pieLabeler::selectState $pie::($this,labeler) $pie::($this,sliceLabel,$slice)]} {
            lappend list $slice
        }







>
>
>
>
>







197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
    }

    set value [expr {-1*$growth}]                                                               ;# finally move the following slices
    foreach slice [lrange $pie::($this,slices) [incr index] end] {
        slice::rotate $slice $value
    }
}

proc pie::labelSlice {this slice text} {
    pieLabeler::label $pie::($this,labeler) $pie::($this,sliceLabel,$slice) $text
    update $this                                                                    ;# necessary if number of lines in label changes
}

proc pie::selectedSlices {this} {                                                      ;# return a list of currently selected slices
    set list {}
    foreach slice $pie::($this,slices) {
        if {[pieLabeler::selectState $pie::($this,labeler) $pie::($this,sliceLabel,$slice)]} {
            lappend list $slice
        }
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
    set scale [list\
        [expr {($pie::($this,width)-$room(left)-$room(right))/$pie::($this,initialWidth)}]\
        [expr {\
            ($pie::($this,height)-$room(top)-$room(bottom)-$pie::($this,titleRoom))/\
            ($pie::($this,initialHeight)+$pie::($this,thickness))\
        }]\
    ]
    switched::configure $pie::($this,backgroundSlice) -scale $scale                             ;# update scale of background slice,
    foreach slice $pie::($this,slices) {
        switched::configure $slice -scale $scale                                                                 ;# and other slices
    }
    if {$pie::($this,titleRoom)>0} {                                                                                 ;# title exists
        $canvas coords $pie::($this,title) [expr {$x+($pie::($this,width)/2)}] $y               ;# place text above pie and centered
    }
    # finally update labels now that pie graphics are in position







|







248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
    set scale [list\
        [expr {($pie::($this,width)-$room(left)-$room(right))/$pie::($this,initialWidth)}]\
        [expr {\
            ($pie::($this,height)-$room(top)-$room(bottom)-$pie::($this,titleRoom))/\
            ($pie::($this,initialHeight)+$pie::($this,thickness))\
        }]\
    ]
    switched::configure $pie::($this,backgroundSlice) -scale $scale                              ;# update scale of background slice
    foreach slice $pie::($this,slices) {
        switched::configure $slice -scale $scale                                                                 ;# and other slices
    }
    if {$pie::($this,titleRoom)>0} {                                                                                 ;# title exists
        $canvas coords $pie::($this,title) [expr {$x+($pie::($this,width)/2)}] $y               ;# place text above pie and centered
    }
    # finally update labels now that pie graphics are in position

Changes to modules/tkpiechart/pielabel.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17


18
19
20
21
22
23
24
25
26
set rcsId {$Id: pielabel.tcl,v 1.40 1998/06/07 10:07:30 jfontain Exp $}

class pieLabeler {

    set pieLabeler::(default,font) {Helvetica -12}

    proc pieLabeler {this canvas args} {
        ::set pieLabeler::($this,canvas) $canvas
    }

    proc ~pieLabeler {this} {}

    virtual proc new {this slice args}                                                                  ;# must return a canvasLabel

    virtual proc delete {this label}

    virtual proc set {this label value}



    virtual proc selectState {this label {state {}}}

    # must be invoked only by pie, which knows when it is necessary to update (new or deleted label)
    virtual proc update {this left top right bottom}

    virtual proc room {this arrayName}

}
|
















>
>









1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
set rcsId {$Id: pielabel.tcl,v 1.40.1.1 2000/03/05 20:54:00 jfontain Exp $}

class pieLabeler {

    set pieLabeler::(default,font) {Helvetica -12}

    proc pieLabeler {this canvas args} {
        ::set pieLabeler::($this,canvas) $canvas
    }

    proc ~pieLabeler {this} {}

    virtual proc new {this slice args}                                                                  ;# must return a canvasLabel

    virtual proc delete {this label}

    virtual proc set {this label value}

    virtual proc label {this args}                                                               ;# set or get label if no arguments

    virtual proc selectState {this label {state {}}}

    # must be invoked only by pie, which knows when it is necessary to update (new or deleted label)
    virtual proc update {this left top right bottom}

    virtual proc room {this arrayName}

}

Changes to modules/tkpiechart/selector.tcl.

1
2
3
4
5
6
7
8
set rcsId {$Id: selector.tcl,v 1.4 1999/08/16 20:59:03 jfontain Exp $}

# implements generic selection on a list of unique identifiers

class selector {

    proc selector {this args} switched {$args} {
        ::set selector::($this,order) 0
|







1
2
3
4
5
6
7
8
set rcsId {$Id: selector.tcl,v 1.4.1.1 2000/07/30 19:47:35 jfontain Exp $}

# implements generic selection on a list of unique identifiers

class selector {

    proc selector {this args} switched {$args} {
        ::set selector::($this,order) 0
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111

        ::set select {}
        ::set deselect {}
        foreach index $indices {
            if {[::set ${this}selected($index)]} {
                lappend deselect $index
                ::set ${this}selected($index) 0
                if {$index==$selector::($this,lastSelected)} {
                    ::unset selector::($this,lastSelected)                                               ;# nothing is left selected
                }
            } else {
                lappend select $index
                ::set ${this}selected($index) 1
                ::set selector::($this,lastSelected) $index                      ;# keep track of last selected object for extension
            }
            ::set ${this}order($index) $selector::($this,order)                                        ;# keep track of action order







|
|







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111

        ::set select {}
        ::set deselect {}
        foreach index $indices {
            if {[::set ${this}selected($index)]} {
                lappend deselect $index
                ::set ${this}selected($index) 0
                if {[info exists selector::($this,lastSelected)]&&($index==$selector::($this,lastSelected))} {
                    ::unset selector::($this,lastSelected)                     ;# too complicated to find out what was selected last
                }
            } else {
                lappend select $index
                ::set ${this}selected($index) 1
                ::set selector::($this,lastSelected) $index                      ;# keep track of last selected object for extension
            }
            ::set ${this}order($index) $selector::($this,order)                                        ;# keep track of action order

Deleted modules/tkpiechart/slice.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
set rcsId {$Id: slice.tcl,v 1.39 1998/06/07 10:19:25 jfontain Exp $}


class slice {
    variable PI 3.14159265358979323846
}

proc slice::slice {this canvas xRadius yRadius args} switched {$args} {                          ;# all dimensions must be in pixels
    # note: all slice elements are tagged with slice($this)
    set slice::($this,canvas) $canvas
    set slice::($this,xRadius) $xRadius
    set slice::($this,yRadius) $yRadius
    switched::complete $this
    complete $this                                                  ;# wait till all options have been set for initial configuration
    update $this
}

proc slice::~slice {this} {
    if {[string length $switched::($this,-deletecommand)]>0} {                              ;# always invoke command at global level
        uplevel $switched::($this,-deletecommand)
    }
    $slice::($this,canvas) delete slice($this)
}

proc slice::options {this} {
    return [list\
        [list -bottomcolor {} {}]\
        [list -deletecommand {} {}]\
        [list -height 0 0]\
        [list -scale {1 1} {1 1}]\
        [list -startandextent {0 0} {0 0}]\
        [list -topcolor {} {}]\
    ]
}

foreach option {-bottomcolor -height -topcolor} {                                        ;# no dynamic options allowed: see complete
    proc slice::set$option {this value} "
        if {\$switched::(\$this,complete)} {
            error {option $option cannot be set dynamically}
        }
    "
}

proc slice::set-deletecommand {this value} {}                                                    ;# data is stored at switched level

proc slice::set-scale {this value} {
    if {$switched::($this,complete)} {
        update $this                                                                       ;# requires initialization to be complete
    }
}

proc slice::set-startandextent {this value} {
    foreach {start extent} $value {}
    set slice::($this,start) [normalizedAngle $start]
    if {$extent<0} {
        set slice::($this,extent) 0                                                              ;# a negative extent is meaningless
    } elseif {$extent>=360} {                      ;# get as close as possible to 360, which would not work as it is equivalent to 0
        set slice::($this,extent) [expr {360-pow(10,-$::tcl_precision+3)}]
    } else {
        set slice::($this,extent) $extent
    }
    if {$switched::($this,complete)} {
        update $this                                                                       ;# requires initialization to be complete
    }
}

proc slice::normalizedAngle {value} {                                 ;# normalize value between -180 and 180 degrees (not included)
    while {$value>=180} {
        set value [expr {$value-360}]
    }
    while {$value<-180} {
        set value [expr {$value+360}]
    }
    return $value
}

proc slice::complete {this} {
    set canvas $slice::($this,canvas)
    set xRadius $slice::($this,xRadius)
    set yRadius $slice::($this,yRadius)
    set bottomColor $switched::($this,-bottomcolor)
    # use an empty image as an origin marker with only 2 coordinates
    set slice::($this,origin) [$canvas create image -$xRadius -$yRadius -tags slice($this)]
    if {$switched::($this,-height)>0} {                                                                                        ;# 3D
        set slice::($this,startBottomArcFill) [$canvas create arc\
            0 0 0 0 -style chord -extent 0 -fill $bottomColor -outline $bottomColor -tags slice($this)\
        ]
        set slice::($this,startPolygon) [$canvas create polygon 0 0 0 0 0 0 -fill $bottomColor -tags slice($this)]
        set slice::($this,startBottomArc) [$canvas create arc 0 0 0 0 -style arc -extent 0 -fill black -tags slice($this)]

        set slice::($this,endBottomArcFill) [$canvas create arc\
            0 0 0 0 -style chord -extent 0 -fill $bottomColor -outline $bottomColor -tags slice($this)\
        ]
        set slice::($this,endPolygon) [$canvas create polygon 0 0 0 0 0 0 -fill $bottomColor -tags slice($this)]
        set slice::($this,endBottomArc) [$canvas create arc 0 0 0 0 -style arc -extent 0 -fill black -tags slice($this)]

        set slice::($this,startLeftLine) [$canvas create line 0 0 0 0 -tags slice($this)]
        set slice::($this,startRightLine) [$canvas create line 0 0 0 0 -tags slice($this)]
        set slice::($this,endLeftLine) [$canvas create line 0 0 0 0 -tags slice($this)]
        set slice::($this,endRightLine) [$canvas create line 0 0 0 0 -tags slice($this)]
    }
    set slice::($this,topArc) [$canvas create arc\
        -$xRadius -$yRadius $xRadius $yRadius -fill $switched::($this,-topcolor) -tags slice($this)\
    ]
    $canvas move slice($this) $xRadius $yRadius                       ;# move slice so upper-left corner is at requested coordinates
}

proc slice::update {this} {
    set canvas $slice::($this,canvas)
    set coordinates [$canvas coords $slice::($this,origin)]            ;# first store slice position in case it was moved as a whole
    set xRadius $slice::($this,xRadius)
    set yRadius $slice::($this,yRadius)
    $canvas coords $slice::($this,origin) -$xRadius -$yRadius
    $canvas coords $slice::($this,topArc) -$xRadius -$yRadius $xRadius $yRadius
    $canvas itemconfigure $slice::($this,topArc) -start $slice::($this,start) -extent $slice::($this,extent)
    if {$switched::($this,-height)>0} {                                                                                        ;# 3D
        updateBottom $this
    }
    # now position slice at the correct coordinates
    $canvas move slice($this) [expr {[lindex $coordinates 0]+$xRadius}] [expr {[lindex $coordinates 1]+$yRadius}]
    eval $canvas scale slice($this) $coordinates $switched::($this,-scale)                                    ;# finally apply scale
}

proc slice::updateBottom {this} {
    variable PI

    set start $slice::($this,start)
    set extent $slice::($this,extent)

    set canvas $slice::($this,canvas)
    set xRadius $slice::($this,xRadius)
    set yRadius $slice::($this,yRadius)
    set height $switched::($this,-height)

    $canvas itemconfigure $slice::($this,startBottomArcFill) -extent 0                      ;# first make all bottom parts invisible
    $canvas coords $slice::($this,startBottomArcFill) -$xRadius -$yRadius $xRadius $yRadius
    $canvas move $slice::($this,startBottomArcFill) 0 $height
    $canvas itemconfigure $slice::($this,startBottomArc) -extent 0
    $canvas coords $slice::($this,startBottomArc) -$xRadius -$yRadius $xRadius $yRadius
    $canvas move $slice::($this,startBottomArc) 0 $height
    $canvas coords $slice::($this,startLeftLine) 0 0 0 0
    $canvas coords $slice::($this,startRightLine) 0 0 0 0
    $canvas itemconfigure $slice::($this,endBottomArcFill) -extent 0
    $canvas coords $slice::($this,endBottomArcFill) -$xRadius -$yRadius $xRadius $yRadius
    $canvas move $slice::($this,endBottomArcFill) 0 $height
    $canvas itemconfigure $slice::($this,endBottomArc) -extent 0
    $canvas coords $slice::($this,endBottomArc) -$xRadius -$yRadius $xRadius $yRadius
    $canvas move $slice::($this,endBottomArc) 0 $height
    $canvas coords $slice::($this,endLeftLine) 0 0 0 0
    $canvas coords $slice::($this,endRightLine) 0 0 0 0
    $canvas coords $slice::($this,startPolygon) 0 0 0 0 0 0 0 0
    $canvas coords $slice::($this,endPolygon) 0 0 0 0 0 0 0 0

    set startX [expr {$xRadius*cos($start*$PI/180)}]
    set startY [expr {-$yRadius*sin($start*$PI/180)}]
    set end [normalizedAngle [expr {$start+$extent}]]
    set endX [expr {$xRadius*cos($end*$PI/180)}]
    set endY [expr {-$yRadius*sin($end*$PI/180)}]

    set startBottom [expr {$startY+$height}]
    set endBottom [expr {$endY+$height}]

    if {(($start>=0)&&($end>=0))||(($start<0)&&($end<0))} {           ;# start and end angles are on the same side of the 0 abscissa
        if {$extent<=180} {                                                                      ;# slice size is less than half pie
            if {$start<0} {                                                          ;# slice is facing viewer, so bottom is visible
                $canvas itemconfigure $slice::($this,startBottomArcFill) -start $start -extent $extent
                $canvas itemconfigure $slice::($this,startBottomArc) -start $start -extent $extent
                # only one polygon is needed
                $canvas coords $slice::($this,startPolygon) $startX $startY $endX $endY $endX $endBottom $startX $startBottom
                $canvas coords $slice::($this,startLeftLine) $startX $startY $startX $startBottom
                $canvas coords $slice::($this,startRightLine) $endX $endY $endX $endBottom
            }                                                                                            ;# else only top is visible
        } else {                                                                                 ;# slice size is more than half pie
            if {$start<0} {                                               ;# slice opening is facing viewer, so bottom is in 2 parts
                $canvas itemconfigure $slice::($this,startBottomArcFill) -start 0 -extent $start
                $canvas itemconfigure $slice::($this,startBottomArc) -start 0 -extent $start
                $canvas coords $slice::($this,startPolygon) $startX $startY $xRadius 0 $xRadius $height $startX $startBottom
                $canvas coords $slice::($this,startLeftLine) $startX $startY $startX $startBottom
                $canvas coords $slice::($this,startRightLine) $xRadius 0 $xRadius $height

                set bottomArcExtent [expr {$end+180}]
                $canvas itemconfigure $slice::($this,endBottomArcFill) -start -180 -extent $bottomArcExtent
                $canvas itemconfigure $slice::($this,endBottomArc) -start -180 -extent $bottomArcExtent
                $canvas coords $slice::($this,endPolygon) -$xRadius 0 $endX $endY $endX $endBottom -$xRadius $height
                $canvas coords $slice::($this,endLeftLine) -$xRadius 0 -$xRadius $height
                $canvas coords $slice::($this,endRightLine) $endX $endY $endX $endBottom
            } else {                                                 ;# slice back is facing viewer, so bottom occupies half the pie
                $canvas itemconfigure $slice::($this,startBottomArcFill) -start 0 -extent -180
                $canvas itemconfigure $slice::($this,startBottomArc) -start 0 -extent -180
                # only one polygon is needed
                $canvas coords $slice::($this,startPolygon) -$xRadius 0 $xRadius 0 $xRadius $height -$xRadius $height
                $canvas coords $slice::($this,startLeftLine) -$xRadius 0 -$xRadius $height
                $canvas coords $slice::($this,startRightLine) $xRadius 0 $xRadius $height
            }
        }
    } else {                                                         ;# start and end angles are on opposite sides of the 0 abscissa
        if {$start<0} {                                                                              ;# slice start is facing viewer
            $canvas itemconfigure $slice::($this,startBottomArcFill) -start 0 -extent $start
            $canvas itemconfigure $slice::($this,startBottomArc) -start 0 -extent $start
            # only one polygon is needed
            $canvas coords $slice::($this,startPolygon) $startX $startY $xRadius 0 $xRadius $height $startX $startBottom
            $canvas coords $slice::($this,startLeftLine) $startX $startY $startX $startBottom
            $canvas coords $slice::($this,startRightLine) $xRadius 0 $xRadius $height
        } else {                                                                                       ;# slice end is facing viewer
            set bottomArcExtent [expr {$end+180}]
            $canvas itemconfigure $slice::($this,endBottomArcFill) -start -180 -extent $bottomArcExtent
            $canvas itemconfigure $slice::($this,endBottomArc) -start -180 -extent $bottomArcExtent
            # only one polygon is needed
            $canvas coords $slice::($this,endPolygon) -$xRadius 0 $endX $endY $endX $endBottom -$xRadius $height
            $canvas coords $slice::($this,startLeftLine) -$xRadius 0 -$xRadius $height
            $canvas coords $slice::($this,startRightLine) $endX $endY $endX $endBottom
        }
    }
}

proc slice::rotate {this angle} {
    if {$angle==0} return
    set slice::($this,start) [normalizedAngle [expr {$slice::($this,start)+$angle}]]
    update $this
}

proc slice::data {this arrayName} {                                               ;# return actual sizes and positions after scaling
    upvar $arrayName data

    set data(start) $slice::($this,start)
    set data(extent) $slice::($this,extent)
    foreach {x y} $switched::($this,-scale) {}
    set data(xRadius) [expr {$x*$slice::($this,xRadius)}]
    set data(yRadius) [expr {$y*$slice::($this,yRadius)}]
    set data(height) [expr {$y*$switched::($this,-height)}]
    foreach {x y} [$slice::($this,canvas) coords $slice::($this,origin)] {}
    set data(xCenter) [expr {$x+$data(xRadius)}]
    set data(yCenter) [expr {$y+$data(yRadius)}]
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<